Extract methods to read blinking values.
This commit is contained in:
parent
7537048a96
commit
785a01a056
|
@ -597,6 +597,26 @@ public class RuffyScripter {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public <T> T readBlinkingValue(Class<T> expectedType, MenuAttribute attribute) {
|
||||||
|
int retries = 5;
|
||||||
|
Object value = currentMenu.getAttribute(attribute);
|
||||||
|
while (!value.getClass().isAssignableFrom(expectedType.getClass())) {
|
||||||
|
value = currentMenu.getAttribute(attribute);
|
||||||
|
waitForScreenUpdate(1000);
|
||||||
|
retries--;
|
||||||
|
if (retries == 0) {
|
||||||
|
throw new CommandException().message("Failed to read blinkng value: " + attribute);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return (T) value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long readDisplayedDuration() {
|
||||||
|
MenuTime duration = readBlinkingValue(MenuTime.class, MenuAttribute.RUNTIME);
|
||||||
|
return duration.getHour() * 60 + duration.getMinute();
|
||||||
|
}
|
||||||
|
|
||||||
// TODO v2 add remaining info we can extract from the main menu, low battery and low
|
// TODO v2 add remaining info we can extract from the main menu, low battery and low
|
||||||
// cartridge warnings, running extended bolus (how does that look if a TBR is active as well?)
|
// cartridge warnings, running extended bolus (how does that look if a TBR is active as well?)
|
||||||
|
|
||||||
|
|
|
@ -8,8 +8,10 @@ public abstract class BaseCommand implements Command {
|
||||||
@Override public void setScripter(RuffyScripter scripter) { this.scripter = scripter; }
|
@Override public void setScripter(RuffyScripter scripter) { this.scripter = scripter; }
|
||||||
|
|
||||||
// TODO upcoming
|
// TODO upcoming
|
||||||
|
protected final boolean canBeCancelled = true;
|
||||||
protected volatile boolean cancelRequested = false;
|
protected volatile boolean cancelRequested = false;
|
||||||
public void requestCancellation() {
|
public void requestCancellation() {
|
||||||
cancelRequested = true;
|
cancelRequested = true;
|
||||||
}
|
}
|
||||||
|
public boolean isCancellable() { return canBeCancelled; }
|
||||||
}
|
}
|
||||||
|
|
|
@ -130,7 +130,7 @@ public class BolusCommand extends BaseCommand {
|
||||||
|
|
||||||
private void verifyDisplayedBolusAmount() {
|
private void verifyDisplayedBolusAmount() {
|
||||||
scripter.verifyMenuIsDisplayed(MenuType.BOLUS_ENTER);
|
scripter.verifyMenuIsDisplayed(MenuType.BOLUS_ENTER);
|
||||||
double displayedBolus = readDisplayedBolusAmount();
|
double displayedBolus = scripter.readBlinkingValue(Double.class, MenuAttribute.BOLUS);
|
||||||
log.debug("Final bolus: " + displayedBolus);
|
log.debug("Final bolus: " + displayedBolus);
|
||||||
if (Math.abs(displayedBolus - bolus) > 0.05) {
|
if (Math.abs(displayedBolus - bolus) > 0.05) {
|
||||||
throw new CommandException().message("Failed to set correct bolus. Expected: " + bolus + ", actual: " + displayedBolus);
|
throw new CommandException().message("Failed to set correct bolus. Expected: " + bolus + ", actual: " + displayedBolus);
|
||||||
|
@ -138,25 +138,14 @@ public class BolusCommand extends BaseCommand {
|
||||||
|
|
||||||
// check again to ensure the displayed value hasn't change due to due scrolling taking extremely long
|
// check again to ensure the displayed value hasn't change due to due scrolling taking extremely long
|
||||||
SystemClock.sleep(2000);
|
SystemClock.sleep(2000);
|
||||||
double refreshedDisplayedBolus = readDisplayedBolusAmount();
|
scripter.verifyMenuIsDisplayed(MenuType.BOLUS_ENTER);
|
||||||
|
double refreshedDisplayedBolus = scripter.readBlinkingValue(Double.class, MenuAttribute.BOLUS);
|
||||||
if (Math.abs(displayedBolus - refreshedDisplayedBolus) > 0.05) {
|
if (Math.abs(displayedBolus - refreshedDisplayedBolus) > 0.05) {
|
||||||
throw new CommandException().message("Failed to set bolus: bolus changed after input stopped from "
|
throw new CommandException().message("Failed to set bolus: bolus changed after input stopped from "
|
||||||
+ displayedBolus + " -> " + refreshedDisplayedBolus);
|
+ displayedBolus + " -> " + refreshedDisplayedBolus);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private double readDisplayedBolusAmount() {
|
|
||||||
// TODO v2 add timeout? Currently the command execution timeout would trigger if exceeded
|
|
||||||
scripter.verifyMenuIsDisplayed(MenuType.BOLUS_ENTER);
|
|
||||||
// bolus amount is blinking, so we need to make sure we catch it at the right moment
|
|
||||||
Object amountObj = scripter.currentMenu.getAttribute(MenuAttribute.BOLUS);
|
|
||||||
while (!(amountObj instanceof Double)) {
|
|
||||||
scripter.waitForMenuUpdate();
|
|
||||||
amountObj = scripter.currentMenu.getAttribute(MenuAttribute.BOLUS);
|
|
||||||
}
|
|
||||||
return (double) amountObj;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "BolusCommand{" +
|
return "BolusCommand{" +
|
||||||
|
|
|
@ -93,25 +93,17 @@ public class SetTbrCommand extends BaseCommand {
|
||||||
log.debug("SetTbrCommand: 3. getting/setting basal percentage in " + scripter.currentMenu);
|
log.debug("SetTbrCommand: 3. getting/setting basal percentage in " + scripter.currentMenu);
|
||||||
retries = 30;
|
retries = 30;
|
||||||
|
|
||||||
double currentPercentage = -100;
|
double currentPercentage = scripter.readBlinkingValue(Double.class, MenuAttribute.BASAL_RATE);
|
||||||
while (currentPercentage != percentage && retries >= 0) {
|
while (currentPercentage != percentage && retries >= 0) {
|
||||||
retries--;
|
retries--;
|
||||||
Object percentageObj = scripter.currentMenu.getAttribute(MenuAttribute.BASAL_RATE);
|
currentPercentage = scripter.readBlinkingValue(Double.class, MenuAttribute.BASAL_RATE);
|
||||||
|
if (currentPercentage != percentage) {
|
||||||
if (percentageObj != null && (percentageObj instanceof Double)) {
|
int requestedPercentage = (int) percentage;
|
||||||
currentPercentage = ((Double) percentageObj).doubleValue();
|
int actualPercentage = (int) currentPercentage;
|
||||||
|
int steps = (requestedPercentage - actualPercentage) / 10;
|
||||||
if (currentPercentage != percentage) {
|
log.debug("Adjusting basal(" + requestedPercentage + "/" + actualPercentage + ") with " + steps + " steps and " + retries + " retries left");
|
||||||
int requestedPercentage = (int) percentage;
|
scripter.step(steps, (steps < 0 ? RuffyScripter.Key.DOWN : RuffyScripter.Key.UP), 500);
|
||||||
int actualPercentage = (int) currentPercentage;
|
scripter.waitForScreenUpdate(1000);
|
||||||
int steps = (requestedPercentage - actualPercentage) / 10;
|
|
||||||
log.debug("Adjusting basal(" + requestedPercentage + "/" + actualPercentage + ") with " + steps + " steps and " + retries + " retries left");
|
|
||||||
scripter.step(steps, (steps < 0 ? RuffyScripter.Key.DOWN : RuffyScripter.Key.UP), 500);
|
|
||||||
scripter.waitForScreenUpdate(1000);
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
|
||||||
currentPercentage = -100;
|
|
||||||
}
|
}
|
||||||
scripter.waitForScreenUpdate(1000);
|
scripter.waitForScreenUpdate(1000);
|
||||||
}
|
}
|
||||||
|
@ -120,20 +112,8 @@ public class SetTbrCommand extends BaseCommand {
|
||||||
|
|
||||||
log.debug("4. checking basal percentage in " + scripter.currentMenu);
|
log.debug("4. checking basal percentage in " + scripter.currentMenu);
|
||||||
scripter.waitForScreenUpdate(1000);
|
scripter.waitForScreenUpdate(1000);
|
||||||
currentPercentage = -1000;
|
currentPercentage = scripter.readBlinkingValue(Double.class, MenuAttribute.BASAL_RATE);
|
||||||
retries = 10;
|
if (currentPercentage != percentage)
|
||||||
while (currentPercentage < 0 && retries >= 0) {
|
|
||||||
retries--;
|
|
||||||
Object percentageObj = scripter.currentMenu.getAttribute(MenuAttribute.BASAL_RATE);
|
|
||||||
|
|
||||||
if (percentageObj != null && (percentageObj instanceof Double)) {
|
|
||||||
currentPercentage = ((Double) percentageObj).doubleValue();
|
|
||||||
} else {
|
|
||||||
scripter.waitForScreenUpdate(1000);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (retries < 0 || currentPercentage != percentage)
|
|
||||||
throw new CommandException().message("Unable to set percentage. Requested: " + percentage + ", value displayed on pump: " + currentPercentage);
|
throw new CommandException().message("Unable to set percentage. Requested: " + percentage + ", value displayed on pump: " + currentPercentage);
|
||||||
|
|
||||||
if (currentPercentage != 100) {
|
if (currentPercentage != 100) {
|
||||||
|
@ -155,47 +135,31 @@ public class SetTbrCommand extends BaseCommand {
|
||||||
log.debug("6. getting/setting duration in " + scripter.currentMenu);
|
log.debug("6. getting/setting duration in " + scripter.currentMenu);
|
||||||
retries = 30;
|
retries = 30;
|
||||||
|
|
||||||
double currentDuration = -100;
|
double currentDuration = scripter.readDisplayedDuration();
|
||||||
while (currentDuration != duration && retries >= 0) {
|
while (currentDuration != duration && retries >= 0) {
|
||||||
retries--;
|
retries--;
|
||||||
Object durationObj = scripter.currentMenu.getAttribute(MenuAttribute.RUNTIME);
|
currentDuration = scripter.readDisplayedDuration();
|
||||||
log.debug("Requested time: " + duration + " actual time: " + durationObj);
|
log.debug("Requested time: " + duration + " actual time: " + currentDuration);
|
||||||
if (durationObj != null && durationObj instanceof MenuTime) {
|
if (currentDuration != duration) {
|
||||||
MenuTime time = (MenuTime) durationObj;
|
int requestedDuration = (int) duration;
|
||||||
currentDuration = (time.getHour() * 60) + time.getMinute();
|
int actualDuration = (int) currentDuration;
|
||||||
if (currentDuration != duration) {
|
int steps = (requestedDuration - actualDuration) / 15;
|
||||||
int requestedDuration = (int) duration;
|
if (currentDuration + (steps * 15) < requestedDuration)
|
||||||
int actualDuration = (int) currentDuration;
|
steps++;
|
||||||
int steps = (requestedDuration - actualDuration) / 15;
|
else if (currentDuration + (steps * 15) > requestedDuration)
|
||||||
if (currentDuration + (steps * 15) < requestedDuration)
|
steps--;
|
||||||
steps++;
|
log.debug("Adjusting duration(" + requestedDuration + "/" + actualDuration + ") with " + steps + " steps and " + retries + " retries left");
|
||||||
else if (currentDuration + (steps * 15) > requestedDuration)
|
scripter.step(steps, (steps > 0 ? RuffyScripter.Key.UP : RuffyScripter.Key.DOWN), 500);
|
||||||
steps--;
|
scripter.waitForScreenUpdate(1000);
|
||||||
log.debug("Adjusting duration(" + requestedDuration + "/" + actualDuration + ") with " + steps + " steps and " + retries + " retries left");
|
|
||||||
scripter.step(steps, (steps > 0 ? RuffyScripter.Key.UP : RuffyScripter.Key.DOWN), 500);
|
|
||||||
scripter.waitForScreenUpdate(1000);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
scripter.waitForScreenUpdate(1000);
|
|
||||||
}
|
}
|
||||||
if (currentDuration < 0 || retries < 0)
|
if (currentDuration < 0 || retries < 0)
|
||||||
throw new CommandException().message("unable to set duration, requested:" + duration + ", displayed on pump: " + currentDuration);
|
throw new CommandException().message("unable to set duration, requested:" + duration + ", displayed on pump: " + currentDuration);
|
||||||
|
|
||||||
log.debug("7. checking duration in " + scripter.currentMenu);
|
log.debug("7. checking duration in " + scripter.currentMenu);
|
||||||
scripter.waitForScreenUpdate(1000);
|
scripter.waitForScreenUpdate(1000);
|
||||||
currentDuration = -1000;
|
currentDuration = scripter.readDisplayedDuration();
|
||||||
retries = 10;
|
if (currentDuration != duration)
|
||||||
while (currentDuration < 0 && retries >= 0) {
|
|
||||||
retries--;
|
|
||||||
Object durationObj = scripter.currentMenu.getAttribute(MenuAttribute.RUNTIME);
|
|
||||||
|
|
||||||
if (durationObj != null && durationObj instanceof MenuTime) {
|
|
||||||
MenuTime time = (MenuTime) durationObj;
|
|
||||||
currentDuration = (time.getHour() * 60) + time.getMinute();
|
|
||||||
} else
|
|
||||||
scripter.waitForScreenUpdate(1000);
|
|
||||||
}
|
|
||||||
if (retries < 0 || currentDuration != duration)
|
|
||||||
throw new CommandException().message("wrong duration! Requested: " + duration + ", displayed on pump: " + currentDuration);
|
throw new CommandException().message("wrong duration! Requested: " + duration + ", displayed on pump: " + currentDuration);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -216,6 +180,7 @@ public class SetTbrCommand extends BaseCommand {
|
||||||
// TODO how probable is it, that a totally unrelated error (like occlusion alert)
|
// TODO how probable is it, that a totally unrelated error (like occlusion alert)
|
||||||
// is raised at this point, which we'd cancel together with the TBR cancelled alert?
|
// is raised at this point, which we'd cancel together with the TBR cancelled alert?
|
||||||
if (percentage == 100 && scripter.currentMenu.getType() == WARNING_OR_ERROR) {
|
if (percentage == 100 && scripter.currentMenu.getType() == WARNING_OR_ERROR) {
|
||||||
|
// TODO extract method confirmAlert(alert)
|
||||||
scripter.pressCheckKey();
|
scripter.pressCheckKey();
|
||||||
retries++;
|
retries++;
|
||||||
cancelledError = true;
|
cancelledError = true;
|
||||||
|
|
|
@ -12,8 +12,6 @@ import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
|
|
||||||
import de.jotomo.ruffyscripter.RuffyScripter;
|
|
||||||
|
|
||||||
public class SetTbrCommandAlt extends BaseCommand {
|
public class SetTbrCommandAlt extends BaseCommand {
|
||||||
private static final Logger log = LoggerFactory.getLogger(SetTbrCommand.class);
|
private static final Logger log = LoggerFactory.getLogger(SetTbrCommand.class);
|
||||||
|
|
||||||
|
@ -106,7 +104,7 @@ public class SetTbrCommandAlt extends BaseCommand {
|
||||||
|
|
||||||
private void inputTbrPercentage() {
|
private void inputTbrPercentage() {
|
||||||
scripter.verifyMenuIsDisplayed(MenuType.TBR_SET);
|
scripter.verifyMenuIsDisplayed(MenuType.TBR_SET);
|
||||||
long currentPercent = readDisplayedTbrPercentage();
|
long currentPercent = scripter.readBlinkingValue(Long.class, MenuAttribute.BASAL_RATE);
|
||||||
log.debug("Current TBR %: " + currentPercent);
|
log.debug("Current TBR %: " + currentPercent);
|
||||||
long percentageChange = percentage - currentPercent;
|
long percentageChange = percentage - currentPercent;
|
||||||
long percentageSteps = percentageChange / 10;
|
long percentageSteps = percentageChange / 10;
|
||||||
|
@ -130,7 +128,7 @@ public class SetTbrCommandAlt extends BaseCommand {
|
||||||
|
|
||||||
private void verifyDisplayedTbrPercentage() {
|
private void verifyDisplayedTbrPercentage() {
|
||||||
scripter.verifyMenuIsDisplayed(MenuType.TBR_SET);
|
scripter.verifyMenuIsDisplayed(MenuType.TBR_SET);
|
||||||
long displayedPercentage = readDisplayedTbrPercentage();
|
long displayedPercentage = scripter.readBlinkingValue(Long.class, MenuAttribute.BASAL_RATE);
|
||||||
if (displayedPercentage != percentage) {
|
if (displayedPercentage != percentage) {
|
||||||
log.debug("Final displayed TBR percentage: " + displayedPercentage);
|
log.debug("Final displayed TBR percentage: " + displayedPercentage);
|
||||||
throw new CommandException().message("Failed to set TBR percentage");
|
throw new CommandException().message("Failed to set TBR percentage");
|
||||||
|
@ -138,7 +136,8 @@ public class SetTbrCommandAlt extends BaseCommand {
|
||||||
|
|
||||||
// check again to ensure the displayed value hasn't change due to due scrolling taking extremely long
|
// check again to ensure the displayed value hasn't change due to due scrolling taking extremely long
|
||||||
SystemClock.sleep(2000);
|
SystemClock.sleep(2000);
|
||||||
long refreshedDisplayedTbrPecentage = readDisplayedTbrPercentage();
|
scripter.verifyMenuIsDisplayed(MenuType.TBR_SET);
|
||||||
|
long refreshedDisplayedTbrPecentage = scripter.readBlinkingValue(Long.class, MenuAttribute.BASAL_RATE);
|
||||||
if (displayedPercentage != refreshedDisplayedTbrPecentage) {
|
if (displayedPercentage != refreshedDisplayedTbrPecentage) {
|
||||||
throw new CommandException().message("Failed to set TBR percentage: " +
|
throw new CommandException().message("Failed to set TBR percentage: " +
|
||||||
"percentage changed after input stopped from "
|
"percentage changed after input stopped from "
|
||||||
|
@ -146,21 +145,9 @@ public class SetTbrCommandAlt extends BaseCommand {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private long readDisplayedTbrPercentage() {
|
|
||||||
// TODO v2 add timeout? Currently the command execution timeout would trigger if exceeded
|
|
||||||
Object percentageObj = scripter.currentMenu.getAttribute(MenuAttribute.BASAL_RATE);
|
|
||||||
// this as a bit hacky, the display value is blinking, so we might catch that, so
|
|
||||||
// keep trying till we get the Double we want
|
|
||||||
while (!(percentageObj instanceof Double)) {
|
|
||||||
scripter.waitForMenuUpdate();
|
|
||||||
percentageObj = scripter.currentMenu.getAttribute(MenuAttribute.BASAL_RATE);
|
|
||||||
}
|
|
||||||
return ((Double) percentageObj).longValue();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void inputTbrDuration() {
|
private void inputTbrDuration() {
|
||||||
scripter.verifyMenuIsDisplayed(MenuType.TBR_DURATION);
|
scripter.verifyMenuIsDisplayed(MenuType.TBR_DURATION);
|
||||||
long currentDuration = readDisplayedTbrDuration();
|
long currentDuration = scripter.readDisplayedDuration();
|
||||||
if (currentDuration % 15 != 0) {
|
if (currentDuration % 15 != 0) {
|
||||||
// The duration displayed is how long an active TBR will still run,
|
// The duration displayed is how long an active TBR will still run,
|
||||||
// which might be something like 0:13, hence not in 15 minute steps.
|
// which might be something like 0:13, hence not in 15 minute steps.
|
||||||
|
@ -170,7 +157,7 @@ public class SetTbrCommandAlt extends BaseCommand {
|
||||||
scripter.verifyMenuIsDisplayed(MenuType.TBR_DURATION);
|
scripter.verifyMenuIsDisplayed(MenuType.TBR_DURATION);
|
||||||
scripter.pressUpKey();
|
scripter.pressUpKey();
|
||||||
scripter.waitForMenuUpdate();
|
scripter.waitForMenuUpdate();
|
||||||
currentDuration = readDisplayedTbrDuration();
|
currentDuration = scripter.readDisplayedDuration();
|
||||||
}
|
}
|
||||||
log.debug("Current TBR duration: " + currentDuration);
|
log.debug("Current TBR duration: " + currentDuration);
|
||||||
long durationChange = duration - currentDuration;
|
long durationChange = duration - currentDuration;
|
||||||
|
@ -195,7 +182,7 @@ public class SetTbrCommandAlt extends BaseCommand {
|
||||||
|
|
||||||
private void verifyDisplayedTbrDuration() {
|
private void verifyDisplayedTbrDuration() {
|
||||||
scripter.verifyMenuIsDisplayed(MenuType.TBR_DURATION);
|
scripter.verifyMenuIsDisplayed(MenuType.TBR_DURATION);
|
||||||
long displayedDuration = readDisplayedTbrDuration();
|
long displayedDuration = scripter.readDisplayedDuration();
|
||||||
if (displayedDuration != duration) {
|
if (displayedDuration != duration) {
|
||||||
log.debug("Final displayed TBR duration: " + displayedDuration);
|
log.debug("Final displayed TBR duration: " + displayedDuration);
|
||||||
throw new CommandException().message("Failed to set TBR duration");
|
throw new CommandException().message("Failed to set TBR duration");
|
||||||
|
@ -203,7 +190,8 @@ public class SetTbrCommandAlt extends BaseCommand {
|
||||||
|
|
||||||
// check again to ensure the displayed value hasn't change due to due scrolling taking extremely long
|
// check again to ensure the displayed value hasn't change due to due scrolling taking extremely long
|
||||||
SystemClock.sleep(2000);
|
SystemClock.sleep(2000);
|
||||||
long refreshedDisplayedTbrDuration = readDisplayedTbrDuration();
|
scripter.verifyMenuIsDisplayed(MenuType.TBR_DURATION);
|
||||||
|
long refreshedDisplayedTbrDuration = scripter.readDisplayedDuration();
|
||||||
if (displayedDuration != refreshedDisplayedTbrDuration) {
|
if (displayedDuration != refreshedDisplayedTbrDuration) {
|
||||||
throw new CommandException().message("Failed to set TBR duration: " +
|
throw new CommandException().message("Failed to set TBR duration: " +
|
||||||
"duration changed after input stopped from "
|
"duration changed after input stopped from "
|
||||||
|
@ -211,19 +199,7 @@ public class SetTbrCommandAlt extends BaseCommand {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private long readDisplayedTbrDuration() {
|
|
||||||
// TODO v2 add timeout? Currently the command execution timeout would trigger if exceeded
|
|
||||||
scripter.verifyMenuIsDisplayed(MenuType.TBR_DURATION);
|
|
||||||
Object durationObj = scripter.currentMenu.getAttribute(MenuAttribute.RUNTIME);
|
|
||||||
// this as a bit hacky, the display value is blinking, so we might catch that, so
|
|
||||||
// keep trying till we get the Double we want
|
|
||||||
while (!(durationObj instanceof MenuTime)) {
|
|
||||||
scripter.waitForMenuUpdate();
|
|
||||||
durationObj = scripter.currentMenu.getAttribute(MenuAttribute.RUNTIME);
|
|
||||||
}
|
|
||||||
MenuTime duration = (MenuTime) durationObj;
|
|
||||||
return duration.getHour() * 60 + duration.getMinute();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void cancelTbrAndConfirmCancellationWarning() {
|
private void cancelTbrAndConfirmCancellationWarning() {
|
||||||
// confirm entered TBR
|
// confirm entered TBR
|
||||||
|
|
Loading…
Reference in a new issue