From c161a74d7341f4d7a7635a358dedd555b37348cc Mon Sep 17 00:00:00 2001 From: Electroblob77 <35599699+Electroblob77@users.noreply.github.com> Date: Tue, 31 Mar 2020 21:33:10 +0100 Subject: [PATCH] Add bookshelf interface to arcane workbench Implements the main functionality: - Access bookshelves from within the workbench - Search by spell name, tier, element and type - Sort by tier, element or alphabetically, ascending or descending - Three-way shift-clicking support - Automatic return of books to bookshelves when wand is removed --- .../wizardry/block/BlockBookshelf.java | 10 - .../client/gui/GuiArcaneWorkbench.java | 223 +++++++++++-- .../inventory/ContainerArcaneWorkbench.java | 298 +++++++++++++++--- .../wizardry/inventory/SlotBookList.java | 70 ++++ .../wizardry/inventory/VirtualSlot.java | 79 +++++ .../electroblob/wizardry/spell/Spell.java | 29 ++ .../assets/ebwizardry/lang/en_gb.lang | 5 + .../assets/ebwizardry/lang/en_us.lang | 5 + .../textures/gui/arcane_workbench.png | Bin 31627 -> 40318 bytes 9 files changed, 646 insertions(+), 73 deletions(-) create mode 100644 src/main/java/electroblob/wizardry/inventory/SlotBookList.java create mode 100644 src/main/java/electroblob/wizardry/inventory/VirtualSlot.java diff --git a/src/main/java/electroblob/wizardry/block/BlockBookshelf.java b/src/main/java/electroblob/wizardry/block/BlockBookshelf.java index b4e23861..9fc4c90a 100644 --- a/src/main/java/electroblob/wizardry/block/BlockBookshelf.java +++ b/src/main/java/electroblob/wizardry/block/BlockBookshelf.java @@ -50,16 +50,6 @@ public class BlockBookshelf extends BlockHorizontal implements ITileEntityProvid return new BlockStateContainer.Builder(this).add(FACING).add(BOOKS).build(); } - @Override - public boolean isOpaqueCube(IBlockState state){ - return false; - } - - @Override - public boolean isFullCube(IBlockState state){ - return false; - } - @Override public BlockFaceShape getBlockFaceShape(IBlockAccess world, IBlockState state, BlockPos pos, EnumFacing face){ return state.getValue(FACING).getAxis() == face.getAxis() ? BlockFaceShape.UNDEFINED : BlockFaceShape.SOLID; diff --git a/src/main/java/electroblob/wizardry/client/gui/GuiArcaneWorkbench.java b/src/main/java/electroblob/wizardry/client/gui/GuiArcaneWorkbench.java index 7d8be0a3..28901598 100644 --- a/src/main/java/electroblob/wizardry/client/gui/GuiArcaneWorkbench.java +++ b/src/main/java/electroblob/wizardry/client/gui/GuiArcaneWorkbench.java @@ -6,6 +6,8 @@ import electroblob.wizardry.constants.Element; import electroblob.wizardry.constants.Tier; import electroblob.wizardry.data.SpellGlyphData; import electroblob.wizardry.data.WizardData; +import electroblob.wizardry.inventory.ContainerArcaneWorkbench; +import electroblob.wizardry.inventory.SlotBookList; import electroblob.wizardry.item.IManaStoringItem; import electroblob.wizardry.item.ISpellCastingItem; import electroblob.wizardry.item.IWorkbenchItem; @@ -14,23 +16,25 @@ import electroblob.wizardry.packet.PacketControlInput; import electroblob.wizardry.packet.WizardryPacketHandler; import electroblob.wizardry.registry.WizardrySounds; import electroblob.wizardry.spell.Spell; -import electroblob.wizardry.inventory.ContainerArcaneWorkbench; import electroblob.wizardry.tileentity.TileEntityArcaneWorkbench; import electroblob.wizardry.util.WandHelper; import net.minecraft.client.Minecraft; import net.minecraft.client.audio.PositionedSoundRecord; import net.minecraft.client.gui.GuiButton; +import net.minecraft.client.gui.GuiTextField; import net.minecraft.client.gui.inventory.GuiContainer; import net.minecraft.client.renderer.GlStateManager; import net.minecraft.client.renderer.GlStateManager.DestFactor; import net.minecraft.client.renderer.GlStateManager.SourceFactor; import net.minecraft.client.resources.I18n; import net.minecraft.entity.player.InventoryPlayer; +import net.minecraft.inventory.ClickType; import net.minecraft.inventory.IInventory; import net.minecraft.inventory.Slot; import net.minecraft.item.Item; import net.minecraft.item.ItemStack; import net.minecraft.util.ResourceLocation; +import net.minecraft.util.math.MathHelper; import net.minecraft.util.text.TextFormatting; import net.minecraftforge.client.event.TextureStitchEvent; import net.minecraftforge.fml.common.Mod; @@ -38,6 +42,10 @@ import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; import net.minecraftforge.fml.common.network.simpleimpl.IMessage; import net.minecraftforge.fml.relauncher.Side; import org.lwjgl.input.Keyboard; +import org.lwjgl.input.Mouse; + +import java.io.IOException; +import java.util.Locale; @Mod.EventBusSubscriber(Side.CLIENT) public class GuiArcaneWorkbench extends GuiContainer { @@ -46,12 +54,15 @@ public class GuiArcaneWorkbench extends GuiContainer { public static final ResourceLocation texture = new ResourceLocation(Wizardry.MODID, "textures/gui/arcane_workbench.png"); - private IInventory playerInventory; + private InventoryPlayer playerInventory; private IInventory arcaneWorkbenchInventory; + private ContainerArcaneWorkbench arcaneWorkbenchContainer; - private static final int TOOLTIP_WIDTH = 164; + private static final int TOOLTIP_WIDTH = 144; private static final int TOOLTIP_TEXT_INSET = 6; + private static final int BOOKSHELF_UI_WIDTH = 122; + /** We report the actual size of the GUI to Minecraft when a wand is in so JEI doesn't overdraw it. * For calculations, we use the size without the tooltip, which is stored in this constant. */ private static final int MAIN_GUI_WIDTH = 176; @@ -61,25 +72,69 @@ public class GuiArcaneWorkbench extends GuiContainer { private static final int RUNE_WIDTH = 100; private static final int RUNE_HEIGHT = 100; + private static final int SCROLL_BAR_LEFT = 102; + private static final int SCROLL_BAR_TOP = 34; + private static final int SCROLL_BAR_WIDTH = 12; + private static final int SCROLL_BAR_HEIGHT = 178; + private static final int SCROLL_HANDLE_HEIGHT = 15; + private static final int PROGRESSION_BAR_WIDTH = 152; private static final int PROGRESSION_BAR_HEIGHT = 3; private static final int HALO_DIAMETER = 156; private static final int TEXTURE_WIDTH = 512; - private static final int TEXTURE_HEIGHT = 256; + private static final int TEXTURE_HEIGHT = 512; private int animationTimer = 0; private static final int ANIMATION_DURATION = 20; + private GuiTextField searchField; + private boolean searchNeedsClearing; + + private float scroll = 0; + private boolean scrolling = false; + public GuiArcaneWorkbench(InventoryPlayer invPlayer, TileEntityArcaneWorkbench entity){ super(new ContainerArcaneWorkbench(invPlayer, entity)); + this.arcaneWorkbenchContainer = (ContainerArcaneWorkbench)inventorySlots; this.playerInventory = invPlayer; this.arcaneWorkbenchInventory = entity; xSize = MAIN_GUI_WIDTH; ySize = 220; } + @Override + public void initGui(){ + + this.mc.player.openContainer = this.inventorySlots; + this.guiLeft = (this.width - this.xSize) / 2; + this.guiTop = (this.height - this.ySize) / 2; + + Keyboard.enableRepeatEvents(true); + + this.buttonList.clear(); + this.buttonList.add(this.applyBtn = new GuiButtonApply(0, this.width / 2 + 64, this.height / 2 + 3)); + this.buttonList.add(new GuiButtonSort(1, this.guiLeft - 44, this.guiTop + 8, ContainerArcaneWorkbench.SortType.TIER)); + this.buttonList.add(new GuiButtonSort(2, this.guiLeft - 31, this.guiTop + 8, ContainerArcaneWorkbench.SortType.ELEMENT)); + this.buttonList.add(new GuiButtonSort(3, this.guiLeft - 18, this.guiTop + 8, ContainerArcaneWorkbench.SortType.ALPHABETICAL)); + + this.searchField = new GuiTextField(0, this.fontRenderer, this.guiLeft - 113, this.guiTop + 22, 104, this.fontRenderer.FONT_HEIGHT); + this.searchField.setMaxStringLength(50); + this.searchField.setEnableBackgroundDrawing(false); + this.searchField.setVisible(true); + this.searchField.setTextColor(16777215); + this.searchField.setCanLoseFocus(false); + this.searchField.setFocused(true); + + } + + @Override + public void onGuiClosed(){ + super.onGuiClosed(); + Keyboard.enableRepeatEvents(false); + } + // Huh, didn't realise this method existed. Pretty neat. @Override public void updateScreen(){ @@ -93,18 +148,33 @@ public class GuiArcaneWorkbench extends GuiContainer { GlStateManager.color(1, 1, 1, 1); // Just in case + boolean mouseHeld = Mouse.isButtonDown(0); + + if(!scrolling && mouseHeld && getMaxScrollRows() > 0 && isPointInRegion(SCROLL_BAR_LEFT - BOOKSHELF_UI_WIDTH, + SCROLL_BAR_TOP, SCROLL_BAR_WIDTH, SCROLL_BAR_HEIGHT, mouseX, mouseY)){ + scrolling = true; + } + + if(!mouseHeld || getMaxScrollRows() == 0) scrolling = false; + + if(scrolling){ + scroll = MathHelper.clamp((float)(mouseY - SCROLL_BAR_TOP - SCROLL_HANDLE_HEIGHT/2 - guiTop) + /(SCROLL_BAR_HEIGHT - SCROLL_HANDLE_HEIGHT), 0, 1); + arcaneWorkbenchContainer.scrollTo((int)(getMaxScrollRows() * scroll + 0.5f)); + } + Slot slot = this.inventorySlots.getSlot(ContainerArcaneWorkbench.CENTRE_SLOT); // Tests if there is a wand in the workbench and edits the positioning accordingly if(slot.getHasStack() && slot.getStack().getItem() instanceof IWorkbenchItem && ((IWorkbenchItem)slot.getStack().getItem()).showTooltip(slot.getStack())){ xSize = MAIN_GUI_WIDTH + TOOLTIP_WIDTH; - guiLeft = (this.width - this.xSize) / 2; - this.applyBtn.x = (this.width - TOOLTIP_WIDTH) / 2 + 64; +// guiLeft = (this.width - this.xSize) / 2; +// this.applyBtn.x = (this.width - TOOLTIP_WIDTH) / 2 + 64; }else{ xSize = MAIN_GUI_WIDTH; - guiLeft = (this.width - this.xSize) / 2; - this.applyBtn.x = this.width / 2 + 64; +// guiLeft = (this.width - this.xSize) / 2; +// this.applyBtn.x = this.width / 2 + 64; } this.applyBtn.enabled = slot.getHasStack(); @@ -218,6 +288,15 @@ public class GuiArcaneWorkbench extends GuiContainer { } } + // Bookshelf interface + DrawingUtils.drawTexturedRect(guiLeft - BOOKSHELF_UI_WIDTH, guiTop, 0, 256, BOOKSHELF_UI_WIDTH, ySize, TEXTURE_WIDTH, TEXTURE_HEIGHT); + + // Scroll bar + DrawingUtils.drawTexturedRect(guiLeft - BOOKSHELF_UI_WIDTH + SCROLL_BAR_LEFT, + guiTop + SCROLL_BAR_TOP + (int)(scroll * (SCROLL_BAR_HEIGHT - SCROLL_HANDLE_HEIGHT) + 0.5f), + getMaxScrollRows() > 0 ? 30 : 30 + SCROLL_BAR_WIDTH, 476, + SCROLL_BAR_WIDTH, SCROLL_HANDLE_HEIGHT, TEXTURE_WIDTH, TEXTURE_HEIGHT); + // Tooltip only drawn if there is a wand if(this.inventorySlots.getSlot(ContainerArcaneWorkbench.CENTRE_SLOT).getHasStack()){ @@ -302,11 +381,16 @@ public class GuiArcaneWorkbench extends GuiContainer { null); x += 18; GlStateManager.disableDepth(); + GlStateManager.disableLighting(); // Whyyyyyy? } } } } + this.searchField.drawTextBox(); // Easier to do this last, then we don't need to re-bind the GUI texture twice + + GlStateManager.color(1, 1, 1, 1); + Minecraft.getMinecraft().renderEngine.bindTexture(texture); // Fixes the bug that caused the slot highlight to render opaque. I don't know why it works, it just works! @@ -324,6 +408,7 @@ public class GuiArcaneWorkbench extends GuiContainer { : I18n.format(this.arcaneWorkbenchInventory.getName()), 8, 6, 4210752); this.fontRenderer.drawString(this.playerInventory.hasCustomName() ? this.playerInventory.getName() : I18n.format(this.playerInventory.getName()), 8, this.ySize - 96 + 2, 4210752); + this.fontRenderer.drawString(I18n.format("container." + Wizardry.MODID + ":arcane_workbench.bookshelves"), 8 - BOOKSHELF_UI_WIDTH, 6, 4210752); if(this.inventorySlots.getSlot(ContainerArcaneWorkbench.CENTRE_SLOT).getHasStack()){ @@ -421,28 +506,18 @@ public class GuiArcaneWorkbench extends GuiContainer { } } } + + this.buttonList.forEach(b -> b.drawButtonForegroundLayer(mouseX, mouseY)); } - @Override - public void initGui(){ - this.mc.player.openContainer = this.inventorySlots; - this.guiLeft = (this.width - this.xSize) / 2; - this.guiTop = (this.height - this.ySize) / 2; - Keyboard.enableRepeatEvents(true); - this.buttonList.clear(); - this.buttonList.add(this.applyBtn = new GuiButtonApply(0, this.width / 2 + 64, this.height / 2 + 3)); - } - - @Override - public void onGuiClosed(){ - super.onGuiClosed(); - Keyboard.enableRepeatEvents(false); - } + // Controls @Override protected void actionPerformed(GuiButton button){ + if(button.enabled){ - if(button.id == 0){ + + if(button == applyBtn){ // Packet building IMessage msg = new PacketControlInput.Message(PacketControlInput.ControlType.APPLY_BUTTON); WizardryPacketHandler.net.sendToServer(msg); @@ -452,10 +527,106 @@ public class GuiArcaneWorkbench extends GuiContainer { // Animation animationTimer = 20; } + + if(button instanceof GuiButtonSort) this.arcaneWorkbenchContainer.setSortType(((GuiButtonSort)button).sortType); } } - private class GuiButtonApply extends GuiButton { + private int getMaxScrollRows(){ + return Math.max(0, MathHelper.ceil((float)arcaneWorkbenchContainer.getActiveBookshelfSlots().size() + / ContainerArcaneWorkbench.BOOKSHELF_SLOTS_X) - ContainerArcaneWorkbench.BOOKSHELF_SLOTS_Y); + } + + @Override + public void handleMouseInput() throws IOException{ + + super.handleMouseInput(); + int scrollDist = -Mouse.getEventDWheel(); + + if(scrollDist != 0 && getMaxScrollRows() > 0){ + + if(scrollDist > 0) this.scroll += 1f / getMaxScrollRows(); + if(scrollDist < 0) this.scroll -= 1f / getMaxScrollRows(); + + scroll = MathHelper.clamp(scroll, 0, 1); + + arcaneWorkbenchContainer.scrollTo((int)(scroll * getMaxScrollRows() + 0.5f)); + } + } + + @Override + protected void handleMouseClick(Slot slot, int slotId, int mouseButton, ClickType type){ + + searchNeedsClearing = true; + + // Click type behaves weirdly, don't use it! Query the item stack held by the cursor instead + if(slot instanceof SlotBookList && ((SlotBookList)slot).hasDelegate() && playerInventory.getItemStack().isEmpty()){ + // If no item is currently being moved, divert book list slots to send the virtual slot through instead + // See explanation in ContainerArcaneWorkbench + Slot virtualSlot = ((SlotBookList)slot).getDelegate(); + super.handleMouseClick(virtualSlot, virtualSlot.slotNumber, mouseButton, type); + }else{ + super.handleMouseClick(slot, slotId, mouseButton, type); + } + + arcaneWorkbenchContainer.updateActiveBookshelfSlots(); + } + + @Override + protected void keyTyped(char typedChar, int keyCode) throws IOException { + + if(this.searchNeedsClearing){ + this.searchNeedsClearing = false; + this.searchField.setText(""); + } + + if(this.searchField.textboxKeyTyped(typedChar, keyCode)){ + arcaneWorkbenchContainer.setSearchText(searchField.getText().toLowerCase(Locale.ROOT)); + }else{ + super.keyTyped(typedChar, keyCode); + } + } + + // Nested classes + + private class GuiButtonSort extends GuiButton { + + private final ContainerArcaneWorkbench.SortType sortType; + + public GuiButtonSort(int id, int x, int y, ContainerArcaneWorkbench.SortType sortType){ + super(id, x, y, 10, 10, I18n.format("container." + Wizardry.MODID + ":arcane_workbench.sort_" + sortType.name)); + this.sortType = sortType; + } + + @Override + public void drawButton(Minecraft minecraft, int mouseX, int mouseY, float partialTicks){ + + if(this.visible){ + + // Whether the button is highlighted + this.hovered = mouseX >= this.x && mouseY >= this.y && mouseX < this.x + this.width && mouseY < this.y + this.height; + + int k = 0; + int l = 476 + this.sortType.ordinal() * this.height; + + if(sortType == GuiArcaneWorkbench.this.arcaneWorkbenchContainer.getSortType()){ + k += this.width; + if(GuiArcaneWorkbench.this.arcaneWorkbenchContainer.isSortDescending()) k += this.width; + } + + DrawingUtils.drawTexturedRect(this.x, this.y, k, l, this.width, this.height, TEXTURE_WIDTH, TEXTURE_HEIGHT); + + } + } + + @Override + public void drawButtonForegroundLayer(int mouseX, int mouseY){ + if(hovered) drawHoveringText(this.displayString, mouseX - guiLeft, mouseY - guiTop); + } + + } + + private static class GuiButtonApply extends GuiButton { public GuiButtonApply(int id, int x, int y){ super(id, x, y, 16, 16, I18n.format("container." + Wizardry.MODID + ":arcane_workbench.apply")); @@ -481,7 +652,7 @@ public class GuiArcaneWorkbench extends GuiContainer { //colour = 10526880; } - DrawingUtils.drawTexturedRect(this.x, this.y, k, l, this.width, this.height, 512, 256); + DrawingUtils.drawTexturedRect(this.x, this.y, k, l, this.width, this.height, TEXTURE_WIDTH, TEXTURE_HEIGHT); //this.drawCenteredString(minecraft.fontRenderer, this.displayString, this.x + this.width / 2, // this.y + (this.height - 8) / 2, colour); } diff --git a/src/main/java/electroblob/wizardry/inventory/ContainerArcaneWorkbench.java b/src/main/java/electroblob/wizardry/inventory/ContainerArcaneWorkbench.java index be8297c6..43c4a0de 100644 --- a/src/main/java/electroblob/wizardry/inventory/ContainerArcaneWorkbench.java +++ b/src/main/java/electroblob/wizardry/inventory/ContainerArcaneWorkbench.java @@ -1,27 +1,52 @@ package electroblob.wizardry.inventory; import electroblob.wizardry.Wizardry; +import electroblob.wizardry.block.BlockBookshelf; import electroblob.wizardry.event.SpellBindEvent; import electroblob.wizardry.item.IWorkbenchItem; import electroblob.wizardry.item.ItemSpellBook; import electroblob.wizardry.registry.WizardryAdvancementTriggers; import electroblob.wizardry.registry.WizardryItems; +import electroblob.wizardry.spell.Spell; import electroblob.wizardry.tileentity.TileEntityArcaneWorkbench; import electroblob.wizardry.util.WandHelper; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.entity.player.EntityPlayerMP; +import net.minecraft.inventory.ClickType; import net.minecraft.inventory.Container; import net.minecraft.inventory.IInventory; import net.minecraft.inventory.Slot; import net.minecraft.item.Item; import net.minecraft.item.ItemStack; +import net.minecraft.tileentity.TileEntity; import net.minecraft.util.ResourceLocation; +import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.MathHelper; import net.minecraftforge.common.MinecraftForge; -import java.util.HashSet; -import java.util.Set; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import java.util.*; +import java.util.stream.Collectors; +/** + * The container for the arcane workbench GUI. + *
+ * The virtual slot system works as follows: + * - The container has two types of slots: {@link SlotBookList} and {@link VirtualSlot}.B0Jv>^)uUqyEabHm?1)zDHX?sowjajaf^6tN&ZJ4&U+*4IbwX=Wdl& z=zA~il~5-5FtmvISrmItVMT?9ySsb18_SfIhB$M7@4Jis{@eWS{
94BPzv zDQ?%V_GCE`=l5^s-*^EAL#}O12@^OQmvI; Coc&($)$x_(_YP_Smn zh}z9)_uqfn{rPu4%(wV?KI~7p+NbZ9|0g_4F#qmwO!4T#)(MM0*t~6-U%PLTg~w&K z^-dEX9BOXh z@SmFcU#3e@wWG1^c4C_Bkw}i`2VGw%)V&m7zf{1ix0xd%L$*NEOP}}iORM;*H?BFK zwOsGzHZ9QIq%X>NF3S1Nw<-pP7|l=j`BnDI`#C4w;-C7~S?ON>GDf3M*ZCT1)Eu@P z$@N}vBk91cU*f$pO8FXo>}A*|dqF6 ^01atnOW^Rm%TCMHeLU_0}J&Z=ws8Y-Xt zd4K6!{4r4t!7cZeuRgKvq0onkL1PvVOMc(ek_HmxCF$ zD{|cGsJZ!^iQz%lr2pCF)hZMJ9QNmXp3K`I%&_L-|9PE%YP}ceGRe$3aepcElKU#h zujw)D=9)3v&!J<^>+U?}gu;LOuZaFF`!v6d?M7$438#}=_dm90MYn1ljJoD4ms;(R zWY4?iIIAkd^;~6viqJ`OlZN%28TwLta`FzuxHc^HxEptUoAm kx?^~Z98?c3!U@v~kwJYiU3(r_c`fX?^*&re(wW%9D)Z#aB@om9gX#S3fL)lR)) zaFJ~|W1k<-pb|6lZA03<{UJw8IExw7G(Yv<{-1O4{(+}|UKbwEoV2iO&a^FT-!CO8 zFH>P!;WfY8=lSC`TO2M+?(kXLRLsvbD_mpBqN<)ER)z<^CjGx#r|{>m!?)jUKR%l{ z$o!Chb+NRc70i*=VN! z&VQH6iHK*rI67`#Vaqsj-+yA!H9n7XV&UQmv+CSFtxpPfu)TPm@BhV+11eXUTRP$^ zgp~d=Zfvn+NLu#)=;ys@xy~zBA9VX)xM$ MP zZ-yiKY(@{)S8Ov`T%S5ir+%-D6~m;b`7RC~j0XN5Oh2zD*SDWzE%?m4B;;qjM#hvw z&l5Q_`QGN+aBt--Uht&t3HM~ZDyxKs|H~K{7-lQfZ~b%Fe_5^2E#*K%1@jeK6#{(H z8-(`B3%EEZ-CXTyw~b$oQNirfc@N_y%tyk{ZQgvIo3&vXn}Rg^o9_RQN<#&>cD-0$ z#(Lz-KjYAab_y>4cky_{G8j77KdP1sn7doQ*F4Pd@Ve%My{3HcT(`Y;Xqj=Y*`iRx z^;fGE<8-?fal5_$rt2>gW&riVH^hB#4! zQ7q%5V=S9}IluG@2fUhU{(R|DVTDQQ*ZxnpW{hLF5yeopn?Ys%PyG 8x;3VNQ~2H#ycJwVQXx^)>&lf7|cIx_`-eQKxc6#b<#6njwCiC8aDot~3aQ zuD`qZ-)8aioS=>`LxlX#;>|buzZDre{65Bd;rA6Mhs(@o()1c+g=JU|ZIF{X(kggx z(t6Hm$EF={3}i6)>XcXgitFc^z3)%>D`$PnZT|JgMdxzbyZOs!zLh^YzilP6!n40$ zZTlB9E2Oaf{&6DSLiF!T={{ke*HsO_)J2a;T~B|t`T3Gk-rUp8QmG6_pRaa3z`6$H z7PB_rH@yrE+ 973rzy2ED%msJP zY3P32e`9Ui#k~(QzGuH=;%;5r+PQOPi^?*Cb2ih{&&=m_?>X;&wzo-qbFd5(!wrdb zpYCxmWVrqR9@D@7%~O{98H{(#C;qqVoG*A`hD1g?!`spvo+~#QYK;vqJo*3F>fVL_ z^R_ 4j*S7KP+4t&>hpJ6K-d1$bVmfl>_wt$#{!s~6^sng5 zxZ=9)*o@D=STBE`UurzzN_V%>_2er*&Rh|C`~3WM117y$+>k`0RQF8Y-nxXj?$qPD zP!5B;3W1NVA9BzaxUrQjZF%Cu(_!R?IuZi{3w Kd<};sp z)bW<%fxSK~1uD6l=QsRvWSObz5V)d6grU96e)r4%->ugT)^=Zf_B}YNmQ|V6@rmEA zn-jJ!D73lW#qj?M@5Te-UZ6=j2GHnm{;TI=dszezoON>8tK-Piv0nUvwBqyk$C=-Y zvp5v6mIMgwHgTBq)n0Lu!=I3uFRSvT=RcYJ`<0lbw4k?Nfm52D!}&W2$KR kBoR_Rjt0@n;=_wbYDn zG3E@xT1%t@H{IC!RZrwz=9Tlp=F7J0v51si+@D!=UgztvZw~hZC#VUgovw~x|C=%K z{)8Fr3kwQ8R-USNIjU&S%f29;?eCLo_0zihxAN5ef4^lNqehQWpQg}mV+X56b>e@l zV^{ >u^ocho1t}vUcLb;r|M6SU?{J^Ao5$3 gMWFhN+zmx<8*UeS1d6`}wBaYOgc1zCWM9bRo%M+vY#Mv*mpcJuTR? zD0_i&@7)(kvhReCa%>M+ANDOfML&;!gUciR$@}M>lXk4#6QK2PvE^m9?ezl3K*RB# zE{-AKu$r#^>;IK {U%hmG zt<0L_I}C=V3}s32Z|;X1Eh(rySESTe^LUG`>Wh@C-eE_UGk3k=O3r1L3An{&v8Hv> zjh+8$gP-QJ|GOc@63_ACZ>2KRp`T@swy*7;<)pdN@zf<{ 7HD#-~U0n z_*eUtH4pe*@^`Zw5#hacvT>irhESFlhvo-%{it+VIjJtD|FWv;zm3v|tvxdv4A!)- zTy-*___5(9{iB<`{^fqFkNrE}^?%B;pPAM1B1}_%u2dKGD(g yV) `i_q@iF*U&zu&9&n8RUmsMVoFPC`XwD|Li`b{tHFJ*f4!DaFEH?_~+ z>D-veTmTxQ;+Bz>z4-B?;XL;9o4 h#~E>dI@jW7^O!#N sDNGFF zJ=j|#&oKXb;EEMr?Uf$7{E_ 3i5m|;sS^{ZL*Zj|1F?)03nl1*d z_d*}`{(i;KasIdVP5(nCE}In%q `ixJw=}$v607-6r@-?6vFs4m+xKORE#Lmj zeHkTFVhG8HH}3mHSH@4?SHkzQuw}k4)0XJ}JRhgOJN~=T;e7MkdbyMKxBi#Nd4ww0 z1#>&39owgOd!eWAhRDDNQ;xVDH 4=YNw`Sdy+g z6)C-nWeQeiF`0Bfe+PqW+tZbie->}%EqTzdU8UmuE9pdBf1pj8 T~+&}GMzxClvR-13%%mfww)oj>$^R3_n=_&kzj~qUvw|!~m*zl6U z(!XVWpTnHB_J%FdS64D<`mk&XEKI(;KHakZ)9s(HPQ+jNCT{*xzmFko)7FXQqHKb` zr(HWY+AR{P`z_)&BX@%9U$y)5U4Kulwx25O|0<# tJwSP>!p7kv1Hu%>i+s4chBeN>j(rH3Y?hl`$hik|IY$1S1TKwi)AcjtjJNi zu}j-wQ_}8E<)fKl3e!a|-JB4f%`n4x>weu!uT7)>pUBbf;cF;Y%kfIeTJ-f$#G@Og zi5>CFzoZ=PzU*YRaFN^W_&xXJXYbwRrnpY;+IO2-^Ivd(PrMnK#sC_ZPuTb(e)^R+ zGq3Jmr>wxibnQ!nh53OU3^||wm3bxTNWBsK80q`r;;-$R4WAu8JU_{KA&+5`y{~LT z#3fx(=2chYj-L9NGB^5}(YO5tE52R7vws(3nP8xO?~k)V43lG8DmJC57G!Nx;Zl8= z!u~g T$N4arlx18ai?ET$j0n>$+%5=1#XzDHiAy?p--@T)%;RPE{#}gg(%GqoaHa}sw(R3i=fBz|_2K7{Ng{b#S87=Zk z@>CLL|Nb8R^UpUs|9|)Xt>+Ppetmz!j(G1moeWBI=PEq$u>WWBneWCG#uF-c_3APw zRqnU(x!(O(=JAJ`V=W*28qO%x-rNOgk{JAcpHiD7IqT-v<_nvq`I+8~PEXLkb6lKb zmMmlL+Gfdv{X8G9w>J1FPnx8BAX%Mbj xakAH8N?%6Q_-W$kLgrC)dNt#MgD z_fI-I!^XUy(z~wDZ`;LkyGz`P(c@K)^BIR5-w$NIXZYGw9JD|E aX$5Mf+ LP zV7u$5?XC^Z!B3uV=jbc?w7l5;$G1O{N39xeD80Db;3>qIbBV#o?1{Z*$f5S54vJjU z*|GzB{;B3Y_U3N5B*S3+H-E;me?Q+buZ-C}zopS?-G>0LwHM!x<& zy~*#qIS#p8W{}xe{x>iA`yqp?#v8gAw(D*Xd05Q-^ZE5q|964^uXTg#LF=A>xh%K! zpZ%KpLUs3^=O^kT1eo)dIVh}~^~PQ8ll;UE&0m*0=AWB%_54Gd=gdtdK?!dE7OiaX zRI2|}`##j~$VJ`{57)l^f8FrFygzS64(v)(a=ZHG72l>qwwi11UY`E!%Pc!y#a*ip zivM1D!r D29FAf468?6=QOCH$bu4JoZ#U1?DM{oYt1MhXd{y!}_)tc$t+-d`_ z+@_7f4&kh;g%fVws*utt*e`qj+~wuVSmhV}zryuG?0?1+{Zhf$9LFg(=IcZM-#jqy z#=YZdpBBuwPxvNKV81qWnU<(c))xIxsn@3)KPY$34srOCclfQ1g5dwVx2xE*=6i t-*Xr2$ODRNes7h2bLG&x;AxkypDZ&{xHxBnkTw6EEe_@T41F(5s6C_I?<0O- zM$~SGJpvs~2X- h#b3^kLFjhJZqovZNEC zf6aICzKMvnPr5EtpZTUBwnpR1X>tCGyqEW-Ka(?I6Sx_?=}+zz`Q45g9!Zy&RCc{i z5a_FI+*x~f(etYPT05>e&Mtuj*sS_BwOjY={(Bvqd? 2&5AdF78Tf6RW#@5=gr zN=N#Wx|hp&nP8s6pA(+_PX0JQ-`Zp)hosaZ`Dc0z%d_gYS##gm$(S~I;g9Q&>^fyD z&pghFNGfb?Dr8)uAhIO8?tmD}0qBhQAEgR88-9iuqbJ=tr cVy1tV%BY(p2Z-Q++6FuuvXVv L<*_M`;C-e5y|Nj@|@!-b~iSy0RBY#!$@$qeX zEoW2V;NrqBZ>OTP$h!QUfZ)aDc3(9wh#3gKue!eb(fjk!_kUeGHvjtl|5wTl4DYHu zOz(IiskF~i#k}(cZ;1b_>b8!&w)y9Gyw2P8*}U_|%wHcrR=!EjW4UCb{OIzA Unoe-+9XP z&Iwao{*&GO%-2L`rMn7`q!V}a&)Xj;?|qB^_~*1;`geK0@0?l7?qlxM{Y+EP*7W%A zm6q%L&z2{wQ?CE{vgh=#;A=CF-#?Oa;Gj)?L-@gq7X@YI yy^WfBYuG<+2uVz{H|6HpIsNuOs|1Z= z2A_~~+nzbN`p(_IzW8%>rHa0m&m`vwReye;75?5Mz2I^0Z mldZoOElT%xQ_DZoyi8()(}Iwiv~%3iv+G Qa5i7pGj(Sa!iM`}yWr>9jyWUf!S8j^cIvM{3?*>VG@`=6jbvu`>=nR!t1`+M1)s z-k<~;2~114a=QCW(v$ZxjcXp9)!o1GGV|tX8y8AWea-#RE9pSq2V<7wd3W>I2nI}l zaAphpyyX`UPIOtB`F6YOf7aXguW+1+UV3l;*F^#sE5F`~-5tAOiTw?k-*sJok_+db ze0}_}eWv}(CC>M>d(^+h$}QX6{5$P~|N5VQZ+)M(lkw?;S-08#fAC3X BLnefkzw+qzwF0+_0Ew>`4wL$DoDDR>4Z&QEPP3#wApB1>@&`Hnb?3*aI=tXt& zME|}n&GD=)?0$N4`Z1B$;%hWMuI=C0ttjfE_At4x( ;sdmnlMth@^v66mA&d+i) zxK_93&Giue)dHGpY@bb;mtZ?zes$6Mdg+tJYBH zGBL-5#r~JO&qcL}cf?P5arE5F?PcF@+&Q27EBUhQ0zU^CA(NL|rnp9N?2i%N;FTEl z|C;w?6`ztLhSGuxd6g3-9-VKQu>IHVsz0U2_AAz2^oX}+h~ZYe9eQl n52 zSczSEk)iYKm$%aaJ^ougkoMGs|GsY~i_I-O^YUBTB *zq3~kW xmuuJFPh9&-T %; z &&NLzbvo(TyZAV|KHL*|5e19%3cci8((kR{Qhk1_DSwvma@9+^x)Xd{iv@=?9lt7 z*b2TtHn6|_*c;AnvlKpQx+d0}qb#oBZeY9?&+Fi*jnO+VtHi!PsokA+T<_9cmn4yS z0>QPXwEk7PZMnH^(X{BT2ipt`x9z`w>-mwuGhf4f)fMs#w(y<4l56D?xO;+dwHDLP zmoHNGOaHPKIHI&$YSORoji+Q8HoG+J-F@ceJ+QZRm_LU{y%F10rNMjLW8Pi=-|hFe zv=nwnJ6ui+ImP;V{<0$`XIYyfl#Bz{dx~ Q)hTk9-MhHWf*Z}(Tl z&YXT`ZzHIIbfbmgg{kt+2MisZUoKhQ`c)LB?qKJh!`b5GdSi BkrGg9a09;&gM|7${~@umLdo(ex4zFqWPdCBl<2)BRn z_2V_$FA3zZs(Z|6xoPQqjd9iderLgi<@b1wM|trzY74|{7G`E-h>?6T&72|POZk#_ z3 !MQZnxOmpdSBe%!C-bsKjP1uY>j0PKYLa6*!F$fG3m;2n`P`?Tcx+P z-{0l5OwZ-$e2a_EWmI0y+2!&!d3yAb8?#I$%NQA^+htY%_^|MWS3(Cvf~(_%e;vj* zSKRMp%)G{O |fs(c^;9K9j`>x>8Hho@h+Vc*gr_ z`|as@aoa=or03K)|MU6k=Gb@qg#7i)r0{LW<21CdB+vi#GPQ5Qjo%%%@9XX7C?ts1 zwH`jDtF-p8TxC&y?$H?q3=ON5m ~hxfk8Pd?0=ApSO*KYT?& zecmqS$S;|PKdSJ|SgvxBwcv^9>KnF}Roym*H8Bp4Pu9$9blB~~Jf-O8wMYEhy)E>F zPR0i 4R9&!6&w#t0|^uvZ9 z1NY^A&)ys7zwT-9{__8^Mg22g-=FC7;^yz^a~gt@;?Jz_D-rpXyHBsV(?dl^$^u{O zPhhddt+ZyLg496Uoz@DE(mP&ADskF>J@ReW?1#^#FQx9Cd-!XSv2EWx#cAdfjvVjp zc#(Ph<&=&%e*5`CAA^-Dz0UZ1y5t*we|o+1iOD^ETleep|FmAalxO_^{l3Yw&nEli z8{9u=eD=N0z4vK#@pWw;_Z*Ix->v<=Yd?Qol>GgQJAc0muM_|N_v6Z)?=-KP@|ajJ zy%aWOrhQ)Q{gVmv><_Gd@Zv>BUw{8cn~Hf$=O5<|X1Eb><>sXoy5IDR7xu*MSwH*s z!AZ7$XHxbB9V(Z4H_d(Zr4y;yU%anu*=BuGc_-7--zVIZ&Z<5Rp3St-$wi-ay31W* ztvmWM>U``DOFqV$=G1(=ZylH&?YhPLmYn 2VgMO{+opAco&y{)$b{y(Y_xY`PHMYbyWiy*PXf(~i?5i604a@(|I&UW?#!B2X z{nYFHB+uiF-A?t&JVj?`n>ly=cb!b`6Wz?6yY6-$mqCn9AkPNXPdOL%nXKgzo75Iy zkp8w@ciNA+6NEooE8OFq)U@#M+0Ckk*S0EEY(B&T8X{XDIP+-O`kxl7jvRcmxL)r= zs0hoWZ(nYCT;0WIY3=d2?osiNw@dC%d%Ghb&*4{0(vcZkj4~B>P3vnGxXgHEZ%cYw z$vNHcPgUphgPUJvm2I-zW$V**g9Wy;+%$UKcxjV;+@#mG-bY2EPI(3XtvSCv+x$T1 ztegc0d%mm73YIs&u=dy$vE}%?syr*MZwlvY_VvA%J`brgEziAt)i17TY&Dx>Z^VP^ zhoV|zYWCXOrN4`a7K>kfAVlZriv3&q_x=6(OkwHTTSmFAC2wNHzE4>6=%qlCneBu3 zrytF8`*fdqTG_{gclXEJ^grHkLMxpEwD#9^=Q0zy^M4kmYp!NCJ9NOW{A3r$QlA^s z8e=~$oRCt=_NMxD?L(=_lFmLyuYI26>=(ECOjpQuJqE6%hRd^iF8|zg)Hi3J|2a|q z?HV$Lfx9zmTT}M)d)D6&?2cV2b?W(#?Y>DdDL>BtasiL{Ik^2&eJ1Q}c~;n5?seD2 zmRZ?}IZIYWKYqk(tIn|^`GU{+wFb*(eyht~_g`r% +28?Fl?O^#r=8W!E4_(&fEKQ z-eZerP7hhjzkJwwRk=iTR-RjrBdBV kac@gv7OK5^fEm(vl8Vs#Js zCaG_a3fm)mp*V0ub&lB2a|+Vczt?mWsrxxZoYjtdbL0HY{_UG>?Jn|a%Bb7F@I0kC zSB2@!mZJ_|l9me_O`Y%Tbv{(BYNF*nejg?l28J67KR0*(kiPuvkNnp|CU({J+oJ!d z %XyZ?|0D{M^ylulG1#TxU7)?OTEDSLq`MKToJQ`R#tBl!JY^m7!&k`6C6l zAFmiZ^lS38SA7!Q|Fu|jUwYa7`9eE7Rz9AgR^Gn6^*(>Nae&pfRx4hyTWP;onHU%v zvitw7o!(+G!R~f%?W67QH5W=BZ#Y| U6w z8;{1qEjPZU QVuh=CgZa&strTbWGUifr} zoU3&g&zXg77n-|d{@2IsoeYO77dq~WSMhh&(|!E8^;F=B-F4D>4jup6ziJBoTktQ( zCS#Y}KMTRhFE*ZJnQFVPYR>8jm*+pbAE@$K%l~!6Mu*ndJq041FPXG_IOj}1(i<@O z(5eno&9z}Na&nh0Uc7ipzv=nG&kP5a7BDPYtG#a4{N;J9>!S{bcCZ|luW|mDdN3ex z@eco4toe~G@~%yt?{@n8G&__v%A^XMD0WhrT(D28?##BijF-~f^UtzMEEDFReBq>B zwZ(a6_kWH&naf$e8$Fz&_qy0i_rja h^F1fn@niYYQ~l|g z(;H_*GAw X{n2``P*B1OzW0Zs*^-oQ+|%+x+u0E}#8lbYEps zddCk*rJbHG`5Jfh=bV4{IRC!#qF|*euOrJ{K5en{U;ec-UVYN$g5SYPmcHMY|EgLR ztYoJ;@z R=oGS|JKbbvspK5a@TXE zY7x-hlQs5oMc>wMuXGNzPoGv0TH#}HzH06~wS@)~G|vCteW&d3z3Z1JOj5n4&UtZ- zNuE60M8P_*^^^aY-Vm9oedE51)`F^{_0#u1f5F6aX5+ 9%)(VToOr@?kNNh=60;8f9)E6CY5uJ zFegW7 M+qXLsOUT)nuHu=*vQpT(}dR~SUQm{%$-(^}ea aL*J~d_1`0Wz?9L=$%N(nJd>|B z{GA#0bG}_V8Fj|STI21G#JPG7U!S~_oA^e!Q?Y*KePegS&C~1qBN8QGYXRzP^{VEs z6*V{>b|O}u_23epU*D#bGKI8#365oGe|^-NGp6I8x3u`(TtiXg@6$I6S#>kKzrTO~ zCvH$uhtECB$jCHIYtU_!-C3L~+`YRm$va`H`>&LB!jHKMM7cgUNhq8<;gvLTcG$sw zO|g9&xBgI{$kM9T_~z@*v%kC6M+TbRjytwCMQK{bt+XrNYD{6h9;?;M+jn|&F8@`v z&^GB7w@cp9^9%ASRigh`oRMWR{C+luVV&}~o*(MEP6{>YCcejKOm>){BO6e}WA%Ww z@%@P#HG 8UYxSn+V{BQCc8KsS1oJ;J>1lL5} z*(#8*v9eBei>;R|$Gas{Uza5aE}vI2&2Veq{P(xSFVtMnQc{?(zf|j6v@65MxFU`W z52ba{3vQ?;WNYPgB?#@C-}zH-nQmW$(9b1;f79>pwqki$y^i%*$+`PGr|BQo)xOif z<^bANqp+a Hpo8e3zWs5+D60X8wB4s~^rcecN<5`uypo%&XMDANu{|@0U8u81Xm%e{Gsnzi^$R z^1q<01c6uVzs|WDJ~^NKoFStn|45_HiU^Gp=bjqo`3p5%iTiL}Z41}+(`mc(*?#Er zGcZh87$O>{^ra+eoyQU`mVD*Uo}2z{{=7`$g5Ue#+4HX+GJE7Cub$hQz0b~3T|(`V z;3n-7_bWMe^92`LZC6;r8^Ur%Y2~Yvw(B@!ro3VPc-n5_ofAhJ-2NDyk!4b?lzjF) zS@(c~tzUogo_mvb+irVx&Eoj+W%-L{C!eeja{rTbw mF~pavU^v#Pd!W5KLBbK z71+3*^(s(i)7d%MT7TQ!^X^k7dx(`ju`Co^^HcNiGUW+dPtN>2XHlw}aNuP-!MiIK z=j;odzx?lw?DHjyWmsliGtTP{InA0Ao9FQL$-0-H&)@5}V*C~PZDq)j69<1LTz-2X zNp^x`k=Kn5hEI>OCbi7^&v%s5VxG$B`OEd5P6}c+TzX(xSOeFSdv5=7XJv0*JOjM1 z?g`8D;@84iYsL5lle_)}={nR_%6MqF_8)q->jeYP+1EU?*ENSN`W?k|PPy*nxAV7s zOB%OYu01j}qS%0M`6@>Xqtl`v7B{ba$Ts8SzGj6Gr>Xnhe(srX&D2}f@N3VF<1M#a zVyslG7;l+gFwbP HOwE7EzI*;zt{Ce!i`9MeRTM9XHcoTn6j%ONCpXhw`(6h_^q1r2hf2*)T+>f+ zZCK>m_*>KTfEw$A*Q_OT4ESHYcR9xEu2yT`TH-%VNn*BN-xuTG^A;svm=u*6&5%-8 zbeZwSl`pQ~+IbT9fk?;sLLZm-{EG~+H_T1*TBUhO+*@N=Rcy)(t`keLJ a;Zaa`?IxOl_& zB-@6Jg$qjA-Xy1 2wACcJ! SRDpBKC zjiY+$)QBxE|C92YL7O@^q YBHU^qq zaBmmp4c=NW!gTUq`YnEyef~PXw?18eu5rhU`#TvY@rqh;Z`;51Pq3DQQ c3Lmq_F4U$ zBF7^=8R2D3##2hUPt^SVz4_hd$lvmyRJXuZNju_yQq<8k0vALa1h{pkd9+!6EM6h_ zAvx>uvIBi$_SR`PzIUcpR-TJ#sItwocX_$+ga5CWwVlc)W{a9v`;;uP{JL$!1u= 4QJr#rRihi>^k^VrQN`*z)rQ+`
qY;6HG?i*UB zF9X98PB^BxY)qWPV3ymzXZr2$M>8Ahf)Z8+ALtc6H?KU!Z}P8n5oYD-Vjq+ie%Wkb z?2zu5VfbLvk+&>N!e8gtW-i|U7(AH%R?lJT|BdPQuRZVn>GaS3+*|qO9oAfov!&Ow zHm2PE*QWV@-r1Sv)9gJJ&uroS!x}U#uA}PhK1TV6)7&0r{fm#;k#&jZ%#lmV3*&xd zUYGpdxzk^X+5F=9e1 6_` 6TN2o_B62wx_-(WBY(hR($28agwoR363Y zOHY5@aVBTiX)C@(3=4nEQxW_3vhuM>hAzWxk#^}bhnr0{sE2&n{OzZC5R>Uk?w?i- zwc#!+^bSSFKG9HnrC!SX>UGQUnF<|u8KzukUGh1!?EaO1E1Mi|9asC!z4<$1&ZZyy zpp1}U_ayX>&$8Nc+rF~SwpQM4_Njl#`Mw{AJF6QX6z!fL$@G8Mi}~JV_4j>#zn<;& zr-~_YRmFGK+_ZfT9?ly&PW~0o;%ni4Z!ap_b+<$#?U&+n fM zLSY5dgE^n>?4R`S#DwjF>?xO+mqs;2s6Tkl-sAiIK*hhCe~o^d-8-jm1|ECb&TZhU z$I$C6y8GnsY&(mH|3a;f^H(Ua%=o?4_nyXuWcL*^i|$@|uOBJ5^XR91?LVhq@s+S0 zJmM?)<#5{}uO~Mc6%=ooGqs%k9U7>-Om@QC=kjK*3_IiM);`)ExL2f$@o$5|E&kS7 zi &dR!djDp7Gk}_jNIfFe_P6)VL;t3* z|DM71Kgc>}N8FP57pKcFR_Ck?o}?|%x$(i~=L>?g?=}3n5wE!Yt={bHe03hb#T+Z8 z1!F{K-?;vM`8DTP*YiByuze`yD0>)ar=a2Y@wC?OtGpb?UB1Qs+pi?l`|teg$&>a} z7#8Gl+~;a)`kUX{xQj7~^ X~; zc}BddtG7~Lv{{AW#hebmW(f=K?}h4i%9Ab^{JV1JxrwdWJbUFu%b)FA{?KB(z<;Hd zeLoM{b6bK2PaOU*=d%C!apzyhtjd3KKj+lc?R+l7;Jo5mn7ZMk246;n^z%nADJNRD zZJ*!!WU9sH13DU6Z=`3mo!6W)jcMlJZ>pcJf4?=Y&7ie!qu7D9FH>djzJAW^VfRqq zo4JFJdy>_n=f&xtuQM%J_r`wyM5znA8ag+BSNHRfRCkDZTHpC0UDt2Z_T2r#;0&3- z_a%R?#oBpyHczY9Jih+w`)zyI&tIo}`Q3C*Mx$-^f!8j}>u0n09J!-B(WFs-+ryjd zn6~NGFAm5sH*<3PE_LH=+qO^lw=#-Fp5YRe{`*>Ck<)W#-a}tAgBNsovYMp*{vEhK zt=1s4^Gztri^^5{-U@ZgKJU^EaI4HxSjG}`P~r26cN`m9^6QU@9n8FU|Nf>+=6V62 zk{rs!{yH--Oy|q`&wL pSkRi)whA zZp`j- {$G2}P3Z2 *1Uw-D(^bp1K zhipd6vMeh%P@2ylf!cHUxwSx{rWD;ppz-IP?{+u z{Qm8dHrxC@=G#vl@=OY4xJ2qsUD(O!^)J--kd4x`Kml{*$=|n&)q8Pv^#5qiI1$7e zqb0QEXI*jRv9 EL_N%@QYKPUF5Ua$RB|64v~?)mK;^J*`LUpnbtSNrn#|5N#Olm1=% z|EGD+>FfW$<^SB)YxmDM|Ni9j^_fmSF8e<(PyTg2{=Ko_#q@u-=KXm%U2Wq(x8R&_ z34i9-TP@rFYnkHf+JB$Id7u3M{i#K&zRdFf%m3QNFaK}8H-A?D(@9O5HuZaK&%|U_ z>-N=8w!EYFaO=#BDEp0j`|I<}&ZTsHeZ`&AA8DiZ?dKUog++3&f3Ljnt-nwH+|9mD zmllhfb-%u #Z?@2+ZJ*uWqvCE`zHhCLxqfgd^O=-= z#frZ+>-W6qjo&W5{(qM_--|EjgBiE)`>+4^W5>QnXRD9CzW;OI`tIxP4;`XnjxW1= z*5}~ni3JLtivIuh{)x_AGjZ$UhElcte9tZ>*{YtBGcA5&_2Kx|e?MQ JN9h0|ug_+!On?(lm5^ZH|xb@s3D+*ZE^ c{lusZ2`!^fGmZC$sJR|J+=^{Kx0t`yBpkG~aIL zFppdQ`SnxV|HnUfsxP&FE+eS;&!hIA^uAp`XViP7f7yRxzkmJAf7!q0In3F8K>yDt zZ5Nj>=eGZ!$~JNR=bz7x%Kv#Nt|X|}JpZ@2{r)f6>tBBjKN!>h-}h0i(yuS^|F^fy zc+q}8;Oc8nyK*Vplb#Qp)fUz1heins@BMW&@XX`Azm66vX$K0e)Hk2BW#W{>{(|mn zww_4!Y&oO&eR;?Up%alsL6 7EPZ4Kn`P`asMp|R(C=C0mQg(Ke=ou9csp0EDQ z43&viPZzn)_g}W~T(y)$kMP9r5i6FbtY>QI_~mu#;l5u|%M)kw2wyZdTo_~j;tO|j zqS!0J%kuwDYRK(g-uUQ#!1RNcU--Kna{01LApBv2fgtak2fr@K_dfdm@2S0A|NY{n z`=uY+*8SxE`uCn7$A9zskNusUFSgr#Jbv@*-)Mc`RqEyL3;&)A`R;xH=0lsuF6&(8 za9#U-#pO|1>;}brskSeNZ*Veh{-A#AfAXpA|02a5q8WU@tl!UjY11jc9%g|wMvoa> z5&X ;3+e?^{*3|Gvb#pQaC=Tfe^i zxc ;d`zwfN4t8pjC-`V!wUv}~f{aq^0zo=p6KgGEh?U#zb$bMnJ z(EP&j&KJJkwG;B|z9&9^yZ`&^;|99x4gU4kf2=?Ax};$GgCCvoKQv{|oSuB`rkB)< z=zXtW@5+ 1cW~RPsX^0ojS@v_{+;!%L_G|yfw{lb` z9dWi}S>fk6!=%AOkMrvf^Dx2HU(auR8@R+|Zo!2+0UpN~6FB$&F6%sR5&HD^$-0!) zzu$^DIDeb <+v!{ zeqH@1_bkB=_diabR`+?{m-+R#Pak#udup}*hQ0cr<6B-kyx@{(?fQ3NlKL|7eI65@ z8Qs45KdA4IGUxKAHl8dI-207g|2dPDly~y?al3ENSR4$$)ra+8xW)A%o59Db<<~;r z4bwg1e}&|5F426txI*3V*Lk<^$0Gl>oeAYgITByQ%4N#%D`x4+u8(`pOj-QsYxK)w zcfb6Z9?Wq6JL{t7-#zcud40(>zodJ=tocd3z3Q+2yi1*(-*jKf%g9_078U)^fBzTplK;8vYp&04f4%vC^PHILm#_bC%DeaH)UDY6ZQCz>ulv!S zT2dGGZ++h9U%mey$LyJR`;k?Bb@uEHx1I*CI{Trh=ft=E?j<$5IIeR)SthgobZmOp zw*9xhiG-j3(%~!~Q4<^MrM)+8*MTKmRW`lGxvxwPOu4b=e+c)4cjEfOf}Z_ui-Tvq zdvDx+d;c@-_M%@)3-|QfU4QXs&a?HcREc9+sYx@O-u7UExKaFIw_``~LXr?`Fl& z$%T)1OU#{rxuAZ3#b5inAN*WO4~}|%eIob#^4~S8e%t=vpW0CJu6ygX{bzsvKC$2H zh~Bp8alhYe-L%gu>AF!x=SI zhr IAN-1OhlK)-*I_jqV3;tF0Yq!gn=fxBEPuex9w)4YYg%AC|pOwq6^JS@d@O!_{ z{;x0Nmwn&=K7Q%^|3|j#x&E8~^KNj}>FDn-`R&Xjx@zKo|8al0SN>1huch;UteZRG z|GK#U_BEIHAN!)Vh<&}CkkTUd{ogfiPdj%+MafKcs%nh?{5s8l?`>*-Eqze7E6LLR z1FvF2RrSuoy_Ici*k`13HGZ+m`S-8wyV@jMd)6f7{cCi!4W2Y*7?dQxV%YS2+MW%1 zW$n{za+i60^;ya1a4}iYFP?pFyA^}dqS?=44Fq}5xhsWS=dJm8GV+b3HE$`y`4+2& zdoN >P5F}6F?JM6W)xKlKr226|$e_M6?zWx)=!2KZ$^XsKf)SSQZzwJq`l*4q!Ozp&L zY#NnX3L-K_te>ubSDEzt)=mAX^V4p4ADx(Iz3|9U7nysnXBMg*+SkPPvs%!A>-*Ne z2Gx(7pRgR^uv@~g>CgT`7N_d?S5gwQ=TFIhryct7x7NLapG{By7PC9NtyfwUey;Q1 zH|frQ%l9k%vyPuSaex0O-G|kV0lU^b_xJOAQXF67|4sej_Mfj`R6mu!sQFh?aPAq` ze|D#~x4dU{e7R{}d^< Rk!|N4uo_s?^Ok98{;cL?m5 zP|BeHZ~gy-zLEpoz{Gw|KILTln9bh8Z4WlRV7U{Vm=3-7Py#q5kaC*B | znC-dZ9n*&=>+QY8_Pf3``!Cb~|5xXS`u}p%{x@~}H(pe~&QGW|b~OW3No@>BO?L-F z{%3u!fA^lnPx-U=?7rMjcfY=7KG5nGoBOWoUs9av)&`HC2hTB1NI0whNPj-l$>P*$ zqP)Jm4maWxZohxD#L0Sh!i)|(Z)=Nkr6}jB*z+87=j~jVK2LwmtE*F7ePVrl7?XeK z W z7~KC&JL8?n&~Ntp{%)rJ|HnEFmisl<%jq1HUpjwQ=I`Gb_b2ajo&EQHY-4`icg4Vr z+u4VI-~TTCC3^n9`WMXi|I30)STVK#+xL_@&Hs6~xa!?q^Ox7__HH-$x&M3fevkFF z|GvMdwf~~{>qx)fHotwl>uMQxyjaoA^uBLJq{yMHAIFP3HENdDr|Qk_s<&Qy-tY6| zgum&r43n=ouV-znvb!yu&@Op3&^q|UP2tw#HyPc`wl7Iam?gvWSI21Ko(4mnLV@rt z5^w63b+xFw%={ZaGwHyzkOqCeGhEE)H=7+?<8a|R`-#YRLLVysM&7#hH*M|jT&|{A z-`}&n88p1Mflf-?{98s|KW(PGy!_>d4-*dyR{Z&~@kZIfN~QYmb%&DQ>t~4HTMjyD z`LN)R3-^C>)ZYL8&w4HYzn}g!+I#=kx_}EK{+j>gIyt}pAAHXCW!iS3+GpkdFL##T zkGb*f|I+zC^s3&ocgBGVrCR$h3)fD5zb;;$L9dfz#j5M?=3P(ah JLX z|EK*izO*KYy@88y-P-@V%p7v-H}A68{4du!t~g`j4bh{8*X(C!Opo2aJ0MK?z{|bM z%bad!K4260*y5sfd8L3~uhRj}sjnD orl?32l_bXZ42(W|IhsV z`y<`rpUStMu(`KMUCGMECgx>pUtiygCr_6AxU>0z?(fn)^Y3kTcPR;~d8Zd4xWVV# z{jP@8qJPs`${it*C!+M=rUsMAyXiN4rVD!nGZZ9C`cIvIU5`OdN@=ZU{0Y(juG#m` zJlyW2uuf;&&MIXFBf(^u2Dk4`iuJ+U6;#sB7Cf~(uj0?Tql#f#fWQpF`r3W--k4{) z{fk`vK*OK;M=fLPxrSdMQ#<#r<(OdIdcgJc?{u4pu79F-_xEdgEqNcmS>&&F&A$53 zDIWim?SB^=%YXko|HrkZ-2XyYbfP~jSJ~qY$y};}j8PBev`$BwU!QyQb#}B>yq&V4 z(AVzFLq$>_pU }ZRvH}((5yYcmFQj)$4kGf870Z-wM~yer~BcsldKkzLrP) z-sHMzZ?+jL)k*a=@3ocf|5ah<`+a+N^_PmSdF4OrPWD^BuH<`iKS^f$x;Le )RuD23HA(U6q)k&h6H9=20t=VIjY6R z^YU|~Z$-=vkK=70)(D*N*yQqO+8^1>%dZ=Eob`-T=X +w97TPde@AY@hx%+2uLoi=V6h=>A%?U(!h-#Z_c zHCW2%aqNhVn&4)62e-89_ V1E>3@fh;qte1cE+P;ThFm>2>v7W`R`PLovAe&@0w;V7x$VI7ct+wuWgr9 zq+-I<-3;3}E|jr+P|5k|-P{!9o$!{UVB4qbZhy+M9+;?CWhzz{y>o~Zh*A5L&(V ;3(ae*eqVFSo?^Z@Kh%|KI3+z5D(~@5{~nxZzFm z*N^xAmj916U@vHOIneFol74ma?qK65?p#mq>#@BGvsXQpIO~si^&j8=`@{aY8(uh_ z#&D(h=VhLT9Y_7&SR|hk%Wx6AaHB@}8e6v~Ysc%9gxy6ILhn`^Gr!q($aBX%JtL#H z4Mxd62K}>EHns_5s8?%QFkZU%yZ&a!{!oUTT?`vkOr9ye@ZCRuozsDM+n;ln&MOvu ze!%YE-2DIA-tPZT+g;nmzW>wg`7U4h8D5t%yIq~Ud)xE-lj<^9w^$YlE2@hhSo>?K zV-d@VZ+~~+slRa{{Q1vjiwha?ucjTSYTq6EN_fWljLzAC$C6wRn8>HTiDukt8{lQi zP^Z@*FF40<&2Q!;=> 87g((qcB;SlOnw z^`IX|#uxcm26JHrG236ZjAaHB=CUW8h(Ff$=IyzLtY_lNx#824{)_8>eg7cg=82ln zm?dTha;-q8X1lTYtWy7eX@N|k@TXa#pAXwu^-cZ1jM<^*sk|G5@z>WG_sbYw2rSsK z;ke)b*E2V4Pw!ZttGMkfXU1~p+^@w2Oe)Km)!YPHrnp^Xonhi9(-FU83Y)~lSh*#p zj6Tm3J11;;_jp?5)PL7rtT-PRcKiOK>uzUe3o&+Ili2d~#r4*0Qq8G$|3RH7>%T_x ztG|~lU;lrfeA7Y}hVJeL@ul^zRd>&DYyUIDk|9XyO|Zm*$G<-;-PfNo^=lem!;OWu zFKu35m~Wuo@OOejnR8u|_@UPiE93gVi(9H*yq;q0 VeVc^vgZBz0O$dUi<%zcX-nuX{Ll|S%%O1u9^M*5?-qt%k$;m_rJ%^ zo%nCOzuGIm@^wo3lmEA#+k3tL`#}GZz7>PcbGDw9h9}yDC5^7Ddsp32 3QW>59b+&lS zQ$2WO`9Z-9w-29nJ|xyl$4fp6KQiI%x3{ s1ufj*kIZ0~5gq1(epWFS%{(DD? zfSBl4-`n$-v1FZ&f5fzS-eRY7?2M6SSMTf((Be?J&G(|5@x~N~g>Mb7FdSLrzFTd_ z1|1I*QH5KY0Ub|{rW#wN{hF=TzS`}NEBk>Y;mn56dBwt+4eOrg6szw!yFd5SceDT7 zPTs%$N1>kKMvFkj##i^NPM+Uc{%yw!-FNJ-e|+4Z#<$Xr*A&b4eR7yiHLWbN7G%m4hjT*IXh-IO<9X2w +E=xq!cav;I*9J zT@~m3EH9_L(yG^V`|H{?J@WX!OW{BDRT%b&?$1*U==$gV?f>WV_WtYleB!#huXeY@ z#`Uv*?3Ur?zRR>iDdG0E{ds~Rf*W#g$8Tp?#li5C`9PS ? z+kcjAtNeNWGe^uP-G<7y4vC-Rcf@hsW<6>zZm&CeuQ02QYG8nX)lE&GFWLdj+t+^0 zEoaYqRR1#SPaf~H&I|nf{4Za;$k4vHe^PyT%fBCw-!Hhg`E{jztSrOV>YA;JO!xlV z-HJT-pWn`W!S+2<%cgyXH4HhQ@H1EoFoj%a@99i+I@J7Y`HVgFFFvMAwY -ZGn#H@uAtc(}U zx4a#1^k{!x#)ft==35zmA@? ;{rmCXF7CheFN`I_a6#|2>`itH|9r~%@%#7b zR~9yPe=NEhtp9(zZZgl^^?)ANzcm~;To29{Wdx<2R)Gpbj>g@K_x$KDWjoN&QkBN< za9-pO@25ldMNA5}IaWM5|C2#M-nM%-qrxMWgI9dmeE$Cb`u9!7V<*Q2^1M2eubiJR zsx;~SW&OpGU&>`W_g`kz=wy)I8l8QoyYW))w~e_^{9Pt~3FXjucYnV>znskpmxkV3 zYkS`xb$Ds^JHr28SjiL_25qLY&e)0jMHv|w-dqu!Ai&wb`ue-Chu{3J6Jg9`cbFeh z<*1|a@cZ3Q^Jo2;S;Cc|@A^0B!x`n%)7ltkmL3Qc@cI1lz#OIe%;<(Ei|fz7Qx&}6 z`tRk&>odQkb2T{Z`t#r*^T%m>x4*BQcjtatLBWL$f4!gBbKm3Cn7C8DMxW!$zJHcA zYa45A85kP4_1WgtZd6*ds;bD`=WBO&eU_rav>zw?8QvZDh&N$XaAY{5>M)0!p-`z| zt+0aSM{_r(+iM$^{$)rETHv$d&h+a}Z-)#HV`$7y1dXu#c6c>4lF#FUBo!idvtgK#uxlnq69^0l; z2A8LGR-N{*N_SrSXKue(Iw70kjF5_Ksf;=6xrqJIQD=f*y<~q`zHml!{nM%8n{4*T z3Ov#MH_7_KG^H8S|I{ij*q@_Zod0q9oyKh ^+<2AemJSF4xbmW%q+`=ONa zvp_wkovOk6=kedZGB7ZhX>-hoeOkYeyJ2R8h3=V?PQ`}P|8_d1$h$bMVV)4Bye0B` zY-r8dL-qpyx|j|K?Gt6nJ#t-hzgW+=>#dPLfBpXcUi|2hWpVsV_!$nUin8td6tDch zXsPVvmhOv;FYZ?beri~&+of+eKUsX=C+5mBF6qMQi{799QTYWl3D4lr&b;B=3($Gx z3=Q523`{KTkG<;mgIWU@6gUJK|HtptpFY#2MgMj+8_2Ewawq=3di3$}@grw`6frU| zG_XlEgYHNv2wBGgnxig%cSkX8+VOsQ Ox|B%eb&;RnU{6B*_kZY!uGR&)fXDPGPyJ7V{o{W1-J-$_d zU9yGQ6?`xq)Q@=GgI#iibBP~Q&AXk?H}rr)k73 ;BEe( z-Q-sDj_ZGne70lyyyai!Y<>q?ROG WxB2f^ z>GOh?fIMUFf;bPvVPIeYEqP-AEwcq#!T@nT19;w?8j@*A7fK%^ol5|+WQPmWgC9R; z^!4|Lt9jb^fB!5aBlEx (yiQjgLmuA&1xoPEd&+PkrZg%bS^VY`m z`8zhxPOsZsnf~Q_?fmCAzk@CyVPpUw5{5=Ku$DeKA;``MN*yc=3<)`5r~YlYo98}j z+17X$S%w*l878DgrbLGA_FNSlr|u~<--Th8FvBOdQ1@BOCZ^7`QZ3zecb&fyLvSiT z*yo_=;Q(D3fX1uN$;-3i0L2<;0XP#RI-%6|2+iMz%XZ6V&bn47Sjv#l$K)_Abz*Ad zTeX#bm2*`*YlIjx{1{G1hsb8ma+{X=YRZ+DWxMS<8GNSNqL{ ^=~VG-VQ8@2^hm&9&Bo~`rR(Y+>;H
%=0?alAMq-+2EUGzS5 zE&G9zNTvlF4Efi+{yzU|f7ZR! g!Z?Ck8V**jheHZV9G7M;7a|MxQYX^aeMr_~(3&G=%qH hqcgXvOlhPP$bmrU0FReE)1zUSPf{kLK`9GFo&t!8@o;Od{fztd-@ dD zdgXP=8eaw$1}On1rKCmsSq)bHVhBm*Y*?87V)Bxo%p43RCzjOv-+yM$z}TQVhqK@r zzXHRB4>Lh7ZeVb5K7YygKl7P+_n8)KaQr^|h;M%j$VZkOEWW$q85x)ugoCyP?|+eG zm)hSwFI!mw6b#M|ff^dSX82!xyhw`S%sk%)9$RPqtbeKL-$Re_-Q(bBU^~aqll^(R z)n`ejE~)Ck0F7PS{y+H4zW>@EMkyJFO*-8=r?bpGOHaKv*(e$IbLOdO%qA5LmV6AA z&8w7sFQ3@tGk22J=RJq(E|v4MB)Bm$95ak&aM*l<1wEA&pUP*vP|;m=P?f=$Az;zv zmoBTX?s{7f%MC1`Ya$pJ#OB^-dLRal$0y~WBN-F=&V2Ig+#7dZn!$i|8Uw=to&)!c z4;IEWxWcl<+pTwMY$N7AES;qC(UWC?C8I)qK Q%HGsCh2atsUx%p1P@ z6ij=4@N^J6gOn)4tSxeTP7F&IOj9`-k>_W!&WgdOO%+^tHKYdYVljCA^+D=NW` y++3Z5E8Z0{CbTgs{GVS5FEBE1rR|KAn;p0Q`F^hk z%?-pw3p8awDYq!(QYtNed)D4a`PqKUAA?NHa6R(v+qW_omy+GF?kSCP?Cb56l&)RB zo?KkK*_7Y@^F(F$J%tRx37pXMkdXKE@_&Ya6ji0DwPD%S#l^vw1vnTYHc2*2I~(4e zSzBw{CvShRNQL2r`3;F}vXfft`xzCY%(v_H ZZEZ{|V2}&E38BzNUToyF2@&;%6-@{PE#o#`fD=`LcvxZ;2{mV2F=CDP1%3^!qQ5 zPBL5f?miPOzel#;zGTa#9alH|hwOWI;M%pY`sDQ{|1K (-}j*9n(qabURdxG{bHt=c~?PuFYKJlZHeuVY8{ z^N&-X- rRulXo`)c5b3jUAig z- AhnZkM=W=KURo%6u{w z0akkQ!6s!v#thARbzh$Oov^G}^yO#hamE8qEDf8M+51E$zYjM{1Ihc^=D+yc|J|C8 zK}?O|jr+X|r)T|taKrKPJjNA5VhjlnnGgKF`?~Pw+ =AT!0`(5YkR1aIf_Sn_6tAERxzm#n7d>hTsP (EyH^4Y&ZDQNxt%9WRP zytn^!cw+kJ=HCBh$JVc3zx%H&L&!|V9ZNIi_Zs^h%P(_2@NVYcup_V3``@;;EHq|N zK2~ZqH(Kh;H|_tOKQ5Y=$Nj%G{o=2evCX`DzvvegzdocJ|9@X`&iNUhcdp%d+Q>NL zHABJ6FF!k83#!}Sv}V4LpI-ZaZ$xcrdT#v &x%o)m;3Y z^}ICxuTs?cJG >QKDGC}_v~LQo7Ep(IVimJ?A})v3^UY?_X|BxiMjd1rcd?z`^uOrcUGSh zVL0H#+7KDb`N4m>zK;z{&!bNV7<6(OPDt0xth{4$-JUt%+Lh18_4s)X80}29_s{zE zZ0A4C|B09X|2<`9{H?e$fkDiSLFe%^%jxWF2{+g9nEkK3YqPy$wj^VM7NbJ`pT#DH zpYN kbI9trHVTm!r t_QTIC8D{uvo1KSrU_dQk(A`PFf8`&RwH{x5?N2U9$kWx&Wt~$(69Bga3!4A{ literal 31627 zcmeAS@N?(olHy`uVBq!ia0y~yU}9ikU}WH6V_;x7I^kS81A~-xRY*ihP-3}4K~a8M zW=^U?No7H*LTW{38UsVct+lh$x5b!GTlzm)#Fk|Tv$4#LtyOHMfBu;%xlEiAH1%p^ zjd#!S9efsP(hp9}{r_wK^}q7}rp(!VIxPC-(u#ji=2gr5x%B7x`RB$z{`~v**#A%6 z@6+Gk9bZ53{E_ruG8)f6OS0X+JzxCFpTBkge(hcT`uB`)doRlS|GQ`K@}$(^?|Z)O z4eXl#{_ywv>+07_|6KmE=D+pl>f3)Uzx>``tSWJPM|_vwJdsJy-!EFO;x?g5s;2JW zIV(-oI&(XA_qXqpzo+-qamW2O-m?G5x&HT(FRuq!#P3s|azE+IU%MOkkH2$$@m#Rg ze)G4}jR_BrFR1IkyLb29YP-$SI|Wug+Bf;r{pdaSEeeHBebLkY6Y|fvZvFe^pD)jN zq?9~6$FFW0x2?;fT4z4%o`S=b^R;!_W<2hkdR`*j=l$+!S#JvWE=l>@BCXwdQ_pnM z#uHJGUjIned1$+R|8rfnoqze}NHUvq$9$YF|Ghl^-~T^ W`{mOdi}N*Q|1L`{ zeD|K0L-4#Ao3N1Nht?!M)gMyHyp0xSpNu6cm%LGz 4HiNm@E3swHsovRSLI24&}N zy?!z1^x3G)ty{0%ez8$q;Y`)bt6#5G%Qv_4<=O72DmW%#e9q+amdLcZx!)|so^JlM zDKsoL_p52yoy^PscE5R5cDuG;m~Uyxr;WjWwr{@}>uoK&eD-?Y&ac~UzyC3DYkpY$ z*{C17#sBAQ{cv`c(X{)OU(c`kSh}|UjuMBTkEL?5;pM&iw3tOoLeAB2Te_$ES$>W! zNS(NbHMpoO;Mj=-JH=bP_C?>*pZzn;KlkasM*he6)N`7p|D|UZd)+lJu0MPGeoAit zagCR%9 DGcG{&_dd@|z*7djYmACp$c_}RX&}NIy#`nRm<{o+f&iZYfeUjbc z&)wzQ$}Z`fM8w&wy?5_@ 7u`d>UqC+UVm{}OxW&1#w|0qB!|`IOjpfc#+vTj&BtCG {}g=`EeXdOtU^}{`=U~^bb3(*#_FBiwkYno8EeOf<)K; zE3q7#zh0f|_gL^}$i{YqNtW~7oDH6BxUQ;@maD7xy;^P4##1U^OBW^Y3FMN@h+ns4 z8=L8sCCXD|3-XI>pT7LfnW;B*4bzFYmeW6V7PmS(8k{`4`Tfb5w}0lQuCIC> +Ai)uN61`D__2|{_~#y-%P&yKlk;@3Dii@zL9gLV9AOECjE~ZA&bxC&e^