From a6aa05b110251470f3e0cbe701bde8b5a91ea6c6 Mon Sep 17 00:00:00 2001 From: Carlos Rafael Giani Date: Sat, 25 Feb 2023 17:07:43 +0100 Subject: [PATCH 01/17] Add log() overloads to UserEntryLogger that accept a timestamp That way, if the user is already passing the timestamp as part of the log() call's payload (in listValues), mismatches can be avoided by passing the same timestamp as the timestamp arguments in the new overloads. --- .../interfaces/logging/UserEntryLogger.kt | 2 ++ .../implementation/UserEntryLoggerImpl.kt | 14 +++++++++----- .../implementation/pump/PumpSyncImplementation.kt | 8 +++++++- 3 files changed, 18 insertions(+), 6 deletions(-) diff --git a/core/interfaces/src/main/java/info/nightscout/interfaces/logging/UserEntryLogger.kt b/core/interfaces/src/main/java/info/nightscout/interfaces/logging/UserEntryLogger.kt index dd425e5dac..2bd447ca79 100644 --- a/core/interfaces/src/main/java/info/nightscout/interfaces/logging/UserEntryLogger.kt +++ b/core/interfaces/src/main/java/info/nightscout/interfaces/logging/UserEntryLogger.kt @@ -9,6 +9,8 @@ import info.nightscout.interfaces.userEntry.ValueWithUnitMapper interface UserEntryLogger { + fun log(action: Action, source: Sources, note: String?, timestamp: Long, vararg listValues: ValueWithUnit?) + fun log(action: Action, source: Sources, note: String?, timestamp: Long, listValues: List) fun log(action: Action, source: Sources, note: String? = "", vararg listValues: ValueWithUnit?) fun log(action: Action, source: Sources, vararg listValues: ValueWithUnit?) fun log(action: Action, source: Sources, note: String? = "", listValues: List = listOf()) diff --git a/implementation/src/main/java/info/nightscout/implementation/UserEntryLoggerImpl.kt b/implementation/src/main/java/info/nightscout/implementation/UserEntryLoggerImpl.kt index 97730d0da9..41e76ca0d6 100644 --- a/implementation/src/main/java/info/nightscout/implementation/UserEntryLoggerImpl.kt +++ b/implementation/src/main/java/info/nightscout/implementation/UserEntryLoggerImpl.kt @@ -29,16 +29,14 @@ class UserEntryLoggerImpl @Inject constructor( private val compositeDisposable = CompositeDisposable() - override fun log(action: Action, source: Sources, note: String?, vararg listValues: ValueWithUnit?) = log(action, source, note, listValues.toList()) + override fun log(action: Action, source: Sources, note: String?, timestamp: Long, vararg listValues: ValueWithUnit?) = log(action, source, note, timestamp, listValues.toList()) - override fun log(action: Action, source: Sources, vararg listValues: ValueWithUnit?) = log(action, source, "", listValues.toList()) - - override fun log(action: Action, source: Sources, note: String?, listValues: List) { + override fun log(action: Action, source: Sources, note: String?, timestamp: Long, listValues: List) { val filteredValues = listValues.toList().filterNotNull() log( listOf( UserEntry( - timestamp = dateUtil.now(), + timestamp = timestamp, action = action, source = source, note = note ?: "", @@ -48,6 +46,12 @@ class UserEntryLoggerImpl @Inject constructor( ) } + override fun log(action: Action, source: Sources, note: String?, vararg listValues: ValueWithUnit?) = log(action, source, note, listValues.toList()) + + override fun log(action: Action, source: Sources, vararg listValues: ValueWithUnit?) = log(action, source, "", listValues.toList()) + + override fun log(action: Action, source: Sources, note: String?, listValues: List) = log(action, source, note, dateUtil.now(), listValues) + override fun log(entries: List) { compositeDisposable += repository.runTransactionForResult(UserEntryTransaction(entries)) .subscribeOn(aapsSchedulers.io) diff --git a/implementation/src/main/java/info/nightscout/implementation/pump/PumpSyncImplementation.kt b/implementation/src/main/java/info/nightscout/implementation/pump/PumpSyncImplementation.kt index d7c55ffc8a..4281353859 100644 --- a/implementation/src/main/java/info/nightscout/implementation/pump/PumpSyncImplementation.kt +++ b/implementation/src/main/java/info/nightscout/implementation/pump/PumpSyncImplementation.kt @@ -273,7 +273,13 @@ class PumpSyncImplementation @Inject constructor( pumpSerial = pumpSerial ) ) - uel.log(UserEntry.Action.CAREPORTAL, pumpType.source.toDbSource(), note, ValueWithUnit.Timestamp(timestamp), ValueWithUnit.TherapyEventType(type.toDBbEventType())) + uel.log( + action = UserEntry.Action.CAREPORTAL, + source = pumpType.source.toDbSource(), + note = note, + timestamp = timestamp, + ValueWithUnit.Timestamp(timestamp), ValueWithUnit.TherapyEventType(type.toDBbEventType()) + ) repository.runTransactionForResult(InsertIfNewByTimestampTherapyEventTransaction(therapyEvent)) .doOnError { aapsLogger.error(LTag.DATABASE, "Error while saving TherapyEvent", it) From b4cb00ab0be545bed91a450d84fa4801a2b31547 Mon Sep 17 00:00:00 2001 From: Carlos Rafael Giani Date: Sun, 5 Mar 2023 19:50:27 +0100 Subject: [PATCH 02/17] combov2: Remove notes from auto-inserted reservoir and battery changes Unfortunately, even though the notes are informative, they do not fit well in the treatments fragment. The only solution thus far is to remove them from the therapy entries. Fixes https://github.com/nightscout/AndroidAPS/issues/2382 --- .../main/kotlin/info/nightscout/pump/combov2/ComboV2Plugin.kt | 2 -- 1 file changed, 2 deletions(-) diff --git a/pump/combov2/src/main/kotlin/info/nightscout/pump/combov2/ComboV2Plugin.kt b/pump/combov2/src/main/kotlin/info/nightscout/pump/combov2/ComboV2Plugin.kt index 9e595f2d33..bc2043caa1 100644 --- a/pump/combov2/src/main/kotlin/info/nightscout/pump/combov2/ComboV2Plugin.kt +++ b/pump/combov2/src/main/kotlin/info/nightscout/pump/combov2/ComboV2Plugin.kt @@ -872,7 +872,6 @@ class ComboV2Plugin @Inject constructor ( pumpSync.insertTherapyEventIfNewWithTimestamp( timestamp = System.currentTimeMillis(), type = DetailedBolusInfo.EventType.INSULIN_CHANGE, - note = rh.gs(R.string.combov2_note_reservoir_change), pumpId = null, pumpType = PumpType.ACCU_CHEK_COMBO, pumpSerial = serialNumber() @@ -897,7 +896,6 @@ class ComboV2Plugin @Inject constructor ( pumpSync.insertTherapyEventIfNewWithTimestamp( timestamp = System.currentTimeMillis(), type = DetailedBolusInfo.EventType.PUMP_BATTERY_CHANGE, - note = rh.gs(R.string.combov2_note_battery_change), pumpId = null, pumpType = PumpType.ACCU_CHEK_COMBO, pumpSerial = serialNumber() From c81578f7ff630200576788c831701a5048f3277f Mon Sep 17 00:00:00 2001 From: Carlos Rafael Giani Date: Tue, 7 Mar 2023 14:41:11 +0100 Subject: [PATCH 03/17] combov2: Also enable the Refresh button in the Error state --- .../kotlin/info/nightscout/pump/combov2/ComboV2Fragment.kt | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/pump/combov2/src/main/kotlin/info/nightscout/pump/combov2/ComboV2Fragment.kt b/pump/combov2/src/main/kotlin/info/nightscout/pump/combov2/ComboV2Fragment.kt index cc5646e2a9..8439dd4295 100644 --- a/pump/combov2/src/main/kotlin/info/nightscout/pump/combov2/ComboV2Fragment.kt +++ b/pump/combov2/src/main/kotlin/info/nightscout/pump/combov2/ComboV2Fragment.kt @@ -94,8 +94,13 @@ class ComboV2Fragment : DaggerFragment() { binding.combov2DriverState.text = text binding.combov2RefreshButton.isEnabled = when (connectionState) { + // Enable the refresh button if: + // 1. Pump is not connected (to be able to manually initiate a pump status update) + // 2. Pump is suspended (in case the user resumed the pump and wants to update the status in AAPS) + // 3. When an error happened (to manually clear the pumpErrorObserved flag and unlock the loop after dealing with the error) ComboV2Plugin.DriverState.Disconnected, - ComboV2Plugin.DriverState.Suspended -> true + ComboV2Plugin.DriverState.Suspended, + ComboV2Plugin.DriverState.Error-> true else -> false } From 76dec4aad6868eccbb6fe6eeb177be6a85d37c3f Mon Sep 17 00:00:00 2001 From: Carlos Rafael Giani Date: Wed, 8 Mar 2023 17:37:26 +0100 Subject: [PATCH 04/17] comboctl-parser: Also parse text in alert screens This helps with distinguishing the "snooze" and "confirm" screens. Signed-off-by: Carlos Rafael Giani --- .../info/nightscout/comboctl/parser/Parser.kt | 31 +- .../comboctl/parser/TitleStrings.kt | 44 +- .../main/ParsedDisplayFrameStreamTest.kt | 2 +- .../comboctl/main/RTNavigationTest.kt | 4 +- .../nightscout/comboctl/parser/ParserTest.kt | 222 ++- .../comboctl/parser/TestDisplayFrames.kt | 1484 +++++++++++++++++ 6 files changed, 1752 insertions(+), 35 deletions(-) diff --git a/pump/combov2/comboctl/src/commonMain/kotlin/info/nightscout/comboctl/parser/Parser.kt b/pump/combov2/comboctl/src/commonMain/kotlin/info/nightscout/comboctl/parser/Parser.kt index a908ad3e0f..c3bead098c 100644 --- a/pump/combov2/comboctl/src/commonMain/kotlin/info/nightscout/comboctl/parser/Parser.kt +++ b/pump/combov2/comboctl/src/commonMain/kotlin/info/nightscout/comboctl/parser/Parser.kt @@ -81,8 +81,14 @@ sealed class MainScreenContent { * Possible contents of alert (= warning/error) screens. */ sealed class AlertScreenContent { - data class Warning(val code: Int) : AlertScreenContent() - data class Error(val code: Int) : AlertScreenContent() + enum class AlertScreenState { + TO_SNOOZE, + TO_CONFIRM, + HISTORY_ENTRY + } + + data class Warning(val code: Int, val state: AlertScreenState) : AlertScreenContent() + data class Error(val code: Int, val state: AlertScreenState) : AlertScreenContent() /** * "Content" while the alert symbol & code currently are "blinked out". @@ -1139,8 +1145,9 @@ class AlertScreenParser : Parser() { OptionalParser(SingleGlyphTypeParser(Glyph.LargeSymbol::class)), // warning/error symbol OptionalParser(SingleGlyphTypeParser(Glyph.LargeCharacter::class)), // "W" or "E" OptionalParser(IntegerParser()), // warning/error number - OptionalParser(SingleGlyphTypeParser(Glyph.LargeSymbol::class)), // stop symbol (only with errors) - SingleGlyphParser(Glyph.SmallSymbol(SmallSymbol.CHECK)) + OptionalParser(SingleGlyphTypeParser(Glyph.LargeSymbol::class)), // stop symbol (shown in suspended state) + SingleGlyphParser(Glyph.SmallSymbol(SmallSymbol.CHECK)), + StringParser() // snooze / confirm text ) ).parse(parseContext) @@ -1149,16 +1156,23 @@ class AlertScreenParser : Parser() { parseResult as ParseResult.Sequence + val stateString = parseResult.valueAt(4) + val alertState = when (knownScreenTitles[stateString]) { + TitleID.ALERT_TO_SNOOZE -> AlertScreenContent.AlertScreenState.TO_SNOOZE + TitleID.ALERT_TO_CONFIRM -> AlertScreenContent.AlertScreenState.TO_CONFIRM + else -> return ParseResult.Failed + } + return when (parseResult.valueAtOrNull(0)) { Glyph.LargeSymbol(LargeSymbol.WARNING) -> { ParseResult.Value(ParsedScreen.AlertScreen( - AlertScreenContent.Warning(parseResult.valueAt(2)) + AlertScreenContent.Warning(parseResult.valueAt(2), alertState) )) } Glyph.LargeSymbol(LargeSymbol.ERROR) -> { ParseResult.Value(ParsedScreen.AlertScreen( - AlertScreenContent.Error(parseResult.valueAt(2)) + AlertScreenContent.Error(parseResult.valueAt(2), alertState) )) } @@ -1654,7 +1668,10 @@ class MyDataErrorDataScreenParser : Parser() { index = index, totalNumEntries = totalNumEntries, timestamp = timestamp, - alert = if (alertType == SmallSymbol.WARNING) AlertScreenContent.Warning(alertNumber) else AlertScreenContent.Error(alertNumber) + alert = if (alertType == SmallSymbol.WARNING) + AlertScreenContent.Warning(alertNumber, AlertScreenContent.AlertScreenState.HISTORY_ENTRY) + else + AlertScreenContent.Error(alertNumber, AlertScreenContent.AlertScreenState.HISTORY_ENTRY) ) ) } diff --git a/pump/combov2/comboctl/src/commonMain/kotlin/info/nightscout/comboctl/parser/TitleStrings.kt b/pump/combov2/comboctl/src/commonMain/kotlin/info/nightscout/comboctl/parser/TitleStrings.kt index 8b13c08d8e..3e85fb5981 100644 --- a/pump/combov2/comboctl/src/commonMain/kotlin/info/nightscout/comboctl/parser/TitleStrings.kt +++ b/pump/combov2/comboctl/src/commonMain/kotlin/info/nightscout/comboctl/parser/TitleStrings.kt @@ -19,7 +19,9 @@ enum class TitleID { BOLUS_DATA, ERROR_DATA, DAILY_TOTALS, - TBR_DATA + TBR_DATA, + ALERT_TO_SNOOZE, + ALERT_TO_CONFIRM } /** @@ -46,6 +48,8 @@ val knownScreenTitles = mapOf( "ERROR DATA" to TitleID.ERROR_DATA, "DAILY TOTALS" to TitleID.DAILY_TOTALS, "TBR DATA" to TitleID.TBR_DATA, + "TO SNOOZE" to TitleID.ALERT_TO_SNOOZE, + "TO CONFIRM" to TitleID.ALERT_TO_CONFIRM, // Spanish "QUICK INFO" to TitleID.QUICK_INFO, @@ -60,6 +64,8 @@ val knownScreenTitles = mapOf( "DATOS DE ERROR" to TitleID.ERROR_DATA, "TOTALES DIARIOS" to TitleID.DAILY_TOTALS, "DATOS DE DBT" to TitleID.TBR_DATA, + "REPETIR SEÑAL" to TitleID.ALERT_TO_SNOOZE, + "CONFIRMAR" to TitleID.ALERT_TO_CONFIRM, // French "QUICK INFO" to TitleID.QUICK_INFO, @@ -74,6 +80,8 @@ val knownScreenTitles = mapOf( "ERREURS" to TitleID.ERROR_DATA, "QUANTITÉS JOURN." to TitleID.DAILY_TOTALS, "DBT" to TitleID.TBR_DATA, + "RAPPEL TARD" to TitleID.ALERT_TO_SNOOZE, // actually, the text is "RAPPEL + TARD", but the + symbol is ignored to simplify parsing + "POUR CONFIRMER" to TitleID.ALERT_TO_CONFIRM, // Italian "QUICK INFO" to TitleID.QUICK_INFO, @@ -88,6 +96,8 @@ val knownScreenTitles = mapOf( "MEMORIA ALLARMI" to TitleID.ERROR_DATA, "TOTALI GIORNATA" to TitleID.DAILY_TOTALS, "MEMORIA PBT" to TitleID.TBR_DATA, + "RIPETI ALLARME" to TitleID.ALERT_TO_SNOOZE, + "PER CONFERMARE" to TitleID.ALERT_TO_CONFIRM, // Russian "QUICK INFO" to TitleID.QUICK_INFO, @@ -102,6 +112,8 @@ val knownScreenTitles = mapOf( "ДАHHЫE OБ O ИБ." to TitleID.ERROR_DATA, "CУTOЧHЫE ДOЗЫ" to TitleID.DAILY_TOTALS, "ДАHHЫE O BБC" to TitleID.TBR_DATA, + "BЫKЛ. ЗBУK" to TitleID.ALERT_TO_SNOOZE, + "ПOДTBEPДИTЬ" to TitleID.ALERT_TO_CONFIRM, // Turkish "QUICK INFO" to TitleID.QUICK_INFO, @@ -116,6 +128,8 @@ val knownScreenTitles = mapOf( "HATA VERİLERİ" to TitleID.ERROR_DATA, "GÜNLÜK TOPLAM" to TitleID.DAILY_TOTALS, "GBH VERİLERİ" to TitleID.TBR_DATA, + "ERTELE" to TitleID.ALERT_TO_SNOOZE, + "ONAYLA" to TitleID.ALERT_TO_CONFIRM, // Polish "QUICK INFO" to TitleID.QUICK_INFO, @@ -130,6 +144,8 @@ val knownScreenTitles = mapOf( "DANE BŁĘDU" to TitleID.ERROR_DATA, "DZIEN. D. CAŁK." to TitleID.DAILY_TOTALS, "DANE TDP" to TitleID.TBR_DATA, + "ABY WYCISZYĆ" to TitleID.ALERT_TO_SNOOZE, + "ABY POTWIERDZ." to TitleID.ALERT_TO_CONFIRM, // Czech "QUICK INFO" to TitleID.QUICK_INFO, @@ -144,6 +160,8 @@ val knownScreenTitles = mapOf( "ÚDAJE CHYB" to TitleID.ERROR_DATA, "CELK. DEN. DÁVKY" to TitleID.DAILY_TOTALS, "ÚDAJE DBD" to TitleID.TBR_DATA, + "ODLOŽIT" to TitleID.ALERT_TO_SNOOZE, + "POTVRDIT" to TitleID.ALERT_TO_CONFIRM, // Hungarian "QUICK INFO" to TitleID.QUICK_INFO, @@ -158,6 +176,8 @@ val knownScreenTitles = mapOf( "HIBAADATOK" to TitleID.ERROR_DATA, "NAPI TELJES" to TitleID.DAILY_TOTALS, "TBR-ADATOK" to TitleID.TBR_DATA, + "NÉMÍTÁS" to TitleID.ALERT_TO_SNOOZE, + "JÓVÁHAGYÁS" to TitleID.ALERT_TO_CONFIRM, // Slovak "QUICK INFO" to TitleID.QUICK_INFO, @@ -172,6 +192,8 @@ val knownScreenTitles = mapOf( "DÁTA O CHYBÁCH" to TitleID.ERROR_DATA, "SÚČTY DŇA" to TitleID.DAILY_TOTALS, "DBD DÁTA" to TitleID.TBR_DATA, + "STLMI" to TitleID.ALERT_TO_SNOOZE, + "POTVRDI" to TitleID.ALERT_TO_CONFIRM, // Romanian "QUICK INFO" to TitleID.QUICK_INFO, @@ -186,6 +208,8 @@ val knownScreenTitles = mapOf( "DATE EROARE" to TitleID.ERROR_DATA, "TOTALURI ZILNICE" to TitleID.DAILY_TOTALS, "DATE RBT" to TitleID.TBR_DATA, + "OPRIRE SONERIE" to TitleID.ALERT_TO_SNOOZE, + "CONFIRMARE" to TitleID.ALERT_TO_CONFIRM, // Croatian "QUICK INFO" to TitleID.QUICK_INFO, @@ -200,6 +224,8 @@ val knownScreenTitles = mapOf( "PODACI O GREŠK." to TitleID.ERROR_DATA, "UKUPNE DNEV.DOZE" to TitleID.DAILY_TOTALS, "PODACI O PBD-U" to TitleID.TBR_DATA, + "ZA ODGODU" to TitleID.ALERT_TO_SNOOZE, + "ZA POTVRDU" to TitleID.ALERT_TO_CONFIRM, // Dutch "QUICK INFO" to TitleID.QUICK_INFO, @@ -214,6 +240,8 @@ val knownScreenTitles = mapOf( "FOUTENGEGEVENS" to TitleID.ERROR_DATA, "DAGTOTALEN" to TitleID.DAILY_TOTALS, "TBD-GEGEVENS" to TitleID.TBR_DATA, + "UITSTELLEN" to TitleID.ALERT_TO_SNOOZE, + "BEVESTIGEN" to TitleID.ALERT_TO_CONFIRM, // Greek "QUICK INFO" to TitleID.QUICK_INFO, @@ -228,6 +256,8 @@ val knownScreenTitles = mapOf( "ΔEΔOМ. ΣΦАΛМАTΩN" to TitleID.ERROR_DATA, "HМEPHΣIO ΣΥNOΛO" to TitleID.DAILY_TOTALS, "ΔEΔOМENА П.B.P." to TitleID.TBR_DATA, + "ANAΣTOΛH" to TitleID.ALERT_TO_SNOOZE, + "EПIBEBАIΩΣH" to TitleID.ALERT_TO_CONFIRM, // Finnish "QUICK INFO" to TitleID.QUICK_INFO, @@ -242,6 +272,8 @@ val knownScreenTitles = mapOf( "HÄLYTYSTIEDOT" to TitleID.ERROR_DATA, "PÄIV. KOK.ANNOS" to TitleID.DAILY_TOTALS, "TBA - TIEDOT" to TitleID.TBR_DATA, + "ILMOITA MYÖH." to TitleID.ALERT_TO_SNOOZE, + "VAHVISTA" to TitleID.ALERT_TO_CONFIRM, // Norwegian "QUICK INFO" to TitleID.QUICK_INFO, @@ -256,6 +288,8 @@ val knownScreenTitles = mapOf( "FEILDATA" to TitleID.ERROR_DATA, "DØGNMENGDE" to TitleID.DAILY_TOTALS, "MBD-DATA" to TitleID.TBR_DATA, + "FOR Å SLUMRE" to TitleID.ALERT_TO_SNOOZE, + "FOR Å BEKREFTE" to TitleID.ALERT_TO_CONFIRM, // Portuguese "QUICK INFO" to TitleID.QUICK_INFO, @@ -271,6 +305,8 @@ val knownScreenTitles = mapOf( "DADOS DE ERROS" to TitleID.ERROR_DATA, "DADOS DE ALARMES" to TitleID.ERROR_DATA, "TOTAIS DIÁRIOS" to TitleID.DAILY_TOTALS, "DADOS DBT" to TitleID.TBR_DATA, + "PARA SILENCIAR" to TitleID.ALERT_TO_SNOOZE, + "PARA CONFIRMAR" to TitleID.ALERT_TO_CONFIRM, // Swedish "QUICK INFO" to TitleID.QUICK_INFO, @@ -285,6 +321,8 @@ val knownScreenTitles = mapOf( "FELDATA" to TitleID.ERROR_DATA, "DYGNSHISTORIK" to TitleID.DAILY_TOTALS, "TBD DATA" to TitleID.TBR_DATA, + "SNOOZE" to TitleID.ALERT_TO_SNOOZE, + "BEKRÄFTA" to TitleID.ALERT_TO_CONFIRM, // Danish "QUICK INFO" to TitleID.QUICK_INFO, @@ -299,6 +337,8 @@ val knownScreenTitles = mapOf( "FEJLDATA" to TitleID.ERROR_DATA, "DAGLIG TOTAL" to TitleID.DAILY_TOTALS, "MBR-DATA" to TitleID.TBR_DATA, + "FOR AT UDSÆTTE" to TitleID.ALERT_TO_SNOOZE, + "FOR GODKEND" to TitleID.ALERT_TO_CONFIRM, // German "QUICK INFO" to TitleID.QUICK_INFO, @@ -313,6 +353,8 @@ val knownScreenTitles = mapOf( "FEHLERMELDUNGEN" to TitleID.ERROR_DATA, "TAGESGESAMTMENGE" to TitleID.DAILY_TOTALS, "TBR-INFORMATION" to TitleID.TBR_DATA, + "NEU ERINNERN" to TitleID.ALERT_TO_SNOOZE, + "BESTÄTIGEN" to TitleID.ALERT_TO_CONFIRM, // Some pumps came preconfigured with a different quick info name "ACCU CHECK SPIRIT" to TitleID.QUICK_INFO diff --git a/pump/combov2/comboctl/src/jvmTest/kotlin/info/nightscout/comboctl/main/ParsedDisplayFrameStreamTest.kt b/pump/combov2/comboctl/src/jvmTest/kotlin/info/nightscout/comboctl/main/ParsedDisplayFrameStreamTest.kt index 0afd398ceb..b8a83ac9a4 100644 --- a/pump/combov2/comboctl/src/jvmTest/kotlin/info/nightscout/comboctl/main/ParsedDisplayFrameStreamTest.kt +++ b/pump/combov2/comboctl/src/jvmTest/kotlin/info/nightscout/comboctl/main/ParsedDisplayFrameStreamTest.kt @@ -300,7 +300,7 @@ class ParsedDisplayFrameStreamTest { // We expect normal parsing behavior. stream.feedDisplayFrame(testFrameW6CancelTbrWarningScreen) val parsedWarningFrame = stream.getParsedDisplayFrame(processAlertScreens = false) - assertEquals(ParsedScreen.AlertScreen(AlertScreenContent.Warning(6)), parsedWarningFrame!!.parsedScreen) + assertEquals(ParsedScreen.AlertScreen(AlertScreenContent.Warning(6, AlertScreenContent.AlertScreenState.TO_SNOOZE)), parsedWarningFrame!!.parsedScreen) // Feed a W6 screen, but with alert screen detection enabled. // We expect the alert screen to be detected and an exception diff --git a/pump/combov2/comboctl/src/jvmTest/kotlin/info/nightscout/comboctl/main/RTNavigationTest.kt b/pump/combov2/comboctl/src/jvmTest/kotlin/info/nightscout/comboctl/main/RTNavigationTest.kt index 387fd7cd8b..7999bb184e 100644 --- a/pump/combov2/comboctl/src/jvmTest/kotlin/info/nightscout/comboctl/main/RTNavigationTest.kt +++ b/pump/combov2/comboctl/src/jvmTest/kotlin/info/nightscout/comboctl/main/RTNavigationTest.kt @@ -723,7 +723,7 @@ class RTNavigationTest { )), ParsedScreen.BasalRate1ProgrammingMenuScreen, ParsedScreen.BasalRate2ProgrammingMenuScreen, - ParsedScreen.AlertScreen(AlertScreenContent.Warning(code = 6)), + ParsedScreen.AlertScreen(AlertScreenContent.Warning(code = 6, AlertScreenContent.AlertScreenState.TO_SNOOZE)), ParsedScreen.BasalRate3ProgrammingMenuScreen, ParsedScreen.BasalRate4ProgrammingMenuScreen, ParsedScreen.BasalRate5ProgrammingMenuScreen @@ -864,7 +864,7 @@ class RTNavigationTest { ParsedScreen.TemporaryBasalRatePercentageScreen(170, remainingDurationInMinutes = 30), ParsedScreen.TemporaryBasalRatePercentageScreen(170, remainingDurationInMinutes = 30), ParsedScreen.TemporaryBasalRatePercentageScreen(170, remainingDurationInMinutes = 30), - ParsedScreen.AlertScreen(AlertScreenContent.Warning(code = 6)), + ParsedScreen.AlertScreen(AlertScreenContent.Warning(code = 6, AlertScreenContent.AlertScreenState.TO_SNOOZE)), ParsedScreen.TemporaryBasalRatePercentageScreen(160, remainingDurationInMinutes = 30), ParsedScreen.TemporaryBasalRatePercentageScreen(160, remainingDurationInMinutes = 30) )) diff --git a/pump/combov2/comboctl/src/jvmTest/kotlin/info/nightscout/comboctl/parser/ParserTest.kt b/pump/combov2/comboctl/src/jvmTest/kotlin/info/nightscout/comboctl/parser/ParserTest.kt index 3d342a7599..540213c19a 100644 --- a/pump/combov2/comboctl/src/jvmTest/kotlin/info/nightscout/comboctl/parser/ParserTest.kt +++ b/pump/combov2/comboctl/src/jvmTest/kotlin/info/nightscout/comboctl/parser/ParserTest.kt @@ -679,16 +679,16 @@ class ParserTest { assertEquals(ParseResult.Value::class, result::class) val alertScreen = (result as ParseResult.Value<*>).value as ParsedScreen.AlertScreen - assertEquals(AlertScreenContent.Warning(6), alertScreen.content) + assertEquals(AlertScreenContent.Warning(6, AlertScreenContent.AlertScreenState.TO_SNOOZE), alertScreen.content) } @Test fun checkW8CancelBolusWarningScreenParsing() { val testScreens = listOf( Pair(testFrameW8CancelBolusWarningScreen0, AlertScreenContent.None), - Pair(testFrameW8CancelBolusWarningScreen1, AlertScreenContent.Warning(8)), + Pair(testFrameW8CancelBolusWarningScreen1, AlertScreenContent.Warning(8, AlertScreenContent.AlertScreenState.TO_SNOOZE)), Pair(testFrameW8CancelBolusWarningScreen2, AlertScreenContent.None), - Pair(testFrameW8CancelBolusWarningScreen3, AlertScreenContent.Warning(8)) + Pair(testFrameW8CancelBolusWarningScreen3, AlertScreenContent.Warning(8, AlertScreenContent.AlertScreenState.TO_CONFIRM)) ) for (testScreen in testScreens) { @@ -704,7 +704,7 @@ class ParserTest { fun checkE2BatteryEmptyErrorScreenParsing() { val testScreens = listOf( Pair(testFrameE2BatteryEmptyErrorScreen0, AlertScreenContent.None), - Pair(testFrameE2BatteryEmptyErrorScreen1, AlertScreenContent.Error(2)) + Pair(testFrameE2BatteryEmptyErrorScreen1, AlertScreenContent.Error(2, AlertScreenContent.AlertScreenState.TO_CONFIRM)) ) for (testScreen in testScreens) { @@ -963,7 +963,7 @@ class ParserTest { ParsedScreen.MyDataErrorDataScreen( index = 1, totalNumEntries = 30, timestamp = LocalDateTime(year = 0, monthNumber = 1, dayOfMonth = 28, hour = 11, minute = 0, second = 0), - alert = AlertScreenContent.Warning(6) + alert = AlertScreenContent.Warning(6, AlertScreenContent.AlertScreenState.HISTORY_ENTRY) ) ), Pair( @@ -994,7 +994,7 @@ class ParserTest { ParsedScreen.MyDataErrorDataScreen( index = 1, totalNumEntries = 30, timestamp = LocalDateTime(year = 0, monthNumber = 1, dayOfMonth = 28, hour = 11, minute = 0, second = 0), - alert = AlertScreenContent.Warning(6) + alert = AlertScreenContent.Warning(6, AlertScreenContent.AlertScreenState.HISTORY_ENTRY) ) ), Pair( @@ -1025,7 +1025,7 @@ class ParserTest { ParsedScreen.MyDataErrorDataScreen( index = 1, totalNumEntries = 30, timestamp = LocalDateTime(year = 0, monthNumber = 5, dayOfMonth = 11, hour = 21, minute = 56, second = 0), - alert = AlertScreenContent.Warning(7) + alert = AlertScreenContent.Warning(7, AlertScreenContent.AlertScreenState.HISTORY_ENTRY) ) ), Pair( @@ -1056,7 +1056,7 @@ class ParserTest { ParsedScreen.MyDataErrorDataScreen( index = 1, totalNumEntries = 30, timestamp = LocalDateTime(year = 0, monthNumber = 5, dayOfMonth = 11, hour = 21, minute = 56, second = 0), - alert = AlertScreenContent.Warning(7) + alert = AlertScreenContent.Warning(7, AlertScreenContent.AlertScreenState.HISTORY_ENTRY) ) ), Pair( @@ -1087,7 +1087,7 @@ class ParserTest { ParsedScreen.MyDataErrorDataScreen( index = 1, totalNumEntries = 30, timestamp = LocalDateTime(year = 0, monthNumber = 5, dayOfMonth = 11, hour = 21, minute = 56, second = 0), - alert = AlertScreenContent.Warning(7) + alert = AlertScreenContent.Warning(7, AlertScreenContent.AlertScreenState.HISTORY_ENTRY) ) ), Pair( @@ -1118,7 +1118,7 @@ class ParserTest { ParsedScreen.MyDataErrorDataScreen( index = 1, totalNumEntries = 30, timestamp = LocalDateTime(year = 0, monthNumber = 5, dayOfMonth = 11, hour = 21, minute = 56, second = 0), - alert = AlertScreenContent.Warning(7) + alert = AlertScreenContent.Warning(7, AlertScreenContent.AlertScreenState.HISTORY_ENTRY) ) ), Pair( @@ -1149,7 +1149,7 @@ class ParserTest { ParsedScreen.MyDataErrorDataScreen( index = 1, totalNumEntries = 30, timestamp = LocalDateTime(year = 0, monthNumber = 5, dayOfMonth = 11, hour = 21, minute = 56, second = 0), - alert = AlertScreenContent.Warning(7) + alert = AlertScreenContent.Warning(7, AlertScreenContent.AlertScreenState.HISTORY_ENTRY) ) ), Pair( @@ -1180,7 +1180,7 @@ class ParserTest { ParsedScreen.MyDataErrorDataScreen( index = 1, totalNumEntries = 30, timestamp = LocalDateTime(year = 0, monthNumber = 5, dayOfMonth = 11, hour = 21, minute = 56, second = 0), - alert = AlertScreenContent.Warning(7) + alert = AlertScreenContent.Warning(7, AlertScreenContent.AlertScreenState.HISTORY_ENTRY) ) ), Pair( @@ -1211,7 +1211,7 @@ class ParserTest { ParsedScreen.MyDataErrorDataScreen( index = 1, totalNumEntries = 30, timestamp = LocalDateTime(year = 0, monthNumber = 5, dayOfMonth = 11, hour = 21, minute = 56, second = 0), - alert = AlertScreenContent.Warning(7) + alert = AlertScreenContent.Warning(7, AlertScreenContent.AlertScreenState.HISTORY_ENTRY) ) ), Pair( @@ -1242,7 +1242,7 @@ class ParserTest { ParsedScreen.MyDataErrorDataScreen( index = 1, totalNumEntries = 30, timestamp = LocalDateTime(year = 0, monthNumber = 5, dayOfMonth = 11, hour = 21, minute = 56, second = 0), - alert = AlertScreenContent.Warning(7) + alert = AlertScreenContent.Warning(7, AlertScreenContent.AlertScreenState.HISTORY_ENTRY) ) ), Pair( @@ -1273,7 +1273,7 @@ class ParserTest { ParsedScreen.MyDataErrorDataScreen( index = 1, totalNumEntries = 30, timestamp = LocalDateTime(year = 0, monthNumber = 5, dayOfMonth = 11, hour = 21, minute = 56, second = 0), - alert = AlertScreenContent.Warning(7) + alert = AlertScreenContent.Warning(7, AlertScreenContent.AlertScreenState.HISTORY_ENTRY) ) ), Pair( @@ -1304,7 +1304,7 @@ class ParserTest { ParsedScreen.MyDataErrorDataScreen( index = 1, totalNumEntries = 30, timestamp = LocalDateTime(year = 0, monthNumber = 2, dayOfMonth = 1, hour = 1, minute = 6, second = 0), - alert = AlertScreenContent.Warning(1) + alert = AlertScreenContent.Warning(1, AlertScreenContent.AlertScreenState.HISTORY_ENTRY) ) ), Pair( @@ -1335,7 +1335,7 @@ class ParserTest { ParsedScreen.MyDataErrorDataScreen( index = 1, totalNumEntries = 30, timestamp = LocalDateTime(year = 0, monthNumber = 2, dayOfMonth = 1, hour = 1, minute = 6, second = 0), - alert = AlertScreenContent.Warning(1) + alert = AlertScreenContent.Warning(1, AlertScreenContent.AlertScreenState.HISTORY_ENTRY) ) ), Pair( @@ -1366,7 +1366,7 @@ class ParserTest { ParsedScreen.MyDataErrorDataScreen( index = 1, totalNumEntries = 30, timestamp = LocalDateTime(year = 0, monthNumber = 2, dayOfMonth = 1, hour = 1, minute = 6, second = 0), - alert = AlertScreenContent.Warning(1) + alert = AlertScreenContent.Warning(1, AlertScreenContent.AlertScreenState.HISTORY_ENTRY) ) ), Pair( @@ -1397,7 +1397,7 @@ class ParserTest { ParsedScreen.MyDataErrorDataScreen( index = 1, totalNumEntries = 30, timestamp = LocalDateTime(year = 0, monthNumber = 2, dayOfMonth = 1, hour = 1, minute = 6, second = 0), - alert = AlertScreenContent.Warning(1) + alert = AlertScreenContent.Warning(1, AlertScreenContent.AlertScreenState.HISTORY_ENTRY) ) ), Pair( @@ -1428,7 +1428,7 @@ class ParserTest { ParsedScreen.MyDataErrorDataScreen( index = 1, totalNumEntries = 30, timestamp = LocalDateTime(year = 0, monthNumber = 2, dayOfMonth = 1, hour = 1, minute = 6, second = 0), - alert = AlertScreenContent.Warning(1) + alert = AlertScreenContent.Warning(1, AlertScreenContent.AlertScreenState.HISTORY_ENTRY) ) ), Pair( @@ -1459,7 +1459,7 @@ class ParserTest { ParsedScreen.MyDataErrorDataScreen( index = 1, totalNumEntries = 30, timestamp = LocalDateTime(year = 0, monthNumber = 2, dayOfMonth = 1, hour = 1, minute = 6, second = 0), - alert = AlertScreenContent.Warning(1) + alert = AlertScreenContent.Warning(1, AlertScreenContent.AlertScreenState.HISTORY_ENTRY) ) ), Pair( @@ -1490,7 +1490,7 @@ class ParserTest { ParsedScreen.MyDataErrorDataScreen( index = 1, totalNumEntries = 30, timestamp = LocalDateTime(year = 0, monthNumber = 2, dayOfMonth = 1, hour = 1, minute = 6, second = 0), - alert = AlertScreenContent.Warning(1) + alert = AlertScreenContent.Warning(1, AlertScreenContent.AlertScreenState.HISTORY_ENTRY) ) ), Pair( @@ -1521,7 +1521,7 @@ class ParserTest { ParsedScreen.MyDataErrorDataScreen( index = 1, totalNumEntries = 30, timestamp = LocalDateTime(year = 0, monthNumber = 2, dayOfMonth = 1, hour = 1, minute = 6, second = 0), - alert = AlertScreenContent.Warning(1) + alert = AlertScreenContent.Warning(1, AlertScreenContent.AlertScreenState.HISTORY_ENTRY) ) ), Pair( @@ -1552,7 +1552,7 @@ class ParserTest { ParsedScreen.MyDataErrorDataScreen( index = 1, totalNumEntries = 30, timestamp = LocalDateTime(year = 0, monthNumber = 1, dayOfMonth = 28, hour = 11, minute = 0, second = 0), - alert = AlertScreenContent.Warning(6) + alert = AlertScreenContent.Warning(6, AlertScreenContent.AlertScreenState.HISTORY_ENTRY) ) ), Pair( @@ -1595,6 +1595,180 @@ class ParserTest { } } + @Test + fun checkAlertScreenTextParsing() { + val testScreens = listOf( + Pair( + AlertSnoozeAndConfirmScreens.testAlertScreenSnoozeTextEnglishScreen, + AlertScreenContent.Warning(6, AlertScreenContent.AlertScreenState.TO_SNOOZE) + ), + Pair( + AlertSnoozeAndConfirmScreens.testAlertScreenConfirmTextEnglishScreen, + AlertScreenContent.Warning(6, AlertScreenContent.AlertScreenState.TO_CONFIRM) + ), + Pair( + AlertSnoozeAndConfirmScreens.testAlertScreenSnoozeTextSpanishScreen, + AlertScreenContent.Warning(6, AlertScreenContent.AlertScreenState.TO_SNOOZE) + ), + Pair( + AlertSnoozeAndConfirmScreens.testAlertScreenConfirmTextSpanishScreen, + AlertScreenContent.Warning(6, AlertScreenContent.AlertScreenState.TO_CONFIRM) + ), + Pair( + AlertSnoozeAndConfirmScreens.testAlertScreenSnoozeTextFrenchScreen, + AlertScreenContent.Warning(6, AlertScreenContent.AlertScreenState.TO_SNOOZE) + ), + Pair( + AlertSnoozeAndConfirmScreens.testAlertScreenConfirmTextFrenchScreen, + AlertScreenContent.Warning(6, AlertScreenContent.AlertScreenState.TO_CONFIRM) + ), + Pair( + AlertSnoozeAndConfirmScreens.testAlertScreenSnoozeTextItalianScreen, + AlertScreenContent.Warning(6, AlertScreenContent.AlertScreenState.TO_SNOOZE) + ), + Pair( + AlertSnoozeAndConfirmScreens.testAlertScreenConfirmTextItalianScreen, + AlertScreenContent.Warning(6, AlertScreenContent.AlertScreenState.TO_CONFIRM) + ), + Pair( + AlertSnoozeAndConfirmScreens.testAlertScreenSnoozeTextRussianScreen, + AlertScreenContent.Warning(6, AlertScreenContent.AlertScreenState.TO_SNOOZE) + ), + Pair( + AlertSnoozeAndConfirmScreens.testAlertScreenConfirmTextRussianScreen, + AlertScreenContent.Warning(6, AlertScreenContent.AlertScreenState.TO_CONFIRM) + ), + Pair( + AlertSnoozeAndConfirmScreens.testAlertScreenSnoozeTextTurkishScreen, + AlertScreenContent.Warning(6, AlertScreenContent.AlertScreenState.TO_SNOOZE) + ), + Pair( + AlertSnoozeAndConfirmScreens.testAlertScreenConfirmTextTurkishScreen, + AlertScreenContent.Warning(6, AlertScreenContent.AlertScreenState.TO_CONFIRM) + ), + Pair( + AlertSnoozeAndConfirmScreens.testAlertScreenSnoozeTextPolishScreen, + AlertScreenContent.Warning(6, AlertScreenContent.AlertScreenState.TO_SNOOZE) + ), + Pair( + AlertSnoozeAndConfirmScreens.testAlertScreenConfirmTextPolishScreen, + AlertScreenContent.Warning(6, AlertScreenContent.AlertScreenState.TO_CONFIRM) + ), + Pair( + AlertSnoozeAndConfirmScreens.testAlertScreenSnoozeTextCzechScreen, + AlertScreenContent.Warning(6, AlertScreenContent.AlertScreenState.TO_SNOOZE) + ), + Pair( + AlertSnoozeAndConfirmScreens.testAlertScreenConfirmTextCzechScreen, + AlertScreenContent.Warning(6, AlertScreenContent.AlertScreenState.TO_CONFIRM) + ), + Pair( + AlertSnoozeAndConfirmScreens.testAlertScreenSnoozeTextHungarianScreen, + AlertScreenContent.Warning(6, AlertScreenContent.AlertScreenState.TO_SNOOZE) + ), + Pair( + AlertSnoozeAndConfirmScreens.testAlertScreenConfirmTextHungarianScreen, + AlertScreenContent.Warning(6, AlertScreenContent.AlertScreenState.TO_CONFIRM) + ), + Pair( + AlertSnoozeAndConfirmScreens.testAlertScreenSnoozeTextSlovakScreen, + AlertScreenContent.Warning(6, AlertScreenContent.AlertScreenState.TO_SNOOZE) + ), + Pair( + AlertSnoozeAndConfirmScreens.testAlertScreenConfirmTextSlovakScreen, + AlertScreenContent.Warning(6, AlertScreenContent.AlertScreenState.TO_CONFIRM) + ), + Pair( + AlertSnoozeAndConfirmScreens.testAlertScreenSnoozeTextRomanianScreen, + AlertScreenContent.Warning(6, AlertScreenContent.AlertScreenState.TO_SNOOZE) + ), + Pair( + AlertSnoozeAndConfirmScreens.testAlertScreenConfirmTextRomanianScreen, + AlertScreenContent.Warning(6, AlertScreenContent.AlertScreenState.TO_CONFIRM) + ), + Pair( + AlertSnoozeAndConfirmScreens.testAlertScreenSnoozeTextCroatianScreen, + AlertScreenContent.Warning(6, AlertScreenContent.AlertScreenState.TO_SNOOZE) + ), + Pair( + AlertSnoozeAndConfirmScreens.testAlertScreenConfirmTextCroatianScreen, + AlertScreenContent.Warning(6, AlertScreenContent.AlertScreenState.TO_CONFIRM) + ), + Pair( + AlertSnoozeAndConfirmScreens.testAlertScreenSnoozeTextDutchScreen, + AlertScreenContent.Warning(6, AlertScreenContent.AlertScreenState.TO_SNOOZE) + ), + Pair( + AlertSnoozeAndConfirmScreens.testAlertScreenConfirmTextDutchScreen, + AlertScreenContent.Warning(6, AlertScreenContent.AlertScreenState.TO_CONFIRM) + ), + Pair( + AlertSnoozeAndConfirmScreens.testAlertScreenSnoozeTextGreekScreen, + AlertScreenContent.Warning(6, AlertScreenContent.AlertScreenState.TO_SNOOZE) + ), + Pair( + AlertSnoozeAndConfirmScreens.testAlertScreenConfirmTextGreekScreen, + AlertScreenContent.Warning(6, AlertScreenContent.AlertScreenState.TO_CONFIRM) + ), + Pair( + AlertSnoozeAndConfirmScreens.testAlertScreenSnoozeTextFinnishScreen, + AlertScreenContent.Warning(6, AlertScreenContent.AlertScreenState.TO_SNOOZE) + ), + Pair( + AlertSnoozeAndConfirmScreens.testAlertScreenConfirmTextFinnishScreen, + AlertScreenContent.Warning(6, AlertScreenContent.AlertScreenState.TO_CONFIRM) + ), + Pair( + AlertSnoozeAndConfirmScreens.testAlertScreenSnoozeTextNorwegianScreen, + AlertScreenContent.Warning(6, AlertScreenContent.AlertScreenState.TO_SNOOZE) + ), + Pair( + AlertSnoozeAndConfirmScreens.testAlertScreenConfirmTextNorwegianScreen, + AlertScreenContent.Warning(6, AlertScreenContent.AlertScreenState.TO_CONFIRM) + ), + Pair( + AlertSnoozeAndConfirmScreens.testAlertScreenSnoozeTextPortugueseScreen, + AlertScreenContent.Warning(6, AlertScreenContent.AlertScreenState.TO_SNOOZE) + ), + Pair( + AlertSnoozeAndConfirmScreens.testAlertScreenConfirmTextPortugueseScreen, + AlertScreenContent.Warning(6, AlertScreenContent.AlertScreenState.TO_CONFIRM) + ), + Pair( + AlertSnoozeAndConfirmScreens.testAlertScreenSnoozeTextSwedishScreen, + AlertScreenContent.Warning(6, AlertScreenContent.AlertScreenState.TO_SNOOZE) + ), + Pair( + AlertSnoozeAndConfirmScreens.testAlertScreenConfirmTextSwedishScreen, + AlertScreenContent.Warning(6, AlertScreenContent.AlertScreenState.TO_CONFIRM) + ), + Pair( + AlertSnoozeAndConfirmScreens.testAlertScreenSnoozeTextDanishScreen, + AlertScreenContent.Warning(6, AlertScreenContent.AlertScreenState.TO_SNOOZE) + ), + Pair( + AlertSnoozeAndConfirmScreens.testAlertScreenConfirmTextDanishScreen, + AlertScreenContent.Warning(6, AlertScreenContent.AlertScreenState.TO_CONFIRM) + ), + Pair( + AlertSnoozeAndConfirmScreens.testAlertScreenSnoozeTextGermanScreen, + AlertScreenContent.Warning(6, AlertScreenContent.AlertScreenState.TO_SNOOZE) + ), + Pair( + AlertSnoozeAndConfirmScreens.testAlertScreenConfirmTextGermanScreen, + AlertScreenContent.Warning(6, AlertScreenContent.AlertScreenState.TO_CONFIRM) + ), + ) + + for (testScreen in testScreens) { + val testContext = TestContext(testScreen.first, 0, skipTitleString = true) + val result = AlertScreenParser().parse(testContext.parseContext) + + assertEquals(ParseResult.Value::class, result::class) + val alertScreen = (result as ParseResult.Value<*>).value as ParsedScreen.AlertScreen + assertEquals(testScreen.second, alertScreen.content) + } + } @Test fun checkToplevelScreenParsing() { val testScreens = listOf( diff --git a/pump/combov2/comboctl/src/jvmTest/kotlin/info/nightscout/comboctl/parser/TestDisplayFrames.kt b/pump/combov2/comboctl/src/jvmTest/kotlin/info/nightscout/comboctl/parser/TestDisplayFrames.kt index 73eabc7362..7da7090adc 100644 --- a/pump/combov2/comboctl/src/jvmTest/kotlin/info/nightscout/comboctl/parser/TestDisplayFrames.kt +++ b/pump/combov2/comboctl/src/jvmTest/kotlin/info/nightscout/comboctl/parser/TestDisplayFrames.kt @@ -9712,3 +9712,1487 @@ val testMyDataBolusDataGermanScreen = makeDisplayFrame(arrayOf( " ███ ███ ██ ███ █ █ █ █ █ ███████ ███ ███ ██ ███ ███ ", " " )) + +object AlertSnoozeAndConfirmScreens { + + val testAlertScreenSnoozeTextEnglishScreen = makeDisplayFrame( + arrayOf( + "█████ ████ ████ ███ █ █ █ ███ █████ █ █ █████ ███ ", + " █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + " █ █ █ █ █ █ █ █ ██ █ █ █ █ █ █ █ █ ", + " █ ████ ████ █ █████ █ █ █ █ ████ █ █ ████ █ █ ", + " █ █ █ █ █ █ █ █ █ ██ █ █ █ █ █ █ █ ", + " █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + " █ ████ █ █ ███ █ █ █ █ ███ █████ █████ █████ █████ ███ ", + " ", + " ██ ██ ██ ███ ████████ ", + " ████ ██ ██ ██ ██████████ ", + " █ █ ██ ██ ██ ████████████ ", + " ██ ██ ██ ██ ██ ██████████████ ", + " █ █ ██ ██ ██ ██ ████████████████ ", + " ██ ██ ██ ██ ██ ██ ██ █ █ █ █ ██ ", + " █ ██ █ ██ ██ ██ ██████ █ ███ ██ █ █ █ █ ", + " ██ ██ ██ ██ ██ ██ ███ ██ █ ██ ██ █ █ ██ ", + " █ ██ █ ██ ██ ██ ██ ██ ██ ██ ██ █ █ ███ ", + " ██ ██ ██ ██ ██ ██ ██ ██ █ ██ ██ █ ███ ", + " █ █ ██ ██ ██ ██ ██ ████████████████ ", + " ██ ██ ██ ██ ████ ██ ██ ██ ██████████████ ", + " █ █ ██████████ ██ ██ ████████████ ", + " ████████████████ ███ ███ ██ ██ ██████████ ", + " ███████████████ █ █ ████ ████████ ", + " ", + " ", + " █ █████ ███ ████ █ █ ███ ███ █████ █████ ", + " ██ █ █ █ █ █ █ █ █ █ █ █ █ ", + "█ ██ █ █ █ █ ██ █ █ █ █ █ █ █ ", + "███ █ █ █ ███ █ █ █ █ █ █ █ █ ████ ", + " █ █ █ █ █ █ ██ █ █ █ █ █ █ ", + " █ █ █ █ █ █ █ █ █ █ █ █ ", + " █ ███ ████ █ █ ███ ███ █████ █████ " + ) + ) + + val testAlertScreenConfirmTextEnglishScreen = makeDisplayFrame( + arrayOf( + "█████ ████ ████ ███ █ █ █ ███ █████ █ █ █████ ███ ", + " █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + " █ █ █ █ █ █ █ █ ██ █ █ █ █ █ █ █ █ ", + " █ ████ ████ █ █████ █ █ █ █ ████ █ █ ████ █ █ ", + " █ █ █ █ █ █ █ █ █ ██ █ █ █ █ █ █ █ ", + " █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + " █ ████ █ █ ███ █ █ █ █ ███ █████ █████ █████ █████ ███ ", + " ", + " ██ ██ ██ ███ ████████ ", + " ████ ██ ██ ██ ██████████ ", + " █ █ ██ ██ ██ ████████████ ", + " ██ ██ ██ ██ ██ ██████████████ ", + " █ █ ██ ██ ██ ██ ████████████████ ", + " ██ ██ ██ ██ ██ ██ ██ █ █ █ █ ██ ", + " █ ██ █ ██ ██ ██ ██████ █ ███ ██ █ █ █ █ ", + " ██ ██ ██ ██ ██ ██ ███ ██ █ ██ ██ █ █ ██ ", + " █ ██ █ ██ ██ ██ ██ ██ ██ ██ ██ █ █ ███ ", + " ██ ██ ██ ██ ██ ██ ██ ██ █ ██ ██ █ ███ ", + " █ █ ██ ██ ██ ██ ██ ████████████████ ", + " ██ ██ ██ ██ ████ ██ ██ ██ ██████████████ ", + " █ █ ██████████ ██ ██ ████████████ ", + " ████████████████ ███ ███ ██ ██ ██████████ ", + " ███████████████ █ █ ████ ████████ ", + " ", + " ", + " █ █████ ███ ███ ███ █ █ █████ ███ ████ █ █ ", + " ██ █ █ █ █ █ █ █ █ █ █ █ █ █ ██ ██ ", + "█ ██ █ █ █ █ █ █ ██ █ █ █ █ █ █ █ █ ", + "███ █ █ █ █ █ █ █ █ █ ████ █ ████ █ █ █ ", + " █ █ █ █ █ █ █ █ ██ █ █ █ █ █ █ ", + " █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + " █ ███ ███ ███ █ █ █ ███ █ █ █ █ " + ) + ) + + val testAlertScreenSnoozeTextSpanishScreen = makeDisplayFrame( + arrayOf( + "███ ████ █████ ███ █ █ █ ███ █████ █ █ ███ █ ", + "█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + "█ █ █ █ █ █ █ █ ██ █ █ █ █ █ █ █ █ █ █ ", + "█ █ ████ █ █ █████ █ █ █ █ ████ █ █████ █ █ █████ ", + "█ █ █ █ █ █ █ █ █ ██ █ █ █ █ █ █ █ █ █ ", + "█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + "███ ████ █ ███ █ █ █ █ ███ █████ █████ █ █ ███ █ █ ", + " ", + " ██ ██ ██ ███ ████████ ", + " ████ ██ ██ ██ ██████████ ", + " █ █ ██ ██ ██ ████████████ ", + " ██ ██ ██ ██ ██ ██████████████ ", + " █ █ ██ ██ ██ ██ ████████████████ ", + " ██ ██ ██ ██ ██ ██ ██ █ █ █ █ ██ ", + " █ ██ █ ██ ██ ██ ██████ █ ███ ██ █ █ █ █ ", + " ██ ██ ██ ██ ██ ██ ███ ██ █ ██ ██ █ █ ██ ", + " █ ██ █ ██ ██ ██ ██ ██ ██ ██ ██ █ █ ███ ", + " ██ ██ ██ ██ ██ ██ ██ ██ █ ██ ██ █ ███ ", + " █ █ ██ ██ ██ ██ ██ ████████████████ ", + " ██ ██ ██ ██ ████ ██ ██ ██ ██████████████ ", + " █ █ ██████████ ██ ██ ████████████ ", + " ████████████████ ███ ███ ██ ██ ██████████ ", + " ███████████████ █ █ ████ ████████ ", + " ", + " ", + " █ ████ █████ ████ █████ █████ ███ ████ ████ █████ █ █ █ █ ", + " ██ █ █ █ █ █ █ █ █ █ █ █ █ █ ██ █ █ █ ", + "█ ██ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + "███ ████ ████ ████ ████ █ █ ████ ███ ████ ██ █ █████ █ ", + " █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + " █ █ █ █ █ █ █ █ █ █ █ █ ██ █ █ █ ", + " █ █ █████ █ █████ █ ███ █ █ ████ █████ █ █ █ █ █████ " + ) + ) + + val testAlertScreenConfirmTextSpanishScreen = makeDisplayFrame( + arrayOf( + "███ ████ █████ ███ █ █ █ ███ █████ █ █ ███ █ ", + "█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + "█ █ █ █ █ █ █ █ ██ █ █ █ █ █ █ █ █ █ █ ", + "█ █ ████ █ █ █████ █ █ █ █ ████ █ █████ █ █ █████ ", + "█ █ █ █ █ █ █ █ █ ██ █ █ █ █ █ █ █ █ █ ", + "█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + "███ ████ █ ███ █ █ █ █ ███ █████ █████ █ █ ███ █ █ ", + " ", + " ██ ██ ██ ███ ████████ ", + " ████ ██ ██ ██ ██████████ ", + " █ █ ██ ██ ██ ████████████ ", + " ██ ██ ██ ██ ██ ██████████████ ", + " █ █ ██ ██ ██ ██ ████████████████ ", + " ██ ██ ██ ██ ██ ██ ██ █ █ █ █ ██ ", + " █ ██ █ ██ ██ ██ ██████ █ ███ ██ █ █ █ █ ", + " ██ ██ ██ ██ ██ ██ ███ ██ █ ██ ██ █ █ ██ ", + " █ ██ █ ██ ██ ██ ██ ██ ██ ██ ██ █ █ ███ ", + " ██ ██ ██ ██ ██ ██ ██ ██ █ ██ ██ █ ███ ", + " █ █ ██ ██ ██ ██ ██ ████████████████ ", + " ██ ██ ██ ██ ████ ██ ██ ██ ██████████████ ", + " █ █ ██████████ ██ ██ ████████████ ", + " ████████████████ ███ ███ ██ ██ ██████████ ", + " ███████████████ █ █ ████ ████████ ", + " ", + " ", + " █ ███ ███ █ █ █████ ███ ████ █ █ █ ████ ", + " ██ █ █ █ █ █ █ █ █ █ █ ██ ██ █ █ █ █ ", + "█ ██ █ █ █ ██ █ █ █ █ █ █ █ █ █ █ █ █ ", + "███ █ █ █ █ █ █ ████ █ ████ █ █ █ █████ ████ ", + " █ █ █ █ █ ██ █ █ █ █ █ █ █ █ █ █ ", + " █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + " ███ ███ █ █ █ ███ █ █ █ █ █ █ █ █ " + ) + ) + + val testAlertScreenSnoozeTextFrenchScreen = makeDisplayFrame( + arrayOf( + "███ ████ █████ █ █ █ █ █ █ █ █ █ ", + "█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + "█ █ █ █ █ █ █ ██ █ ██ █ █ █ █ █████ ", + "█ █ ████ █ █████ █ █ █ █ █ █ █ █ █ █ ", + "█ █ █ █ █ █ █ █ ██ █ ██ █ █ █ ████ ", + "█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + "███ ████ █ █ █ █ █ █ █ ███ █████ █████ ", + " ", + " ██ ██ ██ ███ ████████ ", + " ████ ██ ██ ██ ██████████ ", + " █ █ ██ ██ ██ ████████████ ", + " ██ ██ ██ ██ ██ ██████████████ ", + " █ █ ██ ██ ██ ██ ████████████████ ", + " ██ ██ ██ ██ ██ ██ ██ █ █ █ █ ██ ", + " █ ██ █ ██ ██ ██ ██████ █ ███ ██ █ █ █ █ ", + " ██ ██ ██ ██ ██ ██ ███ ██ █ ██ ██ █ █ ██ ", + " █ ██ █ ██ ██ ██ ██ ██ ██ ██ ██ █ █ ███ ", + " ██ ██ ██ ██ ██ ██ ██ ██ █ ██ ██ █ ███ ", + " █ █ ██ ██ ██ ██ ██ ████████████████ ", + " ██ ██ ██ ██ ████ ██ ██ ██ ██████████████ ", + " █ █ ██████████ ██ ██ ████████████ ", + " ████████████████ ███ ███ ██ ██ ██████████ ", + " ███████████████ █ █ ████ ████████ ", + " ", + " ", + " █ ████ █ ████ ████ █████ █ █████ █ ████ ███ ", + " ██ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + "█ ██ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + "███ ████ █████ ████ ████ ████ █ █████ █ █████ ████ █ █ ", + " █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + " █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + " █ █ █ █ █ █ █████ █████ █ █ █ █ █ ███ " + ) + ) + + val testAlertScreenConfirmTextFrenchScreen = makeDisplayFrame( + arrayOf( + "███ ████ █████ █ █ █ █ █ █ █ █ █ ", + "█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + "█ █ █ █ █ █ █ ██ █ ██ █ █ █ █ █████ ", + "█ █ ████ █ █████ █ █ █ █ █ █ █ █ █ █ ", + "█ █ █ █ █ █ █ █ ██ █ ██ █ █ █ ████ ", + "█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + "███ ████ █ █ █ █ █ █ █ ███ █████ █████ ", + " ", + " ██ ██ ██ ███ ████████ ", + " ████ ██ ██ ██ ██████████ ", + " █ █ ██ ██ ██ ████████████ ", + " ██ ██ ██ ██ ██ ██████████████ ", + " █ █ ██ ██ ██ ██ ████████████████ ", + " ██ ██ ██ ██ ██ ██ ██ █ █ █ █ ██ ", + " █ ██ █ ██ ██ ██ ██████ █ ███ ██ █ █ █ █ ", + " ██ ██ ██ ██ ██ ██ ███ ██ █ ██ ██ █ █ ██ ", + " █ ██ █ ██ ██ ██ ██ ██ ██ ██ ██ █ █ ███ ", + " ██ ██ ██ ██ ██ ██ ██ ██ █ ██ ██ █ ███ ", + " █ █ ██ ██ ██ ██ ██ ████████████████ ", + " ██ ██ ██ ██ ████ ██ ██ ██ ██████████████ ", + " █ █ ██████████ ██ ██ ████████████ ", + " ████████████████ ███ ███ ██ ██ ██████████ ", + " ███████████████ █ █ ████ ████████ ", + " ", + " ", + " █ ████ ███ █ █ ████ ███ ███ █ █ █████ ███ ████ █ █ █████ ████ ", + " ██ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ██ ██ █ █ █ ", + "█ ██ █ █ █ █ █ █ █ █ █ █ █ ██ █ █ █ █ █ █ █ █ █ █ █ ", + "███ ████ █ █ █ █ ████ █ █ █ █ █ █ ████ █ ████ █ █ █ ████ ████ ", + " █ █ █ █ █ █ █ █ █ █ █ █ ██ █ █ █ █ █ █ █ █ █ ", + " █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + " █ ███ ███ █ █ ███ ███ █ █ █ ███ █ █ █ █ █████ █ █ " + ) + ) + + val testAlertScreenSnoozeTextItalianScreen = makeDisplayFrame( + arrayOf( + "████ ████ █████ █ █ █ █ █ █ █ █ █ █ █████ ███ ", + "█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + "█ █ █ █ █ █ █ ██ █ ██ █ █ █ █ █ █ █ █ █ █ ", + "████ ████ █ █████ █ █ █ █ █ █ █ █ █ █ █████ █ █ █ ", + "█ █ █ █ █ █ █ ██ █ ██ █ █ █ █ █ █ █ █ █ ", + "█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + "█ ████ █ █ █ █ █ █ █ ███ █████ █████ █ █ █ ███ ", + " ", + " ██ ██ ██ ███ ", + " ████ ██ ██ ██ ", + " █ █ ██ ██ ██ ", + " ██ ██ ██ ██ ██ ", + " █ █ ██ ██ ██ ██ ", + " ██ ██ ██ ██ ██ ██ ██ ", + " █ ██ █ ██ ██ ██ ██████ ", + " ██ ██ ██ ██ ██ ██ ███ ██ ", + " █ ██ █ ██ ██ ██ ██ ██ ", + " ██ ██ ██ ██ ██ ██ ██ ██ ", + " █ █ ██ ██ ██ ██ ██ ", + " ██ ██ ██ ██ ████ ██ ██ ██ ", + " █ █ ██████████ ██ ██ ", + " ████████████████ ███ ███ ██ ██ ", + " ███████████████ █ █ ████ ", + " ", + " ", + " █ ████ ███ ████ █████ █████ ███ █ █ █ █ ████ █ █ █████ ", + " ██ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ██ ██ █ ", + "█ ██ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + "███ ████ █ ████ ████ █ █ █████ █ █ █████ ████ █ █ █ ████ ", + " █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + " █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + " █ █ ███ █ █████ █ ███ █ █ █████ █████ █ █ █ █ █ █ █████ " + ) + ) + + val testAlertScreenConfirmTextItalianScreen = makeDisplayFrame( + arrayOf( + "████ ████ █████ █ █ █ █ █ █ █ █ █ █ █████ ███ ", + "█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + "█ █ █ █ █ █ █ ██ █ ██ █ █ █ █ █ █ █ █ █ █ ", + "████ ████ █ █████ █ █ █ █ █ █ █ █ █ █ █████ █ █ █ ", + "█ █ █ █ █ █ █ ██ █ ██ █ █ █ █ █ █ █ █ █ ", + "█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + "█ ████ █ █ █ █ █ █ █ ███ █████ █████ █ █ █ ███ ", + " ", + " ██ ██ ██ ███ ", + " ████ ██ ██ ██ ", + " █ █ ██ ██ ██ ", + " ██ ██ ██ ██ ██ ", + " █ █ ██ ██ ██ ██ ", + " ██ ██ ██ ██ ██ ██ ██ ", + " █ ██ █ ██ ██ ██ ██████ ", + " ██ ██ ██ ██ ██ ██ ███ ██ ", + " █ ██ █ ██ ██ ██ ██ ██ ", + " ██ ██ ██ ██ ██ ██ ██ ██ ", + " █ █ ██ ██ ██ ██ ██ ", + " ██ ██ ██ ██ ████ ██ ██ ██ ", + " █ █ ██████████ ██ ██ ", + " ████████████████ ███ ███ ██ ██ ", + " ███████████████ █ █ ████ ", + " ", + " ", + " █ ████ █████ ████ ███ ███ █ █ █████ █████ ████ █ █ █ ████ █████ ", + " ██ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ██ ██ █ █ █ █ █ ", + "█ ██ █ █ █ █ █ █ █ █ ██ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + "███ ████ ████ ████ █ █ █ █ █ █ ████ ████ ████ █ █ █ █████ ████ ████ ", + " █ █ █ █ █ █ █ █ █ ██ █ █ █ █ █ █ █ █ █ █ █ ", + " █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + " █ █████ █ █ ███ ███ █ █ █ █████ █ █ █ █ █ █ █ █ █████ " + ) + ) + + val testAlertScreenSnoozeTextRussianScreen = makeDisplayFrame( + arrayOf( + "████ █████ ███ ███ █████ █ █ █████ █ █ █████ █ █ █ ", + "█ █ █ █ █ █ █ █ ██ ██ █ █ █ █ █ █ █ █ ", + "█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + "████ ████ █ █ █ █ █ █ ████ █████ ████ █████ █ █ ", + "█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █████ ", + "█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + "████ ████ ███ ███ █ █ █ █████ █ █ █████ █ █ █ █ ", + " ", + " ██ ██ ██ ███ ", + " ████ ██ ██ ██ ", + " █ █ ██ ██ ██ ", + " ██ ██ ██ ██ ██ ", + " █ █ ██ ██ ██ ██ ", + " ██ ██ ██ ██ ██ ██ ██ ", + " █ ██ █ ██ ██ ██ ██████ ", + " ██ ██ ██ ██ ██ ██ ███ ██ ", + " █ ██ █ ██ ██ ██ ██ ██ ", + " ██ ██ ██ ██ ██ ██ ██ ██ ", + " █ █ ██ ██ ██ ██ ██ ", + " ██ ██ ██ ██ ████ ██ ██ ██ ", + " █ █ ██████████ ██ ██ ", + " ████████████████ ███ ███ ██ ██ ", + " ███████████████ █ █ ████ ", + " ", + " ", + " █ ████ █ █ █ █ ████ ███ ████ █ █ █ █ ", + " ██ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + "█ ██ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + "███ ████ ██ █ ██ █ █ ██ ████ ███ ██ ", + " █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + " █ █ █ █ █ █ █ █ █ ██ █ █ █ █ █ █ █ ", + " ████ ██ █ █ █ ██ █ ██ ███ ████ █ █ █ " + ) + ) + + val testAlertScreenConfirmTextRussianScreen = makeDisplayFrame( + arrayOf( + "████ █████ ███ ███ █████ █ █ █████ █ █ █████ █ █ █ ", + "█ █ █ █ █ █ █ █ ██ ██ █ █ █ █ █ █ █ █ ", + "█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + "████ ████ █ █ █ █ █ █ ████ █████ ████ █████ █ █ ", + "█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █████ ", + "█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + "████ ████ ███ ███ █ █ █ █████ █ █ █████ █ █ █ █ ", + " ", + " ██ ██ ██ ███ ", + " ████ ██ ██ ██ ", + " █ █ ██ ██ ██ ", + " ██ ██ ██ ██ ██ ", + " █ █ ██ ██ ██ ██ ", + " ██ ██ ██ ██ ██ ██ ██ ", + " █ ██ █ ██ ██ ██ ██████ ", + " ██ ██ ██ ██ ██ ██ ███ ██ ", + " █ ██ █ ██ ██ ██ ██ ██ ", + " ██ ██ ██ ██ ██ ██ ██ ██ ", + " █ █ ██ ██ ██ ██ ██ ", + " ██ ██ ██ ██ ████ ██ ██ ██ ", + " █ █ ██████████ ██ ██ ", + " ████████████████ ███ ███ ██ ██ ", + " ███████████████ █ █ ████ ", + " ", + " ", + " █ █████ ███ ██ █████ ████ █████ ████ ██ █ █ █████ █ ", + " ██ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ██ █ █ ", + "█ ██ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + "███ █ █ █ █ █ █ █ ████ ████ ████ █ █ █ █ █ █ ███ ", + " █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + " █ █ █ █ █████ █ █ █ █ █ █████ ██ █ █ █ █ ", + " █ █ ███ █ █ █ ████ █████ █ █ █ █ █ █ ███ " + ) + ) + + val testAlertScreenSnoozeTextTurkishScreen = makeDisplayFrame( + arrayOf( + " ███ ████ █ █ █ ████ █████ █ █ █████ ███ █ █ ███ █ ", + "█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + "█ █ █ █ █ ███ █ █ █ █ █ █ █ █ █ ███ █ █ █ ███ ", + "█ ███ ████ █████ █ ████ █ █████ █ ████ █ █ █ █ █ █ █ ", + "█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + "█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + " ████ ████ █ █ ███ █ █ █ █ █████ █████ ███ ███ █████ ███ ███ ", + " ", + " ██ ██ ██ ███ ", + " ████ ██ ██ ██ ", + " █ █ ██ ██ ██ ", + " ██ ██ ██ ██ ██ ", + " █ █ ██ ██ ██ ██ ", + " ██ ██ ██ ██ ██ ██ ██ ", + " █ ██ █ ██ ██ ██ ██████ ", + " ██ ██ ██ ██ ██ ██ ███ ██ ", + " █ ██ █ ██ ██ ██ ██ ██ ", + " ██ ██ ██ ██ ██ ██ ██ ██ ", + " █ █ ██ ██ ██ ██ ██ ", + " ██ ██ ██ ██ ████ ██ ██ ██ ", + " █ █ ██████████ ██ ██ ", + " ████████████████ ███ ███ ██ ██ ", + " ███████████████ █ █ ████ ", + " ", + " ", + " █ █████ ████ █████ █████ █ █████ ", + " ██ █ █ █ █ █ █ █ ", + "█ ██ █ █ █ █ █ █ █ ", + "███ ████ ████ █ ████ █ ████ ", + " █ █ █ █ █ █ █ █ ", + " █ █ █ █ █ █ █ ", + " █████ █ █ █ █████ █████ █████ " + ) + ) + + val testAlertScreenConfirmTextTurkishScreen = makeDisplayFrame( + arrayOf( + " ███ ████ █ █ █ ████ █████ █ █ █████ ███ █ █ ███ █ ", + "█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + "█ █ █ █ █ ███ █ █ █ █ █ █ █ █ █ ███ █ █ █ ███ ", + "█ ███ ████ █████ █ ████ █ █████ █ ████ █ █ █ █ █ █ █ ", + "█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + "█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + " ████ ████ █ █ ███ █ █ █ █ █████ █████ ███ ███ █████ ███ ███ ", + " ", + " ██ ██ ██ ███ ", + " ████ ██ ██ ██ ", + " █ █ ██ ██ ██ ", + " ██ ██ ██ ██ ██ ", + " █ █ ██ ██ ██ ██ ", + " ██ ██ ██ ██ ██ ██ ██ ", + " █ ██ █ ██ ██ ██ ██████ ", + " ██ ██ ██ ██ ██ ██ ███ ██ ", + " █ ██ █ ██ ██ ██ ██ ██ ", + " ██ ██ ██ ██ ██ ██ ██ ██ ", + " █ █ ██ ██ ██ ██ ██ ", + " ██ ██ ██ ██ ████ ██ ██ ██ ", + " █ █ ██████████ ██ ██ ", + " ████████████████ ███ ███ ██ ██ ", + " ███████████████ █ █ ████ ", + " ", + " ", + " █ ███ █ █ █ █ █ █ █ ", + " ██ █ █ █ █ █ █ █ █ █ █ █ ", + "█ ██ █ █ ██ █ █ █ █ █ █ █ █ ", + "███ █ █ █ █ █ █████ █ █ █ █████ ", + " █ █ █ █ ██ █ █ █ █ █ █ ", + " █ █ █ █ █ █ █ █ █ █ ", + " ███ █ █ █ █ █ █████ █ █ " + ) + ) + + val testAlertScreenSnoozeTextPolishScreen = makeDisplayFrame( + arrayOf( + " █ █ █ █ █ █ ███ █ █ █ █ █ ███ █████ ███ ████ ", + " █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + "█ █ ██ █ █ █ █ █ █ █ █ █ █ ██ █ █ █ █ █ █ █ █ ", + "█████ █ █ █ █ █ █ █ █ █ █ █ █████ █ █ █ █ █ █ █ █ ████ ", + "█ █ █ ██ █ █ █ █ █ █ █ █ █ █ █ ██ █ █ █ █ █ █ ", + "█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + "█ █ █ █ ███ █████ ███ █ █ █ █ █ █ ███ █ ███ █ ", + " ", + " ██ ██ ██ ███ ", + " ████ ██ ██ ██ ", + " █ █ ██ ██ ██ ", + " ██ ██ ██ ██ ██ ", + " █ █ ██ ██ ██ ██ ", + " ██ ██ ██ ██ ██ ██ ██ ", + " █ ██ █ ██ ██ ██ ██████ ", + " ██ ██ ██ ██ ██ ██ ███ ██ ", + " █ ██ █ ██ ██ ██ ██ ██ ", + " ██ ██ ██ ██ ██ ██ ██ ██ ", + " █ █ ██ ██ ██ ██ ██ ", + " ██ ██ ██ ██ ████ ██ ██ ██ ", + " █ █ ██████████ ██ ██ ", + " ████████████████ ███ ███ ██ ██ ", + " ███████████████ █ █ ████ ", + " ", + " ", + " █ █ ████ █ █ █ █ █ █ ███ ███ ████ █████ █ █ █ ", + " ██ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + "█ ██ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ████ ", + "███ █████ ████ █ █ █ █ █ █ █ █ █ ███ █ █ █ █ ", + " █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + " █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + " █ █ ████ █ █ █ █ ███ ███ ████ █████ █ ████ " + ) + ) + + val testAlertScreenConfirmTextPolishScreen = makeDisplayFrame( + arrayOf( + " █ █ █ █ █ █ ███ █ █ █ █ █ ███ █████ ███ ████ ", + " █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + "█ █ ██ █ █ █ █ █ █ █ █ █ █ ██ █ █ █ █ █ █ █ █ ", + "█████ █ █ █ █ █ █ █ █ █ █ █ █████ █ █ █ █ █ █ █ █ ████ ", + "█ █ █ ██ █ █ █ █ █ █ █ █ █ █ █ ██ █ █ █ █ █ █ ", + "█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + "█ █ █ █ ███ █████ ███ █ █ █ █ █ █ ███ █ ███ █ ", + " ", + " ██ ██ ██ ███ ", + " ████ ██ ██ ██ ", + " █ █ ██ ██ ██ ", + " ██ ██ ██ ██ ██ ", + " █ █ ██ ██ ██ ██ ", + " ██ ██ ██ ██ ██ ██ ██ ", + " █ ██ █ ██ ██ ██ ██████ ", + " ██ ██ ██ ██ ██ ██ ███ ██ ", + " █ ██ █ ██ ██ ██ ██ ██ ", + " ██ ██ ██ ██ ██ ██ ██ ██ ", + " █ █ ██ ██ ██ ██ ██ ", + " ██ ██ ██ ██ ████ ██ ██ ██ ", + " █ █ ██████████ ██ ██ ", + " ████████████████ ███ ███ ██ ██ ", + " ███████████████ █ █ ████ ", + " ", + " ", + " █ █ ████ █ █ ████ ███ █████ █ █ ███ █████ ████ ███ █████ ", + " ██ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + "█ ██ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + "███ █████ ████ █ █ ████ █ █ █ █ █ █ █ ████ ████ █ █ █ ", + " █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + " █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ██ ", + " █ █ ████ █ █ ███ █ █ █ ███ █████ █ █ ███ █████ ██ " + ) + ) + + val testAlertScreenSnoozeTextCzechScreen = makeDisplayFrame( + arrayOf( + "███ ████ ███ █████ ████ █ █ █ █ █████ █ █ █ ", + "█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + "█ █ █ █ █ █ █ █ █ █ █ ████ █ ██ █ █ █ ", + "█ █ ████ █ █ █ ████ █ █ █ ████ █ █ █ █████ ", + "█ █ █ █ █ █ █ █ █ █ █ ███ █ █ ██ █ █ ", + "█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + "███ ████ ███ █████ █ █ ███ ████ █████ █ █ █ █ ", + " ", + " ██ ██ ██ ███ ", + " ████ ██ ██ ██ ", + " █ █ ██ ██ ██ ", + " ██ ██ ██ ██ ██ ", + " █ █ ██ ██ ██ ██ ", + " ██ ██ ██ ██ ██ ██ ██ ", + " █ ██ █ ██ ██ ██ ██████ ", + " ██ ██ ██ ██ ██ ██ ███ ██ ", + " █ ██ █ ██ ██ ██ ██ ██ ", + " ██ ██ ██ ██ ██ ██ ██ ██ ", + " █ █ ██ ██ ██ ██ ██ ", + " ██ ██ ██ ██ ████ ██ ██ ██ ", + " █ █ ██████████ ██ ██ ", + " ████████████████ ███ ███ ██ ██ ", + " ███████████████ █ █ ████ ", + " ", + " ", + " █ ███ ███ █ ███ █ █ ███ █████ ", + " ██ █ █ █ █ █ █ █ █ █ █ ", + "█ ██ █ █ █ █ █ █ █ █████ █ █ ", + "███ █ █ █ █ █ █ █ █ █ █ ", + " █ █ █ █ █ █ █ █ █ █ █ ", + " █ █ █ █ █ █ █ █ █ █ ", + " ███ ███ █████ ███ █████ ███ █ " + ) + ) + + val testAlertScreenConfirmTextCzechScreen = makeDisplayFrame( + arrayOf( + "███ ████ ███ █████ ████ █ █ █ █ █████ █ █ █ ", + "█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + "█ █ █ █ █ █ █ █ █ █ █ ████ █ ██ █ █ █ ", + "█ █ ████ █ █ █ ████ █ █ █ ████ █ █ █ █████ ", + "█ █ █ █ █ █ █ █ █ █ █ ███ █ █ ██ █ █ ", + "█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + "███ ████ ███ █████ █ █ ███ ████ █████ █ █ █ █ ", + " ", + " ██ ██ ██ ███ ", + " ████ ██ ██ ██ ", + " █ █ ██ ██ ██ ", + " ██ ██ ██ ██ ██ ", + " █ █ ██ ██ ██ ██ ", + " ██ ██ ██ ██ ██ ██ ██ ", + " █ ██ █ ██ ██ ██ ██████ ", + " ██ ██ ██ ██ ██ ██ ███ ██ ", + " █ ██ █ ██ ██ ██ ██ ██ ", + " ██ ██ ██ ██ ██ ██ ██ ██ ", + " █ █ ██ ██ ██ ██ ██ ", + " ██ ██ ██ ██ ████ ██ ██ ██ ", + " █ █ ██████████ ██ ██ ", + " ████████████████ ███ ███ ██ ██ ", + " ███████████████ █ █ ████ ", + " ", + " ", + " █ ████ ███ █████ █ █ ████ ███ ███ █████ ", + " ██ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + "█ ██ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + "███ ████ █ █ █ █ █ ████ █ █ █ █ ", + " █ █ █ █ █ █ █ █ █ █ █ █ █ ", + " █ █ █ █ █ █ █ █ █ █ █ █ ", + " █ ███ █ █ █ █ ███ ███ █ " + ) + ) + + val testAlertScreenSnoozeTextHungarianScreen = makeDisplayFrame( + arrayOf( + "█████ ████ ████ █ █ █████ ███ ████ █████ █ █ █ █ ███ █████ ", + " █ █ █ █ █ ██ ██ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + " █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + " █ ████ ████ █ █ █ ████ █ ███ ███ █ █████ ██ █████ █ █ █ ", + " █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + " █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + " █ ████ █ █ █ █ █████ ████ ████ █████ █ █ █ █ █ █ ███ █ ", + " ", + " ██ ██ ██ ███ ", + " ████ ██ ██ ██ ", + " █ █ ██ ██ ██ ", + " ██ ██ ██ ██ ██ ", + " █ █ ██ ██ ██ ██ ", + " ██ ██ ██ ██ ██ ██ ██ ", + " █ ██ █ ██ ██ ██ ██████ ", + " ██ ██ ██ ██ ██ ██ ███ ██ ", + " █ ██ █ ██ ██ ██ ██ ██ ", + " ██ ██ ██ ██ ██ ██ ██ ██ ", + " █ █ ██ ██ ██ ██ ██ ", + " ██ ██ ██ ██ ████ ██ ██ ██ ", + " █ █ ██████████ ██ ██ ", + " ████████████████ ███ ███ ██ ██ ", + " ███████████████ █ █ ████ ", + " ", + " ", + " █ █ █ █ █ █ █ █████ █ ████ ", + " ██ █ █ █ ██ ██ █ █ █ █ ", + "█ ██ ██ █ █████ █ █ █ ███ █ █ █ ", + "███ █ █ █ █ █ █ █ █ █ █ █ ███ ", + " █ █ ██ ████ █ █ █ █ █ █ █ ", + " █ █ █ █ █ █ █ █████ █ ", + " █ █ █████ █ █ ███ █ █ █ ████ " + ) + ) + + val testAlertScreenConfirmTextHungarianScreen = makeDisplayFrame( + arrayOf( + "█████ ████ ████ █ █ █████ ███ ████ █████ █ █ █ █ ███ █████ ", + " █ █ █ █ █ ██ ██ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + " █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + " █ ████ ████ █ █ █ ████ █ ███ ███ █ █████ ██ █████ █ █ █ ", + " █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + " █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + " █ ████ █ █ █ █ █████ ████ ████ █████ █ █ █ █ █ █ ███ █ ", + " ", + " ██ ██ ██ ███ ", + " ████ ██ ██ ██ ", + " █ █ ██ ██ ██ ", + " ██ ██ ██ ██ ██ ", + " █ █ ██ ██ ██ ██ ", + " ██ ██ ██ ██ ██ ██ ██ ", + " █ ██ █ ██ ██ ██ ██████ ", + " ██ ██ ██ ██ ██ ██ ███ ██ ", + " █ ██ █ ██ ██ ██ ██ ██ ", + " ██ ██ ██ ██ ██ ██ ██ ██ ", + " █ █ ██ ██ ██ ██ ██ ", + " ██ ██ ██ ██ ████ ██ ██ ██ ", + " █ █ ██████████ ██ ██ ", + " ████████████████ ███ ███ ██ ██ ", + " ███████████████ █ █ ████ ", + " ", + " ", + " █ ███ █ █ █ █ █ █ █ ███ █ █ █ ████ ", + " ██ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + "█ ██ █ ███ █ █ █ █ █ █ █ █ █ █ █ █ ", + "███ █ █ █ █ █ █ █ █████ █████ █ ███ █ █ █ █ ███ ", + " █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + " █ █ █ █ █ █ █████ █ █ █ █ █ █ █ █████ █ ", + " ██ ███ █ █ █ █ █ █ █ ████ █ █ █ ████ " + ) + ) + + val testAlertScreenSnoozeTextSlovakScreen = makeDisplayFrame( + arrayOf( + "███ ████ ███ █████ ████ █ █ █ █ █████ █ █ █ ", + "█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + "█ █ █ █ █ █ █ █ █ █ █ ████ █ ██ █ █ ", + "█ █ ████ █ █ █ ████ █ █ █ ████ █ █ █ █ █ ", + "█ █ █ █ █ █ █ █ █ █ █ ███ █ █ ██ █ █ ", + "█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █████ ", + "███ ████ ███ █████ █ █ ███ ████ █████ █ █ █ █ ", + " ", + " ██ ██ ██ ███ ", + " ████ ██ ██ ██ ", + " █ █ ██ ██ ██ ", + " ██ ██ ██ ██ ██ ", + " █ █ ██ ██ ██ ██ ", + " ██ ██ ██ ██ ██ ██ ██ ", + " █ ██ █ ██ ██ ██ ██████ ", + " ██ ██ ██ ██ ██ ██ ███ ██ ", + " █ ██ █ ██ ██ ██ ██ ██ ", + " ██ ██ ██ ██ ██ ██ ██ ██ ", + " █ █ ██ ██ ██ ██ ██ ", + " ██ ██ ██ ██ ████ ██ ██ ██ ", + " █ █ ██████████ ██ ██ ", + " ████████████████ ███ ███ ██ ██ ", + " ███████████████ █ █ ████ ", + " ", + " ", + " █ ████ █████ █ █ █ ███ █ █ ", + " ██ █ █ █ ██ ██ █ █ ", + "█ ██ █ █ █ █ █ █ █ █████ ", + "███ ███ █ █ █ █ █ █ █ ", + " █ █ █ █ █ █ █ █ ", + " █ █ █ █ █ █ █ ", + " ████ █ █████ █ █ ███ █ " + ) + ) + + val testAlertScreenConfirmTextSlovakScreen = makeDisplayFrame( + arrayOf( + "███ ████ ███ █████ ████ █ █ █ █ █████ █ █ █ ", + "█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + "█ █ █ █ █ █ █ █ █ █ █ ████ █ ██ █ █ ", + "█ █ ████ █ █ █ ████ █ █ █ ████ █ █ █ █ █ ", + "█ █ █ █ █ █ █ █ █ █ █ ███ █ █ ██ █ █ ", + "█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █████ ", + "███ ████ ███ █████ █ █ ███ ████ █████ █ █ █ █ ", + " ", + " ██ ██ ██ ███ ", + " ████ ██ ██ ██ ", + " █ █ ██ ██ ██ ", + " ██ ██ ██ ██ ██ ", + " █ █ ██ ██ ██ ██ ", + " ██ ██ ██ ██ ██ ██ ██ ", + " █ ██ █ ██ ██ ██ ██████ ", + " ██ ██ ██ ██ ██ ██ ███ ██ ", + " █ ██ █ ██ ██ ██ ██ ██ ", + " ██ ██ ██ ██ ██ ██ ██ ██ ", + " █ █ ██ ██ ██ ██ ██ ", + " ██ ██ ██ ██ ████ ██ ██ ██ ", + " █ █ ██████████ ██ ██ ", + " ████████████████ ███ ███ ██ ██ ", + " ███████████████ █ █ ████ ", + " ", + " ", + " █ ████ ███ █████ █ █ ████ ███ ███ █ █ ", + " ██ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + "█ ██ █ █ █ █ █ █ █ █ █ █ █ █ █████ ", + "███ ████ █ █ █ █ █ ████ █ █ █ █ ", + " █ █ █ █ █ █ █ █ █ █ █ █ █ ", + " █ █ █ █ █ █ █ █ █ █ █ █ ", + " █ ███ █ █ █ █ ███ ███ █ " + ) + ) + + val testAlertScreenSnoozeTextRomanianScreen = makeDisplayFrame( + arrayOf( + "████ ████ █████ █ █ █ █ █ █ █ █████ ", + "█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + "█ █ █ █ █ █ █ ██ █ █ █ █ █ █ █ ", + "████ ████ █ █████ █ █ █ █ █ █ █████ █ ", + "█ █ █ █ █ █ █ █ ██ █ █ █ █ █ █ ", + "█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + "█ █ ████ █ █ █ █ █ ███ █████ █ █ █ ", + " ", + " ██ ██ ██ ███ ", + " ████ ██ ██ ██ ", + " █ █ ██ ██ ██ ", + " ██ ██ ██ ██ ██ ", + " █ █ ██ ██ ██ ██ ", + " ██ ██ ██ ██ ██ ██ ██ ", + " █ ██ █ ██ ██ ██ ██████ ", + " ██ ██ ██ ██ ██ ██ ███ ██ ", + " █ ██ █ ██ ██ ██ ██ ██ ", + " ██ ██ ██ ██ ██ ██ ██ ██ ", + " █ █ ██ ██ ██ ██ ██ ", + " ██ ██ ██ ██ ████ ██ ██ ██ ", + " █ █ ██████████ ██ ██ ", + " ████████████████ ███ ███ ██ ██ ", + " ███████████████ █ █ ████ ", + " ", + " ", + " █ ███ ████ ████ ███ ████ █████ ████ ███ █ █ █████ ████ ███ █████ ", + " ██ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + "█ ██ █ █ █ █ █ █ █ █ █ █ █ █ █ ██ █ █ █ █ █ █ ", + "███ █ █ ████ ████ █ ████ ████ ███ █ █ █ █ █ ████ ████ █ ████ ", + " █ █ █ █ █ █ █ █ █ █ █ █ █ █ ██ █ █ █ █ █ ", + " █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + " ███ █ █ █ ███ █ █ █████ ████ ███ █ █ █████ █ █ ███ █████ " + ) + ) + + val testAlertScreenConfirmTextRomanianScreen = makeDisplayFrame( + arrayOf( + "████ ████ █████ █ █ █ █ █ █ █ █████ ", + "█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + "█ █ █ █ █ █ █ ██ █ █ █ █ █ █ █ ", + "████ ████ █ █████ █ █ █ █ █ █ █████ █ ", + "█ █ █ █ █ █ █ █ ██ █ █ █ █ █ █ ", + "█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + "█ █ ████ █ █ █ █ █ ███ █████ █ █ █ ", + " ", + " ██ ██ ██ ███ ", + " ████ ██ ██ ██ ", + " █ █ ██ ██ ██ ", + " ██ ██ ██ ██ ██ ", + " █ █ ██ ██ ██ ██ ", + " ██ ██ ██ ██ ██ ██ ██ ", + " █ ██ █ ██ ██ ██ ██████ ", + " ██ ██ ██ ██ ██ ██ ███ ██ ", + " █ ██ █ ██ ██ ██ ██ ██ ", + " ██ ██ ██ ██ ██ ██ ██ ██ ", + " █ █ ██ ██ ██ ██ ██ ", + " ██ ██ ██ ██ ████ ██ ██ ██ ", + " █ █ ██████████ ██ ██ ", + " ████████████████ ███ ███ ██ ██ ", + " ███████████████ █ █ ████ ", + " ", + " ", + " █ ███ ███ █ █ █████ ███ ████ █ █ █ ████ █████ ", + " ██ █ █ █ █ █ █ █ █ █ █ ██ ██ █ █ █ █ █ ", + "█ ██ █ █ █ ██ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + "███ █ █ █ █ █ █ ████ █ ████ █ █ █ █████ ████ ████ ", + " █ █ █ █ █ ██ █ █ █ █ █ █ █ █ █ █ █ ", + " █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + " ███ ███ █ █ █ ███ █ █ █ █ █ █ █ █ █████ " + ) + ) + + val testAlertScreenSnoozeTextCroatianScreen = makeDisplayFrame( + arrayOf( + "████ ████ ███ ███ █████ █ █ █ █████ █ █ █ █ ", + "█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + "█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ██ █ █ █ ", + "████ ████ █ █ █ █ █ ██ █████ █ █████ █ █ █ █████ ", + "█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ██ █ █ ", + "█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + "█ ████ ███ ███ █ █ █ █ █ █████ █ █ █ █ █ █ ", + " ", + " ██ ██ ██ ███ ", + " ████ ██ ██ ██ ", + " █ █ ██ ██ ██ ", + " ██ ██ ██ ██ ██ ", + " █ █ ██ ██ ██ ██ ", + " ██ ██ ██ ██ ██ ██ ██ ", + " █ ██ █ ██ ██ ██ ██████ ", + " ██ ██ ██ ██ ██ ██ ███ ██ ", + " █ ██ █ ██ ██ ██ ██ ██ ", + " ██ ██ ██ ██ ██ ██ ██ ██ ", + " █ █ ██ ██ ██ ██ ██ ", + " ██ ██ ██ ██ ████ ██ ██ ██ ", + " █ █ ██████████ ██ ██ ", + " ████████████████ ███ ███ ██ ██ ", + " ███████████████ █ █ ████ ", + " ", + " ", + " █ █████ █ ███ ███ ███ ███ ███ █ █ ", + " ██ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + "█ ██ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + "███ █ █████ █ █ █ █ █ ███ █ █ █ █ █ █ ", + " █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + " █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + " █████ █ █ ███ ███ ████ ███ ███ ███ " + ) + ) + + val testAlertScreenConfirmTextCroatianScreen = makeDisplayFrame( + arrayOf( + "████ ████ ███ ███ █████ █ █ █ █████ █ █ █ █ ", + "█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + "█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ██ █ █ █ ", + "████ ████ █ █ █ █ █ ██ █████ █ █████ █ █ █ █████ ", + "█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ██ █ █ ", + "█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + "█ ████ ███ ███ █ █ █ █ █ █████ █ █ █ █ █ █ ", + " ", + " ██ ██ ██ ███ ", + " ████ ██ ██ ██ ", + " █ █ ██ ██ ██ ", + " ██ ██ ██ ██ ██ ", + " █ █ ██ ██ ██ ██ ", + " ██ ██ ██ ██ ██ ██ ██ ", + " █ ██ █ ██ ██ ██ ██████ ", + " ██ ██ ██ ██ ██ ██ ███ ██ ", + " █ ██ █ ██ ██ ██ ██ ██ ", + " ██ ██ ██ ██ ██ ██ ██ ██ ", + " █ █ ██ ██ ██ ██ ██ ", + " ██ ██ ██ ██ ████ ██ ██ ██ ", + " █ █ ██████████ ██ ██ ", + " ████████████████ ███ ███ ██ ██ ", + " ███████████████ █ █ ████ ", + " ", + " ", + " █ █████ █ ████ ███ █████ █ █ ████ ███ █ █ ", + " ██ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + "█ ██ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + "███ █ █████ ████ █ █ █ █ █ ████ █ █ █ █ ", + " █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + " █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + " █████ █ █ █ ███ █ █ █ █ ███ ███ " + ) + ) + + val testAlertScreenSnoozeTextDutchScreen = makeDisplayFrame( + arrayOf( + "█████ ████ ███ ███ █████ █ █ █ █ █ █ █ █ █████ █████ ████ ███ ", + " █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + " █ █ █ █ █ █ █ █ █ ██ █ ██ █ █ █ █ █ █ █ █ █ █ ", + " █ ████ █ █ █ ███ ████ █████ █ █ █ █ █ █ █ █ █ ████ ████ ████ █ █ ", + " █ █ █ █ █ █ █ █ █ █ █ ██ █ ██ █ █ █ █ █ █ █ █ █ ", + " █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + " █ ████ ███ ████ █████ █ █ █ █ █ █ ███ █████ █████ █████ █ █ ███ ", + " ", + " ██ ██ ██ ███ ", + " ████ ██ ██ ██ ", + " █ █ ██ ██ ██ ", + " ██ ██ ██ ██ ██ ", + " █ █ ██ ██ ██ ██ ", + " ██ ██ ██ ██ ██ ██ ██ ", + " █ ██ █ ██ ██ ██ ██████ ", + " ██ ██ ██ ██ ██ ██ ███ ██ ", + " █ ██ █ ██ ██ ██ ██ ██ ", + " ██ ██ ██ ██ ██ ██ ██ ██ ", + " █ █ ██ ██ ██ ██ ██ ", + " ██ ██ ██ ██ ████ ██ ██ ██ ", + " █ █ ██████████ ██ ██ ", + " ████████████████ ███ ███ ██ ██ ", + " ███████████████ █ █ ████ ", + " ", + " ", + " █ █ █ ███ █████ ████ █████ █████ █ █ █████ █ █ ", + " ██ █ █ █ █ █ █ █ █ █ █ █ █ ", + "█ ██ █ █ █ █ █ █ █ █ █ █ ██ █ ", + "███ █ █ █ █ ███ █ ████ █ █ ████ █ █ █ ", + " █ █ █ █ █ █ █ █ █ █ █ █ ██ ", + " █ █ █ █ █ █ █ █ █ █ █ █ ", + " ███ ███ █ ████ █ █████ █████ █████ █████ █ █ " + ) + ) + + val testAlertScreenConfirmTextDutchScreen = makeDisplayFrame( + arrayOf( + "█████ ████ ███ ███ █████ █ █ █ █ █ █ █ █ █████ █████ ████ ███ ", + " █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + " █ █ █ █ █ █ █ █ █ ██ █ ██ █ █ █ █ █ █ █ █ █ █ ", + " █ ████ █ █ █ ███ ████ █████ █ █ █ █ █ █ █ █ █ ████ ████ ████ █ █ ", + " █ █ █ █ █ █ █ █ █ █ █ ██ █ ██ █ █ █ █ █ █ █ █ █ ", + " █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + " █ ████ ███ ████ █████ █ █ █ █ █ █ ███ █████ █████ █████ █ █ ███ ", + " ", + " ██ ██ ██ ███ ", + " ████ ██ ██ ██ ", + " █ █ ██ ██ ██ ", + " ██ ██ ██ ██ ██ ", + " █ █ ██ ██ ██ ██ ", + " ██ ██ ██ ██ ██ ██ ██ ", + " █ ██ █ ██ ██ ██ ██████ ", + " ██ ██ ██ ██ ██ ██ ███ ██ ", + " █ ██ █ ██ ██ ██ ██ ██ ", + " ██ ██ ██ ██ ██ ██ ██ ██ ", + " █ █ ██ ██ ██ ██ ██ ", + " ██ ██ ██ ██ ████ ██ ██ ██ ", + " █ █ ██████████ ██ ██ ", + " ████████████████ ███ ███ ██ ██ ", + " ███████████████ █ █ ████ ", + " ", + " ", + " █ ████ █████ █ █ █████ ████ █████ ███ ███ █████ █ █ ", + " ██ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + "█ ██ █ █ █ █ █ █ █ █ █ █ █ ██ █ ", + "███ ████ ████ █ █ ████ ███ █ █ █ ███ ████ █ █ █ ", + " █ █ █ █ █ █ █ █ █ █ █ █ █ █ ██ ", + " █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + " ████ █████ █ █████ ████ █ ███ ████ █████ █ █ " + ) + ) + + val testAlertScreenSnoozeTextGreekScreen = makeDisplayFrame( + arrayOf( + " █ █ █ █ █ ████ ███ █████ █ █ █████ ████ ████ ", + " █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + "█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + "█ █ ██ ███ ████ █ █ █ █████ █ █ ████ ████ ", + "█████ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + "█ █ █ █ █ █ █ █ █ █ █ █ █ ██ █ █ ██ █ ██ ", + "█ █ █ █ █ █ ██ ██ █████ █ █ █ █ ██ ████ ██ █ ██ ", + " ", + " ██ ██ ██ ███ ", + " ████ ██ ██ ██ ", + " █ █ ██ ██ ██ ", + " ██ ██ ██ ██ ██ ", + " █ █ ██ ██ ██ ██ ", + " ██ ██ ██ ██ ██ ██ ██ ", + " █ ██ █ ██ ██ ██ ██████ ", + " ██ ██ ██ ██ ██ ██ ███ ██ ", + " █ ██ █ ██ ██ ██ ██ ██ ", + " ██ ██ ██ ██ ██ ██ ██ ██ ", + " █ █ ██ ██ ██ ██ ██ ", + " ██ ██ ██ ██ ████ ██ ██ ██ ", + " █ █ ██████████ ██ ██ ", + " ████████████████ ███ ███ ██ ██ ", + " ███████████████ █ █ ████ ", + " ", + " ", + " █ █ █ █ █ █████ █████ ███ █ █ █ ", + " ██ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + "█ ██ █ █ ██ █ █ █ █ █ █ █ █ █ █ █ ", + "███ █████ █ █ █ █████ █ █ █ █ █ █ █████ ", + " █ █ █ █ ██ █ █ █ █ █ █ █ █ █ █ ", + " █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + " █ █ █ █ █ █ █████ █ ███ █ █ █ █ " + ) + ) + + val testAlertScreenConfirmTextGreekScreen = makeDisplayFrame( + arrayOf( + " █ █ █ █ █ ████ ███ █████ █ █ █████ ████ ████ ", + " █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + "█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + "█ █ ██ ███ ████ █ █ █ █████ █ █ ████ ████ ", + "█████ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + "█ █ █ █ █ █ █ █ █ █ █ █ █ ██ █ █ ██ █ ██ ", + "█ █ █ █ █ █ ██ ██ █████ █ █ █ █ ██ ████ ██ █ ██ ", + " ", + " ██ ██ ██ ███ ", + " ████ ██ ██ ██ ", + " █ █ ██ ██ ██ ", + " ██ ██ ██ ██ ██ ", + " █ █ ██ ██ ██ ██ ", + " ██ ██ ██ ██ ██ ██ ██ ", + " █ ██ █ ██ ██ ██ ██████ ", + " ██ ██ ██ ██ ██ ██ ███ ██ ", + " █ ██ █ ██ ██ ██ ██ ██ ", + " ██ ██ ██ ██ ██ ██ ██ ██ ", + " █ █ ██ ██ ██ ██ ██ ", + " ██ ██ ██ ██ ████ ██ ██ ██ ", + " █ █ ██████████ ██ ██ ", + " ████████████████ ███ ███ ██ ██ ", + " ███████████████ █ █ ████ ", + " ", + " ", + " █ █████ █████ ███ ████ █████ ████ █ ███ ███ █████ █ █ ", + " ██ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + "█ ██ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + "███ ████ █ █ █ ████ ████ ████ █ █ █ █ █ █ █████ ", + " █ █ █ █ █ █ █ █ █ █ █████ █ █ █ █ █ █ ", + " █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + " █████ █ █ ███ ████ █████ ████ █ █ ███ ██ ██ █████ █ █ " + ) + ) + + val testAlertScreenSnoozeTextFinnishScreen = makeDisplayFrame( + arrayOf( + "█████ ████ █ ████ █████ ████ █ █ █ █ █████ █████ █████ █████ █ █ ", + " █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + " █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + " █ ████ █████ ████ ████ ████ █ █ █ █ █ ████ █ █ █ █ ", + " █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + " █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + " █ ████ █ █ █ █████ █ █ ███ ███ █ █████ █ █ ███ ", + " ", + " ██ ██ ██ ███ ", + " ████ ██ ██ ██ ", + " █ █ ██ ██ ██ ", + " ██ ██ ██ ██ ██ ", + " █ █ ██ ██ ██ ██ ", + " ██ ██ ██ ██ ██ ██ ██ ", + " █ ██ █ ██ ██ ██ ██████ ", + " ██ ██ ██ ██ ██ ██ ███ ██ ", + " █ ██ █ ██ ██ ██ ██ ██ ", + " ██ ██ ██ ██ ██ ██ ██ ██ ", + " █ █ ██ ██ ██ ██ ██ ", + " ██ ██ ██ ██ ████ ██ ██ ██ ", + " █ █ ██████████ ██ ██ ", + " ████████████████ ███ ███ ██ ██ ", + " ███████████████ █ █ ████ ", + " ", + " ", + " █ ███ █ █ █ ███ ███ █████ █ █ █ █ █ █ █ █ █ ", + " ██ █ █ ██ ██ █ █ █ █ █ █ ██ ██ █ █ ███ █ █ ", + "█ ██ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + "███ █ █ █ █ █ █ █ █ █ █████ █ █ █ █ █ █ █ █████ ", + " █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + " █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ██ ", + " ███ █████ █ █ ███ ███ █ █ █ █ █ █ ███ █ █ ██ " + ) + ) + + val testAlertScreenConfirmTextFinnishScreen = makeDisplayFrame( + arrayOf( + "█████ ████ █ ████ █████ ████ █ █ █ █ █████ █████ █████ █████ █ █ ", + " █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + " █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + " █ ████ █████ ████ ████ ████ █ █ █ █ █ ████ █ █ █ █ ", + " █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + " █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + " █ ████ █ █ █ █████ █ █ ███ ███ █ █████ █ █ ███ ", + " ", + " ██ ██ ██ ███ ", + " ████ ██ ██ ██ ", + " █ █ ██ ██ ██ ", + " ██ ██ ██ ██ ██ ", + " █ █ ██ ██ ██ ██ ", + " ██ ██ ██ ██ ██ ██ ██ ", + " █ ██ █ ██ ██ ██ ██████ ", + " ██ ██ ██ ██ ██ ██ ███ ██ ", + " █ ██ █ ██ ██ ██ ██ ██ ", + " ██ ██ ██ ██ ██ ██ ██ ██ ", + " █ █ ██ ██ ██ ██ ██ ", + " ██ ██ ██ ██ ████ ██ ██ ██ ", + " █ █ ██████████ ██ ██ ", + " ████████████████ ███ ███ ██ ██ ", + " ███████████████ █ █ ████ ", + " ", + " ", + " █ █ █ █ █ █ █ █ ███ ████ █████ █ ", + " ██ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + "█ ██ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + "███ █ █ █████ █████ █ █ █ ███ █ █████ ", + " █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + " █ █ █ █ █ █ █ █ █ █ █ █ █ ", + " █ █ █ █ █ █ ███ ████ █ █ █ " + ) + ) + + val testAlertScreenSnoozeTextNorwegianScreen = makeDisplayFrame( + arrayOf( + "█ █ ████ ███ █ █ █ ████ ████ █ █ █████ █████ ", + "██ ██ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + "█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + "█ █ █ ████ █ █ █████ █ █ ████ ████ █ █ █ █ ", + "█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + "█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + "█ █ ████ ███ █ █ █ ████ █ █ ███ █ █ ", + " ", + " ██ ██ ██ ███ ", + " ████ ██ ██ ██ ", + " █ █ ██ ██ ██ ", + " ██ ██ ██ ██ ██ ", + " █ █ ██ ██ ██ ██ ", + " ██ ██ ██ ██ ██ ██ ██ ", + " █ ██ █ ██ ██ ██ ██████ ", + " ██ ██ ██ ██ ██ ██ ███ ██ ", + " █ ██ █ ██ ██ ██ ██ ██ ", + " ██ ██ ██ ██ ██ ██ ██ ██ ", + " █ █ ██ ██ ██ ██ ██ ", + " ██ ██ ██ ██ ████ ██ ██ ██ ", + " █ █ ██████████ ██ ██ ", + " ████████████████ ███ ███ ██ ██ ", + " ███████████████ █ █ ████ ", + " ", + " ", + " █ █████ ███ ████ █ ████ █ █ █ █ █ ████ █████ ", + " ██ █ █ █ █ █ █ █ █ █ █ █ ██ ██ █ █ █ ", + "█ ██ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + "███ ████ █ █ ████ █ █ ███ █ █ █ █ █ █ ████ ████ ", + " █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + " █ █ █ █ █ █████ █ █ █ █ █ █ █ █ █ ", + " █ ███ █ █ █ █ ████ █████ ███ █ █ █ █ █████ " + ) + ) + + val testAlertScreenConfirmTextNorwegianScreen = makeDisplayFrame( + arrayOf( + "█ █ ████ ███ █ █ █ ████ ████ █ █ █████ █████ ", + "██ ██ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + "█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + "█ █ █ ████ █ █ █████ █ █ ████ ████ █ █ █ █ ", + "█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + "█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + "█ █ ████ ███ █ █ █ ████ █ █ ███ █ █ ", + " ", + " ██ ██ ██ ███ ", + " ████ ██ ██ ██ ", + " █ █ ██ ██ ██ ", + " ██ ██ ██ ██ ██ ", + " █ █ ██ ██ ██ ██ ", + " ██ ██ ██ ██ ██ ██ ██ ", + " █ ██ █ ██ ██ ██ ██████ ", + " ██ ██ ██ ██ ██ ██ ███ ██ ", + " █ ██ █ ██ ██ ██ ██ ██ ", + " ██ ██ ██ ██ ██ ██ ██ ██ ", + " █ █ ██ ██ ██ ██ ██ ", + " ██ ██ ██ ██ ████ ██ ██ ██ ", + " █ █ ██████████ ██ ██ ", + " ████████████████ ███ ███ ██ ██ ", + " ███████████████ █ █ ████ ", + " ", + " ", + " █ █████ ███ ████ █ ████ █████ █ █ ████ █████ █████ █████ █████ ", + " ██ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + "█ ██ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + "███ ████ █ █ ████ █ █ ████ ████ ██ ████ ████ ████ █ ████ ", + " █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + " █ █ █ █ █ █████ █ █ █ █ █ █ █ █ █ █ █ ", + " █ ███ █ █ █ █ ████ █████ █ █ █ █ █████ █ █ █████ " + ) + ) + + val testAlertScreenSnoozeTextPortugueseScreen = makeDisplayFrame( + arrayOf( + "███ ████ █████ ███ █ █ █ ███ █████ █ █ ███ █ ", + "█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + "█ █ █ █ █ █ █ █ ██ █ █ █ █ █ █ █ █ █ █ ", + "█ █ ████ █ █ █████ █ █ █ █ ████ █ █████ █ █ █████ ", + "█ █ █ █ █ █ █ █ █ ██ █ █ █ █ █ █ █ █ █ ", + "█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + "███ ████ █ ███ █ █ █ █ ███ █████ █████ █ █ ███ █ █ ", + " ", + " ██ ██ ██ ███ ", + " ████ ██ ██ ██ ", + " █ █ ██ ██ ██ ", + " ██ ██ ██ ██ ██ ", + " █ █ ██ ██ ██ ██ ", + " ██ ██ ██ ██ ██ ██ ██ ", + " █ ██ █ ██ ██ ██ ██████ ", + " ██ ██ ██ ██ ██ ██ ███ ██ ", + " █ ██ █ ██ ██ ██ ██ ██ ", + " ██ ██ ██ ██ ██ ██ ██ ██ ", + " █ █ ██ ██ ██ ██ ██ ", + " ██ ██ ██ ██ ████ ██ ██ ██ ", + " █ █ ██████████ ██ ██ ", + " ████████████████ ███ ███ ██ ██ ", + " ███████████████ █ █ ████ ", + " ", + " ", + " █ ████ █ ████ █ ████ ███ █ █████ █ █ ███ ███ █ ████ ", + " ██ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + "█ ██ █ █ █ █ █ █ █ █ █ █ █ █ ██ █ █ █ █ █ █ █ ", + "███ ████ █████ ████ █████ ███ █ █ ████ █ █ █ █ █ █████ ████ ", + " █ █ █ █ █ █ █ █ █ █ █ █ █ ██ █ █ █ █ █ █ ", + " █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + " █ █ █ █ █ █ █ ████ ███ █████ █████ █ █ ███ ███ █ █ █ █ " + ) + ) + + val testAlertScreenConfirmTextPortugueseScreen = makeDisplayFrame( + arrayOf( + "███ ████ █████ ███ █ █ █ ███ █████ █ █ ███ █ ", + "█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + "█ █ █ █ █ █ █ █ ██ █ █ █ █ █ █ █ █ █ █ ", + "█ █ ████ █ █ █████ █ █ █ █ ████ █ █████ █ █ █████ ", + "█ █ █ █ █ █ █ █ █ ██ █ █ █ █ █ █ █ █ █ ", + "█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + "███ ████ █ ███ █ █ █ █ ███ █████ █████ █ █ ███ █ █ ", + " ", + " ██ ██ ██ ███ ", + " ████ ██ ██ ██ ", + " █ █ ██ ██ ██ ", + " ██ ██ ██ ██ ██ ", + " █ █ ██ ██ ██ ██ ", + " ██ ██ ██ ██ ██ ██ ██ ", + " █ ██ █ ██ ██ ██ ██████ ", + " ██ ██ ██ ██ ██ ██ ███ ██ ", + " █ ██ █ ██ ██ ██ ██ ██ ", + " ██ ██ ██ ██ ██ ██ ██ ██ ", + " █ █ ██ ██ ██ ██ ██ ", + " ██ ██ ██ ██ ████ ██ ██ ██ ", + " █ █ ██████████ ██ ██ ", + " ████████████████ ███ ███ ██ ██ ", + " ███████████████ █ █ ████ ", + " ", + " ", + " █ ████ █ ████ █ ███ ███ █ █ █████ ███ ████ █ █ █ ████ ", + " ██ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ██ ██ █ █ █ █ ", + "█ ██ █ █ █ █ █ █ █ █ █ █ █ ██ █ █ █ █ █ █ █ █ █ █ █ █ ", + "███ ████ █████ ████ █████ █ █ █ █ █ █ ████ █ ████ █ █ █ █████ ████ ", + " █ █ █ █ █ █ █ █ █ █ █ █ ██ █ █ █ █ █ █ █ █ █ █ ", + " █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + " █ █ █ █ █ █ █ ███ ███ █ █ █ ███ █ █ █ █ █ █ █ █ " + ) + ) + + val testAlertScreenSnoozeTextSwedishScreen = makeDisplayFrame( + arrayOf( + "█████ ████ ███ █ █ █ ████ ████ █ █ █████ █████ █ █ ", + " █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + " █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ██ █ ", + " █ ████ █ █ █████ █ █ ████ ████ █ █ █ ████ █ █ █ ", + " █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ██ ", + " █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + " █ ████ ███ █ █ █ ████ █ █ ███ █ █████ █ █ ", + " ", + " ██ ██ ██ ███ ", + " ████ ██ ██ ██ ", + " █ █ ██ ██ ██ ", + " ██ ██ ██ ██ ██ ", + " █ █ ██ ██ ██ ██ ", + " ██ ██ ██ ██ ██ ██ ██ ", + " █ ██ █ ██ ██ ██ ██████ ", + " ██ ██ ██ ██ ██ ██ ███ ██ ", + " █ ██ █ ██ ██ ██ ██ ██ ", + " ██ ██ ██ ██ ██ ██ ██ ██ ", + " █ █ ██ ██ ██ ██ ██ ", + " ██ ██ ██ ██ ████ ██ ██ ██ ", + " █ █ ██████████ ██ ██ ", + " ████████████████ ███ ███ ██ ██ ", + " ███████████████ █ █ ████ ", + " ", + " ", + " █ ████ █ █ ███ ███ █████ █████ ", + " ██ █ █ █ █ █ █ █ █ █ ", + "█ ██ █ ██ █ █ █ █ █ █ █ ", + "███ ███ █ █ █ █ █ █ █ █ ████ ", + " █ █ █ ██ █ █ █ █ █ █ ", + " █ █ █ █ █ █ █ █ █ ", + " ████ █ █ ███ ███ █████ █████ " + ) + ) + + val testAlertScreenConfirmTextSwedishScreen = makeDisplayFrame( + arrayOf( + "█████ ████ ███ █ █ █ ████ ████ █ █ █████ █████ █ █ ", + " █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + " █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ██ █ ", + " █ ████ █ █ █████ █ █ ████ ████ █ █ █ ████ █ █ █ ", + " █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ██ ", + " █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + " █ ████ ███ █ █ █ ████ █ █ ███ █ █████ █ █ ", + " ", + " ██ ██ ██ ███ ", + " ████ ██ ██ ██ ", + " █ █ ██ ██ ██ ", + " ██ ██ ██ ██ ██ ", + " █ █ ██ ██ ██ ██ ", + " ██ ██ ██ ██ ██ ██ ██ ", + " █ ██ █ ██ ██ ██ ██████ ", + " ██ ██ ██ ██ ██ ██ ███ ██ ", + " █ ██ █ ██ ██ ██ ██ ██ ", + " ██ ██ ██ ██ ██ ██ ██ ██ ", + " █ █ ██ ██ ██ ██ ██ ", + " ██ ██ ██ ██ ████ ██ ██ ██ ", + " █ █ ██████████ ██ ██ ", + " ████████████████ ███ ███ ██ ██ ", + " ███████████████ █ █ ████ ", + " ", + " ", + " █ ████ █████ █ █ ████ █ █ █████ █████ █ ", + " ██ █ █ █ █ █ █ █ ███ █ █ █ █ ", + "█ ██ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + "███ ████ ████ ██ ████ █ █ ████ █ █████ ", + " █ █ █ █ █ █ █ █ █████ █ █ █ █ ", + " █ █ █ █ █ █ █ █ █ █ █ █ █ ", + " ████ █████ █ █ █ █ █ █ █ █ █ █ " + ) + ) + + val testAlertScreenSnoozeTextDanishScreen = makeDisplayFrame( + arrayOf( + "█ █ ████ ████ █ █ █ █ █ █ █ █ █ █████ ████ █████ █████ ", + "██ ██ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + "█ █ █ █ █ █ █ █ █ ██ █ ██ █ █ █ █ █ █ █ █ █ █ ", + "█ █ █ ████ ████ █████ █ █ █ █ █ █ █ █ █ █ ████ ████ ████ █ ", + "█ █ █ █ █ █ █ █ █ ██ █ ██ █ █ █ █ █ █ █ █ █ ", + "█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + "█ █ ████ █ █ █ █ █ █ █ █ ███ █████ █████ █████ █ █ █████ █ ", + " ", + " ██ ██ ██ ███ ", + " ████ ██ ██ ██ ", + " █ █ ██ ██ ██ ", + " ██ ██ ██ ██ ██ ", + " █ █ ██ ██ ██ ██ ", + " ██ ██ ██ ██ ██ ██ ██ ", + " █ ██ █ ██ ██ ██ ██████ ", + " ██ ██ ██ ██ ██ ██ ███ ██ ", + " █ ██ █ ██ ██ ██ ██ ██ ", + " ██ ██ ██ ██ ██ ██ ██ ██ ", + " █ █ ██ ██ ██ ██ ██ ", + " ██ ██ ██ ██ ████ ██ ██ ██ ", + " █ █ ██████████ ██ ██ ", + " ████████████████ ███ ███ ██ ██ ", + " ███████████████ █ █ ████ ", + " ", + " ", + " █ █████ ███ ████ █ █████ █ █ ███ ████ ████ █████ █████ █████ ", + " ██ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + "█ ██ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + "███ ████ █ █ ████ █████ █ █ █ █ █ ███ ████ █ █ ████ ", + " █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + " █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + " █ ███ █ █ █ █ █ ███ ███ ████ █ ███ █ █ █████ " + ) + ) + + val testAlertScreenConfirmTextDanishScreen = makeDisplayFrame( + arrayOf( + "█ █ ████ ████ █ █ █ █ █ █ █ █ █ █████ ████ █████ █████ ", + "██ ██ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + "█ █ █ █ █ █ █ █ █ ██ █ ██ █ █ █ █ █ █ █ █ █ █ ", + "█ █ █ ████ ████ █████ █ █ █ █ █ █ █ █ █ █ ████ ████ ████ █ ", + "█ █ █ █ █ █ █ █ █ ██ █ ██ █ █ █ █ █ █ █ █ █ ", + "█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + "█ █ ████ █ █ █ █ █ █ █ █ ███ █████ █████ █████ █ █ █████ █ ", + " ", + " ██ ██ ██ ███ ", + " ████ ██ ██ ██ ", + " █ █ ██ ██ ██ ", + " ██ ██ ██ ██ ██ ", + " █ █ ██ ██ ██ ██ ", + " ██ ██ ██ ██ ██ ██ ██ ", + " █ ██ █ ██ ██ ██ ██████ ", + " ██ ██ ██ ██ ██ ██ ███ ██ ", + " █ ██ █ ██ ██ ██ ██ ██ ", + " ██ ██ ██ ██ ██ ██ ██ ██ ", + " █ █ ██ ██ ██ ██ ██ ", + " ██ ██ ██ ██ ████ ██ ██ ██ ", + " █ █ ██████████ ██ ██ ", + " ████████████████ ███ ███ ██ ██ ", + " ███████████████ █ █ ████ ", + " ", + " ", + " █ █████ ███ ████ ███ ███ ███ █ █ █████ █ █ ███ ", + " ██ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + "█ ██ █ █ █ █ █ █ █ █ █ █ █ █ █ ██ █ █ █ ", + "███ ████ █ █ ████ █ ███ █ █ █ █ ██ ████ █ █ █ █ █ ", + " █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ██ █ █ ", + " █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + " █ ███ █ █ ████ ███ ███ █ █ █████ █ █ ███ " + ) + ) + + val testAlertScreenSnoozeTextGermanScreen = makeDisplayFrame( + arrayOf( + "█████ ████ ████ █ ████ ████ ████ █ █ ███ █ █ ", + " █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + " █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + " █ ████ ████ █████ ████ ████ ████ █ █ █ █████ ", + " █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + " █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + " █ ████ █ █ █ █ ████ ████ █ █ ███ ███ █ █ ", + " ", + " ██ ██ ██ ███ ", + " ████ ██ ██ ██ ", + " █ █ ██ ██ ██ ", + " ██ ██ ██ ██ ██ ", + " █ █ ██ ██ ██ ██ ", + " ██ ██ ██ ██ ██ ██ ██ ", + " █ ██ █ ██ ██ ██ ██████ ", + " ██ ██ ██ ██ ██ ██ ███ ██ ", + " █ ██ █ ██ ██ ██ ██ ██ ", + " ██ ██ ██ ██ ██ ██ ██ ██ ", + " █ █ ██ ██ ██ ██ ██ ", + " ██ ██ ██ ██ ████ ██ ██ ██ ", + " █ █ ██████████ ██ ██ ", + " ████████████████ ███ ███ ██ ██ ", + " ███████████████ █ █ ████ ", + " ", + " ", + " █ █ █ █████ █ █ █████ ████ ███ █ █ █ █ █████ ████ █ █ ", + " ██ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + "█ ██ ██ █ █ █ █ █ █ █ █ ██ █ ██ █ █ █ █ ██ █ ", + "███ █ █ █ ████ █ █ ████ ████ █ █ █ █ █ █ █ ████ ████ █ █ █ ", + " █ █ ██ █ █ █ █ █ █ █ █ ██ █ ██ █ █ █ █ ██ ", + " █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + " █ █ █████ ███ █████ █ █ ███ █ █ █ █ █████ █ █ █ █ " + ) + ) + + val testAlertScreenConfirmTextGermanScreen = makeDisplayFrame( + arrayOf( + "█████ ████ ████ █ ████ ████ ████ █ █ ███ █ █ ", + " █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + " █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + " █ ████ ████ █████ ████ ████ ████ █ █ █ █████ ", + " █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + " █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + " █ ████ █ █ █ █ ████ ████ █ █ ███ ███ █ █ ", + " ", + " ██ ██ ██ ███ ", + " ████ ██ ██ ██ ", + " █ █ ██ ██ ██ ", + " ██ ██ ██ ██ ██ ", + " █ █ ██ ██ ██ ██ ", + " ██ ██ ██ ██ ██ ██ ██ ", + " █ ██ █ ██ ██ ██ ██████ ", + " ██ ██ ██ ██ ██ ██ ███ ██ ", + " █ ██ █ ██ ██ ██ ██ ██ ", + " ██ ██ ██ ██ ██ ██ ██ ██ ", + " █ █ ██ ██ ██ ██ ██ ", + " ██ ██ ██ ██ ████ ██ ██ ██ ", + " █ █ ██████████ ██ ██ ", + " ████████████████ ███ ███ ██ ██ ", + " ███████████████ █ █ ████ ", + " ", + " ", + " █ ████ █████ ████ █████ █ █ █████ ███ ███ █████ █ █ ", + " ██ █ █ █ █ █ ███ █ █ █ █ █ █ █ ", + "█ ██ █ █ █ █ █ █ █ █ █ █ █ ██ █ ", + "███ ████ ████ ███ █ █ █ █ █ █ ███ ████ █ █ █ ", + " █ █ █ █ █ █ █████ █ █ █ █ █ █ ██ ", + " █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + " ████ █████ ████ █ █ █ █ ███ ████ █████ █ █ " + ) + ) + +} \ No newline at end of file From d2c0aba2b58d201d5755a182387cade107d05905 Mon Sep 17 00:00:00 2001 From: Carlos Rafael Giani Date: Wed, 8 Mar 2023 17:53:58 +0100 Subject: [PATCH 05/17] comboctl-main: Improve alert screen handling * Check if the alert screen is the confirm or snooze screen, and press the CHECK button once or twice accordingly. This avoids fringe cases where the amount of button presses is incorrect. * In rare cases, more alert screens may show up after dismissing the current one. Add code to keep observing remaining alerts and redo the dismissing logic after a while if necessary. Signed-off-by: Carlos Rafael Giani --- .../info/nightscout/comboctl/main/Pump.kt | 29 +++++++++++++++++-- 1 file changed, 26 insertions(+), 3 deletions(-) diff --git a/pump/combov2/comboctl/src/commonMain/kotlin/info/nightscout/comboctl/main/Pump.kt b/pump/combov2/comboctl/src/commonMain/kotlin/info/nightscout/comboctl/main/Pump.kt index 13e5d845ef..508b1e189b 100644 --- a/pump/combov2/comboctl/src/commonMain/kotlin/info/nightscout/comboctl/main/Pump.kt +++ b/pump/combov2/comboctl/src/commonMain/kotlin/info/nightscout/comboctl/main/Pump.kt @@ -249,6 +249,7 @@ class Pump( // Used for keeping track of wether an RT alert screen was already dismissed // (necessary since the screen may change its contents but still be the same screen). private var rtScreenAlreadyDismissed = false + private var seenAlertAfterDismissingCounter = 0 // Used in handleAlertScreenContent() to check if the current alert // screen contains the same alert as the previous one. private var lastObservedAlertScreenContent: AlertScreenContent? = null @@ -2401,10 +2402,32 @@ class Pump( // the two button presses, so there is no need to wait // for the second screen - just press twice right away. if (!rtScreenAlreadyDismissed) { - logger(LogLevel.DEBUG) { "Dismissing W$warningCode by short-pressing CHECK twice" } - rtNavigationContext.shortPressButton(RTNavigationButton.CHECK) - rtNavigationContext.shortPressButton(RTNavigationButton.CHECK) + val numRequiredButtonPresses = when (alertScreenContent.state) { + AlertScreenContent.AlertScreenState.TO_SNOOZE -> 2 + AlertScreenContent.AlertScreenState.TO_CONFIRM -> 1 + else -> throw AlertScreenException(alertScreenContent) + } + logger(LogLevel.DEBUG) { "Dismissing W$warningCode by short-pressing CHECK $numRequiredButtonPresses time(s)" } + for (i in 1..numRequiredButtonPresses) + rtNavigationContext.shortPressButton(RTNavigationButton.CHECK) rtScreenAlreadyDismissed = true + } else { + // In rare cases, an alert screen may still show after an alert + // was dismissed. Unfortunately, it is not immediately clear if + // this is the case, because the RT screen updates can come in + // with some temporal jitter. So, to be safe, we only begin to + // again handle alert screens after >10 alert screens were + // observed in sequence. + logger(LogLevel.DEBUG) { "W$warningCode already dismissed" } + seenAlertAfterDismissingCounter++ + if (seenAlertAfterDismissingCounter > 10) { + logger(LogLevel.WARN) { + "Saw an alert screen $seenAlertAfterDismissingCounter time(s) " + + "after having dismissed an alert twice; now again handling alerts" + } + rtScreenAlreadyDismissed = false + seenAlertAfterDismissingCounter = 0 + } } } } From dbe72e72daf2fbda2e9e67735931f73d5be9cfcc Mon Sep 17 00:00:00 2001 From: Carlos Rafael Giani Date: Wed, 8 Mar 2023 20:15:08 +0100 Subject: [PATCH 06/17] comboctl-parser: Add Slovenian support Signed-off-by: Carlos Rafael Giani --- .../comboctl/parser/TitleStrings.kt | 16 + .../main/ParsedDisplayFrameStreamTest.kt | 4 +- .../nightscout/comboctl/parser/ParserTest.kt | 129 +- .../comboctl/parser/TestDisplayFrames.kt | 3261 ++++++++++------- 4 files changed, 2007 insertions(+), 1403 deletions(-) diff --git a/pump/combov2/comboctl/src/commonMain/kotlin/info/nightscout/comboctl/parser/TitleStrings.kt b/pump/combov2/comboctl/src/commonMain/kotlin/info/nightscout/comboctl/parser/TitleStrings.kt index 3e85fb5981..6b8944b5e3 100644 --- a/pump/combov2/comboctl/src/commonMain/kotlin/info/nightscout/comboctl/parser/TitleStrings.kt +++ b/pump/combov2/comboctl/src/commonMain/kotlin/info/nightscout/comboctl/parser/TitleStrings.kt @@ -356,6 +356,22 @@ val knownScreenTitles = mapOf( "NEU ERINNERN" to TitleID.ALERT_TO_SNOOZE, "BESTÄTIGEN" to TitleID.ALERT_TO_CONFIRM, + // Slovenian + "QUICK INFO" to TitleID.QUICK_INFO, + "ODSTOTEK ZBO" to TitleID.TBR_PERCENTAGE, + "TRAJANJE ZBO" to TitleID.TBR_DURATION, + "URA" to TitleID.HOUR, + "MINUTE" to TitleID.MINUTE, + "LETO" to TitleID.YEAR, + "MESEC" to TitleID.MONTH, + "DAN" to TitleID.DAY, + "PODATKI O BOLUSU" to TitleID.BOLUS_DATA, + "PODATKI O NAPAKI" to TitleID.ERROR_DATA, + "DNEVNA PORABA" to TitleID.DAILY_TOTALS, + "PODATKI O ZBO" to TitleID.TBR_DATA, + "UTIŠANJE" to TitleID.ALERT_TO_SNOOZE, + "POTRDITEV" to TitleID.ALERT_TO_CONFIRM, + // Some pumps came preconfigured with a different quick info name "ACCU CHECK SPIRIT" to TitleID.QUICK_INFO ) diff --git a/pump/combov2/comboctl/src/jvmTest/kotlin/info/nightscout/comboctl/main/ParsedDisplayFrameStreamTest.kt b/pump/combov2/comboctl/src/jvmTest/kotlin/info/nightscout/comboctl/main/ParsedDisplayFrameStreamTest.kt index b8a83ac9a4..deeab186a4 100644 --- a/pump/combov2/comboctl/src/jvmTest/kotlin/info/nightscout/comboctl/main/ParsedDisplayFrameStreamTest.kt +++ b/pump/combov2/comboctl/src/jvmTest/kotlin/info/nightscout/comboctl/main/ParsedDisplayFrameStreamTest.kt @@ -13,7 +13,7 @@ import info.nightscout.comboctl.parser.ParsedScreen import info.nightscout.comboctl.parser.testFrameMainScreenWithTimeSeparator import info.nightscout.comboctl.parser.testFrameMainScreenWithoutTimeSeparator import info.nightscout.comboctl.parser.testFrameStandardBolusMenuScreen -import info.nightscout.comboctl.parser.testFrameTbrDurationEnglishScreen +import info.nightscout.comboctl.parser.TbrPercentageAndDurationScreens import info.nightscout.comboctl.parser.testFrameTemporaryBasalRateNoPercentageScreen import info.nightscout.comboctl.parser.testFrameTemporaryBasalRatePercentage110Screen import info.nightscout.comboctl.parser.testFrameW6CancelTbrWarningScreen @@ -328,7 +328,7 @@ class ParsedDisplayFrameStreamTest { val displayFrameList = listOf( testFrameTemporaryBasalRatePercentage110Screen, testFrameTemporaryBasalRateNoPercentageScreen, - testFrameTbrDurationEnglishScreen + TbrPercentageAndDurationScreens.testFrameTbrDurationEnglishScreen ) val parsedFrameList = mutableListOf() diff --git a/pump/combov2/comboctl/src/jvmTest/kotlin/info/nightscout/comboctl/parser/ParserTest.kt b/pump/combov2/comboctl/src/jvmTest/kotlin/info/nightscout/comboctl/parser/ParserTest.kt index 540213c19a..e31f78cdf8 100644 --- a/pump/combov2/comboctl/src/jvmTest/kotlin/info/nightscout/comboctl/parser/ParserTest.kt +++ b/pump/combov2/comboctl/src/jvmTest/kotlin/info/nightscout/comboctl/parser/ParserTest.kt @@ -722,26 +722,27 @@ class ParserTest { Pair(testFrameTemporaryBasalRatePercentage100Screen, 100), Pair(testFrameTemporaryBasalRatePercentage110Screen, 110), Pair(testFrameTemporaryBasalRateNoPercentageScreen, null), - Pair(testFrameTbrPercentageEnglishScreen, 110), - Pair(testFrameTbrPercentageSpanishScreen, 110), - Pair(testFrameTbrPercentageFrenchScreen, 110), - Pair(testFrameTbrPercentageItalianScreen, 110), - Pair(testFrameTbrPercentageRussianScreen, 110), - Pair(testFrameTbrPercentageTurkishScreen, 110), - Pair(testFrameTbrPercentagePolishScreen, 100), - Pair(testFrameTbrPercentageCzechScreen, 110), - Pair(testFrameTbrPercentageHungarianScreen, 110), - Pair(testFrameTbrPercentageSlovakScreen, 110), - Pair(testFrameTbrPercentageRomanianScreen, 110), - Pair(testFrameTbrPercentageCroatianScreen, 110), - Pair(testFrameTbrPercentageDutchScreen, 110), - Pair(testFrameTbrPercentageGreekScreen, 110), - Pair(testFrameTbrPercentageFinnishScreen, 110), - Pair(testFrameTbrPercentageNorwegianScreen, 110), - Pair(testFrameTbrPercentagePortugueseScreen, 110), - Pair(testFrameTbrPercentageSwedishScreen, 110), - Pair(testFrameTbrPercentageDanishScreen, 110), - Pair(testFrameTbrPercentageGermanScreen, 110) + Pair(TbrPercentageAndDurationScreens.testFrameTbrPercentageEnglishScreen, 110), + Pair(TbrPercentageAndDurationScreens.testFrameTbrPercentageSpanishScreen, 110), + Pair(TbrPercentageAndDurationScreens.testFrameTbrPercentageFrenchScreen, 110), + Pair(TbrPercentageAndDurationScreens.testFrameTbrPercentageItalianScreen, 110), + Pair(TbrPercentageAndDurationScreens.testFrameTbrPercentageRussianScreen, 110), + Pair(TbrPercentageAndDurationScreens.testFrameTbrPercentageTurkishScreen, 110), + Pair(TbrPercentageAndDurationScreens.testFrameTbrPercentagePolishScreen, 100), + Pair(TbrPercentageAndDurationScreens.testFrameTbrPercentageCzechScreen, 110), + Pair(TbrPercentageAndDurationScreens.testFrameTbrPercentageHungarianScreen, 110), + Pair(TbrPercentageAndDurationScreens.testFrameTbrPercentageSlovakScreen, 110), + Pair(TbrPercentageAndDurationScreens.testFrameTbrPercentageRomanianScreen, 110), + Pair(TbrPercentageAndDurationScreens.testFrameTbrPercentageCroatianScreen, 110), + Pair(TbrPercentageAndDurationScreens.testFrameTbrPercentageDutchScreen, 110), + Pair(TbrPercentageAndDurationScreens.testFrameTbrPercentageGreekScreen, 110), + Pair(TbrPercentageAndDurationScreens.testFrameTbrPercentageFinnishScreen, 110), + Pair(TbrPercentageAndDurationScreens.testFrameTbrPercentageNorwegianScreen, 110), + Pair(TbrPercentageAndDurationScreens.testFrameTbrPercentagePortugueseScreen, 110), + Pair(TbrPercentageAndDurationScreens.testFrameTbrPercentageSwedishScreen, 110), + Pair(TbrPercentageAndDurationScreens.testFrameTbrPercentageDanishScreen, 110), + Pair(TbrPercentageAndDurationScreens.testFrameTbrPercentageGermanScreen, 110), + Pair(TbrPercentageAndDurationScreens.testFrameTbrPercentageSlovenianScreen, 110), ) for (testScreen in testScreens) { @@ -769,26 +770,27 @@ class ParserTest { fun checkTemporaryBasalRateDurationScreenParsing() { val testScreens = listOf( Pair(testFrameTbrDurationNoDurationScreen, null), - Pair(testFrameTbrDurationEnglishScreen, 30), - Pair(testFrameTbrDurationSpanishScreen, 30), - Pair(testFrameTbrDurationFrenchScreen, 30), - Pair(testFrameTbrDurationItalianScreen, 30), - Pair(testFrameTbrDurationRussianScreen, 30), - Pair(testFrameTbrDurationTurkishScreen, 30), - Pair(testFrameTbrDurationPolishScreen, 30), - Pair(testFrameTbrDurationCzechScreen, 30), - Pair(testFrameTbrDurationHungarianScreen, 30), - Pair(testFrameTbrDurationSlovakScreen, 30), - Pair(testFrameTbrDurationRomanianScreen, 30), - Pair(testFrameTbrDurationCroatianScreen, 30), - Pair(testFrameTbrDurationDutchScreen, 30), - Pair(testFrameTbrDurationGreekScreen, 30), - Pair(testFrameTbrDurationFinnishScreen, 30), - Pair(testFrameTbrDurationNorwegianScreen, 30), - Pair(testFrameTbrDurationPortugueseScreen, 30), - Pair(testFrameTbrDurationSwedishScreen, 30), - Pair(testFrameTbrDurationDanishScreen, 30), - Pair(testFrameTbrDurationGermanScreen, 30) + Pair(TbrPercentageAndDurationScreens.testFrameTbrDurationEnglishScreen, 30), + Pair(TbrPercentageAndDurationScreens.testFrameTbrDurationSpanishScreen, 30), + Pair(TbrPercentageAndDurationScreens.testFrameTbrDurationFrenchScreen, 30), + Pair(TbrPercentageAndDurationScreens.testFrameTbrDurationItalianScreen, 30), + Pair(TbrPercentageAndDurationScreens.testFrameTbrDurationRussianScreen, 30), + Pair(TbrPercentageAndDurationScreens.testFrameTbrDurationTurkishScreen, 30), + Pair(TbrPercentageAndDurationScreens.testFrameTbrDurationPolishScreen, 30), + Pair(TbrPercentageAndDurationScreens.testFrameTbrDurationCzechScreen, 30), + Pair(TbrPercentageAndDurationScreens.testFrameTbrDurationHungarianScreen, 30), + Pair(TbrPercentageAndDurationScreens.testFrameTbrDurationSlovakScreen, 30), + Pair(TbrPercentageAndDurationScreens.testFrameTbrDurationRomanianScreen, 30), + Pair(TbrPercentageAndDurationScreens.testFrameTbrDurationCroatianScreen, 30), + Pair(TbrPercentageAndDurationScreens.testFrameTbrDurationDutchScreen, 30), + Pair(TbrPercentageAndDurationScreens.testFrameTbrDurationGreekScreen, 30), + Pair(TbrPercentageAndDurationScreens.testFrameTbrDurationFinnishScreen, 30), + Pair(TbrPercentageAndDurationScreens.testFrameTbrDurationNorwegianScreen, 30), + Pair(TbrPercentageAndDurationScreens.testFrameTbrDurationPortugueseScreen, 30), + Pair(TbrPercentageAndDurationScreens.testFrameTbrDurationSwedishScreen, 30), + Pair(TbrPercentageAndDurationScreens.testFrameTbrDurationDanishScreen, 30), + Pair(TbrPercentageAndDurationScreens.testFrameTbrDurationGermanScreen, 30), + Pair(TbrPercentageAndDurationScreens.testFrameTbrDurationSlovenianScreen, 15) ) for (testScreen in testScreens) { @@ -927,6 +929,12 @@ class ParserTest { Pair(testTimeAndDateSettingsMonthGermanScreen, ParsedScreen.TimeAndDateSettingsMonthScreen(4)), Pair(testTimeAndDateSettingsDayGermanScreen, ParsedScreen.TimeAndDateSettingsDayScreen(21)), + Pair(testTimeAndDateSettingsHourSlovenianScreen, ParsedScreen.TimeAndDateSettingsHourScreen(19)), + Pair(testTimeAndDateSettingsMinuteSlovenianScreen, ParsedScreen.TimeAndDateSettingsMinuteScreen(50)), + Pair(testTimeAndDateSettingsYearSlovenianScreen, ParsedScreen.TimeAndDateSettingsYearScreen(2023)), + Pair(testTimeAndDateSettingsMonthSlovenianScreen, ParsedScreen.TimeAndDateSettingsMonthScreen(3)), + Pair(testTimeAndDateSettingsDaySlovenianScreen, ParsedScreen.TimeAndDateSettingsDayScreen(8)), + // Extra test to verify that a *minute* 24 is not incorrectly interpreted // as an *hour* 24 and thus translated to 0 (this is done because the Combo // may show midnight as both hour 0 and hour 24). @@ -1569,7 +1577,38 @@ class ParserTest { timestamp = LocalDateTime(year = 0, monthNumber = 1, dayOfMonth = 28, hour = 11, minute = 0, second = 0), percentage = 110, durationInMinutes = 0 ) - ) + ), + Pair( + testMyDataBolusDataSlovenianScreen, + ParsedScreen.MyDataBolusDataScreen( + index = 1, totalNumEntries = 30, + timestamp = LocalDateTime(year = 0, monthNumber = 1, dayOfMonth = 1, hour = 23, minute = 21, second = 0), + bolusAmount = 3200, bolusType = MyDataBolusType.MULTI_WAVE, durationInMinutes = 43 + ) + ), + Pair( + testMyDataErrorDataSlovenianScreen, + ParsedScreen.MyDataErrorDataScreen( + index = 1, totalNumEntries = 30, + timestamp = LocalDateTime(year = 0, monthNumber = 3, dayOfMonth = 8, hour = 17, minute = 31, second = 0), + alert = AlertScreenContent.Warning(6, AlertScreenContent.AlertScreenState.HISTORY_ENTRY) + ) + ), + Pair( + testMyDataDailyTotalsSlovenianScreen, + ParsedScreen.MyDataDailyTotalsScreen( + index = 1, totalNumEntries = 30, date = LocalDate(year = 0, dayOfMonth = 8, monthNumber = 3), + totalDailyAmount = 32100 + ) + ), + Pair( + testMyDataTbrDataSlovenianScreen, + ParsedScreen.MyDataTbrDataScreen( + index = 1, totalNumEntries = 30, + timestamp = LocalDateTime(year = 0, monthNumber = 3, dayOfMonth = 8, hour = 17, minute = 31, second = 0), + percentage = 110, durationInMinutes = 1 + ) + ), ) for (testScreen in testScreens) { @@ -1758,6 +1797,14 @@ class ParserTest { AlertSnoozeAndConfirmScreens.testAlertScreenConfirmTextGermanScreen, AlertScreenContent.Warning(6, AlertScreenContent.AlertScreenState.TO_CONFIRM) ), + Pair( + AlertSnoozeAndConfirmScreens.testAlertScreenSnoozeTextSlovenianScreen, + AlertScreenContent.Warning(6, AlertScreenContent.AlertScreenState.TO_SNOOZE) + ), + Pair( + AlertSnoozeAndConfirmScreens.testAlertScreenConfirmTextSlovenianScreen, + AlertScreenContent.Warning(6, AlertScreenContent.AlertScreenState.TO_CONFIRM) + ), ) for (testScreen in testScreens) { diff --git a/pump/combov2/comboctl/src/jvmTest/kotlin/info/nightscout/comboctl/parser/TestDisplayFrames.kt b/pump/combov2/comboctl/src/jvmTest/kotlin/info/nightscout/comboctl/parser/TestDisplayFrames.kt index 7da7090adc..3787c25fd0 100644 --- a/pump/combov2/comboctl/src/jvmTest/kotlin/info/nightscout/comboctl/parser/TestDisplayFrames.kt +++ b/pump/combov2/comboctl/src/jvmTest/kotlin/info/nightscout/comboctl/parser/TestDisplayFrames.kt @@ -1840,1403 +1840,1559 @@ val testFrameTbrDurationNoDurationScreen = makeDisplayFrame(arrayOf( " " )) -val testFrameTbrPercentageEnglishScreen = makeDisplayFrame(arrayOf( - "█████ ████ ████ ████ █████ ████ ███ █████ █ █ █████ █ ███ █████ ", - " █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", - " █ █ █ █ █ █ █ █ █ █ █ █ ██ █ █ █ █ █ █ ", - " █ ████ ████ ████ ████ ████ █ ████ █ █ █ █ █████ █ ███ ████ ", - " █ █ █ █ █ █ █ █ █ █ █ █ ██ █ █ █ █ █ █ ", - " █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", - " █ ████ █ █ █ █████ █ █ ███ █████ █ █ █ █ █ ████ █████ ", - " ", - " ██ ██ ████ ██ ██ ", - " ███████ ███ ███ ██ ██ ████ ██ ", - " ███████ ████ ████ ██ ██ ████ ██ ", - " ██ ██ ██ ██ ██ ██ ██ ██ ", - " ██ ███████ ██ ██ ██ ██ ██ ", - " ██ ███████ ██ ██ ██ ██ ██ ", - "███████ ██ ██ ██ ██ ██ ██ ██ ", - "███████ ██ ██ ██ ██ ██ ██ ██ ", - "██ ██ ██ ██ ██ ██ ██ ██ ██ ", - "██ ██ ██ ██ ██ ██ ██ ██ ██ ", - "██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ", - "██ ██ ██ ██ ██ ██ ██ ██ ██ ████ ", - "██ ██ ██ ██ ██ ██ ██ ██ ██ ████ ", - "██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ", - "██ ██ ██ ██ ██ ██ ████ ", - " ", - " █ ███ ███ █████ ███ ", - " ██ █ █ █ █ ██ █ █ █ ", - "███████ █ ██ █ ██ ██ █ █ ██ ", - "████████ █ █ █ █ █ █ █ █ █ █ ", - "███████ ██ █ ██ █ ██ █ ██ █ ", - " ██ █ █ █ █ ██ █ █ █ █ ", - " █ ███ ███ ███ ███ ", - " " -)) -val testFrameTbrDurationEnglishScreen = makeDisplayFrame(arrayOf( - "█████ ████ ████ ███ █ █ ████ █ █████ ███ ███ █ █ ", - " █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", - " █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ██ █ ", - " █ ████ ████ █ █ █ █ ████ █████ █ █ █ █ █ █ █ ", - " █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ██ ", - " █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", - " █ ████ █ █ ███ ███ █ █ █ █ █ ███ ███ █ █ ", - " ", - " ████ ████ █████ ████ ", - " ██ ██ ██ ██ ██ ██ ██ ██ ██ ", - " ███ ██ ██ ██ ██ ██ ██ ██ ", - " ████ ██ ██ ██ ██ ██ ██ ██ ", - " █████ ██ ██ ██ ██ ██ ██ ██ ", - " ██████ ██ ██ ██ ██ ███ ██ ██ ██ ", - "███████████████ ██ ██ ██ ██ ███ ███ ██ ██ ", - "████████████████ ██ ██ ██ ██ ███ ██ ██ ██ ", - "████████████████ ██ ██ ██ ██ ██ ██ ██ ", - "███████████████ ██ ██ ██ ██ ██ ██ ██ ", - " ██████ ██ ██ ██ ██ ███ ██ ██ ██ ", - " █████ ██ ██ ██ ██ ███ ██ ██ ██ ", - " ████ ██ ██ ██ ██ ███ ██ ██ ██ ", - " ███ ██ ██ ██ ██ ██ ██ ██ ██ ", - " ██ ████ ████ █████ ████ ", - " ", - " ████ █ █ ███ ██ ", - " █ ███ ██ ██ █ █ ██ █ ", - "███ █ █ █ █ █ ██ █ ", - "█ █ █ █ █ █ █ █ █ █ ", - "█ █ █ █ █ █ ██ █ █ ", - "█ █ █ █ █ █ █ █ █ ██ ", - "█ █ █ █ ███ ███ ███ ██ ", - " " -)) +object TbrPercentageAndDurationScreens { + val testFrameTbrPercentageEnglishScreen = makeDisplayFrame( + arrayOf( + "█████ ████ ████ ████ █████ ████ ███ █████ █ █ █████ █ ███ █████ ", + " █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + " █ █ █ █ █ █ █ █ █ █ █ █ ██ █ █ █ █ █ █ ", + " █ ████ ████ ████ ████ ████ █ ████ █ █ █ █ █████ █ ███ ████ ", + " █ █ █ █ █ █ █ █ █ █ █ █ ██ █ █ █ █ █ █ ", + " █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + " █ ████ █ █ █ █████ █ █ ███ █████ █ █ █ █ █ ████ █████ ", + " ", + " ██ ██ ████ ██ ██ ", + " ███████ ███ ███ ██ ██ ████ ██ ", + " ███████ ████ ████ ██ ██ ████ ██ ", + " ██ ██ ██ ██ ██ ██ ██ ██ ", + " ██ ███████ ██ ██ ██ ██ ██ ", + " ██ ███████ ██ ██ ██ ██ ██ ", + "███████ ██ ██ ██ ██ ██ ██ ██ ", + "███████ ██ ██ ██ ██ ██ ██ ██ ", + "██ ██ ██ ██ ██ ██ ██ ██ ██ ", + "██ ██ ██ ██ ██ ██ ██ ██ ██ ", + "██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ", + "██ ██ ██ ██ ██ ██ ██ ██ ██ ████ ", + "██ ██ ██ ██ ██ ██ ██ ██ ██ ████ ", + "██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ", + "██ ██ ██ ██ ██ ██ ████ ", + " ", + " █ ███ ███ █████ ███ ", + " ██ █ █ █ █ ██ █ █ █ ", + "███████ █ ██ █ ██ ██ █ █ ██ ", + "████████ █ █ █ █ █ █ █ █ █ █ ", + "███████ ██ █ ██ █ ██ █ ██ █ ", + " ██ █ █ █ █ ██ █ █ █ █ ", + " █ ███ ███ ███ ███ ", + " " + ) + ) + val testFrameTbrDurationEnglishScreen = makeDisplayFrame( + arrayOf( + "█████ ████ ████ ███ █ █ ████ █ █████ ███ ███ █ █ ", + " █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + " █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ██ █ ", + " █ ████ ████ █ █ █ █ ████ █████ █ █ █ █ █ █ █ ", + " █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ██ ", + " █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + " █ ████ █ █ ███ ███ █ █ █ █ █ ███ ███ █ █ ", + " ", + " ████ ████ █████ ████ ", + " ██ ██ ██ ██ ██ ██ ██ ██ ██ ", + " ███ ██ ██ ██ ██ ██ ██ ██ ", + " ████ ██ ██ ██ ██ ██ ██ ██ ", + " █████ ██ ██ ██ ██ ██ ██ ██ ", + " ██████ ██ ██ ██ ██ ███ ██ ██ ██ ", + "███████████████ ██ ██ ██ ██ ███ ███ ██ ██ ", + "████████████████ ██ ██ ██ ██ ███ ██ ██ ██ ", + "████████████████ ██ ██ ██ ██ ██ ██ ██ ", + "███████████████ ██ ██ ██ ██ ██ ██ ██ ", + " ██████ ██ ██ ██ ██ ███ ██ ██ ██ ", + " █████ ██ ██ ██ ██ ███ ██ ██ ██ ", + " ████ ██ ██ ██ ██ ███ ██ ██ ██ ", + " ███ ██ ██ ██ ██ ██ ██ ██ ██ ", + " ██ ████ ████ █████ ████ ", + " ", + " ████ █ █ ███ ██ ", + " █ ███ ██ ██ █ █ ██ █ ", + "███ █ █ █ █ █ ██ █ ", + "█ █ █ █ █ █ █ █ █ █ ", + "█ █ █ █ █ █ ██ █ █ ", + "█ █ █ █ █ █ █ █ █ ██ ", + "█ █ █ █ ███ ███ ███ ██ ", + " " + ) + ) -val testFrameTbrPercentageSpanishScreen = makeDisplayFrame(arrayOf( - "████ ███ ████ ███ █████ █ █ █████ █ ███ █████ ███ ████ █████ ", - "█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", - "█ █ █ █ █ █ █ █ ██ █ █ █ █ █ █ █ █ █ █ █ ", - "████ █ █ ████ █ ████ █ █ █ █ █████ █ ████ █ █ ████ █ ", - "█ █ █ █ █ █ █ █ ██ █ █ █ █ █ █ █ █ █ █ ", - "█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", - "█ ███ █ █ ███ █████ █ █ █ █ █ ██ █████ ███ ████ █ ", - " ", - " ██ ██ ████ ██ ██ ", - " ███████ ███ ███ ██ ██ ████ ██ ", - " ███████ ████ ████ ██ ██ ████ ██ ", - " ██ ██ ██ ██ ██ ██ ██ ██ ", - " ██ ███████ ██ ██ ██ ██ ██ ", - " ██ ███████ ██ ██ ██ ██ ██ ", - "███████ ██ ██ ██ ██ ██ ██ ██ ", - "███████ ██ ██ ██ ██ ██ ██ ██ ", - "██ ██ ██ ██ ██ ██ ██ ██ ██ ", - "██ ██ ██ ██ ██ ██ ██ ██ ██ ", - "██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ", - "██ ██ ██ ██ ██ ██ ██ ██ ██ ████ ", - "██ ██ ██ ██ ██ ██ ██ ██ ██ ████ ", - "██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ", - "██ ██ ██ ██ ██ ██ ████ ", - " ", - " █ ███ ███ █████ ███ ", - " ██ █ █ █ █ ██ █ █ █ ", - "███████ █ ██ █ ██ ██ █ █ ██ ", - "████████ █ █ █ █ █ █ █ █ █ █ ", - "███████ ██ █ ██ █ ██ █ ██ █ ", - " ██ █ █ █ █ ██ █ █ █ █ ", - " █ ███ ███ ███ ███ ", - " " -)) -val testFrameTbrDurationSpanishScreen = makeDisplayFrame(arrayOf( - "███ █ █ ████ █ ███ ███ █ █ █ ███ █████ ███ ████ █████ ", - "█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", - "█ █ █ █ █ █ █ █ █ █ ███ ██ █ █ █ █ █ █ █ █ █ ", - "█ █ █ █ ████ █████ █ █ █ █ █ █ █ █ █ ████ █ █ ████ █ ", - "█ █ █ █ █ █ █ █ █ █ █ █ █ ██ █ █ █ █ █ █ █ █ ", - "█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", - "███ ███ █ █ █ █ ███ ███ ███ █ █ ███ █████ ███ ████ █ ", - " ", - " ████ ████ █████ ████ ", - " ██ ██ ██ ██ ██ ██ ██ ██ ██ ", - " ███ ██ ██ ██ ██ ██ ██ ██ ", - " ████ ██ ██ ██ ██ ██ ██ ██ ", - " █████ ██ ██ ██ ██ ██ ██ ██ ", - " ██████ ██ ██ ██ ██ ███ ██ ██ ██ ", - "███████████████ ██ ██ ██ ██ ███ ███ ██ ██ ", - "████████████████ ██ ██ ██ ██ ███ ██ ██ ██ ", - "████████████████ ██ ██ ██ ██ ██ ██ ██ ", - "███████████████ ██ ██ ██ ██ ██ ██ ██ ", - " ██████ ██ ██ ██ ██ ███ ██ ██ ██ ", - " █████ ██ ██ ██ ██ ███ ██ ██ ██ ", - " ████ ██ ██ ██ ██ ███ ██ ██ ██ ", - " ███ ██ ██ ██ ██ ██ ██ ██ ██ ", - " ██ ████ ████ █████ ████ ", - " ", - " ████ █ █ ███ ██ ", - " █ ███ ██ ██ █ █ ██ █ ", - "███ █ █ █ █ █ ██ █ ", - "█ █ █ █ █ █ █ █ █ █ ", - "█ █ █ █ █ █ ██ █ █ ", - "█ █ █ █ █ █ █ █ █ ██ ", - "█ █ █ █ ███ ███ ███ ██ ", - " " -)) + val testFrameTbrPercentageSpanishScreen = makeDisplayFrame( + arrayOf( + "████ ███ ████ ███ █████ █ █ █████ █ ███ █████ ███ ████ █████ ", + "█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + "█ █ █ █ █ █ █ █ ██ █ █ █ █ █ █ █ █ █ █ █ ", + "████ █ █ ████ █ ████ █ █ █ █ █████ █ ████ █ █ ████ █ ", + "█ █ █ █ █ █ █ █ ██ █ █ █ █ █ █ █ █ █ █ ", + "█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + "█ ███ █ █ ███ █████ █ █ █ █ █ ██ █████ ███ ████ █ ", + " ", + " ██ ██ ████ ██ ██ ", + " ███████ ███ ███ ██ ██ ████ ██ ", + " ███████ ████ ████ ██ ██ ████ ██ ", + " ██ ██ ██ ██ ██ ██ ██ ██ ", + " ██ ███████ ██ ██ ██ ██ ██ ", + " ██ ███████ ██ ██ ██ ██ ██ ", + "███████ ██ ██ ██ ██ ██ ██ ██ ", + "███████ ██ ██ ██ ██ ██ ██ ██ ", + "██ ██ ██ ██ ██ ██ ██ ██ ██ ", + "██ ██ ██ ██ ██ ██ ██ ██ ██ ", + "██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ", + "██ ██ ██ ██ ██ ██ ██ ██ ██ ████ ", + "██ ██ ██ ██ ██ ██ ██ ██ ██ ████ ", + "██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ", + "██ ██ ██ ██ ██ ██ ████ ", + " ", + " █ ███ ███ █████ ███ ", + " ██ █ █ █ █ ██ █ █ █ ", + "███████ █ ██ █ ██ ██ █ █ ██ ", + "████████ █ █ █ █ █ █ █ █ █ █ ", + "███████ ██ █ ██ █ ██ █ ██ █ ", + " ██ █ █ █ █ ██ █ █ █ █ ", + " █ ███ ███ ███ ███ ", + " " + ) + ) + val testFrameTbrDurationSpanishScreen = makeDisplayFrame( + arrayOf( + "███ █ █ ████ █ ███ ███ █ █ █ ███ █████ ███ ████ █████ ", + "█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + "█ █ █ █ █ █ █ █ █ █ ███ ██ █ █ █ █ █ █ █ █ █ ", + "█ █ █ █ ████ █████ █ █ █ █ █ █ █ █ █ ████ █ █ ████ █ ", + "█ █ █ █ █ █ █ █ █ █ █ █ █ ██ █ █ █ █ █ █ █ █ ", + "█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + "███ ███ █ █ █ █ ███ ███ ███ █ █ ███ █████ ███ ████ █ ", + " ", + " ████ ████ █████ ████ ", + " ██ ██ ██ ██ ██ ██ ██ ██ ██ ", + " ███ ██ ██ ██ ██ ██ ██ ██ ", + " ████ ██ ██ ██ ██ ██ ██ ██ ", + " █████ ██ ██ ██ ██ ██ ██ ██ ", + " ██████ ██ ██ ██ ██ ███ ██ ██ ██ ", + "███████████████ ██ ██ ██ ██ ███ ███ ██ ██ ", + "████████████████ ██ ██ ██ ██ ███ ██ ██ ██ ", + "████████████████ ██ ██ ██ ██ ██ ██ ██ ", + "███████████████ ██ ██ ██ ██ ██ ██ ██ ", + " ██████ ██ ██ ██ ██ ███ ██ ██ ██ ", + " █████ ██ ██ ██ ██ ███ ██ ██ ██ ", + " ████ ██ ██ ██ ██ ███ ██ ██ ██ ", + " ███ ██ ██ ██ ██ ██ ██ ██ ██ ", + " ██ ████ ████ █████ ████ ", + " ", + " ████ █ █ ███ ██ ", + " █ ███ ██ ██ █ █ ██ █ ", + "███ █ █ █ █ █ ██ █ ", + "█ █ █ █ █ █ █ █ █ █ ", + "█ █ █ █ █ █ ██ █ █ ", + "█ █ █ █ █ █ █ █ █ ██ ", + "█ █ █ █ ███ ███ ███ ██ ", + " " + ) + ) -val testFrameTbrPercentageFrenchScreen = makeDisplayFrame(arrayOf( - "█ █ █ █ █████ █ █ ████ ███ █ █ ███ ████ █████ ", - "█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", - "█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", - "█ █ █████ █ ████ █ █ ████ █ █ █ █ █ █ ████ █ ", - "█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", - " █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", - " █ █ █ █████ █████ ███ █ █ ███ ███ ███ ████ █ ", - " ", - " ██ ██ ████ ██ ██ ", - " ███████ ███ ███ ██ ██ ████ ██ ", - " ███████ ████ ████ ██ ██ ████ ██ ", - " ██ ██ ██ ██ ██ ██ ██ ██ ", - " ██ ███████ ██ ██ ██ ██ ██ ", - " ██ ███████ ██ ██ ██ ██ ██ ", - "███████ ██ ██ ██ ██ ██ ██ ██ ", - "███████ ██ ██ ██ ██ ██ ██ ██ ", - "██ ██ ██ ██ ██ ██ ██ ██ ██ ", - "██ ██ ██ ██ ██ ██ ██ ██ ██ ", - "██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ", - "██ ██ ██ ██ ██ ██ ██ ██ ██ ████ ", - "██ ██ ██ ██ ██ ██ ██ ██ ██ ████ ", - "██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ", - "██ ██ ██ ██ ██ ██ ████ ", - " ", - " █ ███ ███ █████ ███ ", - " ██ █ █ █ █ ██ █ █ █ ", - "███████ █ ██ █ ██ ██ █ █ ██ ", - "████████ █ █ █ █ █ █ █ █ █ █ ", - "███████ ██ █ ██ █ ██ █ ██ █ ", - " ██ █ █ █ █ ██ █ █ █ █ ", - " █ ███ ███ ███ ███ ", - " " -)) + val testFrameTbrPercentageFrenchScreen = makeDisplayFrame( + arrayOf( + "█ █ █ █ █████ █ █ ████ ███ █ █ ███ ████ █████ ", + "█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + "█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + "█ █ █████ █ ████ █ █ ████ █ █ █ █ █ █ ████ █ ", + "█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + " █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + " █ █ █ █████ █████ ███ █ █ ███ ███ ███ ████ █ ", + " ", + " ██ ██ ████ ██ ██ ", + " ███████ ███ ███ ██ ██ ████ ██ ", + " ███████ ████ ████ ██ ██ ████ ██ ", + " ██ ██ ██ ██ ██ ██ ██ ██ ", + " ██ ███████ ██ ██ ██ ██ ██ ", + " ██ ███████ ██ ██ ██ ██ ██ ", + "███████ ██ ██ ██ ██ ██ ██ ██ ", + "███████ ██ ██ ██ ██ ██ ██ ██ ", + "██ ██ ██ ██ ██ ██ ██ ██ ██ ", + "██ ██ ██ ██ ██ ██ ██ ██ ██ ", + "██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ", + "██ ██ ██ ██ ██ ██ ██ ██ ██ ████ ", + "██ ██ ██ ██ ██ ██ ██ ██ ██ ████ ", + "██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ", + "██ ██ ██ ██ ██ ██ ████ ", + " ", + " █ ███ ███ █████ ███ ", + " ██ █ █ █ █ ██ █ █ █ ", + "███████ █ ██ █ ██ ██ █ █ ██ ", + "████████ █ █ █ █ █ █ █ █ █ █ ", + "███████ ██ █ ██ █ ██ █ ██ █ ", + " ██ █ █ █ █ ██ █ █ █ █ ", + " █ ███ ███ ███ ███ ", + " " + ) + ) -val testFrameTbrDurationFrenchScreen = makeDisplayFrame(arrayOf( - "███ █ █ ████ █ █████ ███ █ █ ███ ████ █████ ", - "█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", - "█ █ █ █ █ █ █████ █ █ █ █ █ █ █ █ █ █ ", - "█ █ █ █ ████ █ ████ █ █ █ █ █ █ ████ █ ", - "█ █ █ █ █ █ ████ █ █ █ █ █ █ █ █ █ █ ", - "█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", - "███ ███ █ █ █████ █████ ███ ███ ███ ████ █ ", - " ", - " ████ ████ █████ ████ ", - " ██ ██ ██ ██ ██ ██ ██ ██ ██ ", - " ███ ██ ██ ██ ██ ██ ██ ██ ", - " ████ ██ ██ ██ ██ ██ ██ ██ ", - " █████ ██ ██ ██ ██ ██ ██ ██ ", - " ██████ ██ ██ ██ ██ ███ ██ ██ ██ ", - "███████████████ ██ ██ ██ ██ ███ ███ ██ ██ ", - "████████████████ ██ ██ ██ ██ ███ ██ ██ ██ ", - "████████████████ ██ ██ ██ ██ ██ ██ ██ ", - "███████████████ ██ ██ ██ ██ ██ ██ ██ ", - " ██████ ██ ██ ██ ██ ███ ██ ██ ██ ", - " █████ ██ ██ ██ ██ ███ ██ ██ ██ ", - " ████ ██ ██ ██ ██ ███ ██ ██ ██ ", - " ███ ██ ██ ██ ██ ██ ██ ██ ██ ", - " ██ ████ ████ █████ ████ ", - " ", - " ████ █ █ ███ ██ ", - " █ ███ ██ ██ █ █ ██ █ ", - "███ █ █ █ █ █ ██ █ ", - "█ █ █ █ █ █ █ █ █ █ ", - "█ █ █ █ █ █ ██ █ █ ", - "█ █ █ █ █ █ █ █ █ ██ ", - "█ █ █ █ ███ ███ ███ ██ ", - " " -)) + val testFrameTbrDurationFrenchScreen = makeDisplayFrame( + arrayOf( + "███ █ █ ████ █ █████ ███ █ █ ███ ████ █████ ", + "█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + "█ █ █ █ █ █ █████ █ █ █ █ █ █ █ █ █ █ ", + "█ █ █ █ ████ █ ████ █ █ █ █ █ █ ████ █ ", + "█ █ █ █ █ █ ████ █ █ █ █ █ █ █ █ █ █ ", + "█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + "███ ███ █ █ █████ █████ ███ ███ ███ ████ █ ", + " ", + " ████ ████ █████ ████ ", + " ██ ██ ██ ██ ██ ██ ██ ██ ██ ", + " ███ ██ ██ ██ ██ ██ ██ ██ ", + " ████ ██ ██ ██ ██ ██ ██ ██ ", + " █████ ██ ██ ██ ██ ██ ██ ██ ", + " ██████ ██ ██ ██ ██ ███ ██ ██ ██ ", + "███████████████ ██ ██ ██ ██ ███ ███ ██ ██ ", + "████████████████ ██ ██ ██ ██ ███ ██ ██ ██ ", + "████████████████ ██ ██ ██ ██ ██ ██ ██ ", + "███████████████ ██ ██ ██ ██ ██ ██ ██ ", + " ██████ ██ ██ ██ ██ ███ ██ ██ ██ ", + " █████ ██ ██ ██ ██ ███ ██ ██ ██ ", + " ████ ██ ██ ██ ██ ███ ██ ██ ██ ", + " ███ ██ ██ ██ ██ ██ ██ ██ ██ ", + " ██ ████ ████ █████ ████ ", + " ", + " ████ █ █ ███ ██ ", + " █ ███ ██ ██ █ █ ██ █ ", + "███ █ █ █ █ █ ██ █ ", + "█ █ █ █ █ █ █ █ █ █ ", + "█ █ █ █ █ █ ██ █ █ ", + "█ █ █ █ █ █ █ █ █ ██ ", + "█ █ █ █ ███ ███ ███ ██ ", + " " + ) + ) -val testFrameTbrPercentageItalianScreen = makeDisplayFrame(arrayOf( - "████ █████ ████ ███ █████ █ █ █████ █ █ █ █ █████ ████ ████ █████ ", - "█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", - "█ █ █ █ █ █ █ ██ █ █ █ █ █ █ █ █ █ █ █ █ █ ", - "████ ████ ████ █ ████ █ █ █ █ █ █ █████ █ ████ ████ ████ █ ", - "█ █ █ █ █ █ █ ██ █ █ █ █ █ █ █ █ █ █ █ ", - "█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", - "█ █████ █ █ ███ █████ █ █ █ ███ █ █ █████ █████ █ ████ █ ", - " ", - " ██ ██ ████ ██ ██ ", - " ███████ ███ ███ ██ ██ ████ ██ ", - " ███████ ████ ████ ██ ██ ████ ██ ", - " ██ ██ ██ ██ ██ ██ ██ ██ ", - " ██ ███████ ██ ██ ██ ██ ██ ", - " ██ ███████ ██ ██ ██ ██ ██ ", - "███████ ██ ██ ██ ██ ██ ██ ██ ", - "███████ ██ ██ ██ ██ ██ ██ ██ ", - "██ ██ ██ ██ ██ ██ ██ ██ ██ ", - "██ ██ ██ ██ ██ ██ ██ ██ ██ ", - "██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ", - "██ ██ ██ ██ ██ ██ ██ ██ ██ ████ ", - "██ ██ ██ ██ ██ ██ ██ ██ ██ ████ ", - "██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ", - "██ ██ ██ ██ ██ ██ ████ ", - " ", - " █ ███ ███ █████ ███ ", - " ██ █ █ █ █ ██ █ █ █ ", - "███████ █ ██ █ ██ ██ █ █ ██ ", - "████████ █ █ █ █ █ █ █ █ █ █ ", - "███████ ██ █ ██ █ ██ █ ██ █ ", - " ██ █ █ █ █ ██ █ █ █ █ ", - " █ ███ ███ ███ ███ ", - " " -)) + val testFrameTbrPercentageItalianScreen = makeDisplayFrame( + arrayOf( + "████ █████ ████ ███ █████ █ █ █████ █ █ █ █ █████ ████ ████ █████ ", + "█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + "█ █ █ █ █ █ █ ██ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + "████ ████ ████ █ ████ █ █ █ █ █ █ █████ █ ████ ████ ████ █ ", + "█ █ █ █ █ █ █ ██ █ █ █ █ █ █ █ █ █ █ █ ", + "█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + "█ █████ █ █ ███ █████ █ █ █ ███ █ █ █████ █████ █ ████ █ ", + " ", + " ██ ██ ████ ██ ██ ", + " ███████ ███ ███ ██ ██ ████ ██ ", + " ███████ ████ ████ ██ ██ ████ ██ ", + " ██ ██ ██ ██ ██ ██ ██ ██ ", + " ██ ███████ ██ ██ ██ ██ ██ ", + " ██ ███████ ██ ██ ██ ██ ██ ", + "███████ ██ ██ ██ ██ ██ ██ ██ ", + "███████ ██ ██ ██ ██ ██ ██ ██ ", + "██ ██ ██ ██ ██ ██ ██ ██ ██ ", + "██ ██ ██ ██ ██ ██ ██ ██ ██ ", + "██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ", + "██ ██ ██ ██ ██ ██ ██ ██ ██ ████ ", + "██ ██ ██ ██ ██ ██ ██ ██ ██ ████ ", + "██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ", + "██ ██ ██ ██ ██ ██ ████ ", + " ", + " █ ███ ███ █████ ███ ", + " ██ █ █ █ █ ██ █ █ █ ", + "███████ █ ██ █ ██ ██ █ █ ██ ", + "████████ █ █ █ █ █ █ █ █ █ █ ", + "███████ ██ █ ██ █ ██ █ ██ █ ", + " ██ █ █ █ █ ██ █ █ █ █ ", + " █ ███ ███ ███ ███ ", + " " + ) + ) -val testFrameTbrDurationItalianScreen = makeDisplayFrame(arrayOf( - "███ █ █ ████ █ █████ █ ████ ████ █████ ", - "█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", - "█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", - "█ █ █ █ ████ █████ █ █████ ████ ████ █ ", - "█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", - "█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", - "███ ███ █ █ █ █ █ █ █ █ ████ █ ", - " ", - " ████ ████ █████ ████ ", - " ██ ██ ██ ██ ██ ██ ██ ██ ██ ", - " ███ ██ ██ ██ ██ ██ ██ ██ ", - " ████ ██ ██ ██ ██ ██ ██ ██ ", - " █████ ██ ██ ██ ██ ██ ██ ██ ", - " ██████ ██ ██ ██ ██ ███ ██ ██ ██ ", - "███████████████ ██ ██ ██ ██ ███ ███ ██ ██ ", - "████████████████ ██ ██ ██ ██ ███ ██ ██ ██ ", - "████████████████ ██ ██ ██ ██ ██ ██ ██ ", - "███████████████ ██ ██ ██ ██ ██ ██ ██ ", - " ██████ ██ ██ ██ ██ ███ ██ ██ ██ ", - " █████ ██ ██ ██ ██ ███ ██ ██ ██ ", - " ████ ██ ██ ██ ██ ███ ██ ██ ██ ", - " ███ ██ ██ ██ ██ ██ ██ ██ ██ ", - " ██ ████ ████ █████ ████ ", - " ", - " ████ █ █ ███ ██ ", - " █ ███ ██ ██ █ █ ██ █ ", - "███ █ █ █ █ █ ██ █ ", - "█ █ █ █ █ █ █ █ █ █ ", - "█ █ █ █ █ █ ██ █ █ ", - "█ █ █ █ █ █ █ █ █ ██ ", - "█ █ █ █ ███ ███ ███ ██ ", - " " -)) + val testFrameTbrDurationItalianScreen = makeDisplayFrame( + arrayOf( + "███ █ █ ████ █ █████ █ ████ ████ █████ ", + "█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + "█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + "█ █ █ █ ████ █████ █ █████ ████ ████ █ ", + "█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + "█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + "███ ███ █ █ █ █ █ █ █ █ ████ █ ", + " ", + " ████ ████ █████ ████ ", + " ██ ██ ██ ██ ██ ██ ██ ██ ██ ", + " ███ ██ ██ ██ ██ ██ ██ ██ ", + " ████ ██ ██ ██ ██ ██ ██ ██ ", + " █████ ██ ██ ██ ██ ██ ██ ██ ", + " ██████ ██ ██ ██ ██ ███ ██ ██ ██ ", + "███████████████ ██ ██ ██ ██ ███ ███ ██ ██ ", + "████████████████ ██ ██ ██ ██ ███ ██ ██ ██ ", + "████████████████ ██ ██ ██ ██ ██ ██ ██ ", + "███████████████ ██ ██ ██ ██ ██ ██ ██ ", + " ██████ ██ ██ ██ ██ ███ ██ ██ ██ ", + " █████ ██ ██ ██ ██ ███ ██ ██ ██ ", + " ████ ██ ██ ██ ██ ███ ██ ██ ██ ", + " ███ ██ ██ ██ ██ ██ ██ ██ ██ ", + " ██ ████ ████ █████ ████ ", + " ", + " ████ █ █ ███ ██ ", + " █ ███ ██ ██ █ █ ██ █ ", + "███ █ █ █ █ █ ██ █ ", + "█ █ █ █ █ █ █ █ █ █ ", + "█ █ █ █ █ █ ██ █ █ ", + "█ █ █ █ █ █ █ █ █ ██ ", + "█ █ █ █ ███ ███ ███ ██ ", + " " + ) + ) -val testFrameTbrPercentageRussianScreen = makeDisplayFrame(arrayOf( - "█████ ████ ███ █ █ █████ █ █ █████ ████ █████ ███ ", - "█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", - "█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", - "█ █ ████ █ █ █ █ ████ █████ █ ████ ████ █ ", - "█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", - "█ █ █ █ █ █████ █ █ █ █ █ █ █ █ █ █ ", - "█ █ █ ███ █ █████ █ █ █ ████ ████ ███ ", - " ", - " ██ ██ ████ ██ ██ ", - " ███████ ███ ███ ██ ██ ████ ██ ", - " ███████ ████ ████ ██ ██ ████ ██ ", - " ██ ██ ██ ██ ██ ██ ██ ██ ", - " ██ ███████ ██ ██ ██ ██ ██ ", - " ██ ███████ ██ ██ ██ ██ ██ ", - "███████ ██ ██ ██ ██ ██ ██ ██ ", - "███████ ██ ██ ██ ██ ██ ██ ██ ", - "██ ██ ██ ██ ██ ██ ██ ██ ██ ", - "██ ██ ██ ██ ██ ██ ██ ██ ██ ", - "██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ", - "██ ██ ██ ██ ██ ██ ██ ██ ██ ████ ", - "██ ██ ██ ██ ██ ██ ██ ██ ██ ████ ", - "██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ", - "██ ██ ██ ██ ██ ██ ████ ", - " ", - " █ ███ ███ █████ ███ ", - " ██ █ █ █ █ ██ █ █ █ ", - "███████ █ ██ █ ██ ██ █ █ ██ ", - "████████ █ █ █ █ █ █ █ █ █ █ ", - "███████ ██ █ ██ █ ██ █ ██ █ ", - " ██ █ █ █ █ ██ █ █ █ █ ", - " █ ███ ███ ███ ███ ", - " " -)) + val testFrameTbrPercentageRussianScreen = makeDisplayFrame( + arrayOf( + "█████ ████ ███ █ █ █████ █ █ █████ ████ █████ ███ ", + "█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + "█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + "█ █ ████ █ █ █ █ ████ █████ █ ████ ████ █ ", + "█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + "█ █ █ █ █ █████ █ █ █ █ █ █ █ █ █ █ ", + "█ █ █ ███ █ █████ █ █ █ ████ ████ ███ ", + " ", + " ██ ██ ████ ██ ██ ", + " ███████ ███ ███ ██ ██ ████ ██ ", + " ███████ ████ ████ ██ ██ ████ ██ ", + " ██ ██ ██ ██ ██ ██ ██ ██ ", + " ██ ███████ ██ ██ ██ ██ ██ ", + " ██ ███████ ██ ██ ██ ██ ██ ", + "███████ ██ ██ ██ ██ ██ ██ ██ ", + "███████ ██ ██ ██ ██ ██ ██ ██ ", + "██ ██ ██ ██ ██ ██ ██ ██ ██ ", + "██ ██ ██ ██ ██ ██ ██ ██ ██ ", + "██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ", + "██ ██ ██ ██ ██ ██ ██ ██ ██ ████ ", + "██ ██ ██ ██ ██ ██ ██ ██ ██ ████ ", + "██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ", + "██ ██ ██ ██ ██ ██ ████ ", + " ", + " █ ███ ███ █████ ███ ", + " ██ █ █ █ █ ██ █ █ █ ", + "███████ █ ██ █ ██ ██ █ █ ██ ", + "████████ █ █ █ █ █ █ █ █ █ █ ", + "███████ ██ █ ██ █ ██ █ ██ █ ", + " ██ █ █ █ █ ██ █ █ █ █ ", + " █ ███ ███ ███ ███ ", + " " + ) + ) -val testFrameTbrDurationRussianScreen = makeDisplayFrame(arrayOf( - "█████ ████ ███ ██ ███ ████ █ █ █ █ █ █████ ████ █████ ███ ", - "█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ██ █ █ █ █ █ █ ", - "█ █ █ █ █ █ █ █ █ █ █ █ ███ █ █ █ █ █ █ █ █ ", - "█ █ ████ █ █ █ █ █ █ █ █ ███ █ █ █ █ ████ ████ █ ", - "█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", - "█ █ █ █ █ █████ █ █ █ █ █ █ █ ██ █ █ ██ █ █ █ █ █ █ ", - "█ █ █ ███ █ █ ███ ██ █ █ █ █ █ █ █ ██ ████ ████ ███ ", - " ", - " ████ ████ █████ ████ ", - " ██ ██ ██ ██ ██ ██ ██ ██ ██ ", - " ███ ██ ██ ██ ██ ██ ██ ██ ", - " ████ ██ ██ ██ ██ ██ ██ ██ ", - " █████ ██ ██ ██ ██ ██ ██ ██ ", - " ██████ ██ ██ ██ ██ ███ ██ ██ ██ ", - "███████████████ ██ ██ ██ ██ ███ ███ ██ ██ ", - "████████████████ ██ ██ ██ ██ ███ ██ ██ ██ ", - "████████████████ ██ ██ ██ ██ ██ ██ ██ ", - "███████████████ ██ ██ ██ ██ ██ ██ ██ ", - " ██████ ██ ██ ██ ██ ███ ██ ██ ██ ", - " █████ ██ ██ ██ ██ ███ ██ ██ ██ ", - " ████ ██ ██ ██ ██ ███ ██ ██ ██ ", - " ███ ██ ██ ██ ██ ██ ██ ██ ██ ", - " ██ ████ ████ █████ ████ ", - " ", - " ████ █ █ ███ ██ ", - " █ ███ ██ ██ █ █ ██ █ ", - "███ █ █ █ █ █ ██ █ ", - "█ █ █ █ █ █ █ █ █ █ ", - "█ █ █ █ █ █ ██ █ █ ", - "█ █ █ █ █ █ █ █ █ ██ ", - "█ █ █ █ ███ ███ ███ ██ ", - " " -)) + val testFrameTbrDurationRussianScreen = makeDisplayFrame( + arrayOf( + "█████ ████ ███ ██ ███ ████ █ █ █ █ █ █████ ████ █████ ███ ", + "█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ██ █ █ █ █ █ █ ", + "█ █ █ █ █ █ █ █ █ █ █ █ ███ █ █ █ █ █ █ █ █ ", + "█ █ ████ █ █ █ █ █ █ █ █ ███ █ █ █ █ ████ ████ █ ", + "█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + "█ █ █ █ █ █████ █ █ █ █ █ █ █ ██ █ █ ██ █ █ █ █ █ █ ", + "█ █ █ ███ █ █ ███ ██ █ █ █ █ █ █ █ ██ ████ ████ ███ ", + " ", + " ████ ████ █████ ████ ", + " ██ ██ ██ ██ ██ ██ ██ ██ ██ ", + " ███ ██ ██ ██ ██ ██ ██ ██ ", + " ████ ██ ██ ██ ██ ██ ██ ██ ", + " █████ ██ ██ ██ ██ ██ ██ ██ ", + " ██████ ██ ██ ██ ██ ███ ██ ██ ██ ", + "███████████████ ██ ██ ██ ██ ███ ███ ██ ██ ", + "████████████████ ██ ██ ██ ██ ███ ██ ██ ██ ", + "████████████████ ██ ██ ██ ██ ██ ██ ██ ", + "███████████████ ██ ██ ██ ██ ██ ██ ██ ", + " ██████ ██ ██ ██ ██ ███ ██ ██ ██ ", + " █████ ██ ██ ██ ██ ███ ██ ██ ██ ", + " ████ ██ ██ ██ ██ ███ ██ ██ ██ ", + " ███ ██ ██ ██ ██ ██ ██ ██ ██ ", + " ██ ████ ████ █████ ████ ", + " ", + " ████ █ █ ███ ██ ", + " █ ███ ██ ██ █ █ ██ █ ", + "███ █ █ █ █ █ ██ █ ", + "█ █ █ █ █ █ █ █ █ █ ", + "█ █ █ █ █ █ ██ █ █ ", + "█ █ █ █ █ █ █ █ █ ██ ", + "█ █ █ █ ███ ███ ███ ██ ", + " " + ) + ) -val testFrameTbrPercentageTurkishScreen = makeDisplayFrame(arrayOf( - " ███ ████ █ █ █ █ █ █ █████ ███ █████ ████ █ ", - "█ █ █ █ █ █ █ █ █ █ █ █ █ ", - "█ █ █ █ █ █ █ █ █ █ █ █ █ █ ███ ", - "█ ███ ████ █████ █ █ █ █ █ █ █ ████ ███ █ ", - "█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", - "█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", - " ████ ████ █ █ █ ███ █████ ███ █████ ████ ███ ", - " ", - " ██ ██ ████ ██ ██ ", - " ███████ ███ ███ ██ ██ ████ ██ ", - " ███████ ████ ████ ██ ██ ████ ██ ", - " ██ ██ ██ ██ ██ ██ ██ ██ ", - " ██ ███████ ██ ██ ██ ██ ██ ", - " ██ ███████ ██ ██ ██ ██ ██ ", - "███████ ██ ██ ██ ██ ██ ██ ██ ", - "███████ ██ ██ ██ ██ ██ ██ ██ ", - "██ ██ ██ ██ ██ ██ ██ ██ ██ ", - "██ ██ ██ ██ ██ ██ ██ ██ ██ ", - "██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ", - "██ ██ ██ ██ ██ ██ ██ ██ ██ ████ ", - "██ ██ ██ ██ ██ ██ ██ ██ ██ ████ ", - "██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ", - "██ ██ ██ ██ ██ ██ ████ ", - " ", - " █ ███ ███ █████ ███ ", - " ██ █ █ █ █ ██ █ █ █ ", - "███████ █ ██ █ ██ ██ █ █ ██ ", - "████████ █ █ █ █ █ █ █ █ █ █ ", - "███████ ██ █ ██ █ ██ █ ██ █ ", - " ██ █ █ █ █ ██ █ █ █ █ ", - " █ ███ ███ ███ ███ ", - " " -)) + val testFrameTbrPercentageTurkishScreen = makeDisplayFrame( + arrayOf( + " ███ ████ █ █ █ █ █ █ █████ ███ █████ ████ █ ", + "█ █ █ █ █ █ █ █ █ █ █ █ █ ", + "█ █ █ █ █ █ █ █ █ █ █ █ █ █ ███ ", + "█ ███ ████ █████ █ █ █ █ █ █ █ ████ ███ █ ", + "█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + "█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + " ████ ████ █ █ █ ███ █████ ███ █████ ████ ███ ", + " ", + " ██ ██ ████ ██ ██ ", + " ███████ ███ ███ ██ ██ ████ ██ ", + " ███████ ████ ████ ██ ██ ████ ██ ", + " ██ ██ ██ ██ ██ ██ ██ ██ ", + " ██ ███████ ██ ██ ██ ██ ██ ", + " ██ ███████ ██ ██ ██ ██ ██ ", + "███████ ██ ██ ██ ██ ██ ██ ██ ", + "███████ ██ ██ ██ ██ ██ ██ ██ ", + "██ ██ ██ ██ ██ ██ ██ ██ ██ ", + "██ ██ ██ ██ ██ ██ ██ ██ ██ ", + "██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ", + "██ ██ ██ ██ ██ ██ ██ ██ ██ ████ ", + "██ ██ ██ ██ ██ ██ ██ ██ ██ ████ ", + "██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ", + "██ ██ ██ ██ ██ ██ ████ ", + " ", + " █ ███ ███ █████ ███ ", + " ██ █ █ █ █ ██ █ █ █ ", + "███████ █ ██ █ ██ ██ █ █ ██ ", + "████████ █ █ █ █ █ █ █ █ █ █ ", + "███████ ██ █ ██ █ ██ █ ██ █ ", + " ██ █ █ █ █ ██ █ █ █ █ ", + " █ ███ ███ ███ ███ ", + " " + ) + ) -val testFrameTbrDurationTurkishScreen = makeDisplayFrame(arrayOf( - " ███ ████ █ █ ████ █ █ ████ █████ ████ █ ", - "█ █ █ █ █ █ █ █ █ █ █ ", - "█ █ █ █ █ █ █ █ █ █ █ █ ███ ", - "█ ███ ████ █████ ███ █ █ ████ ████ ███ █ ", - "█ █ █ █ █ █ █ █ █ █ █ █ █ █ ", - "█ █ █ █ █ █ █ █ █ █ █ █ █ █ ", - " ████ ████ █ █ ████ ███ █ █ █████ ████ ███ ", - " ", - " ████ ████ █████ ████ ", - " ██ ██ ██ ██ ██ ██ ██ ██ ██ ", - " ███ ██ ██ ██ ██ ██ ██ ██ ", - " ████ ██ ██ ██ ██ ██ ██ ██ ", - " █████ ██ ██ ██ ██ ██ ██ ██ ", - " ██████ ██ ██ ██ ██ ███ ██ ██ ██ ", - "███████████████ ██ ██ ██ ██ ███ ███ ██ ██ ", - "████████████████ ██ ██ ██ ██ ███ ██ ██ ██ ", - "████████████████ ██ ██ ██ ██ ██ ██ ██ ", - "███████████████ ██ ██ ██ ██ ██ ██ ██ ", - " ██████ ██ ██ ██ ██ ███ ██ ██ ██ ", - " █████ ██ ██ ██ ██ ███ ██ ██ ██ ", - " ████ ██ ██ ██ ██ ███ ██ ██ ██ ", - " ███ ██ ██ ██ ██ ██ ██ ██ ██ ", - " ██ ████ ████ █████ ████ ", - " ", - " ████ █ █ ███ ██ ", - " █ ███ ██ ██ █ █ ██ █ ", - "███ █ █ █ █ █ ██ █ ", - "█ █ █ █ █ █ █ █ █ █ ", - "█ █ █ █ █ █ ██ █ █ ", - "█ █ █ █ █ █ █ █ █ ██ ", - "█ █ █ █ ███ ███ ███ ██ ", - " " -)) + val testFrameTbrDurationTurkishScreen = makeDisplayFrame( + arrayOf( + " ███ ████ █ █ ████ █ █ ████ █████ ████ █ ", + "█ █ █ █ █ █ █ █ █ █ █ ", + "█ █ █ █ █ █ █ █ █ █ █ █ ███ ", + "█ ███ ████ █████ ███ █ █ ████ ████ ███ █ ", + "█ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + "█ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + " ████ ████ █ █ ████ ███ █ █ █████ ████ ███ ", + " ", + " ████ ████ █████ ████ ", + " ██ ██ ██ ██ ██ ██ ██ ██ ██ ", + " ███ ██ ██ ██ ██ ██ ██ ██ ", + " ████ ██ ██ ██ ██ ██ ██ ██ ", + " █████ ██ ██ ██ ██ ██ ██ ██ ", + " ██████ ██ ██ ██ ██ ███ ██ ██ ██ ", + "███████████████ ██ ██ ██ ██ ███ ███ ██ ██ ", + "████████████████ ██ ██ ██ ██ ███ ██ ██ ██ ", + "████████████████ ██ ██ ██ ██ ██ ██ ██ ", + "███████████████ ██ ██ ██ ██ ██ ██ ██ ", + " ██████ ██ ██ ██ ██ ███ ██ ██ ██ ", + " █████ ██ ██ ██ ██ ███ ██ ██ ██ ", + " ████ ██ ██ ██ ██ ███ ██ ██ ██ ", + " ███ ██ ██ ██ ██ ██ ██ ██ ██ ", + " ██ ████ ████ █████ ████ ", + " ", + " ████ █ █ ███ ██ ", + " █ ███ ██ ██ █ █ ██ █ ", + "███ █ █ █ █ █ ██ █ ", + "█ █ █ █ █ █ █ █ █ █ ", + "█ █ █ █ █ █ ██ █ █ ", + "█ █ █ █ █ █ █ █ █ ██ ", + "█ █ █ █ ███ ███ ███ ██ ", + " " + ) + ) -val testFrameTbrPercentagePolishScreen = makeDisplayFrame(arrayOf( - "████ ████ ███ ███ █████ █ █ █████ █████ ███ ████ ", - "█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", - "█ █ █ █ █ █ █ █ ██ █ █ █ █ █ █ █ ", - "████ ████ █ █ █ ████ █ █ █ █ █ █ █ ████ ", - "█ █ █ █ █ █ █ █ ██ █ █ █ █ █ ", - "█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", - "█ █ █ ███ ███ █████ █ █ █ █ ███ █ ", - " ", - " ██ ████ ████ ██ ██ ", - " ███████ ███ ██ ██ ██ ██ ████ ██ ", - " ███████ ████ ██ ██ ██ ██ ████ ██ ", - " ██ ██ ██ ██ ██ ██ ██ ██ ██ ", - " ██ ███████ ██ ██ ██ ██ ██ ██ ", - " ██ ███████ ██ ██ ██ ██ ██ ██ ", - "███████ ██ ██ ██ ██ ██ ██ ██ ██ ", - "███████ ██ ██ ██ ██ ██ ██ ██ ██ ", - "██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ", - "██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ", - "██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ", - "██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ████ ", - "██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ████ ", - "██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ", - "██ ██ ██ ██ ██ ████ ████ ", - " ", - " ", - " ", - " ", - " ", - " ", - " ", - " ", - " " -)) + val testFrameTbrPercentagePolishScreen = makeDisplayFrame( + arrayOf( + "████ ████ ███ ███ █████ █ █ █████ █████ ███ ████ ", + "█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + "█ █ █ █ █ █ █ █ ██ █ █ █ █ █ █ █ ", + "████ ████ █ █ █ ████ █ █ █ █ █ █ █ ████ ", + "█ █ █ █ █ █ █ █ ██ █ █ █ █ █ ", + "█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + "█ █ █ ███ ███ █████ █ █ █ █ ███ █ ", + " ", + " ██ ████ ████ ██ ██ ", + " ███████ ███ ██ ██ ██ ██ ████ ██ ", + " ███████ ████ ██ ██ ██ ██ ████ ██ ", + " ██ ██ ██ ██ ██ ██ ██ ██ ██ ", + " ██ ███████ ██ ██ ██ ██ ██ ██ ", + " ██ ███████ ██ ██ ██ ██ ██ ██ ", + "███████ ██ ██ ██ ██ ██ ██ ██ ██ ", + "███████ ██ ██ ██ ██ ██ ██ ██ ██ ", + "██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ", + "██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ", + "██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ", + "██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ████ ", + "██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ████ ", + "██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ", + "██ ██ ██ ██ ██ ████ ████ ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " " + ) + ) -val testFrameTbrDurationPolishScreen = makeDisplayFrame(arrayOf( - " ███ █████ █ ████ █████ ████ █ █ █ █ █ ███ █ █████ ███ ████ ", - "█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", - "█ █ █ █ █ █ █ █ █ █ █ █ ██ █ █ █ █ █ █ █ █ █ ", - "█ █ █████ ███ █ ████ █ █ █ █████ █ █ █ █ █████ █ █ █ ████ ", - "█ █ █ █ █ █ █ █ █ █ █ █ █ █ ██ █ █ █ █ █ █ █ ", - "█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", - " ███ █████ █ █ ████ █ █ █ █ █ █ █ █ █ ███ █ █ █ ███ █ ", - " ", - " ████ ████ █████ ████ ", - " ██ ██ ██ ██ ██ ██ ██ ██ ██ ", - " ███ ██ ██ ██ ██ ██ ██ ██ ", - " ████ ██ ██ ██ ██ ██ ██ ██ ", - " █████ ██ ██ ██ ██ ██ ██ ██ ", - " ██████ ██ ██ ██ ██ ███ ██ ██ ██ ", - "███████████████ ██ ██ ██ ██ ███ ███ ██ ██ ", - "████████████████ ██ ██ ██ ██ ███ ██ ██ ██ ", - "████████████████ ██ ██ ██ ██ ██ ██ ██ ", - "███████████████ ██ ██ ██ ██ ██ ██ ██ ", - " ██████ ██ ██ ██ ██ ███ ██ ██ ██ ", - " █████ ██ ██ ██ ██ ███ ██ ██ ██ ", - " ████ ██ ██ ██ ██ ███ ██ ██ ██ ", - " ███ ██ ██ ██ ██ ██ ██ ██ ██ ", - " ██ ████ ████ █████ ████ ", - " ", - " ████ █ █ ███ ██ ", - " █ ███ ██ ██ █ █ ██ █ ", - "███ █ █ █ █ █ ██ █ ", - "█ █ █ █ █ █ █ █ █ █ ", - "█ █ █ █ █ █ ██ █ █ ", - "█ █ █ █ █ █ █ █ █ ██ ", - "█ █ █ █ ███ ███ ███ ██ ", - " " -)) + val testFrameTbrDurationPolishScreen = makeDisplayFrame( + arrayOf( + " ███ █████ █ ████ █████ ████ █ █ █ █ █ ███ █ █████ ███ ████ ", + "█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + "█ █ █ █ █ █ █ █ █ █ █ █ ██ █ █ █ █ █ █ █ █ █ ", + "█ █ █████ ███ █ ████ █ █ █ █████ █ █ █ █ █████ █ █ █ ████ ", + "█ █ █ █ █ █ █ █ █ █ █ █ █ █ ██ █ █ █ █ █ █ █ ", + "█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + " ███ █████ █ █ ████ █ █ █ █ █ █ █ █ █ ███ █ █ █ ███ █ ", + " ", + " ████ ████ █████ ████ ", + " ██ ██ ██ ██ ██ ██ ██ ██ ██ ", + " ███ ██ ██ ██ ██ ██ ██ ██ ", + " ████ ██ ██ ██ ██ ██ ██ ██ ", + " █████ ██ ██ ██ ██ ██ ██ ██ ", + " ██████ ██ ██ ██ ██ ███ ██ ██ ██ ", + "███████████████ ██ ██ ██ ██ ███ ███ ██ ██ ", + "████████████████ ██ ██ ██ ██ ███ ██ ██ ██ ", + "████████████████ ██ ██ ██ ██ ██ ██ ██ ", + "███████████████ ██ ██ ██ ██ ██ ██ ██ ", + " ██████ ██ ██ ██ ██ ███ ██ ██ ██ ", + " █████ ██ ██ ██ ██ ███ ██ ██ ██ ", + " ████ ██ ██ ██ ██ ███ ██ ██ ██ ", + " ███ ██ ██ ██ ██ ██ ██ ██ ██ ", + " ██ ████ ████ █████ ████ ", + " ", + " ████ █ █ ███ ██ ", + " █ ███ ██ ██ █ █ ██ █ ", + "███ █ █ █ █ █ ██ █ ", + "█ █ █ █ █ █ █ █ █ █ ", + "█ █ █ █ █ █ ██ █ █ ", + "█ █ █ █ █ █ █ █ █ ██ ", + "█ █ █ █ ███ ███ ███ ██ ", + " " + ) + ) -val testFrameTbrPercentageCzechScreen = makeDisplayFrame(arrayOf( - "████ ████ ███ ███ █████ █ █ █████ ███ ███ ████ ███ ", - "█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", - "█ █ █ █ █ █ █ █ ██ █ █ █ █ █ █ █ █ █ █ ", - "████ ████ █ █ █ ████ █ █ █ █ █ █ █ █ ████ █ █ ", - "█ █ █ █ █ █ █ █ ██ █ █ █ █ █ █ █ █ █ ", - "█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", - "█ █ █ ███ ███ █████ █ █ █ ███ ███ ████ ███ ", - " ", - " ██ ██ ████ ██ ██ ", - " ███████ ███ ███ ██ ██ ████ ██ ", - " ███████ ████ ████ ██ ██ ████ ██ ", - " ██ ██ ██ ██ ██ ██ ██ ██ ", - " ██ ███████ ██ ██ ██ ██ ██ ", - " ██ ███████ ██ ██ ██ ██ ██ ", - "███████ ██ ██ ██ ██ ██ ██ ██ ", - "███████ ██ ██ ██ ██ ██ ██ ██ ", - "██ ██ ██ ██ ██ ██ ██ ██ ██ ", - "██ ██ ██ ██ ██ ██ ██ ██ ██ ", - "██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ", - "██ ██ ██ ██ ██ ██ ██ ██ ██ ████ ", - "██ ██ ██ ██ ██ ██ ██ ██ ██ ████ ", - "██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ", - "██ ██ ██ ██ ██ ██ ████ ", - " ", - " █ ███ ███ █████ ███ ", - " ██ █ █ █ █ ██ █ █ █ ", - "███████ █ ██ █ ██ ██ █ █ ██ ", - "████████ █ █ █ █ █ █ █ █ █ █ ", - "███████ ██ █ ██ █ ██ █ ██ █ ", - " ██ █ █ █ █ ██ █ █ █ █ ", - " █ ███ ███ ███ ███ ", - " " -)) + val testFrameTbrPercentageCzechScreen = makeDisplayFrame( + arrayOf( + "████ ████ ███ ███ █████ █ █ █████ ███ ███ ████ ███ ", + "█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + "█ █ █ █ █ █ █ █ ██ █ █ █ █ █ █ █ █ █ █ ", + "████ ████ █ █ █ ████ █ █ █ █ █ █ █ █ ████ █ █ ", + "█ █ █ █ █ █ █ █ ██ █ █ █ █ █ █ █ █ █ ", + "█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + "█ █ █ ███ ███ █████ █ █ █ ███ ███ ████ ███ ", + " ", + " ██ ██ ████ ██ ██ ", + " ███████ ███ ███ ██ ██ ████ ██ ", + " ███████ ████ ████ ██ ██ ████ ██ ", + " ██ ██ ██ ██ ██ ██ ██ ██ ", + " ██ ███████ ██ ██ ██ ██ ██ ", + " ██ ███████ ██ ██ ██ ██ ██ ", + "███████ ██ ██ ██ ██ ██ ██ ██ ", + "███████ ██ ██ ██ ██ ██ ██ ██ ", + "██ ██ ██ ██ ██ ██ ██ ██ ██ ", + "██ ██ ██ ██ ██ ██ ██ ██ ██ ", + "██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ", + "██ ██ ██ ██ ██ ██ ██ ██ ██ ████ ", + "██ ██ ██ ██ ██ ██ ██ ██ ██ ████ ", + "██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ", + "██ ██ ██ ██ ██ ██ ████ ", + " ", + " █ ███ ███ █████ ███ ", + " ██ █ █ █ █ ██ █ █ █ ", + "███████ █ ██ █ ██ ██ █ █ ██ ", + "████████ █ █ █ █ █ █ █ █ █ █ ", + "███████ ██ █ ██ █ ██ █ ██ █ ", + " ██ █ █ █ █ ██ █ █ █ █ ", + " █ ███ ███ ███ ███ ", + " " + ) + ) -val testFrameTbrDurationCzechScreen = makeDisplayFrame(arrayOf( - "█████ ████ █ █ █ █ █ █ ███ ████ ███ ", - " █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", - " █ █ █ █ █ █ ██ █ ███ █ █ █ █ █ █ ", - " █ ████ █ █ █ █ █ █ █ █ █ █ ████ █ █ ", - " █ █ █ █ █ █ █ █ ██ █ █ █ █ █ █ █ ", - " █ █ █ █ █ █████ █ █ █ █ █ █ █ █ █ ", - " █ █ █ █ █ █ █ █ ███ ███ ████ ███ ", - " ", - " ████ ████ █████ ████ ", - " ██ ██ ██ ██ ██ ██ ██ ██ ██ ", - " ███ ██ ██ ██ ██ ██ ██ ██ ", - " ████ ██ ██ ██ ██ ██ ██ ██ ", - " █████ ██ ██ ██ ██ ██ ██ ██ ", - " ██████ ██ ██ ██ ██ ███ ██ ██ ██ ", - "███████████████ ██ ██ ██ ██ ███ ███ ██ ██ ", - "████████████████ ██ ██ ██ ██ ███ ██ ██ ██ ", - "████████████████ ██ ██ ██ ██ ██ ██ ██ ", - "███████████████ ██ ██ ██ ██ ██ ██ ██ ", - " ██████ ██ ██ ██ ██ ███ ██ ██ ██ ", - " █████ ██ ██ ██ ██ ███ ██ ██ ██ ", - " ████ ██ ██ ██ ██ ███ ██ ██ ██ ", - " ███ ██ ██ ██ ██ ██ ██ ██ ██ ", - " ██ ████ ████ █████ ████ ", - " ", - " ████ █ █ ███ ██ ", - " █ ███ ██ ██ █ █ ██ █ ", - "███ █ █ █ █ █ ██ █ ", - "█ █ █ █ █ █ █ █ █ █ ", - "█ █ █ █ █ █ ██ █ █ ", - "█ █ █ █ █ █ █ █ █ ██ ", - "█ █ █ █ ███ ███ ███ ██ ", - " " -)) + val testFrameTbrDurationCzechScreen = makeDisplayFrame( + arrayOf( + "█████ ████ █ █ █ █ █ █ ███ ████ ███ ", + " █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + " █ █ █ █ █ █ ██ █ ███ █ █ █ █ █ █ ", + " █ ████ █ █ █ █ █ █ █ █ █ █ ████ █ █ ", + " █ █ █ █ █ █ █ █ ██ █ █ █ █ █ █ █ ", + " █ █ █ █ █ █████ █ █ █ █ █ █ █ █ █ ", + " █ █ █ █ █ █ █ █ ███ ███ ████ ███ ", + " ", + " ████ ████ █████ ████ ", + " ██ ██ ██ ██ ██ ██ ██ ██ ██ ", + " ███ ██ ██ ██ ██ ██ ██ ██ ", + " ████ ██ ██ ██ ██ ██ ██ ██ ", + " █████ ██ ██ ██ ██ ██ ██ ██ ", + " ██████ ██ ██ ██ ██ ███ ██ ██ ██ ", + "███████████████ ██ ██ ██ ██ ███ ███ ██ ██ ", + "████████████████ ██ ██ ██ ██ ███ ██ ██ ██ ", + "████████████████ ██ ██ ██ ██ ██ ██ ██ ", + "███████████████ ██ ██ ██ ██ ██ ██ ██ ", + " ██████ ██ ██ ██ ██ ███ ██ ██ ██ ", + " █████ ██ ██ ██ ██ ███ ██ ██ ██ ", + " ████ ██ ██ ██ ██ ███ ██ ██ ██ ", + " ███ ██ ██ ██ ██ ██ ██ ██ ██ ", + " ██ ████ ████ █████ ████ ", + " ", + " ████ █ █ ███ ██ ", + " █ ███ ██ ██ █ █ ██ █ ", + "███ █ █ █ █ █ ██ █ ", + "█ █ █ █ █ █ █ █ █ █ ", + "█ █ █ █ █ █ ██ █ █ ", + "█ █ █ █ █ █ █ █ █ ██ ", + "█ █ █ █ ███ ███ ███ ██ ", + " " + ) + ) -val testFrameTbrPercentageHungarianScreen = makeDisplayFrame(arrayOf( - "█████ ████ ████ ████ █████ █ █████ █ █ █ █ █ ", - " █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", - " █ █ █ █ █ █ █ █ █ █ █ █ █████ █ █ ", - " █ ████ ████ ███ █ █ █ █ █████ █ █ ██ ", - " █ █ █ █ █ █ █ █ █ █ █ █ █ ████ █ █ ", - " █ █ █ █ █ █ █ █████ █ █ █ █ █ █ █ ", - " █ ████ █ █ ████ █████ █ █ █████ █ █ █████ █████ █ █ ", - " ", - " ██ ██ ████ ██ ██ ", - " ███████ ███ ███ ██ ██ ████ ██ ", - " ███████ ████ ████ ██ ██ ████ ██ ", - " ██ ██ ██ ██ ██ ██ ██ ██ ", - " ██ ███████ ██ ██ ██ ██ ██ ", - " ██ ███████ ██ ██ ██ ██ ██ ", - "███████ ██ ██ ██ ██ ██ ██ ██ ", - "███████ ██ ██ ██ ██ ██ ██ ██ ", - "██ ██ ██ ██ ██ ██ ██ ██ ██ ", - "██ ██ ██ ██ ██ ██ ██ ██ ██ ", - "██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ", - "██ ██ ██ ██ ██ ██ ██ ██ ██ ████ ", - "██ ██ ██ ██ ██ ██ ██ ██ ██ ████ ", - "██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ", - "██ ██ ██ ██ ██ ██ ████ ", - " ", - " █ ███ ███ █████ ███ ", - " ██ █ █ █ █ ██ █ █ █ ", - "███████ █ ██ █ ██ ██ █ █ ██ ", - "████████ █ █ █ █ █ █ █ █ █ █ ", - "███████ ██ █ ██ █ ██ █ ██ █ ", - " ██ █ █ █ █ ██ █ █ █ █ ", - " █ ███ ███ ███ ███ ", - " " -)) + val testFrameTbrPercentageHungarianScreen = makeDisplayFrame( + arrayOf( + "█████ ████ ████ ████ █████ █ █████ █ █ █ █ █ ", + " █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + " █ █ █ █ █ █ █ █ █ █ █ █ █████ █ █ ", + " █ ████ ████ ███ █ █ █ █ █████ █ █ ██ ", + " █ █ █ █ █ █ █ █ █ █ █ █ █ ████ █ █ ", + " █ █ █ █ █ █ █ █████ █ █ █ █ █ █ █ ", + " █ ████ █ █ ████ █████ █ █ █████ █ █ █████ █████ █ █ ", + " ", + " ██ ██ ████ ██ ██ ", + " ███████ ███ ███ ██ ██ ████ ██ ", + " ███████ ████ ████ ██ ██ ████ ██ ", + " ██ ██ ██ ██ ██ ██ ██ ██ ", + " ██ ███████ ██ ██ ██ ██ ██ ", + " ██ ███████ ██ ██ ██ ██ ██ ", + "███████ ██ ██ ██ ██ ██ ██ ██ ", + "███████ ██ ██ ██ ██ ██ ██ ██ ", + "██ ██ ██ ██ ██ ██ ██ ██ ██ ", + "██ ██ ██ ██ ██ ██ ██ ██ ██ ", + "██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ", + "██ ██ ██ ██ ██ ██ ██ ██ ██ ████ ", + "██ ██ ██ ██ ██ ██ ██ ██ ██ ████ ", + "██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ", + "██ ██ ██ ██ ██ ██ ████ ", + " ", + " █ ███ ███ █████ ███ ", + " ██ █ █ █ █ ██ █ █ █ ", + "███████ █ ██ █ ██ ██ █ █ ██ ", + "████████ █ █ █ █ █ █ █ █ █ █ ", + "███████ ██ █ ██ █ ██ █ ██ █ ", + " ██ █ █ █ █ ██ █ █ █ █ ", + " █ ███ ███ ███ ███ ", + " " + ) + ) -val testFrameTbrDurationHungarianScreen = makeDisplayFrame(arrayOf( - "█████ ████ ████ ███ ███ █ █ █████ █ ████ █████ █ █ █ ", - " █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ██ ██ ", - " █ █ █ █ █ █ █ █ ███ █ █ █ █ █ █ █ █ █ █ █ ", - " █ ████ ████ █ █ █ █ █ █ █████ ████ █ █████ █ █ █ ", - " █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", - " █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", - " █ ████ █ █ ███ ███ ███ █ █ █ █ █ █ █ █ █ █ ", - " ", - " ████ ████ █████ ████ ", - " ██ ██ ██ ██ ██ ██ ██ ██ ██ ", - " ███ ██ ██ ██ ██ ██ ██ ██ ", - " ████ ██ ██ ██ ██ ██ ██ ██ ", - " █████ ██ ██ ██ ██ ██ ██ ██ ", - " ██████ ██ ██ ██ ██ ███ ██ ██ ██ ", - "███████████████ ██ ██ ██ ██ ███ ███ ██ ██ ", - "████████████████ ██ ██ ██ ██ ███ ██ ██ ██ ", - "████████████████ ██ ██ ██ ██ ██ ██ ██ ", - "███████████████ ██ ██ ██ ██ ██ ██ ██ ", - " ██████ ██ ██ ██ ██ ███ ██ ██ ██ ", - " █████ ██ ██ ██ ██ ███ ██ ██ ██ ", - " ████ ██ ██ ██ ██ ███ ██ ██ ██ ", - " ███ ██ ██ ██ ██ ██ ██ ██ ██ ", - " ██ ████ ████ █████ ████ ", - " ", - " ████ █ █ ███ ██ ", - " █ ███ ██ ██ █ █ ██ █ ", - "███ █ █ █ █ █ ██ █ ", - "█ █ █ █ █ █ █ █ █ █ ", - "█ █ █ █ █ █ ██ █ █ ", - "█ █ █ █ █ █ █ █ █ ██ ", - "█ █ █ █ ███ ███ ███ ██ ", - " " -)) + val testFrameTbrDurationHungarianScreen = makeDisplayFrame( + arrayOf( + "█████ ████ ████ ███ ███ █ █ █████ █ ████ █████ █ █ █ ", + " █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ██ ██ ", + " █ █ █ █ █ █ █ █ ███ █ █ █ █ █ █ █ █ █ █ █ ", + " █ ████ ████ █ █ █ █ █ █ █████ ████ █ █████ █ █ █ ", + " █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + " █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + " █ ████ █ █ ███ ███ ███ █ █ █ █ █ █ █ █ █ █ ", + " ", + " ████ ████ █████ ████ ", + " ██ ██ ██ ██ ██ ██ ██ ██ ██ ", + " ███ ██ ██ ██ ██ ██ ██ ██ ", + " ████ ██ ██ ██ ██ ██ ██ ██ ", + " █████ ██ ██ ██ ██ ██ ██ ██ ", + " ██████ ██ ██ ██ ██ ███ ██ ██ ██ ", + "███████████████ ██ ██ ██ ██ ███ ███ ██ ██ ", + "████████████████ ██ ██ ██ ██ ███ ██ ██ ██ ", + "████████████████ ██ ██ ██ ██ ██ ██ ██ ", + "███████████████ ██ ██ ██ ██ ██ ██ ██ ", + " ██████ ██ ██ ██ ██ ███ ██ ██ ██ ", + " █████ ██ ██ ██ ██ ███ ██ ██ ██ ", + " ████ ██ ██ ██ ██ ███ ██ ██ ██ ", + " ███ ██ ██ ██ ██ ██ ██ ██ ██ ", + " ██ ████ ████ █████ ████ ", + " ", + " ████ █ █ ███ ██ ", + " █ ███ ██ ██ █ █ ██ █ ", + "███ █ █ █ █ █ ██ █ ", + "█ █ █ █ █ █ █ █ █ █ ", + "█ █ █ █ █ █ ██ █ █ ", + "█ █ █ █ █ █ █ █ █ ██ ", + "█ █ █ █ ███ ███ ███ ██ ", + " " + ) + ) -val testFrameTbrPercentageSlovakScreen = makeDisplayFrame(arrayOf( - "████ █████ ████ ███ █████ █ █ █████ ███ ███ ████ ███ ", - "█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", - "█ █ █ █ █ █ █ ██ █ █ █ █ █ █ █ █ █ █ ", - "████ ████ ████ █ ████ █ █ █ █ █ █ █ █ ████ █ █ ", - "█ █ █ █ █ █ █ ██ █ █ █ █ █ █ █ █ █ ", - "█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", - "█ █████ █ █ ███ █████ █ █ █ ███ ███ ████ ███ ", - " ", - " ██ ██ ████ ██ ██ ", - " ███████ ███ ███ ██ ██ ████ ██ ", - " ███████ ████ ████ ██ ██ ████ ██ ", - " ██ ██ ██ ██ ██ ██ ██ ██ ", - " ██ ███████ ██ ██ ██ ██ ██ ", - " ██ ███████ ██ ██ ██ ██ ██ ", - "███████ ██ ██ ██ ██ ██ ██ ██ ", - "███████ ██ ██ ██ ██ ██ ██ ██ ", - "██ ██ ██ ██ ██ ██ ██ ██ ██ ", - "██ ██ ██ ██ ██ ██ ██ ██ ██ ", - "██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ", - "██ ██ ██ ██ ██ ██ ██ ██ ██ ████ ", - "██ ██ ██ ██ ██ ██ ██ ██ ██ ████ ", - "██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ", - "██ ██ ██ ██ ██ ██ ████ ", - " ", - " █ ███ ███ █████ ███ ", - " ██ █ █ █ █ ██ █ █ █ ", - "███████ █ ██ █ ██ ██ █ █ ██ ", - "████████ █ █ █ █ █ █ █ █ █ █ ", - "███████ ██ █ ██ █ ██ █ ██ █ ", - " ██ █ █ █ █ ██ █ █ █ █ ", - " █ ███ ███ ███ ███ ", - " " -)) + val testFrameTbrPercentageSlovakScreen = makeDisplayFrame( + arrayOf( + "████ █████ ████ ███ █████ █ █ █████ ███ ███ ████ ███ ", + "█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + "█ █ █ █ █ █ █ ██ █ █ █ █ █ █ █ █ █ █ ", + "████ ████ ████ █ ████ █ █ █ █ █ █ █ █ ████ █ █ ", + "█ █ █ █ █ █ █ ██ █ █ █ █ █ █ █ █ █ ", + "█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + "█ █████ █ █ ███ █████ █ █ █ ███ ███ ████ ███ ", + " ", + " ██ ██ ████ ██ ██ ", + " ███████ ███ ███ ██ ██ ████ ██ ", + " ███████ ████ ████ ██ ██ ████ ██ ", + " ██ ██ ██ ██ ██ ██ ██ ██ ", + " ██ ███████ ██ ██ ██ ██ ██ ", + " ██ ███████ ██ ██ ██ ██ ██ ", + "███████ ██ ██ ██ ██ ██ ██ ██ ", + "███████ ██ ██ ██ ██ ██ ██ ██ ", + "██ ██ ██ ██ ██ ██ ██ ██ ██ ", + "██ ██ ██ ██ ██ ██ ██ ██ ██ ", + "██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ", + "██ ██ ██ ██ ██ ██ ██ ██ ██ ████ ", + "██ ██ ██ ██ ██ ██ ██ ██ ██ ████ ", + "██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ", + "██ ██ ██ ██ ██ ██ ████ ", + " ", + " █ ███ ███ █████ ███ ", + " ██ █ █ █ █ ██ █ █ █ ", + "███████ █ ██ █ ██ ██ █ █ ██ ", + "████████ █ █ █ █ █ █ █ █ █ █ ", + "███████ ██ █ ██ █ ██ █ ██ █ ", + " ██ █ █ █ █ ██ █ █ █ █ ", + " █ ███ ███ ███ ███ ", + " " + ) + ) -val testFrameTbrDurationSlovakScreen = makeDisplayFrame(arrayOf( - "█████ ████ █ █ █ █ █ ███ █████ ███ ████ ███ ", - " █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", - " █ █ █ █ █ █ █ ██ █ █ █ █ █ █ █ █ █ ", - " █ ████ █ █ █████ █ █ █ █ ████ █ █ ████ █ █ ", - " █ █ █ █ █ █ █ █ ██ █ █ █ █ █ █ █ █ ", - " █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", - " █ █ █ █ █ █ █ █ ███ █████ ███ ████ ███ ", - " ", - " ████ ████ █████ ████ ", - " ██ ██ ██ ██ ██ ██ ██ ██ ██ ", - " ███ ██ ██ ██ ██ ██ ██ ██ ", - " ████ ██ ██ ██ ██ ██ ██ ██ ", - " █████ ██ ██ ██ ██ ██ ██ ██ ", - " ██████ ██ ██ ██ ██ ███ ██ ██ ██ ", - "███████████████ ██ ██ ██ ██ ███ ███ ██ ██ ", - "████████████████ ██ ██ ██ ██ ███ ██ ██ ██ ", - "████████████████ ██ ██ ██ ██ ██ ██ ██ ", - "███████████████ ██ ██ ██ ██ ██ ██ ██ ", - " ██████ ██ ██ ██ ██ ███ ██ ██ ██ ", - " █████ ██ ██ ██ ██ ███ ██ ██ ██ ", - " ████ ██ ██ ██ ██ ███ ██ ██ ██ ", - " ███ ██ ██ ██ ██ ██ ██ ██ ██ ", - " ██ ████ ████ █████ ████ ", - " ", - " ████ █ █ ███ ██ ", - " █ ███ ██ ██ █ █ ██ █ ", - "███ █ █ █ █ █ ██ █ ", - "█ █ █ █ █ █ █ █ █ █ ", - "█ █ █ █ █ █ ██ █ █ ", - "█ █ █ █ █ █ █ █ █ ██ ", - "█ █ █ █ ███ ███ ███ ██ ", - " " -)) + val testFrameTbrDurationSlovakScreen = makeDisplayFrame( + arrayOf( + "█████ ████ █ █ █ █ █ ███ █████ ███ ████ ███ ", + " █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + " █ █ █ █ █ █ █ ██ █ █ █ █ █ █ █ █ █ ", + " █ ████ █ █ █████ █ █ █ █ ████ █ █ ████ █ █ ", + " █ █ █ █ █ █ █ █ ██ █ █ █ █ █ █ █ █ ", + " █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + " █ █ █ █ █ █ █ █ ███ █████ ███ ████ ███ ", + " ", + " ████ ████ █████ ████ ", + " ██ ██ ██ ██ ██ ██ ██ ██ ██ ", + " ███ ██ ██ ██ ██ ██ ██ ██ ", + " ████ ██ ██ ██ ██ ██ ██ ██ ", + " █████ ██ ██ ██ ██ ██ ██ ██ ", + " ██████ ██ ██ ██ ██ ███ ██ ██ ██ ", + "███████████████ ██ ██ ██ ██ ███ ███ ██ ██ ", + "████████████████ ██ ██ ██ ██ ███ ██ ██ ██ ", + "████████████████ ██ ██ ██ ██ ██ ██ ██ ", + "███████████████ ██ ██ ██ ██ ██ ██ ██ ", + " ██████ ██ ██ ██ ██ ███ ██ ██ ██ ", + " █████ ██ ██ ██ ██ ███ ██ ██ ██ ", + " ████ ██ ██ ██ ██ ███ ██ ██ ██ ", + " ███ ██ ██ ██ ██ ██ ██ ██ ██ ", + " ██ ████ ████ █████ ████ ", + " ", + " ████ █ █ ███ ██ ", + " █ ███ ██ ██ █ █ ██ █ ", + "███ █ █ █ █ █ ██ █ ", + "█ █ █ █ █ █ █ █ █ █ ", + "█ █ █ █ █ █ ██ █ █ ", + "█ █ █ █ █ █ █ █ █ ██ ", + "█ █ █ █ ███ ███ ███ ██ ", + " " + ) + ) -val testFrameTbrPercentageRomanianScreen = makeDisplayFrame(arrayOf( - "████ ████ ███ ███ █████ █ █ █████ ████ ████ █████ ", - "█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", - "█ █ █ █ █ █ █ █ ██ █ █ █ █ █ █ █ ", - "████ ████ █ █ █ ████ █ █ █ █ ████ ████ █ ", - "█ █ █ █ █ █ █ █ ██ █ █ █ █ █ █ ", - "█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", - "█ █ █ ███ ███ █████ █ █ █ █ █ ████ █ ", - " ", - " ██ ██ ████ ██ ██ ", - " ███████ ███ ███ ██ ██ ████ ██ ", - " ███████ ████ ████ ██ ██ ████ ██ ", - " ██ ██ ██ ██ ██ ██ ██ ██ ", - " ██ ███████ ██ ██ ██ ██ ██ ", - " ██ ███████ ██ ██ ██ ██ ██ ", - "███████ ██ ██ ██ ██ ██ ██ ██ ", - "███████ ██ ██ ██ ██ ██ ██ ██ ", - "██ ██ ██ ██ ██ ██ ██ ██ ██ ", - "██ ██ ██ ██ ██ ██ ██ ██ ██ ", - "██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ", - "██ ██ ██ ██ ██ ██ ██ ██ ██ ████ ", - "██ ██ ██ ██ ██ ██ ██ ██ ██ ████ ", - "██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ", - "██ ██ ██ ██ ██ ██ ████ ", - " ", - " █ ███ ███ █████ ███ ", - " ██ █ █ █ █ ██ █ █ █ ", - "███████ █ ██ █ ██ ██ █ █ ██ ", - "████████ █ █ █ █ █ █ █ █ █ █ ", - "███████ ██ █ ██ █ ██ █ ██ █ ", - " ██ █ █ █ █ ██ █ █ █ █ ", - " █ ███ ███ ███ ███ ", - " " -)) + val testFrameTbrPercentageRomanianScreen = makeDisplayFrame( + arrayOf( + "████ ████ ███ ███ █████ █ █ █████ ████ ████ █████ ", + "█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + "█ █ █ █ █ █ █ █ ██ █ █ █ █ █ █ █ ", + "████ ████ █ █ █ ████ █ █ █ █ ████ ████ █ ", + "█ █ █ █ █ █ █ █ ██ █ █ █ █ █ █ ", + "█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + "█ █ █ ███ ███ █████ █ █ █ █ █ ████ █ ", + " ", + " ██ ██ ████ ██ ██ ", + " ███████ ███ ███ ██ ██ ████ ██ ", + " ███████ ████ ████ ██ ██ ████ ██ ", + " ██ ██ ██ ██ ██ ██ ██ ██ ", + " ██ ███████ ██ ██ ██ ██ ██ ", + " ██ ███████ ██ ██ ██ ██ ██ ", + "███████ ██ ██ ██ ██ ██ ██ ██ ", + "███████ ██ ██ ██ ██ ██ ██ ██ ", + "██ ██ ██ ██ ██ ██ ██ ██ ██ ", + "██ ██ ██ ██ ██ ██ ██ ██ ██ ", + "██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ", + "██ ██ ██ ██ ██ ██ ██ ██ ██ ████ ", + "██ ██ ██ ██ ██ ██ ██ ██ ██ ████ ", + "██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ", + "██ ██ ██ ██ ██ ██ ████ ", + " ", + " █ ███ ███ █████ ███ ", + " ██ █ █ █ █ ██ █ █ █ ", + "███████ █ ██ █ ██ ██ █ █ ██ ", + "████████ █ █ █ █ █ █ █ █ █ █ ", + "███████ ██ █ ██ █ ██ █ ██ █ ", + " ██ █ █ █ █ ██ █ █ █ █ ", + " █ ███ ███ ███ ███ ", + " " + ) + ) -val testFrameTbrDurationRomanianScreen = makeDisplayFrame(arrayOf( - "███ █ █ ████ █ █████ █ ████ ████ █████ ", - "█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", - "█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", - "█ █ █ █ ████ █████ █ █████ ████ ████ █ ", - "█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", - "█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", - "███ ███ █ █ █ █ █ █ █ █ █ ████ █ ", - " ", - " ████ ████ █████ ████ ", - " ██ ██ ██ ██ ██ ██ ██ ██ ██ ", - " ███ ██ ██ ██ ██ ██ ██ ██ ", - " ████ ██ ██ ██ ██ ██ ██ ██ ", - " █████ ██ ██ ██ ██ ██ ██ ██ ", - " ██████ ██ ██ ██ ██ ███ ██ ██ ██ ", - "███████████████ ██ ██ ██ ██ ███ ███ ██ ██ ", - "████████████████ ██ ██ ██ ██ ███ ██ ██ ██ ", - "████████████████ ██ ██ ██ ██ ██ ██ ██ ", - "███████████████ ██ ██ ██ ██ ██ ██ ██ ", - " ██████ ██ ██ ██ ██ ███ ██ ██ ██ ", - " █████ ██ ██ ██ ██ ███ ██ ██ ██ ", - " ████ ██ ██ ██ ██ ███ ██ ██ ██ ", - " ███ ██ ██ ██ ██ ██ ██ ██ ██ ", - " ██ ████ ████ █████ ████ ", - " ", - " ████ █ █ ███ ██ ", - " █ ███ ██ ██ █ █ ██ █ ", - "███ █ █ █ █ █ ██ █ ", - "█ █ █ █ █ █ █ █ █ █ ", - "█ █ █ █ █ █ ██ █ █ ", - "█ █ █ █ █ █ █ █ █ ██ ", - "█ █ █ █ ███ ███ ███ ██ ", - " " -)) + val testFrameTbrDurationRomanianScreen = makeDisplayFrame( + arrayOf( + "███ █ █ ████ █ █████ █ ████ ████ █████ ", + "█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + "█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + "█ █ █ █ ████ █████ █ █████ ████ ████ █ ", + "█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + "█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + "███ ███ █ █ █ █ █ █ █ █ █ ████ █ ", + " ", + " ████ ████ █████ ████ ", + " ██ ██ ██ ██ ██ ██ ██ ██ ██ ", + " ███ ██ ██ ██ ██ ██ ██ ██ ", + " ████ ██ ██ ██ ██ ██ ██ ██ ", + " █████ ██ ██ ██ ██ ██ ██ ██ ", + " ██████ ██ ██ ██ ██ ███ ██ ██ ██ ", + "███████████████ ██ ██ ██ ██ ███ ███ ██ ██ ", + "████████████████ ██ ██ ██ ██ ███ ██ ██ ██ ", + "████████████████ ██ ██ ██ ██ ██ ██ ██ ", + "███████████████ ██ ██ ██ ██ ██ ██ ██ ", + " ██████ ██ ██ ██ ██ ███ ██ ██ ██ ", + " █████ ██ ██ ██ ██ ███ ██ ██ ██ ", + " ████ ██ ██ ██ ██ ███ ██ ██ ██ ", + " ███ ██ ██ ██ ██ ██ ██ ██ ██ ", + " ██ ████ ████ █████ ████ ", + " ", + " ████ █ █ ███ ██ ", + " █ ███ ██ ██ █ █ ██ █ ", + "███ █ █ █ █ █ ██ █ ", + "█ █ █ █ █ █ █ █ █ █ ", + "█ █ █ █ █ █ ██ █ █ ", + "█ █ █ █ █ █ █ █ █ ██ ", + "█ █ █ █ ███ ███ ███ ██ ", + " " + ) + ) -val testFrameTbrPercentageCroatianScreen = makeDisplayFrame(arrayOf( - "████ ███ ████ █████ ███ █████ █ █ █ ████ ████ ███ ", - "█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", - "█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ███ ", - "████ █ █ ███ █ █ █ █ █████ ██ ████ ████ █ █ █████ █ ", - "█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ████ ", - "█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", - "█ ███ ████ █ ███ █ █ █ █ █ █ ████ ███ ████ ", - " ", - " ██ ██ ████ ██ ██ ", - " ███████ ███ ███ ██ ██ ████ ██ ", - " ███████ ████ ████ ██ ██ ████ ██ ", - " ██ ██ ██ ██ ██ ██ ██ ██ ", - " ██ ███████ ██ ██ ██ ██ ██ ", - " ██ ███████ ██ ██ ██ ██ ██ ", - "███████ ██ ██ ██ ██ ██ ██ ██ ", - "███████ ██ ██ ██ ██ ██ ██ ██ ", - "██ ██ ██ ██ ██ ██ ██ ██ ██ ", - "██ ██ ██ ██ ██ ██ ██ ██ ██ ", - "██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ", - "██ ██ ██ ██ ██ ██ ██ ██ ██ ████ ", - "██ ██ ██ ██ ██ ██ ██ ██ ██ ████ ", - "██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ", - "██ ██ ██ ██ ██ ██ ████ ", - " ", - " █ ███ ███ █████ ███ ", - " ██ █ █ █ █ ██ █ █ █ ", - "███████ █ ██ █ ██ ██ █ █ ██ ", - "████████ █ █ █ █ █ █ █ █ █ █ ", - "███████ ██ █ ██ █ ██ █ ██ █ ", - " ██ █ █ █ █ ██ █ █ █ █ ", - " █ ███ ███ ███ ███ ", - " " -)) + val testFrameTbrPercentageCroatianScreen = makeDisplayFrame( + arrayOf( + "████ ███ ████ █████ ███ █████ █ █ █ ████ ████ ███ ", + "█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + "█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ███ ", + "████ █ █ ███ █ █ █ █ █████ ██ ████ ████ █ █ █████ █ ", + "█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ████ ", + "█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + "█ ███ ████ █ ███ █ █ █ █ █ █ ████ ███ ████ ", + " ", + " ██ ██ ████ ██ ██ ", + " ███████ ███ ███ ██ ██ ████ ██ ", + " ███████ ████ ████ ██ ██ ████ ██ ", + " ██ ██ ██ ██ ██ ██ ██ ██ ", + " ██ ███████ ██ ██ ██ ██ ██ ", + " ██ ███████ ██ ██ ██ ██ ██ ", + "███████ ██ ██ ██ ██ ██ ██ ██ ", + "███████ ██ ██ ██ ██ ██ ██ ██ ", + "██ ██ ██ ██ ██ ██ ██ ██ ██ ", + "██ ██ ██ ██ ██ ██ ██ ██ ██ ", + "██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ", + "██ ██ ██ ██ ██ ██ ██ ██ ██ ████ ", + "██ ██ ██ ██ ██ ██ ██ ██ ██ ████ ", + "██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ", + "██ ██ ██ ██ ██ ██ ████ ", + " ", + " █ ███ ███ █████ ███ ", + " ██ █ █ █ █ ██ █ █ █ ", + "███████ █ ██ █ ██ ██ █ █ ██ ", + "████████ █ █ █ █ █ █ █ █ █ █ ", + "███████ ██ █ ██ █ ██ █ ██ █ ", + " ██ █ █ █ █ ██ █ █ █ █ ", + " █ ███ ███ ███ ███ ", + " " + ) + ) -val testFrameTbrDurationCroatianScreen = makeDisplayFrame(arrayOf( - "█████ ████ █ ███ █ █ █ ███ █████ ████ ████ ███ ", - " █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", - " █ █ █ █ █ █ █ █ ██ █ █ █ █ █ █ █ █ █ ███ ", - " █ ████ █████ █ █████ █ █ █ █ ████ ████ ████ █ █ █████ █ ", - " █ █ █ █ █ █ █ █ █ ██ █ █ █ █ █ █ █ ████ ", - " █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", - " █ █ █ █ █ ██ █ █ █ █ ██ █████ █ ████ ███ ████ ", - " ", - " ████ ████ █████ ████ ", - " ██ ██ ██ ██ ██ ██ ██ ██ ██ ", - " ███ ██ ██ ██ ██ ██ ██ ██ ", - " ████ ██ ██ ██ ██ ██ ██ ██ ", - " █████ ██ ██ ██ ██ ██ ██ ██ ", - " ██████ ██ ██ ██ ██ ███ ██ ██ ██ ", - "███████████████ ██ ██ ██ ██ ███ ███ ██ ██ ", - "████████████████ ██ ██ ██ ██ ███ ██ ██ ██ ", - "████████████████ ██ ██ ██ ██ ██ ██ ██ ", - "███████████████ ██ ██ ██ ██ ██ ██ ██ ", - " ██████ ██ ██ ██ ██ ███ ██ ██ ██ ", - " █████ ██ ██ ██ ██ ███ ██ ██ ██ ", - " ████ ██ ██ ██ ██ ███ ██ ██ ██ ", - " ███ ██ ██ ██ ██ ██ ██ ██ ██ ", - " ██ ████ ████ █████ ████ ", - " ", - " ████ █ █ ███ ██ ", - " █ ███ ██ ██ █ █ ██ █ ", - "███ █ █ █ █ █ ██ █ ", - "█ █ █ █ █ █ █ █ █ █ ", - "█ █ █ █ █ █ ██ █ █ ", - "█ █ █ █ █ █ █ █ █ ██ ", - "█ █ █ █ ███ ███ ███ ██ ", - " " -)) + val testFrameTbrDurationCroatianScreen = makeDisplayFrame( + arrayOf( + "█████ ████ █ ███ █ █ █ ███ █████ ████ ████ ███ ", + " █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + " █ █ █ █ █ █ █ █ ██ █ █ █ █ █ █ █ █ █ ███ ", + " █ ████ █████ █ █████ █ █ █ █ ████ ████ ████ █ █ █████ █ ", + " █ █ █ █ █ █ █ █ █ ██ █ █ █ █ █ █ █ ████ ", + " █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + " █ █ █ █ █ ██ █ █ █ █ ██ █████ █ ████ ███ ████ ", + " ", + " ████ ████ █████ ████ ", + " ██ ██ ██ ██ ██ ██ ██ ██ ██ ", + " ███ ██ ██ ██ ██ ██ ██ ██ ", + " ████ ██ ██ ██ ██ ██ ██ ██ ", + " █████ ██ ██ ██ ██ ██ ██ ██ ", + " ██████ ██ ██ ██ ██ ███ ██ ██ ██ ", + "███████████████ ██ ██ ██ ██ ███ ███ ██ ██ ", + "████████████████ ██ ██ ██ ██ ███ ██ ██ ██ ", + "████████████████ ██ ██ ██ ██ ██ ██ ██ ", + "███████████████ ██ ██ ██ ██ ██ ██ ██ ", + " ██████ ██ ██ ██ ██ ███ ██ ██ ██ ", + " █████ ██ ██ ██ ██ ███ ██ ██ ██ ", + " ████ ██ ██ ██ ██ ███ ██ ██ ██ ", + " ███ ██ ██ ██ ██ ██ ██ ██ ██ ", + " ██ ████ ████ █████ ████ ", + " ", + " ████ █ █ ███ ██ ", + " █ ███ ██ ██ █ █ ██ █ ", + "███ █ █ █ █ █ ██ █ ", + "█ █ █ █ █ █ █ █ █ █ ", + "█ █ █ █ █ █ ██ █ █ ", + "█ █ █ █ █ █ █ █ █ ██ ", + "█ █ █ █ ███ ███ ███ ██ ", + " " + ) + ) -val testFrameTbrPercentageDutchScreen = makeDisplayFrame(arrayOf( - "█████ ████ ███ ████ █████ ████ ███ █████ █ █ █████ █ ███ █████ ", - " █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", - " █ █ █ █ █ █ █ █ █ █ █ █ ██ █ █ █ █ █ █ ", - " █ ████ █ █ █████ ████ ████ ████ █ ████ █ █ █ █ █████ █ ███ ████ ", - " █ █ █ █ █ █ █ █ █ █ █ █ ██ █ █ █ █ █ █ ", - " █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", - " █ ████ ███ █ █████ █ █ ███ █████ █ █ █ █ █ ████ █████ ", - " ", - " ██ ██ ████ ██ ██ ", - " ███████ ███ ███ ██ ██ ████ ██ ", - " ███████ ████ ████ ██ ██ ████ ██ ", - " ██ ██ ██ ██ ██ ██ ██ ██ ", - " ██ ███████ ██ ██ ██ ██ ██ ", - " ██ ███████ ██ ██ ██ ██ ██ ", - "███████ ██ ██ ██ ██ ██ ██ ██ ", - "███████ ██ ██ ██ ██ ██ ██ ██ ", - "██ ██ ██ ██ ██ ██ ██ ██ ██ ", - "██ ██ ██ ██ ██ ██ ██ ██ ██ ", - "██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ", - "██ ██ ██ ██ ██ ██ ██ ██ ██ ████ ", - "██ ██ ██ ██ ██ ██ ██ ██ ██ ████ ", - "██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ", - "██ ██ ██ ██ ██ ██ ████ ", - " ", - " █ ███ ███ █████ ███ ", - " ██ █ █ █ █ ██ █ █ █ ", - "███████ █ ██ █ ██ ██ █ █ ██ ", - "████████ █ █ █ █ █ █ █ █ █ █ ", - "███████ ██ █ ██ █ ██ █ ██ █ ", - " ██ █ █ █ █ ██ █ █ █ █ ", - " █ ███ ███ ███ ███ ", - " " -)) + val testFrameTbrPercentageDutchScreen = makeDisplayFrame( + arrayOf( + "█████ ████ ███ ████ █████ ████ ███ █████ █ █ █████ █ ███ █████ ", + " █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + " █ █ █ █ █ █ █ █ █ █ █ █ ██ █ █ █ █ █ █ ", + " █ ████ █ █ █████ ████ ████ ████ █ ████ █ █ █ █ █████ █ ███ ████ ", + " █ █ █ █ █ █ █ █ █ █ █ █ ██ █ █ █ █ █ █ ", + " █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + " █ ████ ███ █ █████ █ █ ███ █████ █ █ █ █ █ ████ █████ ", + " ", + " ██ ██ ████ ██ ██ ", + " ███████ ███ ███ ██ ██ ████ ██ ", + " ███████ ████ ████ ██ ██ ████ ██ ", + " ██ ██ ██ ██ ██ ██ ██ ██ ", + " ██ ███████ ██ ██ ██ ██ ██ ", + " ██ ███████ ██ ██ ██ ██ ██ ", + "███████ ██ ██ ██ ██ ██ ██ ██ ", + "███████ ██ ██ ██ ██ ██ ██ ██ ", + "██ ██ ██ ██ ██ ██ ██ ██ ██ ", + "██ ██ ██ ██ ██ ██ ██ ██ ██ ", + "██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ", + "██ ██ ██ ██ ██ ██ ██ ██ ██ ████ ", + "██ ██ ██ ██ ██ ██ ██ ██ ██ ████ ", + "██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ", + "██ ██ ██ ██ ██ ██ ████ ", + " ", + " █ ███ ███ █████ ███ ", + " ██ █ █ █ █ ██ █ █ █ ", + "███████ █ ██ █ ██ ██ █ █ ██ ", + "████████ █ █ █ █ █ █ █ █ █ █ ", + "███████ ██ █ ██ █ ██ █ ██ █ ", + " ██ █ █ █ █ ██ █ █ █ █ ", + " █ ███ ███ ███ ███ ", + " " + ) + ) -val testFrameTbrDurationDutchScreen = makeDisplayFrame(arrayOf( - "█████ ████ ███ ███ █ █ █ █ ████ ", - " █ █ █ █ █ █ █ █ █ █ █ █ █ ", - " █ █ █ █ █ █ █ █ █ █ █ █ █ ", - " █ ████ █ █ █████ █ █ █ █ █ █ ████ ", - " █ █ █ █ █ █ █ █ █ █ █ █ █ ", - " █ █ █ █ █ █ █ █ █ █ █ █ █ ", - " █ ████ ███ ███ ███ ███ █ █ ", - " ", - " ████ ████ █████ ████ ", - " ██ ██ ██ ██ ██ ██ ██ ██ ██ ", - " ███ ██ ██ ██ ██ ██ ██ ██ ", - " ████ ██ ██ ██ ██ ██ ██ ██ ", - " █████ ██ ██ ██ ██ ██ ██ ██ ", - " ██████ ██ ██ ██ ██ ███ ██ ██ ██ ", - "███████████████ ██ ██ ██ ██ ███ ███ ██ ██ ", - "████████████████ ██ ██ ██ ██ ███ ██ ██ ██ ", - "████████████████ ██ ██ ██ ██ ██ ██ ██ ", - "███████████████ ██ ██ ██ ██ ██ ██ ██ ", - " ██████ ██ ██ ██ ██ ███ ██ ██ ██ ", - " █████ ██ ██ ██ ██ ███ ██ ██ ██ ", - " ████ ██ ██ ██ ██ ███ ██ ██ ██ ", - " ███ ██ ██ ██ ██ ██ ██ ██ ██ ", - " ██ ████ ████ █████ ████ ", - " ", - " ████ █ █ ███ ██ ", - " █ ███ ██ ██ █ █ ██ █ ", - "███ █ █ █ █ █ ██ █ ", - "█ █ █ █ █ █ █ █ █ █ ", - "█ █ █ █ █ █ ██ █ █ ", - "█ █ █ █ █ █ █ █ █ ██ ", - "█ █ █ █ ███ ███ ███ ██ ", - " " -)) + val testFrameTbrDurationDutchScreen = makeDisplayFrame( + arrayOf( + "█████ ████ ███ ███ █ █ █ █ ████ ", + " █ █ █ █ █ █ █ █ █ █ █ █ █ ", + " █ █ █ █ █ █ █ █ █ █ █ █ █ ", + " █ ████ █ █ █████ █ █ █ █ █ █ ████ ", + " █ █ █ █ █ █ █ █ █ █ █ █ █ ", + " █ █ █ █ █ █ █ █ █ █ █ █ █ ", + " █ ████ ███ ███ ███ ███ █ █ ", + " ", + " ████ ████ █████ ████ ", + " ██ ██ ██ ██ ██ ██ ██ ██ ██ ", + " ███ ██ ██ ██ ██ ██ ██ ██ ", + " ████ ██ ██ ██ ██ ██ ██ ██ ", + " █████ ██ ██ ██ ██ ██ ██ ██ ", + " ██████ ██ ██ ██ ██ ███ ██ ██ ██ ", + "███████████████ ██ ██ ██ ██ ███ ███ ██ ██ ", + "████████████████ ██ ██ ██ ██ ███ ██ ██ ██ ", + "████████████████ ██ ██ ██ ██ ██ ██ ██ ", + "███████████████ ██ ██ ██ ██ ██ ██ ██ ", + " ██████ ██ ██ ██ ██ ███ ██ ██ ██ ", + " █████ ██ ██ ██ ██ ███ ██ ██ ██ ", + " ████ ██ ██ ██ ██ ███ ██ ██ ██ ", + " ███ ██ ██ ██ ██ ██ ██ ██ ██ ", + " ██ ████ ████ █████ ████ ", + " ", + " ████ █ █ ███ ██ ", + " █ ███ ██ ██ █ █ ██ █ ", + "███ █ █ █ █ █ ██ █ ", + "█ █ █ █ █ █ █ █ █ █ ", + "█ █ █ █ █ █ ██ █ █ ", + "█ █ █ █ █ █ █ █ █ ██ ", + "█ █ █ █ ███ ███ ███ ██ ", + " " + ) + ) -val testFrameTbrPercentageGreekScreen = makeDisplayFrame(arrayOf( - "█████ ███ █████ ███ █████ █████ ███ █████ ████ ████ ", - "█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", - "█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", - "█ █ █ █ █ █ █ █ █ █ █ █ █ ████ ████ ", - "█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", - "█ █ █ █ █ █ █ █ █ █ █ █ █ ██ █ █ ██ █ ██ ", - "█ █ ███ █████ ███ █████ █ ███ █ █ ██ ████ ██ █ ██ ", - " ", - " ██ ██ ████ ██ ██ ", - " ███████ ███ ███ ██ ██ ████ ██ ", - " ███████ ████ ████ ██ ██ ████ ██ ", - " ██ ██ ██ ██ ██ ██ ██ ██ ", - " ██ ███████ ██ ██ ██ ██ ██ ", - " ██ ███████ ██ ██ ██ ██ ██ ", - "███████ ██ ██ ██ ██ ██ ██ ██ ", - "███████ ██ ██ ██ ██ ██ ██ ██ ", - "██ ██ ██ ██ ██ ██ ██ ██ ██ ", - "██ ██ ██ ██ ██ ██ ██ ██ ██ ", - "██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ", - "██ ██ ██ ██ ██ ██ ██ ██ ██ ████ ", - "██ ██ ██ ██ ██ ██ ██ ██ ██ ████ ", - "██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ", - "██ ██ ██ ██ ██ ██ ████ ", - " ", - " █ ███ ███ █████ ███ ", - " ██ █ █ █ █ ██ █ █ █ ", - "███████ █ ██ █ ██ ██ █ █ ██ ", - "████████ █ █ █ █ █ █ █ █ █ █ ", - "███████ ██ █ ██ █ ██ █ ██ █ ", - " ██ █ █ █ █ ██ █ █ █ █ ", - " █ ███ ███ ███ ███ ", - " " -)) + val testFrameTbrPercentageGreekScreen = makeDisplayFrame( + arrayOf( + "█████ ███ █████ ███ █████ █████ ███ █████ ████ ████ ", + "█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + "█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + "█ █ █ █ █ █ █ █ █ █ █ █ █ ████ ████ ", + "█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + "█ █ █ █ █ █ █ █ █ █ █ █ █ ██ █ █ ██ █ ██ ", + "█ █ ███ █████ ███ █████ █ ███ █ █ ██ ████ ██ █ ██ ", + " ", + " ██ ██ ████ ██ ██ ", + " ███████ ███ ███ ██ ██ ████ ██ ", + " ███████ ████ ████ ██ ██ ████ ██ ", + " ██ ██ ██ ██ ██ ██ ██ ██ ", + " ██ ███████ ██ ██ ██ ██ ██ ", + " ██ ███████ ██ ██ ██ ██ ██ ", + "███████ ██ ██ ██ ██ ██ ██ ██ ", + "███████ ██ ██ ██ ██ ██ ██ ██ ", + "██ ██ ██ ██ ██ ██ ██ ██ ██ ", + "██ ██ ██ ██ ██ ██ ██ ██ ██ ", + "██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ", + "██ ██ ██ ██ ██ ██ ██ ██ ██ ████ ", + "██ ██ ██ ██ ██ ██ ██ ██ ██ ████ ", + "██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ", + "██ ██ ██ ██ ██ ██ ████ ", + " ", + " █ ███ ███ █████ ███ ", + " ██ █ █ █ █ ██ █ █ █ ", + "███████ █ ██ █ ██ ██ █ █ ██ ", + "████████ █ █ █ █ █ █ █ █ █ █ ", + "███████ ██ █ ██ █ ██ █ ██ █ ", + " ██ █ █ █ █ ██ █ █ █ █ ", + " █ ███ ███ ███ ███ ", + " " + ) + ) -val testFrameTbrDurationGreekScreen = makeDisplayFrame(arrayOf( - " █ ███ █ ████ █ █ █████ ███ █ █████ ████ ████ ", - " █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", - " █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", - " █ █ █ █ █ ████ ██ ████ █ █ █ █ █ ████ ████ ", - "█ █ █ █████ █ █ █ █ █ █████ █ █ █ █ █ ", - "█ █ █ █ █ █ █ █ █ █ █ █ █ █ ██ █ █ ██ █ ██ ", - "█████ ███ █ █ █ █ █ █████ ███ █ █ █ █ ██ ████ ██ █ ██ ", - " ", - " ████ ████ █████ ████ ", - " ██ ██ ██ ██ ██ ██ ██ ██ ██ ", - " ███ ██ ██ ██ ██ ██ ██ ██ ", - " ████ ██ ██ ██ ██ ██ ██ ██ ", - " █████ ██ ██ ██ ██ ██ ██ ██ ", - " ██████ ██ ██ ██ ██ ███ ██ ██ ██ ", - "███████████████ ██ ██ ██ ██ ███ ███ ██ ██ ", - "████████████████ ██ ██ ██ ██ ███ ██ ██ ██ ", - "████████████████ ██ ██ ██ ██ ██ ██ ██ ", - "███████████████ ██ ██ ██ ██ ██ ██ ██ ", - " ██████ ██ ██ ██ ██ ███ ██ ██ ██ ", - " █████ ██ ██ ██ ██ ███ ██ ██ ██ ", - " ████ ██ ██ ██ ██ ███ ██ ██ ██ ", - " ███ ██ ██ ██ ██ ██ ██ ██ ██ ", - " ██ ████ ████ █████ ████ ", - " ", - " ████ █ █ ███ ██ ", - " █ ███ ██ ██ █ █ ██ █ ", - "███ █ █ █ █ █ ██ █ ", - "█ █ █ █ █ █ █ █ █ █ ", - "█ █ █ █ █ █ ██ █ █ ", - "█ █ █ █ █ █ █ █ █ ██ ", - "█ █ █ █ ███ ███ ███ ██ ", - " " -)) + val testFrameTbrDurationGreekScreen = makeDisplayFrame( + arrayOf( + " █ ███ █ ████ █ █ █████ ███ █ █████ ████ ████ ", + " █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + " █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + " █ █ █ █ █ ████ ██ ████ █ █ █ █ █ ████ ████ ", + "█ █ █ █████ █ █ █ █ █ █████ █ █ █ █ █ ", + "█ █ █ █ █ █ █ █ █ █ █ █ █ █ ██ █ █ ██ █ ██ ", + "█████ ███ █ █ █ █ █ █████ ███ █ █ █ █ ██ ████ ██ █ ██ ", + " ", + " ████ ████ █████ ████ ", + " ██ ██ ██ ██ ██ ██ ██ ██ ██ ", + " ███ ██ ██ ██ ██ ██ ██ ██ ", + " ████ ██ ██ ██ ██ ██ ██ ██ ", + " █████ ██ ██ ██ ██ ██ ██ ██ ", + " ██████ ██ ██ ██ ██ ███ ██ ██ ██ ", + "███████████████ ██ ██ ██ ██ ███ ███ ██ ██ ", + "████████████████ ██ ██ ██ ██ ███ ██ ██ ██ ", + "████████████████ ██ ██ ██ ██ ██ ██ ██ ", + "███████████████ ██ ██ ██ ██ ██ ██ ██ ", + " ██████ ██ ██ ██ ██ ███ ██ ██ ██ ", + " █████ ██ ██ ██ ██ ███ ██ ██ ██ ", + " ████ ██ ██ ██ ██ ███ ██ ██ ██ ", + " ███ ██ ██ ██ ██ ██ ██ ██ ██ ", + " ██ ████ ████ █████ ████ ", + " ", + " ████ █ █ ███ ██ ", + " █ ███ ██ ██ █ █ ██ █ ", + "███ █ █ █ █ █ ██ █ ", + "█ █ █ █ █ █ █ █ █ █ ", + "█ █ █ █ █ █ ██ █ █ ", + "█ █ █ █ █ █ █ █ █ ██ ", + "█ █ █ █ ███ ███ ███ ██ ", + " " + ) + ) -val testFrameTbrPercentageFinnishScreen = makeDisplayFrame(arrayOf( - "█████ ████ █ ████ ████ ███ ████ █████ █ █ █████ █████ ███ ", - " █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", - " █ █ █ █ █ █ █ █ █ █ █ █ █ ██ █ █ █ █ ", - " █ ████ █████ █████ ████ ████ █ █ ███ ████ █ █ █ █ █ █ ", - " █ █ █ █ █ █ █ █ █ █ █ █ █ ██ █ █ █ ", - " █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", - " █ ████ █ █ █ █ █ ███ ████ █████ █ █ █ █ ███ ", - " ", - " ██ ██ ████ ██ ██ ", - " ███████ ███ ███ ██ ██ ████ ██ ", - " ███████ ████ ████ ██ ██ ████ ██ ", - " ██ ██ ██ ██ ██ ██ ██ ██ ", - " ██ ███████ ██ ██ ██ ██ ██ ", - " ██ ███████ ██ ██ ██ ██ ██ ", - "███████ ██ ██ ██ ██ ██ ██ ██ ", - "███████ ██ ██ ██ ██ ██ ██ ██ ", - "██ ██ ██ ██ ██ ██ ██ ██ ██ ", - "██ ██ ██ ██ ██ ██ ██ ██ ██ ", - "██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ", - "██ ██ ██ ██ ██ ██ ██ ██ ██ ████ ", - "██ ██ ██ ██ ██ ██ ██ ██ ██ ████ ", - "██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ", - "██ ██ ██ ██ ██ ██ ████ ", - " ", - " █ ███ ███ █████ ███ ", - " ██ █ █ █ █ ██ █ █ █ ", - "███████ █ ██ █ ██ ██ █ █ ██ ", - "████████ █ █ █ █ █ █ █ █ █ █ ", - "███████ ██ █ ██ █ ██ █ ██ █ ", - " ██ █ █ █ █ ██ █ █ █ █ ", - " █ ███ ███ ███ ███ ", - " " -)) + val testFrameTbrPercentageFinnishScreen = makeDisplayFrame( + arrayOf( + "█████ ████ █ ████ ████ ███ ████ █████ █ █ █████ █████ ███ ", + " █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + " █ █ █ █ █ █ █ █ █ █ █ █ █ ██ █ █ █ █ ", + " █ ████ █████ █████ ████ ████ █ █ ███ ████ █ █ █ █ █ █ ", + " █ █ █ █ █ █ █ █ █ █ █ █ █ ██ █ █ █ ", + " █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + " █ ████ █ █ █ █ █ ███ ████ █████ █ █ █ █ ███ ", + " ", + " ██ ██ ████ ██ ██ ", + " ███████ ███ ███ ██ ██ ████ ██ ", + " ███████ ████ ████ ██ ██ ████ ██ ", + " ██ ██ ██ ██ ██ ██ ██ ██ ", + " ██ ███████ ██ ██ ██ ██ ██ ", + " ██ ███████ ██ ██ ██ ██ ██ ", + "███████ ██ ██ ██ ██ ██ ██ ██ ", + "███████ ██ ██ ██ ██ ██ ██ ██ ", + "██ ██ ██ ██ ██ ██ ██ ██ ██ ", + "██ ██ ██ ██ ██ ██ ██ ██ ██ ", + "██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ", + "██ ██ ██ ██ ██ ██ ██ ██ ██ ████ ", + "██ ██ ██ ██ ██ ██ ██ ██ ██ ████ ", + "██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ", + "██ ██ ██ ██ ██ ██ ████ ", + " ", + " █ ███ ███ █████ ███ ", + " ██ █ █ █ █ ██ █ █ █ ", + "███████ █ ██ █ ██ ██ █ █ ██ ", + "████████ █ █ █ █ █ █ █ █ █ █ ", + "███████ ██ █ ██ █ ██ █ ██ █ ", + " ██ █ █ █ █ ██ █ █ █ █ ", + " █ ███ ███ ███ ███ ", + " " + ) + ) -val testFrameTbrDurationFinnishScreen = makeDisplayFrame(arrayOf( - "█████ ████ █ █ █ █████ ████ █████ ███ ", - " █ █ █ █ █ █ █ █ █ █ █ █ ", - " █ █ █ █ █ █ █ █ █ █ █ █ ", - " █ ████ █████ █████ ██ ████ ███ █ █ █ ", - " █ █ █ █ █ █ █ █ █ █ █ █ ", - " █ █ █ █ █ █ █ █ █ █ █ █ ", - " █ ████ █ █ █ █ █████ ████ █ ███ ", - " ", - " ████ ████ █████ ████ ", - " ██ ██ ██ ██ ██ ██ ██ ██ ██ ", - " ███ ██ ██ ██ ██ ██ ██ ██ ", - " ████ ██ ██ ██ ██ ██ ██ ██ ", - " █████ ██ ██ ██ ██ ██ ██ ██ ", - " ██████ ██ ██ ██ ██ ███ ██ ██ ██ ", - "███████████████ ██ ██ ██ ██ ███ ███ ██ ██ ", - "████████████████ ██ ██ ██ ██ ███ ██ ██ ██ ", - "████████████████ ██ ██ ██ ██ ██ ██ ██ ", - "███████████████ ██ ██ ██ ██ ██ ██ ██ ", - " ██████ ██ ██ ██ ██ ███ ██ ██ ██ ", - " █████ ██ ██ ██ ██ ███ ██ ██ ██ ", - " ████ ██ ██ ██ ██ ███ ██ ██ ██ ", - " ███ ██ ██ ██ ██ ██ ██ ██ ██ ", - " ██ ████ ████ █████ ████ ", - " ", - " ████ █ █ ███ ██ ", - " █ ███ ██ ██ █ █ ██ █ ", - "███ █ █ █ █ █ ██ █ ", - "█ █ █ █ █ █ █ █ █ █ ", - "█ █ █ █ █ █ ██ █ █ ", - "█ █ █ █ █ █ █ █ █ ██ ", - "█ █ █ █ ███ ███ ███ ██ ", - " " -)) + val testFrameTbrDurationFinnishScreen = makeDisplayFrame( + arrayOf( + "█████ ████ █ █ █ █████ ████ █████ ███ ", + " █ █ █ █ █ █ █ █ █ █ █ █ ", + " █ █ █ █ █ █ █ █ █ █ █ █ ", + " █ ████ █████ █████ ██ ████ ███ █ █ █ ", + " █ █ █ █ █ █ █ █ █ █ █ █ ", + " █ █ █ █ █ █ █ █ █ █ █ █ ", + " █ ████ █ █ █ █ █████ ████ █ ███ ", + " ", + " ████ ████ █████ ████ ", + " ██ ██ ██ ██ ██ ██ ██ ██ ██ ", + " ███ ██ ██ ██ ██ ██ ██ ██ ", + " ████ ██ ██ ██ ██ ██ ██ ██ ", + " █████ ██ ██ ██ ██ ██ ██ ██ ", + " ██████ ██ ██ ██ ██ ███ ██ ██ ██ ", + "███████████████ ██ ██ ██ ██ ███ ███ ██ ██ ", + "████████████████ ██ ██ ██ ██ ███ ██ ██ ██ ", + "████████████████ ██ ██ ██ ██ ██ ██ ██ ", + "███████████████ ██ ██ ██ ██ ██ ██ ██ ", + " ██████ ██ ██ ██ ██ ███ ██ ██ ██ ", + " █████ ██ ██ ██ ██ ███ ██ ██ ██ ", + " ████ ██ ██ ██ ██ ███ ██ ██ ██ ", + " ███ ██ ██ ██ ██ ██ ██ ██ ██ ", + " ██ ████ ████ █████ ████ ", + " ", + " ████ █ █ ███ ██ ", + " █ ███ ██ ██ █ █ ██ █ ", + "███ █ █ █ █ █ ██ █ ", + "█ █ █ █ █ █ █ █ █ █ ", + "█ █ █ █ █ █ ██ █ █ ", + "█ █ █ █ █ █ █ █ █ ██ ", + "█ █ █ █ ███ ███ ███ ██ ", + " " + ) + ) -val testFrameTbrPercentageNorwegianScreen = makeDisplayFrame(arrayOf( - "█ █ ████ ███ ████ ████ ███ ████ █████ █ █ █████ ", - "██ ██ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", - "█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ██ █ █ ", - "█ █ █ ████ █ █ █████ ████ ████ █ █ ███ ████ █ █ █ █ ", - "█ █ █ █ █ █ █ █ █ █ █ █ █ █ ██ █ ", - "█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", - "█ █ ████ ███ █ █ █ ███ ████ █████ █ █ █ ", - " ", - " ██ ██ ████ ██ ██ ", - " ███████ ███ ███ ██ ██ ████ ██ ", - " ███████ ████ ████ ██ ██ ████ ██ ", - " ██ ██ ██ ██ ██ ██ ██ ██ ", - " ██ ███████ ██ ██ ██ ██ ██ ", - " ██ ███████ ██ ██ ██ ██ ██ ", - "███████ ██ ██ ██ ██ ██ ██ ██ ", - "███████ ██ ██ ██ ██ ██ ██ ██ ", - "██ ██ ██ ██ ██ ██ ██ ██ ██ ", - "██ ██ ██ ██ ██ ██ ██ ██ ██ ", - "██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ", - "██ ██ ██ ██ ██ ██ ██ ██ ██ ████ ", - "██ ██ ██ ██ ██ ██ ██ ██ ██ ████ ", - "██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ", - "██ ██ ██ ██ ██ ██ ████ ", - " ", - " █ ███ ███ █████ ███ ", - " ██ █ █ █ █ ██ █ █ █ ", - "███████ █ ██ █ ██ ██ █ █ ██ ", - "████████ █ █ █ █ █ █ █ █ █ █ ", - "███████ ██ █ ██ █ ██ █ ██ █ ", - " ██ █ █ █ █ ██ █ █ █ █ ", - " █ ███ ███ ███ ███ ", - " " -)) + val testFrameTbrPercentageNorwegianScreen = makeDisplayFrame( + arrayOf( + "█ █ ████ ███ ████ ████ ███ ████ █████ █ █ █████ ", + "██ ██ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + "█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ██ █ █ ", + "█ █ █ ████ █ █ █████ ████ ████ █ █ ███ ████ █ █ █ █ ", + "█ █ █ █ █ █ █ █ █ █ █ █ █ █ ██ █ ", + "█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + "█ █ ████ ███ █ █ █ ███ ████ █████ █ █ █ ", + " ", + " ██ ██ ████ ██ ██ ", + " ███████ ███ ███ ██ ██ ████ ██ ", + " ███████ ████ ████ ██ ██ ████ ██ ", + " ██ ██ ██ ██ ██ ██ ██ ██ ", + " ██ ███████ ██ ██ ██ ██ ██ ", + " ██ ███████ ██ ██ ██ ██ ██ ", + "███████ ██ ██ ██ ██ ██ ██ ██ ", + "███████ ██ ██ ██ ██ ██ ██ ██ ", + "██ ██ ██ ██ ██ ██ ██ ██ ██ ", + "██ ██ ██ ██ ██ ██ ██ ██ ██ ", + "██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ", + "██ ██ ██ ██ ██ ██ ██ ██ ██ ████ ", + "██ ██ ██ ██ ██ ██ ██ ██ ██ ████ ", + "██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ", + "██ ██ ██ ██ ██ ██ ████ ", + " ", + " █ ███ ███ █████ ███ ", + " ██ █ █ █ █ ██ █ █ █ ", + "███████ █ ██ █ ██ ██ █ █ ██ ", + "████████ █ █ █ █ █ █ █ █ █ █ ", + "███████ ██ █ ██ █ ██ █ ██ █ ", + " ██ █ █ █ █ ██ █ █ █ █ ", + " █ ███ ███ ███ ███ ", + " " + ) + ) -val testFrameTbrDurationNorwegianScreen = makeDisplayFrame(arrayOf( - "█ █ ████ ███ █ █ █ ████ ███ ███ █ █ █████ █████ ", - "██ ██ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", - "█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", - "█ █ █ ████ █ █ █████ █ █ █████ ████ █ █ ███ █████ ████ █ ", - "█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", - "█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", - "█ █ ████ ███ █ █ █ █ █ ███ ████ █ █ █████ █ ", - " ", - " ████ ████ █████ ████ ", - " ██ ██ ██ ██ ██ ██ ██ ██ ██ ", - " ███ ██ ██ ██ ██ ██ ██ ██ ", - " ████ ██ ██ ██ ██ ██ ██ ██ ", - " █████ ██ ██ ██ ██ ██ ██ ██ ", - " ██████ ██ ██ ██ ██ ███ ██ ██ ██ ", - "███████████████ ██ ██ ██ ██ ███ ███ ██ ██ ", - "████████████████ ██ ██ ██ ██ ███ ██ ██ ██ ", - "████████████████ ██ ██ ██ ██ ██ ██ ██ ", - "███████████████ ██ ██ ██ ██ ██ ██ ██ ", - " ██████ ██ ██ ██ ██ ███ ██ ██ ██ ", - " █████ ██ ██ ██ ██ ███ ██ ██ ██ ", - " ████ ██ ██ ██ ██ ███ ██ ██ ██ ", - " ███ ██ ██ ██ ██ ██ ██ ██ ██ ", - " ██ ████ ████ █████ ████ ", - " ", - " ████ █ █ ███ ██ ", - " █ ███ ██ ██ █ █ ██ █ ", - "███ █ █ █ █ █ ██ █ ", - "█ █ █ █ █ █ █ █ █ █ ", - "█ █ █ █ █ █ ██ █ █ ", - "█ █ █ █ █ █ █ █ █ ██ ", - "█ █ █ █ ███ ███ ███ ██ ", - " " -)) + val testFrameTbrDurationNorwegianScreen = makeDisplayFrame( + arrayOf( + "█ █ ████ ███ █ █ █ ████ ███ ███ █ █ █████ █████ ", + "██ ██ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + "█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + "█ █ █ ████ █ █ █████ █ █ █████ ████ █ █ ███ █████ ████ █ ", + "█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + "█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + "█ █ ████ ███ █ █ █ █ █ ███ ████ █ █ █████ █ ", + " ", + " ████ ████ █████ ████ ", + " ██ ██ ██ ██ ██ ██ ██ ██ ██ ", + " ███ ██ ██ ██ ██ ██ ██ ██ ", + " ████ ██ ██ ██ ██ ██ ██ ██ ", + " █████ ██ ██ ██ ██ ██ ██ ██ ", + " ██████ ██ ██ ██ ██ ███ ██ ██ ██ ", + "███████████████ ██ ██ ██ ██ ███ ███ ██ ██ ", + "████████████████ ██ ██ ██ ██ ███ ██ ██ ██ ", + "████████████████ ██ ██ ██ ██ ██ ██ ██ ", + "███████████████ ██ ██ ██ ██ ██ ██ ██ ", + " ██████ ██ ██ ██ ██ ███ ██ ██ ██ ", + " █████ ██ ██ ██ ██ ███ ██ ██ ██ ", + " ████ ██ ██ ██ ██ ███ ██ ██ ██ ", + " ███ ██ ██ ██ ██ ██ ██ ██ ██ ", + " ██ ████ ████ █████ ████ ", + " ", + " ████ █ █ ███ ██ ", + " █ ███ ██ ██ █ █ ██ █ ", + "███ █ █ █ █ █ ██ █ ", + "█ █ █ █ █ █ █ █ █ █ ", + "█ █ █ █ █ █ ██ █ █ ", + "█ █ █ █ █ █ █ █ █ ██ ", + "█ █ █ █ ███ ███ ███ ██ ", + " " + ) + ) -val testFrameTbrPercentagePortugueseScreen = makeDisplayFrame(arrayOf( - "███ ████ █████ ████ █████ ████ ███ █████ █ █ █████ █ ███ █████ █ █ ", - "█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ██ ██ ", - "█ █ █ █ █ █ █ █ █ █ █ █ ██ █ █ █ █ █ █ █ █ █ ", - "█ █ ████ █ ████ ████ ████ █ ████ █ █ █ █ █████ █ ███ ████ █ █ █ ", - "█ █ █ █ █ █ █ █ █ █ █ █ ██ █ █ █ █ █ █ █ █ ", - "█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", - "███ ████ █ █ █████ █ █ ███ █████ █ █ █ █ █ ████ █████ █ █ ", - " ", - " ██ ██ ████ ██ ██ ", - " ███████ ███ ███ ██ ██ ████ ██ ", - " ███████ ████ ████ ██ ██ ████ ██ ", - " ██ ██ ██ ██ ██ ██ ██ ██ ", - " ██ ███████ ██ ██ ██ ██ ██ ", - " ██ ███████ ██ ██ ██ ██ ██ ", - "███████ ██ ██ ██ ██ ██ ██ ██ ", - "███████ ██ ██ ██ ██ ██ ██ ██ ", - "██ ██ ██ ██ ██ ██ ██ ██ ██ ", - "██ ██ ██ ██ ██ ██ ██ ██ ██ ", - "██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ", - "██ ██ ██ ██ ██ ██ ██ ██ ██ ████ ", - "██ ██ ██ ██ ██ ██ ██ ██ ██ ████ ", - "██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ", - "██ ██ ██ ██ ██ ██ ████ ", - " ", - " █ ███ ███ █████ ███ ", - " ██ █ █ █ █ ██ █ █ █ ", - "███████ █ ██ █ ██ ██ █ █ ██ ", - "████████ █ █ █ █ █ █ █ █ █ █ ", - "███████ ██ █ ██ █ ██ █ ██ █ ", - " ██ █ █ █ █ ██ █ █ █ █ ", - " █ ███ ███ ███ ███ ", - " " -)) + val testFrameTbrPercentagePortugueseScreen = makeDisplayFrame( + arrayOf( + "███ ████ █████ ████ █████ ████ ███ █████ █ █ █████ █ ███ █████ █ █ ", + "█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ██ ██ ", + "█ █ █ █ █ █ █ █ █ █ █ █ ██ █ █ █ █ █ █ █ █ █ ", + "█ █ ████ █ ████ ████ ████ █ ████ █ █ █ █ █████ █ ███ ████ █ █ █ ", + "█ █ █ █ █ █ █ █ █ █ █ █ ██ █ █ █ █ █ █ █ █ ", + "█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + "███ ████ █ █ █████ █ █ ███ █████ █ █ █ █ █ ████ █████ █ █ ", + " ", + " ██ ██ ████ ██ ██ ", + " ███████ ███ ███ ██ ██ ████ ██ ", + " ███████ ████ ████ ██ ██ ████ ██ ", + " ██ ██ ██ ██ ██ ██ ██ ██ ", + " ██ ███████ ██ ██ ██ ██ ██ ", + " ██ ███████ ██ ██ ██ ██ ██ ", + "███████ ██ ██ ██ ██ ██ ██ ██ ", + "███████ ██ ██ ██ ██ ██ ██ ██ ", + "██ ██ ██ ██ ██ ██ ██ ██ ██ ", + "██ ██ ██ ██ ██ ██ ██ ██ ██ ", + "██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ", + "██ ██ ██ ██ ██ ██ ██ ██ ██ ████ ", + "██ ██ ██ ██ ██ ██ ██ ██ ██ ████ ", + "██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ", + "██ ██ ██ ██ ██ ██ ████ ", + " ", + " █ ███ ███ █████ ███ ", + " ██ █ █ █ █ ██ █ █ █ ", + "███████ █ ██ █ ██ ██ █ █ ██ ", + "████████ █ █ █ █ █ █ █ █ █ █ ", + "███████ ██ █ ██ █ ██ █ ██ █ ", + " ██ █ █ █ █ ██ █ █ █ █ ", + " █ ███ ███ ███ ███ ", + " " + ) + ) -val testFrameTbrDurationPortugueseScreen = makeDisplayFrame(arrayOf( - "███ ████ █████ ███ █ █ ████ █ ████ █ █ ███ ", - "█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ██ █ █ ", - "█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", - "█ █ ████ █ █ █ █ █ ████ █████ █ █ █ █ █ ", - "█ █ █ █ █ █ █ █ █ █ █ █ █ ████ █ █ █ █ ", - "█ █ █ █ █ █ █ █ █ █ █ █ █ █ █████ █ █ ", - "███ ████ █ ███ ███ █ █ █ █ ██ █ █ ███ ", - " ", - " ████ ████ █████ ████ ", - " ██ ██ ██ ██ ██ ██ ██ ██ ██ ", - " ███ ██ ██ ██ ██ ██ ██ ██ ", - " ████ ██ ██ ██ ██ ██ ██ ██ ", - " █████ ██ ██ ██ ██ ██ ██ ██ ", - " ██████ ██ ██ ██ ██ ███ ██ ██ ██ ", - "███████████████ ██ ██ ██ ██ ███ ███ ██ ██ ", - "████████████████ ██ ██ ██ ██ ███ ██ ██ ██ ", - "████████████████ ██ ██ ██ ██ ██ ██ ██ ", - "███████████████ ██ ██ ██ ██ ██ ██ ██ ", - " ██████ ██ ██ ██ ██ ███ ██ ██ ██ ", - " █████ ██ ██ ██ ██ ███ ██ ██ ██ ", - " ████ ██ ██ ██ ██ ███ ██ ██ ██ ", - " ███ ██ ██ ██ ██ ██ ██ ██ ██ ", - " ██ ████ ████ █████ ████ ", - " ", - " ████ █ █ ███ ██ ", - " █ ███ ██ ██ █ █ ██ █ ", - "███ █ █ █ █ █ ██ █ ", - "█ █ █ █ █ █ █ █ █ █ ", - "█ █ █ █ █ █ ██ █ █ ", - "█ █ █ █ █ █ █ █ █ ██ ", - "█ █ █ █ ███ ███ ███ ██ ", - " " -)) + val testFrameTbrDurationPortugueseScreen = makeDisplayFrame( + arrayOf( + "███ ████ █████ ███ █ █ ████ █ ████ █ █ ███ ", + "█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ██ █ █ ", + "█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + "█ █ ████ █ █ █ █ █ ████ █████ █ █ █ █ █ ", + "█ █ █ █ █ █ █ █ █ █ █ █ █ ████ █ █ █ █ ", + "█ █ █ █ █ █ █ █ █ █ █ █ █ █ █████ █ █ ", + "███ ████ █ ███ ███ █ █ █ █ ██ █ █ ███ ", + " ", + " ████ ████ █████ ████ ", + " ██ ██ ██ ██ ██ ██ ██ ██ ██ ", + " ███ ██ ██ ██ ██ ██ ██ ██ ", + " ████ ██ ██ ██ ██ ██ ██ ██ ", + " █████ ██ ██ ██ ██ ██ ██ ██ ", + " ██████ ██ ██ ██ ██ ███ ██ ██ ██ ", + "███████████████ ██ ██ ██ ██ ███ ███ ██ ██ ", + "████████████████ ██ ██ ██ ██ ███ ██ ██ ██ ", + "████████████████ ██ ██ ██ ██ ██ ██ ██ ", + "███████████████ ██ ██ ██ ██ ██ ██ ██ ", + " ██████ ██ ██ ██ ██ ███ ██ ██ ██ ", + " █████ ██ ██ ██ ██ ███ ██ ██ ██ ", + " ████ ██ ██ ██ ██ ███ ██ ██ ██ ", + " ███ ██ ██ ██ ██ ██ ██ ██ ██ ", + " ██ ████ ████ █████ ████ ", + " ", + " ████ █ █ ███ ██ ", + " █ ███ ██ ██ █ █ ██ █ ", + "███ █ █ █ █ █ ██ █ ", + "█ █ █ █ █ █ █ █ █ █ ", + "█ █ █ █ █ █ ██ █ █ ", + "█ █ █ █ █ █ █ █ █ ██ ", + "█ █ █ █ ███ ███ ███ ██ ", + " " + ) + ) -val testFrameTbrPercentageSwedishScreen = makeDisplayFrame(arrayOf( - "█████ ████ ███ ████ ████ ███ ███ █████ █ █ █████ ", - " █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", - " █ █ █ █ █ █ █ █ █ █ █ █ █ ██ █ █ ", - " █ ████ █ █ ████ ████ █ █ █ ████ █ █ █ █ ", - " █ █ █ █ █ █ █ █ █ █ █ █ █ ██ █ ", - " █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", - " █ ████ ███ █ █ █ ███ ███ █████ █ █ █ ", - " ", - " ██ ██ ████ ██ ██ ", - " ███████ ███ ███ ██ ██ ████ ██ ", - " ███████ ████ ████ ██ ██ ████ ██ ", - " ██ ██ ██ ██ ██ ██ ██ ██ ", - " ██ ███████ ██ ██ ██ ██ ██ ", - " ██ ███████ ██ ██ ██ ██ ██ ", - "███████ ██ ██ ██ ██ ██ ██ ██ ", - "███████ ██ ██ ██ ██ ██ ██ ██ ", - "██ ██ ██ ██ ██ ██ ██ ██ ██ ", - "██ ██ ██ ██ ██ ██ ██ ██ ██ ", - "██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ", - "██ ██ ██ ██ ██ ██ ██ ██ ██ ████ ", - "██ ██ ██ ██ ██ ██ ██ ██ ██ ████ ", - "██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ", - "██ ██ ██ ██ ██ ██ ████ ", - " ", - " █ ███ ███ █████ ███ ", - " ██ █ █ █ █ ██ █ █ █ ", - "███████ █ ██ █ ██ ██ █ █ ██ ", - "████████ █ █ █ █ █ █ █ █ █ █ ", - "███████ ██ █ ██ █ ██ █ ██ █ ", - " ██ █ █ █ █ ██ █ █ █ █ ", - " █ ███ ███ ███ ███ ", - " " -)) + val testFrameTbrPercentageSwedishScreen = makeDisplayFrame( + arrayOf( + "█████ ████ ███ ████ ████ ███ ███ █████ █ █ █████ ", + " █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + " █ █ █ █ █ █ █ █ █ █ █ █ █ ██ █ █ ", + " █ ████ █ █ ████ ████ █ █ █ ████ █ █ █ █ ", + " █ █ █ █ █ █ █ █ █ █ █ █ █ ██ █ ", + " █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + " █ ████ ███ █ █ █ ███ ███ █████ █ █ █ ", + " ", + " ██ ██ ████ ██ ██ ", + " ███████ ███ ███ ██ ██ ████ ██ ", + " ███████ ████ ████ ██ ██ ████ ██ ", + " ██ ██ ██ ██ ██ ██ ██ ██ ", + " ██ ███████ ██ ██ ██ ██ ██ ", + " ██ ███████ ██ ██ ██ ██ ██ ", + "███████ ██ ██ ██ ██ ██ ██ ██ ", + "███████ ██ ██ ██ ██ ██ ██ ██ ", + "██ ██ ██ ██ ██ ██ ██ ██ ██ ", + "██ ██ ██ ██ ██ ██ ██ ██ ██ ", + "██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ", + "██ ██ ██ ██ ██ ██ ██ ██ ██ ████ ", + "██ ██ ██ ██ ██ ██ ██ ██ ██ ████ ", + "██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ", + "██ ██ ██ ██ ██ ██ ████ ", + " ", + " █ ███ ███ █████ ███ ", + " ██ █ █ █ █ ██ █ █ █ ", + "███████ █ ██ █ ██ ██ █ █ ██ ", + "████████ █ █ █ █ █ █ █ █ █ █ ", + "███████ ██ █ ██ █ ██ █ ██ █ ", + " ██ █ █ █ █ ██ █ █ █ █ ", + " █ ███ ███ ███ ███ ", + " " + ) + ) -val testFrameTbrDurationSwedishScreen = makeDisplayFrame(arrayOf( - "█████ ████ ███ ███ █ █ ████ █ █████ ███ ███ █ █ ", - " █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", - " █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ██ █ ", - " █ ████ █ █ █ █ █ █ ████ █████ █ █ █ █ █ █ █ ", - " █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ██ ", - " █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", - " █ ████ ███ ███ ███ █ █ █ █ █ ███ ███ █ █ ", - " ", - " ████ ████ █████ ████ ", - " ██ ██ ██ ██ ██ ██ ██ ██ ██ ", - " ███ ██ ██ ██ ██ ██ ██ ██ ", - " ████ ██ ██ ██ ██ ██ ██ ██ ", - " █████ ██ ██ ██ ██ ██ ██ ██ ", - " ██████ ██ ██ ██ ██ ███ ██ ██ ██ ", - "███████████████ ██ ██ ██ ██ ███ ███ ██ ██ ", - "████████████████ ██ ██ ██ ██ ███ ██ ██ ██ ", - "████████████████ ██ ██ ██ ██ ██ ██ ██ ", - "███████████████ ██ ██ ██ ██ ██ ██ ██ ", - " ██████ ██ ██ ██ ██ ███ ██ ██ ██ ", - " █████ ██ ██ ██ ██ ███ ██ ██ ██ ", - " ████ ██ ██ ██ ██ ███ ██ ██ ██ ", - " ███ ██ ██ ██ ██ ██ ██ ██ ██ ", - " ██ ████ ████ █████ ████ ", - " ", - " ████ █ █ ███ ██ ", - " █ ███ ██ ██ █ █ ██ █ ", - "███ █ █ █ █ █ ██ █ ", - "█ █ █ █ █ █ █ █ █ █ ", - "█ █ █ █ █ █ ██ █ █ ", - "█ █ █ █ █ █ █ █ █ ██ ", - "█ █ █ █ ███ ███ ███ ██ ", - " " -)) + val testFrameTbrDurationSwedishScreen = makeDisplayFrame( + arrayOf( + "█████ ████ ███ ███ █ █ ████ █ █████ ███ ███ █ █ ", + " █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + " █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ██ █ ", + " █ ████ █ █ █ █ █ █ ████ █████ █ █ █ █ █ █ █ ", + " █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ██ ", + " █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + " █ ████ ███ ███ ███ █ █ █ █ █ ███ ███ █ █ ", + " ", + " ████ ████ █████ ████ ", + " ██ ██ ██ ██ ██ ██ ██ ██ ██ ", + " ███ ██ ██ ██ ██ ██ ██ ██ ", + " ████ ██ ██ ██ ██ ██ ██ ██ ", + " █████ ██ ██ ██ ██ ██ ██ ██ ", + " ██████ ██ ██ ██ ██ ███ ██ ██ ██ ", + "███████████████ ██ ██ ██ ██ ███ ███ ██ ██ ", + "████████████████ ██ ██ ██ ██ ███ ██ ██ ██ ", + "████████████████ ██ ██ ██ ██ ██ ██ ██ ", + "███████████████ ██ ██ ██ ██ ██ ██ ██ ", + " ██████ ██ ██ ██ ██ ███ ██ ██ ██ ", + " █████ ██ ██ ██ ██ ███ ██ ██ ██ ", + " ████ ██ ██ ██ ██ ███ ██ ██ ██ ", + " ███ ██ ██ ██ ██ ██ ██ ██ ██ ", + " ██ ████ ████ █████ ████ ", + " ", + " ████ █ █ ███ ██ ", + " █ ███ ██ ██ █ █ ██ █ ", + "███ █ █ █ █ █ ██ █ ", + "█ █ █ █ █ █ █ █ █ █ ", + "█ █ █ █ █ █ ██ █ █ ", + "█ █ █ █ █ █ █ █ █ ██ ", + "█ █ █ █ ███ ███ ███ ██ ", + " " + ) + ) -val testFrameTbrPercentageDanishScreen = makeDisplayFrame(arrayOf( - "█ █ ████ ████ ████ ████ ███ ███ █████ █ █ █████ ", - "██ ██ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", - "█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ██ █ █ ", - "█ █ █ ████ ████ █████ ████ ████ █ █ █ ████ █ █ █ █ ", - "█ █ █ █ █ █ █ █ █ █ █ █ █ █ ██ █ ", - "█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", - "█ █ ████ █ █ █ █ █ ███ ███ █████ █ █ █ ", - " ", - " ██ ██ ████ ██ ██ ", - " ███████ ███ ███ ██ ██ ████ ██ ", - " ███████ ████ ████ ██ ██ ████ ██ ", - " ██ ██ ██ ██ ██ ██ ██ ██ ", - " ██ ███████ ██ ██ ██ ██ ██ ", - " ██ ███████ ██ ██ ██ ██ ██ ", - "███████ ██ ██ ██ ██ ██ ██ ██ ", - "███████ ██ ██ ██ ██ ██ ██ ██ ", - "██ ██ ██ ██ ██ ██ ██ ██ ██ ", - "██ ██ ██ ██ ██ ██ ██ ██ ██ ", - "██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ", - "██ ██ ██ ██ ██ ██ ██ ██ ██ ████ ", - "██ ██ ██ ██ ██ ██ ██ ██ ██ ████ ", - "██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ", - "██ ██ ██ ██ ██ ██ ████ ", - " ", - " █ ███ ███ █████ ███ ", - " ██ █ █ █ █ ██ █ █ █ ", - "███████ █ ██ █ ██ ██ █ █ ██ ", - "████████ █ █ █ █ █ █ █ █ █ █ ", - "███████ ██ █ ██ █ ██ █ ██ █ ", - " ██ █ █ █ █ ██ █ █ █ █ ", - " █ ███ ███ ███ ███ ", - " " -)) + val testFrameTbrPercentageDanishScreen = makeDisplayFrame( + arrayOf( + "█ █ ████ ████ ████ ████ ███ ███ █████ █ █ █████ ", + "██ ██ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + "█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ██ █ █ ", + "█ █ █ ████ ████ █████ ████ ████ █ █ █ ████ █ █ █ █ ", + "█ █ █ █ █ █ █ █ █ █ █ █ █ █ ██ █ ", + "█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + "█ █ ████ █ █ █ █ █ ███ ███ █████ █ █ █ ", + " ", + " ██ ██ ████ ██ ██ ", + " ███████ ███ ███ ██ ██ ████ ██ ", + " ███████ ████ ████ ██ ██ ████ ██ ", + " ██ ██ ██ ██ ██ ██ ██ ██ ", + " ██ ███████ ██ ██ ██ ██ ██ ", + " ██ ███████ ██ ██ ██ ██ ██ ", + "███████ ██ ██ ██ ██ ██ ██ ██ ", + "███████ ██ ██ ██ ██ ██ ██ ██ ", + "██ ██ ██ ██ ██ ██ ██ ██ ██ ", + "██ ██ ██ ██ ██ ██ ██ ██ ██ ", + "██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ", + "██ ██ ██ ██ ██ ██ ██ ██ ██ ████ ", + "██ ██ ██ ██ ██ ██ ██ ██ ██ ████ ", + "██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ", + "██ ██ ██ ██ ██ ██ ████ ", + " ", + " █ ███ ███ █████ ███ ", + " ██ █ █ █ █ ██ █ █ █ ", + "███████ █ ██ █ ██ ██ █ █ ██ ", + "████████ █ █ █ █ █ █ █ █ █ █ ", + "███████ ██ █ ██ █ ██ █ ██ █ ", + " ██ █ █ █ █ ██ █ █ █ █ ", + " █ ███ ███ ███ ███ ", + " " + ) + ) -val testFrameTbrDurationDanishScreen = makeDisplayFrame(arrayOf( - "█ █ ████ ████ █ █ █ ████ ███ ███ █ █ █████ ███ ", - "██ ██ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", - "█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", - "█ █ █ ████ ████ █████ █ █ █████ ████ █ █ ███ █████ ████ █ █ ", - "█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", - "█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", - "█ █ ████ █ █ █ █ █ █ █ ███ ████ █ █ █████ ███ ", - " ", - " ████ ████ █████ ████ ", - " ██ ██ ██ ██ ██ ██ ██ ██ ██ ", - " ███ ██ ██ ██ ██ ██ ██ ██ ", - " ████ ██ ██ ██ ██ ██ ██ ██ ", - " █████ ██ ██ ██ ██ ██ ██ ██ ", - " ██████ ██ ██ ██ ██ ███ ██ ██ ██ ", - "███████████████ ██ ██ ██ ██ ███ ███ ██ ██ ", - "████████████████ ██ ██ ██ ██ ███ ██ ██ ██ ", - "████████████████ ██ ██ ██ ██ ██ ██ ██ ", - "███████████████ ██ ██ ██ ██ ██ ██ ██ ", - " ██████ ██ ██ ██ ██ ███ ██ ██ ██ ", - " █████ ██ ██ ██ ██ ███ ██ ██ ██ ", - " ████ ██ ██ ██ ██ ███ ██ ██ ██ ", - " ███ ██ ██ ██ ██ ██ ██ ██ ██ ", - " ██ ████ ████ █████ ████ ", - " ", - " ████ █ █ ███ ██ ", - " █ ███ ██ ██ █ █ ██ █ ", - "███ █ █ █ █ █ ██ █ ", - "█ █ █ █ █ █ █ █ █ █ ", - "█ █ █ █ █ █ ██ █ █ ", - "█ █ █ █ █ █ █ █ █ ██ ", - "█ █ █ █ ███ ███ ███ ██ ", - " " -)) + val testFrameTbrDurationDanishScreen = makeDisplayFrame( + arrayOf( + "█ █ ████ ████ █ █ █ ████ ███ ███ █ █ █████ ███ ", + "██ ██ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + "█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + "█ █ █ ████ ████ █████ █ █ █████ ████ █ █ ███ █████ ████ █ █ ", + "█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + "█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + "█ █ ████ █ █ █ █ █ █ █ ███ ████ █ █ █████ ███ ", + " ", + " ████ ████ █████ ████ ", + " ██ ██ ██ ██ ██ ██ ██ ██ ██ ", + " ███ ██ ██ ██ ██ ██ ██ ██ ", + " ████ ██ ██ ██ ██ ██ ██ ██ ", + " █████ ██ ██ ██ ██ ██ ██ ██ ", + " ██████ ██ ██ ██ ██ ███ ██ ██ ██ ", + "███████████████ ██ ██ ██ ██ ███ ███ ██ ██ ", + "████████████████ ██ ██ ██ ██ ███ ██ ██ ██ ", + "████████████████ ██ ██ ██ ██ ██ ██ ██ ", + "███████████████ ██ ██ ██ ██ ██ ██ ██ ", + " ██████ ██ ██ ██ ██ ███ ██ ██ ██ ", + " █████ ██ ██ ██ ██ ███ ██ ██ ██ ", + " ████ ██ ██ ██ ██ ███ ██ ██ ██ ", + " ███ ██ ██ ██ ██ ██ ██ ██ ██ ", + " ██ ████ ████ █████ ████ ", + " ", + " ████ █ █ ███ ██ ", + " █ ███ ██ ██ █ █ ██ █ ", + "███ █ █ █ █ █ ██ █ ", + "█ █ █ █ █ █ █ █ █ █ ", + "█ █ █ █ █ █ ██ █ █ ", + "█ █ █ █ █ █ █ █ █ ██ ", + "█ █ █ █ ███ ███ ███ ██ ", + " " + ) + ) -val testFrameTbrPercentageGermanScreen = makeDisplayFrame(arrayOf( - "█████ ████ ████ █ █ █████ ████ █████ ", - " █ █ █ █ █ █ █ █ █ █ █ ", - " █ █ █ █ █ █ █ █ █ █ █ ", - " █ ████ ████ █ █ █ ████ ████ █ ", - " █ █ █ █ █ █ █ █ █ █ █ █ ", - " █ █ █ █ █ █ █ █ █ █ █ █ ", - " █ ████ █ █ █ █ █████ █ █ █ ", - " ", - " ██ ██ ████ ██ ██ ", - " ███████ ███ ███ ██ ██ ████ ██ ", - " ███████ ████ ████ ██ ██ ████ ██ ", - " ██ ██ ██ ██ ██ ██ ██ ██ ", - " ██ ███████ ██ ██ ██ ██ ██ ", - " ██ ███████ ██ ██ ██ ██ ██ ", - "███████ ██ ██ ██ ██ ██ ██ ██ ", - "███████ ██ ██ ██ ██ ██ ██ ██ ", - "██ ██ ██ ██ ██ ██ ██ ██ ██ ", - "██ ██ ██ ██ ██ ██ ██ ██ ██ ", - "██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ", - "██ ██ ██ ██ ██ ██ ██ ██ ██ ████ ", - "██ ██ ██ ██ ██ ██ ██ ██ ██ ████ ", - "██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ", - "██ ██ ██ ██ ██ ██ ████ ", - " ", - " █ ███ ███ █████ ███ ", - " ██ █ █ █ █ ██ █ █ █ ", - "███████ █ ██ █ ██ ██ █ █ ██ ", - "████████ █ █ █ █ █ █ █ █ █ █ ", - "███████ ██ █ ██ █ ██ █ ██ █ ", - " ██ █ █ █ █ ██ █ █ █ █ ", - " █ ███ ███ ███ ███ ", - " " -)) + val testFrameTbrPercentageGermanScreen = makeDisplayFrame( + arrayOf( + "█████ ████ ████ █ █ █████ ████ █████ ", + " █ █ █ █ █ █ █ █ █ █ █ ", + " █ █ █ █ █ █ █ █ █ █ █ ", + " █ ████ ████ █ █ █ ████ ████ █ ", + " █ █ █ █ █ █ █ █ █ █ █ █ ", + " █ █ █ █ █ █ █ █ █ █ █ █ ", + " █ ████ █ █ █ █ █████ █ █ █ ", + " ", + " ██ ██ ████ ██ ██ ", + " ███████ ███ ███ ██ ██ ████ ██ ", + " ███████ ████ ████ ██ ██ ████ ██ ", + " ██ ██ ██ ██ ██ ██ ██ ██ ", + " ██ ███████ ██ ██ ██ ██ ██ ", + " ██ ███████ ██ ██ ██ ██ ██ ", + "███████ ██ ██ ██ ██ ██ ██ ██ ", + "███████ ██ ██ ██ ██ ██ ██ ██ ", + "██ ██ ██ ██ ██ ██ ██ ██ ██ ", + "██ ██ ██ ██ ██ ██ ██ ██ ██ ", + "██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ", + "██ ██ ██ ██ ██ ██ ██ ██ ██ ████ ", + "██ ██ ██ ██ ██ ██ ██ ██ ██ ████ ", + "██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ", + "██ ██ ██ ██ ██ ██ ████ ", + " ", + " █ ███ ███ █████ ███ ", + " ██ █ █ █ █ ██ █ █ █ ", + "███████ █ ██ █ ██ ██ █ █ ██ ", + "████████ █ █ █ █ █ █ █ █ █ █ ", + "███████ ██ █ ██ █ ██ █ ██ █ ", + " ██ █ █ █ █ ██ █ █ █ █ ", + " █ ███ ███ ███ ███ ", + " " + ) + ) -val testFrameTbrDurationGermanScreen = makeDisplayFrame(arrayOf( - "█████ ████ ████ ███ █ █ █ █████ ████ ", - " █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", - " █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", - " █ ████ ████ █ █ █████ █ █ ████ ████ ", - " █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", - " █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", - " █ ████ █ █ ███ █ █ ███ █████ █ █ ", - " ", - " ████ ████ █████ ████ ", - " ██ ██ ██ ██ ██ ██ ██ ██ ██ ", - " ███ ██ ██ ██ ██ ██ ██ ██ ", - " ████ ██ ██ ██ ██ ██ ██ ██ ", - " █████ ██ ██ ██ ██ ██ ██ ██ ", - " ██████ ██ ██ ██ ██ ███ ██ ██ ██ ", - "███████████████ ██ ██ ██ ██ ███ ███ ██ ██ ", - "████████████████ ██ ██ ██ ██ ███ ██ ██ ██ ", - "████████████████ ██ ██ ██ ██ ██ ██ ██ ", - "███████████████ ██ ██ ██ ██ ██ ██ ██ ", - " ██████ ██ ██ ██ ██ ███ ██ ██ ██ ", - " █████ ██ ██ ██ ██ ███ ██ ██ ██ ", - " ████ ██ ██ ██ ██ ███ ██ ██ ██ ", - " ███ ██ ██ ██ ██ ██ ██ ██ ██ ", - " ██ ████ ████ █████ ████ ", - " ", - " ████ █ █ ███ ██ ", - " █ ███ ██ ██ █ █ ██ █ ", - "███ █ █ █ █ █ ██ █ ", - "█ █ █ █ █ █ █ █ █ █ ", - "█ █ █ █ █ █ ██ █ █ ", - "█ █ █ █ █ █ █ █ █ ██ ", - "█ █ █ █ ███ ███ ███ ██ ", - " " -)) + val testFrameTbrDurationGermanScreen = makeDisplayFrame( + arrayOf( + "█████ ████ ████ ███ █ █ █ █████ ████ ", + " █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + " █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + " █ ████ ████ █ █ █████ █ █ ████ ████ ", + " █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + " █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + " █ ████ █ █ ███ █ █ ███ █████ █ █ ", + " ", + " ████ ████ █████ ████ ", + " ██ ██ ██ ██ ██ ██ ██ ██ ██ ", + " ███ ██ ██ ██ ██ ██ ██ ██ ", + " ████ ██ ██ ██ ██ ██ ██ ██ ", + " █████ ██ ██ ██ ██ ██ ██ ██ ", + " ██████ ██ ██ ██ ██ ███ ██ ██ ██ ", + "███████████████ ██ ██ ██ ██ ███ ███ ██ ██ ", + "████████████████ ██ ██ ██ ██ ███ ██ ██ ██ ", + "████████████████ ██ ██ ██ ██ ██ ██ ██ ", + "███████████████ ██ ██ ██ ██ ██ ██ ██ ", + " ██████ ██ ██ ██ ██ ███ ██ ██ ██ ", + " █████ ██ ██ ██ ██ ███ ██ ██ ██ ", + " ████ ██ ██ ██ ██ ███ ██ ██ ██ ", + " ███ ██ ██ ██ ██ ██ ██ ██ ██ ", + " ██ ████ ████ █████ ████ ", + " ", + " ████ █ █ ███ ██ ", + " █ ███ ██ ██ █ █ ██ █ ", + "███ █ █ █ █ █ ██ █ ", + "█ █ █ █ █ █ █ █ █ █ ", + "█ █ █ █ █ █ ██ █ █ ", + "█ █ █ █ █ █ █ █ █ ██ ", + "█ █ █ █ ███ ███ ███ ██ ", + " " + ) + ) + + val testFrameTbrPercentageSlovenianScreen = makeDisplayFrame( + arrayOf( + " ███ ███ ████ █████ ███ █████ █████ █ █ █████ ████ ███ ", + "█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + "█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + "█ █ █ █ ███ █ █ █ █ ████ ██ █ ████ █ █ ", + "█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + "█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + " ███ ███ ████ █ ███ █ █████ █ █ █████ ████ ███ ", + " ", + " ██ ██ ████ ██ ██ ", + " ███████ ███ ███ ██ ██ ████ ██ ", + " ███████ ████ ████ ██ ██ ████ ██ ", + " ██ ██ ██ ██ ██ ██ ██ ██ ", + " ██ ███████ ██ ██ ██ ██ ██ ", + " ██ ███████ ██ ██ ██ ██ ██ ", + "███████ ██ ██ ██ ██ ██ ██ ██ ", + "███████ ██ ██ ██ ██ ██ ██ ██ ", + "██ ██ ██ ██ ██ ██ ██ ██ ██ ", + "██ ██ ██ ██ ██ ██ ██ ██ ██ ", + "██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ", + "██ ██ ██ ██ ██ ██ ██ ██ ██ ████ ", + "██ ██ ██ ██ ██ ██ ██ ██ ██ ████ ", + "██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ", + "██ ██ ██ ██ ██ ██ ████ ", + " ", + " █ ███ ███ █ █████ ", + " ██ █ █ █ █ ██ ██ █ ", + "███████ █ ██ █ ██ ██ █ ████ ", + "████████ █ █ █ █ █ █ █ █ ", + "███████ ██ █ ██ █ ██ █ █ ", + " ██ █ █ █ █ ██ █ █ █ ", + " █ ███ ███ ███ ███ ", + " " + ) + ) + + val testFrameTbrDurationSlovenianScreen = makeDisplayFrame( + arrayOf( + "█████ ████ █ ███ █ █ █ ███ █████ █████ ████ ███ ", + " █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + " █ █ █ █ █ █ █ █ ██ █ █ █ █ █ █ █ █ ", + " █ ████ █████ █ █████ █ █ █ █ ████ █ ████ █ █ ", + " █ █ █ █ █ █ █ █ █ ██ █ █ █ █ █ █ █ ", + " █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + " █ █ █ █ █ ██ █ █ █ █ ██ █████ █████ ████ ███ ", + " ", + " ████ ████ ██ ███████ ", + " ██ ██ ██ ██ ██ ███ ██ ", + " ███ ██ ██ ██ ██ ████ ██ ", + " ████ ██ ██ ██ ██ ██ ██ ", + " █████ ██ ██ ██ ██ ██ ██ ", + " ██████ ██ ██ ██ ██ ███ ██ ██████ ", + "███████████████ ██ ██ ██ ██ ███ ██ ██ ", + "████████████████ ██ ██ ██ ██ ███ ██ ██ ", + "████████████████ ██ ██ ██ ██ ██ ██ ", + "███████████████ ██ ██ ██ ██ ██ ██ ", + " ██████ ██ ██ ██ ██ ███ ██ ██ ", + " █████ ██ ██ ██ ██ ███ ██ ██ ", + " ████ ██ ██ ██ ██ ███ ██ ██ ", + " ███ ██ ██ ██ ██ ██ ██ ██ ", + " ██ ████ ████ ██ █████ ", + " ", + " ████ █ █ ███ ██ ", + " █ ███ ██ ██ █ █ ██ █ ", + "███ █ █ █ █ █ ██ █ ", + "█ █ █ █ █ █ █ █ █ █ ", + "█ █ █ █ █ █ ██ █ █ ", + "█ █ █ █ █ █ █ █ █ ██ ", + "█ █ █ █ ███ ███ ███ ██ ", + " " + ) + ) +} val testTimeAndDateSettingsHour12hFormatScreen = makeDisplayFrame(arrayOf( "█ █ ███ █ █ ████ ", @@ -6808,6 +6964,181 @@ val testTimeAndDateSettingsDayGermanScreen = makeDisplayFrame(arrayOf( " " )) +val testTimeAndDateSettingsHourSlovenianScreen = makeDisplayFrame(arrayOf( + "█ █ ████ █ ", + "█ █ █ █ █ █ ", + "█ █ █ █ █ █ ", + "█ █ ████ █████ ", + "█ █ █ █ █ █ ", + "█ █ █ █ █ █ ", + " ███ █ █ █ █ ", + " ", + " ██ ████ ", + " █████ ███ ██ ██ ", + " ██ ██ ████ ██ ██ ", + " █ █ █ ██ ██ ██ ", + " █ █ ██ ██ ██ ██ ", + "█ █ █ ██ ██ ██ ", + "█ █ ██ ██ ██ ███ ", + "█ ████ ██ ██ ██████ ", + "█ ██ ██ ██ ", + "█ ██ ██ ██ ", + " █ ███ ██ ██ ", + " █ ██ ██ ██ ", + " ██ ████ ██ ██ ", + " █████████ ██ ██ ", + " █████ ██ ███ ", + " ", + " █ ███ █████ ███ ███ ███ ███ █████ ███ █████", + " ██ █ █ ██ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + " █ █ █ ██ ████ █ ██ █ ██ █ █ █ ██ █ █ █ ", + " █ ████ █ █ █ █ █ █ █ ███ █ █ █ █ █ █ ", + " █ █ ██ █ ██ █ ██ █ █ █ ██ █ █ █ █", + " █ █ ██ █ █ █ █ █ █ █ █ ██ █ █ █ █ ██ █ █ █", + " ███ ██ ███ ███ ███ ███ ██ ███ ███ ██ █████ ███ ", + " " +)) + +val testTimeAndDateSettingsMinuteSlovenianScreen = makeDisplayFrame(arrayOf( + "█ █ ███ █ █ █ █ █████ █████ ", + "██ ██ █ █ █ █ █ █ █ ", + "█ █ █ █ ██ █ █ █ █ █ ", + "█ █ █ █ █ █ █ █ █ █ ████ ", + "█ █ █ █ ██ █ █ █ █ ", + "█ █ █ █ █ █ █ █ █ ", + "█ █ ███ █ █ ███ █ █████ ", + " ", + " ███████ ████ ", + " █████ ██ ██ ██ ", + " ██ ██ ██ ██ ██ ", + " █ █ █ ██ ██ ██ ", + " █ █ ██ ██ ██ ██ ", + "█ █ █ ██████ ██ ██ ", + "█ █ ██ ██ ██ ██ ", + "█ ████ ██ ██ ██ ██ ", + "█ ██ ██ ██ ██ ", + "█ ██ ██ ██ ██ ", + " █ ███ ██ ██ ██ ", + " █ ██ ██ ██ ██ ", + " ██ ████ ██ ██ ██ ", + " █████████ ██ ██ ██ ██ ", + " █████ █████ ████ ", + " ", + " █ ███ █████ ███ ███ ███ ███ █████ ███ █████", + " ██ █ █ ██ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + " █ █ █ ██ ████ █ ██ █ ██ █ █ █ ██ █ █ █ ", + " █ ████ █ █ █ █ █ █ █ ███ █ █ █ █ █ █ ", + " █ █ ██ █ ██ █ ██ █ █ █ ██ █ █ █ █", + " █ █ ██ █ █ █ █ █ █ █ █ ██ █ █ █ █ ██ █ █ █", + " ███ ██ ███ ███ ███ ███ ██ ███ ███ ██ █████ ███ ", + " " +)) + +val testTimeAndDateSettingsYearSlovenianScreen = makeDisplayFrame(arrayOf( + "█ █████ █████ ███ ", + "█ █ █ █ █ ", + "█ █ █ █ █ ", + "█ ████ █ █ █ ", + "█ █ █ █ █ ", + "█ █ █ █ █ ", + "█████ █████ █ ███ ", + " ", + " ████ ████ ████ █████ ", + "█████████████ ██ ██ ██ ██ ██ ██ ██ ██ ", + "█ ██ ██ ██ ██ ██ ██ ██ ██ ", + "██████████████ ██ ██ ██ ██ ██ ██ ██ ", + "█ █ █ █ █ █ ██ ██ ██ ██ ██ ██ ", + "██████████████ ██ ██ ██ ██ ██ ", + "█ █ █ █ █ █ ██ ██ ██ ██ ██ ███ ", + "██████████████ ██ ██ ██ ██ ██ ", + "█ █ █ █ █ █ ██ ██ ██ ██ ██ ██ ", + "██████████████ ██ ██ ██ ██ ██ ", + "█ █ █ █ ██████ ██ ██ ██ ██ ██ ", + "██████████████ ██ ██ ██ ██ ██ ", + " █████████████ ██ ██ ██ ██ ██ ", + " ██ ██ ██ ██ ██ ██ ", + " ████████ ████ ████████ █████ ", + " ", + " █ ███ █████ ███ ███ ███ ███ █████ ███ █████", + " ██ █ █ ██ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + " █ █ █ ██ ████ █ ██ █ ██ █ █ █ ██ █ █ █ ", + " █ ████ █ █ █ █ █ █ █ ███ █ █ █ █ █ █ ", + " █ █ ██ █ ██ █ ██ █ █ █ ██ █ █ █ █", + " █ █ ██ █ █ █ █ █ █ █ █ ██ █ █ █ █ ██ █ █ █", + " ███ ██ ███ ███ ███ ███ ██ ███ ███ ██ █████ ███ ", + " " +)) + +val testTimeAndDateSettingsMonthSlovenianScreen = makeDisplayFrame(arrayOf( + "█ █ █████ ████ █████ ███ ", + "██ ██ █ █ █ █ █ ", + "█ █ █ █ █ █ █ ", + "█ █ █ ████ ███ ████ █ ", + "█ █ █ █ █ █ ", + "█ █ █ █ █ █ █ ", + "█ █ █████ ████ █████ ███ ", + " ", + " █████ ", + "█████████████ ██ ██ ", + "█ ██ ██ ", + "██████████████ ██ ", + "█ █ █ █ █ █ ██ ██ ", + "██████████████ ██ ", + "█ █ █ █ █ █ ██ ███ ", + "██████████████ ██ ", + "█ █ █ █ █ █ ██ ██ ", + "██████████████ ██ ", + "█ █ █ █ ██████ ██ ", + "██████████████ ██ ", + " █████████████ ██ ", + " ██ ██ ", + " █████ ", + " ", + " █ ███ █████ ███ ███ ███ ███ █████ ███ █████", + " ██ █ █ ██ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + " █ █ █ ██ ████ █ ██ █ ██ █ █ █ ██ █ █ █ ", + " █ ████ █ █ █ █ █ █ █ ███ █ █ █ █ █ █ ", + " █ █ ██ █ ██ █ ██ █ █ █ ██ █ █ █ █", + " █ █ ██ █ █ █ █ █ █ █ █ ██ █ █ █ █ ██ █ █ █", + " ███ ██ ███ ███ ███ ███ ██ ███ ███ ██ █████ ███ ", + " " +)) + +val testTimeAndDateSettingsDaySlovenianScreen = makeDisplayFrame(arrayOf( + "███ █ █ █ ", + "█ █ █ █ █ █ ", + "█ █ █ █ ██ █ ", + "█ █ █████ █ █ █ ", + "█ █ █ █ █ ██ ", + "█ █ █ █ █ █ ", + "███ █ █ █ █ ", + " ", + " ████ ", + "█████████████ ██ ██ ", + "█ ██ ██ ██ ", + "██████████████ ██ ██ ", + "█ █ █ █ █ █ ██ ██ ██ ", + "██████████████ ██ ██ ", + "█ █ █ █ █ █ ██ ████ ", + "██████████████ ██ ██ ", + "█ █ █ █ █ █ ██ ██ ██ ", + "██████████████ ██ ██ ", + "█ █ █ █ ██████ ██ ██ ", + "██████████████ ██ ██ ", + " █████████████ ██ ██ ", + " ██ ██ ", + " ████ ", + " ", + " █ ███ █████ ███ ███ ███ ███ █████ ███ █████", + " ██ █ █ ██ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + " █ █ █ ██ ████ █ ██ █ ██ █ █ █ ██ █ █ █ ", + " █ ████ █ █ █ █ █ █ █ ███ █ █ █ █ █ █ ", + " █ █ ██ █ ██ █ ██ █ █ █ ██ █ █ █ █", + " █ █ ██ █ █ █ █ █ █ █ █ ██ █ █ █ █ ██ █ █ █", + " ███ ██ ███ ███ ███ ███ ██ ███ ███ ██ █████ ███ ", + " " +)) + val testUSDateFormatScreen = makeDisplayFrame(arrayOf( "███ █ █████ █ █ █ █ ████ █████ ███ ████ █ █ █ █████ ", "█ █ █ █ █ █ █ ██ ██ █ █ █ █ █ █ ██ ██ █ █ █ ", @@ -9713,6 +10044,146 @@ val testMyDataBolusDataGermanScreen = makeDisplayFrame(arrayOf( " " )) +val testMyDataTbrDataSlovenianScreen = makeDisplayFrame(arrayOf( + "████ ███ ███ █ █████ █ █ ███ ███ █████ ████ ███ ", + "█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + "█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + "████ █ █ █ █ █████ █ ██ █ █ █ █ ████ █ █ ", + "█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + "█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + "█ ███ ███ █ █ █ █ █ ███ ███ █████ ████ ███ ", + " ", + " █ █ █ ███ ██ ███ █ █████ ███ ", + " ███ ██ ██ █ █ ██ █ █ █ ██ █ █ █ █ ", + " █████ █ █ █ ██ █ █ ██ █ █ █ █ ██ ", + "███████ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + " ███ █ █ ██ █ █ ██ █ █ █ █ ██ █ ", + " ███ █ █ █ █ █ ██ █ █ █ █ █ █ █ █ ", + " ███ ███ ███ ███ ██ ███ ███ ███ ███ ", + " ", + " █ ███ ███ ███ █ ", + " ██ █ █ █ █ ██ █ █ ██ ", + "███████ █ ██ █ ██ ██ █ ██ █ ", + "████████ █ █ █ █ █ █ █ █ █ █ ", + "███████ ██ █ ██ █ ██ ██ █ █ ", + " ██ █ █ █ █ ██ █ █ █ ", + " █ ███ ███ ███ ███ ", + " ", + " ███ █ █████ █████ █ ███████ ███ ███ ███ █████ ", + " █ █ █ ██ █ ██ █ ██ █ █ █ █ █ █ █ █ █ ", + "█ █ █ █ █ ██ █ █ ███████ █ ██ █ █ █ ██ █ ", + "█ ██ █ █ █ █ █ █ █ █ █ █ █ █ ███ █ █ █ █ ", + "█ █ █ █ ██ █ █ ███████ ██ █ █ █ ██ █ █ ", + " █ █ █ █ ██ █ █ █ █ █ ███ █ █ █ █ ██ █ █ █ █ ", + " ███ ███ █ ███ ███ ███████ ███ ███ ██ ███ ███ ", + " " +)) + +val testMyDataErrorDataSlovenianScreen = makeDisplayFrame(arrayOf( + "████ ███ ███ █ █████ █ █ ███ ███ █ █ █ ████ █ █ █ ███ ", + "█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + "█ █ █ █ █ █ █ █ █ █ █ █ █ █ ██ █ █ █ █ █ █ █ █ █ █ ", + "████ █ █ █ █ █████ █ ██ █ █ █ █ █ █ █████ ████ █████ ██ █ ", + "█ █ █ █ █ █ █ █ █ █ █ █ █ █ ██ █ █ █ █ █ █ █ █ ", + "█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + "█ ███ ███ █ █ █ █ █ ███ ███ █ █ █ █ █ █ █ █ █ ███ ", + " ", + " █ █ █ ██ ███ █ █████ ███ ", + " ███ █ █ █ █ █ ██ █ █ █ █ ", + " █ █ █ █ █ █ ██ █ █ █ █ ██ ", + " █ █ █ █ █ █ ████ █ █ █ █ █ █ █ █ █ ", + " █ █ █ █ █ █ █ ██ █ █ █ █ ██ █ ", + "█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + "███████ █ █ ███ ███ ███ ███ ███ ", + " ", + "████ ████ █████ █ █ █ ███ ███ █████ ████ ███ ", + "█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + "█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + "████ ████ ████ ██ █ █ █ █ ████ █ █ ", + "█ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + "█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + "█ █ █ █████ █ █ █████ ███ ███ █████ ████ ███ ", + " ", + " ███ █ █████ █████ █ ███████ ███ ███ ███ █████ ", + " █ █ █ ██ █ ██ █ ██ █ █ █ █ █ █ █ █ █ ", + "█ █ █ █ █ ██ █ █ ███████ █ ██ █ █ █ ██ █ ", + "█ ██ █ █ █ █ █ █ █ █ █ █ █ █ ███ █ █ █ █ ", + "█ █ █ █ ██ █ █ ███████ ██ █ █ █ ██ █ █ ", + " █ █ █ █ ██ █ █ █ █ █ ███ █ █ █ █ ██ █ █ █ █ ", + " ███ ███ █ ███ ███ ███████ ███ ███ ██ ███ ███ ", + " " +)) + +val testMyDataDailyTotalsSlovenianScreen = makeDisplayFrame(arrayOf( + "███ █ █ █████ █ █ █ █ █ ████ ███ ████ █ ████ █ ", + "█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + "█ █ ██ █ █ █ █ ██ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + "█ █ █ █ █ ████ █ █ █ █ █ █████ ████ █ █ ████ █████ ████ █████ ", + "█ █ █ ██ █ █ █ █ ██ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + "█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + "███ █ █ █████ █ █ █ █ █ █ ███ █ █ █ █ ████ █ █ ", + " ", + " ███ █ █████ ███ ", + " █ █ ██ █ █ █ █ ", + " █ ██ █ █ █ █ ██ ", + " █ █ █ █ █ █ █ █ █ ", + " ██ █ █ █ █ ██ █ ", + " █ █ █ █ █ █ █ █ ", + " ███ ███ ███ ███ ", + " ", + "██████ █████ ███ █ █ █ ", + "█ █ █ █ █ ██ █ █ ", + " █ █ █ █ █ █ ", + " █ █ █ █ █ █ ", + " █ █ █ █ █ █ ", + "█ █ █ █ █ ██ █ █ █ ", + "██████ ███ █████ ██ ███ ███ ", + " ", + " ███████ ███ ███ ███ █████ ", + " █ █ █ █ █ █ █ █ █ ", + " ███████ █ ██ █ █ █ ██ █ ", + " █ █ █ █ █ █ █ ███ █ █ █ █ ", + " ███████ ██ █ █ █ ██ █ █ ", + " █ █ ███ █ █ █ █ ██ █ █ █ █ ", + " ███████ ███ ███ ██ ███ ███ ", + " " +)) + +val testMyDataBolusDataSlovenianScreen = makeDisplayFrame(arrayOf( + "████ ███ ███ █ █████ █ █ ███ ███ ████ ███ █ █ █ ████ █ █ ", + "█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + "█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + "████ █ █ █ █ █████ █ ██ █ █ █ ████ █ █ █ █ █ ███ █ █ ", + "█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + "█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + "█ ███ ███ █ █ █ █ █ ███ ███ ████ ███ █████ ███ ████ ███ ", + " ", + "███ █████ ███ █ █ ███ █ █████ ███ ", + "█ █ █ █ █ █ █ █ █ ██ █ █ █ █ ", + "█ █ █ █ █ █ █ ██ █ █ █ █ ██ ", + "█ ██████ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + "█ █ █ █ █ █ ██ █ █ █ █ ██ █ ", + "█ █ █ █ ██ █ █ █ █ █ █ █ █ █ █ █ ", + "█ █ ███ ██ █████ ███ ███ ███ ███ ███ ", + " ", + " █ ███ ███ █ █████ ", + " ██ █ █ █ █ ██ ██ █ ", + "███████ █ ██ █ ██ ██ █ █ █ ", + "████████ █ █ █ █ █ █ █ █ █ ", + "███████ ██ █ ██ █ ██ █████ █ ", + " ██ █ █ █ █ ██ █ █ █ ", + " █ ███ ███ █ ███ ", + " ", + " ███ ███ █████ ███ █ ███████ ███ █ ███ █ ", + " █ █ █ █ █ █ ██ █ █ ██ █ █ █ █ ██ █ █ ██ ", + "█ █ █ █ █ ██ █ █ ███████ █ ██ █ █ ██ █ ", + "█ ██ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + "█ █ █ █ ██ █ █ ███████ ██ █ █ ██ █ █ ", + " █ █ █ █ █ ██ █ █ █ █ ███ █ █ █ ██ █ █ █ ", + " ███ █████ ███ █████ ███ ███████ ███ ███ ██ ███ ███ ", + " " +)) + object AlertSnoozeAndConfirmScreens { val testAlertScreenSnoozeTextEnglishScreen = makeDisplayFrame( @@ -11195,4 +11666,74 @@ object AlertSnoozeAndConfirmScreens { ) ) + val testAlertScreenSnoozeTextSlovenianScreen = makeDisplayFrame(arrayOf( + "████ ████ █████ █ █ █ ███ ███ █████ ████ ███ ", + "█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + "█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + "████ ████ ████ ██ █ █ █ █ ████ █ █ ", + "█ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + "█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + "█ █ █ █████ █ █ █████ ███ ███ █████ ████ ███ ", + " ", + " ██ ██ ██ ███ ", + " ████ ██ ██ ██ ", + " █ █ ██ ██ ██ ", + " ██ ██ ██ ██ ██ ", + " █ █ ██ ██ ██ ██ ", + " ██ ██ ██ ██ ██ ██ ██ ", + " █ ██ █ ██ ██ ██ ██████ ", + " ██ ██ ██ ██ ██ ██ ███ ██ ", + " █ ██ █ ██ ██ ██ ██ ██ ", + " ██ ██ ██ ██ ██ ██ ██ ██ ", + " █ █ ██ ██ ██ ██ ██ ", + " ██ ██ ██ ██ ████ ██ ██ ██ ", + " █ █ ██████████ ██ ██ ", + " ████████████████ ███ ███ ██ ██ ", + " ███████████████ █ █ ████ ", + " ", + " ", + " █ █ █ █████ ███ █ █ █ █ █ ███ █████ ", + " ██ █ █ █ █ █ █ █ █ █ █ █ ", + "█ ██ █ █ █ █ ████ █ █ ██ █ █ █ ", + "███ █ █ █ █ █ █████ █ █ █ █ ████ ", + " █ █ █ █ █ ███ █ █ █ ██ █ █ ", + " █ █ █ █ █ █ █ █ █ █ █ █ ", + " ███ █ ███ ████ █ █ █ █ ██ █████ " + )) + + val testAlertScreenConfirmTextSlovenianScreen = makeDisplayFrame(arrayOf( + "████ ████ █████ █ █ █ ███ ███ █████ ████ ███ ", + "█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + "█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + "████ ████ ████ ██ █ █ █ █ ████ █ █ ", + "█ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + "█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + "█ █ █ █████ █ █ █████ ███ ███ █████ ████ ███ ", + " ", + " ██ ██ ██ ███ ", + " ████ ██ ██ ██ ", + " █ █ ██ ██ ██ ", + " ██ ██ ██ ██ ██ ", + " █ █ ██ ██ ██ ██ ", + " ██ ██ ██ ██ ██ ██ ██ ", + " █ ██ █ ██ ██ ██ ██████ ", + " ██ ██ ██ ██ ██ ██ ███ ██ ", + " █ ██ █ ██ ██ ██ ██ ██ ", + " ██ ██ ██ ██ ██ ██ ██ ██ ", + " █ █ ██ ██ ██ ██ ██ ", + " ██ ██ ██ ██ ████ ██ ██ ██ ", + " █ █ ██████████ ██ ██ ", + " ████████████████ ███ ███ ██ ██ ", + " ███████████████ █ █ ████ ", + " ", + " ", + " █ ████ ███ █████ ████ ███ ███ █████ █████ █ █ ", + " ██ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + "█ ██ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + "███ ████ █ █ █ ████ █ █ █ █ ████ █ █ ", + " █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + " █ █ █ █ █ █ █ █ █ █ █ █ █ ", + " █ ███ █ █ █ ███ ███ █ █████ █ " + )) + } \ No newline at end of file From 3f3884e5138a274c5fffa69cb8c0b8642ce0cf9f Mon Sep 17 00:00:00 2001 From: Carlos Rafael Giani Date: Wed, 8 Mar 2023 20:41:45 +0100 Subject: [PATCH 07/17] comboctl-parser: Handle percent symbol in some TBR percentage screens Some TBR percentage screens like the Lithuanian one show a % symbol right after the text. Add an optional symbol parser to handle it. Signed-off-by: Carlos Rafael Giani --- .../commonMain/kotlin/info/nightscout/comboctl/parser/Parser.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/pump/combov2/comboctl/src/commonMain/kotlin/info/nightscout/comboctl/parser/Parser.kt b/pump/combov2/comboctl/src/commonMain/kotlin/info/nightscout/comboctl/parser/Parser.kt index c3bead098c..2c2d7be005 100644 --- a/pump/combov2/comboctl/src/commonMain/kotlin/info/nightscout/comboctl/parser/Parser.kt +++ b/pump/combov2/comboctl/src/commonMain/kotlin/info/nightscout/comboctl/parser/Parser.kt @@ -1240,6 +1240,7 @@ class TemporaryBasalRatePercentageScreenParser : Parser() { override fun parseImpl(parseContext: ParseContext): ParseResult { val parseResult = SequenceParser( listOf( + OptionalParser(SingleGlyphParser(Glyph.SmallSymbol(SmallSymbol.PERCENT))), SingleGlyphParser(Glyph.LargeSymbol(LargeSymbol.BASAL)), OptionalParser(IntegerParser()), // TBR percentage SingleGlyphParser(Glyph.LargeSymbol(LargeSymbol.PERCENT)), From 2cdc4c45ea4bc9603988c8726db27b5b31b4d6fe Mon Sep 17 00:00:00 2001 From: Carlos Rafael Giani Date: Wed, 8 Mar 2023 20:46:46 +0100 Subject: [PATCH 08/17] comboctl-parser: Add Lithuanian support Signed-off-by: Carlos Rafael Giani --- .../nightscout/comboctl/parser/Pattern.kt | 9 + .../comboctl/parser/TitleStrings.kt | 16 + .../nightscout/comboctl/parser/ParserTest.kt | 49 +- .../comboctl/parser/TestDisplayFrames.kt | 455 ++++++++++++++++++ 4 files changed, 528 insertions(+), 1 deletion(-) diff --git a/pump/combov2/comboctl/src/commonMain/kotlin/info/nightscout/comboctl/parser/Pattern.kt b/pump/combov2/comboctl/src/commonMain/kotlin/info/nightscout/comboctl/parser/Pattern.kt index dba6ec1f14..c84103c3c9 100644 --- a/pump/combov2/comboctl/src/commonMain/kotlin/info/nightscout/comboctl/parser/Pattern.kt +++ b/pump/combov2/comboctl/src/commonMain/kotlin/info/nightscout/comboctl/parser/Pattern.kt @@ -1414,6 +1414,15 @@ val glyphPatterns = mapOf( "█ ", "█████" )), + Glyph.SmallCharacter('Ė') to Pattern(arrayOf( + " █ ", + " ", + "█████", + "█ ", + "████ ", + "█ ", + "█████" + )), Glyph.SmallCharacter('ę') to Pattern(arrayOf( "█████", "█ ", diff --git a/pump/combov2/comboctl/src/commonMain/kotlin/info/nightscout/comboctl/parser/TitleStrings.kt b/pump/combov2/comboctl/src/commonMain/kotlin/info/nightscout/comboctl/parser/TitleStrings.kt index 6b8944b5e3..fcd06ffe94 100644 --- a/pump/combov2/comboctl/src/commonMain/kotlin/info/nightscout/comboctl/parser/TitleStrings.kt +++ b/pump/combov2/comboctl/src/commonMain/kotlin/info/nightscout/comboctl/parser/TitleStrings.kt @@ -372,6 +372,22 @@ val knownScreenTitles = mapOf( "UTIŠANJE" to TitleID.ALERT_TO_SNOOZE, "POTRDITEV" to TitleID.ALERT_TO_CONFIRM, + // Lithuanian + "QUICK INFO" to TitleID.QUICK_INFO, + "TBR REIKŠMĖS" to TitleID.TBR_PERCENTAGE, + "TBR TRUKMĖ" to TitleID.TBR_DURATION, + "VALANDA" to TitleID.HOUR, + "MINUTĖ" to TitleID.MINUTE, + "METAI" to TitleID.YEAR, + "MĖNUO" to TitleID.MONTH, + "DIENA" to TitleID.DAY, + "BOLIUSO DUOMENYS" to TitleID.BOLUS_DATA, + "KLAIDOS DUOMENYS" to TitleID.ERROR_DATA, + "BENDR. DIENOS K." to TitleID.DAILY_TOTALS, + "TBR DUOMENYS" to TitleID.TBR_DATA, + "NUTILDYTI" to TitleID.ALERT_TO_SNOOZE, + "PATVIRTINTI" to TitleID.ALERT_TO_CONFIRM, + // Some pumps came preconfigured with a different quick info name "ACCU CHECK SPIRIT" to TitleID.QUICK_INFO ) diff --git a/pump/combov2/comboctl/src/jvmTest/kotlin/info/nightscout/comboctl/parser/ParserTest.kt b/pump/combov2/comboctl/src/jvmTest/kotlin/info/nightscout/comboctl/parser/ParserTest.kt index e31f78cdf8..03421aec21 100644 --- a/pump/combov2/comboctl/src/jvmTest/kotlin/info/nightscout/comboctl/parser/ParserTest.kt +++ b/pump/combov2/comboctl/src/jvmTest/kotlin/info/nightscout/comboctl/parser/ParserTest.kt @@ -743,6 +743,7 @@ class ParserTest { Pair(TbrPercentageAndDurationScreens.testFrameTbrPercentageDanishScreen, 110), Pair(TbrPercentageAndDurationScreens.testFrameTbrPercentageGermanScreen, 110), Pair(TbrPercentageAndDurationScreens.testFrameTbrPercentageSlovenianScreen, 110), + Pair(TbrPercentageAndDurationScreens.testFrameTbrPercentageLithuanianScreen, 110), ) for (testScreen in testScreens) { @@ -790,7 +791,8 @@ class ParserTest { Pair(TbrPercentageAndDurationScreens.testFrameTbrDurationSwedishScreen, 30), Pair(TbrPercentageAndDurationScreens.testFrameTbrDurationDanishScreen, 30), Pair(TbrPercentageAndDurationScreens.testFrameTbrDurationGermanScreen, 30), - Pair(TbrPercentageAndDurationScreens.testFrameTbrDurationSlovenianScreen, 15) + Pair(TbrPercentageAndDurationScreens.testFrameTbrDurationSlovenianScreen, 15), + Pair(TbrPercentageAndDurationScreens.testFrameTbrDurationLithuanianScreen, 15), ) for (testScreen in testScreens) { @@ -935,6 +937,12 @@ class ParserTest { Pair(testTimeAndDateSettingsMonthSlovenianScreen, ParsedScreen.TimeAndDateSettingsMonthScreen(3)), Pair(testTimeAndDateSettingsDaySlovenianScreen, ParsedScreen.TimeAndDateSettingsDayScreen(8)), + Pair(testTimeAndDateSettingsHourLithuanianScreen, ParsedScreen.TimeAndDateSettingsHourScreen(20)), + Pair(testTimeAndDateSettingsMinuteLithuanianScreen, ParsedScreen.TimeAndDateSettingsMinuteScreen(16)), + Pair(testTimeAndDateSettingsYearLithuanianScreen, ParsedScreen.TimeAndDateSettingsYearScreen(2023)), + Pair(testTimeAndDateSettingsMonthLithuanianScreen, ParsedScreen.TimeAndDateSettingsMonthScreen(3)), + Pair(testTimeAndDateSettingsDayLithuanianScreen, ParsedScreen.TimeAndDateSettingsDayScreen(8)), + // Extra test to verify that a *minute* 24 is not incorrectly interpreted // as an *hour* 24 and thus translated to 0 (this is done because the Combo // may show midnight as both hour 0 and hour 24). @@ -1609,6 +1617,37 @@ class ParserTest { percentage = 110, durationInMinutes = 1 ) ), + Pair( + testMyDataBolusDataLithuanianScreen, + ParsedScreen.MyDataBolusDataScreen( + index = 1, totalNumEntries = 30, + timestamp = LocalDateTime(year = 0, monthNumber = 1, dayOfMonth = 1, hour = 23, minute = 21, second = 0), + bolusAmount = 3200, bolusType = MyDataBolusType.MULTI_WAVE, durationInMinutes = 43 + ) + ), + Pair( + testMyDataErrorDataLithuanianScreen, + ParsedScreen.MyDataErrorDataScreen( + index = 1, totalNumEntries = 30, + timestamp = LocalDateTime(year = 0, monthNumber = 3, dayOfMonth = 8, hour = 20, minute = 6, second = 0), + alert = AlertScreenContent.Warning(6, AlertScreenContent.AlertScreenState.HISTORY_ENTRY) + ) + ), + Pair( + testMyDataDailyTotalsLithuanianScreen, + ParsedScreen.MyDataDailyTotalsScreen( + index = 1, totalNumEntries = 30, date = LocalDate(year = 0, dayOfMonth = 8, monthNumber = 3), + totalDailyAmount = 33600 + ) + ), + Pair( + testMyDataTbrDataLithuanianScreen, + ParsedScreen.MyDataTbrDataScreen( + index = 1, totalNumEntries = 30, + timestamp = LocalDateTime(year = 0, monthNumber = 3, dayOfMonth = 8, hour = 20, minute = 6, second = 0), + percentage = 110, durationInMinutes = 1 + ) + ), ) for (testScreen in testScreens) { @@ -1805,6 +1844,14 @@ class ParserTest { AlertSnoozeAndConfirmScreens.testAlertScreenConfirmTextSlovenianScreen, AlertScreenContent.Warning(6, AlertScreenContent.AlertScreenState.TO_CONFIRM) ), + Pair( + AlertSnoozeAndConfirmScreens.testAlertScreenSnoozeTextLithuanianScreen, + AlertScreenContent.Warning(6, AlertScreenContent.AlertScreenState.TO_SNOOZE) + ), + Pair( + AlertSnoozeAndConfirmScreens.testAlertScreenConfirmTextLithuanianScreen, + AlertScreenContent.Warning(6, AlertScreenContent.AlertScreenState.TO_CONFIRM) + ), ) for (testScreen in testScreens) { diff --git a/pump/combov2/comboctl/src/jvmTest/kotlin/info/nightscout/comboctl/parser/TestDisplayFrames.kt b/pump/combov2/comboctl/src/jvmTest/kotlin/info/nightscout/comboctl/parser/TestDisplayFrames.kt index 3787c25fd0..0830f7b08b 100644 --- a/pump/combov2/comboctl/src/jvmTest/kotlin/info/nightscout/comboctl/parser/TestDisplayFrames.kt +++ b/pump/combov2/comboctl/src/jvmTest/kotlin/info/nightscout/comboctl/parser/TestDisplayFrames.kt @@ -3392,6 +3392,77 @@ object TbrPercentageAndDurationScreens { " " ) ) + + val testFrameTbrPercentageLithuanianScreen = makeDisplayFrame(arrayOf( + "█████ ████ ████ ████ █████ ███ █ █ █ █ █ █ █ ████ ██ ", + " █ █ █ █ █ █ █ █ █ █ █ █ ██ ██ █ ██ █ ", + " █ █ █ █ █ █ █ █ █ █ █ ████ █ █ █ █████ █ █ ", + " █ ████ ████ ████ ████ █ ██ █ █ █ █ █ ███ █ ", + " █ █ █ █ █ █ █ █ █ █ █ ███ █ █ ████ █ █ ", + " █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ██ ", + " █ ████ █ █ █ █ █████ ███ █ █ ████ █ █ █████ ████ ██ ", + " ", + " ██ ██ ████ ██ ██ ", + " ███████ ███ ███ ██ ██ ████ ██ ", + " ███████ ████ ████ ██ ██ ████ ██ ", + " ██ ██ ██ ██ ██ ██ ██ ██ ", + " ██ ███████ ██ ██ ██ ██ ██ ", + " ██ ███████ ██ ██ ██ ██ ██ ", + "███████ ██ ██ ██ ██ ██ ██ ██ ", + "███████ ██ ██ ██ ██ ██ ██ ██ ", + "██ ██ ██ ██ ██ ██ ██ ██ ██ ", + "██ ██ ██ ██ ██ ██ ██ ██ ██ ", + "██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ", + "██ ██ ██ ██ ██ ██ ██ ██ ██ ████ ", + "██ ██ ██ ██ ██ ██ ██ ██ ██ ████ ", + "██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ", + "██ ██ ██ ██ ██ ██ ████ ", + " ", + " █ ███ ███ █ █████ ", + " ██ █ █ █ █ ██ ██ █ ", + "███████ █ ██ █ ██ ██ █ ████ ", + "████████ █ █ █ █ █ █ █ █ ", + "███████ ██ █ ██ █ ██ █ █ ", + " ██ █ █ █ █ ██ █ █ █ ", + " █ ███ ███ ███ ███ ", + " " + )) + + val testFrameTbrDurationLithuanianScreen = makeDisplayFrame(arrayOf( + "█████ ████ ████ █████ ████ █ █ █ █ █ █ █ ", + " █ █ █ █ █ █ █ █ █ █ █ █ ██ ██ ", + " █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █████ ", + " █ ████ ████ █ ████ █ █ ██ █ █ █ █ ", + " █ █ █ █ █ █ █ █ █ █ █ █ █ █ ████ ", + " █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + " █ ████ █ █ █ █ █ ███ █ █ █ █ █████ ", + " ", + " ████ ████ ██ ███████ ", + " ██ ██ ██ ██ ██ ███ ██ ", + " ███ ██ ██ ██ ██ ████ ██ ", + " ████ ██ ██ ██ ██ ██ ██ ", + " █████ ██ ██ ██ ██ ██ ██ ", + " ██████ ██ ██ ██ ██ ███ ██ ██████ ", + "███████████████ ██ ██ ██ ██ ███ ██ ██ ", + "████████████████ ██ ██ ██ ██ ███ ██ ██ ", + "████████████████ ██ ██ ██ ██ ██ ██ ", + "███████████████ ██ ██ ██ ██ ██ ██ ", + " ██████ ██ ██ ██ ██ ███ ██ ██ ", + " █████ ██ ██ ██ ██ ███ ██ ██ ", + " ████ ██ ██ ██ ██ ███ ██ ██ ", + " ███ ██ ██ ██ ██ ██ ██ ██ ", + " ██ ████ ████ ██ █████ ", + " ", + " ████ █ █ ███ ██ ", + " █ ███ ██ ██ █ █ ██ █ ", + "███ █ █ █ █ █ ██ █ ", + "█ █ █ █ █ █ █ █ █ █ ", + "█ █ █ █ █ █ ██ █ █ ", + "█ █ █ █ █ █ █ █ █ ██ ", + "█ █ █ █ ███ ███ ███ ██ ", + " " + )) + } val testTimeAndDateSettingsHour12hFormatScreen = makeDisplayFrame(arrayOf( @@ -7139,6 +7210,181 @@ val testTimeAndDateSettingsDaySlovenianScreen = makeDisplayFrame(arrayOf( " " )) +val testTimeAndDateSettingsHourLithuanianScreen = makeDisplayFrame(arrayOf( + "█ █ █ █ █ █ █ ███ █ ", + "█ █ █ █ █ █ █ █ █ █ █ █ █ ", + "█ █ █ █ █ █ █ ██ █ █ █ █ █ ", + "█ █ █████ █ █████ █ █ █ █ █ █████ ", + "█ █ █ █ █ █ █ █ ██ █ █ █ █ ", + " █ █ █ █ █ █ █ █ █ █ █ █ █ ", + " █ █ █ █████ █ █ █ █ ███ █ █ ", + " ", + " ████ ████ ", + " █████ ██ ██ ██ ██ ", + " ██ ██ ██ ██ ██ ██ ", + " █ █ █ ██ ██ ██ ██ ", + " █ █ ██ ██ ██ ██ ", + "█ █ █ ██ ██ ██ ", + "█ █ ██ ██ ██ ██ ", + "█ ████ ██ ██ ██ ██ ", + "█ ██ ██ ██ ██ ", + "█ ██ ██ ██ ██ ", + " █ ███ ██ ██ ██ ", + " █ ██ ██ ██ ██ ", + " ██ ████ ██ ██ ██ ", + " █████████ ██ ██ ██ ", + " █████ ████████ ████ ", + " ", + " ███ ███ █ ██ ███ ███ ███ █████ ███ █████", + "█ █ █ █ ██ ██ █ █ █ █ █ █ █ █ █ █ █ ", + " █ █ ██ ██ █ █ █ ██ █ █ █ ██ █ █ █ ", + " █ █ █ █ █ ████ █ █ █ ███ █ █ █ █ █ █ ", + " █ ██ █ ██ █ █ █ ██ █ █ █ ██ █ █ █ █", + " █ █ █ ██ █ █ █ █ █ █ █ ██ █ █ █ █ ██ █ █ █", + "█████ ███ ███ ███ ███ ███ ██ ███ ███ ██ █████ ███ ", + " " +)) + +val testTimeAndDateSettingsMinuteLithuanianScreen = makeDisplayFrame(arrayOf( + "█ █ ███ █ █ █ █ █████ █ ", + "██ ██ █ █ █ █ █ █ ", + "█ █ █ █ ██ █ █ █ █ █████ ", + "█ █ █ █ █ █ █ █ █ █ █ ", + "█ █ █ █ ██ █ █ █ ████ ", + "█ █ █ █ █ █ █ █ █ ", + "█ █ ███ █ █ ███ █ █████ ", + " ", + " ██ ███ ", + " █████ ███ ██ ", + " ██ ██ ████ ██ ", + " █ █ █ ██ ██ ", + " █ █ ██ ██ ██ ", + "█ █ █ ██ ██ ", + "█ █ ██ ██ ██████ ", + "█ ████ ██ ██ ███ ██ ", + "█ ██ ██ ██ ██ ", + "█ ██ ██ ██ ██ ", + " █ ███ ██ ██ ██ ", + " █ ██ ██ ██ ██ ", + " ██ ████ ██ ██ ██ ", + " █████████ ██ ██ ██ ", + " █████ ██ ████ ", + " ", + " ███ ███ █ ██ ███ ███ ███ █████ ███ █████", + "█ █ █ █ ██ ██ █ █ █ █ █ █ █ █ █ █ █ ", + " █ █ ██ ██ █ █ █ ██ █ █ █ ██ █ █ █ ", + " █ █ █ █ █ ████ █ █ █ ███ █ █ █ █ █ █ ", + " █ ██ █ ██ █ █ █ ██ █ █ █ ██ █ █ █ █", + " █ █ █ ██ █ █ █ █ █ █ █ ██ █ █ █ █ ██ █ █ █", + "█████ ███ ███ ███ ███ ███ ██ ███ ███ ██ █████ ███ ", + " " +)) + +val testTimeAndDateSettingsYearLithuanianScreen = makeDisplayFrame(arrayOf( + "█ █ █████ █████ █ ███ ", + "██ ██ █ █ █ █ █ ", + "█ █ █ █ █ █ █ █ ", + "█ █ █ ████ █ █████ █ ", + "█ █ █ █ █ █ █ ", + "█ █ █ █ █ █ █ ", + "█ █ █████ █ █ █ ███ ", + " ", + " ████ ████ ████ █████ ", + "█████████████ ██ ██ ██ ██ ██ ██ ██ ██ ", + "█ ██ ██ ██ ██ ██ ██ ██ ██ ", + "██████████████ ██ ██ ██ ██ ██ ██ ██ ", + "█ █ █ █ █ █ ██ ██ ██ ██ ██ ██ ", + "██████████████ ██ ██ ██ ██ ██ ", + "█ █ █ █ █ █ ██ ██ ██ ██ ██ ███ ", + "██████████████ ██ ██ ██ ██ ██ ", + "█ █ █ █ █ █ ██ ██ ██ ██ ██ ██ ", + "██████████████ ██ ██ ██ ██ ██ ", + "█ █ █ █ ██████ ██ ██ ██ ██ ██ ", + "██████████████ ██ ██ ██ ██ ██ ", + " █████████████ ██ ██ ██ ██ ██ ", + " ██ ██ ██ ██ ██ ██ ", + " ████████ ████ ████████ █████ ", + " ", + " ███ ███ █ ██ ███ ███ ███ █████ ███ █████", + "█ █ █ █ ██ ██ █ █ █ █ █ █ █ █ █ █ █ ", + " █ █ ██ ██ █ █ █ ██ █ █ █ ██ █ █ █ ", + " █ █ █ █ █ ████ █ █ █ ███ █ █ █ █ █ █ ", + " █ ██ █ ██ █ █ █ ██ █ █ █ ██ █ █ █ █", + " █ █ █ ██ █ █ █ █ █ █ █ ██ █ █ █ █ ██ █ █ █", + "█████ ███ ███ ███ ███ ███ ██ ███ ███ ██ █████ ███ ", + " " +)) + +val testTimeAndDateSettingsMonthLithuanianScreen = makeDisplayFrame(arrayOf( + "█ █ █ █ █ █ █ ███ ", + "██ ██ █ █ █ █ █ █ ", + "█ █ █ █████ ██ █ █ █ █ █ ", + "█ █ █ █ █ █ █ █ █ █ █ ", + "█ █ ████ █ ██ █ █ █ █ ", + "█ █ █ █ █ █ █ █ █ ", + "█ █ █████ █ █ ███ ███ ", + " ", + " █████ ", + "█████████████ ██ ██ ", + "█ ██ ██ ", + "██████████████ ██ ", + "█ █ █ █ █ █ ██ ██ ", + "██████████████ ██ ", + "█ █ █ █ █ █ ██ ███ ", + "██████████████ ██ ", + "█ █ █ █ █ █ ██ ██ ", + "██████████████ ██ ", + "█ █ █ █ ██████ ██ ", + "██████████████ ██ ", + " █████████████ ██ ", + " ██ ██ ", + " █████ ", + " ", + " ███ ███ █ ██ ███ ███ ███ █████ ███ █████", + "█ █ █ █ ██ ██ █ █ █ █ █ █ █ █ █ █ █ ", + " █ █ ██ ██ █ █ █ ██ █ █ █ ██ █ █ █ ", + " █ █ █ █ █ ████ █ █ █ ███ █ █ █ █ █ █ ", + " █ ██ █ ██ █ █ █ ██ █ █ █ ██ █ █ █ █", + " █ █ █ ██ █ █ █ █ █ █ █ ██ █ █ █ █ ██ █ █ █", + "█████ ███ ███ ███ ███ ███ ██ ███ ███ ██ █████ ███ ", + " " +)) + +val testTimeAndDateSettingsDayLithuanianScreen = makeDisplayFrame(arrayOf( + "███ ███ █████ █ █ █ ", + "█ █ █ █ █ █ █ █ ", + "█ █ █ █ ██ █ █ █ ", + "█ █ █ ████ █ █ █ █████ ", + "█ █ █ █ █ ██ █ █ ", + "█ █ █ █ █ █ █ █ ", + "███ ███ █████ █ █ █ █ ", + " ", + " ████ ", + "█████████████ ██ ██ ", + "█ ██ ██ ██ ", + "██████████████ ██ ██ ", + "█ █ █ █ █ █ ██ ██ ██ ", + "██████████████ ██ ██ ", + "█ █ █ █ █ █ ██ ████ ", + "██████████████ ██ ██ ", + "█ █ █ █ █ █ ██ ██ ██ ", + "██████████████ ██ ██ ", + "█ █ █ █ ██████ ██ ██ ", + "██████████████ ██ ██ ", + " █████████████ ██ ██ ", + " ██ ██ ", + " ████ ", + " ", + " ███ ███ █ ██ ███ ███ ███ █████ ███ █████", + "█ █ █ █ ██ ██ █ █ █ █ █ █ █ █ █ █ █ ", + " █ █ ██ ██ █ █ █ ██ █ █ █ ██ █ █ █ ", + " █ █ █ █ █ ████ █ █ █ ███ █ █ █ █ █ █ ", + " █ ██ █ ██ █ █ █ ██ █ █ █ ██ █ █ █ █", + " █ █ █ ██ █ █ █ █ █ █ █ ██ █ █ █ █ ██ █ █ █", + "█████ ███ ███ ███ ███ ███ ██ ███ ███ ██ █████ ███ ", + " " +)) + val testUSDateFormatScreen = makeDisplayFrame(arrayOf( "███ █ █████ █ █ █ █ ████ █████ ███ ████ █ █ █ █████ ", "█ █ █ █ █ █ █ ██ ██ █ █ █ █ █ █ ██ ██ █ █ █ ", @@ -10184,6 +10430,146 @@ val testMyDataBolusDataSlovenianScreen = makeDisplayFrame(arrayOf( " " )) +val testMyDataTbrDataLithuanianScreen = makeDisplayFrame(arrayOf( + "█████ ████ ████ ███ █ █ ███ █ █ █████ █ █ █ █ ████ ", + " █ █ █ █ █ █ █ █ █ █ █ ██ ██ █ █ █ █ █ █ ", + " █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ██ █ █ █ █ ", + " █ ████ ████ █ █ █ █ █ █ █ █ █ ████ █ █ █ █ █ ███ ", + " █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ██ █ █ ", + " █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + " █ ████ █ █ ███ ███ ███ █ █ █████ █ █ █ ████ ", + " ", + " █ █ █ ███ ██ ███ █ █████ ███ ", + " ███ ██ ██ █ █ ██ █ █ █ ██ █ █ █ █ ", + " █████ █ █ █ ██ █ █ ██ █ █ █ █ ██ ", + "███████ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + " ███ █ █ ██ █ █ ██ █ █ █ █ ██ █ ", + " ███ █ █ █ █ █ ██ █ █ █ █ █ █ █ █ ", + " ███ ███ ███ ███ ██ ███ ███ ███ ███ ", + " ", + " █ ███ ███ ███ █ ", + " ██ █ █ █ █ ██ █ █ ██ ", + "███████ █ ██ █ ██ ██ █ ██ █ ", + "████████ █ █ █ █ █ █ █ █ █ █ ", + "███████ ██ █ ██ █ ██ ██ █ █ ", + " ██ █ █ █ █ ██ █ █ █ ", + " █ ███ ███ ███ ███ ", + " ", + " ███ ███ ███ ███ ██ ███████ ███ ███ ███ █████ ", + " █ █ █ █ █ █ █ ██ █ █ █ █ █ █ █ █ █ █ █ █ ", + "█ █ █ █ █ ██ ██ █ ██ █ ███████ █ ██ █ █ █ ██ █ ", + "█ ██ █ █ █ █ █ █ █ █ ████ █ █ █ █ █ █ █ ███ █ █ █ █ ", + "█ █ █ ██ █ ██ ██ █ █ █ ███████ ██ █ █ █ ██ █ █ ", + " █ █ █ █ █ ██ █ █ █ █ █ █ ███ █ █ █ █ ██ █ █ █ █ ", + " ███ █████ ███ ███ ███ ███████ ███ ███ ██ ███ ███ ", + " " +)) + +val testMyDataErrorDataLithuanianScreen = makeDisplayFrame(arrayOf( + "█ █ █ █ ███ ███ ███ ████ ███ █ █ ███ █ █ █████ █ █ █ █ ████ ", + "█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ██ ██ █ █ █ █ █ █ ", + "█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ██ █ █ █ █ ", + "██ █ █████ █ █ █ █ █ ███ █ █ █ █ █ █ █ █ █ ████ █ █ █ █ █ ███ ", + "█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ██ █ █ ", + "█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + "█ █ █████ █ █ ███ ███ ███ ████ ███ ███ ███ █ █ █████ █ █ █ ████ ", + " ", + " █ █ █ ██ ███ █ █████ ███ ", + " ███ █ █ █ █ █ ██ █ █ █ █ ", + " █ █ █ █ █ █ ██ █ █ █ █ ██ ", + " █ █ █ █ █ █ ████ █ █ █ █ █ █ █ █ █ ", + " █ █ █ █ █ █ █ ██ █ █ █ █ ██ █ ", + "█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + "███████ █ █ ███ ███ ███ ███ ███ ", + " ", + "█████ ████ ████ █ █████ █ █ █ █ █ █ █ █████ █ ████ ", + " █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + " █ █ █ █ █ █ █ █ ████ █ █ █ █ █ █ █ █ █ █ ", + " █ ████ ████ █████ █ █ █████ █ █ ██ █ █████ ███ ", + " █ █ █ █ █ █ █ █ ███ █ █ █ █ █ █ █ █ █ █ ", + " █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + " █ ████ █ █ █ █ █ ████ █ █ ███ █ █ █ █ █ ████ ", + " ", + " ███ ███ ███ ███ ██ ███████ ███ ███ ███ █████ ", + " █ █ █ █ █ █ █ ██ █ █ █ █ █ █ █ █ █ █ █ █ ", + "█ █ █ █ █ ██ ██ █ ██ █ ███████ █ ██ █ █ █ ██ █ ", + "█ ██ █ █ █ █ █ █ █ █ ████ █ █ █ █ █ █ █ ███ █ █ █ █ ", + "█ █ █ ██ █ ██ ██ █ █ █ ███████ ██ █ █ █ ██ █ █ ", + " █ █ █ █ █ ██ █ █ █ █ █ █ ███ █ █ █ █ ██ █ █ █ █ ", + " ███ █████ ███ ███ ███ ███████ ███ ███ ██ ███ ███ ", + " " +)) + +val testMyDataDailyTotalsLithuanianScreen = makeDisplayFrame(arrayOf( + "████ █████ █ █ ███ ████ ███ ███ █████ █ █ ███ ████ █ █ ", + "█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + "█ █ █ ██ █ █ █ █ █ █ █ █ █ ██ █ █ █ █ █ █ ", + "████ ████ █ █ █ █ █ ████ █ █ █ ████ █ █ █ █ █ ███ ██ ", + "█ █ █ █ ██ █ █ █ █ █ █ █ █ █ ██ █ █ █ █ █ ", + "█ █ █ █ █ █ █ █ █ ██ █ █ █ █ █ █ █ █ █ █ █ ██ ", + "████ █████ █ █ ███ █ █ ██ ███ ███ █████ █ █ ███ ████ █ █ ██ ", + " ", + " ███ █ █████ ███ ", + " █ █ ██ █ █ █ █ ", + " █ ██ █ █ █ █ ██ ", + " █ █ █ █ █ █ █ █ █ ", + " ██ █ █ █ █ ██ █ ", + " █ █ █ █ █ █ █ █ ", + " ███ ███ ███ ███ ", + " ", + "██████ █████ █████ ██ █ █ ", + "█ █ █ █ █ █ █ ", + " █ █ █ █ █ █ ", + " █ █ █ ████ █ █ ", + " █ █ █ █ █ █ █ ", + "█ █ █ █ █ █ ██ █ █ █ █ ", + "██████ ███ ███ ██ ███ ███ ", + " ", + " ███████ ███ ███ ███ █████ ", + " █ █ █ █ █ █ █ █ █ ", + " ███████ █ ██ █ █ █ ██ █ ", + " █ █ █ █ █ █ █ ███ █ █ █ █ ", + " ███████ ██ █ █ █ ██ █ █ ", + " █ █ ███ █ █ █ █ ██ █ █ █ █ ", + " ███████ ███ ███ ██ ███ ███ ", + " " +)) + +val testMyDataBolusDataLithuanianScreen = makeDisplayFrame(arrayOf( + "████ ███ █ ███ █ █ ████ ███ ███ █ █ ███ █ █ █████ █ █ █ █ ████ ", + "█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ██ ██ █ █ █ █ █ █ ", + "█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ██ █ █ █ █ ", + "████ █ █ █ █ █ █ ███ █ █ █ █ █ █ █ █ █ █ █ ████ █ █ █ █ █ ███ ", + "█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ██ █ █ ", + "█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + "████ ███ █████ ███ ███ ████ ███ ███ ███ ███ █ █ █████ █ █ █ ████ ", + " ", + "███ █████ ███ █ █ ███ █ █████ ███ ", + "█ █ █ █ █ █ █ █ █ ██ █ █ █ █ ", + "█ █ █ █ █ █ █ ██ █ █ █ █ ██ ", + "█ ██████ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + "█ █ █ █ █ █ ██ █ █ █ █ ██ █ ", + "█ █ █ █ ██ █ █ █ █ █ █ █ █ █ █ █ ", + "█ █ ███ ██ █████ ███ ███ ███ ███ ███ ", + " ", + " █ ███ ███ █ █████ ", + " ██ █ █ █ █ ██ ██ █ ", + "███████ █ ██ █ ██ ██ █ █ █ ", + "████████ █ █ █ █ █ █ █ █ █ ", + "███████ ██ █ ██ █ ██ █████ █ ", + " ██ █ █ █ █ ██ █ █ █ ", + " █ ███ ███ █ ███ ", + " ", + " ███ ███ █████ ███ █ ███████ ███ █ ███ █ ", + " █ █ █ █ █ █ ██ █ █ ██ █ █ █ █ ██ █ █ ██ ", + "█ █ █ █ █ ██ █ █ ███████ █ ██ █ █ ██ █ ", + "█ ██ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + "█ █ █ █ ██ █ █ ███████ ██ █ █ ██ █ █ ", + " █ █ █ █ █ ██ █ █ █ █ ███ █ █ █ ██ █ █ █ ", + " ███ █████ ███ █████ ███ ███████ ███ ███ ██ ███ ███ ", + " " +)) + object AlertSnoozeAndConfirmScreens { val testAlertScreenSnoozeTextEnglishScreen = makeDisplayFrame( @@ -11736,4 +12122,73 @@ object AlertSnoozeAndConfirmScreens { " █ ███ █ █ █ ███ ███ █ █████ █ " )) + val testAlertScreenSnoozeTextLithuanianScreen = makeDisplayFrame(arrayOf( + "█████ ████ ████ █ █████ █ █ █ █ █ █ █ █████ █ ████ ", + " █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + " █ █ █ █ █ █ █ █ ████ █ █ █ █ █ █ █ █ █ █ ", + " █ ████ ████ █████ █ █ █████ █ █ ██ █ █████ ███ ", + " █ █ █ █ █ █ █ █ ███ █ █ █ █ █ █ █ █ █ █ ", + " █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + " █ ████ █ █ █ █ █ ████ █ █ ███ █ █ █ █ █ ████ ", + " ", + " ██ ██ ██ ███ ", + " ████ ██ ██ ██ ", + " █ █ ██ ██ ██ ", + " ██ ██ ██ ██ ██ ", + " █ █ ██ ██ ██ ██ ", + " ██ ██ ██ ██ ██ ██ ██ ", + " █ ██ █ ██ ██ ██ ██████ ", + " ██ ██ ██ ██ ██ ██ ███ ██ ", + " █ ██ █ ██ ██ ██ ██ ██ ", + " ██ ██ ██ ██ ██ ██ ██ ██ ", + " █ █ ██ ██ ██ ██ ██ ", + " ██ ██ ██ ██ ████ ██ ██ ██ ", + " █ █ ██████████ ██ ██ ", + " ████████████████ ███ ███ ██ ██ ", + " ███████████████ █ █ ████ ", + " ", + " ", + " █ █ █ █ █ █████ ███ █ ███ █ █ █████ ███ ", + " ██ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + "█ ██ ██ █ █ █ █ █ █ █ █ █ █ █ █ ", + "███ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + " █ █ ██ █ █ █ █ █ █ █ █ █ █ ", + " █ █ █ █ █ █ █ █ █ █ █ █ ", + " █ █ ███ █ ███ █████ ███ █ █ ███ " + )) + + val testAlertScreenConfirmTextLithuanianScreen = makeDisplayFrame(arrayOf( + "█████ ████ ████ █ █████ █ █ █ █ █ █ █ █████ █ ████ ", + " █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + " █ █ █ █ █ █ █ █ ████ █ █ █ █ █ █ █ █ █ █ ", + " █ ████ ████ █████ █ █ █████ █ █ ██ █ █████ ███ ", + " █ █ █ █ █ █ █ █ ███ █ █ █ █ █ █ █ █ █ █ ", + " █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + " █ ████ █ █ █ █ █ ████ █ █ ███ █ █ █ █ █ ████ ", + " ", + " ██ ██ ██ ███ ", + " ████ ██ ██ ██ ", + " █ █ ██ ██ ██ ", + " ██ ██ ██ ██ ██ ", + " █ █ ██ ██ ██ ██ ", + " ██ ██ ██ ██ ██ ██ ██ ", + " █ ██ █ ██ ██ ██ ██████ ", + " ██ ██ ██ ██ ██ ██ ███ ██ ", + " █ ██ █ ██ ██ ██ ██ ██ ", + " ██ ██ ██ ██ ██ ██ ██ ██ ", + " █ █ ██ ██ ██ ██ ██ ", + " ██ ██ ██ ██ ████ ██ ██ ██ ", + " █ █ ██████████ ██ ██ ", + " ████████████████ ███ ███ ██ ██ ", + " ███████████████ █ █ ████ ", + " ", + " ", + " █ ████ █ █████ █ █ ███ ████ █████ ███ █ █ █████ ███ ", + " ██ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + "█ ██ █ █ █ █ █ █ █ █ █ █ █ █ ██ █ █ █ ", + "███ ████ █████ █ █ █ █ ████ █ █ █ █ █ █ █ ", + " █ █ █ █ █ █ █ █ █ █ █ █ █ ██ █ █ ", + " █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + " █ █ █ █ █ ███ █ █ █ ███ █ █ █ ███ " + )) } \ No newline at end of file From fe1235dbe15dbb0d0e263cdeda1d77025e941db6 Mon Sep 17 00:00:00 2001 From: Carlos Rafael Giani Date: Wed, 8 Mar 2023 22:19:50 +0100 Subject: [PATCH 09/17] combov2: Wait for coroutines to finish in onStop() --- .../nightscout/pump/combov2/ComboV2Plugin.kt | 84 ++++++++++++------- 1 file changed, 53 insertions(+), 31 deletions(-) diff --git a/pump/combov2/src/main/kotlin/info/nightscout/pump/combov2/ComboV2Plugin.kt b/pump/combov2/src/main/kotlin/info/nightscout/pump/combov2/ComboV2Plugin.kt index bc2043caa1..c9ca336168 100644 --- a/pump/combov2/src/main/kotlin/info/nightscout/pump/combov2/ComboV2Plugin.kt +++ b/pump/combov2/src/main/kotlin/info/nightscout/pump/combov2/ComboV2Plugin.kt @@ -134,8 +134,8 @@ class ComboV2Plugin @Inject constructor ( // Coroutine scope and the associated job. All coroutines // that are started in this plugin are part of this scope. - private val pumpCoroutineMainJob = SupervisorJob() - private val pumpCoroutineScope = CoroutineScope(Dispatchers.Default + pumpCoroutineMainJob) + private var pumpCoroutineScopeJob = SupervisorJob() + private var pumpCoroutineScope = CoroutineScope(Dispatchers.Default + pumpCoroutineScopeJob) private val _pumpDescription = PumpDescription() @@ -255,6 +255,8 @@ class ComboV2Plugin @Inject constructor ( } override fun onStart() { + aapsLogger.info(LTag.PUMP, "Starting combov2 driver") + super.onStart() updateComboCtlLogLevel() @@ -290,49 +292,63 @@ class ComboV2Plugin @Inject constructor ( aapsLogger.debug(LTag.PUMP, "Creating bluetooth interface") bluetoothInterface = AndroidBluetoothInterface(context) + aapsLogger.info(LTag.PUMP, "Continuing combov2 driver start in coroutine") + // Continue initialization in a separate coroutine. This allows us to call // runWithPermissionCheck(), which will keep trying to run the code block // until either the necessary Bluetooth permissions are granted, or the // coroutine is cancelled (see onStop() below). pumpCoroutineScope.launch { - runWithPermissionCheck( - context, config, aapsLogger, androidPermission, - permissionsToCheckFor = listOf("android.permission.BLUETOOTH_CONNECT") - ) { - aapsLogger.debug(LTag.PUMP, "Setting up bluetooth interface") - bluetoothInterface!!.setup() + try { + runWithPermissionCheck( + context, config, aapsLogger, androidPermission, + permissionsToCheckFor = listOf("android.permission.BLUETOOTH_CONNECT") + ) { + aapsLogger.debug(LTag.PUMP, "Setting up bluetooth interface") + bluetoothInterface!!.setup() - aapsLogger.debug(LTag.PUMP, "Setting up pump manager") - pumpManager = ComboCtlPumpManager(bluetoothInterface!!, pumpStateStore) - pumpManager!!.setup { - _pairedStateUIFlow.value = false - unpairing = false + aapsLogger.debug(LTag.PUMP, "Setting up pump manager") + pumpManager = ComboCtlPumpManager(bluetoothInterface!!, pumpStateStore) + pumpManager!!.setup { + _pairedStateUIFlow.value = false + unpairing = false + } + + // UI flows that must have defined values right + // at start are initialized here. + + // The paired state UI flow is special in that it is also + // used as the backing store for the isPaired() function, + // so setting up that UI state flow equals updating that + // paired state. + val paired = pumpManager!!.getPairedPumpAddresses().isNotEmpty() + _pairedStateUIFlow.value = paired + + setDriverState(DriverState.Disconnected) + + aapsLogger.info(LTag.PUMP, "combov2 driver start complete") + + // NOTE: EventInitializationChanged is sent in getPumpStatus() . } - - // UI flows that must have defined values right - // at start are initialized here. - - // The paired state UI flow is special in that it is also - // used as the backing store for the isPaired() function, - // so setting up that UI state flow equals updating that - // paired state. - val paired = pumpManager!!.getPairedPumpAddresses().isNotEmpty() - _pairedStateUIFlow.value = paired - - setDriverState(DriverState.Disconnected) - - // NOTE: EventInitializationChanged is sent in getPumpStatus() . + } catch (e: CancellationException) { + aapsLogger.info(LTag.PUMP, "combov2 driver start cancelled") + throw e } } } override fun onStop() { - // Cancel any ongoing background coroutines. This includes an ongoing - // unfinished initialization that still waits for the user to grant - // Bluetooth permissions. - pumpCoroutineScope.cancel() + aapsLogger.info(LTag.PUMP, "Stopping combov2 driver") runBlocking { + // Cancel any ongoing background coroutines. This includes an ongoing + // unfinished initialization that still waits for the user to grant + // Bluetooth permissions. Also join to wait for the coroutines to + // finish. Otherwise, race conditions can occur, for example, when + // a coroutine tries to access bluetoothInterface right after it + // was torn down below. + pumpCoroutineScopeJob.cancelAndJoin() + // Normally this should not happen, but to be safe, // make sure any running pump instance is disconnected. pump?.disconnect() @@ -353,7 +369,13 @@ class ComboV2Plugin @Inject constructor ( rxBus.send(EventInitializationChanged()) initializationChangedEventSent = false + // The old job and scope were completed. We need new ones. + pumpCoroutineScopeJob = SupervisorJob() + pumpCoroutineScope = CoroutineScope(Dispatchers.Default + pumpCoroutineScopeJob) + super.onStop() + + aapsLogger.info(LTag.PUMP, "combov2 driver stopped") } override fun preprocessPreferences(preferenceFragment: PreferenceFragmentCompat) { From 72819cbc5358830bb45a2a7cd7b76f586737aea3 Mon Sep 17 00:00:00 2001 From: Carlos Rafael Giani Date: Thu, 9 Mar 2023 00:01:01 +0100 Subject: [PATCH 10/17] comboctl-base: Add exceptions for disabled and missing Bluetooth adapters Signed-off-by: Carlos Rafael Giani --- .../comboctl/base/BluetoothException.kt | 16 ++++++++++++++++ .../comboctl/base/BluetoothInterface.kt | 15 +++++++++++++++ 2 files changed, 31 insertions(+) diff --git a/pump/combov2/comboctl/src/commonMain/kotlin/info/nightscout/comboctl/base/BluetoothException.kt b/pump/combov2/comboctl/src/commonMain/kotlin/info/nightscout/comboctl/base/BluetoothException.kt index f2f73ab9ba..eb7e9026b1 100644 --- a/pump/combov2/comboctl/src/commonMain/kotlin/info/nightscout/comboctl/base/BluetoothException.kt +++ b/pump/combov2/comboctl/src/commonMain/kotlin/info/nightscout/comboctl/base/BluetoothException.kt @@ -23,3 +23,19 @@ open class BluetoothPermissionException(message: String?, cause: Throwable?) : B constructor(message: String) : this(message, null) constructor(cause: Throwable) : this(null, cause) } + +/** + * Exception thrown when trying to use Bluetooth even though the adapter is not enabled. + * + * Note that unlike [BluetoothNotAvailableException], here, the adapter _does_ exist, + * and is just currently turned off. + */ +open class BluetoothNotEnabledException : BluetoothException("Bluetooth is not enabled") + +/** + * Exception thrown when trying to use Bluetooth even though there no adapter available. + * + * "Not available" typically means that the platform has no Bluetooth hardware, or that + * said hardware is inaccessible. + */ +open class BluetoothNotAvailableException : BluetoothException("Bluetooth is not available - there is no usable adapter") \ No newline at end of file diff --git a/pump/combov2/comboctl/src/commonMain/kotlin/info/nightscout/comboctl/base/BluetoothInterface.kt b/pump/combov2/comboctl/src/commonMain/kotlin/info/nightscout/comboctl/base/BluetoothInterface.kt index e7eda120fa..cc59e28488 100644 --- a/pump/combov2/comboctl/src/commonMain/kotlin/info/nightscout/comboctl/base/BluetoothInterface.kt +++ b/pump/combov2/comboctl/src/commonMain/kotlin/info/nightscout/comboctl/base/BluetoothInterface.kt @@ -140,6 +140,10 @@ interface BluetoothInterface { * a Bluetooth subsystem that has been shut down. * @throws BluetoothPermissionException if discovery fails because * scanning and connection permissions are missing. + * @throws BluetoothNotEnabledException if the system's + * Bluetooth adapter is currently not enabled. + * @throws BluetoothNotAvailableException if the system's + * Bluetooth adapter is currently not available. * @throws BluetoothException if discovery fails due to an underlying * Bluetooth issue. */ @@ -172,6 +176,10 @@ interface BluetoothInterface { * * @return BluetoothDevice instance for the device with the * given address + * @throws BluetoothNotEnabledException if the system's + * Bluetooth adapter is currently not enabled. + * @throws BluetoothNotAvailableException if the system's + * Bluetooth adapter is currently not available. * @throws IllegalStateException if the interface is in a state * in which accessing devices is not possible, such as * a Bluetooth subsystem that has been shut down. @@ -183,6 +191,8 @@ interface BluetoothInterface { * * @throws BluetoothPermissionException if getting the adapter name * fails because connection permissions are missing. + * @throws BluetoothNotAvailableException if the system's + * Bluetooth adapter is currently not available. * @throws BluetoothException if getting the adapter name fails * due to an underlying Bluetooth issue. */ @@ -205,6 +215,11 @@ interface BluetoothInterface { * round, it is possible that between the [getPairedDeviceAddresses] * call and the [onDeviceUnpaired] assignment, a device is * unpaired, and thus does not get noticed. + * + * @throws BluetoothNotEnabledException if the system's + * Bluetooth adapter is currently not enabled. + * @throws BluetoothNotAvailableException if the system's + * Bluetooth adapter is currently not available. */ fun getPairedDeviceAddresses(): Set } From 13666fd549e413f828dc8bf9d4a7089bd81ef461 Mon Sep 17 00:00:00 2001 From: Carlos Rafael Giani Date: Sat, 11 Mar 2023 11:01:22 +0100 Subject: [PATCH 11/17] combov2: Document and extend runWithPermissionCheck utility function --- .../info/nightscout/pump/combov2/Utility.kt | 43 ++++++++++++++++++- 1 file changed, 41 insertions(+), 2 deletions(-) diff --git a/pump/combov2/src/main/kotlin/info/nightscout/pump/combov2/Utility.kt b/pump/combov2/src/main/kotlin/info/nightscout/pump/combov2/Utility.kt index 03576e4401..407a8ecf06 100644 --- a/pump/combov2/src/main/kotlin/info/nightscout/pump/combov2/Utility.kt +++ b/pump/combov2/src/main/kotlin/info/nightscout/pump/combov2/Utility.kt @@ -3,6 +3,7 @@ package info.nightscout.pump.combov2 import android.content.Context import android.os.Build import info.nightscout.comboctl.android.AndroidBluetoothPermissionException +import info.nightscout.comboctl.base.ComboException import info.nightscout.comboctl.main.BasalProfile import info.nightscout.comboctl.main.NUM_COMBO_BASAL_PROFILE_FACTORS import info.nightscout.interfaces.AndroidPermission @@ -32,7 +33,37 @@ fun AAPSProfile.toComboCtlBasalProfile(): BasalProfile { return BasalProfile(factors) } -suspend fun runWithPermissionCheck( +internal class RetryPermissionCheckException : ComboException("retry permission check") + +// Utility function to perform Android permission checks before running a block. +// If the permissions are not given, wait for a little while, then retry. +// This is needed for AAPS<->combov2 integration, since AAPS can start combov2 +// even _before_ the user granted AAPS BLUETOOTH_CONNECT etc. permissions. +// +// permissionsToCheckFor is a collection of permissions strings like +// Manifest.permission.BLUETOOTH_SCAN. The function goes through the collection, +// and checks each and every permission to see if they have all been granted. +// Only if all have been granted will the block be executed. +// +// It is possible that within the block, some additional permission checks +// are performed - in particular, these can be checks for permissions that +// weren't part of the permissionsToCheckFor collection. If such a permission +// is not granted, the block can throw AndroidBluetoothPermissionException. +// That exception also specifies what exact permissions haven't been granted +// (yet). runWithPermissionCheck() then adds these missing permissions to +// permissionsToCheckFor, and tries its permission check again, this time +// with these extra permissions included. That way, a failed permission +// check within the block does not break anything, and instead, these +// permissions too are re-checked by the same logic as the one that looks +// at the initially specified permissions. +// +// Additionally, the block might perform other checks that are not directly +// permissions but related to them. One example is a check to see if the +// Bluetooth adapter is enabled in addition to checking for Bluetooth +// permissions. When such custom checks fail, they can throw +// RetryPermissionCheckException to inform this function that it should +// retry its run, just as if a permission hadn't been granted. +internal suspend fun runWithPermissionCheck( context: Context, config: Config, aapsLogger: AAPSLogger, @@ -53,12 +84,20 @@ suspend fun runWithPermissionCheck( } if (notAllPermissionsGranted) { - delay(1000) // Wait a little bit before retrying to avoid 100% CPU usage + // Wait a little bit before retrying to avoid 100% CPU usage. + // It is currently unknown if there is a way to instead get + // some sort of event from Android to inform that the permissions + // have now been granted, so we have to resort to polling, + // at least for now. + delay(1000) continue } } return block.invoke() + } catch (e: RetryPermissionCheckException) { + // See the above delay() call, which fulfills the exact same purpose. + delay(1000) } catch (e: AndroidBluetoothPermissionException) { permissions = permissionsToCheckFor union e.missingPermissions } From c1058ad113f79d68afeb997e2f890fc534ccbe90 Mon Sep 17 00:00:00 2001 From: Carlos Rafael Giani Date: Sat, 11 Mar 2023 11:34:14 +0100 Subject: [PATCH 12/17] comboctl-android: Check that the adapter is available and enabled Signed-off-by: Carlos Rafael Giani --- .../android/AndroidBluetoothInterface.kt | 46 ++++++++++++++----- 1 file changed, 35 insertions(+), 11 deletions(-) diff --git a/pump/combov2/comboctl/src/androidMain/kotlin/info/nightscout/comboctl/android/AndroidBluetoothInterface.kt b/pump/combov2/comboctl/src/androidMain/kotlin/info/nightscout/comboctl/android/AndroidBluetoothInterface.kt index a0ff751adb..92402fb7bb 100644 --- a/pump/combov2/comboctl/src/androidMain/kotlin/info/nightscout/comboctl/android/AndroidBluetoothInterface.kt +++ b/pump/combov2/comboctl/src/androidMain/kotlin/info/nightscout/comboctl/android/AndroidBluetoothInterface.kt @@ -7,8 +7,10 @@ import android.content.Intent import android.content.IntentFilter import info.nightscout.comboctl.base.BluetoothAddress import info.nightscout.comboctl.base.BluetoothDevice +import info.nightscout.comboctl.base.BluetoothNotEnabledException import info.nightscout.comboctl.base.BluetoothException import info.nightscout.comboctl.base.BluetoothInterface +import info.nightscout.comboctl.base.BluetoothNotAvailableException import info.nightscout.comboctl.base.LogLevel import info.nightscout.comboctl.base.Logger import info.nightscout.comboctl.base.toBluetoothAddress @@ -35,7 +37,10 @@ private val logger = Logger.get("AndroidBluetoothInterface") * instance is an ideal choice. */ class AndroidBluetoothInterface(private val androidContext: Context) : BluetoothInterface { - private var bluetoothAdapter: SystemBluetoothAdapter? = null + private var _bluetoothAdapter: SystemBluetoothAdapter? = null + private val bluetoothAdapter: SystemBluetoothAdapter + get() = _bluetoothAdapter ?: throw BluetoothNotAvailableException() + private var rfcommServerSocket: SystemBluetoothServerSocket? = null private var discoveryStarted = false private var discoveryBroadcastReceiver: BroadcastReceiver? = null @@ -96,11 +101,16 @@ class AndroidBluetoothInterface(private val androidContext: Context) : Bluetooth else @Suppress("DEPRECATION") getParcelableExtra(name) fun setup() { - val bluetoothManager = androidContext.getSystemService(Context.BLUETOOTH_SERVICE) as SystemBluetoothManager - bluetoothAdapter = bluetoothManager.adapter + val bluetoothManager = androidContext.getSystemService(Context.BLUETOOTH_SERVICE) as? SystemBluetoothManager + _bluetoothAdapter = bluetoothManager?.adapter + + checkIfBluetoothEnabledAndAvailable() val bondedDevices = checkForConnectPermission(androidContext) { - bluetoothAdapter!!.bondedDevices + // The "not enabled" check above is important, because in the disabled + // state, the adapter returns an empty list here. This would mislead + // the logic below into thinking that there are no bonded devices. + bluetoothAdapter.bondedDevices } logger(LogLevel.DEBUG) { "Found ${bondedDevices.size} bonded Bluetooth device(s)" } @@ -180,7 +190,7 @@ class AndroidBluetoothInterface(private val androidContext: Context) : Bluetooth // necessary for correct function, just a detail for sake of completeness.) logger(LogLevel.DEBUG) { "Setting up RFCOMM listener socket" } rfcommServerSocket = checkForConnectPermission(androidContext) { - bluetoothAdapter!!.listenUsingInsecureRfcommWithServiceRecord( + bluetoothAdapter.listenUsingInsecureRfcommWithServiceRecord( sdpServiceName, Constants.sdpSerialPortUUID ) @@ -203,7 +213,7 @@ class AndroidBluetoothInterface(private val androidContext: Context) : Bluetooth logger(LogLevel.DEBUG) { "Closing accepted incoming RFCOMM socket" } try { socket.close() - } catch (e: IOException) { + } catch (_: IOException) { } } } @@ -274,20 +284,24 @@ class AndroidBluetoothInterface(private val androidContext: Context) : Bluetooth stopDiscoveryInternal() } - override fun getDevice(deviceAddress: BluetoothAddress): BluetoothDevice = - AndroidBluetoothDevice(androidContext, bluetoothAdapter!!, deviceAddress) + override fun getDevice(deviceAddress: BluetoothAddress): BluetoothDevice { + checkIfBluetoothEnabledAndAvailable() + return AndroidBluetoothDevice(androidContext, bluetoothAdapter, deviceAddress) + } override fun getAdapterFriendlyName() = - checkForConnectPermission(androidContext) { bluetoothAdapter!!.name } + checkForConnectPermission(androidContext) { bluetoothAdapter.name } ?: throw BluetoothException("Could not get Bluetooth adapter friendly name") - override fun getPairedDeviceAddresses(): Set = - try { + override fun getPairedDeviceAddresses(): Set { + checkIfBluetoothEnabledAndAvailable() + return try { deviceAddressLock.lock() pairedDeviceAddresses.filter { pairedDeviceAddress -> deviceFilterCallback(pairedDeviceAddress) }.toSet() } finally { deviceAddressLock.unlock() } + } private fun stopDiscoveryInternal() { // Close the server socket. This frees RFCOMM resources and ends @@ -332,6 +346,16 @@ class AndroidBluetoothInterface(private val androidContext: Context) : Bluetooth } } + private fun checkIfBluetoothEnabledAndAvailable() { + // Trying to access bluetoothAdapter here if it is currently null will + // automatically cause BluetoothNotAvailableException to be thrown, + // so that case is also covered implicitly by this code. + if (!bluetoothAdapter.isEnabled || (bluetoothAdapter.state != SystemBluetoothAdapter.STATE_ON)) { + logger(LogLevel.ERROR) { "Bluetooth is not enabled" } + throw BluetoothNotEnabledException() + } + } + private fun onAclConnected(intent: Intent, foundNewPairedDevice: (deviceAddress: BluetoothAddress) -> Unit) { // Sanity check in case we get this notification for the // device already and need to avoid duplicate processing. From 6d998c8081d35eaa10673fc121dfbe50d0375db2 Mon Sep 17 00:00:00 2001 From: Carlos Rafael Giani Date: Sat, 11 Mar 2023 11:35:18 +0100 Subject: [PATCH 13/17] combov2: Catch exceptions thrown when the adapter is disabled / unavailable --- .../nightscout/pump/combov2/ComboV2Plugin.kt | 43 ++++++++++++------- 1 file changed, 27 insertions(+), 16 deletions(-) diff --git a/pump/combov2/src/main/kotlin/info/nightscout/pump/combov2/ComboV2Plugin.kt b/pump/combov2/src/main/kotlin/info/nightscout/pump/combov2/ComboV2Plugin.kt index c9ca336168..faccc427f7 100644 --- a/pump/combov2/src/main/kotlin/info/nightscout/pump/combov2/ComboV2Plugin.kt +++ b/pump/combov2/src/main/kotlin/info/nightscout/pump/combov2/ComboV2Plugin.kt @@ -12,6 +12,7 @@ import dagger.android.HasAndroidInjector import info.nightscout.comboctl.android.AndroidBluetoothInterface import info.nightscout.comboctl.base.BasicProgressStage import info.nightscout.comboctl.base.BluetoothException +import info.nightscout.comboctl.base.BluetoothNotEnabledException import info.nightscout.comboctl.base.ComboException import info.nightscout.comboctl.base.DisplayFrame import info.nightscout.comboctl.base.NullDisplayFrame @@ -305,25 +306,35 @@ class ComboV2Plugin @Inject constructor ( permissionsToCheckFor = listOf("android.permission.BLUETOOTH_CONNECT") ) { aapsLogger.debug(LTag.PUMP, "Setting up bluetooth interface") - bluetoothInterface!!.setup() - aapsLogger.debug(LTag.PUMP, "Setting up pump manager") - pumpManager = ComboCtlPumpManager(bluetoothInterface!!, pumpStateStore) - pumpManager!!.setup { - _pairedStateUIFlow.value = false - unpairing = false + try { + bluetoothInterface!!.setup() + + aapsLogger.debug(LTag.PUMP, "Setting up pump manager") + pumpManager = ComboCtlPumpManager(bluetoothInterface!!, pumpStateStore) + pumpManager!!.setup { + _pairedStateUIFlow.value = false + unpairing = false + } + + // UI flows that must have defined values right + // at start are initialized here. + + // The paired state UI flow is special in that it is also + // used as the backing store for the isPaired() function, + // so setting up that UI state flow equals updating that + // paired state. + val paired = pumpManager!!.getPairedPumpAddresses().isNotEmpty() + _pairedStateUIFlow.value = paired + } catch (_: BluetoothNotEnabledException) { + // If the user currently has Bluetooth disabled, retry until + // the user turns it on. AAPS will automatically show a dialog + // box which requests the user to enable Bluetooth. Upon + // catching this exception, runWithPermissionCheck() will wait + // a bit before retrying, so no delay() call is needed here. + throw RetryPermissionCheckException() } - // UI flows that must have defined values right - // at start are initialized here. - - // The paired state UI flow is special in that it is also - // used as the backing store for the isPaired() function, - // so setting up that UI state flow equals updating that - // paired state. - val paired = pumpManager!!.getPairedPumpAddresses().isNotEmpty() - _pairedStateUIFlow.value = paired - setDriverState(DriverState.Disconnected) aapsLogger.info(LTag.PUMP, "combov2 driver start complete") From 377188353ab7e860453e1486112e63b2fd569986 Mon Sep 17 00:00:00 2001 From: Carlos Rafael Giani Date: Sat, 11 Mar 2023 18:57:09 +0100 Subject: [PATCH 14/17] combov2: Show UI notifications and toaster messages when BT is not enabled --- .../interfaces/notifications/Notification.kt | 1 + .../nightscout/pump/combov2/ComboV2Plugin.kt | 44 ++++++++++++++----- 2 files changed, 35 insertions(+), 10 deletions(-) diff --git a/core/interfaces/src/main/java/info/nightscout/interfaces/notifications/Notification.kt b/core/interfaces/src/main/java/info/nightscout/interfaces/notifications/Notification.kt index f7bfe91add..066e412c5f 100644 --- a/core/interfaces/src/main/java/info/nightscout/interfaces/notifications/Notification.kt +++ b/core/interfaces/src/main/java/info/nightscout/interfaces/notifications/Notification.kt @@ -133,6 +133,7 @@ open class Notification { const val EOELOW_PATCH_ALERTS = 79 const val COMBO_PUMP_SUSPENDED = 80 const val COMBO_UNKNOWN_TBR = 81 + const val BLUETOOTH_NOT_ENABLED = 82 const val USER_MESSAGE = 1000 diff --git a/pump/combov2/src/main/kotlin/info/nightscout/pump/combov2/ComboV2Plugin.kt b/pump/combov2/src/main/kotlin/info/nightscout/pump/combov2/ComboV2Plugin.kt index faccc427f7..24c9baf23b 100644 --- a/pump/combov2/src/main/kotlin/info/nightscout/pump/combov2/ComboV2Plugin.kt +++ b/pump/combov2/src/main/kotlin/info/nightscout/pump/combov2/ComboV2Plugin.kt @@ -66,7 +66,6 @@ import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Job import kotlinx.coroutines.SupervisorJob import kotlinx.coroutines.async -import kotlinx.coroutines.cancel import kotlinx.coroutines.cancelAndJoin import kotlinx.coroutines.channels.BufferOverflow import kotlinx.coroutines.channels.Channel @@ -310,6 +309,8 @@ class ComboV2Plugin @Inject constructor ( try { bluetoothInterface!!.setup() + rxBus.send(EventDismissNotification(Notification.BLUETOOTH_NOT_ENABLED)) + aapsLogger.debug(LTag.PUMP, "Setting up pump manager") pumpManager = ComboCtlPumpManager(bluetoothInterface!!, pumpStateStore) pumpManager!!.setup { @@ -327,6 +328,12 @@ class ComboV2Plugin @Inject constructor ( val paired = pumpManager!!.getPairedPumpAddresses().isNotEmpty() _pairedStateUIFlow.value = paired } catch (_: BluetoothNotEnabledException) { + uiInteraction.addNotification( + Notification.BLUETOOTH_NOT_ENABLED, + text = rh.gs(info.nightscout.core.ui.R.string.ble_not_enabled), + level = Notification.INFO + ) + // If the user currently has Bluetooth disabled, retry until // the user turns it on. AAPS will automatically show a dialog // box which requests the user to enable Bluetooth. Upon @@ -555,6 +562,8 @@ class ComboV2Plugin @Inject constructor ( _bluetoothAddressUIFlow.value = bluetoothAddress.toString() _serialNumberUIFlow.value = pumpManager!!.getPumpID(bluetoothAddress) + rxBus.send(EventDismissNotification(Notification.BLUETOOTH_NOT_ENABLED)) + // Erase any display frame that may be left over from a previous connection. @OptIn(kotlinx.coroutines.ExperimentalCoroutinesApi::class) _displayFrameUIFlow.resetReplayCache() @@ -729,6 +738,12 @@ class ComboV2Plugin @Inject constructor ( executePendingDisconnect() } } + } catch (_: BluetoothNotEnabledException) { + uiInteraction.addNotification( + Notification.BLUETOOTH_NOT_ENABLED, + text = rh.gs(info.nightscout.core.ui.R.string.ble_not_enabled), + level = Notification.INFO + ) } catch (e: Exception) { aapsLogger.error(LTag.PUMP, "Connection failure: $e") ToastUtils.showToastInUiThread(context, rh.gs(R.string.combov2_could_not_connect)) @@ -1575,15 +1590,24 @@ class ComboV2Plugin @Inject constructor ( context, config, aapsLogger, androidPermission, permissionsToCheckFor = listOf("android.permission.BLUETOOTH_CONNECT") ) { - pumpManager?.pairWithNewPump(discoveryDuration) { newPumpAddress, previousAttemptFailed -> - aapsLogger.info( - LTag.PUMP, - "New pairing PIN request from Combo pump with Bluetooth " + - "address $newPumpAddress (previous attempt failed: $previousAttemptFailed)" - ) - _previousPairingAttemptFailedFlow.value = previousAttemptFailed - newPINChannel.receive() - } ?: throw IllegalStateException("Attempting to access uninitialized pump manager") + try { + pumpManager?.pairWithNewPump(discoveryDuration) { newPumpAddress, previousAttemptFailed -> + aapsLogger.info( + LTag.PUMP, + "New pairing PIN request from Combo pump with Bluetooth " + + "address $newPumpAddress (previous attempt failed: $previousAttemptFailed)" + ) + _previousPairingAttemptFailedFlow.value = previousAttemptFailed + newPINChannel.receive() + } ?: throw IllegalStateException("Attempting to access uninitialized pump manager") + } catch (e: BluetoothNotEnabledException) { + // If Bluetooth is turned off during pairing, show a toaster message. + // Notifications on the AAPS overview fragment are not useful here + // because the pairing activity obscures that fragment. So, instead, + // alert the user by showing the notification via the toaster. + ToastUtils.errorToast(context, info.nightscout.core.ui.R.string.ble_not_enabled) + ComboCtlPumpManager.PairingResult.ExceptionDuringPairing(e) + } } if (pairingResult !is ComboCtlPumpManager.PairingResult.Success) From cc4cd2dc04d124aca16055c2b559607f4b9052fe Mon Sep 17 00:00:00 2001 From: Carlos Rafael Giani Date: Sat, 11 Mar 2023 19:46:32 +0100 Subject: [PATCH 15/17] comboctl-parser: Don't try to interpret text in error screens That text shows contents that are different to that of warning screens. Instead of extending the interpretation logic to cover such contents as well, just use a generic ERROR_TEXT AlertScreenState. That text won't be interpreted by any program logic anyway, since error screens are never dismissed automatically. Signed-off-by: Carlos Rafael Giani --- .../info/nightscout/comboctl/parser/Parser.kt | 25 +++- .../nightscout/comboctl/parser/ParserTest.kt | 18 +++ .../comboctl/parser/TestDisplayFrames.kt | 140 ++++++++++++++++++ 3 files changed, 175 insertions(+), 8 deletions(-) diff --git a/pump/combov2/comboctl/src/commonMain/kotlin/info/nightscout/comboctl/parser/Parser.kt b/pump/combov2/comboctl/src/commonMain/kotlin/info/nightscout/comboctl/parser/Parser.kt index 2c2d7be005..7ad91437a5 100644 --- a/pump/combov2/comboctl/src/commonMain/kotlin/info/nightscout/comboctl/parser/Parser.kt +++ b/pump/combov2/comboctl/src/commonMain/kotlin/info/nightscout/comboctl/parser/Parser.kt @@ -84,6 +84,9 @@ sealed class AlertScreenContent { enum class AlertScreenState { TO_SNOOZE, TO_CONFIRM, + // Used when the alert is an error. The text in error screens is not + // interpreted, since it is anyway fully up to the user to interpret it. + ERROR_TEXT, HISTORY_ENTRY } @@ -1156,15 +1159,14 @@ class AlertScreenParser : Parser() { parseResult as ParseResult.Sequence - val stateString = parseResult.valueAt(4) - val alertState = when (knownScreenTitles[stateString]) { - TitleID.ALERT_TO_SNOOZE -> AlertScreenContent.AlertScreenState.TO_SNOOZE - TitleID.ALERT_TO_CONFIRM -> AlertScreenContent.AlertScreenState.TO_CONFIRM - else -> return ParseResult.Failed - } - return when (parseResult.valueAtOrNull(0)) { Glyph.LargeSymbol(LargeSymbol.WARNING) -> { + val stateString = parseResult.valueAt(4) + val alertState = when (knownScreenTitles[stateString]) { + TitleID.ALERT_TO_SNOOZE -> AlertScreenContent.AlertScreenState.TO_SNOOZE + TitleID.ALERT_TO_CONFIRM -> AlertScreenContent.AlertScreenState.TO_CONFIRM + else -> return ParseResult.Failed + } ParseResult.Value(ParsedScreen.AlertScreen( AlertScreenContent.Warning(parseResult.valueAt(2), alertState) )) @@ -1172,7 +1174,14 @@ class AlertScreenParser : Parser() { Glyph.LargeSymbol(LargeSymbol.ERROR) -> { ParseResult.Value(ParsedScreen.AlertScreen( - AlertScreenContent.Error(parseResult.valueAt(2), alertState) + AlertScreenContent.Error( + parseResult.valueAt(2), + // We don't really care about the state string if an error is shown. + // It's not like any logic here will interpret it; that text is + // purely for the user. So, don't bother interpreting it here, and + // just assign a generic ERROR_TEXT state value instead. + AlertScreenContent.AlertScreenState.ERROR_TEXT + ) )) } diff --git a/pump/combov2/comboctl/src/jvmTest/kotlin/info/nightscout/comboctl/parser/ParserTest.kt b/pump/combov2/comboctl/src/jvmTest/kotlin/info/nightscout/comboctl/parser/ParserTest.kt index 03421aec21..b3a0c4d584 100644 --- a/pump/combov2/comboctl/src/jvmTest/kotlin/info/nightscout/comboctl/parser/ParserTest.kt +++ b/pump/combov2/comboctl/src/jvmTest/kotlin/info/nightscout/comboctl/parser/ParserTest.kt @@ -716,6 +716,24 @@ class ParserTest { } } + @Test + fun checkE4OcclusionErrorScreenParsing() { + val testScreens = listOf( + Pair(testFrameE4OcclusionErrorScreen0, AlertScreenContent.Error(4, AlertScreenContent.AlertScreenState.ERROR_TEXT)), + Pair(testFrameE4OcclusionErrorScreen1, AlertScreenContent.None), + Pair(testFrameE4OcclusionErrorScreen2, AlertScreenContent.Error(4, AlertScreenContent.AlertScreenState.ERROR_TEXT)), + Pair(testFrameE4OcclusionErrorScreen3, AlertScreenContent.None), + ) + + for (testScreen in testScreens) { + val testContext = TestContext(testScreen.first, 0, skipTitleString = true) + val result = AlertScreenParser().parse(testContext.parseContext) + assertEquals(ParseResult.Value::class, result::class) + val screen = (result as ParseResult.Value<*>).value as ParsedScreen.AlertScreen + assertEquals(testScreen.second, screen.content) + } + } + @Test fun checkTemporaryBasalRatePercentageScreenParsing() { val testScreens = listOf( diff --git a/pump/combov2/comboctl/src/jvmTest/kotlin/info/nightscout/comboctl/parser/TestDisplayFrames.kt b/pump/combov2/comboctl/src/jvmTest/kotlin/info/nightscout/comboctl/parser/TestDisplayFrames.kt index 0830f7b08b..9ed1dae19a 100644 --- a/pump/combov2/comboctl/src/jvmTest/kotlin/info/nightscout/comboctl/parser/TestDisplayFrames.kt +++ b/pump/combov2/comboctl/src/jvmTest/kotlin/info/nightscout/comboctl/parser/TestDisplayFrames.kt @@ -1700,6 +1700,146 @@ val testFrameE2BatteryEmptyErrorScreen1 = makeDisplayFrame(arrayOf( " ████ █████ ████ █ █ █ █ ███ ████ █████ █ █ " )) +val testFrameE4OcclusionErrorScreen0 = makeDisplayFrame(arrayOf( + "█ █ █████ ████ ████ █████ ███ ████ █████ █ █ █ █ ███ ", + "█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + "█ █ █ █ █ █ █ █ █ █ █ █ █ █ ██ █ █ ", + "█ █ ████ ████ ███ █ █ █ ████ ████ █ █ █ █ █ █ ███ ", + "█ █ █ █ █ █ █ █ █ █ █ █ █ █ ██ █ █ ", + " █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + " █ █████ █ █ ████ █ ███ █ █ ███ █ █ ████ ", + " ", + " █████ ████████ ██ ████████ ", + " █████████ ██ ███ ██████████ ", + " ███████████ ██ ███ ████████████ ", + " ███ █████ ███ ██ ████ ██████████████ ", + " ██ ███ ██ ██ █ ██ ████████████████ ", + " ████ █ ████ ██ ██ ██ █ █ █ █ ██ ", + " █████ █████ ██ █ ██ █ ███ ██ █ █ █ █ ", + " ██████ ██████ ███████ ██ ██ █ ██ ██ █ █ ██ ", + " █████ █████ ██ ██ ██ ██ ██ ██ █ █ ███ ", + " ████ █ ████ ██ ████████ █ ██ ██ █ ███ ", + " ██ ███ ██ ██ ██ ████████████████ ", + " ███ █████ ███ ██ ██ ██████████████ ", + " ███████████ ██ ██ ████████████ ", + " █████████ ██ ██ ██████████ ", + " █████ ████████ ██ ████████ ", + " ", + " ", + " █ ████ █████ █ █ █ █ █ █ ████ ███ █ █ █ █ █████ █████ █ █ ", + " ██ █ █ █ █ ██ ██ ██ ██ █ █ █ █ █ █ █ █ █ █ █ █ ", + "█ ██ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ██ █ ", + "███ ███ █ █ █ █ █ █ █ █ █ ███ █ █████ █████ █ █ ████ █ █ █ ", + " █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ██ ", + " █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + " ████ █ ███ █ █ █ █ ████ ███ █ █ █ █ █████ █ █████ █ █ " +)) + +val testFrameE4OcclusionErrorScreen1 = makeDisplayFrame(arrayOf( + "█ █ █████ ████ ████ █████ ███ ████ █████ █ █ █ █ ███ ", + "█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + "█ █ █ █ █ █ █ █ █ █ █ █ █ █ ██ █ █ ", + "█ █ ████ ████ ███ █ █ █ ████ ████ █ █ █ █ █ █ ███ ", + "█ █ █ █ █ █ █ █ █ █ █ █ █ █ ██ █ █ ", + " █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + " █ █████ █ █ ████ █ ███ █ █ ███ █ █ ████ ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " █ ████ █████ █ █ █ █ █ █ ████ ███ █ █ █ █ █████ █████ █ █ ", + " ██ █ █ █ █ ██ ██ ██ ██ █ █ █ █ █ █ █ █ █ █ █ █ ", + "█ ██ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ██ █ ", + "███ ███ █ █ █ █ █ █ █ █ █ ███ █ █████ █████ █ █ ████ █ █ █ ", + " █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ██ ", + " █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + " ████ █ ███ █ █ █ █ ████ ███ █ █ █ █ █████ █ █████ █ █ " +)) + +val testFrameE4OcclusionErrorScreen2 = makeDisplayFrame(arrayOf( + "█ █ █████ ████ ████ █████ ███ ████ █████ █ █ █ █ ███ ", + "█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + "█ █ █ █ █ █ █ █ █ █ █ █ █ █ ██ █ █ ", + "█ █ ████ ████ ███ █ █ █ ████ ████ █ █ █ █ █ █ ███ ", + "█ █ █ █ █ █ █ █ █ █ █ █ █ █ ██ █ █ ", + " █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + " █ █████ █ █ ████ █ ███ █ █ ███ █ █ ████ ", + " ", + " █████ ████████ ██ ████████ ", + " █████████ ██ ███ ██████████ ", + " ███████████ ██ ███ ████████████ ", + " ███ █████ ███ ██ ████ ██████████████ ", + " ██ ███ ██ ██ █ ██ ████████████████ ", + " ████ █ ████ ██ ██ ██ █ █ █ █ ██ ", + " █████ █████ ██ █ ██ █ ███ ██ █ █ █ █ ", + " ██████ ██████ ███████ ██ ██ █ ██ ██ █ █ ██ ", + " █████ █████ ██ ██ ██ ██ ██ ██ █ █ ███ ", + " ████ █ ████ ██ ████████ █ ██ ██ █ ███ ", + " ██ ███ ██ ██ ██ ████████████████ ", + " ███ █████ ███ ██ ██ ██████████████ ", + " ███████████ ██ ██ ████████████ ", + " █████████ ██ ██ ██████████ ", + " █████ ████████ ██ ████████ ", + " ", + " ", + " █ ████ █████ ████ █████ █ █ █████ ███ ███ █████ █ █ ", + " ██ █ █ █ █ █ ███ █ █ █ █ █ █ █ ", + "█ ██ █ █ █ █ █ █ █ █ █ █ █ ██ █ ", + "███ ████ ████ ███ █ █ █ █ █ █ ███ ████ █ █ █ ", + " █ █ █ █ █ █ █████ █ █ █ █ █ █ ██ ", + " █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + " ████ █████ ████ █ █ █ █ ███ ████ █████ █ █ " +)) + +val testFrameE4OcclusionErrorScreen3 = makeDisplayFrame(arrayOf( + "█ █ █████ ████ ████ █████ ███ ████ █████ █ █ █ █ ███ ", + "█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + "█ █ █ █ █ █ █ █ █ █ █ █ █ █ ██ █ █ ", + "█ █ ████ ████ ███ █ █ █ ████ ████ █ █ █ █ █ █ ███ ", + "█ █ █ █ █ █ █ █ █ █ █ █ █ █ ██ █ █ ", + " █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + " █ █████ █ █ ████ █ ███ █ █ ███ █ █ ████ ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " █ ████ █████ ████ █████ █ █ █████ ███ ███ █████ █ █ ", + " ██ █ █ █ █ █ ███ █ █ █ █ █ █ █ ", + "█ ██ █ █ █ █ █ █ █ █ █ █ █ ██ █ ", + "███ ████ ████ ███ █ █ █ █ █ █ ███ ████ █ █ █ ", + " █ █ █ █ █ █ █████ █ █ █ █ █ █ ██ ", + " █ █ █ █ █ █ █ █ █ █ █ █ █ █ ", + " ████ █████ ████ █ █ █ █ ███ ████ █████ █ █ " +)) + val testFrameTemporaryBasalRatePercentage100Screen = makeDisplayFrame(arrayOf( "█████ ████ ████ █ █ █████ ████ █████ ", " █ █ █ █ █ █ █ █ █ █ █ ", From bec7a4aa9782e6b72c1762f00167c713c4df59b7 Mon Sep 17 00:00:00 2001 From: Carlos Rafael Giani Date: Sun, 12 Mar 2023 13:19:33 +0100 Subject: [PATCH 16/17] combov2: Replace unsafe casts --- .../pump/combov2/AAPSPumpStateStore.kt | 3 +- .../nightscout/pump/combov2/ComboV2Plugin.kt | 103 ++++++++++-------- 2 files changed, 62 insertions(+), 44 deletions(-) diff --git a/pump/combov2/src/main/kotlin/info/nightscout/pump/combov2/AAPSPumpStateStore.kt b/pump/combov2/src/main/kotlin/info/nightscout/pump/combov2/AAPSPumpStateStore.kt index 163b7518c3..f55ad8ba4c 100644 --- a/pump/combov2/src/main/kotlin/info/nightscout/pump/combov2/AAPSPumpStateStore.kt +++ b/pump/combov2/src/main/kotlin/info/nightscout/pump/combov2/AAPSPumpStateStore.kt @@ -5,6 +5,7 @@ import info.nightscout.comboctl.base.CurrentTbrState import info.nightscout.comboctl.base.InvariantPumpData import info.nightscout.comboctl.base.Nonce import info.nightscout.comboctl.base.PumpStateStore +import info.nightscout.comboctl.base.PumpStateStoreAccessException import info.nightscout.comboctl.base.Tbr import info.nightscout.comboctl.base.toBluetoothAddress import info.nightscout.comboctl.base.toCipher @@ -151,7 +152,7 @@ class AAPSPumpStateStore( timestamp = Instant.fromEpochSeconds(tbrTimestamp), percentage = tbrPercentage, durationInMinutes = tbrDuration, - type = Tbr.Type.fromStringId(tbrType)!! + type = Tbr.Type.fromStringId(tbrType) ?: throw PumpStateStoreAccessException(pumpAddress, "Invalid type \"$tbrType\"") )) else CurrentTbrState.NoTbrOngoing diff --git a/pump/combov2/src/main/kotlin/info/nightscout/pump/combov2/ComboV2Plugin.kt b/pump/combov2/src/main/kotlin/info/nightscout/pump/combov2/ComboV2Plugin.kt index 24c9baf23b..9a00dae3d1 100644 --- a/pump/combov2/src/main/kotlin/info/nightscout/pump/combov2/ComboV2Plugin.kt +++ b/pump/combov2/src/main/kotlin/info/nightscout/pump/combov2/ComboV2Plugin.kt @@ -290,7 +290,8 @@ class ComboV2Plugin @Inject constructor ( } aapsLogger.debug(LTag.PUMP, "Creating bluetooth interface") - bluetoothInterface = AndroidBluetoothInterface(context) + val newBluetoothInterface = AndroidBluetoothInterface(context) + bluetoothInterface = newBluetoothInterface aapsLogger.info(LTag.PUMP, "Continuing combov2 driver start in coroutine") @@ -307,13 +308,13 @@ class ComboV2Plugin @Inject constructor ( aapsLogger.debug(LTag.PUMP, "Setting up bluetooth interface") try { - bluetoothInterface!!.setup() + newBluetoothInterface.setup() rxBus.send(EventDismissNotification(Notification.BLUETOOTH_NOT_ENABLED)) aapsLogger.debug(LTag.PUMP, "Setting up pump manager") - pumpManager = ComboCtlPumpManager(bluetoothInterface!!, pumpStateStore) - pumpManager!!.setup { + val newPumpManager = ComboCtlPumpManager(newBluetoothInterface, pumpStateStore) + newPumpManager.setup { _pairedStateUIFlow.value = false unpairing = false } @@ -325,8 +326,10 @@ class ComboV2Plugin @Inject constructor ( // used as the backing store for the isPaired() function, // so setting up that UI state flow equals updating that // paired state. - val paired = pumpManager!!.getPairedPumpAddresses().isNotEmpty() + val paired = newPumpManager.getPairedPumpAddresses().isNotEmpty() _pairedStateUIFlow.value = paired + + pumpManager = newPumpManager } catch (_: BluetoothNotEnabledException) { uiInteraction.addNotification( Notification.BLUETOOTH_NOT_ENABLED, @@ -549,18 +552,16 @@ class ComboV2Plugin @Inject constructor ( } try { - runBlocking { - pump = pumpManager?.acquirePump(bluetoothAddress, activeBasalProfile) { event -> handlePumpEvent(event) } + val curPumpManager = pumpManager ?: throw Error("Could not get pump manager; this should not happen. Please report this as a bug.") + + val acquiredPump = runBlocking { + curPumpManager.acquirePump(bluetoothAddress, activeBasalProfile) { event -> handlePumpEvent(event) } } - if (pump == null) { - aapsLogger.error(LTag.PUMP, "Could not get pump instance - pump state store may be corrupted") - unpairDueToPumpDataError() - return - } + pump = acquiredPump _bluetoothAddressUIFlow.value = bluetoothAddress.toString() - _serialNumberUIFlow.value = pumpManager!!.getPumpID(bluetoothAddress) + _serialNumberUIFlow.value = curPumpManager.getPumpID(bluetoothAddress) rxBus.send(EventDismissNotification(Notification.BLUETOOTH_NOT_ENABLED)) @@ -570,7 +571,7 @@ class ComboV2Plugin @Inject constructor ( stateAndStatusFlowsDeferred = pumpCoroutineScope.async { coroutineScope { - pump!!.stateFlow + acquiredPump.stateFlow .onEach { pumpState -> val driverState = when (pumpState) { // The Disconnected pump state is ignored, since the Disconnected @@ -591,7 +592,7 @@ class ComboV2Plugin @Inject constructor ( setDriverState(driverState) } .launchIn(this) - pump!!.statusFlow + acquiredPump.statusFlow .onEach { newPumpStatus -> if (newPumpStatus == null) return@onEach @@ -613,7 +614,7 @@ class ComboV2Plugin @Inject constructor ( rxBus.send(EventRefreshOverview("ComboV2 pump status updated")) } .launchIn(this) - pump!!.lastBolusFlow + acquiredPump.lastBolusFlow .onEach { lastBolus -> if (lastBolus == null) return@onEach @@ -621,7 +622,7 @@ class ComboV2Plugin @Inject constructor ( _lastBolusUIFlow.value = lastBolus } .launchIn(this) - pump!!.currentTbrFlow + acquiredPump.currentTbrFlow .onEach { currentTbr -> _currentTbrUIFlow.value = currentTbr } @@ -629,7 +630,7 @@ class ComboV2Plugin @Inject constructor ( } } - setupUiFlows() + setupUiFlows(acquiredPump) //// // The actual connect procedure begins here. @@ -814,6 +815,8 @@ class ComboV2Plugin @Inject constructor ( } } + val acquiredPump = getAcquiredPump() + rxBus.send(EventDismissNotification(Notification.PROFILE_NOT_SET_NOT_INITIALIZED)) rxBus.send(EventDismissNotification(Notification.FAILED_UPDATE_PROFILE)) @@ -825,7 +828,7 @@ class ComboV2Plugin @Inject constructor ( runBlocking { try { executeCommand { - if (pump!!.setBasalProfile(requestedBasalProfile)) { + if (acquiredPump.setBasalProfile(requestedBasalProfile)) { aapsLogger.debug(LTag.PUMP, "Basal profiles are different; new profile set") activeBasalProfile = requestedBasalProfile updateBaseBasalRateUI() @@ -973,6 +976,8 @@ class ComboV2Plugin @Inject constructor ( // (Also, a zero insulin value makes no sense when bolusing.) require((detailedBolusInfo.insulin > 0) && (detailedBolusInfo.carbs <= 0.0)) { detailedBolusInfo.toString() } + val acquiredPump = getAcquiredPump() + val requestedBolusAmount = detailedBolusInfo.insulin.iuToCctlBolus() val bolusReason = when (detailedBolusInfo.bolusType) { DetailedBolusInfo.BolusType.NORMAL -> ComboCtlPump.StandardBolusReason.NORMAL @@ -1006,7 +1011,7 @@ class ComboV2Plugin @Inject constructor ( ) val bolusProgressJob = pumpCoroutineScope.launch { - pump!!.bolusDeliveryProgressFlow + acquiredPump.bolusDeliveryProgressFlow .collect { progressReport -> when (progressReport.stage) { is RTCommandProgressStage.DeliveringBolus -> { @@ -1029,14 +1034,16 @@ class ComboV2Plugin @Inject constructor ( // Run the delivery in a sub-coroutine to be able // to cancel it via stopBolusDelivering(). val newBolusJob = pumpCoroutineScope.async { - // Store a local reference to the Pump instance. "pump" - // is set to null in case of an error, because then, - // disconnectInternal() is called (which sets pump to null). - // However, we still need to access the last delivered bolus - // from the pump's lastBolusFlow, even if an error happened. - // Solve this by storing this reference and accessing the - // lastBolusFlow through it. - val acquiredPump = pump!! + // NOTE: Above, we take a local reference to the acquired Pump instance, + // with a check that throws an exception in case the "pump" member is + // null. This local reference is particularly important inside this + // coroutine, because the "pump" member is set to null in case of an + // error or other disconnect reason (see disconnectInternal()). However, + // we still need to access the last delivered bolus inside this coroutine + // from the pump's lastBolusFlow, even if an error happened. Accessing + // it through the "pump" member would then result in an NPE. This is + // solved by instead accessing the lastBolusFlow through the local + // "acquiredPump" reference. try { executeCommand { @@ -1216,11 +1223,13 @@ class ComboV2Plugin @Inject constructor ( return } + val acquiredPump = getAcquiredPump() + runBlocking { try { executeCommand { - val tbrComment = when (pump!!.setTbr(percentage, durationInMinutes, tbrType, force100Percent)) { + val tbrComment = when (acquiredPump.setTbr(percentage, durationInMinutes, tbrType, force100Percent)) { ComboCtlPump.SetTbrOutcome.SET_NORMAL_TBR -> rh.gs(R.string.combov2_setting_tbr_succeeded) ComboCtlPump.SetTbrOutcome.SET_EMULATED_100_TBR -> @@ -1373,8 +1382,9 @@ class ComboV2Plugin @Inject constructor ( override fun serialNumber(): String { val bluetoothAddress = getBluetoothAddress() - return if ((bluetoothAddress != null) && (pumpManager != null)) - pumpManager!!.getPumpID(bluetoothAddress) + val curPumpManager = pumpManager + return if ((bluetoothAddress != null) && (curPumpManager != null)) + curPumpManager.getPumpID(bluetoothAddress) else rh.gs(R.string.combov2_not_paired) } @@ -1442,6 +1452,7 @@ class ComboV2Plugin @Inject constructor ( override fun loadTDDs(): PumpEnactResult { val pumpEnactResult = PumpEnactResult(injector) + val acquiredPump = getAcquiredPump() runBlocking { try { @@ -1449,7 +1460,7 @@ class ComboV2Plugin @Inject constructor ( val tddMap = mutableMapOf() executeCommand { - val tddHistory = pump!!.fetchTDDHistory() + val tddHistory = acquiredPump.fetchTDDHistory() tddHistory .filter { it.totalDailyAmount >= 1 } @@ -1771,11 +1782,11 @@ class ComboV2Plugin @Inject constructor ( /*** Misc private functions ***/ - private fun setupUiFlows() { + private fun setupUiFlows(acquiredPump: ComboCtlPump) { pumpUIFlowsDeferred = pumpCoroutineScope.async { try { coroutineScope { - pump!!.connectProgressFlow + acquiredPump.connectProgressFlow .onEach { progressReport -> val description = when (val progStage = progressReport.stage) { is BasicProgressStage.EstablishingBtConnection -> @@ -1793,7 +1804,7 @@ class ComboV2Plugin @Inject constructor ( } .launchIn(this) - pump!!.setDateTimeProgressFlow + acquiredPump.setDateTimeProgressFlow .onEach { progressReport -> val description = when (progressReport.stage) { RTCommandProgressStage.SettingDateTimeHour, @@ -1810,7 +1821,7 @@ class ComboV2Plugin @Inject constructor ( } .launchIn(this) - pump!!.getBasalProfileFlow + acquiredPump.getBasalProfileFlow .onEach { progressReport -> val description = when (val stage = progressReport.stage) { is RTCommandProgressStage.GettingBasalProfile -> @@ -1824,7 +1835,7 @@ class ComboV2Plugin @Inject constructor ( } .launchIn(this) - pump!!.setBasalProfileFlow + acquiredPump.setBasalProfileFlow .onEach { progressReport -> val description = when (val stage = progressReport.stage) { is RTCommandProgressStage.SettingBasalProfile -> @@ -1838,7 +1849,7 @@ class ComboV2Plugin @Inject constructor ( } .launchIn(this) - pump!!.bolusDeliveryProgressFlow + acquiredPump.bolusDeliveryProgressFlow .onEach { progressReport -> val description = when (val stage = progressReport.stage) { is RTCommandProgressStage.DeliveringBolus -> @@ -1856,7 +1867,7 @@ class ComboV2Plugin @Inject constructor ( } .launchIn(this) - pump!!.parsedDisplayFrameFlow + acquiredPump.parsedDisplayFrameFlow .onEach { parsedDisplayFrame -> _displayFrameUIFlow.emit( parsedDisplayFrame?.displayFrame ?: NullDisplayFrame @@ -2058,7 +2069,11 @@ class ComboV2Plugin @Inject constructor ( // It makes no sense to reach this location with pump // being null due to the checks above. - assert(pump != null) + val pumpToDisconnect = pump + if (pumpToDisconnect == null) { + aapsLogger.error(LTag.PUMP, "Current pump is already null") + return + } // Run these operations in a coroutine to be able to wait // until the disconnect really completes and the UI flows @@ -2096,17 +2111,17 @@ class ComboV2Plugin @Inject constructor ( // the Pump.disconnect() call shuts down the RFCOMM socket, // making all send/receive calls fail. - if (pump!!.stateFlow.value == ComboCtlPump.State.Connecting) { + if (pumpToDisconnect.stateFlow.value == ComboCtlPump.State.Connecting) { // Case #1 from above aapsLogger.debug(LTag.PUMP, "Cancelling ongoing connect attempt") connectionSetupJob?.cancel() - pump?.disconnect() + pumpToDisconnect.disconnect() connectionSetupJob?.join() } else { // Case #2 from above aapsLogger.debug(LTag.PUMP, "Disconnecting Combo (if not disconnected already by a cancelling request)") connectionSetupJob?.cancelAndJoin() - pump?.disconnect() + pumpToDisconnect.disconnect() } aapsLogger.debug(LTag.PUMP, "Combo disconnected; cancelling UI flows coroutine") @@ -2339,6 +2354,8 @@ class ComboV2Plugin @Inject constructor ( private fun getBluetoothAddress(): ComboCtlBluetoothAddress? = pumpManager?.getPairedPumpAddresses()?.firstOrNull() + private fun getAcquiredPump() = pump ?: throw Error("There is no currently acquired pump; this should not happen. Please report this as a bug.") + private fun isDisconnected() = when (driverStateFlow.value) { DriverState.NotInitialized, From 9979331ef06a1e6db293eafecbba8e556fe0d4ed Mon Sep 17 00:00:00 2001 From: Carlos Rafael Giani Date: Mon, 13 Mar 2023 21:45:25 +0100 Subject: [PATCH 17/17] comboctl-parser: Fix typo in E2BatteryEmptyErrorScreenParsing test Signed-off-by: Carlos Rafael Giani --- .../kotlin/info/nightscout/comboctl/parser/ParserTest.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pump/combov2/comboctl/src/jvmTest/kotlin/info/nightscout/comboctl/parser/ParserTest.kt b/pump/combov2/comboctl/src/jvmTest/kotlin/info/nightscout/comboctl/parser/ParserTest.kt index b3a0c4d584..c53cfed2d1 100644 --- a/pump/combov2/comboctl/src/jvmTest/kotlin/info/nightscout/comboctl/parser/ParserTest.kt +++ b/pump/combov2/comboctl/src/jvmTest/kotlin/info/nightscout/comboctl/parser/ParserTest.kt @@ -704,7 +704,7 @@ class ParserTest { fun checkE2BatteryEmptyErrorScreenParsing() { val testScreens = listOf( Pair(testFrameE2BatteryEmptyErrorScreen0, AlertScreenContent.None), - Pair(testFrameE2BatteryEmptyErrorScreen1, AlertScreenContent.Error(2, AlertScreenContent.AlertScreenState.TO_CONFIRM)) + Pair(testFrameE2BatteryEmptyErrorScreen1, AlertScreenContent.Error(2, AlertScreenContent.AlertScreenState.ERROR_TEXT)) ) for (testScreen in testScreens) {