NSCv3: process ExtendedBolus
This commit is contained in:
parent
a2522eed9d
commit
228b2ddaca
|
@ -4,17 +4,17 @@ import info.nightscout.sdk.localmodel.entry.NsUnits
|
||||||
|
|
||||||
data class NSExtendedBolus(
|
data class NSExtendedBolus(
|
||||||
override val date: Long,
|
override val date: Long,
|
||||||
override val device: String?,
|
override val device: String? = null,
|
||||||
override val identifier: String?,
|
override val identifier: String?,
|
||||||
override val units: NsUnits?,
|
override val units: NsUnits? = null,
|
||||||
override val srvModified: Long?,
|
override val srvModified: Long? = null,
|
||||||
override val srvCreated: Long?,
|
override val srvCreated: Long? = null,
|
||||||
override val utcOffset: Long,
|
override val utcOffset: Long,
|
||||||
override val subject: String?,
|
override val subject: String? = null,
|
||||||
override var isReadOnly: Boolean,
|
override var isReadOnly: Boolean = false,
|
||||||
override val isValid: Boolean,
|
override val isValid: Boolean,
|
||||||
override val eventType: EventType,
|
override val eventType: EventType,
|
||||||
override val notes: String?,
|
override val notes: String? = null,
|
||||||
override val pumpId: Long?,
|
override val pumpId: Long?,
|
||||||
override val endId: Long?,
|
override val endId: Long?,
|
||||||
override val pumpType: String?,
|
override val pumpType: String?,
|
||||||
|
@ -22,5 +22,6 @@ data class NSExtendedBolus(
|
||||||
override var app: String? = null,
|
override var app: String? = null,
|
||||||
val duration: Long,
|
val duration: Long,
|
||||||
val enteredinsulin: Double,
|
val enteredinsulin: Double,
|
||||||
val isEmulatingTempBasal: Boolean?
|
val isEmulatingTempBasal: Boolean?,
|
||||||
|
val rate: Double?
|
||||||
) : NSTreatment
|
) : NSTreatment
|
||||||
|
|
|
@ -25,7 +25,8 @@ data class NSTemporaryBasal(
|
||||||
val isAbsolute: Boolean,
|
val isAbsolute: Boolean,
|
||||||
val type: Type,
|
val type: Type,
|
||||||
val percent: Double? = null, // when sending to NS (rate - 100)
|
val percent: Double? = null, // when sending to NS (rate - 100)
|
||||||
val absolute: Double? = null // when sending to NS (rate)
|
val absolute: Double? = null, // when sending to NS (rate)
|
||||||
|
var extendedEmulated: NSExtendedBolus? = null
|
||||||
) : NSTreatment {
|
) : NSTreatment {
|
||||||
|
|
||||||
enum class Type {
|
enum class Type {
|
||||||
|
|
|
@ -112,22 +112,23 @@ internal fun RemoteTreatment.toTreatment(): NSTreatment? {
|
||||||
date = treatmentTimestamp,
|
date = treatmentTimestamp,
|
||||||
device = device,
|
device = device,
|
||||||
identifier = identifier,
|
identifier = identifier,
|
||||||
units = NsUnits.fromString(extendedEmulated.units),
|
units = NsUnits.fromString(extendedEmulated?.units),
|
||||||
srvModified = srvModified,
|
srvModified = srvModified,
|
||||||
srvCreated = srvCreated,
|
srvCreated = srvCreated,
|
||||||
utcOffset = utcOffset ?: 0,
|
utcOffset = utcOffset ?: 0,
|
||||||
subject = subject,
|
subject = subject,
|
||||||
isReadOnly = extendedEmulated.isReadOnly ?: false,
|
isReadOnly = extendedEmulated?.isReadOnly ?: false,
|
||||||
isValid = extendedEmulated.isValid ?: true,
|
isValid = extendedEmulated?.isValid ?: true,
|
||||||
eventType = extendedEmulated.eventType,
|
eventType = EventType.COMBO_BOLUS,
|
||||||
notes = extendedEmulated.notes,
|
notes = extendedEmulated?.notes,
|
||||||
pumpId = extendedEmulated.pumpId,
|
pumpId = extendedEmulated?.pumpId,
|
||||||
endId = extendedEmulated.endId,
|
endId = extendedEmulated?.endId,
|
||||||
pumpType = extendedEmulated.pumpType,
|
pumpType = extendedEmulated?.pumpType,
|
||||||
pumpSerial = extendedEmulated.pumpSerial,
|
pumpSerial = extendedEmulated?.pumpSerial,
|
||||||
enteredinsulin = extendedEmulated.enteredinsulin ?: 0.0,
|
enteredinsulin = extendedEmulated?.enteredinsulin ?: 0.0,
|
||||||
duration = extendedEmulated.durationInMilliseconds ?: TimeUnit.MINUTES.toMillis(extendedEmulated.duration ?: 0L),
|
duration = extendedEmulated?.durationInMilliseconds ?: TimeUnit.MINUTES.toMillis(extendedEmulated?.duration ?: 0L),
|
||||||
isEmulatingTempBasal = extendedEmulated.isEmulatingTempBasal
|
isEmulatingTempBasal = extendedEmulated?.isEmulatingTempBasal,
|
||||||
|
rate = rate
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -339,7 +340,8 @@ internal fun RemoteTreatment.toTreatment(): NSTreatment? {
|
||||||
pumpSerial = this.pumpSerial,
|
pumpSerial = this.pumpSerial,
|
||||||
enteredinsulin = this.enteredinsulin,
|
enteredinsulin = this.enteredinsulin,
|
||||||
duration = this.durationInMilliseconds ?: TimeUnit.MINUTES.toMillis(this.duration ?: 0L),
|
duration = this.durationInMilliseconds ?: TimeUnit.MINUTES.toMillis(this.duration ?: 0L),
|
||||||
isEmulatingTempBasal = this.isEmulatingTempBasal
|
isEmulatingTempBasal = this.isEmulatingTempBasal,
|
||||||
|
rate = rate
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -411,33 +413,7 @@ internal fun NSTreatment.toRemoteTreatment(): RemoteTreatment? =
|
||||||
targetTop = targetTop,
|
targetTop = targetTop,
|
||||||
reason = reason.text
|
reason = reason.text
|
||||||
)
|
)
|
||||||
/*
|
|
||||||
// Convert back emulated TBR -> EB
|
|
||||||
eventType == EventType.TEMPORARY_BASAL && extendedEmulated != null ->
|
|
||||||
|
|
||||||
return RemoteTreatment(
|
|
||||||
date = treatmentTimestamp,
|
|
||||||
device = device,
|
|
||||||
identifier = identifier,
|
|
||||||
units = NsUnits.fromString(extendedEmulated.units),
|
|
||||||
srvModified = srvModified,
|
|
||||||
srvCreated = srvCreated,
|
|
||||||
utcOffset = utcOffset ?: 0,
|
|
||||||
subject = subject,
|
|
||||||
isReadOnly = extendedEmulated.isReadOnly ?: false,
|
|
||||||
isValid = extendedEmulated.isValid ?: true,
|
|
||||||
eventType = extendedEmulated.eventType,
|
|
||||||
notes = extendedEmulated.notes,
|
|
||||||
pumpId = extendedEmulated.pumpId,
|
|
||||||
endId = extendedEmulated.endId,
|
|
||||||
pumpType = extendedEmulated.pumpType,
|
|
||||||
pumpSerial = extendedEmulated.pumpSerial,
|
|
||||||
enteredinsulin = extendedEmulated.enteredinsulin ?: 0.0,
|
|
||||||
duration = extendedEmulated.durationInMilliseconds ?: TimeUnit.MINUTES.toMillis(extendedEmulated.duration ?: 0L),
|
|
||||||
isEmulatingTempbasal = extendedEmulated.isEmulatingTempBasal
|
|
||||||
)
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
is NSTemporaryBasal -> RemoteTreatment(
|
is NSTemporaryBasal -> RemoteTreatment(
|
||||||
date = date,
|
date = date,
|
||||||
device = device,
|
device = device,
|
||||||
|
@ -460,7 +436,8 @@ internal fun NSTreatment.toRemoteTreatment(): RemoteTreatment? =
|
||||||
absolute = absolute,
|
absolute = absolute,
|
||||||
percent = percent,
|
percent = percent,
|
||||||
rate = rate,
|
rate = rate,
|
||||||
type = type.name
|
type = type.name,
|
||||||
|
extendedEmulated = extendedEmulated?.toRemoteTreatment()
|
||||||
)
|
)
|
||||||
|
|
||||||
is NSEffectiveProfileSwitch -> RemoteTreatment(
|
is NSEffectiveProfileSwitch -> RemoteTreatment(
|
||||||
|
@ -582,7 +559,8 @@ internal fun NSTreatment.toRemoteTreatment(): RemoteTreatment? =
|
||||||
reason = reason.name
|
reason = reason.name
|
||||||
)
|
)
|
||||||
|
|
||||||
is NSExtendedBolus -> RemoteTreatment(
|
is NSExtendedBolus ->
|
||||||
|
RemoteTreatment(
|
||||||
date = date,
|
date = date,
|
||||||
device = device,
|
device = device,
|
||||||
identifier = identifier,
|
identifier = identifier,
|
||||||
|
@ -594,15 +572,18 @@ internal fun NSTreatment.toRemoteTreatment(): RemoteTreatment? =
|
||||||
isReadOnly = isReadOnly,
|
isReadOnly = isReadOnly,
|
||||||
isValid = isValid,
|
isValid = isValid,
|
||||||
eventType = eventType,
|
eventType = eventType,
|
||||||
|
duration = TimeUnit.MILLISECONDS.toMinutes(duration),
|
||||||
|
durationInMilliseconds = duration,
|
||||||
notes = notes,
|
notes = notes,
|
||||||
|
splitNow = 0,
|
||||||
|
splitExt = 100,
|
||||||
|
enteredinsulin = enteredinsulin,
|
||||||
|
relative = rate,
|
||||||
|
isEmulatingTempBasal = isEmulatingTempBasal,
|
||||||
pumpId = pumpId,
|
pumpId = pumpId,
|
||||||
endId = endId,
|
endId = endId,
|
||||||
pumpType = pumpType,
|
pumpType = pumpType,
|
||||||
pumpSerial = pumpSerial,
|
pumpSerial = pumpSerial
|
||||||
enteredinsulin = enteredinsulin,
|
|
||||||
duration = TimeUnit.MILLISECONDS.toMinutes(duration),
|
|
||||||
durationInMilliseconds = duration,
|
|
||||||
isEmulatingTempBasal = isEmulatingTempBasal
|
|
||||||
)
|
)
|
||||||
|
|
||||||
else -> null
|
else -> null
|
||||||
|
|
|
@ -74,7 +74,7 @@ internal data class RemoteTreatment(
|
||||||
@SerializedName("isEmulatingTempBasal") val isEmulatingTempBasal: Boolean? = null, // boolean "Combo Bolus", "extendedEmulated" (not in doc see below)
|
@SerializedName("isEmulatingTempBasal") val isEmulatingTempBasal: Boolean? = null, // boolean "Combo Bolus", "extendedEmulated" (not in doc see below)
|
||||||
@SerializedName("isAnnouncement") val isAnnouncement: Boolean? = null, // boolean "Announcement"
|
@SerializedName("isAnnouncement") val isAnnouncement: Boolean? = null, // boolean "Announcement"
|
||||||
@SerializedName("rate") val rate: Double? = null, // Double "Temp Basal" absolute rate (could be calculated with percent and profile information...)
|
@SerializedName("rate") val rate: Double? = null, // Double "Temp Basal" absolute rate (could be calculated with percent and profile information...)
|
||||||
@SerializedName("extendedEmulated") val extendedEmulated: RemoteTreatment? = null, // Gson of emulated EB
|
@SerializedName("extendedEmulated") var extendedEmulated: RemoteTreatment? = null, // Gson of emulated EB
|
||||||
@SerializedName("timeshift") val timeshift: Long? = null, // integer "Profile Switch"
|
@SerializedName("timeshift") val timeshift: Long? = null, // integer "Profile Switch"
|
||||||
@SerializedName("percentage") val percentage: Int? = null, // integer "Profile Switch"
|
@SerializedName("percentage") val percentage: Int? = null, // integer "Profile Switch"
|
||||||
@SerializedName("isBasalInsulin") val isBasalInsulin: Boolean? = null // boolean "Bolus"
|
@SerializedName("isBasalInsulin") val isBasalInsulin: Boolean? = null // boolean "Bolus"
|
||||||
|
|
|
@ -48,7 +48,7 @@ data class ExtendedBolus(
|
||||||
require(duration > 0)
|
require(duration > 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun contentEqualsTo(other: ExtendedBolus): Boolean =
|
fun contentEqualsTo(other: ExtendedBolus): Boolean =
|
||||||
isValid == other.isValid &&
|
isValid == other.isValid &&
|
||||||
timestamp == other.timestamp &&
|
timestamp == other.timestamp &&
|
||||||
utcOffset == other.utcOffset &&
|
utcOffset == other.utcOffset &&
|
||||||
|
|
|
@ -38,6 +38,7 @@ import info.nightscout.plugins.sync.nsclientV3.extensions.toNSBolus
|
||||||
import info.nightscout.plugins.sync.nsclientV3.extensions.toNSBolusWizard
|
import info.nightscout.plugins.sync.nsclientV3.extensions.toNSBolusWizard
|
||||||
import info.nightscout.plugins.sync.nsclientV3.extensions.toNSCarbs
|
import info.nightscout.plugins.sync.nsclientV3.extensions.toNSCarbs
|
||||||
import info.nightscout.plugins.sync.nsclientV3.extensions.toNSEffectiveProfileSwitch
|
import info.nightscout.plugins.sync.nsclientV3.extensions.toNSEffectiveProfileSwitch
|
||||||
|
import info.nightscout.plugins.sync.nsclientV3.extensions.toNSExtendedBolus
|
||||||
import info.nightscout.plugins.sync.nsclientV3.extensions.toNSFood
|
import info.nightscout.plugins.sync.nsclientV3.extensions.toNSFood
|
||||||
import info.nightscout.plugins.sync.nsclientV3.extensions.toNSOfflineEvent
|
import info.nightscout.plugins.sync.nsclientV3.extensions.toNSOfflineEvent
|
||||||
import info.nightscout.plugins.sync.nsclientV3.extensions.toNSProfileSwitch
|
import info.nightscout.plugins.sync.nsclientV3.extensions.toNSProfileSwitch
|
||||||
|
@ -387,7 +388,14 @@ class NSClientV3Plugin @Inject constructor(
|
||||||
}
|
}
|
||||||
dataPair.value.toNSTemporaryBasal(profile)
|
dataPair.value.toNSTemporaryBasal(profile)
|
||||||
}
|
}
|
||||||
// is DataSyncSelector.PairExtendedBolus -> dataPair.value.toJson(false, profileFunction.getProfile(dataPair.value.timestamp), dateUtil)
|
is DataSyncSelector.PairExtendedBolus -> {
|
||||||
|
val profile = profileFunction.getProfile(dataPair.value.timestamp)
|
||||||
|
if (profile == null) {
|
||||||
|
dataSyncSelector.confirmLastExtendedBolusIdIfGreater(dataPair.id)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
dataPair.value.toNSExtendedBolus(profile)
|
||||||
|
}
|
||||||
is DataSyncSelector.PairProfileSwitch -> dataPair.value.toNSProfileSwitch(dateUtil)
|
is DataSyncSelector.PairProfileSwitch -> dataPair.value.toNSProfileSwitch(dateUtil)
|
||||||
is DataSyncSelector.PairEffectiveProfileSwitch -> dataPair.value.toNSEffectiveProfileSwitch(dateUtil)
|
is DataSyncSelector.PairEffectiveProfileSwitch -> dataPair.value.toNSEffectiveProfileSwitch(dateUtil)
|
||||||
is DataSyncSelector.PairOfflineEvent -> dataPair.value.toNSOfflineEvent()
|
is DataSyncSelector.PairOfflineEvent -> dataPair.value.toNSOfflineEvent()
|
||||||
|
@ -463,7 +471,15 @@ class NSClientV3Plugin @Inject constructor(
|
||||||
}
|
}
|
||||||
dataSyncSelector.confirmLastTemporaryBasalIdIfGreater(dataPair.id)
|
dataSyncSelector.confirmLastTemporaryBasalIdIfGreater(dataPair.id)
|
||||||
}
|
}
|
||||||
// is DataSyncSelector.PairExtendedBolus -> dataPair.value.toJson(false, profileFunction.getProfile(dataPair.value.timestamp), dateUtil)
|
is DataSyncSelector.PairExtendedBolus -> {
|
||||||
|
if (result.response == 201) { // created
|
||||||
|
dataPair.value.interfaceIDs.nightscoutId = result.identifier
|
||||||
|
storeDataForDb.nsIdExtendedBoluses.add(dataPair.value)
|
||||||
|
storeDataForDb.scheduleNsIdUpdate()
|
||||||
|
}
|
||||||
|
dataSyncSelector.confirmLastExtendedBolusIdIfGreater(dataPair.id)
|
||||||
|
}
|
||||||
|
|
||||||
is DataSyncSelector.PairProfileSwitch -> {
|
is DataSyncSelector.PairProfileSwitch -> {
|
||||||
if (result.response == 201) { // created
|
if (result.response == 201) { // created
|
||||||
dataPair.value.interfaceIDs.nightscoutId = result.identifier
|
dataPair.value.interfaceIDs.nightscoutId = result.identifier
|
||||||
|
|
|
@ -1,8 +1,12 @@
|
||||||
package info.nightscout.plugins.sync.nsclientV3.extensions
|
package info.nightscout.plugins.sync.nsclientV3.extensions
|
||||||
|
|
||||||
|
import info.nightscout.core.extensions.toTemporaryBasal
|
||||||
import info.nightscout.database.entities.ExtendedBolus
|
import info.nightscout.database.entities.ExtendedBolus
|
||||||
import info.nightscout.database.entities.embedments.InterfaceIDs
|
import info.nightscout.database.entities.embedments.InterfaceIDs
|
||||||
|
import info.nightscout.interfaces.profile.Profile
|
||||||
|
import info.nightscout.sdk.localmodel.treatment.EventType
|
||||||
import info.nightscout.sdk.localmodel.treatment.NSExtendedBolus
|
import info.nightscout.sdk.localmodel.treatment.NSExtendedBolus
|
||||||
|
import info.nightscout.sdk.localmodel.treatment.NSTreatment
|
||||||
|
|
||||||
fun NSExtendedBolus.toExtendedBolus(): ExtendedBolus =
|
fun NSExtendedBolus.toExtendedBolus(): ExtendedBolus =
|
||||||
ExtendedBolus(
|
ExtendedBolus(
|
||||||
|
@ -14,3 +18,25 @@ fun NSExtendedBolus.toExtendedBolus(): ExtendedBolus =
|
||||||
isEmulatingTempBasal = isEmulatingTempBasal ?: false,
|
isEmulatingTempBasal = isEmulatingTempBasal ?: false,
|
||||||
interfaceIDs_backing = InterfaceIDs(nightscoutId = identifier, pumpId = pumpId, pumpType = InterfaceIDs.PumpType.fromString(pumpType), pumpSerial = pumpSerial, endId = endId)
|
interfaceIDs_backing = InterfaceIDs(nightscoutId = identifier, pumpId = pumpId, pumpType = InterfaceIDs.PumpType.fromString(pumpType), pumpSerial = pumpSerial, endId = endId)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
fun ExtendedBolus.toNSExtendedBolus(profile: Profile, convertToTemporaryBasal: Boolean = true): NSTreatment =
|
||||||
|
if (isEmulatingTempBasal && convertToTemporaryBasal)
|
||||||
|
this.toTemporaryBasal(profile).toNSTemporaryBasal(profile).also {
|
||||||
|
it.extendedEmulated = toNSExtendedBolus(profile, convertToTemporaryBasal = false) as NSExtendedBolus
|
||||||
|
}
|
||||||
|
else
|
||||||
|
NSExtendedBolus(
|
||||||
|
eventType = EventType.COMBO_BOLUS,
|
||||||
|
isValid = isValid,
|
||||||
|
date = timestamp,
|
||||||
|
utcOffset = utcOffset,
|
||||||
|
enteredinsulin = amount,
|
||||||
|
duration = duration,
|
||||||
|
isEmulatingTempBasal = isEmulatingTempBasal,
|
||||||
|
rate = rate,
|
||||||
|
identifier = interfaceIDs.nightscoutId,
|
||||||
|
pumpId = interfaceIDs.pumpId,
|
||||||
|
pumpType = interfaceIDs.pumpType?.name,
|
||||||
|
pumpSerial = interfaceIDs.pumpSerial,
|
||||||
|
endId = interfaceIDs.endId
|
||||||
|
)
|
||||||
|
|
|
@ -0,0 +1,59 @@
|
||||||
|
package info.nightscout.plugins.sync.nsclientV3.extensions
|
||||||
|
|
||||||
|
import info.nightscout.androidaps.TestBaseWithProfile
|
||||||
|
import info.nightscout.database.entities.ExtendedBolus
|
||||||
|
import info.nightscout.database.entities.embedments.InterfaceIDs
|
||||||
|
import info.nightscout.sdk.localmodel.treatment.NSExtendedBolus
|
||||||
|
import info.nightscout.sdk.localmodel.treatment.NSTemporaryBasal
|
||||||
|
import info.nightscout.sdk.mapper.convertToRemoteAndBack
|
||||||
|
import org.junit.jupiter.api.Assertions
|
||||||
|
import org.junit.jupiter.api.Test
|
||||||
|
|
||||||
|
@Suppress("SpellCheckingInspection")
|
||||||
|
internal class ExtendedBolusExtensionKtTest : TestBaseWithProfile() {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun toExtendedBolus() {
|
||||||
|
var extendedBolus = ExtendedBolus(
|
||||||
|
timestamp = 10000,
|
||||||
|
isValid = true,
|
||||||
|
amount = 2.0,
|
||||||
|
isEmulatingTempBasal = false,
|
||||||
|
duration = 3600000,
|
||||||
|
interfaceIDs_backing = InterfaceIDs(
|
||||||
|
nightscoutId = "nightscoutId",
|
||||||
|
pumpId = 11000,
|
||||||
|
pumpType = InterfaceIDs.PumpType.DANA_I,
|
||||||
|
pumpSerial = "bbbb"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
var extendedBolus2 = (extendedBolus.toNSExtendedBolus(validProfile).convertToRemoteAndBack() as NSExtendedBolus).toExtendedBolus()
|
||||||
|
Assertions.assertTrue(extendedBolus.contentEqualsTo(extendedBolus2))
|
||||||
|
Assertions.assertTrue(extendedBolus.interfaceIdsEqualsTo(extendedBolus2))
|
||||||
|
|
||||||
|
extendedBolus = ExtendedBolus(
|
||||||
|
timestamp = 10000,
|
||||||
|
isValid = true,
|
||||||
|
amount = 4.0,
|
||||||
|
isEmulatingTempBasal = true,
|
||||||
|
duration = 36000,
|
||||||
|
interfaceIDs_backing = InterfaceIDs(
|
||||||
|
nightscoutId = "nightscoutId",
|
||||||
|
pumpId = 11000,
|
||||||
|
pumpType = InterfaceIDs.PumpType.DANA_I,
|
||||||
|
pumpSerial = "bbbb"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
val converted = extendedBolus.toNSExtendedBolus(validProfile)
|
||||||
|
Assertions.assertTrue(converted is NSTemporaryBasal)
|
||||||
|
Assertions.assertNotNull((converted as NSTemporaryBasal).extendedEmulated)
|
||||||
|
val convertedBack = converted.convertToRemoteAndBack()
|
||||||
|
Assertions.assertTrue(convertedBack is NSExtendedBolus)
|
||||||
|
|
||||||
|
extendedBolus2 = (extendedBolus.toNSExtendedBolus(validProfile).convertToRemoteAndBack() as NSExtendedBolus).toExtendedBolus()
|
||||||
|
Assertions.assertTrue(extendedBolus.contentEqualsTo(extendedBolus2))
|
||||||
|
Assertions.assertTrue(extendedBolus.interfaceIdsEqualsTo(extendedBolus2))
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue