/**
* This class was created by <Vazkii>. It's distributed as
* part of the Botania Mod. Get the Source Code in github:
* https://github.com/Vazkii/Botania
*
* Botania is Open Source and distributed under the
* Botania License: http://botaniamod.net/license.php
*
* File Created @ [Jan 25, 2014, 6:11:10 PM (GMT)]
*/
package vazkii.botania.client.core.handler;
import java.awt.Color;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import net.minecraftforge.items.CapabilityItemHandler;
import net.minecraftforge.items.IItemHandler;
import org.lwjgl.opengl.GL11;
import baubles.api.BaublesApi;
import net.minecraft.block.Block;
import net.minecraft.block.BlockLiquid;
import net.minecraft.block.state.IBlockState;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.FontRenderer;
import net.minecraft.client.gui.Gui;
import net.minecraft.client.gui.GuiChat;
import net.minecraft.client.gui.GuiIngame;
import net.minecraft.client.gui.ScaledResolution;
import net.minecraft.client.renderer.GlStateManager;
import net.minecraft.client.resources.I18n;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.profiler.Profiler;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.math.RayTraceResult;
import net.minecraft.util.text.TextFormatting;
import net.minecraftforge.client.event.RenderGameOverlayEvent;
import net.minecraftforge.client.event.RenderGameOverlayEvent.ElementType;
import net.minecraftforge.fml.common.eventhandler.EventPriority;
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
import net.minecraftforge.fml.relauncher.ReflectionHelper;
import vazkii.botania.api.lexicon.ILexicon;
import vazkii.botania.api.lexicon.ILexiconable;
import vazkii.botania.api.lexicon.LexiconEntry;
import vazkii.botania.api.mana.ICreativeManaProvider;
import vazkii.botania.api.mana.IManaItem;
import vazkii.botania.api.mana.IManaUsingItem;
import vazkii.botania.api.mana.ManaItemHandler;
import vazkii.botania.api.recipe.RecipeManaInfusion;
import vazkii.botania.api.wand.IWandHUD;
import vazkii.botania.api.wiki.IWikiProvider;
import vazkii.botania.api.wiki.WikiHooks;
import vazkii.botania.client.core.helper.RenderHelper;
import vazkii.botania.client.lib.LibResources;
import vazkii.botania.common.Botania;
import vazkii.botania.common.block.ModBlocks;
import vazkii.botania.common.block.tile.TileAltar;
import vazkii.botania.common.block.tile.TileRuneAltar;
import vazkii.botania.common.block.tile.corporea.TileCorporeaCrystalCube;
import vazkii.botania.common.block.tile.corporea.TileCorporeaIndex;
import vazkii.botania.common.block.tile.corporea.TileCorporeaIndex.InputHandler;
import vazkii.botania.common.block.tile.mana.TilePool;
import vazkii.botania.common.core.handler.ConfigHandler;
import vazkii.botania.common.core.helper.PlayerHelper;
import vazkii.botania.common.item.ItemCraftingHalo;
import vazkii.botania.common.item.ItemSextant;
import vazkii.botania.common.item.ItemTwigWand;
import vazkii.botania.common.item.ModItems;
import vazkii.botania.common.item.equipment.bauble.ItemDodgeRing;
import vazkii.botania.common.item.equipment.bauble.ItemFlightTiara;
import vazkii.botania.common.item.equipment.bauble.ItemMonocle;
import vazkii.botania.common.lib.LibObfuscation;
public final class HUDHandler {
private HUDHandler() {}
public static final ResourceLocation manaBar = new ResourceLocation(LibResources.GUI_MANA_HUD);
@SubscribeEvent(priority = EventPriority.HIGHEST)
public static void onDrawScreenPre(RenderGameOverlayEvent.Pre event) {
Minecraft mc = Minecraft.getMinecraft();
Profiler profiler = mc.mcProfiler;
if(event.getType() == ElementType.HEALTH) {
profiler.startSection("botania-hud");
IItemHandler baublesInv = BaublesApi.getBaublesHandler(mc.player);
ItemStack headpiece = baublesInv.getStackInSlot(4);
if(!headpiece.isEmpty() && headpiece.getItem() == ModItems.flightTiara) {
profiler.startSection("flugelTiara");
ItemFlightTiara.renderHUD(event.getResolution(), mc.player, headpiece);
profiler.endSection();
}
dodgeRing: {
ItemStack ring = baublesInv.getStackInSlot(1);
if(ring.isEmpty() || !(ring.getItem() instanceof ItemDodgeRing)) {
ring = baublesInv.getStackInSlot(2);
if(ring.isEmpty() || !(ring.getItem() instanceof ItemDodgeRing))
break dodgeRing;
}
profiler.startSection("dodgeRing");
ItemDodgeRing.renderHUD(event.getResolution(), mc.player, ring, event.getPartialTicks());
profiler.endSection();
}
profiler.endSection();
}
}
@SubscribeEvent
public static void onDrawScreenPost(RenderGameOverlayEvent.Post event) {
Minecraft mc = Minecraft.getMinecraft();
Profiler profiler = mc.mcProfiler;
ItemStack main = mc.player.getHeldItemMainhand();
ItemStack offhand = mc.player.getHeldItemOffhand();
if(event.getType() == ElementType.ALL) {
profiler.startSection("botania-hud");
RayTraceResult pos = mc.objectMouseOver;
if(pos != null) {
IBlockState state = pos.typeOfHit == RayTraceResult.Type.BLOCK ? mc.world.getBlockState(pos.getBlockPos()) : null;
Block block = state == null ? null : state.getBlock();
TileEntity tile = pos.typeOfHit == RayTraceResult.Type.BLOCK ? mc.world.getTileEntity(pos.getBlockPos()) : null;
if(PlayerHelper.hasAnyHeldItem(mc.player)) {
if(pos != null && PlayerHelper.hasHeldItem(mc.player, ModItems.twigWand)) {
renderWandModeDisplay(PlayerHelper.getFirstHeldItem(mc.player, ModItems.twigWand), event.getResolution());
if(block instanceof IWandHUD) {
profiler.startSection("wandItem");
((IWandHUD) block).renderHUD(mc, event.getResolution(), mc.world, pos.getBlockPos());
profiler.endSection();
}
} else if(block != null && PlayerHelper.hasHeldItemClass(mc.player, ILexicon.class))
drawLexiconHUD(PlayerHelper.getFirstHeldItemClass(mc.player, ILexicon.class), state, pos, event.getResolution());
if(tile != null && tile instanceof TilePool && !mc.player.getHeldItemMainhand().isEmpty())
renderPoolRecipeHUD(event.getResolution(), (TilePool) tile, mc.player.getHeldItemMainhand());
}
if(tile != null && tile instanceof TileAltar)
((TileAltar) tile).renderHUD(mc, event.getResolution());
else if(tile != null && tile instanceof TileRuneAltar)
((TileRuneAltar) tile).renderHUD(mc, event.getResolution());
if(tile != null && tile instanceof TileCorporeaCrystalCube)
renderCrystalCubeHUD(event.getResolution(), (TileCorporeaCrystalCube) tile);
}
TileCorporeaIndex.getInputHandler();
if(!InputHandler.getNearbyIndexes(mc.player).isEmpty() && mc.currentScreen != null && mc.currentScreen instanceof GuiChat) {
profiler.startSection("nearIndex");
renderNearIndexDisplay(event.getResolution());
profiler.endSection();
}
if(MultiblockRenderHandler.currentMultiblock != null && MultiblockRenderHandler.anchor == null) {
profiler.startSection("multiblockRightClick");
String s = I18n.format("botaniamisc.rightClickToAnchor");
mc.fontRendererObj.drawStringWithShadow(s, event.getResolution().getScaledWidth() / 2 - mc.fontRendererObj.getStringWidth(s) / 2, event.getResolution().getScaledHeight() / 2 - 30, 0xFFFFFF);
profiler.endSection();
}
if(!main.isEmpty() && main.getItem() instanceof ItemCraftingHalo) {
profiler.startSection("craftingHalo_main");
ItemCraftingHalo.renderHUD(event.getResolution(), mc.player, main);
profiler.endSection();
} else if(!offhand.isEmpty() && offhand.getItem() instanceof ItemCraftingHalo) {
profiler.startSection("craftingHalo_off");
ItemCraftingHalo.renderHUD(event.getResolution(), mc.player, offhand);
profiler.endSection();
}
if(!main.isEmpty() && main.getItem() instanceof ItemSextant) {
profiler.startSection("sextant");
ItemSextant.renderHUD(event.getResolution(), mc.player, main);
profiler.endSection();
}
/*if(equippedStack != null && equippedStack.getItem() == ModItems.flugelEye) {
profiler.startSection("flugelEye");
ItemFlugelEye.renderHUD(event.getResolution(), mc.player, equippedStack);
profiler.endSection();
}*/
if(Botania.proxy.isClientPlayerWearingMonocle()) {
profiler.startSection("monocle");
ItemMonocle.renderHUD(event.getResolution(), mc.player);
profiler.endSection();
}
profiler.startSection("manaBar");
EntityPlayer player = mc.player;
if(!player.isSpectator()) {
int totalMana = 0;
int totalMaxMana = 0;
boolean anyRequest = false;
boolean creative = false;
IItemHandler mainInv = player.getCapability(CapabilityItemHandler.ITEM_HANDLER_CAPABILITY, null);
IItemHandler baublesInv = BaublesApi.getBaublesHandler(player);
int invSize = mainInv.getSlots();
int size = invSize;
if(baublesInv != null)
size += baublesInv.getSlots();
for(int i = 0; i < size; i++) {
boolean useBaubles = i >= invSize;
IItemHandler inv = useBaubles ? baublesInv : mainInv;
ItemStack stack = inv.getStackInSlot(i - (useBaubles ? invSize : 0));
if(!stack.isEmpty()) {
Item item = stack.getItem();
if(item instanceof IManaUsingItem)
anyRequest = anyRequest || ((IManaUsingItem) item).usesMana(stack);
}
}
List<ItemStack> items = ManaItemHandler.getManaItems(player);
for (ItemStack stack : items) {
Item item = stack.getItem();
if(!((IManaItem) item).isNoExport(stack)) {
totalMana += ((IManaItem) item).getMana(stack);
totalMaxMana += ((IManaItem) item).getMaxMana(stack);
}
if(item instanceof ICreativeManaProvider && ((ICreativeManaProvider) item).isCreative(stack))
creative = true;
}
Map<Integer, ItemStack> baubles = ManaItemHandler.getManaBaubles(player);
for (Entry<Integer, ItemStack> entry : baubles.entrySet()) {
ItemStack stack = entry.getValue();
Item item = stack.getItem();
if(!((IManaItem) item).isNoExport(stack)) {
totalMana += ((IManaItem) item).getMana(stack);
totalMaxMana += ((IManaItem) item).getMaxMana(stack);
}
if(item instanceof ICreativeManaProvider && ((ICreativeManaProvider) item).isCreative(stack))
creative = true;
}
if(anyRequest)
renderManaInvBar(event.getResolution(), creative, totalMana, totalMaxMana);
}
profiler.endStartSection("itemsRemaining");
ItemsRemainingRenderHandler.render(event.getResolution(), event.getPartialTicks());
profiler.endSection();
profiler.endSection();
GlStateManager.color(1F, 1F, 1F, 1F);
}
}
private static void renderWandModeDisplay(ItemStack stack, ScaledResolution res) {
Minecraft mc = Minecraft.getMinecraft();
Profiler profiler = mc.mcProfiler;
profiler.startSection("wandMode");
int ticks = ReflectionHelper.getPrivateValue(GuiIngame.class, mc.ingameGUI, LibObfuscation.REMAINING_HIGHLIGHT_TICKS);
ticks -= 15;
if(ticks > 0) {
int alpha = Math.min(255, (int) (ticks * 256.0F / 10.0F));
int color = 0x00CC00 + (alpha << 24);
String disp = I18n.format(ItemTwigWand.getModeString(stack));
int x = res.getScaledWidth() / 2 - mc.fontRendererObj.getStringWidth(disp) / 2;
int y = res.getScaledHeight() - 70;
GlStateManager.enableBlend();
GlStateManager.blendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
mc.fontRendererObj.drawStringWithShadow(disp, x, y, color);
GlStateManager.disableBlend();
}
profiler.endSection();
}
private static void renderManaInvBar(ScaledResolution res, boolean hasCreative, int totalMana, int totalMaxMana) {
Minecraft mc = Minecraft.getMinecraft();
int width = 182;
int x = res.getScaledWidth() / 2 - width / 2;
int y = res.getScaledHeight() - ConfigHandler.manaBarHeight;
if(!hasCreative) {
if(totalMaxMana == 0)
width = 0;
else width *= (double) totalMana / (double) totalMaxMana;
}
if(width == 0) {
if(totalMana > 0)
width = 1;
else return;
}
Color color = new Color(Color.HSBtoRGB(0.55F, (float) Math.min(1F, Math.sin(System.currentTimeMillis() / 200D) * 0.5 + 1F), 1F));
GL11.glColor4ub((byte) color.getRed(), (byte) color.getGreen(), (byte) color.getBlue(), (byte) (255 - color.getRed()));
mc.renderEngine.bindTexture(manaBar);
GlStateManager.enableBlend();
GlStateManager.blendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
RenderHelper.drawTexturedModalRect(x, y, 0, 0, 251, width, 5);
GlStateManager.disableBlend();
GL11.glColor4ub((byte) 255, (byte) 255, (byte) 255, (byte) 255);
}
private static void renderPoolRecipeHUD(ScaledResolution res, TilePool tile, ItemStack stack) {
Minecraft mc = Minecraft.getMinecraft();
Profiler profiler = mc.mcProfiler;
profiler.startSection("poolRecipe");
RecipeManaInfusion recipe = TilePool.getMatchingRecipe(stack, tile.getWorld().getBlockState(tile.getPos().down()));
if(recipe != null) {
int x = res.getScaledWidth() / 2 - 11;
int y = res.getScaledHeight() / 2 + 10;
int u = tile.getCurrentMana() >= recipe.getManaToConsume() ? 0 : 22;
int v = mc.player.getName().equals("haighyorkie") && mc.player.isSneaking() ? 23 : 8;
GlStateManager.enableBlend();
GlStateManager.blendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
mc.renderEngine.bindTexture(manaBar);
RenderHelper.drawTexturedModalRect(x, y, 0, u, v, 22, 15);
GlStateManager.color(1F, 1F, 1F, 1F);
net.minecraft.client.renderer.RenderHelper.enableGUIStandardItemLighting();
mc.getRenderItem().renderItemAndEffectIntoGUI(stack, x - 20, y);
mc.getRenderItem().renderItemAndEffectIntoGUI(recipe.getOutput(), x + 26, y);
mc.getRenderItem().renderItemOverlays(mc.fontRendererObj, recipe.getOutput(), x + 26, y);
net.minecraft.client.renderer.RenderHelper.disableStandardItemLighting();
GlStateManager.disableLighting();
GlStateManager.disableBlend();
}
profiler.endSection();
}
private static void renderCrystalCubeHUD(ScaledResolution res, TileCorporeaCrystalCube tile) {
Minecraft mc = Minecraft.getMinecraft();
Profiler profiler = mc.mcProfiler;
profiler.startSection("crystalCube");
ItemStack target = tile.getRequestTarget();
if(!target.isEmpty()) {
String s1 = target.getDisplayName();
String s2 = tile.getItemCount() + "x";
int strlen = Math.max(mc.fontRendererObj.getStringWidth(s1), mc.fontRendererObj.getStringWidth(s2));
int w = res.getScaledWidth();
int h = res.getScaledHeight();
Gui.drawRect(w / 2 + 8, h / 2 - 12, w / 2 + strlen + 32, h / 2 + 10, 0x44000000);
Gui.drawRect(w / 2 + 6, h / 2 - 14, w / 2 + strlen + 34, h / 2 + 12, 0x44000000);
mc.fontRendererObj.drawStringWithShadow(target.getDisplayName(), w / 2 + 30, h / 2 - 10, 0x6666FF);
mc.fontRendererObj.drawStringWithShadow(tile.getItemCount() + "x", w / 2 + 30, h / 2, 0xFFFFFF);
net.minecraft.client.renderer.RenderHelper.enableGUIStandardItemLighting();
GlStateManager.enableRescaleNormal();
mc.getRenderItem().renderItemAndEffectIntoGUI(target, w / 2 + 10, h / 2 - 10);
net.minecraft.client.renderer.RenderHelper.disableStandardItemLighting();
}
profiler.endSection();
}
private static void drawLexiconHUD(ItemStack stack, IBlockState state, RayTraceResult pos, ScaledResolution res) {
Minecraft mc = Minecraft.getMinecraft();
Block block = state.getBlock();
Profiler profiler = mc.mcProfiler;
profiler.startSection("lexicon");
FontRenderer font = mc.fontRendererObj;
boolean draw = false;
String drawStr = "";
String secondLine = "";
GlStateManager.enableBlend();
GlStateManager.blendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
int sx = res.getScaledWidth() / 2 - 17;
int sy = res.getScaledHeight() / 2 + 2;
if(block instanceof ILexiconable) {
LexiconEntry entry = ((ILexiconable) block).getEntry(mc.world, pos.getBlockPos(), mc.player, stack);
if(entry != null) {
if(!((ILexicon) stack.getItem()).isKnowledgeUnlocked(stack, entry.getKnowledgeType()))
font = mc.standardGalacticFontRenderer;
drawStr = I18n.format(entry.getUnlocalizedName());
secondLine = TextFormatting.ITALIC + I18n.format(entry.getTagline());
draw = true;
}
}
if(!draw && pos.entityHit == null) {
profiler.startSection("wikiLookup");
if(!block.isAir(state, mc.world, pos.getBlockPos()) && !(block instanceof BlockLiquid)) {
IWikiProvider provider = WikiHooks.getWikiFor(block);
String url = provider.getWikiURL(mc.world, pos, mc.player);
if(url != null && !url.isEmpty()) {
String name = provider.getBlockName(mc.world, pos, mc.player);
String wikiName = provider.getWikiName(mc.world, pos, mc.player);
drawStr = name + " @ " + TextFormatting.AQUA + wikiName;
draw = true;
}
}
profiler.endSection();
}
if(draw) {
if(!mc.player.isSneaking()) {
drawStr = "?";
secondLine = "";
font = mc.fontRendererObj;
}
mc.getRenderItem().renderItemIntoGUI(new ItemStack(ModItems.lexicon), sx, sy);
GlStateManager.disableLighting();
font.drawStringWithShadow(drawStr, sx + 20, sy + 4, 0xFFFFFFFF);
font.drawStringWithShadow(secondLine, sx + 20, sy + 14, 0xFFAAAAAA);
if(!mc.player.isSneaking()) {
GlStateManager.scale(0.5F, 0.5F, 1F);
mc.fontRendererObj.drawStringWithShadow(TextFormatting.BOLD + mc.gameSettings.keyBindSneak.getDisplayName(), (sx + 10) * 2 - 16, (sy + 8) * 2 + 20, 0xFFFFFFFF);
GlStateManager.scale(2F, 2F, 1F);
}
}
GlStateManager.disableBlend();
GlStateManager.color(1F, 1F, 1F, 1F);
profiler.endSection();
}
private static void renderNearIndexDisplay(ScaledResolution res) {
Minecraft mc = Minecraft.getMinecraft();
String txt0 = I18n.format("botaniamisc.nearIndex0");
String txt1 = TextFormatting.GRAY + I18n.format("botaniamisc.nearIndex1");
String txt2 = TextFormatting.GRAY + I18n.format("botaniamisc.nearIndex2");
int l = Math.max(mc.fontRendererObj.getStringWidth(txt0), Math.max(mc.fontRendererObj.getStringWidth(txt1), mc.fontRendererObj.getStringWidth(txt2))) + 20;
int x = res.getScaledWidth() - l - 20;
int y = res.getScaledHeight() - 60;
Gui.drawRect(x - 6, y - 6, x + l + 6, y + 37, 0x44000000);
Gui.drawRect(x - 4, y - 4, x + l + 4, y + 35, 0x44000000);
net.minecraft.client.renderer.RenderHelper.enableGUIStandardItemLighting();
GlStateManager.enableRescaleNormal();
mc.getRenderItem().renderItemAndEffectIntoGUI(new ItemStack(ModBlocks.corporeaIndex), x, y + 10);
net.minecraft.client.renderer.RenderHelper.disableStandardItemLighting();
mc.fontRendererObj.drawStringWithShadow(txt0, x + 20, y, 0xFFFFFF);
mc.fontRendererObj.drawStringWithShadow(txt1, x + 20, y + 14, 0xFFFFFF);
mc.fontRendererObj.drawStringWithShadow(txt2, x + 20, y + 24, 0xFFFFFF);
}
public static void drawSimpleManaHUD(int color, int mana, int maxMana, String name, ScaledResolution res) {
GlStateManager.enableBlend();
GlStateManager.blendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
Minecraft mc = Minecraft.getMinecraft();
int x = res.getScaledWidth() / 2 - mc.fontRendererObj.getStringWidth(name) / 2;
int y = res.getScaledHeight() / 2 + 10;
mc.fontRendererObj.drawStringWithShadow(name, x, y, color);
x = res.getScaledWidth() / 2 - 51;
y += 10;
renderManaBar(x, y, color, mana < 0 ? 0.5F : 1F, mana, maxMana);
if(mana < 0) {
String text = I18n.format("botaniamisc.statusUnknown");
x = res.getScaledWidth() / 2 - mc.fontRendererObj.getStringWidth(text) / 2;
y -= 1;
mc.fontRendererObj.drawString(text, x, y, color);
}
GlStateManager.disableBlend();
}
public static void drawComplexManaHUD(int color, int mana, int maxMana, String name, ScaledResolution res, ItemStack bindDisplay, boolean properlyBound) {
drawSimpleManaHUD(color, mana, maxMana, name, res);
Minecraft mc = Minecraft.getMinecraft();
int x = res.getScaledWidth() / 2 + 55;
int y = res.getScaledHeight() / 2 + 12;
net.minecraft.client.renderer.RenderHelper.enableGUIStandardItemLighting();
GlStateManager.enableRescaleNormal();
mc.getRenderItem().renderItemAndEffectIntoGUI(bindDisplay, x, y);
net.minecraft.client.renderer.RenderHelper.disableStandardItemLighting();
GlStateManager.disableDepth();
if(properlyBound) {
mc.fontRendererObj.drawStringWithShadow("\u2714", x + 10, y + 9, 0x004C00);
mc.fontRendererObj.drawStringWithShadow("\u2714", x + 10, y + 8, 0x0BD20D);
} else {
mc.fontRendererObj.drawStringWithShadow("\u2718", x + 10, y + 9, 0x4C0000);
mc.fontRendererObj.drawStringWithShadow("\u2718", x + 10, y + 8, 0xD2080D);
}
GlStateManager.enableDepth();
}
public static void renderManaBar(int x, int y, int color, float alpha, int mana, int maxMana) {
Minecraft mc = Minecraft.getMinecraft();
GlStateManager.color(1F, 1F, 1F, alpha);
mc.renderEngine.bindTexture(manaBar);
RenderHelper.drawTexturedModalRect(x, y, 0, 0, 0, 102, 5);
int manaPercentage = Math.max(0, (int) ((double) mana / (double) maxMana * 100));
if(manaPercentage == 0 && mana > 0)
manaPercentage = 1;
RenderHelper.drawTexturedModalRect(x + 1, y + 1, 0, 0, 5, 100, 3);
Color color_ = new Color(color);
GL11.glColor4ub((byte) color_.getRed(), (byte) color_.getGreen(),(byte) color_.getBlue(), (byte) (255F * alpha));
RenderHelper.drawTexturedModalRect(x + 1, y + 1, 0, 0, 5, Math.min(100, manaPercentage), 3);
GL11.glColor4ub((byte) 255, (byte) 255, (byte) 255, (byte) 255);
}
}