From c7a653f7e7e62ac946c78750ae2ac649427505f7 Mon Sep 17 00:00:00 2001 From: basaigh <53559772+basaigh@users.noreply.github.com> Date: Wed, 30 Aug 2023 20:49:16 +0100 Subject: [PATCH] 23w33a + 23w35a + implement PlayerSpawnInfo object --- .../mc/protocol/codec/MinecraftCodec.java | 4 +- .../protocol/codec/MinecraftCodecHelper.java | 27 +++++++++++++ .../data/game/advancement/Advancement.java | 13 +++--- .../game/entity/player/PlayerSpawnInfo.java | 21 ++++++++++ .../data/game/level/sound/BuiltinSound.java | 11 +++++ .../clientbound/ClientboundLoginPacket.java | 38 ++---------------- .../clientbound/ClientboundRespawnPacket.java | 31 ++------------ .../ClientboundUpdateAdvancementsPacket.java | 15 +------ src/main/resources/networkCodec.nbt | Bin 4600 -> 4609 bytes 9 files changed, 77 insertions(+), 83 deletions(-) create mode 100644 src/main/java/com/github/steveice10/mc/protocol/data/game/entity/player/PlayerSpawnInfo.java diff --git a/src/main/java/com/github/steveice10/mc/protocol/codec/MinecraftCodec.java b/src/main/java/com/github/steveice10/mc/protocol/codec/MinecraftCodec.java index 4598b3daf..ca9156bb3 100644 --- a/src/main/java/com/github/steveice10/mc/protocol/codec/MinecraftCodec.java +++ b/src/main/java/com/github/steveice10/mc/protocol/codec/MinecraftCodec.java @@ -208,9 +208,9 @@ public class MinecraftCodec { } public static final PacketCodec CODEC = PacketCodec.builder() - .protocolVersion((1 << 30) | 145) + .protocolVersion((1 << 30) | 147) .helper(() -> new MinecraftCodecHelper(LEVEL_EVENTS, SOUND_NAMES)) - .minecraftVersion("23w32a") + .minecraftVersion("23w35a") .state(ProtocolState.HANDSHAKE, PacketStateCodec.builder() .registerServerboundPacket(0x00, ClientIntentionPacket.class, ClientIntentionPacket::new) ) diff --git a/src/main/java/com/github/steveice10/mc/protocol/codec/MinecraftCodecHelper.java b/src/main/java/com/github/steveice10/mc/protocol/codec/MinecraftCodecHelper.java index f8ae5a029..48ac5102b 100644 --- a/src/main/java/com/github/steveice10/mc/protocol/codec/MinecraftCodecHelper.java +++ b/src/main/java/com/github/steveice10/mc/protocol/codec/MinecraftCodecHelper.java @@ -25,6 +25,8 @@ import com.github.steveice10.mc.protocol.data.game.entity.metadata.VillagerData; import com.github.steveice10.mc.protocol.data.game.entity.object.Direction; import com.github.steveice10.mc.protocol.data.game.entity.player.BlockBreakStage; +import com.github.steveice10.mc.protocol.data.game.entity.player.GameMode; +import com.github.steveice10.mc.protocol.data.game.entity.player.PlayerSpawnInfo; import com.github.steveice10.mc.protocol.data.game.entity.type.PaintingType; import com.github.steveice10.mc.protocol.data.game.level.LightUpdateData; import com.github.steveice10.mc.protocol.data.game.level.block.BlockEntityType; @@ -442,6 +444,31 @@ public void writeGlobalPos(ByteBuf buf, GlobalPos pos) { this.writePosition(buf, pos.getPosition()); } + public PlayerSpawnInfo readPlayerSpawnInfo(ByteBuf buf) { + String dimension = this.readString(buf); + String worldName = this.readString(buf); + long hashedSeed = buf.readLong(); + GameMode gameMode = GameMode.byId(buf.readByte()); + GameMode previousGamemode = GameMode.byNullableId(buf.readByte()); + boolean debug = buf.readBoolean(); + boolean flat = buf.readBoolean(); + GlobalPos lastDeathPos = this.readNullable(buf, this::readGlobalPos); + int portalCooldown = this.readVarInt(buf); + return new PlayerSpawnInfo(dimension, worldName, hashedSeed, gameMode, previousGamemode, debug, flat, lastDeathPos, portalCooldown); + } + + public void writePlayerSpawnInfo(ByteBuf buf, PlayerSpawnInfo info) { + this.writeString(buf, info.getDimension()); + this.writeString(buf, info.getWorldName()); + buf.writeLong(info.getHashedSeed()); + buf.writeByte(info.getGameMode().ordinal()); + buf.writeByte(GameMode.toNullableId(info.getPreviousGamemode())); + buf.writeBoolean(info.isDebug()); + buf.writeBoolean(info.isFlat()); + this.writeNullable(buf, info.getLastDeathPos(), this::writeGlobalPos); + this.writeVarInt(buf, info.getPortalCooldown()); + } + public ParticleType readParticleType(ByteBuf buf) { return ParticleType.from(this.readVarInt(buf)); } diff --git a/src/main/java/com/github/steveice10/mc/protocol/data/game/advancement/Advancement.java b/src/main/java/com/github/steveice10/mc/protocol/data/game/advancement/Advancement.java index 5593434bb..0967f9fe7 100644 --- a/src/main/java/com/github/steveice10/mc/protocol/data/game/advancement/Advancement.java +++ b/src/main/java/com/github/steveice10/mc/protocol/data/game/advancement/Advancement.java @@ -12,22 +12,21 @@ @AllArgsConstructor public class Advancement { private final @NonNull String id; - private final @NonNull List criteria; private final @NonNull List> requirements; private final String parentId; private final DisplayData displayData; private final boolean sendsTelemetryEvent; - public Advancement(@NonNull String id, @NonNull List criteria, @NonNull List> requirements, boolean sendsTelemetryEvent) { - this(id, criteria, requirements, null, null, sendsTelemetryEvent); + public Advancement(@NonNull String id, @NonNull List> requirements, boolean sendsTelemetryEvent) { + this(id, requirements, null, null, sendsTelemetryEvent); } - public Advancement(@NonNull String id, @NonNull List criteria, @NonNull List> requirements, String parentId, boolean sendsTelemetryEvent) { - this(id, criteria, requirements, parentId, null, sendsTelemetryEvent); + public Advancement(@NonNull String id, @NonNull List> requirements, String parentId, boolean sendsTelemetryEvent) { + this(id, requirements, parentId, null, sendsTelemetryEvent); } - public Advancement(@NonNull String id, @NonNull List criteria, @NonNull List> requirements, DisplayData displayData, boolean sendsTelemetryEvent) { - this(id, criteria, requirements, null, displayData, sendsTelemetryEvent); + public Advancement(@NonNull String id, @NonNull List> requirements, DisplayData displayData, boolean sendsTelemetryEvent) { + this(id, requirements, null, displayData, sendsTelemetryEvent); } @Data diff --git a/src/main/java/com/github/steveice10/mc/protocol/data/game/entity/player/PlayerSpawnInfo.java b/src/main/java/com/github/steveice10/mc/protocol/data/game/entity/player/PlayerSpawnInfo.java new file mode 100644 index 000000000..3d301da1a --- /dev/null +++ b/src/main/java/com/github/steveice10/mc/protocol/data/game/entity/player/PlayerSpawnInfo.java @@ -0,0 +1,21 @@ +package com.github.steveice10.mc.protocol.data.game.entity.player; + +import com.github.steveice10.mc.protocol.data.game.entity.metadata.GlobalPos; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NonNull; +import org.jetbrains.annotations.Nullable; + +@Data +@AllArgsConstructor +public class PlayerSpawnInfo { + private final @NonNull String dimension; + private final @NonNull String worldName; + private final long hashedSeed; + private final @NonNull GameMode gameMode; + private final @Nullable GameMode previousGamemode; + private final boolean debug; + private final boolean flat; + private final @Nullable GlobalPos lastDeathPos; + private final int portalCooldown; +} diff --git a/src/main/java/com/github/steveice10/mc/protocol/data/game/level/sound/BuiltinSound.java b/src/main/java/com/github/steveice10/mc/protocol/data/game/level/sound/BuiltinSound.java index c24952164..9c8846e9c 100644 --- a/src/main/java/com/github/steveice10/mc/protocol/data/game/level/sound/BuiltinSound.java +++ b/src/main/java/com/github/steveice10/mc/protocol/data/game/level/sound/BuiltinSound.java @@ -1265,6 +1265,12 @@ public enum BuiltinSound implements Sound { ENTITY_SPIDER_STEP("entity.spider.step"), ENTITY_SPLASH_POTION_BREAK("entity.splash_potion.break"), ENTITY_SPLASH_POTION_THROW("entity.splash_potion.throw"), + BLOCK_SPONGE_BREAK("block.sponge.break"), + BLOCK_SPONGE_FALL("block.sponge.fall"), + BLOCK_SPONGE_HIT("block.sponge.hit"), + BLOCK_SPONGE_PLACE("block.sponge.place"), + BLOCK_SPONGE_STEP("block.sponge.step"), + BLOCK_SPONGE_ABSORB("block.sponge.absorb"), ITEM_SPYGLASS_USE("item.spyglass.use"), ITEM_SPYGLASS_STOP_USING("item.spyglass.stop_using"), ENTITY_SQUID_AMBIENT("entity.squid.ambient"), @@ -1409,6 +1415,11 @@ public enum BuiltinSound implements Sound { BLOCK_WET_GRASS_HIT("block.wet_grass.hit"), BLOCK_WET_GRASS_PLACE("block.wet_grass.place"), BLOCK_WET_GRASS_STEP("block.wet_grass.step"), + BLOCK_WET_SPONGE_BREAK("block.wet_sponge.break"), + BLOCK_WET_SPONGE_FALL("block.wet_sponge.fall"), + BLOCK_WET_SPONGE_HIT("block.wet_sponge.hit"), + BLOCK_WET_SPONGE_PLACE("block.wet_sponge.place"), + BLOCK_WET_SPONGE_STEP("block.wet_sponge.step"), ENTITY_WITCH_AMBIENT("entity.witch.ambient"), ENTITY_WITCH_CELEBRATE("entity.witch.celebrate"), ENTITY_WITCH_DEATH("entity.witch.death"), diff --git a/src/main/java/com/github/steveice10/mc/protocol/packet/ingame/clientbound/ClientboundLoginPacket.java b/src/main/java/com/github/steveice10/mc/protocol/packet/ingame/clientbound/ClientboundLoginPacket.java index cc019e5b6..bc9a41ba1 100644 --- a/src/main/java/com/github/steveice10/mc/protocol/packet/ingame/clientbound/ClientboundLoginPacket.java +++ b/src/main/java/com/github/steveice10/mc/protocol/packet/ingame/clientbound/ClientboundLoginPacket.java @@ -4,6 +4,7 @@ import com.github.steveice10.mc.protocol.codec.MinecraftPacket; import com.github.steveice10.mc.protocol.data.game.entity.metadata.GlobalPos; import com.github.steveice10.mc.protocol.data.game.entity.player.GameMode; +import com.github.steveice10.mc.protocol.data.game.entity.player.PlayerSpawnInfo; import com.github.steveice10.opennbt.tag.builtin.CompoundTag; import io.netty.buffer.ByteBuf; import lombok.AllArgsConstructor; @@ -26,15 +27,7 @@ public class ClientboundLoginPacket implements MinecraftPacket { private final int simulationDistance; private final boolean reducedDebugInfo; private final boolean enableRespawnScreen; - private final @NonNull String dimension; - private final @NonNull String worldName; - private final long hashedSeed; - private final @NonNull GameMode gameMode; - private final @Nullable GameMode previousGamemode; - private final boolean debug; - private final boolean flat; - private final @Nullable GlobalPos lastDeathPos; - private final int portalCooldown; + private final PlayerSpawnInfo commonPlayerSpawnInfo; public ClientboundLoginPacket(ByteBuf in, MinecraftCodecHelper helper) throws IOException { this.entityId = in.readInt(); @@ -49,19 +42,7 @@ public ClientboundLoginPacket(ByteBuf in, MinecraftCodecHelper helper) throws IO this.simulationDistance = helper.readVarInt(in); this.reducedDebugInfo = in.readBoolean(); this.enableRespawnScreen = in.readBoolean(); - this.dimension = helper.readString(in); - this.worldName = helper.readString(in); - this.hashedSeed = in.readLong(); - this.gameMode = GameMode.byId(in.readByte()); - this.previousGamemode = GameMode.byNullableId(in.readByte()); - this.debug = in.readBoolean(); - this.flat = in.readBoolean(); - if (in.readBoolean()) { - this.lastDeathPos = helper.readGlobalPos(in); - } else { - this.lastDeathPos = null; - } - this.portalCooldown = helper.readVarInt(in); + this.commonPlayerSpawnInfo = helper.readPlayerSpawnInfo(in); } @Override @@ -77,17 +58,6 @@ public void serialize(ByteBuf out, MinecraftCodecHelper helper) throws IOExcepti helper.writeVarInt(out, this.simulationDistance); out.writeBoolean(this.reducedDebugInfo); out.writeBoolean(this.enableRespawnScreen); - helper.writeString(out, this.dimension); - helper.writeString(out, this.worldName); - out.writeLong(this.hashedSeed); - out.writeByte(this.gameMode.ordinal()); - out.writeByte(GameMode.toNullableId(this.previousGamemode)); - out.writeBoolean(this.debug); - out.writeBoolean(this.flat); - out.writeBoolean(this.lastDeathPos != null); - if (this.lastDeathPos != null) { - helper.writeGlobalPos(out, this.lastDeathPos); - } - helper.writeVarInt(out, this.portalCooldown); + helper.writePlayerSpawnInfo(out, this.commonPlayerSpawnInfo); } } diff --git a/src/main/java/com/github/steveice10/mc/protocol/packet/ingame/clientbound/ClientboundRespawnPacket.java b/src/main/java/com/github/steveice10/mc/protocol/packet/ingame/clientbound/ClientboundRespawnPacket.java index 730ca51b6..7278b9db3 100644 --- a/src/main/java/com/github/steveice10/mc/protocol/packet/ingame/clientbound/ClientboundRespawnPacket.java +++ b/src/main/java/com/github/steveice10/mc/protocol/packet/ingame/clientbound/ClientboundRespawnPacket.java @@ -4,6 +4,7 @@ import com.github.steveice10.mc.protocol.codec.MinecraftPacket; import com.github.steveice10.mc.protocol.data.game.entity.metadata.GlobalPos; import com.github.steveice10.mc.protocol.data.game.entity.player.GameMode; +import com.github.steveice10.mc.protocol.data.game.entity.player.PlayerSpawnInfo; import io.netty.buffer.ByteBuf; import lombok.AllArgsConstructor; import lombok.Data; @@ -18,29 +19,13 @@ public class ClientboundRespawnPacket implements MinecraftPacket { private static final byte KEEP_ATTRIBUTES = 1; private static final byte KEEP_ENTITY_DATA = 2; - private final @NonNull String dimension; - private final @NonNull String worldName; - private final long hashedSeed; - private final @NonNull GameMode gamemode; - private final @Nullable GameMode previousGamemode; - private final boolean debug; - private final boolean flat; - private final @Nullable GlobalPos lastDeathPos; - private final int portalCooldown; + private final PlayerSpawnInfo commonPlayerSpawnInfo; // The following two are the dataToKeep byte private final boolean keepMetadata; private final boolean keepAttributes; public ClientboundRespawnPacket(ByteBuf in, MinecraftCodecHelper helper) { - this.dimension = helper.readString(in); - this.worldName = helper.readString(in); - this.hashedSeed = in.readLong(); - this.gamemode = GameMode.byId(in.readUnsignedByte()); // Intentionally unsigned as of 1.19.3 - this.previousGamemode = GameMode.byNullableId(in.readByte()); - this.debug = in.readBoolean(); - this.flat = in.readBoolean(); - this.lastDeathPos = helper.readNullable(in, helper::readGlobalPos); - this.portalCooldown = helper.readVarInt(in); + this.commonPlayerSpawnInfo = helper.readPlayerSpawnInfo(in); byte dataToKeep = in.readByte(); this.keepAttributes = (dataToKeep & KEEP_ATTRIBUTES) != 0; this.keepMetadata = (dataToKeep & KEEP_ENTITY_DATA) != 0; @@ -48,15 +33,7 @@ public ClientboundRespawnPacket(ByteBuf in, MinecraftCodecHelper helper) { @Override public void serialize(ByteBuf out, MinecraftCodecHelper helper) { - helper.writeString(out, this.dimension); - helper.writeString(out, this.worldName); - out.writeLong(this.hashedSeed); - out.writeByte(this.gamemode.ordinal()); - out.writeByte(GameMode.toNullableId(this.previousGamemode)); - out.writeBoolean(this.debug); - out.writeBoolean(this.flat); - helper.writeNullable(out, this.lastDeathPos, helper::writeGlobalPos); - helper.writeVarInt(out, this.portalCooldown); + helper.writePlayerSpawnInfo(out, this.commonPlayerSpawnInfo); byte dataToKeep = 0; if (this.keepMetadata) { dataToKeep += KEEP_ENTITY_DATA; diff --git a/src/main/java/com/github/steveice10/mc/protocol/packet/ingame/clientbound/ClientboundUpdateAdvancementsPacket.java b/src/main/java/com/github/steveice10/mc/protocol/packet/ingame/clientbound/ClientboundUpdateAdvancementsPacket.java index bc4883eba..4a4383b22 100644 --- a/src/main/java/com/github/steveice10/mc/protocol/packet/ingame/clientbound/ClientboundUpdateAdvancementsPacket.java +++ b/src/main/java/com/github/steveice10/mc/protocol/packet/ingame/clientbound/ClientboundUpdateAdvancementsPacket.java @@ -52,7 +52,7 @@ public ClientboundUpdateAdvancementsPacket(ByteBuf in, MinecraftCodecHelper help this.advancements = new Advancement[helper.readVarInt(in)]; for (int i = 0; i < this.advancements.length; i++) { String id = helper.readString(in); - String parentId = in.readBoolean() ? helper.readString(in) : null; + String parentId = helper.readNullable(in, helper::readString); DisplayData displayData = null; if (in.readBoolean()) { Component title = helper.readComponent(in); @@ -72,12 +72,6 @@ public ClientboundUpdateAdvancementsPacket(ByteBuf in, MinecraftCodecHelper help displayData = new DisplayData(title, description, icon, frameType, showToast, hidden, posX, posY, backgroundTexture); } - List criteria = new ArrayList<>(); - int criteriaCount = helper.readVarInt(in); - for (int j = 0; j < criteriaCount; j++) { - criteria.add(helper.readString(in)); - } - List> requirements = new ArrayList<>(); int requirementCount = helper.readVarInt(in); for (int j = 0; j < requirementCount; j++) { @@ -92,7 +86,7 @@ public ClientboundUpdateAdvancementsPacket(ByteBuf in, MinecraftCodecHelper help boolean sendTelemetryEvent = in.readBoolean(); - this.advancements[i] = new Advancement(id, criteria, requirements, parentId, displayData, sendTelemetryEvent); + this.advancements[i] = new Advancement(id, requirements, parentId, displayData, sendTelemetryEvent); } this.removedAdvancements = new String[helper.readVarInt(in)]; @@ -165,11 +159,6 @@ public void serialize(ByteBuf out, MinecraftCodecHelper helper) throws IOExcepti out.writeBoolean(false); } - helper.writeVarInt(out, advancement.getCriteria().size()); - for (String criterion : advancement.getCriteria()) { - helper.writeString(out, criterion); - } - helper.writeVarInt(out, advancement.getRequirements().size()); for (List requirement : advancement.getRequirements()) { helper.writeVarInt(out, requirement.size()); diff --git a/src/main/resources/networkCodec.nbt b/src/main/resources/networkCodec.nbt index 317752bb7acbb276b56b4bb23678a43e6b5c1dff..bdd185a1f0849b7ce5527003c3ff0a8fb3d0309b 100644 GIT binary patch delta 4161 zcmV-H5WesDBY`B4djYGFd?kN-yozc=Yz;^QA+#mN+PFv1W;C|NFn6oybJP?A1eXk&nDRL7hX*AVi=rL3TuNm|$vat4ZQL_^GhO#(eC8G3)bq)(Yujk76g zNSc}!F%bbJ)}s+*9P0473>{w7X3VO>nG_WSNlgP?zHAh_Eb^vmJ{07XqEV1E(@>Dl z0427f5e}xDIDr~V8ESkXK514(o=Q=~r>d!v5H#DR9NG*tspWGiF{5ag5+u`HN<7L& zg9~w;aiGI;J~aGEMWcV=Q%ys|e>z2(F78LJwUSdAZ&KmPcvMrB@ty+899PCri`cC& zV%0OW*-gxvRh_5P)bYt``Xprq6jIU*x7i>JU#t0&p*N@KWatr1ONQRVDT?%|6XMdy zsfe6YxFV8hsv`1Xc0O^b8S1f?FQ3RMMduSqGcBLUXW1cmNbY|JIvmRvg2jxYL$Dy3 z7J|j2Y!pV=F#`?O^PwQ86pezUnTCRV1}Jet9WicG+l->`MusM@0P|*5=R&GF6T+HK zki=8ap;m~_W=?d(l)}*wG*i(L&lDxZK4Uw!UFiwZ4#ifmok@GH?q?c-F`kG9i(lRD zIAu%I5Gp#vq~d=UbUHc55J}H5#V}t5k90kFSVLRVibju_#4;o-_isLwJFjZmpHI_1kQ7v3XzJi-u~yTdOiqa@GWirzWN&XTRgo)K-g#y3 zT0TW4EZ~sSVUZR~IYC^KlhB&{3Bz|%rw_TWM+4G&=fm%$YJKPKtt+qI0m>CXYfnZ{ zW$G{+*hqh6t1Ks>HTiR@%HAMIW%&S5`K>IEy?a~!%crs@BUnXRxKBB_@k)t1-UP$K z4+a+1wWxWIAmrNZcB&dzuUxx({dHhB1E}FKfHS`>qN^D05@6qziQj5C6K#e6g^}C= z*g93OlPL6W7)_1CXld*$_fIX>Xw*CdK} zwz}9gWX%(lKF~9@>{$V#lN<yIUQC`b5itC^39CDdZQ9*!!8 zN*>)dBS}0W1t>QQ$w;fGBdvP86X+xyO#DwcDp(GsDR*%)oA34r=eR>e$-zac`kK;n(UTBj!X~5GCVP&|05%ENUAZw+X7C6&ruM z1F@5-)X+NaHDyI$ShUmiq^zRzVz_B*4p=tb&3{jo>BA_7j6nEu0x*yECRo3vaGDk{dx zxelf#uT;^7#X7WwEu%|(O)3wU(N=$pF~_8~Jn!M+A-VbA2>Hg@(UqL2M}{OkZc%oe z1Dm#)(`!sXsCp-ba#>mfPKU%d+j5`G$(fZf{^fp>}NH~!E7ckE|%#{?F6%oW9#US8mP%6BrD0p{Zc!hsBIe|qg zut)(mso)Z7wCQ~@))isS2Wz`O6>Bs{Sj!Q4m$Z`dPU@!cccnmCr^8*zfLrb?bHTl- z!+j2h+m|Q>@k(CAK{Wx;-~EaTIs!mP&;oz^f3aVfAiGD@WtfMDPg59nWjFV>vKRUW8 zOps$fuUj4~@XXT`9tEBAD$Bj@jS+kc6s+dagzrq8v7xjjESKXWf{Sc9fR0be{l3Ly zaSpbvli&v!ARie+>`-jG9Q0K=LbAj5kXqo$V}a34^2n6JOMGCPN0S%`IWqasD{ia~`fo2gU1-2bR9)v!#35Q&7lYSR_}Qf-$Kg4aW4w*)V+*wipOT?$6Eo{o*OSM9N;fn66zCB#lC zhNucgkpNFY0tjLT?sOa$NOI-?eikm3M0zd0}w)q9ZZjB=gL_wKsaHs zc&4Nw+1t$8hIZQiR4IXmFU5lEy|N7W4(aq#oRmr^doXGST|YhcY4a^ z;+b;1Fk%G1zu{tM7|L*|ob>K9fgAf><*?@2a`v4b5768Ah!EFk62}=E%>fS&Yn}r` z)pDQh7n|5OJOOS={U4OIrRY|C5`;Up9p0 z88Zz}-YROiRFt|CVYd6r!Xw*lPTaTs`yCW&rZ~pr_G?#OgjdlC|Ei0B6YR9QBI}1O zCa8jr%R8RF*pAUYb-gwYR6}d>g%0A#+cYBC)KJ|NaiZ;Q9}xmeo2KB&m~n4lcP!|Y z>LReaoQ0jnJ`2Fn-#z+_LQ~P9xykqT6li2qbP6;aTdtJT#n7!$5zssvhsM9p+>P;` zvassW#chIYU^tE9uEkh?zkxQfX;Nt+?#~OwdSTl9aN@Estwgic#deF_{NsQAvmgKB z+wX|rQ}1I(Jh6x{zS!+Gag$oq9pCt$pZ!W0j(Od^9O%Lwb!9U*mIX%+ck3Gc;@oYj z)g;w2t{>FuFVVS zVKd;HwJsn0?O}mr=fm%)@lyN>LelDbdzFsEqD@<^SV*2vheYR|1FiuLm6Qi_5&^T(|Uo&!v$k(^c*yf~G>%yq$+y;pzYb-{Mh^1RRF zwlas??NzJAh1Th|E4w(*I>Vg(mf8!@}W~-$8iU_L=h$8H=Zz}L6)-$Cw*e9}ISU2Xe8I8GgYML?c{=@&yy)nVE z)U%dmr1jD~ZvIwhmXWqpBXQz{wZO)K?SlipQxASWlVChfb*AQdhxWa<&-E9oHj72& zg$z{U0xU9rnNmCx+ccV3+Bk$}YidM6xpo{MJ^X0ytb`sTqHOC{>e5bEyHh&8uv7fd zOWLVN^{clh7G{daMB*@0UZKV=DNhs|6Bn11EjIFWRZkpF7K>fRC1s5L;!r_t z=+`iL^1v#;1sFgwfcD3yrY3_w_{&4GKSs%9kb8fBoU~$};ONDj?P47};~q)pp5@+u z^yi1fy??Zq(GZaY#-YQgd+YR(c5m?NUb_I@Db{h%r#o(ro6m23bVxk*hx%SG^-hxt z%knwI-kSxA`pzA;z52l5Bi!o)uTV{I z8mM_wODSC@LQOrUj-A8&$qz0AD8B#Tcc-BE=7W24hGMLoNlOSlg3aiAel8qXLJ0Vl zv7|PB`(Ne^43yC?x1$-U>oC?c#Oko3Bh8C{Q!~QhNu9z^RZBfogO752=(n#KBh1|> zDLhkhQkeA2#dsIcNUu?xp^;vnKdoUdPoG=8UTP1#F7N^Nz-yJ(r5P)&&*HkuO6nIC z`&g#zcOJQ218RqVcCHSCk48KEc@Ukx_|R}M?Sx;?@m#UkyqJ!SBF035ER=r#uMY`- zO7gEeq-Jq=4e`D+XvJ`Peok@v=ApsqVMev3l)l2uG-}wmJT(~{jkXpgS!$>9pI;=) z#NW@vLu}jO!hT_@g^pa`+QdSJ_c!VA0C+$DNLxy2hUPu_-IcQShjOi-<)x{%LPw(W zNByfBHXDr%?RD0dOS^-ayEh(g#G?0qhbiw)`c~4D+!q#CRj`@3#rn}f!tQ}xRq5Qb z%Cm3(#UTOahp{qRJDE(Za;6gH_NR_|7ocDVr&i=;T;+AHA9;=mo ztfm~ta$!48VqZCP<-oc*W9*OQCG&eJ?9Ww}CzB)Yj|RtBb>$#5YT-xA3ohwr}C@^{)fq zUAnYA1w8x>bFRVDYh49At;)TBHa!j;iKE)|zclvx;!Gs|U5(O0LqW<-Yaho% zN*7tO)$aPNt#;?98R_=F{^xwHw7f5A3M2L9m%M7%zHc5(V?~U20gV+J#Tgna^!c-Y z6A}HtzfbNVPbI9L|BHyu)XtRJprI>X_D)i%_(s$=`H1x0mB!78fviN;eWHQZCHx`zP-$zB3irsR)wYa-WcohTRM8COs6MgQ`L+Jkj LDNp^cjF|ucd>}Kw delta 4164 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