diff options
author | hannibal2 <24389977+hannibal00212@users.noreply.github.com> | 2023-03-23 15:38:34 +0100 |
---|---|---|
committer | hannibal2 <24389977+hannibal00212@users.noreply.github.com> | 2023-03-23 15:38:34 +0100 |
commit | 53303c391dc335bc676263f5be75bcc110a74446 (patch) | |
tree | bbac55772616c16d041d4753ecd36565441286cb /src/main/java/at/hannibal2/skyhanni | |
parent | afb4dae8eda1403079d73480dd3621d5e361f21f (diff) | |
download | skyhanni-53303c391dc335bc676263f5be75bcc110a74446.tar.gz skyhanni-53303c391dc335bc676263f5be75bcc110a74446.tar.bz2 skyhanni-53303c391dc335bc676263f5be75bcc110a74446.zip |
removed toMutableList in render list logic and prevent ConcurrentModificationException
Diffstat (limited to 'src/main/java/at/hannibal2/skyhanni')
14 files changed, 119 insertions, 82 deletions
diff --git a/src/main/java/at/hannibal2/skyhanni/features/bingo/BingoCardDisplay.kt b/src/main/java/at/hannibal2/skyhanni/features/bingo/BingoCardDisplay.kt index f88ec4b59..d97e1c42e 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/bingo/BingoCardDisplay.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/bingo/BingoCardDisplay.kt @@ -26,7 +26,7 @@ class BingoCardDisplay { private val MAX_COMMUNITY_GOALS = 5 private var tick = 0 - private val display = mutableListOf<String>() + private var display = listOf<String>() private val config get() = SkyHanniMod.feature.bingo private val goalCompletePattern = Pattern.compile("§6§lBINGO GOAL COMPLETE! §r§e(.*)") @@ -121,20 +121,25 @@ class BingoCardDisplay { } private fun update() { - display.clear() + display = drawDisplay() + } + + private fun drawDisplay(): MutableList<String> { + val newList = mutableListOf<String>() - display.add("Community Goals") + newList.add("Community Goals") if (communityGoals.isEmpty()) { - display.add("§cOpen the §e/bingo §ccard.") + newList.add("§cOpen the §e/bingo §ccard.") } else { - communityGoals.mapTo(display) { " " + it.description + if (it.done) " §aDONE" else "" } + communityGoals.mapTo(newList) { " " + it.description + if (it.done) " §aDONE" else "" } val todo = personalGoals.filter { !it.done } val done = MAX_PERSONAL_GOALS - todo.size - display.add(" ") - display.add("Personal Goals: ($done/$MAX_PERSONAL_GOALS done)") - todo.mapTo(display) { " " + it.description } + newList.add(" ") + newList.add("Personal Goals: ($done/$MAX_PERSONAL_GOALS done)") + todo.mapTo(newList) { " " + it.description } } + return newList } private var lastSneak = false diff --git a/src/main/java/at/hannibal2/skyhanni/features/bingo/BingoNextStepHelper.kt b/src/main/java/at/hannibal2/skyhanni/features/bingo/BingoNextStepHelper.kt index 75c755de3..af909605e 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/bingo/BingoNextStepHelper.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/bingo/BingoNextStepHelper.kt @@ -28,7 +28,7 @@ class BingoNextStepHelper { companion object { private val finalSteps = mutableListOf<NextStep>() private val currentSteps = mutableListOf<NextStep>() - val currentHelp = mutableListOf<String>() + var currentHelp = listOf<String>() fun command() { updateResult(true) @@ -42,18 +42,23 @@ class BingoNextStepHelper { if (print) println() } - currentHelp.clear() - currentHelp.add("Bingo Step Helper") + currentHelp = drawDisplay(print) + } + + private fun drawDisplay(print: Boolean): MutableList<String> { + val newCurrentHelp = mutableListOf<String>() + newCurrentHelp.add("Bingo Step Helper") if (currentSteps.isEmpty()) { - currentHelp.add("§cOpen the §e/bingo §ccard.") + newCurrentHelp.add("§cOpen the §e/bingo §ccard.") } for (currentStep in currentSteps) { val text = getName(currentStep) - currentHelp.add(" §7$text") + newCurrentHelp.add(" §7$text") if (print) println(text) } if (print) println() + return newCurrentHelp } private fun printRequirements(step: NextStep, print: Boolean, parentDone: Boolean = false, depth: Int = 0) { diff --git a/src/main/java/at/hannibal2/skyhanni/features/bingo/MinionCraftHelper.kt b/src/main/java/at/hannibal2/skyhanni/features/bingo/MinionCraftHelper.kt index b27a6290e..7662a434f 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/bingo/MinionCraftHelper.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/bingo/MinionCraftHelper.kt @@ -24,7 +24,7 @@ class MinionCraftHelper { private var minionNamePattern = Pattern.compile("(.*) Minion (.*)") private var tick = 0 - private var display = mutableListOf<String>() + private var display = listOf<String>() private var hasMinionInInventory = false private var hasItemsForMinion = false private val tierOneMinions = mutableListOf<String>() @@ -56,7 +56,7 @@ class MinionCraftHelper { } if (!hasMinionInInventory && !hasItemsForMinion) { - display.clear() + display = emptyList() return } @@ -67,14 +67,22 @@ class MinionCraftHelper { val (minions, otherItems) = loadFromInventory(mainInventory) - display.clear() + display = drawDisplay(minions, otherItems) + } + + private fun drawDisplay( + minions: MutableMap<String, String>, + otherItems: MutableMap<String, Int>, + ): MutableList<String> { + val newDisplay = mutableListOf<String>() for ((minionName, minionId) in minions) { val matcher = minionNamePattern.matcher(minionName) - if (!matcher.matches()) return + if (!matcher.matches()) continue val cleanName = matcher.group(1).removeColor() val number = matcher.group(2).romanToDecimalIfNeeded() - addMinion(cleanName, number, minionId, otherItems) + addMinion(cleanName, number, minionId, otherItems, newDisplay) } + return newDisplay } @SubscribeEvent @@ -185,10 +193,16 @@ class MinionCraftHelper { } } - private fun addMinion(name: String, minionTier: Int, minionId: String, otherItems: MutableMap<String, Int>) { + private fun addMinion( + name: String, + minionTier: Int, + minionId: String, + otherItems: MutableMap<String, Int>, + newDisplay: MutableList<String>, + ) { val nextTier = minionTier + 1 val minionName = "§9$name Minion $nextTier" - display.add(minionName) + newDisplay.add(minionName) val nextMinionId = minionId.addOneToId() for (recipe in NEUItems.getRecipes(nextMinionId)) { if (recipe !is CraftingRecipe) continue @@ -213,19 +227,19 @@ class MinionCraftHelper { val itemName = NEUItems.getItemStack(rawId).name ?: "§cName??§f" if (percentage >= 1) { val color = if (itemId.startsWith("WOOD_")) "§7" else "§a" - display.add(" $itemName§8: ${color}DONE") + newDisplay.add(" $itemName§8: ${color}DONE") otherItems[itemId] = have - needAmount } else { val format = LorenzUtils.formatPercentage(percentage) val haveFormat = LorenzUtils.formatInteger(have) val needFormat = LorenzUtils.formatInteger(needAmount) - display.add("$itemName§8: §e$format §8(§7$haveFormat§8/§7$needFormat§8)") + newDisplay.add("$itemName§8: §e$format §8(§7$haveFormat§8/§7$needFormat§8)") allDone = false } } - display.add(" ") + newDisplay.add(" ") if (allDone) { - addMinion(name, nextTier, nextMinionId, otherItems) + addMinion(name, nextTier, nextMinionId, otherItems, newDisplay) notify(minionName) } } diff --git a/src/main/java/at/hannibal2/skyhanni/features/garden/CropMoneyDisplay.kt b/src/main/java/at/hannibal2/skyhanni/features/garden/CropMoneyDisplay.kt index 4e7853c38..d0d5d64f2 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/garden/CropMoneyDisplay.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/garden/CropMoneyDisplay.kt @@ -18,7 +18,7 @@ import net.minecraftforge.fml.common.gameevent.TickEvent import java.util.* class CropMoneyDisplay { - private val display = mutableListOf<List<Any>>() + private var display = mutableListOf<List<Any>>() private val config get() = SkyHanniMod.feature.garden private var tick = 0 private var loaded = false @@ -52,9 +52,7 @@ class CropMoneyDisplay { private fun update() { init() - val newDisplay = drawNewDisplay() - display.clear() - display.addAll(newDisplay) + display = drawNewDisplay() } private fun drawNewDisplay(): MutableList<List<Any>> { diff --git a/src/main/java/at/hannibal2/skyhanni/features/garden/DicerRngDropCounter.kt b/src/main/java/at/hannibal2/skyhanni/features/garden/DicerRngDropCounter.kt index ef1ee8a82..7e87b7b91 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/garden/DicerRngDropCounter.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/garden/DicerRngDropCounter.kt @@ -12,7 +12,7 @@ import at.hannibal2.skyhanni.utils.RenderUtils.renderStrings import net.minecraftforge.fml.common.eventhandler.SubscribeEvent class DicerRngDropCounter { - private val display = mutableListOf<String>() + private var display = listOf<String>() private val drops = mutableMapOf<CropType, MutableMap<DropRarity, Int>>() private val itemDrops = mutableListOf<ItemDrop>() @@ -59,9 +59,7 @@ class DicerRngDropCounter { } private fun update() { - val newDisplay = drawDisplay() - display.clear() - display.addAll(newDisplay) + display = drawDisplay() } private fun drawDisplay(): List<String> { diff --git a/src/main/java/at/hannibal2/skyhanni/features/garden/EliteFarmingWeight.kt b/src/main/java/at/hannibal2/skyhanni/features/garden/EliteFarmingWeight.kt index 4eac3e0bb..d8bc15e16 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/garden/EliteFarmingWeight.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/garden/EliteFarmingWeight.kt @@ -61,7 +61,7 @@ class EliteFarmingWeight { private val config get() = SkyHanniMod.feature.garden private val localCounter = mutableMapOf<CropType, Long>() - private var display = mutableListOf<String>() + private var display = listOf<String>() private var profileId = "" private var lastLeaderboardUpdate = 0L private var apiError = false diff --git a/src/main/java/at/hannibal2/skyhanni/features/garden/GardenBestCropTime.kt b/src/main/java/at/hannibal2/skyhanni/features/garden/GardenBestCropTime.kt index 2205d9c8e..cce6dd67f 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/garden/GardenBestCropTime.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/garden/GardenBestCropTime.kt @@ -9,11 +9,12 @@ import at.hannibal2.skyhanni.utils.TimeUtils import java.util.* class GardenBestCropTime { - val display = mutableListOf<List<Any>>() + var display = listOf<List<Any>>() val timeTillNextCrop = mutableMapOf<CropType, Long>() private val config get() = SkyHanniMod.feature.garden - fun drawBestDisplay(currentCrop: CropType?) { + fun drawBestDisplay(currentCrop: CropType?): List<List<Any>> { + val newList = mutableListOf<List<Any>>() if (timeTillNextCrop.size < CropType.values().size) { updateTimeTillNextCrop() } @@ -33,10 +34,11 @@ class GardenBestCropTime { } val title = if (gardenExp) "§2Garden Experience" else "§bSkyBlock Level" - display.add(Collections.singletonList("§eBest Crop Time §7($title§7)")) + newList.add(Collections.singletonList("§eBest Crop Time §7($title§7)")) if (sorted.isEmpty()) { - display.add(Collections.singletonList("§cFarm crops to add them to this list!")) + newList.add(Collections.singletonList("§cFarm crops to add them to this list!")) + return newList } var number = 0 @@ -61,8 +63,9 @@ class GardenBestCropTime { val gardenExpForTier = getGardenExpForTier(nextTier) list.add(" §7(§2$gardenExpForTier §7Exp)") } - display.add(list) + newList.add(list) } + return newList } private fun getGardenExpForTier(gardenLevel: Int) = if (gardenLevel > 30) 300 else gardenLevel * 10 diff --git a/src/main/java/at/hannibal2/skyhanni/features/garden/GardenCropMilestoneDisplay.kt b/src/main/java/at/hannibal2/skyhanni/features/garden/GardenCropMilestoneDisplay.kt index 89461e076..eb8bcde86 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/garden/GardenCropMilestoneDisplay.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/garden/GardenCropMilestoneDisplay.kt @@ -19,7 +19,7 @@ import net.minecraftforge.fml.common.eventhandler.SubscribeEvent import java.util.* class GardenCropMilestoneDisplay { - private val progressDisplay = mutableListOf<List<Any>>() + private var progressDisplay = listOf<List<Any>>() private val cultivatingData = mutableMapOf<CropType, Int>() private val config get() = SkyHanniMod.feature.garden private val bestCropTime = GardenBestCropTime() @@ -147,28 +147,29 @@ class GardenCropMilestoneDisplay { } private fun update() { - progressDisplay.clear() - bestCropTime.display.clear() + progressDisplay = emptyList() + bestCropTime.display = emptyList() currentCrop?.let { - drawProgressDisplay(it, it.getCounter()) + progressDisplay = drawProgressDisplay(it, it.getCounter()) if (config.cropMilestoneBestDisplay) { - bestCropTime.drawBestDisplay(it) + bestCropTime.display = bestCropTime.drawBestDisplay(it) } } if (config.cropMilestoneBestAlwaysOn) { if (currentCrop == null) { - bestCropTime.drawBestDisplay(null) + bestCropTime.display = bestCropTime.drawBestDisplay(null) } } } - private fun drawProgressDisplay(crop: CropType, counter: Long) { - progressDisplay.add(Collections.singletonList("§6Crop Milestones")) + private fun drawProgressDisplay(crop: CropType, counter: Long): MutableList<List<Any>> { + val newList = mutableListOf<List<Any>>() + newList.add(Collections.singletonList("§6Crop Milestones")) val list = mutableListOf<Any>() GardenAPI.addGardenCropToList(crop, list) list.add(crop.cropName) - progressDisplay.add(list) + newList.add(list) val currentTier = GardenCropMilestones.getTierForCrops(counter) @@ -181,13 +182,13 @@ class GardenCropMilestoneDisplay { val haveFormat = LorenzUtils.formatInteger(have) val needFormat = LorenzUtils.formatInteger(need) - progressDisplay.add(Collections.singletonList("§7Progress to Tier $nextTier§8:")) - progressDisplay.add(Collections.singletonList("§e$haveFormat§8/§e$needFormat")) + newList.add(Collections.singletonList("§7Progress to Tier $nextTier§8:")) + newList.add(Collections.singletonList("§e$haveFormat§8/§e$needFormat")) lastItemInHand?.let { if (GardenAPI.readCounter(it) == -1) { - progressDisplay.add(Collections.singletonList("§cWarning: You need Cultivating!")) - return + newList.add(Collections.singletonList("§cWarning: You need Cultivating!")) + return newList } } @@ -207,15 +208,17 @@ class GardenCropMilestoneDisplay { SendTitleHelper.sendTitle("§b$crop $nextTier in $duration", 1_500) } } - progressDisplay.add(Collections.singletonList("§7in §b$duration")) + newList.add(Collections.singletonList("§7in §b$duration")) val format = LorenzUtils.formatInteger(averageSpeedPerSecond * 60) - progressDisplay.add(Collections.singletonList("§7Crops/minute§8: §e$format")) + newList.add(Collections.singletonList("§7Crops/minute§8: §e$format")) } if (needsInventory) { - progressDisplay.add(Collections.singletonList("§cOpen §e/cropmilestones §cto update!")) + newList.add(Collections.singletonList("§cOpen §e/cropmilestones §cto update!")) } + + return newList } private fun isEnabled() = GardenAPI.inGarden() && config.cropMilestoneProgress diff --git a/src/main/java/at/hannibal2/skyhanni/features/garden/GardenNextJacobContest.kt b/src/main/java/at/hannibal2/skyhanni/features/garden/GardenNextJacobContest.kt index d01716ea0..5be04363c 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/garden/GardenNextJacobContest.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/garden/GardenNextJacobContest.kt @@ -17,7 +17,7 @@ import java.time.Instant import java.util.regex.Pattern class GardenNextJacobContest { - private val display = mutableListOf<Any>() + private var display = listOf<Any>() private var tick = 0 private var contests = mutableMapOf<Long, FarmingContest>() private var inCalendar = false @@ -121,9 +121,7 @@ class GardenNextJacobContest { private fun update() { nextContestCrops.clear() - val newDisplay = drawDisplay() - display.clear() - display.addAll(newDisplay) + display = drawDisplay() } private fun drawDisplay(): List<Any> { diff --git a/src/main/java/at/hannibal2/skyhanni/features/garden/GardenVisitorFeatures.kt b/src/main/java/at/hannibal2/skyhanni/features/garden/GardenVisitorFeatures.kt index f66697e6a..1e0be2855 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/garden/GardenVisitorFeatures.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/garden/GardenVisitorFeatures.kt @@ -30,7 +30,7 @@ import java.util.regex.Pattern class GardenVisitorFeatures { private val visitors = mutableMapOf<String, Visitor>() - private val display = mutableListOf<List<Any>>() + private var display = listOf<List<Any>>() private var lastClickedNpc = 0 private var onBarnPlot = false private var tick = 0 @@ -88,9 +88,7 @@ class GardenVisitorFeatures { } private fun updateDisplay() { - val list = drawDisplay() - display.clear() - display.addAll(list) + display = drawDisplay() } private fun drawDisplay(): List<List<Any>> { diff --git a/src/main/java/at/hannibal2/skyhanni/features/garden/SkyMartBestProfit.kt b/src/main/java/at/hannibal2/skyhanni/features/garden/SkyMartBestProfit.kt index d1d9119cd..d38e9f3b3 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/garden/SkyMartBestProfit.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/garden/SkyMartBestProfit.kt @@ -21,7 +21,7 @@ import java.util.regex.Pattern class SkyMartBestProfit { private val pattern = Pattern.compile("§c(.*) Copper") - private val display = mutableListOf<List<Any>>() + private var display = listOf<List<Any>>() private val config get() = SkyHanniMod.feature.garden @SubscribeEvent @@ -63,10 +63,17 @@ class SkyMartBestProfit { } } - display.clear() + display = drawDisplay(priceMap, iconMap) + } + + private fun drawDisplay( + priceMap: MutableMap<Pair<String, String>, Double>, + iconMap: MutableMap<String, ItemStack>, + ): MutableList<List<Any>> { + val newList = mutableListOf<List<Any>>() - display.add(Collections.singletonList("Coins per §cCopper§f:")) - display.add(Collections.singletonList("")) + newList.add(Collections.singletonList("Coins per §cCopper§f:")) + newList.add(Collections.singletonList("")) val keys = priceMap.sortedDesc().keys val renderer = Minecraft.getMinecraft().fontRendererObj @@ -78,13 +85,14 @@ class SkyMartBestProfit { while (renderer.getStringWidth(displayName.removeColor()) < longest) { displayName += " " } - display.add(listOf(itemStack, "$displayName $second")) + newList.add(listOf(itemStack, "$displayName $second")) } + return newList } @SubscribeEvent fun onInventoryClose(event: InventoryCloseEvent) { - display.clear() + display = emptyList() } @SubscribeEvent diff --git a/src/main/java/at/hannibal2/skyhanni/features/misc/NonGodPotEffectDisplay.kt b/src/main/java/at/hannibal2/skyhanni/features/misc/NonGodPotEffectDisplay.kt index 0fc8b26d8..742e91c1d 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/misc/NonGodPotEffectDisplay.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/misc/NonGodPotEffectDisplay.kt @@ -24,7 +24,7 @@ class NonGodPotEffectDisplay { private var checkFooter = false private val activeEffects = mutableMapOf<String, Long>() - private val display = mutableListOf<String>() + private var display = listOf<String>() private var lastTick = 0L private var nonGodPotEffects = mapOf( @@ -82,12 +82,17 @@ class NonGodPotEffectDisplay { private fun update() { val now = System.currentTimeMillis() - display.clear() if (activeEffects.values.removeIf { now > it }) { //to fetch the real amount of active pots totalEffectsCount = 0 checkFooter = true } + + display = drawDisplay(now) + } + + private fun drawDisplay(now: Long): MutableList<String> { + val newDisplay = mutableListOf<String>() for (effect in activeEffects.sorted()) { val label = effect.key if (label.contains("Invisibility")) continue @@ -100,14 +105,15 @@ class NonGodPotEffectDisplay { val color = colorForTime(seconds) - display.add("$label $color$format") + newDisplay.add("$label $color$format") } val diff = totalEffectsCount - activeEffects.size if (diff > 0) { - display.add("§eOpen the /effects inventory") - display.add("§eto show the missing $diff effects!") + newDisplay.add("§eOpen the /effects inventory") + newDisplay.add("§eto show the missing $diff effects!") checkFooter = true } + return newDisplay } private fun colorForTime(seconds: Long): String { diff --git a/src/main/java/at/hannibal2/skyhanni/features/nether/reputationhelper/CrimsonIsleReputationHelper.kt b/src/main/java/at/hannibal2/skyhanni/features/nether/reputationhelper/CrimsonIsleReputationHelper.kt index c50cec5dd..5184f282a 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/nether/reputationhelper/CrimsonIsleReputationHelper.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/nether/reputationhelper/CrimsonIsleReputationHelper.kt @@ -26,7 +26,7 @@ class CrimsonIsleReputationHelper(skyHanniMod: SkyHanniMod) { var repoData: JsonObject = JsonObject() var factionType = FactionType.NONE - private val display = mutableListOf<List<Any>>() + private var display = listOf<List<Any>>() private var dirty = true private var tick = 0 @@ -74,17 +74,19 @@ class CrimsonIsleReputationHelper(skyHanniMod: SkyHanniMod) { } private fun updateRender() { - display.clear() + val newList = mutableListOf<List<Any>>() //TODO test if (factionType == FactionType.NONE) return - display.add(Collections.singletonList("Reputation Helper:")) - questHelper.render(display) - miniBossHelper.render(display) + newList.add(Collections.singletonList("Reputation Helper:")) + questHelper.render(newList) + miniBossHelper.render(newList) if (factionType == FactionType.MAGE) { - kuudraBossHelper.render(display) + kuudraBossHelper.render(newList) } + + display = newList } @SubscribeEvent(priority = EventPriority.LOWEST) diff --git a/src/main/java/at/hannibal2/skyhanni/utils/RenderUtils.kt b/src/main/java/at/hannibal2/skyhanni/utils/RenderUtils.kt index 2697259dd..a8bbc9436 100644 --- a/src/main/java/at/hannibal2/skyhanni/utils/RenderUtils.kt +++ b/src/main/java/at/hannibal2/skyhanni/utils/RenderUtils.kt @@ -458,7 +458,7 @@ object RenderUtils { if (list.isEmpty()) return var offsetY = 0 - for (s in list.toMutableList()) { + for (s in list) { renderString(s, offsetY = offsetY, center = center) offsetY += 10 + extraSpace } @@ -472,9 +472,8 @@ object RenderUtils { if (list.isEmpty()) return var offsetY = 0 - // TODO remove toMutableList try { - for (line in list.toMutableList()) { + for (line in list) { renderLine(line, offsetY, itemScale) offsetY += 10 + extraSpace + 2 } |