From 0468f572afb199ee2505fffedca9112f50de2c92 Mon Sep 17 00:00:00 2001 From: Marc R Kellerman <9411143+mkellerman@users.noreply.github.com> Date: Sat, 15 Jun 2024 23:41:53 -0700 Subject: [PATCH 01/33] fix: Aggregate Javascript logs --- .../APS/OpenAPS/JavaScriptWorker.swift | 154 +++++++++++++++++- 1 file changed, 151 insertions(+), 3 deletions(-) diff --git a/FreeAPS/Sources/APS/OpenAPS/JavaScriptWorker.swift b/FreeAPS/Sources/APS/OpenAPS/JavaScriptWorker.swift index 66991b2b6..fe95b0d5d 100644 --- a/FreeAPS/Sources/APS/OpenAPS/JavaScriptWorker.swift +++ b/FreeAPS/Sources/APS/OpenAPS/JavaScriptWorker.swift @@ -7,6 +7,7 @@ final class JavaScriptWorker { private let processQueue = DispatchQueue(label: "DispatchQueue.JavaScriptWorker") private let virtualMachine: JSVirtualMachine @SyncAccess(lock: contextLock) private var commonContext: JSContext? = nil + private var aggregatedLogs: [String] = [] // Step 1: Property to store log messages init() { virtualMachine = processQueue.sync { JSVirtualMachine()! } @@ -20,9 +21,11 @@ final class JavaScriptWorker { } } let consoleLog: @convention(block) (String) -> Void = { message in - debug(.openAPS, "JavaScript log: \(message)") + let trimmedMessage = message.trimmingCharacters(in: .whitespacesAndNewlines) + if !trimmedMessage.isEmpty { + self.aggregatedLogs.append(trimmedMessage) + } } - context.setObject( consoleLog, forKeyedSubscript: "_consoleLog" as NSString @@ -30,8 +33,152 @@ final class JavaScriptWorker { return context } + // New method to flush aggregated logs + private func aggregateLogs() { + let patternsAndReplacements: [(pattern: String, replacement: String)] = [ + ( + "Middleware reason: (.*)", + "\"middlewareReason\": \"$1\", " + ), + ( + "Pumphistory is empty!", + "\"pumpHistory\": \"empty\", " + ), + ( + "insulinFactor set to : (-?\\d+(\\.\\d+)?)", + "\"insulineFactor\": \"$1\", " + ), + ( + "Using weighted TDD average: (-?\\d+(\\.\\d+)?) U", + "\"weightedTDDAverage\": \"$1\", " + ), + ( + ", instead of past 24 h \\((-?\\d+(\\.\\d+)?) U\\)", + "\"past24TTDAverage\": \"$1\", " + ), + ( + ", weight: (-?\\d+(\\.\\d+)?)", + "\"weight\": \"$1\", " + ), + ( + ", Dynamic ratios log: (.*)", + "\"dynamicRatiosLog\": \"$1\", " + ), + ( + "Default Half Basal Target used: (-?\\d+(\\.\\d+)?) mmol/L", + "\"halfBasalTarget\": \"$1\", " + ), + ( + "Autosens ratio: (-?\\d+(\\.\\d+)?);", + "\"autosensRatio\": \"$1\", " + ), + ( + "Threshold set to (-?\\d+(\\.\\d+)?)", + "\"threshold\": \"$1\", " + ), + ( + "ISF unchanged: (-?\\d+(\\.\\d+)?)", + "\"isf\": \"$1\", " + "\"prevIsf\": \"$1\", " + ), + ( + "ISF from (-?\\d+(\\.\\d+)?) to (-?\\d+(\\.\\d+)?)", + "\"isf\": \"$3\", " + "\"prevIsf\": \"$1\", " + ), + ( + "CR:(-?\\d+(\\.\\d+)?)", + "\"cr\": \"$1\", " + ), + ( + "currenttemp:(-?\\d+(\\.\\d+)?) lastTempAge:(-?\\d+(\\.\\d+)?)m, tempModulus:(-?\\d+(\\.\\d+)?)m", + "\"currenttemp\": \"$1\", " + "\"lastTempAge\": \"$3\", " + "\"tempModulus\": \"$5\", " + ), + ( + "SMB (\\w+) \\((.*)\\)", + "\"smb\": \"$1\", " + "\"smbReason\": \"$2\", " + ), + ( + "profile.sens:(-?\\d+(\\.\\d+)?), sens:(-?\\d+(\\.\\d+)?), CSF:(-?\\d+(\\.\\d+)?)", + "\"profileSens\": \"$1\", " + "\"sens\": \"$3\", " + "\"csf\": \"$5\", " + ), + ( + "Carb Impact:(-?\\d+(\\.\\d+)?)mg/dL per 5m; CI Duration:(-?\\d+(\\.\\d+)?)hours; remaining CI \\((-?\\d+(\\.\\d+)?)h peak\\):(-?\\d+(\\.\\d+)?)mg/dL per 5m", + "\"carbImpact\": \"$1\", " + "\"carbImpactDuration\": \"$3\", " + "\"carbImpactRemainingTime\": \"$5\", " + + "\"carbImpactRemaining\": \"$7\", " + ), + ( + "UAM Impact:(-?\\d+(\\.\\d+)?)mg/dL per 5m; UAM Duration:(-?\\d+(\\.\\d+)?)hours", + "\"uamImpact\": \"$1\", " + "\"uamImpactDuration\": \"$3\", " + ), + ( + "minPredBG: (-?\\d+(\\.\\d+)?) minIOBPredBG: (-?\\d+(\\.\\d+)?) minZTGuardBG: (-?\\d+(\\.\\d+)?)", + "\"minPredBG\": \"$1\", " + "\"minIOBPredBG\": \"$3\", " + "\"minZTGuardBG\": \"$5\", " + ), + ( + "avgPredBG:(-?\\d+(\\.\\d+)?) COB\\/Carbs:(-?\\d+(\\.\\d+)?)\\/(-?\\d+(\\.\\d+)?)", + "\"avgPredBG\": \"$1\", " + "\"cob\": \"$3\", " + "\"carbs\": \"$5\", " + ), + ( + "BG projected to remain above (-?\\d+(\\.\\d+)?) for (-?\\d+(\\.\\d+)?)minutes", + "\"projectedBG\": \"$1\", " + "\"projectedBGDuration\": \"$3\", " + ), + ( + "naive_eventualBG:,(-?\\d+(\\.\\d+)?),bgUndershoot:,(-?\\d+(\\.\\d+)?),zeroTempDuration:,(-?\\d+(\\.\\d+)?),zeroTempEffect:,(-?\\d+(\\.\\d+)?),carbsReq:,(-?\\d+(\\.\\d+)?)", + "\"naiveEventualBG\": \"$1\", " + "\"bgUndershoot\": \"$3\", " + "\"zeroTempDuration\": \"$5\", " + + "\"zeroTempEffect\": \"$7\", " + "\"carbsReq\": \"$9\", " + ), + ( + "(.*) \\(\\.? insulinReq: (-?\\d+(\\.\\d+)?) U\\)", + "\"insulinReqReason\": \"$1\", " + "\"insulinReq\": \"$2\", " + ), + ( + "(.*) \\(\\.? insulinForManualBolus: (-?\\d+(\\.\\d+)?) U\\)", + "\"insulinForManualBolusReason\": \"$1\", " + "\"insulinForManualBolus\": \"$2\", " + ), + ( + "Setting neutral temp basal of (-?\\d+(\\.\\d+)?)U/hr", + "\"basalRate\": \"$1\"/hr', " + ) + ] + var combinedLogs = aggregatedLogs.joined(separator: "\n").trimmingCharacters(in: .whitespacesAndNewlines) + aggregatedLogs.removeAll() + + if !combinedLogs.isEmpty { + // Apply each pattern and replace matches + for (pattern, replacement) in patternsAndReplacements { + if let regex = try? NSRegularExpression(pattern: pattern, options: []) { + let range = NSRange(combinedLogs.startIndex..., in: combinedLogs) + combinedLogs = regex.stringByReplacingMatches( + in: combinedLogs, + options: [], + range: range, + withTemplate: replacement + ) + } else { + error(.openAPS, "Invalid regex pattern: \(pattern)") + } + } + + // Check if combinedLogs is a valid JSON string. If so, print it as JSON, if not, print it as a string + if let jsonData = "{\(combinedLogs)}".data(using: .utf8) { + do { + let jsonObject = try JSONSerialization.jsonObject(with: jsonData, options: []) + let prettyPrintedData = try JSONSerialization.data(withJSONObject: jsonObject, options: .prettyPrinted) + if let prettyPrintedString = String(data: prettyPrintedData, encoding: .utf8) { + debug(.openAPS, "JavaScript log [JSON]: \(prettyPrintedString)") + } + } catch { + debug(.openAPS, "JavaScript log: \(combinedLogs)") + } + } else { + debug(.openAPS, "JavaScript log: \(combinedLogs)") + } + } + } + @discardableResult func evaluate(script: Script) -> JSValue! { - evaluate(string: script.body) + let result = evaluate(string: script.body) + aggregateLogs() + return result } private func evaluate(string: String) -> JSValue! { @@ -52,6 +199,7 @@ final class JavaScriptWorker { commonContext = createContext() defer { commonContext = nil + aggregateLogs() } return execute(self) } From 037656f749a4c30be6d9a3caa088ffb39acf02c6 Mon Sep 17 00:00:00 2001 From: Marc R Kellerman <9411143+mkellerman@users.noreply.github.com> Date: Sun, 23 Jun 2024 08:45:33 -0700 Subject: [PATCH 02/33] fix: refactored to a more generic log parsing method --- .../APS/OpenAPS/JavaScriptWorker.swift | 196 ++++++------------ 1 file changed, 69 insertions(+), 127 deletions(-) diff --git a/FreeAPS/Sources/APS/OpenAPS/JavaScriptWorker.swift b/FreeAPS/Sources/APS/OpenAPS/JavaScriptWorker.swift index fe95b0d5d..e26c9de76 100644 --- a/FreeAPS/Sources/APS/OpenAPS/JavaScriptWorker.swift +++ b/FreeAPS/Sources/APS/OpenAPS/JavaScriptWorker.swift @@ -3,6 +3,42 @@ import JavaScriptCore private let contextLock = NSRecursiveLock() +extension String { + func replacingRegex( + matching pattern: String, + findingOptions: NSRegularExpression.Options = .caseInsensitive, + replacingOptions: NSRegularExpression.MatchingOptions = [], + with template: String + ) throws -> String { + let regex = try NSRegularExpression(pattern: pattern, options: findingOptions) + let range = NSRange(startIndex..., in: self) + return regex.stringByReplacingMatches(in: self, options: replacingOptions, range: range, withTemplate: template) + } +} + +extension String { + var lowercasingFirst: String { prefix(1).lowercased() + dropFirst() } + var uppercasingFirst: String { prefix(1).uppercased() + dropFirst() } + + var camelCased: String { + guard !isEmpty else { return "" } + let parts = components(separatedBy: .alphanumerics.inverted) + let first = parts.first!.lowercasingFirst + let rest = parts.dropFirst().map(\.uppercasingFirst) + + return ([first] + rest).joined() + } + + var pascalCased: String { + guard !isEmpty else { return "" } + let parts = components(separatedBy: .alphanumerics.inverted) + let first = parts.first!.uppercasingFirst + let rest = parts.dropFirst().map(\.uppercasingFirst) + + return ([first] + rest).joined() + } +} + final class JavaScriptWorker { private let processQueue = DispatchQueue(label: "DispatchQueue.JavaScriptWorker") private let virtualMachine: JSVirtualMachine @@ -21,9 +57,36 @@ final class JavaScriptWorker { } } let consoleLog: @convention(block) (String) -> Void = { message in - let trimmedMessage = message.trimmingCharacters(in: .whitespacesAndNewlines) - if !trimmedMessage.isEmpty { - self.aggregatedLogs.append(trimmedMessage) + + var parsedMessage = message.trimmingCharacters(in: .whitespacesAndNewlines) + parsedMessage = try! parsedMessage.replacingRegex(matching: ";", with: ", ") + parsedMessage = try! parsedMessage.replacingRegex(matching: "\\s?:\\s?,?", with: ": ") + parsedMessage = try! parsedMessage.replacingRegex(matching: "(\\w+: \\d+(?= [^,:\\s]+:))", with: "$1,") + parsedMessage = try! parsedMessage.replacingRegex(matching: "^[^\\w]*", with: "") + parsedMessage = try! parsedMessage.replacingRegex(matching: "(\\sset)?\\sto:?\\s+", with: ": ") + parsedMessage = try! parsedMessage.replacingRegex(matching: "(\\w+) is (\\w+)\\!?", with: "$1: $2") + parsedMessage = try! parsedMessage.replacingRegex(matching: "NaN \\(\\. (.+)\\)", with: "$1, ") + parsedMessage = try! parsedMessage.replacingRegex(matching: "Setting (.+) of (.*)", with: "$1: $2 ") + parsedMessage = try! parsedMessage.replacingRegex(matching: "(Using\\s|\\sused)", with: "") + parsedMessage = try! parsedMessage.replacingRegex( + matching: " instead of past 24 h \\((" + "(-?\\d+(\\.\\d+)?)" + " U)\\)", + with: "weighted TDD average past 24h: $1" + ) + parsedMessage = try! parsedMessage.replacingRegex(matching: "^(.+) \\((.+)\\)$", with: "$1: $2") + parsedMessage = try! parsedMessage.replacingRegex(matching: "\\s?,\\s?$", with: "") + + // Step 2: Split parsedMessage by ',' and, then split by ':' to get the key-value pair + // Step 3: Convert the key to a camelCased string + parsedMessage.split(separator: ",").forEach { property in + let keyPair = property.split(separator: ":") + if keyPair.count != 2 { + self.aggregatedLogs.append("\"unknown\": \"\(property)\"") + return + } + let key = keyPair[0].trimmingCharacters(in: .whitespacesAndNewlines).pascalCased + let value = keyPair[1].trimmingCharacters(in: .whitespacesAndNewlines) + let keyPairResult = "\"\(key)\": \"\(value)\"" + self.aggregatedLogs.append("\(keyPairResult)") } } context.setObject( @@ -35,137 +98,16 @@ final class JavaScriptWorker { // New method to flush aggregated logs private func aggregateLogs() { - let patternsAndReplacements: [(pattern: String, replacement: String)] = [ - ( - "Middleware reason: (.*)", - "\"middlewareReason\": \"$1\", " - ), - ( - "Pumphistory is empty!", - "\"pumpHistory\": \"empty\", " - ), - ( - "insulinFactor set to : (-?\\d+(\\.\\d+)?)", - "\"insulineFactor\": \"$1\", " - ), - ( - "Using weighted TDD average: (-?\\d+(\\.\\d+)?) U", - "\"weightedTDDAverage\": \"$1\", " - ), - ( - ", instead of past 24 h \\((-?\\d+(\\.\\d+)?) U\\)", - "\"past24TTDAverage\": \"$1\", " - ), - ( - ", weight: (-?\\d+(\\.\\d+)?)", - "\"weight\": \"$1\", " - ), - ( - ", Dynamic ratios log: (.*)", - "\"dynamicRatiosLog\": \"$1\", " - ), - ( - "Default Half Basal Target used: (-?\\d+(\\.\\d+)?) mmol/L", - "\"halfBasalTarget\": \"$1\", " - ), - ( - "Autosens ratio: (-?\\d+(\\.\\d+)?);", - "\"autosensRatio\": \"$1\", " - ), - ( - "Threshold set to (-?\\d+(\\.\\d+)?)", - "\"threshold\": \"$1\", " - ), - ( - "ISF unchanged: (-?\\d+(\\.\\d+)?)", - "\"isf\": \"$1\", " + "\"prevIsf\": \"$1\", " - ), - ( - "ISF from (-?\\d+(\\.\\d+)?) to (-?\\d+(\\.\\d+)?)", - "\"isf\": \"$3\", " + "\"prevIsf\": \"$1\", " - ), - ( - "CR:(-?\\d+(\\.\\d+)?)", - "\"cr\": \"$1\", " - ), - ( - "currenttemp:(-?\\d+(\\.\\d+)?) lastTempAge:(-?\\d+(\\.\\d+)?)m, tempModulus:(-?\\d+(\\.\\d+)?)m", - "\"currenttemp\": \"$1\", " + "\"lastTempAge\": \"$3\", " + "\"tempModulus\": \"$5\", " - ), - ( - "SMB (\\w+) \\((.*)\\)", - "\"smb\": \"$1\", " + "\"smbReason\": \"$2\", " - ), - ( - "profile.sens:(-?\\d+(\\.\\d+)?), sens:(-?\\d+(\\.\\d+)?), CSF:(-?\\d+(\\.\\d+)?)", - "\"profileSens\": \"$1\", " + "\"sens\": \"$3\", " + "\"csf\": \"$5\", " - ), - ( - "Carb Impact:(-?\\d+(\\.\\d+)?)mg/dL per 5m; CI Duration:(-?\\d+(\\.\\d+)?)hours; remaining CI \\((-?\\d+(\\.\\d+)?)h peak\\):(-?\\d+(\\.\\d+)?)mg/dL per 5m", - "\"carbImpact\": \"$1\", " + "\"carbImpactDuration\": \"$3\", " + "\"carbImpactRemainingTime\": \"$5\", " + - "\"carbImpactRemaining\": \"$7\", " - ), - ( - "UAM Impact:(-?\\d+(\\.\\d+)?)mg/dL per 5m; UAM Duration:(-?\\d+(\\.\\d+)?)hours", - "\"uamImpact\": \"$1\", " + "\"uamImpactDuration\": \"$3\", " - ), - ( - "minPredBG: (-?\\d+(\\.\\d+)?) minIOBPredBG: (-?\\d+(\\.\\d+)?) minZTGuardBG: (-?\\d+(\\.\\d+)?)", - "\"minPredBG\": \"$1\", " + "\"minIOBPredBG\": \"$3\", " + "\"minZTGuardBG\": \"$5\", " - ), - ( - "avgPredBG:(-?\\d+(\\.\\d+)?) COB\\/Carbs:(-?\\d+(\\.\\d+)?)\\/(-?\\d+(\\.\\d+)?)", - "\"avgPredBG\": \"$1\", " + "\"cob\": \"$3\", " + "\"carbs\": \"$5\", " - ), - ( - "BG projected to remain above (-?\\d+(\\.\\d+)?) for (-?\\d+(\\.\\d+)?)minutes", - "\"projectedBG\": \"$1\", " + "\"projectedBGDuration\": \"$3\", " - ), - ( - "naive_eventualBG:,(-?\\d+(\\.\\d+)?),bgUndershoot:,(-?\\d+(\\.\\d+)?),zeroTempDuration:,(-?\\d+(\\.\\d+)?),zeroTempEffect:,(-?\\d+(\\.\\d+)?),carbsReq:,(-?\\d+(\\.\\d+)?)", - "\"naiveEventualBG\": \"$1\", " + "\"bgUndershoot\": \"$3\", " + "\"zeroTempDuration\": \"$5\", " + - "\"zeroTempEffect\": \"$7\", " + "\"carbsReq\": \"$9\", " - ), - ( - "(.*) \\(\\.? insulinReq: (-?\\d+(\\.\\d+)?) U\\)", - "\"insulinReqReason\": \"$1\", " + "\"insulinReq\": \"$2\", " - ), - ( - "(.*) \\(\\.? insulinForManualBolus: (-?\\d+(\\.\\d+)?) U\\)", - "\"insulinForManualBolusReason\": \"$1\", " + "\"insulinForManualBolus\": \"$2\", " - ), - ( - "Setting neutral temp basal of (-?\\d+(\\.\\d+)?)U/hr", - "\"basalRate\": \"$1\"/hr', " - ) - ] - var combinedLogs = aggregatedLogs.joined(separator: "\n").trimmingCharacters(in: .whitespacesAndNewlines) + let combinedLogs = aggregatedLogs.joined(separator: "\n").trimmingCharacters(in: .whitespacesAndNewlines) aggregatedLogs.removeAll() if !combinedLogs.isEmpty { - // Apply each pattern and replace matches - for (pattern, replacement) in patternsAndReplacements { - if let regex = try? NSRegularExpression(pattern: pattern, options: []) { - let range = NSRange(combinedLogs.startIndex..., in: combinedLogs) - combinedLogs = regex.stringByReplacingMatches( - in: combinedLogs, - options: [], - range: range, - withTemplate: replacement - ) - } else { - error(.openAPS, "Invalid regex pattern: \(pattern)") - } - } - // Check if combinedLogs is a valid JSON string. If so, print it as JSON, if not, print it as a string if let jsonData = "{\(combinedLogs)}".data(using: .utf8) { do { let jsonObject = try JSONSerialization.jsonObject(with: jsonData, options: []) - let prettyPrintedData = try JSONSerialization.data(withJSONObject: jsonObject, options: .prettyPrinted) - if let prettyPrintedString = String(data: prettyPrintedData, encoding: .utf8) { - debug(.openAPS, "JavaScript log [JSON]: \(prettyPrintedString)") - } + _ = try JSONSerialization.data(withJSONObject: jsonObject, options: .prettyPrinted) + debug(.openAPS, "JavaScript log [JSON]: \n{\n\(combinedLogs)\n}") } catch { debug(.openAPS, "JavaScript log: \(combinedLogs)") } From e64189f278ed289ca060ed06ca1f4d4986795993 Mon Sep 17 00:00:00 2001 From: Marc R Kellerman <9411143+mkellerman@users.noreply.github.com> Date: Sun, 23 Jun 2024 08:52:41 -0700 Subject: [PATCH 03/33] fix: formatting --- .../Sources/APS/OpenAPS/JavaScriptWorker.swift | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/FreeAPS/Sources/APS/OpenAPS/JavaScriptWorker.swift b/FreeAPS/Sources/APS/OpenAPS/JavaScriptWorker.swift index e26c9de76..2e90d92c3 100644 --- a/FreeAPS/Sources/APS/OpenAPS/JavaScriptWorker.swift +++ b/FreeAPS/Sources/APS/OpenAPS/JavaScriptWorker.swift @@ -77,17 +77,18 @@ final class JavaScriptWorker { // Step 2: Split parsedMessage by ',' and, then split by ':' to get the key-value pair // Step 3: Convert the key to a camelCased string + var keyPairResults = " " parsedMessage.split(separator: ",").forEach { property in let keyPair = property.split(separator: ":") if keyPair.count != 2 { - self.aggregatedLogs.append("\"unknown\": \"\(property)\"") - return + keyPairResults += "\"unknown\": \"\(property)\", " + } else { + let key = keyPair[0].trimmingCharacters(in: .whitespacesAndNewlines).pascalCased + let value = keyPair[1].trimmingCharacters(in: .whitespacesAndNewlines) + keyPairResults += "\"\(key)\": \"\(value)\", " } - let key = keyPair[0].trimmingCharacters(in: .whitespacesAndNewlines).pascalCased - let value = keyPair[1].trimmingCharacters(in: .whitespacesAndNewlines) - let keyPairResult = "\"\(key)\": \"\(value)\"" - self.aggregatedLogs.append("\(keyPairResult)") } + self.aggregatedLogs.append("\(keyPairResults)") } context.setObject( consoleLog, @@ -98,7 +99,7 @@ final class JavaScriptWorker { // New method to flush aggregated logs private func aggregateLogs() { - let combinedLogs = aggregatedLogs.joined(separator: "\n").trimmingCharacters(in: .whitespacesAndNewlines) + let combinedLogs = aggregatedLogs.joined(separator: "\n") aggregatedLogs.removeAll() if !combinedLogs.isEmpty { From 01e0ffdc4b62c78cfe381d6a6c4040819e5bf649 Mon Sep 17 00:00:00 2001 From: Marc R Kellerman <9411143+mkellerman@users.noreply.github.com> Date: Sun, 23 Jun 2024 09:53:13 -0700 Subject: [PATCH 04/33] Fix: comments --- FreeAPS/Sources/APS/OpenAPS/JavaScriptWorker.swift | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/FreeAPS/Sources/APS/OpenAPS/JavaScriptWorker.swift b/FreeAPS/Sources/APS/OpenAPS/JavaScriptWorker.swift index 2e90d92c3..53524d17d 100644 --- a/FreeAPS/Sources/APS/OpenAPS/JavaScriptWorker.swift +++ b/FreeAPS/Sources/APS/OpenAPS/JavaScriptWorker.swift @@ -58,6 +58,7 @@ final class JavaScriptWorker { } let consoleLog: @convention(block) (String) -> Void = { message in + // Step 1: Format/Leandup the log entry using RegEx var parsedMessage = message.trimmingCharacters(in: .whitespacesAndNewlines) parsedMessage = try! parsedMessage.replacingRegex(matching: ";", with: ", ") parsedMessage = try! parsedMessage.replacingRegex(matching: "\\s?:\\s?,?", with: ": ") @@ -76,13 +77,13 @@ final class JavaScriptWorker { parsedMessage = try! parsedMessage.replacingRegex(matching: "\\s?,\\s?$", with: "") // Step 2: Split parsedMessage by ',' and, then split by ':' to get the key-value pair - // Step 3: Convert the key to a camelCased string var keyPairResults = " " parsedMessage.split(separator: ",").forEach { property in let keyPair = property.split(separator: ":") if keyPair.count != 2 { keyPairResults += "\"unknown\": \"\(property)\", " } else { + // Step 3: Convert the key to a PascalCased string let key = keyPair[0].trimmingCharacters(in: .whitespacesAndNewlines).pascalCased let value = keyPair[1].trimmingCharacters(in: .whitespacesAndNewlines) keyPairResults += "\"\(key)\": \"\(value)\", " From 85bf02a5752462b55f570f51e667f12fc237a627 Mon Sep 17 00:00:00 2001 From: Marc R Kellerman <9411143+mkellerman@users.noreply.github.com> Date: Tue, 2 Jul 2024 15:54:37 -0700 Subject: [PATCH 05/33] refactored to simpler formatter and cleanup autosens --- .../APS/OpenAPS/JavaScriptWorker.swift | 145 ++++++++++-------- 1 file changed, 84 insertions(+), 61 deletions(-) diff --git a/FreeAPS/Sources/APS/OpenAPS/JavaScriptWorker.swift b/FreeAPS/Sources/APS/OpenAPS/JavaScriptWorker.swift index 53524d17d..e1667a171 100644 --- a/FreeAPS/Sources/APS/OpenAPS/JavaScriptWorker.swift +++ b/FreeAPS/Sources/APS/OpenAPS/JavaScriptWorker.swift @@ -3,29 +3,14 @@ import JavaScriptCore private let contextLock = NSRecursiveLock() -extension String { - func replacingRegex( - matching pattern: String, - findingOptions: NSRegularExpression.Options = .caseInsensitive, - replacingOptions: NSRegularExpression.MatchingOptions = [], - with template: String - ) throws -> String { - let regex = try NSRegularExpression(pattern: pattern, options: findingOptions) - let range = NSRange(startIndex..., in: self) - return regex.stringByReplacingMatches(in: self, options: replacingOptions, range: range, withTemplate: template) - } -} - extension String { var lowercasingFirst: String { prefix(1).lowercased() + dropFirst() } var uppercasingFirst: String { prefix(1).uppercased() + dropFirst() } - var camelCased: String { guard !isEmpty else { return "" } let parts = components(separatedBy: .alphanumerics.inverted) let first = parts.first!.lowercasingFirst let rest = parts.dropFirst().map(\.uppercasingFirst) - return ([first] + rest).joined() } @@ -34,7 +19,6 @@ extension String { let parts = components(separatedBy: .alphanumerics.inverted) let first = parts.first!.uppercasingFirst let rest = parts.dropFirst().map(\.uppercasingFirst) - return ([first] + rest).joined() } } @@ -43,7 +27,8 @@ final class JavaScriptWorker { private let processQueue = DispatchQueue(label: "DispatchQueue.JavaScriptWorker") private let virtualMachine: JSVirtualMachine @SyncAccess(lock: contextLock) private var commonContext: JSContext? = nil - private var aggregatedLogs: [String] = [] // Step 1: Property to store log messages + private var aggregatedLogs: [String] = [] + private var logFormatting: String = "" init() { virtualMachine = processQueue.sync { JSVirtualMachine()! } @@ -57,39 +42,11 @@ final class JavaScriptWorker { } } let consoleLog: @convention(block) (String) -> Void = { message in - - // Step 1: Format/Leandup the log entry using RegEx - var parsedMessage = message.trimmingCharacters(in: .whitespacesAndNewlines) - parsedMessage = try! parsedMessage.replacingRegex(matching: ";", with: ", ") - parsedMessage = try! parsedMessage.replacingRegex(matching: "\\s?:\\s?,?", with: ": ") - parsedMessage = try! parsedMessage.replacingRegex(matching: "(\\w+: \\d+(?= [^,:\\s]+:))", with: "$1,") - parsedMessage = try! parsedMessage.replacingRegex(matching: "^[^\\w]*", with: "") - parsedMessage = try! parsedMessage.replacingRegex(matching: "(\\sset)?\\sto:?\\s+", with: ": ") - parsedMessage = try! parsedMessage.replacingRegex(matching: "(\\w+) is (\\w+)\\!?", with: "$1: $2") - parsedMessage = try! parsedMessage.replacingRegex(matching: "NaN \\(\\. (.+)\\)", with: "$1, ") - parsedMessage = try! parsedMessage.replacingRegex(matching: "Setting (.+) of (.*)", with: "$1: $2 ") - parsedMessage = try! parsedMessage.replacingRegex(matching: "(Using\\s|\\sused)", with: "") - parsedMessage = try! parsedMessage.replacingRegex( - matching: " instead of past 24 h \\((" + "(-?\\d+(\\.\\d+)?)" + " U)\\)", - with: "weighted TDD average past 24h: $1" - ) - parsedMessage = try! parsedMessage.replacingRegex(matching: "^(.+) \\((.+)\\)$", with: "$1: $2") - parsedMessage = try! parsedMessage.replacingRegex(matching: "\\s?,\\s?$", with: "") - - // Step 2: Split parsedMessage by ',' and, then split by ':' to get the key-value pair - var keyPairResults = " " - parsedMessage.split(separator: ",").forEach { property in - let keyPair = property.split(separator: ":") - if keyPair.count != 2 { - keyPairResults += "\"unknown\": \"\(property)\", " - } else { - // Step 3: Convert the key to a PascalCased string - let key = keyPair[0].trimmingCharacters(in: .whitespacesAndNewlines).pascalCased - let value = keyPair[1].trimmingCharacters(in: .whitespacesAndNewlines) - keyPairResults += "\"\(key)\": \"\(value)\", " - } + let trimmedMessage = message.trimmingCharacters(in: .whitespacesAndNewlines) + if !trimmedMessage.isEmpty { +// debug(.openAPS, "JavaScript log: \(trimmedMessage)") + self.aggregatedLogs.append("\(trimmedMessage)") } - self.aggregatedLogs.append("\(keyPairResults)") } context.setObject( consoleLog, @@ -100,26 +57,92 @@ final class JavaScriptWorker { // New method to flush aggregated logs private func aggregateLogs() { - let combinedLogs = aggregatedLogs.joined(separator: "\n") + let combinedLogs = aggregatedLogs.joined(separator: "\n").trimmingCharacters(in: .whitespacesAndNewlines) aggregatedLogs.removeAll() - if !combinedLogs.isEmpty { - // Check if combinedLogs is a valid JSON string. If so, print it as JSON, if not, print it as a string - if let jsonData = "{\(combinedLogs)}".data(using: .utf8) { - do { - let jsonObject = try JSONSerialization.jsonObject(with: jsonData, options: []) - _ = try JSONSerialization.data(withJSONObject: jsonObject, options: .prettyPrinted) - debug(.openAPS, "JavaScript log [JSON]: \n{\n\(combinedLogs)\n}") - } catch { - debug(.openAPS, "JavaScript log: \(combinedLogs)") + if combinedLogs.isEmpty { return } + + var logOutput = "" + var jsonOutput = "" + if logFormatting == "Middleware" { + jsonOutput += "{\n" + combinedLogs.replacingOccurrences(of: ";", with: ",") + .replacingOccurrences(of: "\\s?:\\s?,?", with: ": ", options: .regularExpression) + .replacingOccurrences(of: "(\\w+: \\d+(?= [^,:\\s]+:))", with: "$1,", options: .regularExpression) + .replacingOccurrences(of: "^[^\\w]*", with: "", options: .regularExpression) + .replacingOccurrences(of: "(\\sset)?\\sto:?\\s+", with: ": ", options: .regularExpression) + .replacingOccurrences(of: "(\\w+) is (\\w+)\\!?", with: "$1: $2", options: .regularExpression) + .replacingOccurrences(of: "NaN \\(\\. (.+)\\)", with: "$1, ", options: .regularExpression) + .replacingOccurrences(of: "Setting (.+) of (.*)", with: "$1: $2 ", options: .regularExpression) + .replacingOccurrences(of: "(Using\\s|\\sused)", with: "", options: .regularExpression) + .replacingOccurrences( + of: " instead of past 24 h \\((" + "(-?\\d+(\\.\\d+)?)" + " U)\\)", + with: "weighted TDD average past 24h: $1", + options: .regularExpression + ) + .replacingOccurrences(of: "^(.+) \\((.+)\\)$", with: "$1: $2", options: .regularExpression) + .replacingOccurrences(of: "\\s?,\\s?$", with: "", options: .regularExpression) + .split(separator: "\n").forEach { logLine in + jsonOutput += " " + logLine.split(separator: ",").forEach { logItem in + let keyPair = logItem.split(separator: ":") + if keyPair.count != 2 { + jsonOutput += "\"unknown\": \"\(logItem)\", " + } else { + let key = keyPair[0].trimmingCharacters(in: .whitespacesAndNewlines).pascalCased + let value = keyPair[1].trimmingCharacters(in: .whitespacesAndNewlines) + jsonOutput += "\"\(key)\": \"\(value)\", " + } + } + jsonOutput += "\n" } - } else { - debug(.openAPS, "JavaScript log: \(combinedLogs)") + jsonOutput += "}" + } + + if logFormatting == "prepare/autosens.js" { + logOutput += combinedLogs.replacingOccurrences( + of: "((?:[\\=\\+\\-]\\n)+)?\\d+h\\n((?:[\\=\\+\\-]\\n)+)?", + with: "", + options: .regularExpression + ) + } + + if logFormatting == "prepare/autotune-prep.js" { + // print(combinedLogs) + } + + if logFormatting == "prepare/autotune-core.js" { + // print(combinedLogs) + } + + debug(.openAPS, "JavaScript Format: \(logFormatting)") + + // Check if combinedLogs is a valid JSON string. If so, print it as JSON, if not, print it as a string + if let jsonData = "\(jsonOutput)".data(using: .utf8) { + do { + let jsonObject = try JSONSerialization.jsonObject(with: jsonData, options: []) + _ = try JSONSerialization.data(withJSONObject: jsonObject, options: .prettyPrinted) + debug(.openAPS, "JavaScript log: \(jsonOutput)") + return + } catch { + // debug(.openAPS, "JavaScript log: \(combinedLogs)") + } + } + + if !logOutput.isEmpty { + logOutput.split(separator: "\n").forEach { logLine in + debug(.openAPS, "JavaScript log: \(logLine)") } + return + } + + combinedLogs.split(separator: "\n").forEach { logLine in + debug(.openAPS, "JavaScript log: \(logLine)") } } @discardableResult func evaluate(script: Script) -> JSValue! { + logFormatting = script.name let result = evaluate(string: script.body) aggregateLogs() return result From 0415460eea9ef79e9cdea50ff8f466f4a3ae509f Mon Sep 17 00:00:00 2001 From: Marc R Kellerman <9411143+mkellerman@users.noreply.github.com> Date: Thu, 4 Jul 2024 07:58:15 -0700 Subject: [PATCH 06/33] fix: output unknown outputs as regular log lines --- .../APS/OpenAPS/JavaScriptWorker.swift | 56 +++++++++---------- 1 file changed, 25 insertions(+), 31 deletions(-) diff --git a/FreeAPS/Sources/APS/OpenAPS/JavaScriptWorker.swift b/FreeAPS/Sources/APS/OpenAPS/JavaScriptWorker.swift index e1667a171..e03c2446a 100644 --- a/FreeAPS/Sources/APS/OpenAPS/JavaScriptWorker.swift +++ b/FreeAPS/Sources/APS/OpenAPS/JavaScriptWorker.swift @@ -64,7 +64,9 @@ final class JavaScriptWorker { var logOutput = "" var jsonOutput = "" - if logFormatting == "Middleware" { + + switch logFormatting { + case "Middleware": jsonOutput += "{\n" combinedLogs.replacingOccurrences(of: ";", with: ",") .replacingOccurrences(of: "\\s?:\\s?,?", with: ": ", options: .regularExpression) @@ -86,58 +88,50 @@ final class JavaScriptWorker { jsonOutput += " " logLine.split(separator: ",").forEach { logItem in let keyPair = logItem.split(separator: ":") - if keyPair.count != 2 { - jsonOutput += "\"unknown\": \"\(logItem)\", " - } else { + if keyPair.count == 2 { let key = keyPair[0].trimmingCharacters(in: .whitespacesAndNewlines).pascalCased let value = keyPair[1].trimmingCharacters(in: .whitespacesAndNewlines) jsonOutput += "\"\(key)\": \"\(value)\", " + } else { + logOutput += "\(logItem)\n" } } jsonOutput += "\n" } jsonOutput += "}" - } + jsonOutput = jsonOutput.replacingOccurrences(of: "\\s+\\n+", with: "\n", options: .regularExpression) - if logFormatting == "prepare/autosens.js" { + case "prepare/autosens.js": logOutput += combinedLogs.replacingOccurrences( of: "((?:[\\=\\+\\-]\\n)+)?\\d+h\\n((?:[\\=\\+\\-]\\n)+)?", with: "", options: .regularExpression ) + // case "prepare/autotune-prep.js" + // case "prepare/autotune-core.js" + default: + debug(.openAPS, "JavaScript Format: \(logFormatting)") + logOutput = combinedLogs } - if logFormatting == "prepare/autotune-prep.js" { - // print(combinedLogs) - } - - if logFormatting == "prepare/autotune-core.js" { - // print(combinedLogs) - } - - debug(.openAPS, "JavaScript Format: \(logFormatting)") - - // Check if combinedLogs is a valid JSON string. If so, print it as JSON, if not, print it as a string - if let jsonData = "\(jsonOutput)".data(using: .utf8) { - do { - let jsonObject = try JSONSerialization.jsonObject(with: jsonData, options: []) - _ = try JSONSerialization.data(withJSONObject: jsonObject, options: .prettyPrinted) - debug(.openAPS, "JavaScript log: \(jsonOutput)") - return - } catch { - // debug(.openAPS, "JavaScript log: \(combinedLogs)") + if !jsonOutput.isEmpty { + if let jsonData = "\(jsonOutput)".data(using: .utf8) { + do { + let jsonObject = try JSONSerialization.jsonObject(with: jsonData, options: []) + _ = try JSONSerialization.data(withJSONObject: jsonObject, options: .prettyPrinted) + debug(.openAPS, "JavaScript log: \(jsonOutput)") + } catch { + logOutput = combinedLogs + } } } if !logOutput.isEmpty { logOutput.split(separator: "\n").forEach { logLine in - debug(.openAPS, "JavaScript log: \(logLine)") + if !"\(logLine)".trimmingCharacters(in: .whitespacesAndNewlines).isEmpty { + debug(.openAPS, "JavaScript log: \(logLine)") + } } - return - } - - combinedLogs.split(separator: "\n").forEach { logLine in - debug(.openAPS, "JavaScript log: \(logLine)") } } From 14f0b4a0c99e8ec7bd3a89d0684ee99be1ccc983 Mon Sep 17 00:00:00 2001 From: Marc R Kellerman <9411143+mkellerman@users.noreply.github.com> Date: Fri, 5 Jul 2024 19:38:38 -0700 Subject: [PATCH 07/33] chore: rename and cleanup some of the variables --- .../APS/OpenAPS/JavaScriptWorker.swift | 86 ++++--------------- 1 file changed, 15 insertions(+), 71 deletions(-) diff --git a/FreeAPS/Sources/APS/OpenAPS/JavaScriptWorker.swift b/FreeAPS/Sources/APS/OpenAPS/JavaScriptWorker.swift index e03c2446a..5e91cd57a 100644 --- a/FreeAPS/Sources/APS/OpenAPS/JavaScriptWorker.swift +++ b/FreeAPS/Sources/APS/OpenAPS/JavaScriptWorker.swift @@ -27,8 +27,8 @@ final class JavaScriptWorker { private let processQueue = DispatchQueue(label: "DispatchQueue.JavaScriptWorker") private let virtualMachine: JSVirtualMachine @SyncAccess(lock: contextLock) private var commonContext: JSContext? = nil - private var aggregatedLogs: [String] = [] - private var logFormatting: String = "" + private var consoleLogs: [String] = [] + private var logContext: String = "" init() { virtualMachine = processQueue.sync { JSVirtualMachine()! } @@ -45,7 +45,7 @@ final class JavaScriptWorker { let trimmedMessage = message.trimmingCharacters(in: .whitespacesAndNewlines) if !trimmedMessage.isEmpty { // debug(.openAPS, "JavaScript log: \(trimmedMessage)") - self.aggregatedLogs.append("\(trimmedMessage)") + self.consoleLogs.append("\(trimmedMessage)") } } context.setObject( @@ -56,89 +56,33 @@ final class JavaScriptWorker { } // New method to flush aggregated logs - private func aggregateLogs() { - let combinedLogs = aggregatedLogs.joined(separator: "\n").trimmingCharacters(in: .whitespacesAndNewlines) - aggregatedLogs.removeAll() + private func outputLogs() { + var outputLogs = consoleLogs.joined(separator: "\n").trimmingCharacters(in: .whitespacesAndNewlines) + consoleLogs.removeAll() - if combinedLogs.isEmpty { return } + if outputLogs.isEmpty { return } - var logOutput = "" - var jsonOutput = "" - - switch logFormatting { - case "Middleware": - jsonOutput += "{\n" - combinedLogs.replacingOccurrences(of: ";", with: ",") - .replacingOccurrences(of: "\\s?:\\s?,?", with: ": ", options: .regularExpression) - .replacingOccurrences(of: "(\\w+: \\d+(?= [^,:\\s]+:))", with: "$1,", options: .regularExpression) - .replacingOccurrences(of: "^[^\\w]*", with: "", options: .regularExpression) - .replacingOccurrences(of: "(\\sset)?\\sto:?\\s+", with: ": ", options: .regularExpression) - .replacingOccurrences(of: "(\\w+) is (\\w+)\\!?", with: "$1: $2", options: .regularExpression) - .replacingOccurrences(of: "NaN \\(\\. (.+)\\)", with: "$1, ", options: .regularExpression) - .replacingOccurrences(of: "Setting (.+) of (.*)", with: "$1: $2 ", options: .regularExpression) - .replacingOccurrences(of: "(Using\\s|\\sused)", with: "", options: .regularExpression) - .replacingOccurrences( - of: " instead of past 24 h \\((" + "(-?\\d+(\\.\\d+)?)" + " U)\\)", - with: "weighted TDD average past 24h: $1", - options: .regularExpression - ) - .replacingOccurrences(of: "^(.+) \\((.+)\\)$", with: "$1: $2", options: .regularExpression) - .replacingOccurrences(of: "\\s?,\\s?$", with: "", options: .regularExpression) - .split(separator: "\n").forEach { logLine in - jsonOutput += " " - logLine.split(separator: ",").forEach { logItem in - let keyPair = logItem.split(separator: ":") - if keyPair.count == 2 { - let key = keyPair[0].trimmingCharacters(in: .whitespacesAndNewlines).pascalCased - let value = keyPair[1].trimmingCharacters(in: .whitespacesAndNewlines) - jsonOutput += "\"\(key)\": \"\(value)\", " - } else { - logOutput += "\(logItem)\n" - } - } - jsonOutput += "\n" - } - jsonOutput += "}" - jsonOutput = jsonOutput.replacingOccurrences(of: "\\s+\\n+", with: "\n", options: .regularExpression) - - case "prepare/autosens.js": - logOutput += combinedLogs.replacingOccurrences( + if logContext == "prepare/autosens.js" { + outputLogs = outputLogs.replacingOccurrences( of: "((?:[\\=\\+\\-]\\n)+)?\\d+h\\n((?:[\\=\\+\\-]\\n)+)?", with: "", options: .regularExpression ) - // case "prepare/autotune-prep.js" - // case "prepare/autotune-core.js" - default: - debug(.openAPS, "JavaScript Format: \(logFormatting)") - logOutput = combinedLogs - } - - if !jsonOutput.isEmpty { - if let jsonData = "\(jsonOutput)".data(using: .utf8) { - do { - let jsonObject = try JSONSerialization.jsonObject(with: jsonData, options: []) - _ = try JSONSerialization.data(withJSONObject: jsonObject, options: .prettyPrinted) - debug(.openAPS, "JavaScript log: \(jsonOutput)") - } catch { - logOutput = combinedLogs - } - } } - if !logOutput.isEmpty { - logOutput.split(separator: "\n").forEach { logLine in + if !outputLogs.isEmpty { + outputLogs.split(separator: "\n").forEach { logLine in if !"\(logLine)".trimmingCharacters(in: .whitespacesAndNewlines).isEmpty { - debug(.openAPS, "JavaScript log: \(logLine)") + debug(.openAPS, "\(logContext): \(logLine)") } } } } @discardableResult func evaluate(script: Script) -> JSValue! { - logFormatting = script.name + logContext = script.name let result = evaluate(string: script.body) - aggregateLogs() + outputLogs() return result } @@ -160,7 +104,7 @@ final class JavaScriptWorker { commonContext = createContext() defer { commonContext = nil - aggregateLogs() + outputLogs() } return execute(self) } From dd38115d98c27ae7f0b22c65b9c51a27381432ae Mon Sep 17 00:00:00 2001 From: Marc R Kellerman <9411143+mkellerman@users.noreply.github.com> Date: Fri, 12 Jul 2024 15:48:36 -0700 Subject: [PATCH 08/33] fix: autosens logs to be evaluated line by line --- FreeAPS/Sources/APS/OpenAPS/JavaScriptWorker.swift | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/FreeAPS/Sources/APS/OpenAPS/JavaScriptWorker.swift b/FreeAPS/Sources/APS/OpenAPS/JavaScriptWorker.swift index 5e91cd57a..6fab33e3c 100644 --- a/FreeAPS/Sources/APS/OpenAPS/JavaScriptWorker.swift +++ b/FreeAPS/Sources/APS/OpenAPS/JavaScriptWorker.swift @@ -63,11 +63,13 @@ final class JavaScriptWorker { if outputLogs.isEmpty { return } if logContext == "prepare/autosens.js" { - outputLogs = outputLogs.replacingOccurrences( - of: "((?:[\\=\\+\\-]\\n)+)?\\d+h\\n((?:[\\=\\+\\-]\\n)+)?", - with: "", - options: .regularExpression - ) + outputLogs = outputLogs.split(separator: "\n").map { logLine in + logLine.replacingOccurrences( + of: "^[-+=]|\\d{1,2}h$", + with: "", + options: .regularExpression + ) + }.joined(separator: "\n") } if !outputLogs.isEmpty { From a77b1232964e6e550e8496e09b2f329f8d063941 Mon Sep 17 00:00:00 2001 From: Marc R Kellerman <9411143+mkellerman@users.noreply.github.com> Date: Thu, 18 Jul 2024 17:14:16 -0700 Subject: [PATCH 09/33] fix regex to include u(x) --- FreeAPS/Sources/APS/OpenAPS/JavaScriptWorker.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/FreeAPS/Sources/APS/OpenAPS/JavaScriptWorker.swift b/FreeAPS/Sources/APS/OpenAPS/JavaScriptWorker.swift index 6fab33e3c..f5aee6d4a 100644 --- a/FreeAPS/Sources/APS/OpenAPS/JavaScriptWorker.swift +++ b/FreeAPS/Sources/APS/OpenAPS/JavaScriptWorker.swift @@ -65,7 +65,7 @@ final class JavaScriptWorker { if logContext == "prepare/autosens.js" { outputLogs = outputLogs.split(separator: "\n").map { logLine in logLine.replacingOccurrences( - of: "^[-+=]|\\d{1,2}h$", + of: "^[-+=x]|u\\(|\\)|\\d{1,2}h$", with: "", options: .regularExpression ) From 5a33cd1b7fce2e2d512a11022050cb8a0aac961e Mon Sep 17 00:00:00 2001 From: marionbarker Date: Sat, 20 Jul 2024 20:21:55 -0700 Subject: [PATCH 10/33] update submodule TidepoolSevice: align with LoopKit:dev version --- TidepoolService | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/TidepoolService b/TidepoolService index a2ccad72a..b28625628 160000 --- a/TidepoolService +++ b/TidepoolService @@ -1 +1 @@ -Subproject commit a2ccad72a55600c28549ab86ab1964c0d6558868 +Subproject commit b28625628e181b96f0db7ec3739d920a3c92465b From 0354c35a18103373203dc256701723a7539a5400 Mon Sep 17 00:00:00 2001 From: Marc R Kellerman <9411143+mkellerman@users.noreply.github.com> Date: Mon, 22 Jul 2024 15:41:23 -0700 Subject: [PATCH 11/33] chore: middleware to show the actual name being executed --- FreeAPS/Sources/APS/OpenAPS/OpenAPS.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/FreeAPS/Sources/APS/OpenAPS/OpenAPS.swift b/FreeAPS/Sources/APS/OpenAPS/OpenAPS.swift index 5aefb7929..26854e440 100644 --- a/FreeAPS/Sources/APS/OpenAPS/OpenAPS.swift +++ b/FreeAPS/Sources/APS/OpenAPS/OpenAPS.swift @@ -635,7 +635,7 @@ final class OpenAPS { private func middlewareScript(name: String) -> Script? { if let body = storage.retrieveRaw(name) { - return Script(name: "Middleware", body: body) + return Script(name: name, body: body) } if let url = Foundation.Bundle.main.url(forResource: "javascript/\(name)", withExtension: "") { From c560f9b170acafa4b8dc7b2d7adf09701a6bca10 Mon Sep 17 00:00:00 2001 From: Marc R Kellerman <9411143+mkellerman@users.noreply.github.com> Date: Mon, 29 Jul 2024 17:25:51 -0700 Subject: [PATCH 12/33] fix regex to include single exclamation point --- FreeAPS/Sources/APS/OpenAPS/JavaScriptWorker.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/FreeAPS/Sources/APS/OpenAPS/JavaScriptWorker.swift b/FreeAPS/Sources/APS/OpenAPS/JavaScriptWorker.swift index f5aee6d4a..b687ab4c9 100644 --- a/FreeAPS/Sources/APS/OpenAPS/JavaScriptWorker.swift +++ b/FreeAPS/Sources/APS/OpenAPS/JavaScriptWorker.swift @@ -65,7 +65,7 @@ final class JavaScriptWorker { if logContext == "prepare/autosens.js" { outputLogs = outputLogs.split(separator: "\n").map { logLine in logLine.replacingOccurrences( - of: "^[-+=x]|u\\(|\\)|\\d{1,2}h$", + of: "^[-+=x!]|u\\(|\\)|\\d{1,2}h$", with: "", options: .regularExpression ) From d4af108ad94589b7340c2f5dee09437adc76c195 Mon Sep 17 00:00:00 2001 From: Marc R Kellerman <9411143+mkellerman@users.noreply.github.com> Date: Mon, 29 Jul 2024 17:26:27 -0700 Subject: [PATCH 13/33] fix remove middleware label --- FreeAPS/Sources/APS/OpenAPS/OpenAPS.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/FreeAPS/Sources/APS/OpenAPS/OpenAPS.swift b/FreeAPS/Sources/APS/OpenAPS/OpenAPS.swift index 26854e440..4d3c5e54e 100644 --- a/FreeAPS/Sources/APS/OpenAPS/OpenAPS.swift +++ b/FreeAPS/Sources/APS/OpenAPS/OpenAPS.swift @@ -639,7 +639,7 @@ final class OpenAPS { } if let url = Foundation.Bundle.main.url(forResource: "javascript/\(name)", withExtension: "") { - return Script(name: "Middleware", body: try! String(contentsOf: url)) + return Script(name: name, body: try! String(contentsOf: url)) } return nil From 0d6bb18178f26afda46afe10915b65d2d37e124c Mon Sep 17 00:00:00 2001 From: marionbarker Date: Mon, 19 Aug 2024 15:24:31 -0700 Subject: [PATCH 14/33] update submodules OmniXXX: fix rare UI error for pod already paired --- OmniBLE | 2 +- OmniKit | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/OmniBLE b/OmniBLE index eacf06f78..e39834584 160000 --- a/OmniBLE +++ b/OmniBLE @@ -1 +1 @@ -Subproject commit eacf06f7873e73d6cb8ccd0556b35f734b90df40 +Subproject commit e39834584548821adf442f13abed0d5cfd237a72 diff --git a/OmniKit b/OmniKit index 03d3a1db5..849dc7abc 160000 --- a/OmniKit +++ b/OmniKit @@ -1 +1 @@ -Subproject commit 03d3a1db5a4da9b218a60254fa1b0ea72ee808ed +Subproject commit 849dc7abc821728dae7e064176a409e6ceb0dadd From cd25e6f415f8d622f31ed0e268a46ec9ccc2611c Mon Sep 17 00:00:00 2001 From: Mike Plante Date: Sun, 25 Aug 2024 15:48:22 -0400 Subject: [PATCH 15/33] glucose rounding fix --- FreeAPS/Sources/Modules/DataTable/View/DataTableRootView.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/FreeAPS/Sources/Modules/DataTable/View/DataTableRootView.swift b/FreeAPS/Sources/Modules/DataTable/View/DataTableRootView.swift index e57cc3633..09cfd99d8 100644 --- a/FreeAPS/Sources/Modules/DataTable/View/DataTableRootView.swift +++ b/FreeAPS/Sources/Modules/DataTable/View/DataTableRootView.swift @@ -45,7 +45,7 @@ extension DataTable { formatter.minimumFractionDigits = 0 formatter.maximumFractionDigits = 1 } - formatter.roundingMode = .down + formatter.roundingMode = .halfUp return formatter } From 9c02c60e6d4c7db9838ef454aad25a813e2fcf59 Mon Sep 17 00:00:00 2001 From: Tony Partridge Date: Fri, 20 Sep 2024 11:10:10 +0100 Subject: [PATCH 16/33] Fix Discord URL --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 56af6b2fb..bbd84aab4 100644 --- a/README.md +++ b/README.md @@ -63,7 +63,7 @@ Instructions in greater detail, but not Trio-specific: # Documentation -[Discord Trio - Server ](https://discord.gg/KepAG6RdYZ) +[Discord Trio - Server ](https://discord.diy-trio.org) [Trio documentation](https://docs.diy-trio.org/en/latest/) From b0f6d41a4bedffd884df45e7ca9abca2c61bbf87 Mon Sep 17 00:00:00 2001 From: Tony Partridge Date: Fri, 20 Sep 2024 11:10:50 +0100 Subject: [PATCH 17/33] Fix Discord URL --- CODE_OF_CONDUCT.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md index fe81f2198..eac055636 100644 --- a/CODE_OF_CONDUCT.md +++ b/CODE_OF_CONDUCT.md @@ -59,7 +59,7 @@ representative at an online or offline event. ## Enforcement Instances of abusive, harassing, or otherwise unacceptable behavior may be -reported to the Discord server admins. Please join our [Discord server](https://discord.gg/dbe5Twav8D) to contact +reported to the Discord server admins. Please join our [Discord server](https://discord.diy-trio.org) to contact them directly for any enforcement issues. All complaints will be reviewed and investigated promptly and fairly. From 4f2eada5534c5cd5e99e1b05480f487d50f93968 Mon Sep 17 00:00:00 2001 From: marionbarker Date: Fri, 20 Sep 2024 08:09:37 -0700 Subject: [PATCH 18/33] update submodule LibreTransmitter: support libre 2 plus european sensors --- LibreTransmitter | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/LibreTransmitter b/LibreTransmitter index c01eba63e..fb83de05e 160000 --- a/LibreTransmitter +++ b/LibreTransmitter @@ -1 +1 @@ -Subproject commit c01eba63e94e9f6f2841a8835680c4e39c61b18d +Subproject commit fb83de05e5505c8d114902077783c460e4ef23f0 From b94606ccdca73df44013f697e34bdc2904967ab9 Mon Sep 17 00:00:00 2001 From: Marc R Kellerman <9411143+mkellerman@users.noreply.github.com> Date: Sun, 22 Sep 2024 11:15:21 -0700 Subject: [PATCH 19/33] fix: use only the lastPathComponent of the script name --- FreeAPS/Sources/APS/OpenAPS/JavaScriptWorker.swift | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/FreeAPS/Sources/APS/OpenAPS/JavaScriptWorker.swift b/FreeAPS/Sources/APS/OpenAPS/JavaScriptWorker.swift index b687ab4c9..d0829319e 100644 --- a/FreeAPS/Sources/APS/OpenAPS/JavaScriptWorker.swift +++ b/FreeAPS/Sources/APS/OpenAPS/JavaScriptWorker.swift @@ -44,7 +44,6 @@ final class JavaScriptWorker { let consoleLog: @convention(block) (String) -> Void = { message in let trimmedMessage = message.trimmingCharacters(in: .whitespacesAndNewlines) if !trimmedMessage.isEmpty { -// debug(.openAPS, "JavaScript log: \(trimmedMessage)") self.consoleLogs.append("\(trimmedMessage)") } } @@ -62,7 +61,7 @@ final class JavaScriptWorker { if outputLogs.isEmpty { return } - if logContext == "prepare/autosens.js" { + if logContext == "autosens.js" { outputLogs = outputLogs.split(separator: "\n").map { logLine in logLine.replacingOccurrences( of: "^[-+=x!]|u\\(|\\)|\\d{1,2}h$", @@ -82,7 +81,7 @@ final class JavaScriptWorker { } @discardableResult func evaluate(script: Script) -> JSValue! { - logContext = script.name + logContext = URL(fileURLWithPath: script.name).lastPathComponent let result = evaluate(string: script.body) outputLogs() return result From d552f6ec2c7718c0c4c1c752846bcddd1497273a Mon Sep 17 00:00:00 2001 From: Tony Partridge Date: Mon, 23 Sep 2024 11:49:29 +0100 Subject: [PATCH 20/33] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index bbd84aab4..28dd24a03 100644 --- a/README.md +++ b/README.md @@ -63,7 +63,7 @@ Instructions in greater detail, but not Trio-specific: # Documentation -[Discord Trio - Server ](https://discord.diy-trio.org) +[Discord Trio - Server ](http://discord.diy-trio.org) [Trio documentation](https://docs.diy-trio.org/en/latest/) From daf67987c1487b5a9d6955d776fdfce01ad79556 Mon Sep 17 00:00:00 2001 From: Tony Partridge Date: Mon, 23 Sep 2024 11:49:57 +0100 Subject: [PATCH 21/33] Update CODE_OF_CONDUCT.md --- CODE_OF_CONDUCT.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md index eac055636..7e89591ef 100644 --- a/CODE_OF_CONDUCT.md +++ b/CODE_OF_CONDUCT.md @@ -59,7 +59,7 @@ representative at an online or offline event. ## Enforcement Instances of abusive, harassing, or otherwise unacceptable behavior may be -reported to the Discord server admins. Please join our [Discord server](https://discord.diy-trio.org) to contact +reported to the Discord server admins. Please join our [Discord server](http://discord.diy-trio.org) to contact them directly for any enforcement issues. All complaints will be reviewed and investigated promptly and fairly. From 410a03186cde790ee11dcc7485c28fe5694a5ec3 Mon Sep 17 00:00:00 2001 From: marionbarker Date: Wed, 2 Oct 2024 19:07:57 -0700 Subject: [PATCH 22/33] CGMBLEKit: SHA only, no code change --- CGMBLEKit | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CGMBLEKit b/CGMBLEKit index 15af9cf31..b786e8b55 160000 --- a/CGMBLEKit +++ b/CGMBLEKit @@ -1 +1 @@ -Subproject commit 15af9cf319bff2ac49c361da254ad667461d4687 +Subproject commit b786e8b5531cb08c259103c472dcd6a6752728f8 From 5396a2bd7d56d43d510e5b923fddd6605147ec9d Mon Sep 17 00:00:00 2001 From: marionbarker Date: Wed, 2 Oct 2024 19:08:20 -0700 Subject: [PATCH 23/33] G7SensorKit: Add ONE+ to the display name --- G7SensorKit | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/G7SensorKit b/G7SensorKit index b5e992e21..2be3eb29b 160000 --- a/G7SensorKit +++ b/G7SensorKit @@ -1 +1 @@ -Subproject commit b5e992e211d2ac6224acb105dd97fb484767da72 +Subproject commit 2be3eb29b0a18aa89f8b60281341e46e07d024e5 From 3f5da155da004bf5cf5a9091819c5978f2d3f39d Mon Sep 17 00:00:00 2001 From: marionbarker Date: Wed, 2 Oct 2024 19:09:42 -0700 Subject: [PATCH 24/33] LibreTransmitter: Xcode 16 build speedup, fix notification --- LibreTransmitter | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/LibreTransmitter b/LibreTransmitter index fb83de05e..0848e263c 160000 --- a/LibreTransmitter +++ b/LibreTransmitter @@ -1 +1 @@ -Subproject commit fb83de05e5505c8d114902077783c460e4ef23f0 +Subproject commit 0848e263c119a22fbd8660b5c0e17490ccaad5ab From d95ef4e7055df794c3e19ce0a7ff687b01b06afd Mon Sep 17 00:00:00 2001 From: marionbarker Date: Wed, 2 Oct 2024 19:10:07 -0700 Subject: [PATCH 25/33] LoopKit: Xcode 16 build speedup --- LoopKit | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/LoopKit b/LoopKit index 6d9b19ab7..a5c1d6680 160000 --- a/LoopKit +++ b/LoopKit @@ -1 +1 @@ -Subproject commit 6d9b19ab7e9f749d573fd42f6bcd2ce4c302cf66 +Subproject commit a5c1d668075778a5c2bf9079ca38c4708522ea4e From 8c2c24de901a12b7041ebcfe0c60469173c032b3 Mon Sep 17 00:00:00 2001 From: marionbarker Date: Wed, 2 Oct 2024 19:10:07 -0700 Subject: [PATCH 26/33] OmniBLE: Xcode 16 build speedup; fix/deactivate-sideways-pull --- OmniBLE | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/OmniBLE b/OmniBLE index e39834584..4ad811774 160000 --- a/OmniBLE +++ b/OmniBLE @@ -1 +1 @@ -Subproject commit e39834584548821adf442f13abed0d5cfd237a72 +Subproject commit 4ad811774c09cae208678552dbc20ee6cc9d4f59 From dd3dc5abcab1304f59362b946991fde912b2fe70 Mon Sep 17 00:00:00 2001 From: marionbarker Date: Wed, 2 Oct 2024 19:10:07 -0700 Subject: [PATCH 27/33] OmniKit: Xcode 16 build speedup; fix/deactivate-sideways-pull --- OmniKit | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/OmniKit b/OmniKit index 849dc7abc..01bc59889 160000 --- a/OmniKit +++ b/OmniKit @@ -1 +1 @@ -Subproject commit 849dc7abc821728dae7e064176a409e6ceb0dadd +Subproject commit 01bc59889b9216737942ea3f0cab22f6a6c4a0e8 From ca463b97b84f839335920ccd035a820ed6461cf2 Mon Sep 17 00:00:00 2001 From: marionbarker Date: Thu, 3 Oct 2024 10:55:52 -0700 Subject: [PATCH 28/33] LibreTransmitter: SHA only, no code change --- LibreTransmitter | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/LibreTransmitter b/LibreTransmitter index 0848e263c..0f6d11621 160000 --- a/LibreTransmitter +++ b/LibreTransmitter @@ -1 +1 @@ -Subproject commit 0848e263c119a22fbd8660b5c0e17490ccaad5ab +Subproject commit 0f6d116213b7e4c2b54a3be11c83504f6315a608 From d12357aaf3f4f881d92761b2ebab529214717ebe Mon Sep 17 00:00:00 2001 From: marionbarker Date: Mon, 7 Oct 2024 14:54:48 -0700 Subject: [PATCH 29/33] LibreTransmitter: update SHA, no code change --- LibreTransmitter | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/LibreTransmitter b/LibreTransmitter index 0f6d11621..a230b91a3 160000 --- a/LibreTransmitter +++ b/LibreTransmitter @@ -1 +1 @@ -Subproject commit 0f6d116213b7e4c2b54a3be11c83504f6315a608 +Subproject commit a230b91a3d30c7b0d4ffbd240234b34cbaf354b1 From 48e2fd91bacb99d0782ee81e88801e1a65a19cd2 Mon Sep 17 00:00:00 2001 From: marionbarker Date: Mon, 7 Oct 2024 15:01:56 -0700 Subject: [PATCH 30/33] LoopKit: improve visibility of items to select --- LoopKit | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/LoopKit b/LoopKit index a5c1d6680..edb69560c 160000 --- a/LoopKit +++ b/LoopKit @@ -1 +1 @@ -Subproject commit a5c1d668075778a5c2bf9079ca38c4708522ea4e +Subproject commit edb69560cb921a8848ea0a450c89bd26cbe54046 From 3acfe1e2ca2444317923e6fd0834086718f6641b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B8rn=20Inge=20Berg?= Date: Thu, 10 Oct 2024 11:09:28 +0200 Subject: [PATCH 31/33] issue #40 : update glucose units when creating manager --- FreeAPS/Sources/APS/FetchGlucoseManager.swift | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/FreeAPS/Sources/APS/FetchGlucoseManager.swift b/FreeAPS/Sources/APS/FetchGlucoseManager.swift index 333b4ef71..7b6f44c78 100644 --- a/FreeAPS/Sources/APS/FetchGlucoseManager.swift +++ b/FreeAPS/Sources/APS/FetchGlucoseManager.swift @@ -1,5 +1,6 @@ import Combine import Foundation +import HealthKit import LoopKit import LoopKitUI import SwiftDate @@ -98,6 +99,14 @@ final class BaseFetchGlucoseManager: FetchGlucoseManager, Injectable { settingsManager.settings.uploadGlucose = cgmM.shouldSyncToRemoteService } + private func updateManagerUnits(_ manager: CGMManagerUI?) { + let units = settingsManager.settings.units + let managerName = cgmManager.map { "\(type(of: $0))" } ?? "nil" + let loopkitUnits: HKUnit = units == .mgdL ? .milligramsPerDeciliter : .millimolesPerLiter + print("manager: \(managerName) is changing units to: \(loopkitUnits.description) ") + manager?.unitDidChange(to: loopkitUnits) + } + func updateGlucoseSource(cgmGlucoseSourceType: CGMType, cgmGlucosePluginId: String, newManager: CGMManagerUI?) { // if changed, remove all calibrations if self.cgmGlucoseSourceType != cgmGlucoseSourceType || self.cgmGlucosePluginId != cgmGlucosePluginId { @@ -120,6 +129,8 @@ final class BaseFetchGlucoseManager: FetchGlucoseManager, Injectable { removeCalibrations() } else if self.cgmGlucoseSourceType == .plugin, cgmManager == nil, let rawCGMManager = rawCGMManager { cgmManager = cgmManagerFromRawValue(rawCGMManager) + updateManagerUnits(cgmManager) + } else { saveConfigManager() } @@ -151,7 +162,6 @@ final class BaseFetchGlucoseManager: FetchGlucoseManager, Injectable { else { return nil } - return Manager.init(rawState: rawState) } From f797d6f2ff405a33ba4aa81810cb9252d4aaf21d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B8rn=20Inge=20Berg?= Date: Thu, 10 Oct 2024 11:11:34 +0200 Subject: [PATCH 32/33] issue #40 : update manager glucose units when changing trio preferences --- .../PreferencesEditor/PreferencesEditorDataFlow.swift | 1 + .../PreferencesEditor/PreferencesEditorProvider.swift | 11 +++++++++++ .../PreferencesEditorStateModel.swift | 1 + 3 files changed, 13 insertions(+) diff --git a/FreeAPS/Sources/Modules/PreferencesEditor/PreferencesEditorDataFlow.swift b/FreeAPS/Sources/Modules/PreferencesEditor/PreferencesEditorDataFlow.swift index 1bbd54d6c..0915350f2 100644 --- a/FreeAPS/Sources/Modules/PreferencesEditor/PreferencesEditorDataFlow.swift +++ b/FreeAPS/Sources/Modules/PreferencesEditor/PreferencesEditorDataFlow.swift @@ -109,6 +109,7 @@ protocol PreferencesEditorProvider: Provider { var preferences: Preferences { get } func savePreferences(_ preferences: Preferences) func migrateUnits() + func updateManagerUnits() } protocol PreferencesSettable: AnyObject { diff --git a/FreeAPS/Sources/Modules/PreferencesEditor/PreferencesEditorProvider.swift b/FreeAPS/Sources/Modules/PreferencesEditor/PreferencesEditorProvider.swift index 7e8c63a04..f2a2765e1 100644 --- a/FreeAPS/Sources/Modules/PreferencesEditor/PreferencesEditorProvider.swift +++ b/FreeAPS/Sources/Modules/PreferencesEditor/PreferencesEditorProvider.swift @@ -1,8 +1,10 @@ import Foundation +import HealthKit extension PreferencesEditor { final class Provider: BaseProvider, PreferencesEditorProvider { @Injected() private var settingsManager: SettingsManager! + @Injected() var fetchGlucoseManager: FetchGlucoseManager! private let processQueue = DispatchQueue(label: "PreferencesEditorProvider.processQueue") var preferences: Preferences { @@ -17,6 +19,15 @@ extension PreferencesEditor { } } + func updateManagerUnits() { + var manager = fetchGlucoseManager.cgmManager + let managerName = manager.map { "\(type(of: $0))" } ?? "nil" + let units = settingsManager.settings.units + let loopkitUnits: HKUnit = units == .mgdL ? .milligramsPerDeciliter : .millimolesPerLiter + print("manager: \(managerName) is changing units to: \(loopkitUnits.description) ") + manager?.unitDidChange(to: loopkitUnits) + } + func migrateUnits() { migrateTargets() migrateISF() diff --git a/FreeAPS/Sources/Modules/PreferencesEditor/PreferencesEditorStateModel.swift b/FreeAPS/Sources/Modules/PreferencesEditor/PreferencesEditorStateModel.swift index d28869fb5..01175ffb7 100644 --- a/FreeAPS/Sources/Modules/PreferencesEditor/PreferencesEditorStateModel.swift +++ b/FreeAPS/Sources/Modules/PreferencesEditor/PreferencesEditorStateModel.swift @@ -16,6 +16,7 @@ extension PreferencesEditor { subscribeSetting(\.units, on: $unitsIndex.map { $0 == 0 ? GlucoseUnits.mgdL : .mmolL }) { unitsIndex = $0 == .mgdL ? 0 : 1 } didSet: { [weak self] _ in + self?.provider.updateManagerUnits() self?.provider.migrateUnits() } From c8e66a6e54c2b9a58736a36c30e442c7867f5d6d Mon Sep 17 00:00:00 2001 From: Sjoerd Bozon Date: Fri, 18 Oct 2024 15:51:27 +0200 Subject: [PATCH 33/33] bump version to 0.2.2 --- Config.xcconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Config.xcconfig b/Config.xcconfig index 5d125fdcb..50a431025 100644 --- a/Config.xcconfig +++ b/Config.xcconfig @@ -1,5 +1,5 @@ APP_DISPLAY_NAME = Trio -APP_VERSION = 0.2.1 +APP_VERSION = 0.2.2 APP_BUILD_NUMBER = 1 COPYRIGHT_NOTICE = DEVELOPER_TEAM = ##TEAM_ID##