From ec1ab8ece31743ea7ee79c5629b4823d85adcb3c Mon Sep 17 00:00:00 2001
From: lax1dude <cgiacun@gmail.com>
Date: Sat, 21 Sep 2024 20:17:42 -0700
Subject: [PATCH] Update #37 - Touch support without userscript, many other
 feats

---
 CODE_STANDARDS.md                             |  306 +++
 CREDITS                                       |   56 +-
 README.md                                     |   47 +-
 buildtools/BuildTools.jar                     |  Bin 198863 -> 201837 bytes
 buildtools/production-index-ext.html          |   16 +-
 buildtools/production-index.html              |   16 +-
 .../gui/CompileLatestClientGUI.java           |   22 +-
 .../v1_8/buildtools/gui/ES6Compat.java        |   43 +
 .../v1_8/buildtools/gui/TeaVMBinaries.java    |    2 +-
 .../headless/CompileLatestClientHeadless.java |   25 +-
 .../buildtools/task/diff/PullRequestTask.java |  112 +-
 .../buildtools/task/init/SetupWorkspace.java  |   70 +-
 .../buildtools/task/teavm/TeaVMBridge.java    |   20 +-
 client_version                                |    2 +-
 patches/minecraft/delete.txt                  |    3 +-
 .../client/LoadingScreenRenderer.edit.java    |   26 +-
 .../net/minecraft/client/Minecraft.edit.java  |  923 +++++--
 .../client/audio/SoundCategory.edit.java      |    6 +-
 .../client/audio/SoundHandler.edit.java       |   13 +-
 .../entity/AbstractClientPlayer.edit.java     |   48 +-
 .../client/entity/EntityPlayerSP.edit.java    |    9 +-
 .../minecraft/client/gui/ChatLine.edit.java   |   28 +
 .../client/gui/FontRenderer.edit.java         |   49 +-
 .../minecraft/client/gui/GuiButton.edit.java  |    8 +
 .../minecraft/client/gui/GuiChat.edit.java    |   88 +-
 .../client/gui/GuiCommandBlock.edit.java      |   19 +-
 .../client/gui/GuiControls.edit.java          |   12 +-
 .../client/gui/GuiCreateFlatWorld.edit.java   |    7 +-
 .../client/gui/GuiCreateWorld.edit.java       |   18 +-
 .../gui/GuiCustomizeWorldScreen.edit.java     |   27 +-
 .../client/gui/GuiDownloadTerrain.edit.java   |    7 +-
 .../client/gui/GuiEnchantment.edit.java       |    3 +-
 .../client/gui/GuiFlatPresets.edit.java       |   27 +-
 .../minecraft/client/gui/GuiIngame.edit.java  |  402 ++-
 .../client/gui/GuiIngameMenu.edit.java        |  142 +-
 .../client/gui/GuiKeyBindingList.edit.java    |   32 +-
 .../client/gui/GuiLanguage.edit.java          |   13 +-
 .../client/gui/GuiMainMenu.edit.java          |    5 +-
 .../client/gui/GuiMultiplayer.edit.java       |   44 +-
 .../minecraft/client/gui/GuiNewChat.edit.java |    4 +
 .../client/gui/GuiOptionSlider.edit.java      |   18 +
 .../minecraft/client/gui/GuiOptions.edit.java |   79 +-
 .../client/gui/GuiOptionsRowList.edit.java    |   78 +-
 .../client/gui/GuiOverlayDebug.edit.java      |  107 +-
 .../client/gui/GuiPageButtonList.edit.java    |   53 +-
 .../client/gui/GuiPlayerTabOverlay.edit.java  |   11 +-
 .../client/gui/GuiRenameWorld.edit.java       |   17 +-
 .../minecraft/client/gui/GuiRepair.edit.java  |   16 +-
 .../minecraft/client/gui/GuiScreen.edit.java  |  352 ++-
 .../client/gui/GuiScreenAddServer.edit.java   |   52 +-
 .../client/gui/GuiScreenBook.edit.java        |   38 +-
 .../gui/GuiScreenCustomizePresets.edit.java   |   26 +-
 .../gui/GuiScreenOptionsSounds.edit.java      |    7 +
 .../gui/GuiScreenResourcePacks.edit.java      |   11 +-
 .../client/gui/GuiScreenServerList.edit.java  |   17 +-
 .../client/gui/GuiSelectWorld.edit.java       |   38 +-
 .../minecraft/client/gui/GuiSlider.edit.java  |    7 +
 .../minecraft/client/gui/GuiSlot.edit.java    |   48 +-
 .../client/gui/GuiTextField.edit.java         |   24 +-
 .../gui/GuiUtilRenderComponents.edit.java     |    7 +
 .../client/gui/GuiVideoSettings.edit.java     |   71 +-
 .../client/gui/ScaledResolution.edit.java     |   20 +
 .../client/gui/ScreenChatOptions.edit.java    |   28 +-
 .../gui/achievement/GuiAchievement.edit.java  |    6 +-
 .../gui/achievement/GuiAchievements.edit.java |    9 +-
 .../client/gui/achievement/GuiStats.edit.java |   20 +-
 .../gui/inventory/GuiContainer.edit.java      |  100 +-
 .../inventory/GuiContainerCreative.edit.java  |   49 +-
 .../gui/inventory/GuiEditSign.edit.java       |   45 +-
 .../multiplayer/ChunkProviderClient.edit.java |   19 +-
 .../multiplayer/GuiConnecting.edit.java       |  215 +-
 .../multiplayer/PlayerControllerMP.edit.java  |    7 +-
 .../client/multiplayer/ServerData.edit.java   |   45 +-
 .../client/multiplayer/ServerList.edit.java   |   10 +-
 .../client/multiplayer/WorldClient.edit.java  |   24 +-
 .../network/NetHandlerPlayClient.edit.java    |  134 +-
 .../network/NetworkPlayerInfo.edit.java       |   54 +-
 .../client/particle/EffectRenderer.edit.java  |   31 +-
 .../client/renderer/EntityRenderer.edit.java  |  263 +-
 .../client/renderer/RenderGlobal.edit.java    |   70 +-
 .../client/renderer/entity/Render.edit.java   |    6 +-
 .../renderer/entity/RenderPlayer.edit.java    |    6 +-
 .../entity/RendererLivingEntity.edit.java     |    6 +-
 .../texture/AbstractTexture.edit.java         |    6 +-
 .../renderer/texture/TextureMap.edit.java     |   39 +-
 .../renderer/texture/TextureUtil.edit.java    |   32 +-
 .../tileentity/RenderItemFrame.edit.java      |    6 +-
 .../TileEntityBannerRenderer.edit.java        |   13 +-
 .../TileEntityChestRenderer.edit.java         |    9 +-
 .../TileEntitySignRenderer.edit.java          |   36 +-
 .../resources/DefaultResourcePack.edit.java   |   10 +-
 .../client/resources/Locale.edit.java         |    2 +-
 .../client/settings/GameSettings.edit.java    |  294 ++-
 .../net/minecraft/entity/Entity.edit.java     |   89 +-
 .../minecraft/entity/EntityLiving.edit.java   |   37 +-
 .../entity/EntityLivingBase.edit.java         |   30 +-
 .../entity/ai/EntityAITasks.edit.java         |   16 +-
 .../entity/ai/EntitySenses.edit.java          |   12 +
 .../entity/item/EntityItem.edit.java          |    2 +-
 .../entity/item/EntityItemFrame.edit.java     |    2 +-
 .../entity/item/EntityMinecart.edit.java      |   22 +-
 .../entity/passive/EntityHorse.edit.java      |   17 +-
 .../entity/passive/EntityOcelot.edit.java     |   17 +
 .../entity/passive/EntityTameable.edit.java   |   19 +-
 .../entity/passive/EntityVillager.edit.java   |   18 +-
 .../entity/player/EntityPlayer.edit.java      |   14 +-
 .../entity/player/EntityPlayerMP.edit.java    |   11 +-
 .../net/minecraft/item/Item.edit.java         |    8 +-
 .../net/minecraft/item/ItemBlock.edit.java    |    2 +-
 .../net/minecraft/item/ItemEgg.edit.java      |    7 +
 .../net/minecraft/item/ItemEnderEye.edit.java |    7 +
 .../minecraft/item/ItemEnderPearl.edit.java   |    7 +
 .../minecraft/item/ItemExpBottle.edit.java    |    7 +
 .../net/minecraft/item/ItemFirework.edit.java |    7 +
 .../net/minecraft/item/ItemSnowball.edit.java |    7 +
 .../net/minecraft/item/ItemStack.edit.java    |   58 +-
 .../network/NetHandlerPlayServer.edit.java    |  129 +-
 .../client/C00PacketLoginStart.edit.java      |   31 +-
 .../server/S02PacketLoginSuccess.edit.java    |   28 +-
 .../pathfinding/PathNavigate.edit.java        |   10 +-
 .../net/minecraft/profiler/Profiler.edit.java |   21 -
 .../scoreboard/ScoreObjective.edit.java       |   23 +-
 .../server/MinecraftServer.edit.java          |   89 +-
 .../ServerConfigurationManager.edit.java      |   55 +-
 .../network/NetHandlerLoginServer.edit.java   |   97 +-
 .../tileentity/TileEntitySign.edit.java       |   33 +-
 .../util/ChatComponentStyle.edit.java         |    7 +
 .../net/minecraft/util/ChatStyle.edit.java    |   23 +-
 .../net/minecraft/util/MouseHelper.edit.java  |    8 +-
 .../util/MovementInputFromOptions.edit.java   |   34 +-
 .../net/minecraft/util/Session.edit.java      |    6 +-
 .../minecraft/util/StringTranslate.edit.java  |   10 +-
 .../net/minecraft/util/StringUtils.edit.java  |    2 +-
 .../net/minecraft/util/Timer.edit.java        |   16 +-
 .../net/minecraft/world/GameRules.edit.java   |    3 +-
 .../net/minecraft/world/World.edit.java       |   79 +-
 .../net/minecraft/world/WorldServer.edit.java |   55 +-
 .../world/WorldServerMulti.edit.java          |    9 +-
 .../world/border/WorldBorder.edit.java        |   23 +-
 .../net/minecraft/world/chunk/Chunk.edit.java |   10 +-
 .../world/demo/DemoWorldServer.edit.java      |    9 +-
 .../world/storage/MapStorage.edit.java        |    2 +-
 .../world/storage/SaveFormatOld.edit.java     |   19 +-
 .../world/storage/SaveHandler.edit.java       |   33 +-
 .../world/storage/WorldInfo.edit.java         |   10 +-
 .../assets/minecraft/lang/en_US.edit.lang     |  205 +-
 .../lwjgl/java/fi/iki/elonen/NanoHTTPD.java   | 2333 +++++++++++++++++
 .../v1_8/internal/OpenGLObjects.java          |   36 +
 .../v1_8/internal/PlatformApplication.java    |   59 +-
 .../v1_8/internal/PlatformAssets.java         |   26 +-
 .../v1_8/internal/PlatformAudio.java          |    8 +-
 .../v1_8/internal/PlatformFilesystem.java     |  123 +-
 .../v1_8/internal/PlatformInput.java          |  414 ++-
 .../v1_8/internal/PlatformNetworking.java     |  130 +-
 .../v1_8/internal/PlatformOpenGL.java         |  292 ++-
 .../v1_8/internal/PlatformRuntime.java        |  142 +-
 .../v1_8/internal/PlatformScreenRecord.java   |   59 +
 .../v1_8/internal/PlatformUpdateSvc.java      |   10 +
 .../v1_8/internal/PlatformWebRTC.java         |  883 +------
 .../v1_8/internal/PlatformWebView.java        |   93 +
 .../v1_8/internal/WebSocketServerQuery.java   |  173 --
 .../buffer/EaglerLWJGLByteBuffer.java         |  111 +-
 .../buffer/EaglerLWJGLFloatBuffer.java        |   84 +-
 .../internal/buffer/EaglerLWJGLIntBuffer.java |   86 +-
 .../buffer/EaglerLWJGLShortBuffer.java        |   86 +-
 .../v1_8/internal/lwjgl/DebugFilesystem.java  |   34 +-
 .../lwjgl/DesktopClientConfigAdapter.java     |   60 +-
 .../lwjgl/DesktopWebSocketClient.java         |  109 +
 .../lwjgl/DesktopWebSocketFrameBinary.java    |   64 +
 .../lwjgl/DesktopWebSocketFrameString.java}   |   58 +-
 .../internal/lwjgl/FallbackWebViewHTTPD.java  |   41 +
 .../lwjgl/FallbackWebViewProtocol.java        |  299 +++
 .../internal/lwjgl/FallbackWebViewServer.java |  190 ++
 .../internal/lwjgl/FallbackWebViewWSD.java    |  273 ++
 .../v1_8/internal/lwjgl/JDBCFilesystem.java   |   38 +-
 .../lwjgl/JDBCFilesystemConverter.java        |    6 +-
 .../v1_8/internal/lwjgl/LWJGLEntryPoint.java  |   12 +-
 .../WebSocketClientImpl.java}                 |   72 +-
 .../internal/ClientPlatformSingleplayer.java  |   12 +-
 .../internal/ServerPlatformSingleplayer.java  |   33 +-
 .../internal/lwjgl/MemoryConnection.java      |    4 +-
 .../com/google/common/base/CharMatcher.java   |   24 +-
 .../net/lax1dude/eaglercraft/v1_8/Base64.java |    8 +
 .../v1_8/ClientUUIDLoadingCache.java          |  152 ++
 .../lax1dude/eaglercraft/v1_8/Display.java    |   41 +-
 .../lax1dude/eaglercraft/v1_8/EagRuntime.java |  101 +-
 .../lax1dude/eaglercraft/v1_8/EagUtils.java   |    9 +
 .../eaglercraft/v1_8/EaglerOutputStream.java  |    5 +
 .../v1_8/EaglerXBungeeVersion.java            |   11 +-
 .../v1_8/EaglercraftSoundManager.java         |    6 +-
 .../eaglercraft/v1_8/EaglercraftUUID.java     |   16 +-
 .../eaglercraft/v1_8/EaglercraftVersion.java  |   13 +-
 .../lax1dude/eaglercraft/v1_8/Filesystem.java |  158 ++
 .../lax1dude/eaglercraft/v1_8/Gamepad.java    |  115 +
 .../lax1dude/eaglercraft/v1_8/HashKey.java    |   54 +
 .../lax1dude/eaglercraft/v1_8/IOUtils.java    |    2 +-
 .../lax1dude/eaglercraft/v1_8/Keyboard.java   |    5 +
 .../net/lax1dude/eaglercraft/v1_8/Mouse.java  |   17 +
 .../v1_8/PauseMenuCustomizeState.java         |  257 ++
 .../v1_8/PointerInputAbstraction.java         |  227 ++
 .../net/lax1dude/eaglercraft/v1_8/Touch.java  |  134 +
 .../boot_menu/GuiScreenEnterBootMenu.java     |   54 +
 .../v1_8/cache/EaglerLoadingCache.java        |    2 +-
 .../cookie/GuiScreenInspectSessionToken.java  |   84 +
 .../cookie/GuiScreenRevokeSessionToken.java   |  146 ++
 .../cookie/GuiScreenSendRevokeRequest.java    |  177 ++
 .../v1_8/cookie/HardwareFingerprint.java      |  294 +++
 .../v1_8/cookie/ServerCookieDataStore.java    |  396 +++
 .../v1_8/crypto/AESLightEngine.java           |  527 ++++
 .../v1_8/futures/ListenableFutureTask.java    |    4 +-
 .../internal/AbstractWebSocketClient.java     |  227 ++
 .../EaglerMissingResourceException.java}      |   29 +-
 .../v1_8/internal/EnumFireKeyboardEvent.java  |   20 +
 .../v1_8/internal/EnumFireMouseEvent.java     |   20 +
 .../v1_8/internal/EnumPlatformANGLE.java      |    5 +
 .../v1_8/internal/EnumPlatformAgent.java      |    5 +-
 .../v1_8/internal/EnumPlatformOS.java         |    6 +
 .../EnumTouchEvent.java}                      |   42 +-
 .../v1_8/internal/EnumWebViewContentMode.java |   20 +
 .../v1_8/internal/GLObjectMap.java            |    7 +
 .../v1_8/internal/GamepadConstants.java       |  134 +
 .../v1_8/internal/IClientConfigAdapter.java   |   22 +-
 .../internal/IClientConfigAdapterHooks.java   |    2 +
 .../v1_8/internal/IEaglerFilesystem.java      |   46 +
 .../v1_8/internal/IServerQuery.java           |   12 +-
 .../IWebSocketClient.java}                    |   74 +-
 .../v1_8/internal/IWebSocketFrame.java}       |   28 +-
 .../v1_8/internal/QueryResponse.java          |    4 +-
 .../v1_8/internal/RamdiskFilesystemImpl.java  |  131 +
 .../v1_8/internal/ScreenRecordParameters.java |   37 +
 .../VFSFilenameIteratorNonRecursive.java}     |   50 +-
 .../v1_8/internal/WebViewOptions.java         |   67 +
 .../v1_8/internal/buffer/Buffer.java          |    8 +-
 .../v1_8/internal/buffer/ByteBuffer.java      |   12 +-
 .../buffer/EaglerBufferInputStream.java       |    1 -
 .../v1_8/internal/buffer/FloatBuffer.java     |   12 +-
 .../v1_8/internal/buffer/IntBuffer.java       |   12 +-
 .../v1_8/internal/buffer/ShortBuffer.java     |   12 +-
 .../vfs2/VFSFilenameIteratorImpl.java         |    7 +-
 .../vfs2/VFSListFilesIteratorImpl.java        |    7 +-
 .../v1_8/internal/vfs2/VFile2.java            |   85 +-
 .../v1_8/internal/vfs2/VFileOutputStream.java |    3 +-
 .../v1_8/json/JSONTypeProvider.java           |    6 +-
 .../v1_8/json/impl/SoundMapDeserializer.java  |    2 +-
 .../eaglercraft/v1_8/log4j/LogManager.java    |    2 +-
 .../eaglercraft/v1_8/log4j/Logger.java        |    2 +-
 .../v1_8/minecraft/ChunkUpdateManager.java    |   13 +-
 .../minecraft/EaglerFolderResourcePack.java   |    2 +-
 .../v1_8/minecraft/EaglerFontRenderer.java    |   19 +-
 .../minecraft/EaglerTextureAtlasSprite.java   |   11 +-
 .../v1_8/minecraft/EnumInputEvent.java        |   20 +
 .../v1_8/minecraft/FontMappingHelper.java     |  525 ++++
 .../minecraft/GuiButtonWithStupidIcons.java   |  132 +
 .../GuiScreenGenericErrorMessage.java         |    6 +-
 .../minecraft/GuiScreenVisualViewport.java    |  144 +
 .../v1_8/minecraft/TextureAnimationCache.java |    6 +-
 .../CachedNotifBadgeTexture.java              |   46 +
 .../v1_8/notifications/ClickEventZone.java    |   41 +
 .../notifications/GuiButtonNotifBell.java     |   69 +
 .../notifications/GuiScreenNotifications.java |  172 ++
 .../notifications/GuiSlotNotifications.java   |  338 +++
 .../v1_8/notifications/NotificationBadge.java |  171 ++
 .../v1_8/notifications/NotificationIcon.java  |   51 +
 .../ServerNotificationManager.java            |  277 ++
 .../ServerNotificationRenderer.java           |  539 ++++
 .../eaglercraft/v1_8/opengl/DrawUtils.java    |   58 +-
 .../v1_8/opengl/EaglerMeshLoader.java         |   22 +-
 .../v1_8/opengl/EaglercraftGPU.java           |  457 +++-
 .../v1_8/opengl/EffectPipelineFXAA.java       |   38 +-
 .../v1_8/opengl/FixedFunctionPipeline.java    |   90 +-
 .../v1_8/opengl/FixedFunctionShader.java      |    1 -
 .../eaglercraft/v1_8/opengl/GLSLHeader.java   |   99 +
 .../v1_8/opengl/GameOverlayFramebuffer.java   |   45 +-
 .../v1_8/opengl/GlStateManager.java           |   31 +-
 .../eaglercraft/v1_8/opengl/ImageData.java    |   50 +
 .../v1_8/opengl/InstancedFontRenderer.java    |  122 +-
 .../opengl/InstancedParticleRenderer.java     |  101 +-
 .../v1_8/opengl/RealOpenGLEnums.java          |    2 +-
 .../v1_8/opengl/SoftGLBufferArray.java        |  225 ++
 .../v1_8/opengl/SoftGLBufferState.java        |   31 +
 .../v1_8/opengl/SpriteLevelMixer.java         |   38 +-
 .../eaglercraft/v1_8/opengl/StreamBuffer.java |    6 +-
 .../v1_8/opengl/TextureCopyUtil.java          |  123 +-
 .../v1_8/opengl/TextureFormatHelper.java      |   81 +
 .../v1_8/opengl/VSHInputLayoutParser.java     |   91 +
 .../v1_8/opengl/WorldRenderer.java            |   13 +-
 .../opengl/ext/deferred/BlockVertexIDs.java   |    2 +-
 .../ext/deferred/CloudRenderWorker.java       |   12 +-
 .../ext/deferred/DebugFramebufferView.java    |   15 +-
 .../ext/deferred/DeferredStateManager.java    |    4 +-
 .../ext/deferred/DynamicLightInstance.java    |    4 +-
 .../ext/deferred/DynamicLightManager.java     |    8 +-
 .../ext/deferred/EaglerDeferredPipeline.java  |  184 +-
 .../ForwardRenderCallbackHandler.java         |    2 +-
 .../ext/deferred/LensFlareMeshRenderer.java   |   20 +-
 .../opengl/ext/deferred/ShaderPackInfo.java   |    2 +-
 .../ext/deferred/gui/GuiShaderConfig.java     |    5 +
 .../ext/deferred/gui/GuiShaderConfigList.java |    9 +-
 .../PipelineShaderAccelParticleForward.java   |    2 +-
 .../program/PipelineShaderGBufferCombine.java |    2 +-
 .../program/PipelineShaderGBufferFog.java     |    2 +-
 .../program/PipelineShaderLightingPoint.java  |    2 +-
 .../program/PipelineShaderLightingSun.java    |    2 +-
 .../PipelineShaderPostExposureAvg.java        |    2 +-
 .../program/PipelineShaderReprojControl.java  |    2 +-
 .../program/PipelineShaderShadowsSun.java     |    2 +-
 .../program/PipelineShaderSkyboxRender.java   |    2 +-
 .../ext/deferred/program/ShaderCompiler.java  |    4 +-
 .../ext/deferred/program/ShaderSource.java    |    2 +-
 .../texture/EaglerTextureAtlasSpritePBR.java  |    3 +-
 .../ext/deferred/texture/EmissiveItems.java   |    2 +-
 .../texture/PBRMaterialConstants.java         |    2 +-
 .../DynamicLightBucketLoader.java             |  163 +-
 .../DynamicLightsStateManager.java            |   22 +-
 .../GuiScreenContentWarning.java              |   63 +
 .../LookAlikeUnicodeConv.java                 | 1028 ++++++++
 .../profanity_filter/ProfanityFilter.java     |  534 ++++
 .../eaglercraft/v1_8/profile/CapePackets.java |   48 -
 .../v1_8/profile/EaglerProfile.java           |  110 +-
 .../v1_8/profile/EaglerSkinTexture.java       |   26 +-
 .../v1_8/profile/GuiAuthenticationScreen.java |   15 +-
 .../v1_8/profile/GuiScreenEditCape.java       |    9 +-
 .../v1_8/profile/GuiScreenEditProfile.java    |   21 +-
 .../v1_8/profile/GuiScreenImportProfile.java  |    4 +-
 .../v1_8/profile/RenderHighPoly.java          |    3 +-
 .../v1_8/profile/ServerCapeCache.java         |   63 +-
 .../v1_8/profile/ServerSkinCache.java         |   80 +-
 .../eaglercraft/v1_8/profile/SkinModel.java   |    2 +-
 .../eaglercraft/v1_8/profile/SkinPackets.java |  100 +-
 .../v1_8/profile/SkinPreviewRenderer.java     |    3 +-
 .../recording/EnumScreenRecordingCodec.java   |  152 ++
 .../recording/GuiScreenRecordingNote.java     |   52 +
 .../recording/GuiScreenRecordingSettings.java |  201 ++
 .../v1_8/recording/GuiScreenSelectCodec.java  |   92 +
 .../v1_8/recording/GuiSlotSelectCodec.java    |   58 +
 .../recording/ScreenRecordingController.java  |   99 +
 .../v1_8/socket/ConnectionHandshake.java      |  196 +-
 .../socket/EaglercraftNetworkManager.java     |  120 +-
 .../v1_8/socket/GuiHandshakeApprove.java      |    2 +-
 .../v1_8/socket/RateLimitTracker.java         |   14 +-
 .../v1_8/socket/ServerQueryDispatch.java      |    4 +-
 .../v1_8/socket/ServerQueryImpl.java}         |  102 +-
 .../v1_8/socket/WebSocketNetworkManager.java  |  152 ++
 .../client/ClientV3MessageHandler.java        |  130 +
 .../client/ClientV4MessageHandler.java        |  222 ++
 .../client/GameProtocolMessageController.java |  199 ++
 .../client/IPluginMessageSendFunction.java    |   24 +
 .../client/PacketBufferInputWrapper.java      |  303 +++
 .../client/PacketBufferOutputWrapper.java     |  316 +++
 .../v1_8/sp/SingleplayerServerController.java |   62 +-
 .../eaglercraft/v1_8/sp/SkullCommand.java     |    9 +-
 .../sp/gui/GuiIntegratedServerStartup.java    |   58 -
 .../v1_8/sp/gui/GuiScreenAddRelay.java        |   13 +
 .../GuiScreenDemoIntegratedServerStartup.java |   43 +-
 .../sp/gui/GuiScreenIntegratedServerBusy.java |   10 +-
 .../gui/GuiScreenIntegratedServerCrashed.java |    4 +-
 .../gui/GuiScreenIntegratedServerFailed.java  |   12 +
 .../gui/GuiScreenIntegratedServerStartup.java |   35 +-
 .../v1_8/sp/gui/GuiScreenLANConnect.java      |   11 +
 .../v1_8/sp/gui/GuiScreenLANConnecting.java   |   10 +-
 .../v1_8/sp/gui/GuiScreenNameWorldImport.java |   14 +-
 .../sp/gui/GuiScreenRAMDiskModeDetected.java  |   55 +
 .../v1_8/sp/gui/GuiScreenRelay.java           |   12 +-
 .../gui/GuiScreenSingleplayerConnecting.java  |   18 +-
 .../v1_8/sp/gui/GuiShareToLan.java            |   12 +
 .../eaglercraft/v1_8/sp/gui/GuiSlider2.java   |   36 +-
 .../v1_8/sp/ipc/IPCPacket14StringList.java    |    6 +-
 .../v1_8/sp/ipc/IPCPacket16NBTList.java       |    6 +-
 .../v1_8/sp/ipc/IPCPacket17ConfigureLAN.java  |    2 +-
 ...age.java => IPCPacket1ALoggerMessage.java} |   10 +-
 ...ing.java => IPCPacket1BEnableLogging.java} |    8 +-
 .../v1_8/sp/ipc/IPCPacket1CIssueDetected.java |   57 +
 .../v1_8/sp/ipc/IPCPacketManager.java         |    7 +-
 .../v1_8/sp/lan/LANClientNetworkManager.java  |   60 +-
 .../v1_8/sp/lan/LANClientPeer.java            |   21 +-
 .../v1_8/sp/lan/LANServerController.java      |   54 +-
 .../v1_8/sp/lan/LANServerList.java            |   18 +-
 .../v1_8/sp/relay/RelayLoggerImpl.java        |   54 +
 .../v1_8/sp/relay/RelayManager.java           |   28 +-
 .../eaglercraft/v1_8/sp/relay/RelayQuery.java |    1 +
 .../v1_8/sp/relay/RelayQueryImpl.java         |  225 ++
 .../sp/relay/RelayQueryRateLimitDummy.java    |   75 +
 .../v1_8/sp/relay/RelayServer.java            |   36 +-
 .../sp/relay/RelayServerRateLimitTracker.java |   98 +
 .../v1_8/sp/relay/RelayServerSocket.java      |    9 +-
 .../v1_8/sp/relay/RelayServerSocketImpl.java  |  173 ++
 .../RelayServerSocketRateLimitDummy.java      |   80 +
 .../v1_8/sp/relay/RelayWorldsQuery.java       |    5 +-
 .../v1_8/sp/relay/RelayWorldsQueryImpl.java   |  197 ++
 .../relay/RelayWorldsQueryRateLimitDummy.java |   64 +
 .../v1_8/sp/relay/pkt/ICEServerSet.java       |   55 -
 .../v1_8/sp/relay/pkt/IPacket.java            |  165 --
 .../v1_8/sp/relay/pkt/IPacket00Handshake.java |   57 -
 .../sp/relay/pkt/IPacket01ICEServers.java     |   53 -
 .../sp/relay/pkt/IPacket03ICECandidate.java   |   49 -
 .../sp/relay/pkt/IPacket04Description.java    |   49 -
 .../relay/pkt/IPacketFEDisconnectClient.java  |   67 -
 .../v1_8/sp/relay/pkt/IPacketFFErrorCode.java |   82 -
 .../v1_8/sp/server/EaglerChunkLoader.java     |    4 +-
 .../server/EaglerIntegratedServerWorker.java  |   49 +-
 .../v1_8/sp/server/EaglerMinecraftServer.java |   21 +-
 .../v1_8/sp/server/EaglerSaveFormat.java      |   20 +-
 .../v1_8/sp/server/EaglerSaveHandler.java     |    2 +-
 .../eaglercraft/v1_8/sp/server/WorldsDB.java  |   32 +
 .../v1_8/sp/server/export/EPKCompiler.java    |   97 +-
 .../sp/server/export/WorldConverterEPK.java   |    5 +-
 .../sp/server/export/WorldConverterMCA.java   |   25 +-
 .../v1_8/sp/server/skins/CustomSkullData.java |   29 +-
 .../server/skins/IntegratedCapePackets.java   |   67 +-
 .../server/skins/IntegratedCapeService.java   |   27 +-
 .../server/skins/IntegratedSkinPackets.java   |  208 +-
 .../server/skins/IntegratedSkinService.java   |   59 +-
 .../IntegratedServerPlayerNetworkManager.java |    5 +-
 .../protocol/ServerV3MessageHandler.java      |   90 +
 .../protocol/ServerV4MessageHandler.java      |  104 +
 .../server/voice/IntegratedVoiceService.java  |  149 +-
 .../voice/IntegratedVoiceSignalPackets.java   |  198 --
 .../socket/NetHandlerSingleplayerLogin.java   |   22 +-
 .../v1_8/touch_gui/EnumTouchControl.java      |  579 ++++
 .../v1_8/touch_gui/EnumTouchControlPos.java   |   20 +
 .../v1_8/touch_gui/EnumTouchLayoutState.java  |   28 +
 .../v1_8/touch_gui/TouchControlInput.java     |   27 +
 .../v1_8/touch_gui/TouchControls.java         |  164 ++
 .../v1_8/touch_gui/TouchOverlayRenderer.java  |  197 ++
 .../v1_8/update/GuiUpdateDownloadSuccess.java |   60 +
 .../v1_8/update/GuiUpdateInstallOptions.java  |   84 +
 .../v1_8/update/GuiUpdateVersionList.java     |   13 +-
 .../v1_8/update/GuiUpdateVersionSlot.java     |    5 +-
 .../v1_8/update/RelayUpdateChecker.java       |   10 +-
 .../v1_8/update/UpdateDataObj.java            |   28 +
 .../UpdateResultObj.java}                     |   53 +-
 .../v1_8/update/UpdateService.java            |   23 +-
 .../eaglercraft/v1_8/voice/ExpiringSet.java   |    6 +-
 .../eaglercraft/v1_8/voice/GuiVoiceMenu.java  |   60 +-
 .../v1_8/voice/GuiVoiceOverlay.java           |   11 +-
 .../v1_8/voice/VoiceClientController.java     |   70 +-
 .../v1_8/voice/VoiceSignalPackets.java        |  142 -
 .../v1_8/voice/VoiceTagRenderer.java          |    2 +-
 .../v1_8/webview/GuiScreenPhishingWaring.java |  104 +
 .../webview/GuiScreenRecieveServerInfo.java   |  203 ++
 .../v1_8/webview/GuiScreenServerInfo.java     |  128 +
 .../webview/GuiScreenServerInfoDesktop.java   |   92 +
 .../v1_8/webview/PermissionsCache.java        |   64 +
 .../v1_8/webview/ServerInfoCache.java         |  130 +
 .../webview/WebViewOverlayController.java     |   92 +
 sources/main/java/org/json/JSONArray.java     |  330 ++-
 sources/main/java/org/json/JSONObject.java    |  425 ++-
 .../org/json/JSONParserConfiguration.java     |   26 +
 sources/main/java/org/json/JSONPointer.java   |   12 +
 .../java/org/json/JSONPointerException.java   |   11 +
 .../java/org/json/JSONPropertyIgnore.java     |    6 +-
 .../main/java/org/json/JSONPropertyName.java  |    7 +-
 sources/main/java/org/json/JSONString.java    |    1 +
 sources/main/java/org/json/JSONTokener.java   |   45 +-
 .../java/org/json/ParserConfiguration.java    |  126 +
 .../v1_8/sp/relay/pkt/RelayPacket.java        |    4 +-
 .../sp/relay/pkt/RelayPacket01ICEServers.java |    2 +-
 .../relay/pkt/RelayPacket07LocalWorlds.java   |    2 +-
 sources/resources/SignedClientTemplate.txt    |  229 +-
 sources/resources/assets/eagler/CREDITS.txt   |   56 +-
 .../assets/eagler/audioctx_test_ogg.dat       |  Bin 0 -> 3980 bytes
 .../assets/eagler/audioctx_test_wav16.dat     |  Bin 0 -> 2106 bytes
 .../assets/eagler/audioctx_test_wav32f.dat    |  Bin 0 -> 4144 bytes
 .../eagler/boot_menu/boot_menu_markup.html    |   88 +
 .../eagler/boot_menu/boot_menu_style.css      |  328 +++
 .../conf_template_eaglercraftX_1_8.json       |    4 +
 ...conf_template_eaglercraftX_1_8_signed.json |    4 +
 .../conf_template_eaglercraft_1_5.json        |    4 +
 .../conf_template_eaglercraft_1_5_legacy.json |    5 +
 .../conf_template_eaglercraft_b1_3.json       |    5 +
 .../conf_template_peytonplayz585_a1_2_6.json  |    4 +
 .../conf_template_peytonplayz585_b1_7_3.json  |    4 +
 .../conf_template_peytonplayz585_indev.json   |    4 +
 .../conf_template_standard_offline.json       |    8 +
 .../eagler/boot_menu/meta_opts_templates.json |  192 ++
 .../offline_template_eaglercraftX_1_8.html    |   86 +
 ...template_eaglercraftX_1_8_fat_offline.html |   85 +
 ..._template_eaglercraftX_1_8_fat_signed.html |  268 ++
 ...line_template_eaglercraftX_1_8_signed.html |  267 ++
 .../offline_template_eaglercraft_1_5.html     |   78 +
 ...fline_template_eaglercraft_1_5_legacy.html |   59 +
 .../offline_template_eaglercraft_b1_3.html    |   59 +
 .../offline_template_peytonplayz585_a_b.html  |   40 +
 ...offline_template_peytonplayz585_indev.html |   38 +
 .../offline_template_standard_offline.html    |   77 +
 .../opts_template_eaglercraftX_1_8.txt        |   66 +
 .../opts_template_eaglercraftX_1_8_demo.txt   |   66 +
 ...template_eaglercraftX_1_8_html5Cursors.txt |   66 +
 .../opts_template_eaglercraft_1_5.txt         |   52 +
 .../opts_template_eaglercraft_1_5_legacy.txt  |   32 +
 ...ts_template_eaglercraft_1_5_livestream.txt |   63 +
 .../opts_template_peytonplayz585_a1_2_6.txt   |    6 +
 .../opts_template_peytonplayz585_b1_7_3.txt   |    6 +
 .../boot_menu/web_cl_eagleiii_8x16.woff       |  Bin 0 -> 9876 bytes
 .../assets/eagler/glsl/accel_font.fsh         |   16 +-
 .../assets/eagler/glsl/accel_font.vsh         |   23 +-
 .../assets/eagler/glsl/accel_particle.fsh     |   16 +-
 .../assets/eagler/glsl/accel_particle.vsh     |   29 +-
 sources/resources/assets/eagler/glsl/core.fsh |   70 +-
 sources/resources/assets/eagler/glsl/core.vsh |   28 +-
 .../eagler/glsl/deferred/forward_core.fsh     |   16 +-
 .../glsl/deferred/reproject_control.fsh       |    4 +-
 .../glsl/deferred/shader_pack_info.json       |    2 +-
 .../eagler/glsl/deferred/ssao_generate.fsh    |    2 +-
 .../glsl/dynamiclights/core_dynamiclights.fsh |   29 +-
 .../assets/eagler/glsl/gles2_compat.glsl      |   98 +
 .../assets/eagler/glsl/hw_fingerprint.fsh     |   55 +
 .../resources/assets/eagler/glsl/local.vsh    |   14 +-
 .../assets/eagler/glsl/post_fxaa.fsh          |   34 +-
 .../assets/eagler/glsl/texture_blit.fsh       |   14 +-
 .../assets/eagler/glsl/texture_blit.vsh       |   14 +-
 .../assets/eagler/glsl/texture_mix.fsh        |   14 +-
 .../assets/eagler/gui/eagler_gui.png          |  Bin 8564 -> 11256 bytes
 .../assets/eagler/gui/notif_bk_large.png      |  Bin 0 -> 5089 bytes
 .../resources/assets/eagler/gui/touch_gui.png |  Bin 0 -> 13590 bytes
 sources/resources/plugin_download.zip         |  Bin 256139 -> 540037 bytes
 sources/resources/plugin_version.json         |    2 +-
 sources/resources/profanity_filter.wlist      |  740 ++++++
 sources/resources/relay_download.zip          |  Bin 267938 -> 234512 bytes
 sources/setup/eclipseProjectFiles/.classpath  |    3 +
 sources/setup/eclipseProjectFiles/.project    |   25 +-
 .../workspace_template/.gitignore.default     |    3 +-
 sources/setup/workspace_template/build.gradle |   57 +-
 .../desktopRuntime/RTWebViewClient.html       |  514 ++++
 .../{libGLESv2.so => libGLESv2.so.2}          |  Bin
 sources/setup/workspace_template/gradlew      |  294 ++-
 .../javascript/ES6ShimScript.txt              |   31 +
 .../javascript/OfflineDownloadTemplate.txt    |   29 +-
 .../javascript/SignedBundleTemplate.txt       |   10 +-
 .../javascript/SignedClientTemplate.txt       |  230 +-
 .../javascript/UpdateDownloadSources.txt      |   19 +
 .../workspace_template/javascript/index.html  |   26 +-
 .../v1_8/boot_menu/teavm/BootMenuAssets.java  |   35 +
 .../boot_menu/teavm/BootMenuConstants.java    |   53 +
 .../v1_8/boot_menu/teavm/BootMenuDOM.java     |  203 ++
 .../boot_menu/teavm/BootMenuDataManager.java  |  464 ++++
 .../boot_menu/teavm/BootMenuDatastore.java    |  362 +++
 .../boot_menu/teavm/BootMenuEntryPoint.java   |  178 ++
 .../teavm/BootMenuFatOfflineLoader.java       |   93 +
 .../v1_8/boot_menu/teavm/BootMenuMain.java    |  304 +++
 .../boot_menu/teavm/BootMenuMetadata.java     |  224 ++
 .../boot_menu/teavm/BootableClientEntry.java  |  366 +++
 .../teavm/CheckboxListController.java         |  108 +
 .../boot_menu/teavm/ClientBootFactory.java    |  725 +++++
 .../v1_8/boot_menu/teavm/ClientDataEntry.java |  152 ++
 .../teavm/ConfirmationPopupController.java    |  191 ++
 .../boot_menu/teavm/EPKClientFactory.java     |  100 +
 .../v1_8/boot_menu/teavm/EPKClientParser.java |  136 +
 .../v1_8/boot_menu/teavm/EPKDataEntry.java    |   30 +
 .../boot_menu/teavm/EnumClientFormatType.java |   67 +
 .../boot_menu/teavm/EnumClientLaunchType.java |   86 +
 .../boot_menu/teavm/EnumOfflineParseType.java |   53 +
 .../teavm/FatOfflineDownloadFactory.java      |  207 ++
 .../teavm/IBootMenuConfigAdapter.java         |   30 +
 .../boot_menu/teavm/IProgressMsgCallback.java |   22 +
 .../boot_menu/teavm/InputPopupController.java |  111 +
 .../v1_8/boot_menu/teavm/KeyCodes.java        |   34 +
 .../boot_menu/teavm/LaunchConfigEntry.java    |  143 +
 .../teavm/MenuPopupStateConfirmation.java     |  141 +
 .../teavm/MenuPopupStateEditInteger.java      |  114 +
 .../teavm/MenuPopupStateEditString.java       |  109 +
 .../teavm/MenuPopupStateFileChooser.java      |  106 +
 .../teavm/MenuPopupStateLoading.java          |   98 +
 .../teavm/MenuPopupStateSelection.java        |  141 +
 .../v1_8/boot_menu/teavm/MenuState.java       |  135 +
 .../v1_8/boot_menu/teavm/MenuStateBoot.java   |  583 ++++
 .../teavm/MenuStateClientMultiSelect.java     |  137 +
 .../teavm/MenuStateEditBootOrder.java         |  268 ++
 .../teavm/MenuStateEditingLaunch.java         |  674 +++++
 .../boot_menu/teavm/MenuStateEnterSetup.java  |  261 ++
 .../teavm/MenuStateImportMultiSelect.java     |  144 +
 .../teavm/MenuStateSelectExportClients.java   |  151 ++
 .../teavm/OfflineDownloadFactory.java         |  613 +++++
 .../teavm/OfflineDownloadParser.java          |  990 +++++++
 .../boot_menu/teavm/RelayRandomizeHelper.java |   71 +
 .../teavm/SelectionListController.java        |  240 ++
 .../boot_menu/teavm/SignatureCheckHelper.java |   48 +
 .../teavm/SignedClientInstaller.java          |   77 +
 .../v1_8/boot_menu/teavm/TemplateLoader.java  |   77 +
 .../v1_8/boot_menu/teavm/TemplateParser.java  |  260 ++
 .../teavm/UnsignedBootException.java          |   23 +
 .../teavm/java/com/jcraft/jogg/Buffer.java    |  293 +++
 .../teavm/java/com/jcraft/jogg/Packet.java    |   45 +
 sources/teavm/java/com/jcraft/jogg/Page.java  |  130 +
 .../java/com/jcraft/jogg/StreamState.java     |  538 ++++
 .../teavm/java/com/jcraft/jogg/SyncState.java |  273 ++
 .../teavm/java/com/jcraft/jorbis/Block.java   |  126 +
 .../java/com/jcraft/jorbis/CodeBook.java      |  471 ++++
 .../teavm/java/com/jcraft/jorbis/Comment.java |  240 ++
 .../teavm/java/com/jcraft/jorbis/Drft.java    | 1319 ++++++++++
 .../java/com/jcraft/jorbis/DspState.java      |  369 +++
 .../teavm/java/com/jcraft/jorbis/Floor0.java  |  332 +++
 .../teavm/java/com/jcraft/jorbis/Floor1.java  |  584 +++++
 .../java/com/jcraft/jorbis/FuncFloor.java     |   52 +
 .../java/com/jcraft/jorbis/FuncMapping.java   |   45 +
 .../java/com/jcraft/jorbis/FuncResidue.java   |   45 +
 .../java/com/jcraft/jorbis/FuncTime.java      |   45 +
 .../teavm/java/com/jcraft/jorbis/Info.java    |  468 ++++
 .../java/com/jcraft/jorbis/InfoMode.java      |   34 +
 .../com/jcraft/jorbis/JOrbisException.java    |   40 +
 .../teavm/java/com/jcraft/jorbis/Lookup.java  |  122 +
 sources/teavm/java/com/jcraft/jorbis/Lpc.java |  185 ++
 sources/teavm/java/com/jcraft/jorbis/Lsp.java |  102 +
 .../java/com/jcraft/jorbis/Mapping0.java      |  361 +++
 .../teavm/java/com/jcraft/jorbis/Mdct.java    |  249 ++
 .../teavm/java/com/jcraft/jorbis/PsyInfo.java |   74 +
 .../teavm/java/com/jcraft/jorbis/PsyLook.java |   42 +
 .../java/com/jcraft/jorbis/Residue0.java      |  326 +++
 .../java/com/jcraft/jorbis/Residue1.java      |   44 +
 .../java/com/jcraft/jorbis/Residue2.java      |   41 +
 .../com/jcraft/jorbis/StaticCodeBook.java     |  436 +++
 .../teavm/java/com/jcraft/jorbis/Time0.java   |   52 +
 .../teavm/java/com/jcraft/jorbis/Util.java    |   30 +
 .../java/com/jcraft/jorbis/VorbisFile.java    | 1348 ++++++++++
 .../v1_8/internal/OpenGLObjects.java          |  113 +-
 .../v1_8/internal/PlatformApplication.java    |  307 ++-
 .../v1_8/internal/PlatformAssets.java         |   66 +-
 .../v1_8/internal/PlatformAudio.java          |  315 ++-
 .../v1_8/internal/PlatformFilesystem.java     |  331 +--
 .../v1_8/internal/PlatformInput.java          | 2154 +++++++++++++--
 .../v1_8/internal/PlatformNetworking.java     |  182 +-
 .../v1_8/internal/PlatformOpenGL.java         |  337 ++-
 .../v1_8/internal/PlatformRuntime.java        | 1028 ++++++--
 .../v1_8/internal/PlatformScreenRecord.java   |  286 ++
 .../v1_8/internal/PlatformUpdateSvc.java      |   43 +-
 .../v1_8/internal/PlatformVoiceClient.java    |  265 +-
 .../v1_8/internal/PlatformWebRTC.java         | 1009 ++-----
 .../v1_8/internal/PlatformWebView.java        |  639 +++++
 .../buffer/EaglerArrayByteBuffer.java         |  118 +-
 .../buffer/EaglerArrayFloatBuffer.java        |   87 +-
 .../internal/buffer/EaglerArrayIntBuffer.java |   87 +-
 .../buffer/EaglerArrayShortBuffer.java        |   87 +-
 .../teavm/AdvancedHTMLIFrameElement.java      |  120 +
 .../teavm/ArrayBufferInputStream.java         |   37 +-
 .../internal/teavm/Base64VarIntArray.java     |  129 +
 .../v1_8/internal/teavm/ClassesJSLocator.java |   94 +
 .../v1_8/internal/teavm/ClientMain.java       |  334 ++-
 .../internal/teavm/DebugConsoleWindow.java    |   91 +-
 .../v1_8/internal/teavm/ES6ShimStatus.java    |   82 +
 .../v1_8/internal/teavm/ES6ShimStatusJS.java  |   52 +
 .../v1_8/internal/teavm/EarlyLoadScreen.java  |  220 +-
 .../internal/teavm/EnumES6ShimStatus.java     |   56 +
 .../v1_8/internal/teavm/EnumES6Shims.java     |   58 +
 .../internal/teavm/FixWebMDurationJS.java     |   20 +
 .../teavm/IFrameSafetyException.java}         |   33 +-
 .../internal/teavm/ImmediateContinue.java     |   26 +
 .../internal/teavm/IndexedDBFilesystem.java   |  365 +++
 .../v1_8/internal/teavm/InputEvent.java       |   29 +
 .../teavm/JOrbisAudioBufferDecoder.java       |  420 +++
 .../teavm/LegacyKeycodeTranslator.java        |  328 +++
 .../v1_8/internal/teavm/MessageChannel.java   |   37 +
 .../v1_8/internal/teavm/OffsetTouch.java      |   43 +
 .../v1_8/internal/teavm/PCMToWAVLoader.java   |  118 +
 .../v1_8/internal/teavm/SortedTouchEvent.java |   85 +
 .../internal/teavm/TeaVMBlobURLHandle.java    |   28 +
 .../internal/teavm/TeaVMBlobURLManager.java   |  188 ++
 .../teavm/TeaVMClientConfigAdapter.java       |  243 +-
 .../teavm/TeaVMClientConfigAdapterHooks.java  |   19 +
 .../internal/teavm/TeaVMDataURLManager.java   |   87 +
 .../teavm/TeaVMEnterBootMenuException.java    |   20 +
 .../v1_8/internal/teavm/TeaVMFetchJS.java     |   44 +
 .../teavm/TeaVMRuntimeDeobfuscator.java       |  242 ++
 .../internal/teavm/TeaVMUpdateThread.java     |   20 +-
 .../v1_8/internal/teavm/TeaVMUtils.java       |  320 +--
 .../internal/teavm/TeaVMWebSocketClient.java  |  125 +
 .../internal/teavm/TeaVMWebSocketFrame.java   |  114 +
 .../v1_8/internal/teavm/Touch.java            |   67 +
 .../v1_8/internal/teavm/TouchEvent.java       |   44 +
 .../v1_8/internal/teavm/TouchList.java        |   28 +
 .../v1_8/internal/teavm/VisualViewport.java   |   45 +
 .../teavm/WebGLANGLEInstancedArrays.java      |   28 +
 .../v1_8/internal/teavm/WebGLBackBuffer.java  |  300 +++
 .../teavm/WebGLOESVertexArrayObject.java      |   28 +
 .../TeaVMRuntimeDeobfuscatorGenerator.java    |  108 +
 .../generators/TeaVMUtilsUnwrapGenerator.java |  166 ++
 .../teavm/opts/JSEaglercraftXOptsHooks.java   |    3 +
 .../teavm/opts/JSEaglercraftXOptsRoot.java    |   72 +
 .../teavm/opts/JSEaglercraftXOptsServer.java  |    3 +
 .../internal/ClientPlatformSingleplayer.java  |  179 +-
 .../internal/ServerPlatformSingleplayer.java  |  207 +-
 .../internal/teavm/SingleThreadWorker.java    |   44 +
 .../sp/server/internal/teavm/WorkerMain.java  |    2 +-
 .../org/teavm/backend/javascript/long.js      |  693 +++++
 683 files changed, 62074 insertions(+), 8996 deletions(-)
 create mode 100644 CODE_STANDARDS.md
 create mode 100644 buildtools/src/main/java/net/lax1dude/eaglercraft/v1_8/buildtools/gui/ES6Compat.java
 create mode 100644 patches/minecraft/net/minecraft/client/gui/ChatLine.edit.java
 create mode 100644 patches/minecraft/net/minecraft/client/gui/ScaledResolution.edit.java
 create mode 100644 patches/minecraft/net/minecraft/entity/ai/EntitySenses.edit.java
 delete mode 100644 patches/minecraft/net/minecraft/profiler/Profiler.edit.java
 create mode 100644 sources/lwjgl/java/fi/iki/elonen/NanoHTTPD.java
 create mode 100644 sources/lwjgl/java/net/lax1dude/eaglercraft/v1_8/internal/PlatformScreenRecord.java
 create mode 100644 sources/lwjgl/java/net/lax1dude/eaglercraft/v1_8/internal/PlatformWebView.java
 delete mode 100644 sources/lwjgl/java/net/lax1dude/eaglercraft/v1_8/internal/WebSocketServerQuery.java
 create mode 100644 sources/lwjgl/java/net/lax1dude/eaglercraft/v1_8/internal/lwjgl/DesktopWebSocketClient.java
 create mode 100644 sources/lwjgl/java/net/lax1dude/eaglercraft/v1_8/internal/lwjgl/DesktopWebSocketFrameBinary.java
 rename sources/{main/java/net/lax1dude/eaglercraft/v1_8/sp/relay/pkt/IPacket70SpecialUpdate.java => lwjgl/java/net/lax1dude/eaglercraft/v1_8/internal/lwjgl/DesktopWebSocketFrameString.java} (50%)
 create mode 100644 sources/lwjgl/java/net/lax1dude/eaglercraft/v1_8/internal/lwjgl/FallbackWebViewHTTPD.java
 create mode 100644 sources/lwjgl/java/net/lax1dude/eaglercraft/v1_8/internal/lwjgl/FallbackWebViewProtocol.java
 create mode 100644 sources/lwjgl/java/net/lax1dude/eaglercraft/v1_8/internal/lwjgl/FallbackWebViewServer.java
 create mode 100644 sources/lwjgl/java/net/lax1dude/eaglercraft/v1_8/internal/lwjgl/FallbackWebViewWSD.java
 rename sources/lwjgl/java/net/lax1dude/eaglercraft/v1_8/internal/{WebSocketPlayClient.java => lwjgl/WebSocketClientImpl.java} (57%)
 create mode 100644 sources/main/java/net/lax1dude/eaglercraft/v1_8/ClientUUIDLoadingCache.java
 create mode 100644 sources/main/java/net/lax1dude/eaglercraft/v1_8/Filesystem.java
 create mode 100644 sources/main/java/net/lax1dude/eaglercraft/v1_8/Gamepad.java
 create mode 100644 sources/main/java/net/lax1dude/eaglercraft/v1_8/HashKey.java
 create mode 100644 sources/main/java/net/lax1dude/eaglercraft/v1_8/PauseMenuCustomizeState.java
 create mode 100644 sources/main/java/net/lax1dude/eaglercraft/v1_8/PointerInputAbstraction.java
 create mode 100644 sources/main/java/net/lax1dude/eaglercraft/v1_8/Touch.java
 create mode 100644 sources/main/java/net/lax1dude/eaglercraft/v1_8/boot_menu/GuiScreenEnterBootMenu.java
 create mode 100644 sources/main/java/net/lax1dude/eaglercraft/v1_8/cookie/GuiScreenInspectSessionToken.java
 create mode 100644 sources/main/java/net/lax1dude/eaglercraft/v1_8/cookie/GuiScreenRevokeSessionToken.java
 create mode 100644 sources/main/java/net/lax1dude/eaglercraft/v1_8/cookie/GuiScreenSendRevokeRequest.java
 create mode 100644 sources/main/java/net/lax1dude/eaglercraft/v1_8/cookie/HardwareFingerprint.java
 create mode 100644 sources/main/java/net/lax1dude/eaglercraft/v1_8/cookie/ServerCookieDataStore.java
 create mode 100644 sources/main/java/net/lax1dude/eaglercraft/v1_8/crypto/AESLightEngine.java
 create mode 100644 sources/main/java/net/lax1dude/eaglercraft/v1_8/internal/AbstractWebSocketClient.java
 rename sources/{teavm/java/net/lax1dude/eaglercraft/v1_8/internal/PlatformBufferFunctions.java => main/java/net/lax1dude/eaglercraft/v1_8/internal/EaglerMissingResourceException.java} (63%)
 create mode 100644 sources/main/java/net/lax1dude/eaglercraft/v1_8/internal/EnumFireKeyboardEvent.java
 create mode 100644 sources/main/java/net/lax1dude/eaglercraft/v1_8/internal/EnumFireMouseEvent.java
 rename sources/main/java/net/lax1dude/eaglercraft/v1_8/{sp/relay/pkt/IPacket05ClientSuccess.java => internal/EnumTouchEvent.java} (55%)
 create mode 100644 sources/main/java/net/lax1dude/eaglercraft/v1_8/internal/EnumWebViewContentMode.java
 create mode 100644 sources/main/java/net/lax1dude/eaglercraft/v1_8/internal/GamepadConstants.java
 create mode 100644 sources/main/java/net/lax1dude/eaglercraft/v1_8/internal/IEaglerFilesystem.java
 rename sources/main/java/net/lax1dude/eaglercraft/v1_8/{sp/relay/pkt/IPacket07LocalWorlds.java => internal/IWebSocketClient.java} (50%)
 rename sources/{lwjgl/java/net/lax1dude/eaglercraft/v1_8/internal/PlatformBufferFunctions.java => main/java/net/lax1dude/eaglercraft/v1_8/internal/IWebSocketFrame.java} (62%)
 create mode 100644 sources/main/java/net/lax1dude/eaglercraft/v1_8/internal/RamdiskFilesystemImpl.java
 create mode 100644 sources/main/java/net/lax1dude/eaglercraft/v1_8/internal/ScreenRecordParameters.java
 rename sources/main/java/net/lax1dude/eaglercraft/v1_8/{sp/relay/pkt/IPacket69Pong.java => internal/VFSFilenameIteratorNonRecursive.java} (53%)
 create mode 100644 sources/main/java/net/lax1dude/eaglercraft/v1_8/internal/WebViewOptions.java
 create mode 100644 sources/main/java/net/lax1dude/eaglercraft/v1_8/minecraft/EnumInputEvent.java
 create mode 100644 sources/main/java/net/lax1dude/eaglercraft/v1_8/minecraft/FontMappingHelper.java
 create mode 100644 sources/main/java/net/lax1dude/eaglercraft/v1_8/minecraft/GuiButtonWithStupidIcons.java
 create mode 100644 sources/main/java/net/lax1dude/eaglercraft/v1_8/minecraft/GuiScreenVisualViewport.java
 create mode 100644 sources/main/java/net/lax1dude/eaglercraft/v1_8/notifications/CachedNotifBadgeTexture.java
 create mode 100644 sources/main/java/net/lax1dude/eaglercraft/v1_8/notifications/ClickEventZone.java
 create mode 100644 sources/main/java/net/lax1dude/eaglercraft/v1_8/notifications/GuiButtonNotifBell.java
 create mode 100644 sources/main/java/net/lax1dude/eaglercraft/v1_8/notifications/GuiScreenNotifications.java
 create mode 100644 sources/main/java/net/lax1dude/eaglercraft/v1_8/notifications/GuiSlotNotifications.java
 create mode 100644 sources/main/java/net/lax1dude/eaglercraft/v1_8/notifications/NotificationBadge.java
 create mode 100644 sources/main/java/net/lax1dude/eaglercraft/v1_8/notifications/NotificationIcon.java
 create mode 100644 sources/main/java/net/lax1dude/eaglercraft/v1_8/notifications/ServerNotificationManager.java
 create mode 100644 sources/main/java/net/lax1dude/eaglercraft/v1_8/notifications/ServerNotificationRenderer.java
 create mode 100644 sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/GLSLHeader.java
 create mode 100644 sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/SoftGLBufferArray.java
 create mode 100644 sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/SoftGLBufferState.java
 create mode 100644 sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/TextureFormatHelper.java
 create mode 100644 sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/VSHInputLayoutParser.java
 create mode 100644 sources/main/java/net/lax1dude/eaglercraft/v1_8/profanity_filter/GuiScreenContentWarning.java
 create mode 100644 sources/main/java/net/lax1dude/eaglercraft/v1_8/profanity_filter/LookAlikeUnicodeConv.java
 create mode 100644 sources/main/java/net/lax1dude/eaglercraft/v1_8/profanity_filter/ProfanityFilter.java
 create mode 100644 sources/main/java/net/lax1dude/eaglercraft/v1_8/recording/EnumScreenRecordingCodec.java
 create mode 100644 sources/main/java/net/lax1dude/eaglercraft/v1_8/recording/GuiScreenRecordingNote.java
 create mode 100644 sources/main/java/net/lax1dude/eaglercraft/v1_8/recording/GuiScreenRecordingSettings.java
 create mode 100644 sources/main/java/net/lax1dude/eaglercraft/v1_8/recording/GuiScreenSelectCodec.java
 create mode 100644 sources/main/java/net/lax1dude/eaglercraft/v1_8/recording/GuiSlotSelectCodec.java
 create mode 100644 sources/main/java/net/lax1dude/eaglercraft/v1_8/recording/ScreenRecordingController.java
 rename sources/{teavm/java/net/lax1dude/eaglercraft/v1_8/internal/teavm/TeaVMServerQuery.java => main/java/net/lax1dude/eaglercraft/v1_8/socket/ServerQueryImpl.java} (64%)
 create mode 100644 sources/main/java/net/lax1dude/eaglercraft/v1_8/socket/WebSocketNetworkManager.java
 create mode 100644 sources/main/java/net/lax1dude/eaglercraft/v1_8/socket/protocol/client/ClientV3MessageHandler.java
 create mode 100644 sources/main/java/net/lax1dude/eaglercraft/v1_8/socket/protocol/client/ClientV4MessageHandler.java
 create mode 100644 sources/main/java/net/lax1dude/eaglercraft/v1_8/socket/protocol/client/GameProtocolMessageController.java
 create mode 100644 sources/main/java/net/lax1dude/eaglercraft/v1_8/socket/protocol/client/IPluginMessageSendFunction.java
 create mode 100644 sources/main/java/net/lax1dude/eaglercraft/v1_8/socket/protocol/client/PacketBufferInputWrapper.java
 create mode 100644 sources/main/java/net/lax1dude/eaglercraft/v1_8/socket/protocol/client/PacketBufferOutputWrapper.java
 delete mode 100644 sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/gui/GuiIntegratedServerStartup.java
 create mode 100644 sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/gui/GuiScreenRAMDiskModeDetected.java
 rename sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/ipc/{IPCPacket20LoggerMessage.java => IPCPacket1ALoggerMessage.java} (86%)
 rename sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/ipc/{IPCPacket21EnableLogging.java => IPCPacket1BEnableLogging.java} (87%)
 create mode 100644 sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/ipc/IPCPacket1CIssueDetected.java
 create mode 100644 sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/relay/RelayLoggerImpl.java
 create mode 100644 sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/relay/RelayQueryImpl.java
 create mode 100644 sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/relay/RelayQueryRateLimitDummy.java
 create mode 100644 sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/relay/RelayServerRateLimitTracker.java
 create mode 100644 sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/relay/RelayServerSocketImpl.java
 create mode 100644 sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/relay/RelayServerSocketRateLimitDummy.java
 create mode 100644 sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/relay/RelayWorldsQueryImpl.java
 create mode 100644 sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/relay/RelayWorldsQueryRateLimitDummy.java
 delete mode 100644 sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/relay/pkt/ICEServerSet.java
 delete mode 100644 sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/relay/pkt/IPacket.java
 delete mode 100644 sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/relay/pkt/IPacket00Handshake.java
 delete mode 100644 sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/relay/pkt/IPacket01ICEServers.java
 delete mode 100644 sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/relay/pkt/IPacket03ICECandidate.java
 delete mode 100644 sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/relay/pkt/IPacket04Description.java
 delete mode 100644 sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/relay/pkt/IPacketFEDisconnectClient.java
 delete mode 100644 sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/relay/pkt/IPacketFFErrorCode.java
 create mode 100644 sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/server/WorldsDB.java
 create mode 100644 sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/server/socket/protocol/ServerV3MessageHandler.java
 create mode 100644 sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/server/socket/protocol/ServerV4MessageHandler.java
 delete mode 100644 sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/server/voice/IntegratedVoiceSignalPackets.java
 create mode 100644 sources/main/java/net/lax1dude/eaglercraft/v1_8/touch_gui/EnumTouchControl.java
 create mode 100644 sources/main/java/net/lax1dude/eaglercraft/v1_8/touch_gui/EnumTouchControlPos.java
 create mode 100644 sources/main/java/net/lax1dude/eaglercraft/v1_8/touch_gui/EnumTouchLayoutState.java
 create mode 100644 sources/main/java/net/lax1dude/eaglercraft/v1_8/touch_gui/TouchControlInput.java
 create mode 100644 sources/main/java/net/lax1dude/eaglercraft/v1_8/touch_gui/TouchControls.java
 create mode 100644 sources/main/java/net/lax1dude/eaglercraft/v1_8/touch_gui/TouchOverlayRenderer.java
 create mode 100644 sources/main/java/net/lax1dude/eaglercraft/v1_8/update/GuiUpdateDownloadSuccess.java
 create mode 100644 sources/main/java/net/lax1dude/eaglercraft/v1_8/update/GuiUpdateInstallOptions.java
 create mode 100644 sources/main/java/net/lax1dude/eaglercraft/v1_8/update/UpdateDataObj.java
 rename sources/main/java/net/lax1dude/eaglercraft/v1_8/{sp/relay/pkt/IPacket06ClientFailure.java => update/UpdateResultObj.java} (53%)
 delete mode 100644 sources/main/java/net/lax1dude/eaglercraft/v1_8/voice/VoiceSignalPackets.java
 create mode 100644 sources/main/java/net/lax1dude/eaglercraft/v1_8/webview/GuiScreenPhishingWaring.java
 create mode 100644 sources/main/java/net/lax1dude/eaglercraft/v1_8/webview/GuiScreenRecieveServerInfo.java
 create mode 100644 sources/main/java/net/lax1dude/eaglercraft/v1_8/webview/GuiScreenServerInfo.java
 create mode 100644 sources/main/java/net/lax1dude/eaglercraft/v1_8/webview/GuiScreenServerInfoDesktop.java
 create mode 100644 sources/main/java/net/lax1dude/eaglercraft/v1_8/webview/PermissionsCache.java
 create mode 100644 sources/main/java/net/lax1dude/eaglercraft/v1_8/webview/ServerInfoCache.java
 create mode 100644 sources/main/java/net/lax1dude/eaglercraft/v1_8/webview/WebViewOverlayController.java
 create mode 100644 sources/main/java/org/json/JSONParserConfiguration.java
 create mode 100644 sources/main/java/org/json/ParserConfiguration.java
 create mode 100644 sources/resources/assets/eagler/audioctx_test_ogg.dat
 create mode 100644 sources/resources/assets/eagler/audioctx_test_wav16.dat
 create mode 100644 sources/resources/assets/eagler/audioctx_test_wav32f.dat
 create mode 100644 sources/resources/assets/eagler/boot_menu/boot_menu_markup.html
 create mode 100644 sources/resources/assets/eagler/boot_menu/boot_menu_style.css
 create mode 100644 sources/resources/assets/eagler/boot_menu/conf_template_eaglercraftX_1_8.json
 create mode 100644 sources/resources/assets/eagler/boot_menu/conf_template_eaglercraftX_1_8_signed.json
 create mode 100644 sources/resources/assets/eagler/boot_menu/conf_template_eaglercraft_1_5.json
 create mode 100644 sources/resources/assets/eagler/boot_menu/conf_template_eaglercraft_1_5_legacy.json
 create mode 100644 sources/resources/assets/eagler/boot_menu/conf_template_eaglercraft_b1_3.json
 create mode 100644 sources/resources/assets/eagler/boot_menu/conf_template_peytonplayz585_a1_2_6.json
 create mode 100644 sources/resources/assets/eagler/boot_menu/conf_template_peytonplayz585_b1_7_3.json
 create mode 100644 sources/resources/assets/eagler/boot_menu/conf_template_peytonplayz585_indev.json
 create mode 100644 sources/resources/assets/eagler/boot_menu/conf_template_standard_offline.json
 create mode 100644 sources/resources/assets/eagler/boot_menu/meta_opts_templates.json
 create mode 100644 sources/resources/assets/eagler/boot_menu/offline_template_eaglercraftX_1_8.html
 create mode 100644 sources/resources/assets/eagler/boot_menu/offline_template_eaglercraftX_1_8_fat_offline.html
 create mode 100644 sources/resources/assets/eagler/boot_menu/offline_template_eaglercraftX_1_8_fat_signed.html
 create mode 100644 sources/resources/assets/eagler/boot_menu/offline_template_eaglercraftX_1_8_signed.html
 create mode 100644 sources/resources/assets/eagler/boot_menu/offline_template_eaglercraft_1_5.html
 create mode 100644 sources/resources/assets/eagler/boot_menu/offline_template_eaglercraft_1_5_legacy.html
 create mode 100644 sources/resources/assets/eagler/boot_menu/offline_template_eaglercraft_b1_3.html
 create mode 100644 sources/resources/assets/eagler/boot_menu/offline_template_peytonplayz585_a_b.html
 create mode 100644 sources/resources/assets/eagler/boot_menu/offline_template_peytonplayz585_indev.html
 create mode 100644 sources/resources/assets/eagler/boot_menu/offline_template_standard_offline.html
 create mode 100644 sources/resources/assets/eagler/boot_menu/opts_template_eaglercraftX_1_8.txt
 create mode 100644 sources/resources/assets/eagler/boot_menu/opts_template_eaglercraftX_1_8_demo.txt
 create mode 100644 sources/resources/assets/eagler/boot_menu/opts_template_eaglercraftX_1_8_html5Cursors.txt
 create mode 100644 sources/resources/assets/eagler/boot_menu/opts_template_eaglercraft_1_5.txt
 create mode 100644 sources/resources/assets/eagler/boot_menu/opts_template_eaglercraft_1_5_legacy.txt
 create mode 100644 sources/resources/assets/eagler/boot_menu/opts_template_eaglercraft_1_5_livestream.txt
 create mode 100644 sources/resources/assets/eagler/boot_menu/opts_template_peytonplayz585_a1_2_6.txt
 create mode 100644 sources/resources/assets/eagler/boot_menu/opts_template_peytonplayz585_b1_7_3.txt
 create mode 100644 sources/resources/assets/eagler/boot_menu/web_cl_eagleiii_8x16.woff
 create mode 100644 sources/resources/assets/eagler/glsl/gles2_compat.glsl
 create mode 100644 sources/resources/assets/eagler/glsl/hw_fingerprint.fsh
 create mode 100644 sources/resources/assets/eagler/gui/notif_bk_large.png
 create mode 100644 sources/resources/assets/eagler/gui/touch_gui.png
 create mode 100644 sources/resources/profanity_filter.wlist
 create mode 100644 sources/setup/workspace_template/desktopRuntime/RTWebViewClient.html
 rename sources/setup/workspace_template/desktopRuntime/{libGLESv2.so => libGLESv2.so.2} (100%)
 create mode 100644 sources/setup/workspace_template/javascript/ES6ShimScript.txt
 create mode 100644 sources/teavm-boot-menu/java/net/lax1dude/eaglercraft/v1_8/boot_menu/teavm/BootMenuAssets.java
 create mode 100644 sources/teavm-boot-menu/java/net/lax1dude/eaglercraft/v1_8/boot_menu/teavm/BootMenuConstants.java
 create mode 100644 sources/teavm-boot-menu/java/net/lax1dude/eaglercraft/v1_8/boot_menu/teavm/BootMenuDOM.java
 create mode 100644 sources/teavm-boot-menu/java/net/lax1dude/eaglercraft/v1_8/boot_menu/teavm/BootMenuDataManager.java
 create mode 100644 sources/teavm-boot-menu/java/net/lax1dude/eaglercraft/v1_8/boot_menu/teavm/BootMenuDatastore.java
 create mode 100644 sources/teavm-boot-menu/java/net/lax1dude/eaglercraft/v1_8/boot_menu/teavm/BootMenuEntryPoint.java
 create mode 100644 sources/teavm-boot-menu/java/net/lax1dude/eaglercraft/v1_8/boot_menu/teavm/BootMenuFatOfflineLoader.java
 create mode 100644 sources/teavm-boot-menu/java/net/lax1dude/eaglercraft/v1_8/boot_menu/teavm/BootMenuMain.java
 create mode 100644 sources/teavm-boot-menu/java/net/lax1dude/eaglercraft/v1_8/boot_menu/teavm/BootMenuMetadata.java
 create mode 100644 sources/teavm-boot-menu/java/net/lax1dude/eaglercraft/v1_8/boot_menu/teavm/BootableClientEntry.java
 create mode 100644 sources/teavm-boot-menu/java/net/lax1dude/eaglercraft/v1_8/boot_menu/teavm/CheckboxListController.java
 create mode 100644 sources/teavm-boot-menu/java/net/lax1dude/eaglercraft/v1_8/boot_menu/teavm/ClientBootFactory.java
 create mode 100644 sources/teavm-boot-menu/java/net/lax1dude/eaglercraft/v1_8/boot_menu/teavm/ClientDataEntry.java
 create mode 100644 sources/teavm-boot-menu/java/net/lax1dude/eaglercraft/v1_8/boot_menu/teavm/ConfirmationPopupController.java
 create mode 100644 sources/teavm-boot-menu/java/net/lax1dude/eaglercraft/v1_8/boot_menu/teavm/EPKClientFactory.java
 create mode 100644 sources/teavm-boot-menu/java/net/lax1dude/eaglercraft/v1_8/boot_menu/teavm/EPKClientParser.java
 create mode 100644 sources/teavm-boot-menu/java/net/lax1dude/eaglercraft/v1_8/boot_menu/teavm/EPKDataEntry.java
 create mode 100644 sources/teavm-boot-menu/java/net/lax1dude/eaglercraft/v1_8/boot_menu/teavm/EnumClientFormatType.java
 create mode 100644 sources/teavm-boot-menu/java/net/lax1dude/eaglercraft/v1_8/boot_menu/teavm/EnumClientLaunchType.java
 create mode 100644 sources/teavm-boot-menu/java/net/lax1dude/eaglercraft/v1_8/boot_menu/teavm/EnumOfflineParseType.java
 create mode 100644 sources/teavm-boot-menu/java/net/lax1dude/eaglercraft/v1_8/boot_menu/teavm/FatOfflineDownloadFactory.java
 create mode 100644 sources/teavm-boot-menu/java/net/lax1dude/eaglercraft/v1_8/boot_menu/teavm/IBootMenuConfigAdapter.java
 create mode 100644 sources/teavm-boot-menu/java/net/lax1dude/eaglercraft/v1_8/boot_menu/teavm/IProgressMsgCallback.java
 create mode 100644 sources/teavm-boot-menu/java/net/lax1dude/eaglercraft/v1_8/boot_menu/teavm/InputPopupController.java
 create mode 100644 sources/teavm-boot-menu/java/net/lax1dude/eaglercraft/v1_8/boot_menu/teavm/KeyCodes.java
 create mode 100644 sources/teavm-boot-menu/java/net/lax1dude/eaglercraft/v1_8/boot_menu/teavm/LaunchConfigEntry.java
 create mode 100644 sources/teavm-boot-menu/java/net/lax1dude/eaglercraft/v1_8/boot_menu/teavm/MenuPopupStateConfirmation.java
 create mode 100644 sources/teavm-boot-menu/java/net/lax1dude/eaglercraft/v1_8/boot_menu/teavm/MenuPopupStateEditInteger.java
 create mode 100644 sources/teavm-boot-menu/java/net/lax1dude/eaglercraft/v1_8/boot_menu/teavm/MenuPopupStateEditString.java
 create mode 100644 sources/teavm-boot-menu/java/net/lax1dude/eaglercraft/v1_8/boot_menu/teavm/MenuPopupStateFileChooser.java
 create mode 100644 sources/teavm-boot-menu/java/net/lax1dude/eaglercraft/v1_8/boot_menu/teavm/MenuPopupStateLoading.java
 create mode 100644 sources/teavm-boot-menu/java/net/lax1dude/eaglercraft/v1_8/boot_menu/teavm/MenuPopupStateSelection.java
 create mode 100644 sources/teavm-boot-menu/java/net/lax1dude/eaglercraft/v1_8/boot_menu/teavm/MenuState.java
 create mode 100644 sources/teavm-boot-menu/java/net/lax1dude/eaglercraft/v1_8/boot_menu/teavm/MenuStateBoot.java
 create mode 100644 sources/teavm-boot-menu/java/net/lax1dude/eaglercraft/v1_8/boot_menu/teavm/MenuStateClientMultiSelect.java
 create mode 100644 sources/teavm-boot-menu/java/net/lax1dude/eaglercraft/v1_8/boot_menu/teavm/MenuStateEditBootOrder.java
 create mode 100644 sources/teavm-boot-menu/java/net/lax1dude/eaglercraft/v1_8/boot_menu/teavm/MenuStateEditingLaunch.java
 create mode 100644 sources/teavm-boot-menu/java/net/lax1dude/eaglercraft/v1_8/boot_menu/teavm/MenuStateEnterSetup.java
 create mode 100644 sources/teavm-boot-menu/java/net/lax1dude/eaglercraft/v1_8/boot_menu/teavm/MenuStateImportMultiSelect.java
 create mode 100644 sources/teavm-boot-menu/java/net/lax1dude/eaglercraft/v1_8/boot_menu/teavm/MenuStateSelectExportClients.java
 create mode 100644 sources/teavm-boot-menu/java/net/lax1dude/eaglercraft/v1_8/boot_menu/teavm/OfflineDownloadFactory.java
 create mode 100644 sources/teavm-boot-menu/java/net/lax1dude/eaglercraft/v1_8/boot_menu/teavm/OfflineDownloadParser.java
 create mode 100644 sources/teavm-boot-menu/java/net/lax1dude/eaglercraft/v1_8/boot_menu/teavm/RelayRandomizeHelper.java
 create mode 100644 sources/teavm-boot-menu/java/net/lax1dude/eaglercraft/v1_8/boot_menu/teavm/SelectionListController.java
 create mode 100644 sources/teavm-boot-menu/java/net/lax1dude/eaglercraft/v1_8/boot_menu/teavm/SignatureCheckHelper.java
 create mode 100644 sources/teavm-boot-menu/java/net/lax1dude/eaglercraft/v1_8/boot_menu/teavm/SignedClientInstaller.java
 create mode 100644 sources/teavm-boot-menu/java/net/lax1dude/eaglercraft/v1_8/boot_menu/teavm/TemplateLoader.java
 create mode 100644 sources/teavm-boot-menu/java/net/lax1dude/eaglercraft/v1_8/boot_menu/teavm/TemplateParser.java
 create mode 100644 sources/teavm-boot-menu/java/net/lax1dude/eaglercraft/v1_8/boot_menu/teavm/UnsignedBootException.java
 create mode 100644 sources/teavm/java/com/jcraft/jogg/Buffer.java
 create mode 100644 sources/teavm/java/com/jcraft/jogg/Packet.java
 create mode 100644 sources/teavm/java/com/jcraft/jogg/Page.java
 create mode 100644 sources/teavm/java/com/jcraft/jogg/StreamState.java
 create mode 100644 sources/teavm/java/com/jcraft/jogg/SyncState.java
 create mode 100644 sources/teavm/java/com/jcraft/jorbis/Block.java
 create mode 100644 sources/teavm/java/com/jcraft/jorbis/CodeBook.java
 create mode 100644 sources/teavm/java/com/jcraft/jorbis/Comment.java
 create mode 100644 sources/teavm/java/com/jcraft/jorbis/Drft.java
 create mode 100644 sources/teavm/java/com/jcraft/jorbis/DspState.java
 create mode 100644 sources/teavm/java/com/jcraft/jorbis/Floor0.java
 create mode 100644 sources/teavm/java/com/jcraft/jorbis/Floor1.java
 create mode 100644 sources/teavm/java/com/jcraft/jorbis/FuncFloor.java
 create mode 100644 sources/teavm/java/com/jcraft/jorbis/FuncMapping.java
 create mode 100644 sources/teavm/java/com/jcraft/jorbis/FuncResidue.java
 create mode 100644 sources/teavm/java/com/jcraft/jorbis/FuncTime.java
 create mode 100644 sources/teavm/java/com/jcraft/jorbis/Info.java
 create mode 100644 sources/teavm/java/com/jcraft/jorbis/InfoMode.java
 create mode 100644 sources/teavm/java/com/jcraft/jorbis/JOrbisException.java
 create mode 100644 sources/teavm/java/com/jcraft/jorbis/Lookup.java
 create mode 100644 sources/teavm/java/com/jcraft/jorbis/Lpc.java
 create mode 100644 sources/teavm/java/com/jcraft/jorbis/Lsp.java
 create mode 100644 sources/teavm/java/com/jcraft/jorbis/Mapping0.java
 create mode 100644 sources/teavm/java/com/jcraft/jorbis/Mdct.java
 create mode 100644 sources/teavm/java/com/jcraft/jorbis/PsyInfo.java
 create mode 100644 sources/teavm/java/com/jcraft/jorbis/PsyLook.java
 create mode 100644 sources/teavm/java/com/jcraft/jorbis/Residue0.java
 create mode 100644 sources/teavm/java/com/jcraft/jorbis/Residue1.java
 create mode 100644 sources/teavm/java/com/jcraft/jorbis/Residue2.java
 create mode 100644 sources/teavm/java/com/jcraft/jorbis/StaticCodeBook.java
 create mode 100644 sources/teavm/java/com/jcraft/jorbis/Time0.java
 create mode 100644 sources/teavm/java/com/jcraft/jorbis/Util.java
 create mode 100644 sources/teavm/java/com/jcraft/jorbis/VorbisFile.java
 create mode 100644 sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/PlatformScreenRecord.java
 create mode 100644 sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/PlatformWebView.java
 create mode 100644 sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/teavm/AdvancedHTMLIFrameElement.java
 create mode 100644 sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/teavm/Base64VarIntArray.java
 create mode 100644 sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/teavm/ClassesJSLocator.java
 create mode 100644 sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/teavm/ES6ShimStatus.java
 create mode 100644 sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/teavm/ES6ShimStatusJS.java
 create mode 100644 sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/teavm/EnumES6ShimStatus.java
 create mode 100644 sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/teavm/EnumES6Shims.java
 rename sources/{main/java/net/lax1dude/eaglercraft/v1_8/sp/relay/pkt/IPacket02NewClient.java => teavm/java/net/lax1dude/eaglercraft/v1_8/internal/teavm/IFrameSafetyException.java} (64%)
 create mode 100644 sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/teavm/ImmediateContinue.java
 create mode 100644 sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/teavm/IndexedDBFilesystem.java
 create mode 100644 sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/teavm/InputEvent.java
 create mode 100644 sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/teavm/JOrbisAudioBufferDecoder.java
 create mode 100644 sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/teavm/LegacyKeycodeTranslator.java
 create mode 100644 sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/teavm/MessageChannel.java
 create mode 100644 sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/teavm/OffsetTouch.java
 create mode 100644 sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/teavm/PCMToWAVLoader.java
 create mode 100644 sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/teavm/SortedTouchEvent.java
 create mode 100644 sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/teavm/TeaVMBlobURLHandle.java
 create mode 100644 sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/teavm/TeaVMBlobURLManager.java
 create mode 100644 sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/teavm/TeaVMDataURLManager.java
 create mode 100644 sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/teavm/TeaVMEnterBootMenuException.java
 create mode 100644 sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/teavm/TeaVMFetchJS.java
 create mode 100644 sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/teavm/TeaVMRuntimeDeobfuscator.java
 create mode 100644 sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/teavm/TeaVMWebSocketClient.java
 create mode 100644 sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/teavm/TeaVMWebSocketFrame.java
 create mode 100644 sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/teavm/Touch.java
 create mode 100644 sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/teavm/TouchEvent.java
 create mode 100644 sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/teavm/TouchList.java
 create mode 100644 sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/teavm/VisualViewport.java
 create mode 100644 sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/teavm/WebGLANGLEInstancedArrays.java
 create mode 100644 sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/teavm/WebGLBackBuffer.java
 create mode 100644 sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/teavm/WebGLOESVertexArrayObject.java
 create mode 100644 sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/teavm/generators/TeaVMRuntimeDeobfuscatorGenerator.java
 create mode 100644 sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/teavm/generators/TeaVMUtilsUnwrapGenerator.java
 create mode 100644 sources/teavm/java/net/lax1dude/eaglercraft/v1_8/sp/server/internal/teavm/SingleThreadWorker.java
 create mode 100644 sources/teavmc-classpath/resources/org/teavm/backend/javascript/long.js

diff --git a/CODE_STANDARDS.md b/CODE_STANDARDS.md
new file mode 100644
index 00000000..7f14d0ed
--- /dev/null
+++ b/CODE_STANDARDS.md
@@ -0,0 +1,306 @@
+# Eaglercraft Code Standards
+
+**These are some basic rules to follow if you would like to write code that is consistent with the Eaglercraft 1.8 codebase. If you are already familiar with Eaglercraft 1.5 or b1.3, please abandon whatever you think is the best practice as a result of reading that code, those clients should be considered as obsolete prototypes.**
+
+## Part A. Coding Style
+
+### 1. Tabs, not spaces
+
+Tabs not spaces, it makes indentation easier to manage and reduces file size. Other popular projects that are also known to use tabs instead of spaces include the linux kernel. We prefer to set tab width to 4 spaces on our editors.
+
+Format code like the eclipse formatter on factory settings
+
+### 2. Avoid redundant hash map lookups
+
+Don't retrieve the same value from a hash map more than once, that includes checking if an entry exists first before retrieving its value. If you do this, you are a horrible person!
+
+**Incorrect:**
+
+```java
+if(hashMap.containsKey("eagler")) {
+    Object val = hashMap.get("eagler");
+    // do something with val
+}
+```
+
+**Correct:**
+
+```java
+Object val = hashMap.get("eagler");
+if(val != null) {
+    // do something with val
+}
+```
+
+### 3. Cache the return value of a function if you plan to use it multiple times
+
+This is somewhat an extension of rule #2, don't repeatedly call the same function multiple times if there's no reason to, even if its a relatively fast function. Everything is slower and less efficient in a browser.
+
+**Incorrect:**
+
+```java
+while(itr.hasNext()) {
+    if(!Minecraft.getMinecraft().getRenderManager().getEntityClassRenderObject(SomeEntity.class).shouldRender(itr.next())) {
+        itr.remove();
+    }
+}
+```
+
+**Correct:**
+
+```java
+Render<SomeEntity> render = Minecraft.getMinecraft().getRenderManager().getEntityClassRenderObject(SomeEntity.class);
+while(itr.hasNext()) {
+    if(!render.shouldRender(itr.next())) {
+        itr.remove();
+    }
+}
+```
+
+### 4. Iterators aren't that great
+
+Avoid using iterators when possible, this includes a `for(Item item : list)` type loop, since this may compile into bytecode that uses an iterator. If the list is a linked list or some other type of data structure that can’t perform random access efficiently, then it is recommended to use an iterator, but if the collection is guaranteed to be something similar to an ArrayList then implement it via a traditional for loop instead.
+
+**Recommended way to iterate an ArrayList:**
+
+```java
+for(int i = 0, l = list.size(); i < l; ++i) {
+    Item item = list.get(i);
+    // do something
+}
+```
+
+### 5. Don't shit on the heap
+
+Avoid creating temporary single-use objects in performance critical code, since the overhead of doing so is larger in a browser where there’s no type safety to predefine object structures. This includes using lambdas or using most of the stuff in the google guava package. Also this is partially why I prefer not using iterators whenever possible.
+
+**Incorrect, creates 5 temporary objects:**
+
+```java
+List<String> list1 = Arrays.asList("eagler", "eagler", "deevis");
+List<String> list2 = Lists.newArrayList(
+    Collections2.transform(
+        Collections2.filter(
+            list1,
+            (e) -> !e.equals("deevis")
+        ),
+        (e) -> (e + "!")
+    )
+);
+```
+
+**Correct, creates no temporary objects:**
+
+```java
+List<String> list1 = Arrays.asList("eagler", "eagler", "deevis");
+List<String> list2 = Lists.newArrayList();
+for(int i = 0, l = list1.size(); i < l; ++i) {
+    String s = list1.get(i);
+    if(!s.equals("deevis")) {
+        list2.add(s + "!");
+    }
+}
+```
+
+(note: we are ignoring the StringBuilder instances that the compiler generates from ` + "!"`)
+
+### 6. Don't base game/render logic off of the system time
+
+Use `EagRuntime.steadyTimeMillis()` instead to access a monotonic clock, as in a clock that is guaranteed to only run forwards, and is not affected by changes in the system time. `System.currentTimeMillis()` should only be used in situations where you want to know the actual wall time or are measuring elapsed time across multiple page refreshes.
+
+### 7. Prefer multiplication over division
+
+If you're always gonna divide a number by some constant, it is better to multiply it by one-over-the-constant instead.
+
+**Incorrect**
+
+```java
+float b = a / 50.0f;
+```
+
+**Correct**
+
+```java
+float b = a * 0.02f;
+```
+
+### 8. Shaders should take advantage of compiler intrinsics
+
+Although you may think these two pieces of code are identical, its more than likely that the "Correct" example will compile to a more efficient shader on almost any hardware. The functions in GLSL are not a library, they are compiler intrinsics that usually compile to inline assembly that can take advantage of different acceleration instructions in the GPU's instruction set. Vector math should be done in ways that promotes the use of SIMD instructions when the code is compiled to a shader.
+
+**Incorrect:**
+
+```glsl
+float dx = pos1.x - pos2.x;
+float dy = pos1.y - pos2.y;
+float dz = pos1.z - pos2.z;
+float distance = sqrt(dx * dx + dy * dy + dz * dz);
+float fogDensity = pow(2.718, -density * distance);
+```
+
+**Correct:**
+
+```glsl
+float fogDensity = exp(-density * length(pos1.xyz - pos2.xyz));
+```
+
+### 9. Flatten the control flow of shaders
+
+Modern GPUs are able to execute multiple instances of a shader on a single core, but if one of those shaders encounters a branch (if statement, or related) that causes it to begin executing different code from the other instances of the shader running on that core, that instance of the shader can no longer be executed at the same time as the other instances, and suddenly you've significantly increased the amount of time this core will now be busy executing shader instructions to account for all of the branches the different shader instances have taken.
+
+**Incorrect:**
+
+```glsl
+float lightValue = dot(lightDirection, normal);
+if(lightValue > 0.0) {
+    color += lightValue * lightColor * diffuseColor;
+}
+```
+
+**Correct:**
+```glsl
+float lightValue = max(dot(lightDirection, normal), 0.0);
+color += lightValue * lightColor * diffuseColor;
+```
+
+### 10. Use textureLod unless mipmapping is necessary
+
+This will prevent the shader from wasting time trying to determine what mipmap levels to read from when the texture is sampled.
+
+**Incorrect:**
+
+```glsl
+float depthValue = texture(depthBuffer, pos).r;
+```
+
+**Correct:**
+
+```glsl
+float depthValue = textureLod(depthBuffer, pos, 0.0).r;
+```
+
+### 11. Divide complex and branch-intensive shaders into multiple draw calls
+
+You can use a variety of different blending modes to mathematically combine the results of shaders. This is done for the same reason as flattening the control flow, to try and keep instruction pointers in sync by periodically resetting their positions, and also to allow for the driver to multitask better on GPUs with insane numbers of cores. It also allows the shader’s execution to be distributed across multiple frames in the case of something that doesn’t need to update often (like clouds).
+
+
+### 12. Don't abuse `@JSBody` in TeaVM code
+
+TeaVM provides lots of ways of interacting with JavaScript, using `@JSBody` is not the only way, consider using an overlay type.
+
+**Incorrect**
+
+```java
+@JSObject(params = { "obj" }, script = "return obj.valueA;")
+public static native JSObject getValueA(JSObject obj);
+
+@JSObject(params = { "obj" }, script = "return obj.valueB;")
+public static native JSObject getValueB(JSObject obj);
+
+@JSObject(params = { "obj" }, script = "return obj.valueC;")
+public static native JSObject getValueC(JSObject obj);
+
+@JSObject(params = { "obj" }, script = "obj.dumbFunction();")
+public static native void callDumbFunction(JSObject obj);
+```
+
+**Correct**
+
+```java
+public interface MyObject extends JSObject {
+
+    @JSProperty
+    JSObject getValueA();
+
+    @JSProperty
+    JSObject getValueB();
+
+    @JSProperty
+    JSObject getValueC();
+
+    void dumbFunction();
+
+}
+```
+
+### 13. Don't fall for TeaVM's threads
+
+It is impossible to have multithreading in JavaScript, only worker objects can be used to execute code concurrently, which can't share javascript variables. Therefore, when you create a thread in TeaVM, you're creating a virtual thread that isn't capable of running at the same time as any other virtual thread in the TeaVM context. This means it's impossible to speed a TeaVM program up through the use of multiple Java threads, instead it is more than likely that it will just slow the program down more to implement multithreading through TeaVM's threads due to the additional time required for synchronization and context switches. Its more efficient to just program the entire application to be single threaded to begin with, just put everything in the main loop and realize that if it was in a different thread it would just periodically interrupt the main loop.
+
+### 14. Always use try-with-resources
+
+For any code that deals with streams to be considered safe, it should either use a try-with-resources or try/finally in order to release resources when complete, since otherwise the stream might not close if an IO error causes the function to return early. This is especially important for plugin code since its supposed to be able to run on a large server for weeks at a time without the underlying JVM being restarted. If hackers discover a bug in the code to cause a function to return early like this without closing a stream, they might exploit it to fatally crash the server by spamming whatever corrupt packet causes the function to leak the stream, so all code must be written so it can fail at any time without leaking resources.
+
+**Incorrect**
+
+```java
+InputStream is = new FileInputStream(new File("phile.txt"));
+is.write(someArray);
+is.close();
+```
+
+**Correct**
+
+```java
+try(InputStream is = new FileInputStream(new File("phile.txt"))) {
+    is.write(someArray);
+}
+```
+
+Notice that the `.close()` can be omitted completely when using a try-with-resources
+
+### 15. Always close compression/decompression streams 
+
+In the desktop runtime, the default oracle JDK uses native code to implement the compression/decompression streams (InflaterInputStream, GZIPInputStream, etc) and therefore if you forget to close the compression/decompression stream it will cause a memory leak when the code isn't running in a browser. This is a common issue when using byte array input/output streams since you might believe when decompressing data from a byte array that there's no reason to close the stream when you're done since its not a file, but that will still cause a memory leak due to the decompression stream not being cleaned up.
+
+## Part B. Project Structure
+
+### 1. Code decompiled from Minecraft goes in `src/game/java`
+
+Don't add any new classes to `src/game/java`, and ideally any significant additions to the game's source (functions, etc) should be done through creating new classes in `src/main/java` instead of adding it directly to the decompiled classes.
+
+### 2. Do not put platform-dependent code in `src/main/java` or `src/game/java`
+
+One of the objectives of Eaglercraft is to make Minecraft Java edition truly cross platform, why stop at just a desktop and JavaScript runtime? There are plans to create an Android runtime and several WebAssembly runtimes, all of which will be compatible with any pre-existing eaglercraft clients that only depend on the EaglercraftX runtime library and don't directly depend on components of TeaVM or LWJGL. Ideally, all core features of the client should be implemented in the `src/main/java` and `src/game/java` and any platform-dependent features should be stubbed out in some abstract platform-independent way in classes in the `src/teavm/java` and `src/lwjgl/java` and any other future runtime you want your client to support. Ideally, every source folder of platform-dependent code should expose an identical API for access to the platform-independent code as all the other platform-dependant code folders currently expose.
+
+### 3. Don't mix JavaScript with Java
+
+Don’t implement features in the JavaScript runtime by requiring additional JavaScript files be included on index.html, if you must access browser APIs then use the TeaVM JSO to write your code in Java instead so it’s baked directly into classes.js. Certain browser APIs may be missing from the default TeaVM JSO-APIs library but it is not difficult to create the overlay types for them manually. Clients that violate this rule may also not possible to automatically import into the EaglercraftX boot menu depending on how fucked up they are. There aren't any limitations to the TeaVM JSO that give you a good enough excuse not to follow this rule.
+
+### 4. Don't access the classes named "Platform\*" directly from your platform-independent code
+
+Much like the Java runtime environment itself, Eaglercraft's runtime library consists of two layers, the internal classes full of platform-dependent code that expose an intermediate API not meant to be used by programmers directly, and the platform-independent API classes that provide a platform-independent wrapper for the platform dependent classes and also provide all the miscellaneous utility functions that don't require platform dependent code to be implemented. Chances are if you are directly using a function on a class that has a name that starts with "Platform\*", that there is a different class in `src/main/java` that you are meant to use in order to access that feature, that may perform additional checks or adjust the values you are passing to the function before calling the function in the Platform class.
+
+## Part C. Compatibility Standards
+
+### 1. Target minimum JDK version is Java 8
+
+Its difficult to find a platform where its not possible to run Java 8 in some capacity, therefore the desktop runtime of EaglercraftX and the BungeeCord plugin should target Java 8. The Velocity plugin is an exception since Velocity itself doesn't support Java 8 either.
+
+### 2. Target minimum supported browser is Google Chrome 38
+
+Released on October 7, 2014, we think its a good target for the JavaScript versions of EaglercraftX. This is the last version of Chrome that supports hardware accelerated WebGL 1.0 on Windows XP. All base features of the underlying Minecraft 1.8 client must be functional, however things such as EaglercraftX's shaders or dynamic lighting are not required to work. The client cannot crash as a result of any missing features on an old browser, you must either implement fallbacks or safely disable the unsupported features.
+
+### 3. Target minimum supported graphics API is OpenGL ES 2.0 (WebGL 1.0)
+
+The most widely supported graphics API in the world is currently OpenGL ES 2.0, so ideally that should be the target for EaglercraftX 1.8. We can guarantee the client will be on an OpenGL ES 3.0 context 99% of the time, however its not that hard to also maintain support for GLES 2.0 (WebGL 1.0) as well with slightly reduced functionality so we might as well make it a feature in case of the 1% of the time that functionality is not available. The client cannot depend on any GL extensions in order to run in GLES 2.0 mode, however its reasonable to assume there will be VAO support via extensions in most GLES 2.0 contexts so the client includes an abstraction layer (via EaglercraftGPU.java) to seamlessly emulate VAO functionality even when the client is running in GLES 2.0 mode with no VAO extensions. The only core feature of Minecraft 1.8 that is completely unavailable in GLES 2.0 mode is mip-mapping for the blocks/items texture atlas due to being unable to limit the max mipmap level.
+
+### 4. Use preprocessor directives to make portable shaders that can be compiled for both OpenGL ES 2.0 and 3.0 contexts
+
+Most of the shaders in the base "glsl" directory of the resources EPK file use a file called "gles2_compat.glsl" to polyfill certain GLSL features (such as input/output declarations) via preprocessor directives to allow them to be compiled on both OpenGL ES 3.0 and 2.0 contexts. This is the preferred way to implement backwards compatibility over creating seprate versions of the same shaders, since future developers don't need to waste time maintaining multiple versions of the same code if they don't really care about backwards compatibility in the first place.
+
+### 5. Target minimum version of the JavaScript syntax is ES5 strict mode
+
+A shim is included to provide certain ES6 functions, however you should always program with syntax compatible with ES5, so the script doesn't crash immediately due to syntax errors even if the functions that use unsupported syntax aren't actually being called. `build.gradle` currently patches out all the ES5 strict mode incompatible syntax in the output of TeaVM 0.9.2, but this will probably break if you try to update TeaVM. Don't worry though because future WASM versions of EaglercraftX will use the latest versions of TeaVM. **Some common incompatible syntax to avoid includes `const`, `let`, `async`, `( ) => `, and using named functions! You can't do any of these things in your JSBody annotations.**
+
+### 6. You cannot depend on any deprecated browser features
+
+The same way we want EaglercraftX to work on browsers from over 10 years ago, we want it to still work in browsers 10 years from today, therefore the client cannot depend on any deprecated browser features in order for all the base Minecraft 1.8 game's features to work properly. However it is okay to use deprecated features as fallback if any modern non-deprecated feature (such as keyboard event handling) that the game needs if the game is running in an old browser.
+
+### 7. Always use addEventListener to register event handlers
+
+Always use addEventListener to register event handlers for browser APIs, never through the use of assigning the legacy "on\*" (onclick, onkeydown, onmessage, etc) variables, the TeaVMUtils class has a universal helper function for accessing addEventListener on any JSO objects that don’t already implement the function.
+
+### 8. JavaScript should be executed in strict mode
+
+Always make sure your JavaScript files start with `"use strict";`, be careful when adding this to your code retroactively because it will probably break hastily written code unless you haven’t made a single typo that’s not forbidden in strict mode. Be aware that in Chrome 38 this means you can't use stuff such as `const` and `let` or named functions in any of your JSBody annotations!
diff --git a/CREDITS b/CREDITS
index 94adfa4c..c1ec6e60 100644
--- a/CREDITS
+++ b/CREDITS
@@ -3,24 +3,26 @@
  ~~~~~~~~~~~~~~~~~~~~~~~
 
  lax1dude:
- 
+
   - Creator of Eaglercraft
   - Ported the Minecraft 1.8 src to TeaVM
   - Wrote HW accelerated OpenGL 1.3 emulator
   - Wrote the default shader pack
   - Made the integrated PBR resource pack
+  - Added touch and mobile device support
   - Wrote all desktop emulation code
   - Wrote EaglercraftXBungee
   - Wrote EaglercraftXVelocity
   - Wrote WebRTC relay server
   - Wrote voice chat server
   - Wrote the patch and build system
- 
+
  ayunami2000:
- 
+
   - Many bug fixes
   - WebRTC LAN worlds
   - WebRTC voice chat
+  - Worked on touch support
   - Made velocity plugin work
   - Added resource packs
   - Added screen recording
@@ -410,7 +412,7 @@
  Project Author: The Legion of the Bouncy Castle
  Project URL: https://www.bouncycastle.org/java.html
  
- Used For: MD5, SHA-1, SHA-256 implementations
+ Used For: MD5, SHA-1, SHA-256, and AES implementations
  
  * Copyright (c) 2000-2021 The Legion of the Bouncy Castle Inc. (https://www.bouncycastle.org)
  *
@@ -668,23 +670,23 @@
  Project Author: ymnk, JCraft Inc.
  Project URL: http://www.jcraft.com/jorbis/
  
- Used For: Audio in desktop runtime
+ Used For: Audio in desktop runtime and browsers that don't support OGG
  
  * JOrbis
  * Copyright (C) 2000 ymnk, JCraft,Inc.
- *  
+ * 
  * Written by: 2000 ymnk<ymnk@jcraft.com>
  *   
  * Many thanks to 
  *   Monty <monty@xiph.org> and 
  *   The XIPHOPHORUS Company http://www.xiph.org/ .
  * JOrbis has been based on their awesome works, Vorbis codec.
- *   
+ * 
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Library General Public License
  * as published by the Free Software Foundation; either version 2 of
  * the License, or (at your option) any later version.
-   
+ * 
  * This program is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
@@ -696,6 +698,44 @@
  
  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  
+ Project Name: NanoHTTPD
+ Project Author: NanoHTTPD 
+ Project URL: http://nanohttpd.org/
+ 
+ Used For: HTTP server in the desktop runtime
+ 
+ * Copyright (c) 2012-2013 by Paul S. Hawke,
+ * 2001,2005-2013 by Jarno Elonen,
+ * 2010 by Konstantinos Togias All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * 
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 
+ * Neither the name of the NanoHttpd organization nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ 
+ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+ 
  Project Name: sqlite-jdbc
  Project Author: Taro L. Saito (xerial)
  Project URL: https://github.com/xerial/sqlite-jdbc
diff --git a/README.md b/README.md
index d8b5a8a2..5fcdc4b9 100644
--- a/README.md
+++ b/README.md
@@ -37,11 +37,13 @@
 5. Type `./CompileLatestClient.sh` and hit enter, a GUI resembling a classic windows installer should open
 6. Follow the steps shown to you in the new window to finish compiling
 
+## Browser Compatibility
+
+EaglercraftX 1.8 is currently known to work on browsers as old as Chrome 38 on Windows XP, the game supports both WebGL 1.0 and WebGL 2.0 however features such as dynamic lighting and PBR shaders require WebGL 2.0. The game also supports mobile browsers that don't have a keyboard or mouse, the game will enter touch screen mode automatically when touch input is detected. The game also includes an embedded OGG codec (JOrbis) for loading audio files on iOS where the browsers don't support loading OGG files in an AudioContext.
+
 ## Singleplayer
 
-As of January 2024, singleplayer and shared worlds have been added to EaglercraftX 1.8.
-
-Worlds are saved to your browser's local storage and are available even if your device does not have an internet connection. You can also import and export worlds in EaglercraftX as EPK files to copy them between devices and send them to your friends.
+EaglercraftX 1.8 fully supports singleplayer mode through an integrated server. Worlds are saved to your browser's local storage and are available even if your device does not have an internet connection. You can also import and export worlds in EaglercraftX as EPK files to copy them between devices and send them to your friends.
 
 You can also import and export your existing vanilla Minecraft 1.8 worlds into EaglercraftX using ZIP files if you want to try playing all your old 1.8 maps in a modern browser. The glitch that caused some chunks to become corrupt when exporting worlds as vanilla in Eaglercraft 1.5.2 no longer happens in EaglercraftX 1.8, its perfect now. Beware that the inventories of LAN world players are not saved when the world is converted to vanilla, and pets (dogs, cats, horses, etc) might sometimes forget their owners due to the UUID changes.
 
@@ -57,7 +59,7 @@ If you would like to host your own relay, the JAR file and instructions can be d
 
 ## PBR Shaders
 
-EaglercraftX 1.8 includes a deferred physically-based renderer modeled after the GTA V rendering engine with many new improvements and a novel raytracing technique for fast realistic reflections. It can be enabled in the "Shaders" menu in the game's options screen. Shader packs in EaglercraftX are just a component of resource packs, so any custom shaders you install will be in the form of a resource pack. EaglercraftX also comes with a very well optimized built-in PBR shader pack and also a built-in PBR material texture pack to give all blocks and items in the game realistic lighting and materials that looks better than most vanilla Minecraft shader packs. The default shader and texture packs were created from scratch by lax1dude, shaders packs made for vanilla Minecraft will not work in EaglercraftX and no shaders in EaglercraftX were taken from vanilla Minecraft shader packs.
+EaglercraftX 1.8 includes a deferred physically-based renderer modeled after the GTA V rendering engine with many new improvements and a novel raytracing technique for fast realistic reflections. It can be enabled in the "Shaders" menu in the game's options screen. Shader packs in EaglercraftX are just a component of resource packs, so any custom shaders you install will be in the form of a resource pack. EaglercraftX also comes with a very well optimized built-in PBR shader pack and also a built-in PBR material texture pack to give all blocks and items in the game realistic lighting and materials that looks better than most vanilla Minecraft shader packs. The default shader and texture packs were created from scratch by lax1dude, shaders packs made for vanilla Minecraft will not work in EaglercraftX and no shaders in EaglercraftX were taken from vanilla Minecraft shader packs. The shaders are not available in WebGL 1.0 mode or if floating point HDR render targets are not fully supported.
 
 ## Voice Chat
 
@@ -75,6 +77,12 @@ To make a server for EaglercraftX 1.8 the recommended software to use is Eaglerc
 
 There is an experimental velocity plugin available in `gateway/EaglercraftXVelocity` but it is still in development and not recommended for public servers, so be sure to check for updates regularly if you use it. Configuration files are basically identical to EaglercraftXBungee so its safe to just directy copy in your old EaglercraftXBungee config files to the `plugins/eaglerxvelocity` folder and they should work with a minimal number of edits if you are migrating your network from BungeeCord to Velocity.
 
+### Detailed READMEs
+
+- [**EaglerXBungee README**](README_EAGLERXBUNGEE.md)
+- [**EaglerXVelocity README**](README_EAGLERXVELOCITY.md)
+- [**EaglerXBukkitAPI README**](README_EAGLERXBUKKITAPI.md)
+
 ### Installation
 
 Obtain the latest version of the EaglerXBungee JAR file (it can be downloaded in the client from the "Multiplayer" screen) and place it in the "plugins" folder of your BungeeCord server. It's recommended to only join native Minecraft 1.8 servers through an EaglerXBungee server but plugins like ProtocolSupport have allowed some people to join newer servers too.
@@ -164,10 +172,35 @@ The default eaglercraftXOpts values is this:
 - `localStorageNamespace:` can be used to change the prefix of the local storage keys (Default: `"_eaglercraftX"`)
 - `enableMinceraft:` can be used to disable the "Minceraft" title screen
 - `crashOnUncaughtExceptions:` display crash reports when `window.onerror` is fired
+- `openDebugConsoleOnLaunch:` open debug console automatically at launch
+- `fixDebugConsoleUnloadListener:` close debug console beforeunload instead of unload
+- `forceWebViewSupport:` if the server info webview should be allowed even on browsers without the required safety features
+- `enableWebViewCSP:` if the `csp` attibute should be set on the server info webview for extra security
+- `enableServerCookies:` can be used to disable server cookies
+- `allowServerRedirects:` if servers should be allowed to make the client reconnect to a different address
+- `autoFixLegacyStyleAttr:` if the viewport meta tag and style attributes on old offline downloads and websites should be automatically patched
+- `showBootMenuOnLaunch:` if the client should always show the boot menu on every launch
+- `bootMenuBlocksUnsignedClients:` if the boot menu should only be allowed to launch signed clients
+- `allowBootMenu:` can be used to disable the boot menu entirely
+- `forceProfanityFilter:` if the profanity filter should be forced enabled
+- `forceWebGL1:` if the game should force the browser to only use WebGL 1.0 for the canvas
+- `forceWebGL2:` if the game should force the browser to only use WebGL 2.0 for the canvas
+- `allowExperimentalWebGL1:` if the game should be allowed to create an `experimental-webgl` context
+- `useWebGLExt:` can be used to disable all OpenGL ES extensions to test the game on a pure WebGL 1.0/2.0 context
+- `useDelayOnSwap:` if the game should `setTimeout(..., 0)` every frame instead of using MessageChannel hacks
+- `useJOrbisAudioDecoder:` if OGG vorbis files should be decoded using the JOrbis Java OGG decoder instead of using the browser
+- `useXHRFetch:` if the game should use XMLHttpRequest for downloading resources instead of the fetch API
+- `useVisualViewport:` if the game should resize some GUIs relative to `window.visualViewport` (needed on mobile browsers when the keyboard is open)
+- `deobfStackTraces:` can be used to disable the runtime stack-trace deobfuscation, reduces micro stutters if the game is logging errors
+- `disableBlobURLs:` if the game should use `data:` URLs instead of `blob:` URLs for loading certain resources
+- `eaglerNoDelay:` can be used to disable "Vigg's Algorithm", an algorithm that delays and combines multiple EaglercraftX packets together if they are sent in the same tick (does not affect regular Minecraft 1.8 packets)
+- `ramdiskMode:` if worlds and resource packs should be stored in RAM instead of IndexedDB
+- `singleThreadMode:` if the game should run the client and integrated server in the same context instead of creating a worker object
 - `hooks:` can be used to define JavaScript callbacks for certain events
-    * `localStorageSaved:` JavaScript callback to save local storage keys
-    * `localStorageLoaded:` JavaScript callback to load local storage keys
-    * `crashReportShow:` JavaScript callback when a crash report is shown
+    * `localStorageSaved:` JavaScript callback to save local storage keys (key, data)
+    * `localStorageLoaded:` JavaScript callback to load local storage keys (key) returns data
+    * `crashReportShow:` JavaScript callback when a crash report is shown (report, customMessageCB)
+    * `screenChanged:` JavaScript callback when the screen changes/resizes (screenName, scaledWidth, scaledHeight, realWidth, realHeight, scaleFactor)
 
 ### Using Hooks
 
diff --git a/buildtools/BuildTools.jar b/buildtools/BuildTools.jar
index fb427642813bf47fbc725d8f1930c606789300a3..dd772284b5c0ea8729f6040cf84ee7af5be61a59 100644
GIT binary patch
delta 37334
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

delta 34472
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
JE`hZ{{6FGWn4bUu

diff --git a/buildtools/production-index-ext.html b/buildtools/production-index-ext.html
index 12d635f1..dc87c4fd 100644
--- a/buildtools/production-index-ext.html
+++ b/buildtools/production-index-ext.html
@@ -1,8 +1,8 @@
 <!DOCTYPE html>
-<html>
+<html style="width:100%;height:100%;background-color:black;">
 	<head>
 		<meta charset="UTF-8" />
-		<meta name="viewport" content="width=device-width, initial-scale=1.0" />
+		<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0" />
 		<meta name="description" content="Play minecraft 1.8 in your browser" />
 		<meta name="keywords" content="eaglercraft, eaglercraftx, minecraft, 1.8, 1.8.8" />
 		<title>EaglercraftX 1.8</title>
@@ -15,8 +15,8 @@
 		<script type="text/javascript" src="classes.js"></script>
 		<script type="text/javascript">
 			"use strict";
-			window.addEventListener("load", () => {
-				if(document.location.href.startsWith("file:")) {
+			window.addEventListener("load", function() {
+				if(window.location.href.indexOf("file:") === 0) {
 					alert("HTTP please, do not open this file locally, run a local HTTP server and load it via HTTP");
 				}else {
 					var opts = window.eaglercraftXOpts;
@@ -31,10 +31,10 @@
 					
 					if(!opts.joinServer)  {
 						var q = window.location.search;
-						if(typeof q === "string" && q.startsWith("?")) {
-							q = new URLSearchParams(q);
+						if((typeof q === "string") && q[0] === "?" && (typeof window.URLSearchParams !== "undefined")) {
+							q = new window.URLSearchParams(q);
 							var s = q.get("server");
-							if(s) opts.joinServer = s;
+							if(s) window.eaglercraftXOpts.joinServer = s;
 						}
 					}
 					
@@ -43,6 +43,6 @@
 			});
 		</script>
 	</head>
-	<body style="margin:0px;width:100vw;height:100vh;overflow:hidden;" id="game_frame">
+	<body style="margin:0px;width:100%;height:100%;overflow:hidden;background-color:black;" id="game_frame">
 	</body>
 </html>
\ No newline at end of file
diff --git a/buildtools/production-index.html b/buildtools/production-index.html
index 9b56f22c..7eeea4f7 100644
--- a/buildtools/production-index.html
+++ b/buildtools/production-index.html
@@ -1,8 +1,8 @@
 <!DOCTYPE html>
-<html>
+<html style="width:100%;height:100%;background-color:black;">
 	<head>
 		<meta charset="UTF-8" />
-		<meta name="viewport" content="width=device-width, initial-scale=1.0" />
+		<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0" />
 		<meta name="description" content="Play minecraft 1.8 in your browser" />
 		<meta name="keywords" content="eaglercraft, eaglercraftx, minecraft, 1.8, 1.8.8" />
 		<title>EaglercraftX 1.8</title>
@@ -15,14 +15,14 @@
 		<script type="text/javascript" src="classes.js"></script>
 		<script type="text/javascript">
 			"use strict";
-			window.addEventListener("load", () => {
-				if(document.location.href.startsWith("file:")) {
+			window.addEventListener("load", function() {
+				if(window.location.href.indexOf("file:") === 0) {
 					alert("HTTP please, do not open this file locally, run a local HTTP server and load it via HTTP");
 				}else {
 					
 					// %%%%%%%%% launch options %%%%%%%%%%%%
 					
-					const relayId = Math.floor(Math.random() * 3);
+					var relayId = Math.floor(Math.random() * 3);
 					window.eaglercraftXOpts = {
 						demoMode: false,
 						container: "game_frame",
@@ -42,8 +42,8 @@
 					// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 					
 					var q = window.location.search;
-					if(typeof q === "string" && q.startsWith("?")) {
-						q = new URLSearchParams(q);
+					if((typeof q === "string") && q[0] === "?" && (typeof window.URLSearchParams !== "undefined")) {
+						q = new window.URLSearchParams(q);
 						var s = q.get("server");
 						if(s) window.eaglercraftXOpts.joinServer = s;
 					}
@@ -54,6 +54,6 @@
 			});
 		</script>
 	</head>
-	<body style="margin:0px;width:100vw;height:100vh;overflow:hidden;" id="game_frame">
+	<body style="margin:0px;width:100%;height:100%;overflow:hidden;background-color:black;" id="game_frame">
 	</body>
 </html>
\ No newline at end of file
diff --git a/buildtools/src/main/java/net/lax1dude/eaglercraft/v1_8/buildtools/gui/CompileLatestClientGUI.java b/buildtools/src/main/java/net/lax1dude/eaglercraft/v1_8/buildtools/gui/CompileLatestClientGUI.java
index 5ddd23bb..499c6d94 100644
--- a/buildtools/src/main/java/net/lax1dude/eaglercraft/v1_8/buildtools/gui/CompileLatestClientGUI.java
+++ b/buildtools/src/main/java/net/lax1dude/eaglercraft/v1_8/buildtools/gui/CompileLatestClientGUI.java
@@ -251,7 +251,11 @@ public class CompileLatestClientGUI {
 			try {
 				compileResultCode = JavaC.runJavaC(new File(minecraftSrcTmp, "minecraft_src_javadoc.jar"),
 						compiledResultClasses, temporaryDirectory, TeaVMBinaries.getTeaVMRuntimeClasspath(),
-					new File(repositoryFolder, "sources/main/java"), new File(repositoryFolder, "sources/teavm/java"));
+						new File(repositoryFolder, "sources/main/java"),
+						new File(repositoryFolder, "sources/protocol-game/java"),
+						new File(repositoryFolder, "sources/protocol-relay/java"),
+						new File(repositoryFolder, "sources/teavm/java"),
+						new File(repositoryFolder, "sources/teavm-boot-menu/java"));
 			}catch(IOException ex) {
 				throw new CompileFailureException("failed to run javac compiler! " + ex.toString(), ex);
 			}
@@ -292,10 +296,12 @@ public class CompileLatestClientGUI {
 		teavmClassPath.addAll(Arrays.asList(TeaVMBinaries.getTeaVMRuntimeClasspath()));
 		teavmArgs.put("classPathEntries", teavmClassPath);
 
+		teavmArgs.put("compileClassPathEntries", Arrays.asList((new File(repositoryFolder, "sources/teavmc-classpath/resources")).getAbsolutePath()));
+
 		teavmArgs.put("entryPointName", "main");
 		teavmArgs.put("mainClass", "net.lax1dude.eaglercraft.v1_8.internal.teavm.MainClass");
 		teavmArgs.put("minifying", true);
-		teavmArgs.put("optimizationLevel", "ADVANCED");
+		teavmArgs.put("optimizationLevel", "FULL");
 		teavmArgs.put("targetDirectory", outputDirectory.getAbsolutePath());
 		teavmArgs.put("generateSourceMaps", true);
 		teavmArgs.put("targetFileName", "classes.js");
@@ -315,6 +321,15 @@ public class CompileLatestClientGUI {
 			frame.finishCompiling(true, "TeaVM reported problems, check the log");
 			return;
 		}
+
+		System.out.println();
+		System.out.println("Patching classes.js with ES6 shim...");
+		
+		File classesJS = new File(outputDirectory, "classes.js");
+		
+		if(!ES6Compat.patchClassesJS(classesJS, new File(repositoryFolder, "sources/setup/workspace_template/javascript/ES6ShimScript.txt"))) {
+			System.err.println("Error: could not inject shim, continuing anyway because it is not required");
+		}
 		
 		File epkCompiler = new File(repositoryFolder, "sources/setup/workspace_template/desktopRuntime/CompileEPK.jar");
 		
@@ -374,8 +389,7 @@ public class CompileLatestClientGUI {
 			File offlineDownloadGenerator = new File(repositoryFolder, "sources/setup/workspace_template/desktopRuntime/MakeOfflineDownload.jar");
 			MakeOfflineDownload.compilerMain(offlineDownloadGenerator, new String[] {
 					(new File(repositoryFolder, "sources/setup/workspace_template/javascript/OfflineDownloadTemplate.txt")).getAbsolutePath(),
-					(new File(outputDirectory, "classes.js")).getAbsolutePath(),
-					(new File(outputDirectory, "assets.epk")).getAbsolutePath(),
+					classesJS.getAbsolutePath(), (new File(outputDirectory, "assets.epk")).getAbsolutePath(),
 					(new File(outputDirectory, "EaglercraftX_1.8_Offline_en_US.html")).getAbsolutePath(),
 					(new File(outputDirectory, "EaglercraftX_1.8_Offline_International.html")).getAbsolutePath(), 
 					(new File(outputDirectory, "build/languages.epk")).getAbsolutePath()
diff --git a/buildtools/src/main/java/net/lax1dude/eaglercraft/v1_8/buildtools/gui/ES6Compat.java b/buildtools/src/main/java/net/lax1dude/eaglercraft/v1_8/buildtools/gui/ES6Compat.java
new file mode 100644
index 00000000..87847e7b
--- /dev/null
+++ b/buildtools/src/main/java/net/lax1dude/eaglercraft/v1_8/buildtools/gui/ES6Compat.java
@@ -0,0 +1,43 @@
+package net.lax1dude.eaglercraft.v1_8.buildtools.gui;
+
+import java.io.File;
+import java.nio.charset.StandardCharsets;
+
+import org.apache.commons.io.FileUtils;
+
+/**
+ * Copyright (c) 2024 lax1dude. All Rights Reserved.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ * 
+ */
+public class ES6Compat {
+
+	/**
+	 * TODO: remove this when we update TeaVM to 0.10+ (ES6 is impossible)
+	 */
+	public static boolean patchClassesJS(File classesJS, File shimJS) {
+		try {
+			String dest = FileUtils.readFileToString(classesJS, StandardCharsets.UTF_8);
+			int i = dest.substring(0, dest.indexOf("=$rt_globals.Symbol('jsoClass');")).lastIndexOf("let ");
+			dest = dest.substring(0, i) + "var" + dest.substring(i + 3);
+			int j = dest.indexOf("function($rt_globals,$rt_exports){");
+			dest = dest.substring(0, j + 34) + "\n" + FileUtils.readFileToString(shimJS, StandardCharsets.UTF_8) + "\n" + dest.substring(j + 34);
+			FileUtils.writeStringToFile(classesJS, dest, StandardCharsets.UTF_8);
+			return true;
+		}catch(Throwable t) {
+			t.printStackTrace();
+			return false;
+		}
+	}
+
+}
diff --git a/buildtools/src/main/java/net/lax1dude/eaglercraft/v1_8/buildtools/gui/TeaVMBinaries.java b/buildtools/src/main/java/net/lax1dude/eaglercraft/v1_8/buildtools/gui/TeaVMBinaries.java
index 342e1631..0c64c86e 100644
--- a/buildtools/src/main/java/net/lax1dude/eaglercraft/v1_8/buildtools/gui/TeaVMBinaries.java
+++ b/buildtools/src/main/java/net/lax1dude/eaglercraft/v1_8/buildtools/gui/TeaVMBinaries.java
@@ -214,7 +214,7 @@ public class TeaVMBinaries {
 				teavmClasslib.file.getAbsolutePath(), teavmInterop.file.getAbsolutePath(), teavmJSO.file.getAbsolutePath(),
 				teavmJSOApis.file.getAbsolutePath(), teavmJSOImpl.file.getAbsolutePath(),
 				teavmMetaprogrammingAPI.file.getAbsolutePath(), teavmMetaprogrammingImpl.file.getAbsolutePath(),
-				teavmPlatform.file.getAbsolutePath() };
+				teavmPlatform.file.getAbsolutePath(), teavmCore.file.getAbsolutePath() };
 	}
 
 }
diff --git a/buildtools/src/main/java/net/lax1dude/eaglercraft/v1_8/buildtools/gui/headless/CompileLatestClientHeadless.java b/buildtools/src/main/java/net/lax1dude/eaglercraft/v1_8/buildtools/gui/headless/CompileLatestClientHeadless.java
index 25f243d4..60a53ef6 100644
--- a/buildtools/src/main/java/net/lax1dude/eaglercraft/v1_8/buildtools/gui/headless/CompileLatestClientHeadless.java
+++ b/buildtools/src/main/java/net/lax1dude/eaglercraft/v1_8/buildtools/gui/headless/CompileLatestClientHeadless.java
@@ -25,6 +25,7 @@ import org.json.JSONObject;
 import net.lax1dude.eaglercraft.v1_8.buildtools.EaglerBuildTools;
 import net.lax1dude.eaglercraft.v1_8.buildtools.LicensePrompt;
 import net.lax1dude.eaglercraft.v1_8.buildtools.gui.EPKCompiler;
+import net.lax1dude.eaglercraft.v1_8.buildtools.gui.ES6Compat;
 import net.lax1dude.eaglercraft.v1_8.buildtools.gui.JavaC;
 import net.lax1dude.eaglercraft.v1_8.buildtools.gui.MakeOfflineDownload;
 import net.lax1dude.eaglercraft.v1_8.buildtools.gui.TeaVMBinaries;
@@ -60,7 +61,7 @@ public class CompileLatestClientHeadless {
 		
 		System.out.println();
 		System.out.println("Launching client compiler...");
-		System.out.println("Copyright (c) 2022-2023 lax1dude");
+		System.out.println("Copyright (c) 2022-2024 lax1dude");
 		System.out.println();
 		
 		boolean yes = false;
@@ -321,7 +322,11 @@ public class CompileLatestClientHeadless {
 				try {
 					compileResultCode = JavaC.runJavaC(new File(minecraftSrcTmp, "minecraft_src_javadoc.jar"),
 							compiledResultClasses, temporaryDirectory, TeaVMBinaries.getTeaVMRuntimeClasspath(),
-						new File(repositoryFolder, "sources/main/java"), new File(repositoryFolder, "sources/teavm/java"));
+							new File(repositoryFolder, "sources/main/java"),
+							new File(repositoryFolder, "sources/protocol-game/java"),
+							new File(repositoryFolder, "sources/protocol-relay/java"),
+							new File(repositoryFolder, "sources/teavm/java"),
+							new File(repositoryFolder, "sources/teavm-boot-menu/java"));
 				}catch(IOException ex) {
 					throw new CompileFailureException("failed to run javac compiler! " + ex.toString(), ex);
 				}
@@ -362,10 +367,12 @@ public class CompileLatestClientHeadless {
 			teavmClassPath.addAll(Arrays.asList(TeaVMBinaries.getTeaVMRuntimeClasspath()));
 			teavmArgs.put("classPathEntries", teavmClassPath);
 
+			teavmArgs.put("compileClassPathEntries", Arrays.asList((new File(repositoryFolder, "sources/teavmc-classpath/resources")).getAbsolutePath()));
+
 			teavmArgs.put("entryPointName", "main");
 			teavmArgs.put("mainClass", "net.lax1dude.eaglercraft.v1_8.internal.teavm.MainClass");
 			teavmArgs.put("minifying", minifying);
-			teavmArgs.put("optimizationLevel", "ADVANCED");
+			teavmArgs.put("optimizationLevel", "FULL");
 			teavmArgs.put("targetDirectory", outputDirectory.getAbsolutePath());
 			teavmArgs.put("generateSourceMaps", writeSourceMap);
 			teavmArgs.put("targetFileName", "classes.js");
@@ -388,6 +395,15 @@ public class CompileLatestClientHeadless {
 				return;
 			}
 			
+			System.out.println();
+			System.out.println("Patching classes.js with ES6 shim...");
+			
+			File classesJS = new File(outputDirectory, "classes.js");
+			
+			if(!ES6Compat.patchClassesJS(classesJS, new File(repositoryFolder, "sources/setup/workspace_template/javascript/ES6ShimScript.txt"))) {
+				System.err.println("Error: could not inject shim, continuing anyway because it is not required");
+			}
+			
 			File epkCompiler = new File(repositoryFolder, "sources/setup/workspace_template/desktopRuntime/CompileEPK.jar");
 			
 			if(!epkCompiler.exists()) {
@@ -569,8 +585,7 @@ public class CompileLatestClientHeadless {
 				File offlineDownloadGenerator = new File(repositoryFolder, "sources/setup/workspace_template/desktopRuntime/MakeOfflineDownload.jar");
 				MakeOfflineDownload.compilerMain(offlineDownloadGenerator, new String[] {
 						offlineTemplateArg.getAbsolutePath(),
-						(new File(outputDirectory, "classes.js")).getAbsolutePath(),
-						(new File(outputDirectory, "assets.epk")).getAbsolutePath(),
+						classesJS.getAbsolutePath(), (new File(outputDirectory, "assets.epk")).getAbsolutePath(),
 						(new File(outputDirectory, "EaglercraftX_1.8_Offline_en_US.html")).getAbsolutePath(),
 						(new File(outputDirectory, "EaglercraftX_1.8_Offline_International.html")).getAbsolutePath(), 
 						(new File(temporaryDirectory, "languages.epk")).getAbsolutePath()
diff --git a/buildtools/src/main/java/net/lax1dude/eaglercraft/v1_8/buildtools/task/diff/PullRequestTask.java b/buildtools/src/main/java/net/lax1dude/eaglercraft/v1_8/buildtools/task/diff/PullRequestTask.java
index 3d370974..e8833062 100644
--- a/buildtools/src/main/java/net/lax1dude/eaglercraft/v1_8/buildtools/task/diff/PullRequestTask.java
+++ b/buildtools/src/main/java/net/lax1dude/eaglercraft/v1_8/buildtools/task/diff/PullRequestTask.java
@@ -10,6 +10,7 @@ import java.nio.ByteBuffer;
 import java.nio.CharBuffer;
 import java.nio.charset.CharsetDecoder;
 import java.nio.charset.StandardCharsets;
+import java.util.Arrays;
 import java.util.Collection;
 import java.util.HashMap;
 import java.util.HashSet;
@@ -65,13 +66,22 @@ public class PullRequestTask {
 		File originalSourceMainJar = new File(EaglerBuildToolsConfig.getTemporaryDirectory(), "MinecraftSrc/minecraft_src_patch.jar");
 		File minecraftJavadocTmp = new File(EaglerBuildToolsConfig.getTemporaryDirectory(), "MinecraftSrc/minecraft_src_javadoc.jar");
 		File originalSourceMain = new File(EaglerBuildTools.repositoryRoot, "sources/main/java");
+		File originalSourceProtoGame = new File(EaglerBuildTools.repositoryRoot, "sources/protocol-game/java");
+		File originalSourceProtoRelay = new File(EaglerBuildTools.repositoryRoot, "sources/protocol-relay/java");
 		File originalSourceTeaVM = new File(EaglerBuildTools.repositoryRoot, "sources/teavm/java");
+		File originalSourceTeaVMC = new File(EaglerBuildTools.repositoryRoot, "sources/teavmc-classpath/resources");
+		File originalSourceBootMenu = new File(EaglerBuildTools.repositoryRoot, "sources/teavm-boot-menu/java");
 		File originalSourceLWJGL = new File(EaglerBuildTools.repositoryRoot, "sources/lwjgl/java");
 		File originalUnpatchedSourceResourcesJar = new File(EaglerBuildToolsConfig.getTemporaryDirectory(), "MinecraftSrc/minecraft_res.jar");
 		File originalSourceResourcesJar = new File(EaglerBuildToolsConfig.getTemporaryDirectory(), "MinecraftSrc/minecraft_res_patch.jar");
 		File originalSourceResources = new File(EaglerBuildTools.repositoryRoot, "sources/resources");
 		File diffFromMain = new File(EaglerBuildToolsConfig.getWorkspaceDirectory(), "src/main/java");
+		File diffFromGame = new File(EaglerBuildToolsConfig.getWorkspaceDirectory(), "src/game/java");
+		File diffFromProtoGame = new File(EaglerBuildToolsConfig.getWorkspaceDirectory(), "src/protocol-game/java");
+		File diffFromProtoRelay = new File(EaglerBuildToolsConfig.getWorkspaceDirectory(), "src/protocol-relay/java");
 		File diffFromTeaVM = new File(EaglerBuildToolsConfig.getWorkspaceDirectory(), "src/teavm/java");
+		File diffFromBootMenu = new File(EaglerBuildToolsConfig.getWorkspaceDirectory(), "src/teavm-boot-menu/java");
+		File diffFromTeaVMC = new File(EaglerBuildToolsConfig.getWorkspaceDirectory(), "src/teavmc-classpath/resources");
 		File diffFromLWJGL = new File(EaglerBuildToolsConfig.getWorkspaceDirectory(), "src/lwjgl/java");
 		File diffFromResources = new File(EaglerBuildToolsConfig.getWorkspaceDirectory(), "desktopRuntime/resources");
 		File pullRequestTo = new File(EaglerBuildTools.repositoryRoot, "pullrequest");
@@ -111,24 +121,54 @@ public class PullRequestTask {
 		File pullRequestToResources = new File(pullRequestTo, "resources");
 
 		boolean flag = false;
-		int i = copyAllModified(diffFromTeaVM, originalSourceTeaVM);
+		int i = copyAllModified(diffFromMain, originalSourceMain);
+		if(i > 0) {
+			flag = true;
+		}
+		System.out.println("Found " + i + " changed files in /src/main/java/");
+		
+		i = copyAllModified(diffFromProtoGame, originalSourceProtoGame);
+		if(i > 0) {
+			flag = true;
+		}
+		System.out.println("Found " + i + " changed files in /src/protocol-game/java/");
+		
+		i = copyAllModified(diffFromProtoRelay, originalSourceProtoRelay);
+		if(i > 0) {
+			flag = true;
+		}
+		System.out.println("Found " + i + " changed files in /src/protocol-relay/java/");
+		
+		i = copyAllModified(diffFromTeaVM, originalSourceTeaVM);
 		if(i > 0) {
 			flag = true;
 		}
 		System.out.println("Found " + i + " changed files in /src/teavm/java/");
 		
+		i = copyAllModified(diffFromBootMenu, originalSourceBootMenu);
+		if(i > 0) {
+			flag = true;
+		}
+		System.out.println("Found " + i + " changed files in /src/teavm-boot-menu/java/");
+		
+		i = copyAllModified(diffFromTeaVMC, originalSourceTeaVMC);
+		if(i > 0) {
+			flag = true;
+		}
+		System.out.println("Found " + i + " changed files in /src/teavmc-classpath/resources/");
+		
 		i = copyAllModified(diffFromLWJGL, originalSourceLWJGL);
 		if(i > 0) {
 			flag = true;
 		}
 		System.out.println("Found " + i + " changed files in /src/lwjgl/java/");
 		
-		i = createDiffFiles(originalSourceMain, minecraftJavadocTmp, originalUnpatchedSourceMainJar, 
-				originalSourceMainJar, diffFromMain, pullRequestToMain, true);
+		i = createDiffFiles(null, minecraftJavadocTmp, originalUnpatchedSourceMainJar, 
+				originalSourceMainJar, diffFromGame, pullRequestToMain, true);
 		if(i > 0) {
 			flag = true;
 		}
-		System.out.println("Found " + i + " changed files in /src/main/java/");
+		System.out.println("Found " + i + " changed files in /src/game/java/");
 		
 		i = createDiffFiles(originalSourceResources, originalSourceResourcesJar, originalUnpatchedSourceResourcesJar, 
 				null, diffFromResources, pullRequestToResources, false);
@@ -197,9 +237,9 @@ public class PullRequestTask {
 			if(newPath.startsWith("/")) {
 				newPath = newPath.substring(1);
 			}
-			File orig = new File(folderOriginal, newPath);
+			File orig = folderOriginal != null ? new File(folderOriginal, newPath) : null;
 			byte[] jarData = null;
-			boolean replacedFileExists = orig.exists();
+			boolean replacedFileExists = orig != null && orig.exists();
 			if(replacedFileExists) {
 				filesReplaced.add(newPath);
 				if(copyFileIfChanged(wf, orig)) {
@@ -253,9 +293,13 @@ public class PullRequestTask {
 					++cnt;
 				}
 			}else {
-				filesReplaced.add(newPath);
-				FileUtils.copyFile(wf, orig);
-				++cnt;
+				if(folderOriginal == null) {
+					System.err.println("Detected a new file in src/game/java, it will be ignored! Do not created new files! (" + newPath + ")");
+				}else {
+					filesReplaced.add(newPath);
+					FileUtils.copyFile(wf, orig);
+					++cnt;
+				}
 			}
 		}
 		
@@ -278,6 +322,10 @@ public class PullRequestTask {
 			}
 		}
 		
+		if(folderOriginal != null) {
+			cnt += removeAllDeleted(folderEdited, folderOriginal);
+		}
+		
 		return cnt;
 	}
 	
@@ -344,6 +392,33 @@ public class PullRequestTask {
 				++cnt;
 			}
 		}
+		cnt += removeAllDeleted(inDir, outDir);
+		return cnt;
+	}
+	
+	private static int removeAllDeleted(File inDir, File outDir) throws IOException {
+		if(!inDir.isDirectory()) {
+			return 0;
+		}
+		int cnt = 0;
+		Collection<File> existingFiles = FileUtils.listFiles(outDir, null, true);
+		String existingPrefix = outDir.getAbsolutePath();
+		for(File wf : existingFiles) {
+			String editedPath = wf.getAbsolutePath().replace(existingPrefix, "");
+			if(editedPath.indexOf('\\') != -1) {
+				editedPath = editedPath.replace('\\', '/');
+			}
+			if(editedPath.startsWith("/")) {
+				editedPath = editedPath.substring(1);
+			}
+			File edited = new File(inDir, editedPath);
+			if(!edited.isFile()) {
+				if(!wf.delete()) {
+					throw new IOException("Could not delete file: " + wf.getAbsolutePath());
+				}
+				++cnt;
+			}
+		}
 		return cnt;
 	}
 	
@@ -392,15 +467,6 @@ public class PullRequestTask {
 		return hex32(crc.getValue());
 	}
 	
-	private static boolean checkCRC32(File in1, File in2) throws IOException {
-		CRC32 crc = new CRC32();
-		crc.update(FileUtils.readFileToByteArray(in1));
-		long v1 = crc.getValue();
-		crc.reset();
-		crc.update(FileUtils.readFileToByteArray(in2));
-		return v1 != crc.getValue();
-	}
-	
 	private static boolean copyFileIfChanged(File in1, File in2) throws IOException {
 		if(!in2.exists()) {
 			FileUtils.copyFile(in1, in2);
@@ -409,20 +475,14 @@ public class PullRequestTask {
 		if(in1.lastModified() == in2.lastModified()) {
 			return false;
 		}
-		CRC32 crc = new CRC32();
 		byte[] f1 = FileUtils.readFileToByteArray(in1);
-		crc.update(f1);
-		long v1 = crc.getValue();
-		crc.reset();
 		byte[] f2 = FileUtils.readFileToByteArray(in2);
-		crc.update(f2);
-		if(v1 != crc.getValue()) {
-			//System.out.println("changed: " + in1.getAbsolutePath());
+		if(!Arrays.equals(f1, f2)) {
 			FileUtils.writeByteArrayToFile(in2, f1);
 			return true;
 		}else {
 			return false;
 		}
 	}
-	
+
 }
diff --git a/buildtools/src/main/java/net/lax1dude/eaglercraft/v1_8/buildtools/task/init/SetupWorkspace.java b/buildtools/src/main/java/net/lax1dude/eaglercraft/v1_8/buildtools/task/init/SetupWorkspace.java
index 26492e2f..10fea86f 100644
--- a/buildtools/src/main/java/net/lax1dude/eaglercraft/v1_8/buildtools/task/init/SetupWorkspace.java
+++ b/buildtools/src/main/java/net/lax1dude/eaglercraft/v1_8/buildtools/task/init/SetupWorkspace.java
@@ -122,13 +122,22 @@ public class SetupWorkspace {
 
 		File repoSources = new File("./sources");
 		File repoSourcesSetup = new File(repoSources, "setup/workspace_template");
-		File repoSourcesGame = new File(repoSources, "main/java");
+		File repoSourcesMain = new File(repoSources, "main/java");
 		File repoSourcesTeaVM = new File(repoSources, "teavm/java");
 		File repoSourcesLWJGL = new File(repoSources, "lwjgl/java");
+		File repoSourcesProtoGame = new File(repoSources, "protocol-game/java");
+		File repoSourcesProtoRelay = new File(repoSources, "protocol-relay/java");
+		File repoSourcesBootMenu = new File(repoSources, "teavm-boot-menu/java");
+		File repoSourcesTeavmCRes = new File(repoSources, "teavmc-classpath/resources");
 		File repoSourcesResources = new File(repoSources, "resources");
 		File srcMainJava = new File(workspaceDirectory, "src/main/java");
+		File srcGameJava = new File(workspaceDirectory, "src/game/java");
 		File srcLWJGLJava = new File(workspaceDirectory, "src/lwjgl/java");
 		File srcTeaVMJava = new File(workspaceDirectory, "src/teavm/java");
+		File srcProtoGame = new File(workspaceDirectory, "src/protocol-game/java");
+		File srcProtoRelay = new File(workspaceDirectory, "src/protocol-relay/java");
+		File srcBootMenu = new File(workspaceDirectory, "src/teavm-boot-menu/java");
+		File srcTeavmCRes = new File(workspaceDirectory, "src/teavmc-classpath/resources");
 		File resourcesExtractTo = new File(workspaceDirectory, "desktopRuntime/resources");
 		File mcLanguagesZip = new File(mcTmpDirectory, "minecraft_languages.zip");
 		File mcLanguagesExtractTo = new File(workspaceDirectory, "javascript/lang");
@@ -174,11 +183,55 @@ public class SetupWorkspace {
 		System.out.println("Copying files from \"/sources/main/java/\" to workspace...");
 		
 		try {
-			FileUtils.copyDirectory(repoSourcesGame, srcMainJava);
+			FileUtils.copyDirectory(repoSourcesMain, srcMainJava);
 		}catch(IOException ex) {
 			System.err.println("ERROR: could not copy \"/sources/main/java/\" to \"" + srcMainJava.getAbsolutePath() + "\"!");
 			throw ex;
 		}
+		
+		if(repoSourcesProtoGame.isDirectory()) {
+			System.out.println("Copying files from \"/sources/protocol-game/java/\" to workspace...");
+			
+			try {
+				FileUtils.copyDirectory(repoSourcesProtoGame, srcProtoGame);
+			}catch(IOException ex) {
+				System.err.println("ERROR: could not copy \"/sources/protocol-game/java/\" to \"" + srcProtoGame.getAbsolutePath() + "\"!");
+				throw ex;
+			}
+		}
+
+		if(repoSourcesProtoRelay.isDirectory()) {
+			System.out.println("Copying files from \"/sources/protocol-relay/java/\" to workspace...");
+	
+			try {
+				FileUtils.copyDirectory(repoSourcesProtoRelay, srcProtoRelay);
+			}catch(IOException ex) {
+				System.err.println("ERROR: could not copy \"/sources/protocol-relay/java/\" to \"" + srcProtoRelay.getAbsolutePath() + "\"!");
+				throw ex;
+			}
+		}
+
+		if(repoSourcesTeavmCRes.isDirectory()) {
+			System.out.println("Copying files from \"/sources/teavmc-classpath/resources/\" to workspace...");
+			
+			try {
+				FileUtils.copyDirectory(repoSourcesTeavmCRes, srcTeavmCRes);
+			}catch(IOException ex) {
+				System.err.println("ERROR: could not copy \"/sources/teavmc-classpath/resources/\" to \"" + srcTeavmCRes.getAbsolutePath() + "\"!");
+				throw ex;
+			}
+		}
+
+		if(repoSourcesBootMenu.isDirectory()) {
+			System.out.println("Copying files from \"/sources/teavm-boot-menu/java/\" to workspace...");
+			
+			try {
+				FileUtils.copyDirectory(repoSourcesBootMenu, srcBootMenu);
+			}catch(IOException ex) {
+				System.err.println("ERROR: could not copy \"/sources/teavm-boot-menu/java/\" to \"" + srcBootMenu.getAbsolutePath() + "\"!");
+				throw ex;
+			}
+		}
 
 		if(repoSourcesLWJGL.isDirectory()) {
 			System.out.println("Copying files from \"/sources/lwjgl/java/\" to workspace...");
@@ -255,18 +308,18 @@ public class SetupWorkspace {
 			minecraftResJar = tmpPatchedPatchResOut;
 			
 		}else {
-			System.out.println("Extracting files from \"minecraft_src_javadoc.jar\" to \"/src/main/java/\"...");
+			System.out.println("Extracting files from \"minecraft_src_javadoc.jar\" to \"/src/game/java/\"...");
 		}
 			
 		try {
-			if(!srcMainJava.isDirectory() && !srcMainJava.mkdirs()) {
+			if(!srcGameJava.isDirectory() && !srcGameJava.mkdirs()) {
 				System.err.println("ERROR: Could not create destination directory!");
 				return false;
 			}
-			extractJarTo(minecraftJavadocTmp, srcMainJava);
+			extractJarTo(minecraftJavadocTmp, srcGameJava);
 		}catch(IOException ex) {
 			System.err.println("ERROR: could not extract \"" + minecraftJavadocTmp.getName() + ".jar\" to \"" +
-					srcMainJava.getAbsolutePath() + "\"!");
+					srcGameJava.getAbsolutePath() + "\"!");
 			throw ex;
 		}
 		
@@ -364,8 +417,11 @@ public class SetupWorkspace {
 		dotClasspathFile = dotClasspathFile.replace("${LIBRARY_CLASSPATH}", String.join(System.lineSeparator(), classpathEntries));
 		FileUtils.writeStringToFile(new File(desktopRuntimeProjectDir, ".classpath"), dotClasspathFile, "UTF-8");
 		
-		dotProjectFile = dotProjectFile.replace("${LWJGL_SRC_FOLDER}", bsToS((new File(workspaceDirectory, "src/lwjgl/java")).getAbsolutePath()));
 		dotProjectFile = dotProjectFile.replace("${MAIN_SRC_FOLDER}", bsToS((new File(workspaceDirectory, "src/main/java")).getAbsolutePath()));
+		dotProjectFile = dotProjectFile.replace("${GAME_SRC_FOLDER}", bsToS((new File(workspaceDirectory, "src/game/java")).getAbsolutePath()));
+		dotProjectFile = dotProjectFile.replace("${PROTO_GAME_SRC_FOLDER}", bsToS((new File(workspaceDirectory, "src/protocol-game/java")).getAbsolutePath()));
+		dotProjectFile = dotProjectFile.replace("${PROTO_RELAY_SRC_FOLDER}", bsToS((new File(workspaceDirectory, "src/protocol-relay/java")).getAbsolutePath()));
+		dotProjectFile = dotProjectFile.replace("${LWJGL_SRC_FOLDER}", bsToS((new File(workspaceDirectory, "src/lwjgl/java")).getAbsolutePath()));
 		FileUtils.writeStringToFile(new File(desktopRuntimeProjectDir, ".project"), dotProjectFile, "UTF-8");
 		
 		debugRuntimeLaunchConfig = debugRuntimeLaunchConfig.replace("${MAIN_CLASS_FILE}", mainClassConfFile);
diff --git a/buildtools/src/main/java/net/lax1dude/eaglercraft/v1_8/buildtools/task/teavm/TeaVMBridge.java b/buildtools/src/main/java/net/lax1dude/eaglercraft/v1_8/buildtools/task/teavm/TeaVMBridge.java
index d9a8d4fb..95f7c216 100644
--- a/buildtools/src/main/java/net/lax1dude/eaglercraft/v1_8/buildtools/task/teavm/TeaVMBridge.java
+++ b/buildtools/src/main/java/net/lax1dude/eaglercraft/v1_8/buildtools/task/teavm/TeaVMBridge.java
@@ -7,6 +7,9 @@ import java.lang.reflect.Method;
 import java.net.MalformedURLException;
 import java.net.URL;
 import java.net.URLClassLoader;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
 import java.util.Map;
 
 import net.lax1dude.eaglercraft.v1_8.buildtools.gui.TeaVMBinaries;
@@ -33,6 +36,7 @@ public class TeaVMBridge {
 	/**
 	 * <h3>List of required options:</h3>
 	 * <table>
+	 * <tr><td><b>compileClassPathEntries</b></td><td>-&gt; Additional compiler class path entries</td></tr>
 	 * <tr><td><b>classPathEntries</b></td><td>-&gt; BuildStrategy.setClassPathEntries(List&lt;String&gt;)</td></tr>
 	 * <tr><td><b>entryPointName</b></td><td>-&gt; BuildStrategy.setEntryPointName(String)</td></tr>
 	 * <tr><td><b>mainClass</b></td><td>-&gt; BuildStrategy.setMainClass(String)</td></tr>
@@ -45,14 +49,20 @@ public class TeaVMBridge {
 	 * <br>
 	 */
 	public static boolean compileTeaVM(Map<String, Object> options) throws TeaVMClassLoadException, TeaVMRuntimeException {
-		File[] cp = TeaVMBinaries.getTeaVMCompilerClasspath();
-		URL[] urls = new URL[cp.length];
+		List<File> philes = new ArrayList<>();
+		List<String> things = (List<String>)options.get("compileClassPathEntries");
+		for(int i = 0, l = things.size(); i < l; ++i) {
+			philes.add(new File(things.get(i)));
+		}
+		philes.addAll(Arrays.asList(TeaVMBinaries.getTeaVMCompilerClasspath()));
 		
-		for(int i = 0; i < cp.length; ++i) {
+		URL[] urls = new URL[philes.size()];
+		
+		for(int i = 0; i < urls.length; ++i) {
 			try {
-				urls[i] = cp[i].toURI().toURL();
+				urls[i] = philes.get(i).toURI().toURL();
 			} catch (MalformedURLException e) {
-				throw new TeaVMClassLoadException("Could not resolve URL for: " + cp[i].getAbsolutePath(), e);
+				throw new TeaVMClassLoadException("Could not resolve URL for: " + philes.get(i).getAbsolutePath(), e);
 			}
 		}
 		
diff --git a/client_version b/client_version
index b9b626ab..3b26bf81 100644
--- a/client_version
+++ b/client_version
@@ -1 +1 @@
-u36
\ No newline at end of file
+u37
\ No newline at end of file
diff --git a/patches/minecraft/delete.txt b/patches/minecraft/delete.txt
index aa1178f8..4e6a55a7 100644
--- a/patches/minecraft/delete.txt
+++ b/patches/minecraft/delete.txt
@@ -1,4 +1,4 @@
-# 144 files to delete:
+# 145 files to delete:
 net/minecraft/client/renderer/VertexBufferUploader.java
 net/minecraft/realms/DisconnectedRealmsScreen.java
 net/minecraft/client/stream/Metadata.java
@@ -45,6 +45,7 @@ net/minecraft/network/NettyEncryptingDecoder.java
 net/minecraft/server/integrated/IntegratedPlayerList.java
 net/minecraft/client/renderer/WorldVertexBufferUploader.java
 net/minecraft/network/PingResponseHandler.java
+net/minecraft/profiler/Profiler.java
 net/minecraft/client/stream/NullStream.java
 net/minecraft/network/NetworkSystem.java
 net/minecraft/client/shader/Shader.java
diff --git a/patches/minecraft/net/minecraft/client/LoadingScreenRenderer.edit.java b/patches/minecraft/net/minecraft/client/LoadingScreenRenderer.edit.java
index f2245707..3d8a1639 100644
--- a/patches/minecraft/net/minecraft/client/LoadingScreenRenderer.edit.java
+++ b/patches/minecraft/net/minecraft/client/LoadingScreenRenderer.edit.java
@@ -18,15 +18,14 @@
 
 ~ import net.minecraft.client.resources.I18n;
 
-> DELETE  10  @  10 : 11
+> DELETE  9  @  9 : 11
 
-> DELETE  4  @  4 : 6
+> DELETE  3  @  3 : 6
 
-> CHANGE  22 : 25  @  22 : 32
+> CHANGE  22 : 24  @  22 : 32
 
-~ 			ScaledResolution scaledresolution = new ScaledResolution(this.mc);
-~ 			GlStateManager.ortho(0.0D, scaledresolution.getScaledWidth_double(),
-~ 					scaledresolution.getScaledHeight_double(), 0.0D, 100.0D, 300.0D);
+~ 			GlStateManager.ortho(0.0D, mc.scaledResolution.getScaledWidth_double(),
+~ 					mc.scaledResolution.getScaledHeight_double(), 0.0D, 100.0D, 300.0D);
 
 > INSERT  19 : 37  @  19
 
@@ -49,7 +48,11 @@
 + 	}
 + 
 
-> CHANGE  13 : 14  @  13 : 20
+> CHANGE  9 : 10  @  9 : 10
+
+~ 				ScaledResolution scaledresolution = mc.scaledResolution;
+
+> CHANGE  3 : 4  @  3 : 10
 
 ~ 				GlStateManager.clear(256);
 
@@ -58,6 +61,13 @@
 ~ 				GlStateManager.clear(16640);
 ~ 				GlStateManager.color(1.0f, 1.0f, 1.0f, 1.0f);
 
-> DELETE  44  @  44 : 49
+> CHANGE  41 : 45  @  41 : 47
+
+~ 				if (this.message != null) {
+~ 					this.mc.fontRendererObj.drawStringWithShadow(this.message,
+~ 							(float) ((k - this.mc.fontRendererObj.getStringWidth(this.message)) / 2),
+~ 							(float) (l / 2 - 4 + 8), 16777215);
+
+> DELETE  1  @  1 : 2
 
 > EOF
diff --git a/patches/minecraft/net/minecraft/client/Minecraft.edit.java b/patches/minecraft/net/minecraft/client/Minecraft.edit.java
index b6723cde..1d14e426 100644
--- a/patches/minecraft/net/minecraft/client/Minecraft.edit.java
+++ b/patches/minecraft/net/minecraft/client/Minecraft.edit.java
@@ -10,9 +10,7 @@
 ~ import static net.lax1dude.eaglercraft.v1_8.internal.PlatformOpenGL._wglBindFramebuffer;
 ~ 
 
-> DELETE  2  @  2 : 6
-
-> DELETE  1  @  1 : 2
+> DELETE  2  @  2 : 8
 
 > CHANGE  2 : 3  @  2 : 6
 
@@ -20,15 +18,10 @@
 
 > DELETE  1  @  1 : 4
 
-> CHANGE  1 : 56  @  1 : 4
+> CHANGE  1 : 74  @  1 : 4
 
 ~ 
-~ import net.lax1dude.eaglercraft.v1_8.internal.PlatformInput;
-~ 
-~ import org.apache.commons.lang3.Validate;
-~ 
-~ import com.google.common.collect.Lists;
-~ 
+~ import net.lax1dude.eaglercraft.v1_8.ClientUUIDLoadingCache;
 ~ import net.lax1dude.eaglercraft.v1_8.Display;
 ~ import net.lax1dude.eaglercraft.v1_8.EagRuntime;
 ~ import net.lax1dude.eaglercraft.v1_8.EagUtils;
@@ -37,16 +30,30 @@
 ~ import net.lax1dude.eaglercraft.v1_8.IOUtils;
 ~ import net.lax1dude.eaglercraft.v1_8.Keyboard;
 ~ import net.lax1dude.eaglercraft.v1_8.Mouse;
+~ import net.lax1dude.eaglercraft.v1_8.PauseMenuCustomizeState;
+~ import net.lax1dude.eaglercraft.v1_8.PointerInputAbstraction;
+~ import net.lax1dude.eaglercraft.v1_8.Touch;
+~ import net.lax1dude.eaglercraft.v1_8.cookie.ServerCookieDataStore;
+~ import net.lax1dude.eaglercraft.v1_8.internal.PlatformInput;
+~ 
+~ import org.apache.commons.lang3.Validate;
+~ 
+~ import com.google.common.collect.Lists;
+~ 
 ~ import net.lax1dude.eaglercraft.v1_8.futures.Executors;
 ~ import net.lax1dude.eaglercraft.v1_8.futures.FutureTask;
 ~ import net.lax1dude.eaglercraft.v1_8.futures.ListenableFuture;
 ~ import net.lax1dude.eaglercraft.v1_8.futures.ListenableFutureTask;
 ~ import net.lax1dude.eaglercraft.v1_8.internal.EnumPlatformType;
 ~ import net.lax1dude.eaglercraft.v1_8.internal.PlatformRuntime;
+~ import net.lax1dude.eaglercraft.v1_8.internal.PlatformWebRTC;
 ~ import net.lax1dude.eaglercraft.v1_8.log4j.LogManager;
 ~ import net.lax1dude.eaglercraft.v1_8.log4j.Logger;
 ~ import net.lax1dude.eaglercraft.v1_8.minecraft.EaglerFolderResourcePack;
 ~ import net.lax1dude.eaglercraft.v1_8.minecraft.EaglerFontRenderer;
+~ import net.lax1dude.eaglercraft.v1_8.minecraft.EnumInputEvent;
+~ import net.lax1dude.eaglercraft.v1_8.minecraft.GuiScreenGenericErrorMessage;
+~ import net.lax1dude.eaglercraft.v1_8.notifications.ServerNotificationRenderer;
 ~ import net.lax1dude.eaglercraft.v1_8.opengl.EaglerMeshLoader;
 ~ import net.lax1dude.eaglercraft.v1_8.opengl.EaglercraftGPU;
 ~ import net.lax1dude.eaglercraft.v1_8.opengl.GlStateManager;
@@ -61,6 +68,7 @@
 ~ import net.lax1dude.eaglercraft.v1_8.opengl.ext.deferred.texture.MetalsLUT;
 ~ import net.lax1dude.eaglercraft.v1_8.opengl.ext.deferred.texture.PBRTextureMapUtils;
 ~ import net.lax1dude.eaglercraft.v1_8.opengl.ext.deferred.texture.TemperaturesLUT;
+~ import net.lax1dude.eaglercraft.v1_8.profanity_filter.GuiScreenContentWarning;
 ~ import net.lax1dude.eaglercraft.v1_8.profile.EaglerProfile;
 ~ import net.lax1dude.eaglercraft.v1_8.profile.GuiScreenEditProfile;
 ~ import net.lax1dude.eaglercraft.v1_8.profile.SkinPreviewRenderer;
@@ -74,9 +82,17 @@
 ~ import net.lax1dude.eaglercraft.v1_8.sp.gui.GuiScreenIntegratedServerBusy;
 ~ import net.lax1dude.eaglercraft.v1_8.sp.gui.GuiScreenSingleplayerConnecting;
 ~ import net.lax1dude.eaglercraft.v1_8.sp.lan.LANServerController;
+~ import net.lax1dude.eaglercraft.v1_8.touch_gui.TouchControls;
+~ import net.lax1dude.eaglercraft.v1_8.touch_gui.TouchOverlayRenderer;
+~ import net.lax1dude.eaglercraft.v1_8.update.GuiUpdateDownloadSuccess;
+~ import net.lax1dude.eaglercraft.v1_8.update.GuiUpdateInstallOptions;
 ~ import net.lax1dude.eaglercraft.v1_8.update.RelayUpdateChecker;
+~ import net.lax1dude.eaglercraft.v1_8.update.UpdateDataObj;
+~ import net.lax1dude.eaglercraft.v1_8.update.UpdateResultObj;
+~ import net.lax1dude.eaglercraft.v1_8.update.UpdateService;
 ~ import net.lax1dude.eaglercraft.v1_8.voice.GuiVoiceOverlay;
 ~ import net.lax1dude.eaglercraft.v1_8.voice.VoiceClientController;
+~ import net.lax1dude.eaglercraft.v1_8.webview.WebViewOverlayController;
 
 > DELETE  2  @  2 : 4
 
@@ -114,9 +130,7 @@
 
 > DELETE  8  @  8 : 12
 
-> DELETE  1  @  1 : 3
-
-> DELETE  1  @  1 : 3
+> DELETE  1  @  1 : 6
 
 > INSERT  6 : 9  @  6
 
@@ -124,7 +138,11 @@
 + import net.minecraft.util.ChatStyle;
 + import net.minecraft.util.EnumChatFormatting;
 
-> INSERT  11 : 12  @  11
+> INSERT  7 : 8  @  7
+
++ import net.minecraft.util.MovingObjectPosition.MovingObjectType;
+
+> INSERT  4 : 5  @  4
 
 + import net.minecraft.util.StringTranslate;
 
@@ -140,7 +158,11 @@
 
 ~ 	public static final boolean isRunningOnMac = false;
 
-> DELETE  12  @  12 : 14
+> INSERT  10 : 11  @  10
+
++ 	public float displayDPI;
+
+> DELETE  2  @  2 : 4
 
 > INSERT  11 : 12  @  11
 
@@ -156,11 +178,13 @@
 
 ~ 	private EaglercraftNetworkManager myNetworkManager;
 
-> DELETE  9  @  9 : 11
+> DELETE  1  @  1 : 2
+
+> DELETE  7  @  7 : 9
 
 > CHANGE  4 : 5  @  4 : 7
 
-~ 	private final List<FutureTask<?>> scheduledTasks = new LinkedList();
+~ 	private final List<FutureTask<?>> scheduledTasks = new LinkedList<>();
 
 > INSERT  14 : 18  @  14
 
@@ -169,15 +193,20 @@
 + 	public int bungeeOutdatedMsgTimer = 0;
 + 	private boolean isLANOpen = false;
 
-> INSERT  1 : 9  @  1
+> INSERT  1 : 14  @  1
 
 + 	public SkullCommand eagskullCommand;
 + 
 + 	public GuiVoiceOverlay voiceOverlay;
++ 	public ServerNotificationRenderer notifRenderer;
++ 	public TouchOverlayRenderer touchOverlayRenderer;
 + 
 + 	public float startZoomValue = 18.0f;
 + 	public float adjustedZoomValue = 18.0f;
 + 	public boolean isZoomKey = false;
++ 	private String reconnectURI = null;
++ 	public boolean mouseGrabSupported = false;
++ 	public ScaledResolution scaledResolution = null;
 + 
 
 > CHANGE  2 : 3  @  2 : 5
@@ -192,7 +221,11 @@
 
 ~ 		logger.info("Setting user: " + this.session.getProfile().getName());
 
-> CHANGE  6 : 11  @  6 : 10
+> INSERT  2 : 3  @  2
+
++ 		this.displayDPI = 1.0f;
+
+> CHANGE  4 : 9  @  4 : 8
 
 ~ 		String serverToJoin = EagRuntime.getConfiguration().getServerToJoin();
 ~ 		if (serverToJoin != null) {
@@ -247,16 +280,20 @@
 ~ 		EaglerFolderResourcePack.deleteOldResourcePacks(EaglerFolderResourcePack.SERVER_RESOURCE_PACKS, 604800000L);
 ~ 		this.mcResourcePackRepository = new ResourcePackRepository(this.mcDefaultResourcePack, this.metadataSerializer_,
 
-> DELETE  8  @  8 : 11
+> INSERT  4 : 5  @  4
+
++ 		this.scaledResolution = new ScaledResolution(this);
+
+> DELETE  4  @  4 : 7
 
 > CHANGE  3 : 5  @  3 : 5
 
-~ 		this.fontRendererObj = new EaglerFontRenderer(this.gameSettings,
+~ 		this.fontRendererObj = EaglerFontRenderer.createSupportedFontRenderer(this.gameSettings,
 ~ 				new ResourceLocation("textures/font/ascii.png"), this.renderEngine, false);
 
 > CHANGE  5 : 6  @  5 : 6
 
-~ 		this.standardGalacticFontRenderer = new EaglerFontRenderer(this.gameSettings,
+~ 		this.standardGalacticFontRenderer = EaglerFontRenderer.createSupportedFontRenderer(this.gameSettings,
 
 > INSERT  5 : 12  @  5
 
@@ -284,15 +321,25 @@
 
 + 		SkinPreviewRenderer.initialize();
 
-> INSERT  2 : 14  @  2
+> INSERT  2 : 24  @  2
 
++ 
++ 		this.mouseGrabSupported = Mouse.isMouseGrabSupported();
++ 		PointerInputAbstraction.init(this);
++ 
 + 		this.eagskullCommand = new SkullCommand(this);
 + 		this.voiceOverlay = new GuiVoiceOverlay(this);
-+ 		ScaledResolution voiceRes = new ScaledResolution(this);
-+ 		this.voiceOverlay.setResolution(voiceRes.getScaledWidth(), voiceRes.getScaledHeight());
++ 		this.voiceOverlay.setResolution(scaledResolution.getScaledWidth(), scaledResolution.getScaledHeight());
++ 
++ 		this.notifRenderer = new ServerNotificationRenderer();
++ 		this.notifRenderer.init();
++ 		this.notifRenderer.setResolution(this, scaledResolution.getScaledWidth(), scaledResolution.getScaledHeight(),
++ 				scaledResolution.getScaleFactor());
++ 		this.touchOverlayRenderer = new TouchOverlayRenderer(this);
 + 
 + 		ServerList.initServerList(this);
 + 		EaglerProfile.read();
++ 		ServerCookieDataStore.load();
 + 
 + 		GuiScreen mainMenu = new GuiMainMenu();
 + 		if (isDemo()) {
@@ -303,24 +350,35 @@
 
 ~ 			mainMenu = new GuiConnecting(mainMenu, this, this.serverName, this.serverPort);
 
-> INSERT  2 : 4  @  2
+> INSERT  2 : 10  @  2
 
-+ 		this.displayGuiScreen(new GuiScreenEditProfile(mainMenu));
++ 		mainMenu = new GuiScreenEditProfile(mainMenu);
++ 
++ 		if (!EagRuntime.getConfiguration().isForceProfanityFilter() && !gameSettings.hasShownProfanityFilter) {
++ 			mainMenu = new GuiScreenContentWarning(mainMenu);
++ 		}
++ 
++ 		this.displayGuiScreen(mainMenu);
 + 
 
-> DELETE  3  @  3 : 15
+> DELETE  3  @  3 : 6
 
-> CHANGE  16 : 17  @  16 : 24
+> CHANGE  1 : 7  @  1 : 9
 
-~ 		throw new UnsupportedOperationException("wtf u trying to twitch stream in a browser game?");
+~ 		while (Mouse.next())
+~ 			;
+~ 		while (Keyboard.next())
+~ 			;
+~ 		while (Touch.next())
+~ 			;
 
-> CHANGE  2 : 5  @  2 : 24
+> CHANGE  15 : 18  @  15 : 24
 
 ~ 	private void createDisplay() {
 ~ 		Display.create();
 ~ 		Display.setTitle("Eaglercraft 1.8.8");
 
-> DELETE  2  @  2 : 39
+> DELETE  2  @  2 : 63
 
 > CHANGE  1 : 2  @  1 : 11
 
@@ -363,41 +421,68 @@
 + 		GuiMainMenu.doResourceReloadHack();
 + 
 
-> CHANGE  7 : 10  @  7 : 19
+> CHANGE  7 : 12  @  7 : 19
 
 ~ 	private void updateDisplayMode() {
 ~ 		this.displayWidth = Display.getWidth();
 ~ 		this.displayHeight = Display.getHeight();
+~ 		this.displayDPI = Display.getDPI();
+~ 		this.scaledResolution = new ScaledResolution(this);
 
-> CHANGE  2 : 6  @  2 : 46
+> CHANGE  2 : 6  @  2 : 51
 
 ~ 	private void drawSplashScreen(TextureManager textureManagerInstance) {
 ~ 		Display.update();
 ~ 		updateDisplayMode();
 ~ 		GlStateManager.viewport(0, 0, displayWidth, displayHeight);
 
-> DELETE  2  @  2 : 5
+> CHANGE  2 : 4  @  2 : 4
 
-> CHANGE  16 : 17  @  16 : 17
+~ 		GlStateManager.ortho(0.0D, (double) scaledResolution.getScaledWidth(),
+~ 				(double) scaledResolution.getScaledHeight(), 0.0D, 1000.0D, 3000.0D);
+
+> CHANGE  12 : 13  @  12 : 13
 
 ~ 					new DynamicTexture(ImageData.loadImageFile(inputstream)));
 
-> DELETE  24  @  24 : 26
+> CHANGE  20 : 22  @  20 : 22
+
+~ 		this.func_181536_a((scaledResolution.getScaledWidth() - short1) / 2,
+~ 				(scaledResolution.getScaledHeight() - short2) / 2, 0, 0, short1, short2, 255, 255, 255, 255);
+
+> DELETE  2  @  2 : 4
 
 > DELETE  26  @  26 : 30
 
-> CHANGE  31 : 42  @  31 : 32
+> INSERT  17 : 18  @  17
+
++ 		this.scaledResolution = new ScaledResolution(this);
+
+> CHANGE  2 : 4  @  2 : 6
+
+~ 			((GuiScreen) guiScreenIn).setWorldAndResolution(this, scaledResolution.getScaledWidth(),
+~ 					scaledResolution.getScaledHeight());
+
+> INSERT  5 : 9  @  5
+
++ 		EagRuntime.getConfiguration().getHooks().callScreenChangedHook(
++ 				currentScreen != null ? currentScreen.getClass().getName() : null, scaledResolution.getScaledWidth(),
++ 				scaledResolution.getScaledHeight(), displayWidth, displayHeight, scaledResolution.getScaleFactor());
++ 	}
+
+> INSERT  1 : 9  @  1
+
++ 	public void shutdownIntegratedServer(GuiScreen cont) {
++ 		if (SingleplayerServerController.shutdownEaglercraftServer()
++ 				|| SingleplayerServerController.getStatusState() == IntegratedServerState.WORLD_UNLOADING) {
++ 			displayGuiScreen(new GuiScreenIntegratedServerBusy(cont, "singleplayer.busy.stoppingIntegratedServer",
++ 					"singleplayer.failed.stoppingIntegratedServer", SingleplayerServerController::isReady));
++ 		} else {
++ 			displayGuiScreen(cont);
++ 		}
+
+> CHANGE  2 : 3  @  2 : 3
 
-~ 	public void shutdownIntegratedServer(GuiScreen cont) {
-~ 		if (SingleplayerServerController.shutdownEaglercraftServer()
-~ 				|| SingleplayerServerController.getStatusState() == IntegratedServerState.WORLD_UNLOADING) {
-~ 			displayGuiScreen(new GuiScreenIntegratedServerBusy(cont, "singleplayer.busy.stoppingIntegratedServer",
-~ 					"singleplayer.failed.stoppingIntegratedServer", SingleplayerServerController::isReady));
-~ 		} else {
-~ 			displayGuiScreen(cont);
-~ 		}
-~ 	}
-~ 
 ~ 	public void checkGLError(String message) {
 
 > CHANGE  1 : 2  @  1 : 2
@@ -435,79 +520,77 @@
 
 > DELETE  3  @  3 : 5
 
-> CHANGE  5 : 6  @  5 : 6
+> CHANGE  4 : 5  @  4 : 6
 
 ~ 		if (Display.isCloseRequested()) {
 
-> CHANGE  14 : 15  @  14 : 15
+> INSERT  3 : 6  @  3
+
++ 		PointerInputAbstraction.runGameLoop();
++ 		this.gameSettings.touchscreen = PointerInputAbstraction.isTouchMode();
++ 
+
+> DELETE  8  @  8 : 9
+
+> CHANGE  2 : 3  @  2 : 3
 
 ~ 				Util.func_181617_a((FutureTask) this.scheduledTasks.remove(0), logger);
 
-> CHANGE  7 : 18  @  7 : 8
+> DELETE  3  @  3 : 4
+
+> DELETE  1  @  1 : 2
+
+> CHANGE  1 : 15  @  1 : 2
 
 ~ 		if (this.timer.elapsedTicks > 1) {
-~ 			long watchdog = System.currentTimeMillis();
+~ 			long watchdog = EagRuntime.steadyTimeMillis();
 ~ 			for (int j = 0; j < this.timer.elapsedTicks; ++j) {
 ~ 				this.runTick();
-~ 				long millis = System.currentTimeMillis();
+~ 				if (j < this.timer.elapsedTicks - 1) {
+~ 					PointerInputAbstraction.runGameLoop();
+~ 				}
+~ 				long millis = EagRuntime.steadyTimeMillis();
 ~ 				if (millis - watchdog > 50l) {
 ~ 					watchdog = millis;
-~ 					EagUtils.sleep(0l);
+~ 					EagRuntime.immediateContinue();
 ~ 				}
 ~ 			}
 ~ 		} else if (this.timer.elapsedTicks == 1) {
 
-> DELETE  10  @  10 : 18
+> DELETE  3  @  3 : 4
 
-> CHANGE  1 : 4  @  1 : 5
+> DELETE  2  @  2 : 3
+
+> DELETE  1  @  1 : 11
+
+> CHANGE  1 : 12  @  1 : 7
 
 ~ 		if (!Display.contextLost()) {
-~ 			this.mcProfiler.startSection("EaglercraftGPU_optimize");
 ~ 			EaglercraftGPU.optimize();
-
-> CHANGE  1 : 11  @  1 : 2
-
 ~ 			_wglBindFramebuffer(0x8D40, null);
 ~ 			GlStateManager.viewport(0, 0, this.displayWidth, this.displayHeight);
 ~ 			GlStateManager.clearColor(0.0f, 0.0f, 0.0f, 1.0f);
 ~ 			GlStateManager.pushMatrix();
 ~ 			GlStateManager.clear(16640);
-~ 			this.mcProfiler.startSection("display");
 ~ 			GlStateManager.enableTexture2D();
 ~ 			if (this.thePlayer != null && this.thePlayer.isEntityInsideOpaqueBlock()) {
 ~ 				this.gameSettings.thirdPersonView = 0;
 ~ 			}
 
-> CHANGE  1 : 6  @  1 : 5
+> CHANGE  1 : 3  @  1 : 5
 
-~ 			this.mcProfiler.endSection();
 ~ 			if (!this.skipRenderWorld) {
-~ 				this.mcProfiler.endStartSection("gameRenderer");
 ~ 				this.entityRenderer.func_181560_a(this.timer.renderPartialTicks, i);
-~ 				this.mcProfiler.endSection();
 
-> CHANGE  2 : 18  @  2 : 7
+> CHANGE  2 : 5  @  2 : 7
 
-~ 			this.mcProfiler.endSection();
-~ 			if (this.gameSettings.showDebugInfo && this.gameSettings.showDebugProfilerChart
-~ 					&& !this.gameSettings.hideGUI) {
-~ 				if (!this.mcProfiler.profilingEnabled) {
-~ 					this.mcProfiler.clearProfiling();
-~ 				}
-~ 
-~ 				this.mcProfiler.profilingEnabled = true;
-~ 				this.displayDebugInfo(i1);
-~ 			} else {
-~ 				this.mcProfiler.profilingEnabled = false;
-~ 				this.prevFrameTime = System.nanoTime();
-~ 			}
-~ 
 ~ 			this.guiAchievement.updateAchievementWindow();
+~ 			this.touchOverlayRenderer.render(displayWidth, displayHeight, scaledResolution);
 ~ 			GlStateManager.popMatrix();
 
-> DELETE  2  @  2 : 11
+> DELETE  2  @  2 : 12
 
-> DELETE  2  @  2 : 10
+> DELETE  1  @  1 : 9
 
 > INSERT  1 : 2  @  1
 
@@ -526,93 +609,160 @@
 
 > DELETE  3  @  3 : 7
 
-> INSERT  8 : 9  @  8
+> DELETE  3  @  3 : 4
 
-+ 		Mouse.tickCursorShape();
+> DELETE  1  @  1 : 2
 
-> INSERT  5 : 10  @  5
+> CHANGE  2 : 3  @  2 : 3
 
-+ 		if (Display.isVSyncSupported()) {
-+ 			Display.setVSync(this.gameSettings.enableVsync);
-+ 		} else {
-+ 			this.gameSettings.enableVsync = false;
-+ 		}
+~ 		Mouse.tickCursorShape();
 
-> DELETE  34  @  34 : 52
+> CHANGE  3 : 8  @  3 : 4
 
-> CHANGE  39 : 40  @  39 : 40
+~ 		if (Display.isVSyncSupported()) {
+~ 			Display.setVSync(this.gameSettings.enableVsync);
+~ 		} else {
+~ 			this.gameSettings.enableVsync = false;
+~ 		}
 
-~ 			EaglercraftGPU.glLineWidth(1.0F);
+> DELETE  1  @  1 : 2
 
-> CHANGE  9 : 10  @  9 : 10
+> CHANGE  4 : 7  @  4 : 5
 
-~ 					(double) ((float) j - (float) short1 * 0.6F - 16.0F), 0.0D).color(0, 0, 0, 100).endVertex();
+~ 		float dpiFetch = -1.0f;
+~ 		if (!this.fullscreen
+~ 				&& (Display.wasResized() || (dpiFetch = Math.max(Display.getDPI(), 1.0f)) != this.displayDPI)) {
 
-> CHANGE  1 : 2  @  1 : 2
+> INSERT  2 : 3  @  2
 
-~ 					.color(0, 0, 0, 100).endVertex();
++ 			float f = this.displayDPI;
 
-> CHANGE  1 : 2  @  1 : 2
+> CHANGE  2 : 4  @  2 : 3
 
-~ 					.color(0, 0, 0, 100).endVertex();
+~ 			this.displayDPI = dpiFetch == -1.0f ? Math.max(Display.getDPI(), 1.0f) : dpiFetch;
+~ 			if (this.displayWidth != i || this.displayHeight != j || this.displayDPI != f) {
 
-> CHANGE  1 : 2  @  1 : 2
+> DELETE  22  @  22 : 180
 
-~ 					(double) ((float) j - (float) short1 * 0.6F - 16.0F), 0.0D).color(0, 0, 0, 100).endVertex();
+> CHANGE  5 : 7  @  5 : 6
 
-> DELETE  110  @  110 : 114
+~ 		boolean touch = PointerInputAbstraction.isTouchMode();
+~ 		if (touch || Display.isActive()) {
 
-> CHANGE  108 : 109  @  108 : 148
+> CHANGE  2 : 5  @  2 : 3
+
+~ 				if (!touch && mouseGrabSupported) {
+~ 					this.mouseHelper.grabMouseCursor();
+~ 				}
+
+> CHANGE  10 : 13  @  10 : 11
+
+~ 			if (!PointerInputAbstraction.isTouchMode() && mouseGrabSupported) {
+~ 				this.mouseHelper.ungrabMouseCursor();
+~ 			}
+
+> DELETE  6  @  6 : 10
+
+> CHANGE  55 : 56  @  55 : 56
+
+~ 	public void rightClickMouse() {
+
+> CHANGE  52 : 53  @  52 : 92
 
 ~ 		Display.toggleFullscreen();
 
 > INSERT  5 : 6  @  5
 
-+ 		ScaledResolution scaledresolution = new ScaledResolution(this);
++ 		this.scaledResolution = new ScaledResolution(this);
+
+> CHANGE  1 : 2  @  1 : 3
+
+~ 			this.currentScreen.onResize(this, scaledResolution.getScaledWidth(), scaledResolution.getScaledHeight());
+
+> DELETE  3  @  3 : 5
+
+> CHANGE  1 : 3  @  1 : 5
+
+~ 		if (voiceOverlay != null) {
+~ 			voiceOverlay.setResolution(scaledResolution.getScaledWidth(), scaledResolution.getScaledHeight());
+
+> INSERT  1 : 5  @  1
+
++ 		if (notifRenderer != null) {
++ 			notifRenderer.setResolution(this, scaledResolution.getScaledWidth(), scaledResolution.getScaledHeight(),
++ 					scaledResolution.getScaleFactor());
++ 		}
+
+> INSERT  1 : 4  @  1
+
++ 		EagRuntime.getConfiguration().getHooks().callScreenChangedHook(
++ 				currentScreen != null ? currentScreen.getClass().getName() : null, scaledResolution.getScaledWidth(),
++ 				scaledResolution.getScaledHeight(), displayWidth, displayHeight, scaledResolution.getScaleFactor());
+
+> CHANGE  11 : 50  @  11 : 12
+
+~ 		RateLimitTracker.tick();
+~ 
+~ 		boolean isHostingLAN = LANServerController.isHostingLAN();
+~ 		this.isGamePaused = !isHostingLAN && this.isSingleplayer() && this.theWorld != null && this.thePlayer != null
+~ 				&& this.currentScreen != null && this.currentScreen.doesGuiPauseGame();
+~ 
+~ 		if (isLANOpen && !isHostingLAN) {
+~ 			ingameGUI.getChatGUI().printChatMessage(new ChatComponentTranslation("lanServer.relayDisconnected"));
+~ 		}
+~ 		isLANOpen = isHostingLAN;
+~ 
+~ 		if (wasPaused != isGamePaused) {
+~ 			SingleplayerServerController.setPaused(this.isGamePaused);
+~ 			wasPaused = isGamePaused;
+~ 		}
+~ 
+~ 		PlatformWebRTC.runScheduledTasks();
+~ 		WebViewOverlayController.runTick();
+~ 		SingleplayerServerController.runTick();
+~ 		RelayUpdateChecker.runTick();
+~ 
+~ 		UpdateResultObj update = UpdateService.getUpdateResult();
+~ 		if (update != null) {
+~ 			if (update.isSuccess()) {
+~ 				UpdateDataObj updateSuccess = update.getSuccess();
+~ 				if (EagRuntime.getConfiguration().isAllowBootMenu()) {
+~ 					if (currentScreen == null || (!(currentScreen instanceof GuiUpdateDownloadSuccess)
+~ 							&& !(currentScreen instanceof GuiUpdateInstallOptions))) {
+~ 						displayGuiScreen(new GuiUpdateDownloadSuccess(currentScreen, updateSuccess));
+~ 					}
+~ 				} else {
+~ 					UpdateService.quine(updateSuccess.clientSignature, updateSuccess.clientBundle);
+~ 				}
+~ 			} else {
+~ 				displayGuiScreen(
+~ 						new GuiScreenGenericErrorMessage("updateFailed.title", update.getFailure(), currentScreen));
+~ 			}
+~ 		}
+~ 
+
+> CHANGE  4 : 6  @  4 : 5
+
+~ 		VoiceClientController.tickVoiceClient(this);
+~ 
 
 > DELETE  1  @  1 : 2
 
-> DELETE  4  @  4 : 6
+> CHANGE  4 : 8  @  4 : 5
 
-> CHANGE  1 : 2  @  1 : 7
+~ 		if (this.thePlayer != null && this.thePlayer.sendQueue != null) {
+~ 			this.thePlayer.sendQueue.getEaglerMessageController().flush();
+~ 		}
+~ 
 
-~ 		this.voiceOverlay.setResolution(scaledresolution.getScaledWidth(), scaledresolution.getScaledHeight());
-
-> INSERT  11 : 30  @  11
-
-+ 		RateLimitTracker.tick();
-+ 
-+ 		boolean isHostingLAN = LANServerController.isHostingLAN();
-+ 		this.isGamePaused = !isHostingLAN && this.isSingleplayer() && this.theWorld != null && this.thePlayer != null
-+ 				&& this.currentScreen != null && this.currentScreen.doesGuiPauseGame();
-+ 
-+ 		if (isLANOpen && !isHostingLAN) {
-+ 			ingameGUI.getChatGUI().printChatMessage(new ChatComponentTranslation("lanServer.relayDisconnected"));
-+ 		}
-+ 		isLANOpen = isHostingLAN;
-+ 
-+ 		if (wasPaused != isGamePaused) {
-+ 			SingleplayerServerController.setPaused(this.isGamePaused);
-+ 			wasPaused = isGamePaused;
-+ 		}
-+ 
-+ 		SingleplayerServerController.runTick();
-+ 		RelayUpdateChecker.runTick();
-+ 
-
-> INSERT  5 : 8  @  5
-
-+ 		this.mcProfiler.endStartSection("eaglerVoice");
-+ 		VoiceClientController.tickVoiceClient(this);
-+ 
-
-> INSERT  10 : 11  @  10
+> INSERT  2 : 4  @  2
 
 + 			GlStateManager.viewport(0, 0, displayWidth, displayHeight); // to be safe
++ 			GlStateManager.enableAlpha();
 
 > INSERT  8 : 14  @  8
 
-+ 			if (this.currentScreen == null && this.dontPauseTimer <= 0) {
++ 			if (this.currentScreen == null && this.dontPauseTimer <= 0 && !PointerInputAbstraction.isTouchMode()) {
 + 				if (!Mouse.isMouseGrabbed()) {
 + 					this.setIngameNotInFocus();
 + 					this.displayInGameMenu();
@@ -627,7 +777,17 @@
 + 				--this.dontPauseTimer;
 + 			}
 
-> CHANGE  10 : 11  @  10 : 11
+> INSERT  2 : 9  @  2
+
++ 		String pastedStr;
++ 		while ((pastedStr = Touch.getPastedString()) != null) {
++ 			if (this.currentScreen != null) {
++ 				this.currentScreen.fireInputEvent(EnumInputEvent.CLIPBOARD_PASTE, pastedStr);
++ 			}
++ 		}
++ 
+
+> CHANGE  8 : 9  @  8 : 9
 
 ~ 						return Minecraft.this.currentScreen.getClass().getName();
 
@@ -635,18 +795,114 @@
 
 ~ 							return Minecraft.this.currentScreen.getClass().getName();
 
-> CHANGE  25 : 28  @  25 : 26
+> DELETE  8  @  8 : 9
 
-~ 						if (this.isZoomKey) {
-~ 							this.adjustedZoomValue = MathHelper.clamp_float(adjustedZoomValue - j * 4.0f, 5.0f, 32.0f);
-~ 						} else if (this.thePlayer.isSpectator()) {
+> CHANGE  1 : 39  @  1 : 7
 
-> CHANGE  14 : 16  @  14 : 15
+~ 			boolean touched;
+~ 			boolean moused = false;
+~ 
+~ 			while ((touched = Touch.next()) || (moused = Mouse.next())) {
+~ 				boolean touch = false;
+~ 				if (touched) {
+~ 					PointerInputAbstraction.enterTouchModeHook();
+~ 					boolean mouse = moused;
+~ 					moused = false;
+~ 					int tc = Touch.getEventTouchPointCount();
+~ 					if (tc > 0) {
+~ 						for (int i = 0; i < tc; ++i) {
+~ 							final int uid = Touch.getEventTouchPointUID(i);
+~ 							int x = Touch.getEventTouchX(i);
+~ 							int y = Touch.getEventTouchY(i);
+~ 							switch (Touch.getEventType()) {
+~ 							case TOUCHSTART:
+~ 								if (TouchControls.handleTouchBegin(uid, x, y)) {
+~ 									break;
+~ 								}
+~ 								touch = true;
+~ 								handlePlaceTouchStart();
+~ 								break;
+~ 							case TOUCHEND:
+~ 								if (TouchControls.handleTouchEnd(uid, x, y)) {
+~ 									touch = true;
+~ 									break;
+~ 								}
+~ 								handlePlaceTouchEnd();
+~ 								break;
+~ 							default:
+~ 								break;
+~ 							}
+~ 						}
+~ 						TouchControls.handleInput();
+~ 						if (!touch) {
+~ 							continue;
+~ 						}
 
-~ 						if ((!this.inGameHasFocus || !Mouse.isActuallyGrabbed()) && Mouse.getEventButtonState()) {
+> CHANGE  1 : 4  @  1 : 2
+
+~ 						if (!mouse) {
+~ 							continue;
+~ 						}
+
+> INSERT  3 : 16  @  3
+
++ 				if (!touch) {
++ 					int i = Mouse.getEventButton();
++ 					KeyBinding.setKeyBindState(i - 100, Mouse.getEventButtonState());
++ 					if (Mouse.getEventButtonState()) {
++ 						PointerInputAbstraction.enterMouseModeHook();
++ 						if (this.thePlayer.isSpectator() && i == 2) {
++ 							this.ingameGUI.getSpectatorGui().func_175261_b();
++ 						} else {
++ 							KeyBinding.onTick(i - 100);
++ 						}
++ 					}
++ 				}
++ 
+
+> CHANGE  2 : 17  @  2 : 8
+
+~ 					if (!touch) {
+~ 						int j = Mouse.getEventDWheel();
+~ 						if (j != 0) {
+~ 							if (this.isZoomKey) {
+~ 								this.adjustedZoomValue = MathHelper.clamp_float(adjustedZoomValue - j * 4.0f, 5.0f,
+~ 										32.0f);
+~ 							} else if (this.thePlayer.isSpectator()) {
+~ 								j = j < 0 ? -1 : 1;
+~ 								if (this.ingameGUI.getSpectatorGui().func_175262_a()) {
+~ 									this.ingameGUI.getSpectatorGui().func_175259_b(-j);
+~ 								} else {
+~ 									float f = MathHelper.clamp_float(
+~ 											this.thePlayer.capabilities.getFlySpeed() + (float) j * 0.005F, 0.0F, 0.2F);
+~ 									this.thePlayer.capabilities.setFlySpeed(f);
+~ 								}
+
+> CHANGE  1 : 2  @  1 : 4
+
+~ 								this.thePlayer.inventory.changeCurrentItem(j);
+
+> DELETE  1  @  1 : 3
+
+> CHANGE  4 : 7  @  4 : 5
+
+~ 						if ((!this.inGameHasFocus || !(touch || Mouse.isActuallyGrabbed()))
+~ 								&& (touch || Mouse.getEventButtonState())) {
 ~ 							this.inGameHasFocus = false;
 
-> INSERT  16 : 19  @  16
+> CHANGE  3 : 8  @  3 : 4
+
+~ 						if (touch) {
+~ 							this.currentScreen.handleTouchInput();
+~ 						} else {
+~ 							this.currentScreen.handleMouseInput();
+~ 						}
+
+> CHANGE  8 : 9  @  8 : 9
+
+~ 			processTouchMine();
+
+> INSERT  3 : 6  @  3
 
 + 				if (k == 0x1D && (areKeysLocked() || isFullScreen())) {
 + 					KeyBinding.setKeyBindState(gameSettings.keyBindSprint.getKeyCode(), Keyboard.getEventKeyState());
@@ -681,7 +937,13 @@
 
 + 							GlStateManager.recompileShaders();
 
-> INSERT  71 : 77  @  71
+> CHANGE  28 : 29  @  28 : 40
+
+~ 							togglePerspective();
+
+> DELETE  6  @  6 : 18
+
+> INSERT  13 : 19  @  13
 
 + 			boolean zoomKey = this.gameSettings.keyBindZoomCamera.isKeyDown();
 + 			if (zoomKey != isZoomKey) {
@@ -690,75 +952,251 @@
 + 			}
 + 
 
-> INSERT  92 : 93  @  92
+> INSERT  26 : 28  @  26
+
++ 			boolean miningTouch = isMiningTouch();
++ 			boolean useTouch = thePlayer.getItemShouldUseOnTouchEagler();
+
+> CHANGE  1 : 2  @  1 : 2
+
+~ 				if (!this.gameSettings.keyBindUseItem.isKeyDown() && !miningTouch) {
+
+> INSERT  19 : 28  @  19
+
++ 				if (miningTouch && !wasMiningTouch) {
++ 					if ((objectMouseOver != null && objectMouseOver.typeOfHit == MovingObjectType.ENTITY) || useTouch) {
++ 						this.rightClickMouse();
++ 					} else {
++ 						this.clickMouse();
++ 					}
++ 					wasMiningTouch = true;
++ 				}
++ 
+
+> INSERT  8 : 9  @  8
+
++ 			wasMiningTouch = miningTouch;
+
+> INSERT  6 : 10  @  6
+
++ 			if (miningTouch && useTouch && this.rightClickDelayTimer == 0 && !this.thePlayer.isUsingItem()) {
++ 				this.rightClickMouse();
++ 			}
++ 
+
+> CHANGE  1 : 3  @  1 : 2
+
+~ 					this.currentScreen == null && (this.gameSettings.keyBindAttack.isKeyDown() || miningTouch)
+~ 							&& this.inGameHasFocus && !useTouch);
+
+> DELETE  11  @  11 : 12
+
+> DELETE  4  @  4 : 5
+
+> DELETE  4  @  4 : 5
+
+> INSERT  7 : 8  @  7
 
 + 			this.eagskullCommand.tick();
 
-> INSERT  43 : 87  @  43
+> DELETE  28  @  28 : 29
+
+> DELETE  5  @  5 : 6
+
+> DELETE  4  @  4 : 5
+
+> CHANGE  3 : 46  @  3 : 15
+
+~ 		if (this.theWorld != null) {
+~ 			++joinWorldTickCounter;
+~ 			if (bungeeOutdatedMsgTimer > 0) {
+~ 				if (--bungeeOutdatedMsgTimer == 0 && this.thePlayer.sendQueue != null) {
+~ 					String pluginBrand = this.thePlayer.sendQueue.getNetworkManager().getPluginBrand();
+~ 					String pluginVersion = this.thePlayer.sendQueue.getNetworkManager().getPluginVersion();
+~ 					if (pluginBrand != null && pluginVersion != null
+~ 							&& EaglerXBungeeVersion.isUpdateToPluginAvailable(pluginBrand, pluginVersion)) {
+~ 						String pfx = EnumChatFormatting.GOLD + "[EagX]" + EnumChatFormatting.AQUA;
+~ 						ingameGUI.getChatGUI().printChatMessage(
+~ 								new ChatComponentText(pfx + " ---------------------------------------"));
+~ 						ingameGUI.getChatGUI().printChatMessage(
+~ 								new ChatComponentText(pfx + " This server appears to be using version "
+~ 										+ EnumChatFormatting.YELLOW + pluginVersion));
+~ 						ingameGUI.getChatGUI().printChatMessage(
+~ 								new ChatComponentText(pfx + " of the EaglerXBungee plugin which is outdated"));
+~ 						ingameGUI.getChatGUI().printChatMessage(new ChatComponentText(pfx));
+~ 						ingameGUI.getChatGUI()
+~ 								.printChatMessage(new ChatComponentText(pfx + " If you are the admin update to "
+~ 										+ EnumChatFormatting.YELLOW + EaglerXBungeeVersion.getPluginVersion()
+~ 										+ EnumChatFormatting.AQUA + " or newer"));
+~ 						ingameGUI.getChatGUI().printChatMessage(new ChatComponentText(pfx));
+~ 						ingameGUI.getChatGUI().printChatMessage((new ChatComponentText(pfx + " Click: "))
+~ 								.appendSibling((new ChatComponentText("" + EnumChatFormatting.GREEN
+~ 										+ EnumChatFormatting.UNDERLINE + EaglerXBungeeVersion.getPluginButton()))
+~ 												.setChatStyle((new ChatStyle()).setChatClickEvent(
+~ 														new ClickEvent(ClickEvent.Action.EAGLER_PLUGIN_DOWNLOAD,
+~ 																"plugin_download.zip")))));
+~ 						ingameGUI.getChatGUI().printChatMessage(
+~ 								new ChatComponentText(pfx + " ---------------------------------------"));
+~ 					}
+~ 				}
+~ 			}
+~ 		} else {
+~ 			joinWorldTickCounter = 0;
+~ 			if (currentScreen != null && currentScreen.shouldHangupIntegratedServer()) {
+~ 				if (SingleplayerServerController.hangupEaglercraftServer()) {
+~ 					this.displayGuiScreen(new GuiScreenIntegratedServerBusy(currentScreen,
+~ 							"singleplayer.busy.stoppingIntegratedServer",
+~ 							"singleplayer.failed.stoppingIntegratedServer", SingleplayerServerController::isReady));
+~ 				}
+~ 			}
+~ 			TouchControls.resetSneak();
+
+> CHANGE  2 : 30  @  2 : 4
+
+~ 		if (reconnectURI != null) {
+~ 			String reconURI = reconnectURI;
+~ 			reconnectURI = null;
+~ 			if (EagRuntime.getConfiguration().isAllowServerRedirects()) {
+~ 				boolean enableCookies;
+~ 				boolean msg;
+~ 				if (this.currentServerData != null) {
+~ 					enableCookies = this.currentServerData.enableCookies;
+~ 					msg = false;
+~ 				} else {
+~ 					enableCookies = EagRuntime.getConfiguration().isEnableServerCookies();
+~ 					msg = true;
+~ 				}
+~ 				if (theWorld != null) {
+~ 					theWorld.sendQuittingDisconnectingPacket();
+~ 					loadWorld(null);
+~ 				}
+~ 				logger.info("Recieved SPacketRedirectClientV4EAG, reconnecting to: {}", reconURI);
+~ 				if (msg) {
+~ 					logger.warn("No existing server connection, cookies will default to {}!",
+~ 							enableCookies ? "enabled" : "disabled");
+~ 				}
+~ 				ServerAddress addr = AddressResolver.resolveAddressFromURI(reconURI);
+~ 				this.displayGuiScreen(
+~ 						new GuiConnecting(new GuiMainMenu(), this, addr.getIP(), addr.getPort(), enableCookies));
+~ 			} else {
+~ 				logger.warn("Server redirect blocked: {}", reconURI);
+~ 			}
+
+> CHANGE  2 : 4  @  2 : 13
+
+~ 		this.systemTime = getSystemTime();
+~ 	}
+
+> CHANGE  1 : 4  @  1 : 2
+
+~ 	private long placeTouchStartTime = -1l;
+~ 	private long mineTouchStartTime = -1l;
+~ 	private boolean wasMiningTouch = false;
+
+> CHANGE  1 : 12  @  1 : 5
+
+~ 	private void processTouchMine() {
+~ 		if ((currentScreen == null || currentScreen.allowUserInput)
+~ 				&& PointerInputAbstraction.isTouchingScreenNotButton()) {
+~ 			if (PointerInputAbstraction.isDraggingNotTouching()) {
+~ 				if (mineTouchStartTime != -1l) {
+~ 					long l = EagRuntime.steadyTimeMillis();
+~ 					if ((placeTouchStartTime == -1l || (l - placeTouchStartTime) < 350l)
+~ 							|| (l - mineTouchStartTime) < 350l) {
+~ 						mineTouchStartTime = -1l;
+~ 					}
+~ 				}
+
+> CHANGE  1 : 4  @  1 : 2
+
+~ 				if (mineTouchStartTime == -1l) {
+~ 					mineTouchStartTime = EagRuntime.steadyTimeMillis();
+~ 				}
+
+> INSERT  1 : 5  @  1
 
-+ 		if (this.theWorld != null) {
-+ 			++joinWorldTickCounter;
-+ 			if (bungeeOutdatedMsgTimer > 0) {
-+ 				if (--bungeeOutdatedMsgTimer == 0 && this.thePlayer.sendQueue != null) {
-+ 					String pluginBrand = this.thePlayer.sendQueue.getNetworkManager().getPluginBrand();
-+ 					String pluginVersion = this.thePlayer.sendQueue.getNetworkManager().getPluginVersion();
-+ 					if (pluginBrand != null && pluginVersion != null
-+ 							&& EaglerXBungeeVersion.isUpdateToPluginAvailable(pluginBrand, pluginVersion)) {
-+ 						String pfx = EnumChatFormatting.GOLD + "[EagX]" + EnumChatFormatting.AQUA;
-+ 						ingameGUI.getChatGUI().printChatMessage(
-+ 								new ChatComponentText(pfx + " ---------------------------------------"));
-+ 						ingameGUI.getChatGUI().printChatMessage(
-+ 								new ChatComponentText(pfx + " This server appears to be using version "
-+ 										+ EnumChatFormatting.YELLOW + pluginVersion));
-+ 						ingameGUI.getChatGUI().printChatMessage(
-+ 								new ChatComponentText(pfx + " of the EaglerXBungee plugin which is outdated"));
-+ 						ingameGUI.getChatGUI().printChatMessage(new ChatComponentText(pfx));
-+ 						ingameGUI.getChatGUI()
-+ 								.printChatMessage(new ChatComponentText(pfx + " If you are the admin update to "
-+ 										+ EnumChatFormatting.YELLOW + EaglerXBungeeVersion.getPluginVersion()
-+ 										+ EnumChatFormatting.AQUA + " or newer"));
-+ 						ingameGUI.getChatGUI().printChatMessage(new ChatComponentText(pfx));
-+ 						ingameGUI.getChatGUI().printChatMessage((new ChatComponentText(pfx + " Click: "))
-+ 								.appendSibling((new ChatComponentText("" + EnumChatFormatting.GREEN
-+ 										+ EnumChatFormatting.UNDERLINE + EaglerXBungeeVersion.getPluginButton()))
-+ 												.setChatStyle((new ChatStyle()).setChatClickEvent(
-+ 														new ClickEvent(ClickEvent.Action.EAGLER_PLUGIN_DOWNLOAD,
-+ 																"plugin_download.zip")))));
-+ 						ingameGUI.getChatGUI().printChatMessage(
-+ 								new ChatComponentText(pfx + " ---------------------------------------"));
-+ 					}
-+ 				}
-+ 			}
 + 		} else {
-+ 			joinWorldTickCounter = 0;
-+ 			if (currentScreen != null && currentScreen.shouldHangupIntegratedServer()) {
-+ 				if (SingleplayerServerController.hangupEaglercraftServer()) {
-+ 					this.displayGuiScreen(new GuiScreenIntegratedServerBusy(currentScreen,
-+ 							"singleplayer.busy.stoppingIntegratedServer",
-+ 							"singleplayer.failed.stoppingIntegratedServer", SingleplayerServerController::isReady));
-+ 				}
-+ 			}
++ 			mineTouchStartTime = -1l;
 + 		}
++ 	}
+
+> CHANGE  1 : 23  @  1 : 5
+
+~ 	private boolean isMiningTouch() {
+~ 		if (mineTouchStartTime == -1l)
+~ 			return false;
+~ 		long l = EagRuntime.steadyTimeMillis();
+~ 		return (placeTouchStartTime == -1l || (l - placeTouchStartTime) >= 350l) && (l - mineTouchStartTime) >= 350l;
+~ 	}
+~ 
+~ 	private void handlePlaceTouchStart() {
+~ 		if (placeTouchStartTime == -1l) {
+~ 			placeTouchStartTime = EagRuntime.steadyTimeMillis();
+~ 		}
+~ 	}
+~ 
+~ 	private void handlePlaceTouchEnd() {
+~ 		if (placeTouchStartTime != -1l) {
+~ 			int len = (int) (EagRuntime.steadyTimeMillis() - placeTouchStartTime);
+~ 			if (len < 350l && !PointerInputAbstraction.isDraggingNotTouching()) {
+~ 				if (objectMouseOver != null && objectMouseOver.typeOfHit == MovingObjectType.ENTITY) {
+~ 					clickMouse();
+~ 				} else {
+~ 					rightClickMouse();
+~ 				}
+
+> INSERT  1 : 2  @  1
+
++ 			placeTouchStartTime = -1l;
+
+> INSERT  1 : 2  @  1
+
++ 	}
+
+> CHANGE  1 : 14  @  1 : 8
+
+~ 	public void togglePerspective() {
+~ 		++this.gameSettings.thirdPersonView;
+~ 		if (this.gameSettings.thirdPersonView > 2) {
+~ 			this.gameSettings.thirdPersonView = 0;
+~ 		}
+~ 
+~ 		if (this.gameSettings.thirdPersonView == 0) {
+~ 			this.entityRenderer.loadEntityShader(this.getRenderViewEntity());
+~ 		} else if (this.gameSettings.thirdPersonView == 1) {
+~ 			this.entityRenderer.loadEntityShader((Entity) null);
+~ 		}
+~ 
+~ 		this.renderGlobal.setDisplayListEntitiesDirty();
+
+> INSERT  2 : 20  @  2
+
++ 	public void launchIntegratedServer(String folderName, String worldName, WorldSettings worldSettingsIn) {
++ 		this.loadWorld((WorldClient) null);
++ 		renderManager.setEnableFNAWSkins(this.gameSettings.enableFNAWSkins);
++ 		session.reset();
++ 		EaglerProfile.clearServerSkinOverride();
++ 		PauseMenuCustomizeState.reset();
++ 		SingleplayerServerController.launchEaglercraftServer(folderName, gameSettings.difficulty.getDifficultyId(),
++ 				Math.max(gameSettings.renderDistanceChunks, 2), worldSettingsIn);
++ 		EagRuntime.setMCServerWindowGlobal("singleplayer");
++ 		this.displayGuiScreen(new GuiScreenIntegratedServerBusy(
++ 				new GuiScreenSingleplayerConnecting(new GuiMainMenu(), "Connecting to " + folderName),
++ 				"singleplayer.busy.startingIntegratedServer", "singleplayer.failed.startingIntegratedServer",
++ 				() -> SingleplayerServerController.isWorldReady(), (t, u) -> {
++ 					Minecraft.this.displayGuiScreen(GuiScreenIntegratedServerBusy.createException(new GuiMainMenu(),
++ 							((GuiScreenIntegratedServerBusy) t).failMessage, u));
++ 				}));
++ 	}
 + 
 
-> CHANGE  6 : 18  @  6 : 54
-
-~ 		Minecraft.getMinecraft().getRenderManager().setEnableFNAWSkins(this.gameSettings.enableFNAWSkins);
-~ 		session.reset();
-~ 		SingleplayerServerController.launchEaglercraftServer(folderName, gameSettings.difficulty.getDifficultyId(),
-~ 				Math.max(gameSettings.renderDistanceChunks, 2), worldSettingsIn);
-~ 		EagRuntime.setMCServerWindowGlobal("singleplayer");
-~ 		this.displayGuiScreen(new GuiScreenIntegratedServerBusy(
-~ 				new GuiScreenSingleplayerConnecting(new GuiMainMenu(), "Connecting to " + folderName),
-~ 				"singleplayer.busy.startingIntegratedServer", "singleplayer.failed.startingIntegratedServer",
-~ 				() -> SingleplayerServerController.isWorldReady(), (t, u) -> {
-~ 					Minecraft.this.displayGuiScreen(GuiScreenIntegratedServerBusy.createException(new GuiMainMenu(),
-~ 							((GuiScreenIntegratedServerBusy) t).failMessage, u));
-~ 				}));
-
-> INSERT  12 : 13  @  12
+> INSERT  10 : 15  @  10
 
 + 			session.reset();
++ 			EaglerProfile.clearServerSkinOverride();
++ 			PauseMenuCustomizeState.reset();
++ 			ClientUUIDLoadingCache.flushRequestCache();
++ 			WebViewOverlayController.setPacketSendCallback(null);
 
 > DELETE  1  @  1 : 7
 
@@ -779,7 +1217,11 @@
 ~ 		GameSettings g = theMinecraft.gameSettings;
 ~ 		return g.ambientOcclusion != 0 && !g.shadersAODisable;
 
-> CHANGE  130 : 131  @  130 : 131
+> CHANGE  2 : 3  @  2 : 3
+
+~ 	public void middleClickMouse() {
+
+> CHANGE  127 : 128  @  127 : 128
 
 ~ 				return EagRuntime.getVersion();
 
@@ -801,19 +1243,63 @@
 ~ 				return !Minecraft.this.gameSettings.shaders && Minecraft.this.gameSettings.enableDynamicLights ? "Yes"
 ~ 						: "No";
 
-> INSERT  2 : 7  @  2
+> INSERT  2 : 47  @  2
 
 + 		theCrash.getCategory().addCrashSectionCallable("In Ext. Pipeline", new Callable<String>() {
 + 			public String call() throws Exception {
 + 				return GlStateManager.isExtensionPipeline() ? "Yes" : "No";
 + 			}
 + 		});
++ 		theCrash.getCategory().addCrashSectionCallable("GPU Shader5 Capable", new Callable<String>() {
++ 			public String call() throws Exception {
++ 				return EaglercraftGPU.checkShader5Capable() ? "Yes" : "No";
++ 			}
++ 		});
++ 		theCrash.getCategory().addCrashSectionCallable("GPU TexStorage Capable", new Callable<String>() {
++ 			public String call() throws Exception {
++ 				return EaglercraftGPU.checkTexStorageCapable() ? "Yes" : "No";
++ 			}
++ 		});
++ 		theCrash.getCategory().addCrashSectionCallable("GPU TextureLOD Capable", new Callable<String>() {
++ 			public String call() throws Exception {
++ 				return EaglercraftGPU.checkTextureLODCapable() ? "Yes" : "No";
++ 			}
++ 		});
++ 		theCrash.getCategory().addCrashSectionCallable("GPU Instancing Capable", new Callable<String>() {
++ 			public String call() throws Exception {
++ 				return EaglercraftGPU.checkInstancingCapable() ? "Yes" : "No";
++ 			}
++ 		});
++ 		theCrash.getCategory().addCrashSectionCallable("GPU VAO Capable", new Callable<String>() {
++ 			public String call() throws Exception {
++ 				return EaglercraftGPU.checkVAOCapable() ? "Yes" : "No";
++ 			}
++ 		});
++ 		theCrash.getCategory().addCrashSectionCallable("Is Software VAOs", new Callable<String>() {
++ 			public String call() throws Exception {
++ 				return EaglercraftGPU.areVAOsEmulated() ? "Yes" : "No";
++ 			}
++ 		});
++ 		theCrash.getCategory().addCrashSectionCallable("GPU Render-to-MipMap", new Callable<String>() {
++ 			public String call() throws Exception {
++ 				return EaglercraftGPU.checkFBORenderMipmapCapable() ? "Yes" : "No";
++ 			}
++ 		});
++ 		theCrash.getCategory().addCrashSectionCallable("Touch Mode", new Callable<String>() {
++ 			public String call() throws Exception {
++ 				return PointerInputAbstraction.isTouchMode() ? "Yes" : "No";
++ 			}
++ 		});
 
 > CHANGE  2 : 3  @  2 : 6
 
 ~ 				return "Definitely Not; You're an eagler";
 
-> DELETE  36  @  36 : 41
+> CHANGE  32 : 33  @  32 : 34
+
+~ 				return "N/A (disabled)";
+
+> DELETE  2  @  2 : 7
 
 > CHANGE  12 : 13  @  12 : 13
 
@@ -854,7 +1340,7 @@
 
 > CHANGE  1 : 2  @  1 : 2
 
-~ 		return System.currentTimeMillis();
+~ 		return EagRuntime.steadyTimeMillis();
 
 > CHANGE  3 : 4  @  3 : 4
 
@@ -901,7 +1387,7 @@
 
 > DELETE  26  @  26 : 34
 
-> INSERT  7 : 35  @  7
+> INSERT  7 : 48  @  7
 
 + 
 + 	public static int getGLMaximumTextureSize() {
@@ -927,9 +1413,22 @@
 + 	public boolean getEnableFNAWSkins() {
 + 		boolean ret = this.gameSettings.enableFNAWSkins;
 + 		if (this.thePlayer != null) {
-+ 			ret &= this.thePlayer.sendQueue.currentFNAWSkinAllowedState;
++ 			if (this.thePlayer.sendQueue.currentFNAWSkinForcedState) {
++ 				ret = true;
++ 			} else {
++ 				ret &= this.thePlayer.sendQueue.currentFNAWSkinAllowedState;
++ 			}
 + 		}
 + 		return ret;
 + 	}
++ 
++ 	public void handleReconnectPacket(String redirectURI) {
++ 		this.reconnectURI = redirectURI;
++ 	}
++ 
++ 	public boolean isEnableProfanityFilter() {
++ 		return EagRuntime.getConfiguration().isForceProfanityFilter() || gameSettings.enableProfanityFilter;
++ 	}
++ 
 
 > EOF
diff --git a/patches/minecraft/net/minecraft/client/audio/SoundCategory.edit.java b/patches/minecraft/net/minecraft/client/audio/SoundCategory.edit.java
index 93eaafe8..241cae8b 100644
--- a/patches/minecraft/net/minecraft/client/audio/SoundCategory.edit.java
+++ b/patches/minecraft/net/minecraft/client/audio/SoundCategory.edit.java
@@ -12,11 +12,7 @@
 + import com.google.common.collect.Maps;
 + 
 
-> CHANGE  2 : 3  @  2 : 3
-
-~ 	MOBS("hostile", 5), ANIMALS("neutral", 6), PLAYERS("player", 7), AMBIENT("ambient", 8), VOICE("voice", 9);
-
-> INSERT  1 : 3  @  1
+> INSERT  4 : 6  @  4
 
 + 	public static final SoundCategory[] _VALUES = values();
 + 
diff --git a/patches/minecraft/net/minecraft/client/audio/SoundHandler.edit.java b/patches/minecraft/net/minecraft/client/audio/SoundHandler.edit.java
index eca9fb69..c09c014b 100644
--- a/patches/minecraft/net/minecraft/client/audio/SoundHandler.edit.java
+++ b/patches/minecraft/net/minecraft/client/audio/SoundHandler.edit.java
@@ -13,12 +13,10 @@
 
 > DELETE  2  @  2 : 3
 
-> CHANGE  1 : 13  @  1 : 11
+> CHANGE  1 : 11  @  1 : 11
 
 ~ import java.util.Set;
 ~ 
-~ import net.lax1dude.eaglercraft.v1_8.internal.PlatformAudio;
-~ 
 ~ import com.google.common.collect.Lists;
 ~ 
 ~ import net.lax1dude.eaglercraft.v1_8.EaglercraftSoundManager;
@@ -77,14 +75,7 @@
 ~ 		} catch (IOException e) {
 ~ 			throw new RuntimeException("Exception caught reading JSON", e);
 
-> INSERT  122 : 126  @  122
-
-+ 		if (category == SoundCategory.VOICE) {
-+ 			PlatformAudio.setMicVol(volume);
-+ 		}
-+ 
-
-> CHANGE  13 : 19  @  13 : 15
+> CHANGE  135 : 141  @  135 : 137
 
 ~ 			SoundCategory cat = soundeventaccessorcomposite.getSoundCategory();
 ~ 			for (int i = 0; i < categories.length; ++i) {
diff --git a/patches/minecraft/net/minecraft/client/entity/AbstractClientPlayer.edit.java b/patches/minecraft/net/minecraft/client/entity/AbstractClientPlayer.edit.java
index 7a5051d1..15fc7f55 100644
--- a/patches/minecraft/net/minecraft/client/entity/AbstractClientPlayer.edit.java
+++ b/patches/minecraft/net/minecraft/client/entity/AbstractClientPlayer.edit.java
@@ -5,24 +5,39 @@
 # Version: 1.0
 # Author: lax1dude
 
-> CHANGE  2 : 4  @  2 : 4
+> CHANGE  2 : 7  @  2 : 4
 
+~ import net.lax1dude.eaglercraft.v1_8.EagRuntime;
+~ import net.lax1dude.eaglercraft.v1_8.EaglercraftUUID;
 ~ import net.lax1dude.eaglercraft.v1_8.mojang.authlib.GameProfile;
+~ import net.lax1dude.eaglercraft.v1_8.profanity_filter.ProfanityFilter;
 ~ import net.lax1dude.eaglercraft.v1_8.profile.SkinModel;
 
 > DELETE  2  @  2 : 6
 
-> DELETE  6  @  6 : 7
+> INSERT  4 : 5  @  4
 
-> INSERT  6 : 14  @  6
++ import net.minecraft.event.ClickEvent;
 
-+ 	public long eaglerHighPolyAnimationTick = System.currentTimeMillis();
+> INSERT  1 : 4  @  1
+
++ import net.minecraft.scoreboard.ScorePlayerTeam;
++ import net.minecraft.util.ChatComponentText;
++ import net.minecraft.util.IChatComponent;
+
+> DELETE  1  @  1 : 2
+
+> INSERT  6 : 16  @  6
+
++ 	public long eaglerHighPolyAnimationTick = EagRuntime.steadyTimeMillis();
 + 	public float eaglerHighPolyAnimationFloat1 = 0.0f;
 + 	public float eaglerHighPolyAnimationFloat2 = 0.0f;
 + 	public float eaglerHighPolyAnimationFloat3 = 0.0f;
 + 	public float eaglerHighPolyAnimationFloat4 = 0.0f;
 + 	public float eaglerHighPolyAnimationFloat5 = 0.0f;
 + 	public float eaglerHighPolyAnimationFloat6 = 0.0f;
++ 	public EaglercraftUUID clientBrandUUIDCache = null;
++ 	private String nameProfanityFilter = null;
 + 
 
 > DELETE  38  @  38 : 56
@@ -35,4 +50,29 @@
 + 	}
 + 
 
+> INSERT  27 : 49  @  27
+
++ 
++ 	public String getNameProfanityFilter() {
++ 		if (Minecraft.getMinecraft().isEnableProfanityFilter()) {
++ 			if (nameProfanityFilter == null) {
++ 				nameProfanityFilter = ProfanityFilter.getInstance()
++ 						.profanityFilterString(this.getGameProfile().getName());
++ 			}
++ 			return nameProfanityFilter;
++ 		} else {
++ 			return this.getGameProfile().getName();
++ 		}
++ 	}
++ 
++ 	public IChatComponent getDisplayNameProfanityFilter() {
++ 		ChatComponentText chatcomponenttext = new ChatComponentText(
++ 				ScorePlayerTeam.formatPlayerName(this.getTeam(), this.getNameProfanityFilter()));
++ 		chatcomponenttext.getChatStyle()
++ 				.setChatClickEvent(new ClickEvent(ClickEvent.Action.SUGGEST_COMMAND, "/msg " + this.getName() + " "));
++ 		chatcomponenttext.getChatStyle().setChatHoverEvent(this.getHoverEvent());
++ 		chatcomponenttext.getChatStyle().setInsertion(this.getName());
++ 		return chatcomponenttext;
++ 	}
+
 > EOF
diff --git a/patches/minecraft/net/minecraft/client/entity/EntityPlayerSP.edit.java b/patches/minecraft/net/minecraft/client/entity/EntityPlayerSP.edit.java
index f853691b..b7cf5678 100644
--- a/patches/minecraft/net/minecraft/client/entity/EntityPlayerSP.edit.java
+++ b/patches/minecraft/net/minecraft/client/entity/EntityPlayerSP.edit.java
@@ -5,8 +5,9 @@
 # Version: 1.0
 # Author: lax1dude
 
-> INSERT  2 : 4  @  2
+> INSERT  2 : 5  @  2
 
++ import net.lax1dude.eaglercraft.v1_8.EaglercraftVersion;
 + import net.lax1dude.eaglercraft.v1_8.sp.lan.LANClientNetworkManager;
 + import net.lax1dude.eaglercraft.v1_8.sp.socket.ClientIntegratedServerNetworkManager;
 
@@ -22,7 +23,11 @@
 
 ~ 	public EntityPlayerSP(Minecraft mcIn, World worldIn, NetHandlerPlayClient netHandler, StatFileWriter statWriter) {
 
-> DELETE  2  @  2 : 3
+> INSERT  1 : 2  @  1
+
++ 		this.clientBrandUUIDCache = EaglercraftVersion.clientBrandUUID;
+
+> DELETE  1  @  1 : 2
 
 > INSERT  2 : 3  @  2
 
diff --git a/patches/minecraft/net/minecraft/client/gui/ChatLine.edit.java b/patches/minecraft/net/minecraft/client/gui/ChatLine.edit.java
new file mode 100644
index 00000000..2a9236b0
--- /dev/null
+++ b/patches/minecraft/net/minecraft/client/gui/ChatLine.edit.java
@@ -0,0 +1,28 @@
+
+# Eagler Context Redacted Diff
+# Copyright (c) 2024 lax1dude. All rights reserved.
+
+# Version: 1.0
+# Author: lax1dude
+
+> INSERT  2 : 4  @  2
+
++ import net.lax1dude.eaglercraft.v1_8.profanity_filter.ProfanityFilter;
++ import net.minecraft.client.Minecraft;
+
+> INSERT  5 : 6  @  5
+
++ 	private IChatComponent lineStringProfanityFilter;
+
+> CHANGE  9 : 17  @  9 : 10
+
+~ 		if (Minecraft.getMinecraft().isEnableProfanityFilter()) {
+~ 			if (lineStringProfanityFilter == null) {
+~ 				lineStringProfanityFilter = ProfanityFilter.getInstance().profanityFilterChatComponent(lineString);
+~ 			}
+~ 			return lineStringProfanityFilter;
+~ 		} else {
+~ 			return lineString;
+~ 		}
+
+> EOF
diff --git a/patches/minecraft/net/minecraft/client/gui/FontRenderer.edit.java b/patches/minecraft/net/minecraft/client/gui/FontRenderer.edit.java
index 512b09b0..5569b47f 100644
--- a/patches/minecraft/net/minecraft/client/gui/FontRenderer.edit.java
+++ b/patches/minecraft/net/minecraft/client/gui/FontRenderer.edit.java
@@ -7,12 +7,13 @@
 
 > DELETE  2  @  2 : 6
 
-> CHANGE  4 : 11  @  4 : 6
+> CHANGE  4 : 12  @  4 : 6
 
 ~ import net.lax1dude.eaglercraft.v1_8.EaglercraftRandom;
 ~ 
 ~ import net.lax1dude.eaglercraft.v1_8.HString;
 ~ import net.lax1dude.eaglercraft.v1_8.IOUtils;
+~ import net.lax1dude.eaglercraft.v1_8.minecraft.FontMappingHelper;
 ~ import net.lax1dude.eaglercraft.v1_8.opengl.GlStateManager;
 ~ import net.lax1dude.eaglercraft.v1_8.opengl.ImageData;
 ~ import net.lax1dude.eaglercraft.v1_8.opengl.WorldRenderer;
@@ -50,7 +51,24 @@
 ~ 	protected boolean underlineStyle;
 ~ 	protected boolean strikethroughStyle;
 
-> CHANGE  43 : 44  @  43 : 44
+> INSERT  1 : 15  @  1
+
++ 	protected static char[] codepointLookup = new char[] { 192, 193, 194, 200, 202, 203, 205, 211, 212, 213, 218, 223,
++ 			227, 245, 287, 304, 305, 338, 339, 350, 351, 372, 373, 382, 519, 0, 0, 0, 0, 0, 0, 0, 32, 33, 34, 35, 36,
++ 			37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
++ 			64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90,
++ 			91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113,
++ 			114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 0, 199, 252, 233, 226, 228, 224, 229, 231,
++ 			234, 235, 232, 239, 238, 236, 196, 197, 201, 230, 198, 244, 246, 242, 251, 249, 255, 214, 220, 248, 163,
++ 			216, 215, 402, 225, 237, 243, 250, 241, 209, 170, 186, 191, 174, 172, 189, 188, 161, 171, 187, 9617, 9618,
++ 			9619, 9474, 9508, 9569, 9570, 9558, 9557, 9571, 9553, 9559, 9565, 9564, 9563, 9488, 9492, 9524, 9516, 9500,
++ 			9472, 9532, 9566, 9567, 9562, 9556, 9577, 9574, 9568, 9552, 9580, 9575, 9576, 9572, 9573, 9561, 9560, 9554,
++ 			9555, 9579, 9578, 9496, 9484, 9608, 9604, 9612, 9616, 9600, 945, 946, 915, 960, 931, 963, 956, 964, 934,
++ 			920, 937, 948, 8734, 8709, 8712, 8745, 8801, 177, 8805, 8804, 8992, 8993, 247, 8776, 176, 8729, 183, 8730,
++ 			8319, 178, 9632, 0 };
++ 
+
+> CHANGE  42 : 43  @  42 : 43
 
 ~ 		ImageData bufferedimage;
 
@@ -60,7 +78,11 @@
 ~ 		int j = bufferedimage.height;
 ~ 		int[] aint = bufferedimage.pixels;
 
-> CHANGE  68 : 87  @  68 : 78
+> CHANGE  54 : 55  @  54 : 56
+
+~ 			int i = FontMappingHelper.lookupChar(parChar1, false);
+
+> CHANGE  12 : 31  @  12 : 22
 
 ~ 		Tessellator tessellator = Tessellator.getInstance();
 ~ 		WorldRenderer worldrenderer = tessellator.getWorldRenderer();
@@ -130,7 +152,20 @@
 
 ~ 				int i1 = "0123456789abcdefklmnor".indexOf(Character.toLowerCase(parString1.charAt(i + 1)));
 
-> CHANGE  133 : 134  @  133 : 134
+> CHANGE  39 : 40  @  39 : 41
+
+~ 				int j = FontMappingHelper.lookupChar(c0, false);
+
+> INSERT  2 : 3  @  2
+
++ 					char[] chars = FontRenderer.codepointLookup;
+
+> CHANGE  3 : 5  @  3 : 8
+
+~ 						j = this.fontRandom.nextInt(chars.length);
+~ 						c1 = chars[j];
+
+> CHANGE  82 : 83  @  82 : 83
 
 ~ 	private int renderStringAligned(String text, int x, int y, int wrapWidth, int color, boolean parFlag) {
 
@@ -153,7 +188,11 @@
 
 + 		return (int) this.posX;
 
-> INSERT  119 : 122  @  119
+> CHANGE  42 : 43  @  42 : 44
+
+~ 			int i = FontMappingHelper.lookupChar(character, false);
+
+> INSERT  75 : 78  @  75
 
 + 		if ((textColor & -67108864) == 0) {
 + 			textColor |= -16777216;
diff --git a/patches/minecraft/net/minecraft/client/gui/GuiButton.edit.java b/patches/minecraft/net/minecraft/client/gui/GuiButton.edit.java
index 5f7489b5..36d87be3 100644
--- a/patches/minecraft/net/minecraft/client/gui/GuiButton.edit.java
+++ b/patches/minecraft/net/minecraft/client/gui/GuiButton.edit.java
@@ -46,4 +46,12 @@
 ~ 				GlStateManager.popMatrix();
 ~ 			}
 
+> INSERT  32 : 37  @  32
+
++ 
++ 	public boolean isSliderTouchEvents() {
++ 		return false;
++ 	}
++ 
+
 > EOF
diff --git a/patches/minecraft/net/minecraft/client/gui/GuiChat.edit.java b/patches/minecraft/net/minecraft/client/gui/GuiChat.edit.java
index 6b77b96f..2338cc80 100644
--- a/patches/minecraft/net/minecraft/client/gui/GuiChat.edit.java
+++ b/patches/minecraft/net/minecraft/client/gui/GuiChat.edit.java
@@ -7,7 +7,7 @@
 
 > DELETE  2  @  2 : 3
 
-> CHANGE  2 : 13  @  2 : 4
+> CHANGE  2 : 18  @  2 : 4
 
 ~ 
 ~ import org.apache.commons.lang3.StringUtils;
@@ -16,25 +16,50 @@
 ~ 
 ~ import net.lax1dude.eaglercraft.v1_8.Keyboard;
 ~ import net.lax1dude.eaglercraft.v1_8.Mouse;
+~ import net.lax1dude.eaglercraft.v1_8.PointerInputAbstraction;
 ~ import net.lax1dude.eaglercraft.v1_8.log4j.LogManager;
 ~ import net.lax1dude.eaglercraft.v1_8.log4j.Logger;
+~ import net.lax1dude.eaglercraft.v1_8.minecraft.EnumInputEvent;
+~ import net.lax1dude.eaglercraft.v1_8.minecraft.GuiScreenVisualViewport;
+~ import net.lax1dude.eaglercraft.v1_8.notifications.GuiButtonNotifBell;
+~ import net.lax1dude.eaglercraft.v1_8.notifications.GuiScreenNotifications;
 ~ import net.lax1dude.eaglercraft.v1_8.opengl.GlStateManager;
 ~ import net.minecraft.client.resources.I18n;
 
 > DELETE  6  @  6 : 11
 
-> INSERT  12 : 14  @  12
+> CHANGE  1 : 2  @  1 : 2
+
+~ public class GuiChat extends GuiScreenVisualViewport {
+
+> INSERT  10 : 13  @  10
 
 + 	private GuiButton exitButton;
++ 	private GuiButtonNotifBell notifBellButton;
 + 
 
-> INSERT  9 : 12  @  9
+> INSERT  9 : 17  @  9
 
 + 		if (!(this instanceof GuiSleepMP)) {
 + 			this.buttonList.add(exitButton = new GuiButton(69, this.width - 100, 3, 97, 20, I18n.format("chat.exit")));
++ 			if (!this.mc.isIntegratedServerRunning() && this.mc.thePlayer != null
++ 					&& this.mc.thePlayer.sendQueue.getEaglerMessageProtocol().ver >= 4) {
++ 				this.buttonList.add(notifBellButton = new GuiButtonNotifBell(70, this.width - 122, 3));
++ 				notifBellButton.setUnread(mc.thePlayer.sendQueue.getNotifManager().getUnread());
++ 			}
 + 		}
 
-> CHANGE  18 : 20  @  18 : 27
+> CHANGE  14 : 15  @  14 : 15
+
+~ 	public void updateScreen0() {
+
+> INSERT  1 : 4  @  1
+
++ 		if (notifBellButton != null && mc.thePlayer != null) {
++ 			notifBellButton.setUnread(mc.thePlayer.sendQueue.getNotifManager().getUnread());
++ 		}
+
+> CHANGE  2 : 4  @  2 : 11
 
 ~ 	protected void keyTyped(char parChar1, int parInt1) {
 ~ 		if (parInt1 == 1 && (this.mc.gameSettings.keyBindClose.getKeyCode() == 0 || this.mc.areKeysLocked())) {
@@ -77,13 +102,30 @@
 
 > CHANGE  25 : 26  @  25 : 26
 
-~ 	protected void mouseClicked(int parInt1, int parInt2, int parInt3) {
+~ 	protected void mouseClicked0(int parInt1, int parInt2, int parInt3) {
 
-> INSERT  11 : 17  @  11
+> CHANGE  1 : 3  @  1 : 2
+
+~ 			IChatComponent ichatcomponent = this.mc.ingameGUI.getChatGUI()
+~ 					.getChatComponent(PointerInputAbstraction.getVCursorX(), PointerInputAbstraction.getVCursorY());
+
+> INSERT  3 : 6  @  3
+
++ 			if (mc.notifRenderer.handleClicked(this, parInt1, parInt2)) {
++ 				return;
++ 			}
+
+> CHANGE  3 : 4  @  3 : 4
+
+~ 		super.mouseClicked0(parInt1, parInt2, parInt3);
+
+> INSERT  2 : 10  @  2
 
 + 	protected void actionPerformed(GuiButton par1GuiButton) {
 + 		if (par1GuiButton.id == 69) {
 + 			this.mc.displayGuiScreen(null);
++ 		} else if (par1GuiButton.id == 70) {
++ 			this.mc.displayGuiScreen(new GuiScreenNotifications(this));
 + 		}
 + 	}
 + 
@@ -101,27 +143,43 @@
 
 ~ 				stringbuilder.append(this.foundPlayerNames.get(i));
 
-> INSERT  44 : 45  @  44
+> CHANGE  41 : 42  @  41 : 42
 
-+ 		GlStateManager.color(1.0f, 1.0f, 1.0f, 1.0f);
+~ 	public void drawScreen0(int i, int j, float f) {
 
-> INSERT  5 : 9  @  5
+> CHANGE  2 : 5  @  2 : 3
 
-+ 		if (exitButton != null) {
-+ 			exitButton.yPosition = 3 + mc.guiAchievement.getHeight();
-+ 		}
-+ 
+~ 		GlStateManager.color(1.0f, 1.0f, 1.0f, 1.0f);
+~ 		IChatComponent ichatcomponent = this.mc.ingameGUI.getChatGUI()
+~ 				.getChatComponent(PointerInputAbstraction.getVCursorX(), PointerInputAbstraction.getVCursorY());
 
-> CHANGE  8 : 10  @  8 : 9
+> CHANGE  4 : 9  @  4 : 5
+
+~ 		if (exitButton != null) {
+~ 			exitButton.yPosition = 3 + mc.guiAchievement.getHeight();
+~ 		}
+~ 
+~ 		super.drawScreen0(i, j, f);
+
+> CHANGE  7 : 9  @  7 : 8
 
 ~ 			for (int i = 0; i < parArrayOfString.length; ++i) {
 ~ 				String s = parArrayOfString[i];
 
-> INSERT  24 : 28  @  24
+> INSERT  24 : 37  @  24
 
 + 
 + 	public boolean blockPTTKey() {
 + 		return true;
 + 	}
++ 
++ 	public boolean showCopyPasteButtons() {
++ 		return true;
++ 	}
++ 
++ 	public void fireInputEvent(EnumInputEvent event, String str) {
++ 		inputField.fireInputEvent(event, str);
++ 	}
++ 
 
 > EOF
diff --git a/patches/minecraft/net/minecraft/client/gui/GuiCommandBlock.edit.java b/patches/minecraft/net/minecraft/client/gui/GuiCommandBlock.edit.java
index b90ff796..98576b03 100644
--- a/patches/minecraft/net/minecraft/client/gui/GuiCommandBlock.edit.java
+++ b/patches/minecraft/net/minecraft/client/gui/GuiCommandBlock.edit.java
@@ -5,12 +5,13 @@
 # Version: 1.0
 # Author: lax1dude
 
-> CHANGE  2 : 6  @  2 : 7
+> CHANGE  2 : 7  @  2 : 7
 
 ~ import net.lax1dude.eaglercraft.v1_8.netty.Unpooled;
 ~ import net.lax1dude.eaglercraft.v1_8.Keyboard;
 ~ import net.lax1dude.eaglercraft.v1_8.log4j.LogManager;
 ~ import net.lax1dude.eaglercraft.v1_8.log4j.Logger;
+~ import net.lax1dude.eaglercraft.v1_8.minecraft.EnumInputEvent;
 
 > DELETE  5  @  5 : 8
 
@@ -26,11 +27,23 @@
 
 ~ 	protected void mouseClicked(int parInt1, int parInt2, int parInt3) {
 
-> INSERT  46 : 50  @  46
+> INSERT  46 : 62  @  46
 
 + 
 + 	public boolean blockPTTKey() {
-+ 		return commandTextField.isFocused();
++ 		return commandTextField.isFocused() || previousOutputTextField.isFocused();
 + 	}
++ 
++ 	@Override
++ 	public boolean showCopyPasteButtons() {
++ 		return commandTextField.isFocused() || previousOutputTextField.isFocused();
++ 	}
++ 
++ 	@Override
++ 	public void fireInputEvent(EnumInputEvent event, String param) {
++ 		commandTextField.fireInputEvent(event, param);
++ 		previousOutputTextField.fireInputEvent(event, param);
++ 	}
++ 
 
 > EOF
diff --git a/patches/minecraft/net/minecraft/client/gui/GuiControls.edit.java b/patches/minecraft/net/minecraft/client/gui/GuiControls.edit.java
index 6bc61680..50dea76f 100644
--- a/patches/minecraft/net/minecraft/client/gui/GuiControls.edit.java
+++ b/patches/minecraft/net/minecraft/client/gui/GuiControls.edit.java
@@ -11,8 +11,18 @@
 
 > DELETE  1  @  1 : 6
 
-> CHANGE  49 : 50  @  49 : 50
+> CHANGE  6 : 8  @  6 : 7
 
+~ 			GameSettings.Options.INVERT_MOUSE, GameSettings.Options.SENSITIVITY,
+~ 			GameSettings.Options.EAGLER_TOUCH_CONTROL_OPACITY };
+
+> CHANGE  42 : 48  @  42 : 43
+
+~ 	public void handleTouchInput() throws IOException {
+~ 		super.handleTouchInput();
+~ 		this.keyBindingList.handleTouchInput();
+~ 	}
+~ 
 ~ 	protected void actionPerformed(GuiButton parGuiButton) {
 
 > CHANGE  3 : 6  @  3 : 5
diff --git a/patches/minecraft/net/minecraft/client/gui/GuiCreateFlatWorld.edit.java b/patches/minecraft/net/minecraft/client/gui/GuiCreateFlatWorld.edit.java
index 4d9df200..5cca10b2 100644
--- a/patches/minecraft/net/minecraft/client/gui/GuiCreateFlatWorld.edit.java
+++ b/patches/minecraft/net/minecraft/client/gui/GuiCreateFlatWorld.edit.java
@@ -15,8 +15,13 @@
 
 > DELETE  2  @  2 : 3
 
-> CHANGE  61 : 62  @  61 : 62
+> CHANGE  61 : 67  @  61 : 62
 
+~ 	public void handleTouchInput() throws IOException {
+~ 		super.handleTouchInput();
+~ 		this.createFlatWorldListSlotGui.handleTouchInput();
+~ 	}
+~ 
 ~ 	protected void actionPerformed(GuiButton parGuiButton) {
 
 > EOF
diff --git a/patches/minecraft/net/minecraft/client/gui/GuiCreateWorld.edit.java b/patches/minecraft/net/minecraft/client/gui/GuiCreateWorld.edit.java
index fb893414..a343ba99 100644
--- a/patches/minecraft/net/minecraft/client/gui/GuiCreateWorld.edit.java
+++ b/patches/minecraft/net/minecraft/client/gui/GuiCreateWorld.edit.java
@@ -7,10 +7,11 @@
 
 > DELETE  2  @  2 : 3
 
-> CHANGE  1 : 3  @  1 : 6
+> CHANGE  1 : 4  @  1 : 6
 
 ~ 
 ~ import net.lax1dude.eaglercraft.v1_8.Keyboard;
+~ import net.lax1dude.eaglercraft.v1_8.minecraft.EnumInputEvent;
 
 > DELETE  7  @  7 : 8
 
@@ -42,4 +43,19 @@
 ~ 					StringUtils.isNotEmpty(field_146335_h.text) ? "createWorld.seedNote" : "selectWorld.seedInfo",
 ~ 					new Object[0]), this.width / 2 - 100, 85, -6250336);
 
+> INSERT  47 : 59  @  47
+
++ 
++ 	@Override
++ 	public boolean showCopyPasteButtons() {
++ 		return field_146333_g.isFocused() || field_146335_h.isFocused();
++ 	}
++ 
++ 	@Override
++ 	public void fireInputEvent(EnumInputEvent event, String param) {
++ 		field_146333_g.fireInputEvent(event, param);
++ 		field_146335_h.fireInputEvent(event, param);
++ 	}
++ 
+
 > EOF
diff --git a/patches/minecraft/net/minecraft/client/gui/GuiCustomizeWorldScreen.edit.java b/patches/minecraft/net/minecraft/client/gui/GuiCustomizeWorldScreen.edit.java
index d88b2ff5..f49b59c3 100644
--- a/patches/minecraft/net/minecraft/client/gui/GuiCustomizeWorldScreen.edit.java
+++ b/patches/minecraft/net/minecraft/client/gui/GuiCustomizeWorldScreen.edit.java
@@ -5,16 +5,25 @@
 # Version: 1.0
 # Author: lax1dude
 
-> CHANGE  6 : 10  @  6 : 16
+> CHANGE  6 : 11  @  6 : 16
 
 ~ 
 ~ import net.lax1dude.eaglercraft.v1_8.HString;
+~ import net.lax1dude.eaglercraft.v1_8.minecraft.EnumInputEvent;
 ~ import net.lax1dude.eaglercraft.v1_8.opengl.GlStateManager;
 ~ import net.lax1dude.eaglercraft.v1_8.opengl.WorldRenderer;
 
 > DELETE  1  @  1 : 2
 
-> CHANGE  347 : 348  @  347 : 348
+> INSERT  89 : 94  @  89
+
++ 	public void handleTouchInput() throws IOException {
++ 		super.handleTouchInput();
++ 		this.field_175349_r.handleTouchInput();
++ 	}
++ 
+
+> CHANGE  258 : 259  @  258 : 259
 
 ~ 						HString.format("%5.3f", new Object[] { Float.valueOf(this.field_175336_F.mainNoiseScaleX) }),
 
@@ -106,4 +115,18 @@
 
 ~ 	protected void mouseClicked(int parInt1, int parInt2, int parInt3) {
 
+> INSERT  59 : 70  @  59
+
++ 
++ 	@Override
++ 	public boolean showCopyPasteButtons() {
++ 		return field_175349_r.isTextFieldFocused();
++ 	}
++ 
++ 	@Override
++ 	public void fireInputEvent(EnumInputEvent event, String param) {
++ 		field_175349_r.fireInputEvent(event, param);
++ 	}
++ 
+
 > EOF
diff --git a/patches/minecraft/net/minecraft/client/gui/GuiDownloadTerrain.edit.java b/patches/minecraft/net/minecraft/client/gui/GuiDownloadTerrain.edit.java
index 07925d58..8ae7b8d0 100644
--- a/patches/minecraft/net/minecraft/client/gui/GuiDownloadTerrain.edit.java
+++ b/patches/minecraft/net/minecraft/client/gui/GuiDownloadTerrain.edit.java
@@ -11,11 +11,16 @@
 
 ~ 	protected void keyTyped(char parChar1, int parInt1) {
 
-> INSERT  24 : 28  @  24
+> INSERT  24 : 33  @  24
 
 + 
 + 	public boolean shouldHangupIntegratedServer() {
 + 		return false;
 + 	}
++ 
++ 	public boolean canCloseGui() {
++ 		return false;
++ 	}
++ 
 
 > EOF
diff --git a/patches/minecraft/net/minecraft/client/gui/GuiEnchantment.edit.java b/patches/minecraft/net/minecraft/client/gui/GuiEnchantment.edit.java
index b2d9feda..600bbc61 100644
--- a/patches/minecraft/net/minecraft/client/gui/GuiEnchantment.edit.java
+++ b/patches/minecraft/net/minecraft/client/gui/GuiEnchantment.edit.java
@@ -29,8 +29,9 @@
 
 ~ 	protected void mouseClicked(int parInt1, int parInt2, int parInt3) {
 
-> CHANGE  25 : 28  @  25 : 28
+> CHANGE  24 : 28  @  24 : 28
 
+~ 		ScaledResolution scaledresolution = mc.scaledResolution;
 ~ 		GlStateManager.viewport((scaledresolution.getScaledWidth() - 290 - 12) / 2 * scaledresolution.getScaleFactor(),
 ~ 				(scaledresolution.getScaledHeight() - 220 + 10) / 2 * scaledresolution.getScaleFactor(),
 ~ 				290 * scaledresolution.getScaleFactor(), 220 * scaledresolution.getScaleFactor());
diff --git a/patches/minecraft/net/minecraft/client/gui/GuiFlatPresets.edit.java b/patches/minecraft/net/minecraft/client/gui/GuiFlatPresets.edit.java
index 5dc8fbd2..c0dfa359 100644
--- a/patches/minecraft/net/minecraft/client/gui/GuiFlatPresets.edit.java
+++ b/patches/minecraft/net/minecraft/client/gui/GuiFlatPresets.edit.java
@@ -5,10 +5,11 @@
 # Version: 1.0
 # Author: lax1dude
 
-> INSERT  7 : 11  @  7
+> INSERT  7 : 12  @  7
 
 + 
 + import net.lax1dude.eaglercraft.v1_8.Keyboard;
++ import net.lax1dude.eaglercraft.v1_8.minecraft.EnumInputEvent;
 + import net.lax1dude.eaglercraft.v1_8.opengl.GlStateManager;
 + import net.lax1dude.eaglercraft.v1_8.opengl.WorldRenderer;
 
@@ -18,7 +19,15 @@
 
 > DELETE  9  @  9 : 10
 
-> CHANGE  41 : 42  @  41 : 42
+> INSERT  37 : 42  @  37
+
++ 	public void handleTouchInput() throws IOException {
++ 		super.handleTouchInput();
++ 		this.field_146435_s.handleTouchInput();
++ 	}
++ 
+
+> CHANGE  4 : 5  @  4 : 5
 
 ~ 	protected void mouseClicked(int parInt1, int parInt2, int parInt3) {
 
@@ -35,4 +44,18 @@
 ~ 			for (int i = 0, l = parList.size(); i < l; ++i) {
 ~ 				flatgeneratorinfo.getWorldFeatures().put(parList.get(i), Maps.newHashMap());
 
+> INSERT  132 : 143  @  132
+
++ 
++ 	@Override
++ 	public boolean showCopyPasteButtons() {
++ 		return field_146433_u.isFocused();
++ 	}
++ 
++ 	@Override
++ 	public void fireInputEvent(EnumInputEvent event, String param) {
++ 		field_146433_u.fireInputEvent(event, param);
++ 	}
++ 
+
 > EOF
diff --git a/patches/minecraft/net/minecraft/client/gui/GuiIngame.edit.java b/patches/minecraft/net/minecraft/client/gui/GuiIngame.edit.java
index 15edf0f6..efd5bccb 100644
--- a/patches/minecraft/net/minecraft/client/gui/GuiIngame.edit.java
+++ b/patches/minecraft/net/minecraft/client/gui/GuiIngame.edit.java
@@ -5,22 +5,31 @@
 # Version: 1.0
 # Author: lax1dude
 
-> INSERT  2 : 7  @  2
+> INSERT  2 : 12  @  2
 
 + import java.util.ArrayList;
 + import java.util.Collection;
++ 
++ import net.lax1dude.eaglercraft.v1_8.Display;
++ import net.lax1dude.eaglercraft.v1_8.EagRuntime;
 + import net.lax1dude.eaglercraft.v1_8.EaglercraftRandom;
++ import net.lax1dude.eaglercraft.v1_8.PointerInputAbstraction;
++ import net.lax1dude.eaglercraft.v1_8.Touch;
 + import net.lax1dude.eaglercraft.v1_8.minecraft.EaglerTextureAtlasSprite;
 + 
 
-> CHANGE  3 : 7  @  3 : 6
+> CHANGE  3 : 9  @  3 : 6
 
 ~ 
 ~ import net.lax1dude.eaglercraft.v1_8.opengl.GlStateManager;
 ~ import net.lax1dude.eaglercraft.v1_8.opengl.OpenGlHelper;
 ~ import net.lax1dude.eaglercraft.v1_8.opengl.WorldRenderer;
+~ import net.lax1dude.eaglercraft.v1_8.touch_gui.TouchControls;
+~ import net.lax1dude.eaglercraft.v1_8.touch_gui.TouchOverlayRenderer;
 
-> DELETE  2  @  2 : 11
+> CHANGE  2 : 3  @  2 : 11
+
+~ import net.minecraft.client.gui.inventory.GuiInventory;
 
 > DELETE  2  @  2 : 3
 
@@ -28,7 +37,15 @@
 
 ~ import net.minecraft.client.renderer.entity.RenderManager;
 
-> CHANGE  32 : 33  @  32 : 33
+> INSERT  13 : 14  @  13
+
++ import net.minecraft.network.play.client.C16PacketClientStatus;
+
+> INSERT  11 : 12  @  11
+
++ import net.minecraft.util.MovingObjectPosition.MovingObjectType;
+
+> CHANGE  8 : 9  @  8 : 9
 
 ~ 	private final EaglercraftRandom rand = new EaglercraftRandom();
 
@@ -40,34 +57,110 @@
 
 > DELETE  19  @  19 : 20
 
-> CHANGE  16 : 19  @  16 : 21
+> CHANGE  11 : 12  @  11 : 12
+
+~ 		ScaledResolution scaledresolution = mc.scaledResolution;
+
+> CHANGE  4 : 7  @  4 : 9
 
 ~ 		GlStateManager.tryBlendFuncSeparate(770, 771, 1, 0);
 ~ 		GlStateManager.enableDepth();
 ~ 		GlStateManager.disableLighting();
 
-> DELETE  21  @  21 : 22
+> INSERT  15 : 17  @  15
+
++ 		onBeginHotbarDraw();
++ 
+
+> DELETE  6  @  6 : 7
 
 > DELETE  1  @  1 : 8
 
-> CHANGE  44 : 45  @  44 : 47
+> DELETE  1  @  1 : 2
 
-~ 		this.overlayDebug.renderDebugInfo(scaledresolution);
+> DELETE  1  @  1 : 2
 
-> INSERT  83 : 87  @  83
+> DELETE  4  @  4 : 22
+
+> INSERT  1 : 2  @  1
+
++ 		GlStateManager.disableBlend();
+
+> INSERT  7 : 9  @  7
+
++ 		GlStateManager.color(1.0F, 1.0F, 1.0F, 1.0F);
++ 		GlStateManager.disableBlend();
+
+> CHANGE  6 : 8  @  6 : 14
+
+~ 		GlStateManager.color(1.0F, 1.0F, 1.0F, 1.0F);
+~ 		GlStateManager.disableBlend();
+
+> DELETE  1  @  1 : 2
+
+> INSERT  21 : 22  @  21
+
++ 		}
+
+> CHANGE  1 : 20  @  1 : 2
+
+~ 		GlStateManager.color(1.0F, 1.0F, 1.0F, 1.0F);
+~ 		drawEaglerInteractButton(scaledresolution);
+~ 
+~ 		onEndHotbarDraw();
+~ 
+~ 		GlStateManager.color(1.0F, 1.0F, 1.0F, 1.0F);
+~ 		if (this.mc.thePlayer.getSleepTimer() > 0) {
+~ 			GlStateManager.disableDepth();
+~ 			GlStateManager.disableAlpha();
+~ 			int j1 = this.mc.thePlayer.getSleepTimer();
+~ 			float f1 = (float) j1 / 100.0F;
+~ 			if (f1 > 1.0F) {
+~ 				f1 = 1.0F - (float) (j1 - 100) / 10.0F;
+~ 			}
+~ 
+~ 			int k = (int) (220.0F * f1) << 24 | 1052704;
+~ 			drawRect(0, 0, i, j, k);
+~ 			GlStateManager.enableAlpha();
+~ 			GlStateManager.enableDepth();
+
+> INSERT  2 : 8  @  2
+
++ 		if (this.mc.isDemo()) {
++ 			this.renderDemo(scaledresolution);
++ 		}
++ 
++ 		this.overlayDebug.renderDebugInfo(scaledresolution);
++ 
+
+> DELETE  1  @  1 : 2
+
+> DELETE  33  @  33 : 35
+
+> INSERT  18 : 22  @  18
 
 + 		if (this.mc.currentScreen == null) {
 + 			this.mc.voiceOverlay.drawOverlay();
 + 		}
 + 
 
-> INSERT  4 : 7  @  4
+> INSERT  4 : 9  @  4
 
 + 		if (this.mc.gameSettings.hudWorld && (mc.currentScreen == null || !(mc.currentScreen instanceof GuiChat))) {
 + 			j -= 10;
 + 		}
++ 		j -= (this.mc.displayHeight - (Display.getVisualViewportX() + Display.getVisualViewportH())) * j
++ 				/ this.mc.displayHeight;
 
-> INSERT  19 : 30  @  19
+> DELETE  1  @  1 : 2
+
+> DELETE  1  @  1 : 2
+
+> INSERT  11 : 12  @  11
+
++ 
+
+> INSERT  4 : 15  @  4
 
 + 	public void renderGameOverlayCrosshairs(int scaledResWidth, int scaledResHeight) {
 + 		if (this.showCrosshair()) {
@@ -81,7 +174,55 @@
 + 	}
 + 
 
-> DELETE  147  @  147 : 151
+> INSERT  9 : 26  @  9
+
++ 
++ 			if (PointerInputAbstraction.isTouchMode()) {
++ 				this.mc.getTextureManager().bindTexture(TouchOverlayRenderer.spriteSheet);
++ 				this.drawTexturedModalRect(i + 89, sr.getScaledHeight() - 22, 234, 0, 22, 22);
++ 				int areaHAdd = 12;
++ 				hotbarAreaX = (i - 91) * mc.displayWidth / sr.getScaledWidth();
++ 				hotbarAreaY = (sr.getScaledHeight() - 22 - areaHAdd) * mc.displayHeight / sr.getScaledHeight();
++ 				hotbarAreaW = 203 * mc.displayWidth / sr.getScaledWidth();
++ 				hotbarAreaH = (22 + areaHAdd) * mc.displayHeight / sr.getScaledHeight();
++ 			} else {
++ 				hotbarAreaX = -1;
++ 				hotbarAreaY = -1;
++ 				hotbarAreaW = -1;
++ 				hotbarAreaH = -1;
++ 			}
++ 
++ 			this.mc.getTextureManager().bindTexture(widgetsTexPath);
+
+> INSERT  16 : 17  @  16
+
++ 
+
+> DELETE  5  @  5 : 6
+
+> DELETE  9  @  9 : 11
+
+> DELETE  3  @  3 : 4
+
+> DELETE  12  @  12 : 13
+
+> DELETE  1  @  1 : 2
+
+> DELETE  10  @  10 : 11
+
+> DELETE  5  @  5 : 6
+
+> CHANGE  1 : 2  @  1 : 2
+
+~ 			String s = this.highlightingItemStack.getDisplayNameProfanityFilter();
+
+> DELETE  25  @  25 : 26
+
+> DELETE  3  @  3 : 4
+
+> DELETE  11  @  11 : 12
+
+> DELETE  25  @  25 : 29
 
 > CHANGE  17 : 19  @  17 : 18
 
@@ -107,7 +248,23 @@
 + 			GlStateManager.enableBlend();
 + 			GlStateManager.tryBlendFuncSeparate(770, 771, 1, 0);
 
-> CHANGE  248 : 249  @  248 : 249
+> DELETE  23  @  23 : 25
+
+> DELETE  17  @  17 : 19
+
+> DELETE  61  @  61 : 63
+
+> DELETE  39  @  39 : 40
+
+> DELETE  36  @  36 : 37
+
+> DELETE  14  @  14 : 15
+
+> CHANGE  6 : 7  @  6 : 9
+
+~ 			int i = mc.scaledResolution.getScaledWidth();
+
+> CHANGE  40 : 41  @  40 : 41
 
 ~ 	public void renderVignette(float parFloat1, int scaledWidth, int scaledHeight) {
 
@@ -179,4 +336,223 @@
 + 	}
 + 
 
+> INSERT  27 : 243  @  27
+
++ 
++ 	private int hotbarAreaX = -1;
++ 	private int hotbarAreaY = -1;
++ 	private int hotbarAreaW = -1;
++ 	private int hotbarAreaH = -1;
++ 	private int currentHotbarSlotTouch = -1;
++ 	private long hotbarSlotTouchStart = -1l;
++ 	private boolean hotbarSlotTouchAlreadySelected = false;
++ 	private int interactButtonX = -1;
++ 	private int interactButtonY = -1;
++ 	private int interactButtonW = -1;
++ 	private int interactButtonH = -1;
++ 	private int touchVPosX = -1;
++ 	private int touchVPosY = -1;
++ 	private int touchEventUID = -1;
++ 
++ 	private void drawEaglerInteractButton(ScaledResolution parScaledResolution) {
++ 		if (PointerInputAbstraction.isTouchMode() && mc.objectMouseOver != null
++ 				&& mc.objectMouseOver.typeOfHit == MovingObjectType.ENTITY) {
++ 			int scale = parScaledResolution.getScaleFactor();
++ 			interactButtonW = 118 * scale;
++ 			interactButtonH = 20 * scale;
++ 			int xx = (parScaledResolution.getScaledWidth() - 118) / 2;
++ 			int yy = parScaledResolution.getScaledHeight() - 70;
++ 			interactButtonX = xx * scale;
++ 			interactButtonY = yy * scale;
++ 			mc.getTextureManager().bindTexture(TouchOverlayRenderer.spriteSheet);
++ 			boolean hover = touchVPosX >= interactButtonX && touchVPosY >= interactButtonY
++ 					&& touchVPosX < interactButtonX + interactButtonW && touchVPosY < interactButtonY + interactButtonH;
++ 			float f = MathHelper.clamp_float(mc.gameSettings.touchControlOpacity, 0.0f, 1.0f);
++ 			if (f > 0.0f) {
++ 				GlStateManager.color(1.0f, 1.0f, 1.0f, f);
++ 				drawTexturedModalRect(xx, yy, 0, hover ? 216 : 236, 118, 20);
++ 				GlStateManager.color(1.0f, 1.0f, 1.0f, 1.0f);
++ 				drawCenteredString(mc.fontRendererObj, I18n.format("touch.interact.entity"),
++ 						parScaledResolution.getScaledWidth() / 2, yy + 6,
++ 						(hover ? 16777120 : 14737632) | ((int) (f * 255.0f) << 24));
++ 			}
++ 		} else {
++ 			interactButtonX = -1;
++ 			interactButtonY = -1;
++ 			interactButtonW = -1;
++ 			interactButtonH = -1;
++ 		}
++ 	}
++ 
++ 	private int applyTouchHotbarTransformX(int posX, boolean scaled) {
++ 		if (scaled) {
++ 			return (posX + mc.scaledResolution.getScaledWidth() / 4) * 2 / 3;
++ 		} else {
++ 			return (posX + mc.displayWidth / 4) * 2 / 3;
++ 		}
++ 	}
++ 
++ 	private int applyTouchHotbarTransformY(int posY, boolean scaled) {
++ 		if (scaled) {
++ 			return (posY + mc.scaledResolution.getScaledHeight() / 2) * 2 / 3;
++ 		} else {
++ 			return (posY + mc.displayHeight / 2) * 2 / 3;
++ 		}
++ 	}
++ 
++ 	private void onBeginHotbarDraw() {
++ 		if (PointerInputAbstraction.isTouchMode()) {
++ 			GlStateManager.pushMatrix();
++ 			ScaledResolution res = mc.scaledResolution;
++ 			GlStateManager.translate(res.getScaledWidth() / -4, res.getScaledHeight() / -2, field_175199_z);
++ 			GlStateManager.scale(1.5f, 1.5f, 1.5f);
++ 		}
++ 	}
++ 
++ 	private void onEndHotbarDraw() {
++ 		if (PointerInputAbstraction.isTouchMode()) {
++ 			GlStateManager.popMatrix();
++ 		}
++ 	}
++ 
++ 	private int getHotbarSlotTouched(int pointX) {
++ 		int xx = pointX - hotbarAreaX - 2;
++ 		xx /= 20 * mc.scaledResolution.getScaleFactor();
++ 		if (xx < 0)
++ 			xx = 0;
++ 		if (xx > 9)
++ 			xx = 9;
++ 		return xx;
++ 	}
++ 
++ 	public boolean handleTouchBeginEagler(int uid, int pointX, int pointY) {
++ 		if (mc.thePlayer == null) {
++ 			return false;
++ 		}
++ 		if (touchEventUID == -1) {
++ 			pointX = applyTouchHotbarTransformX(pointX, false);
++ 			pointY = applyTouchHotbarTransformY(pointY, false);
++ 			if (pointX >= hotbarAreaX && pointY >= hotbarAreaY && pointX < hotbarAreaX + hotbarAreaW
++ 					&& pointY < hotbarAreaY + hotbarAreaH) {
++ 				touchEventUID = uid;
++ 				currentHotbarSlotTouch = getHotbarSlotTouched(pointX);
++ 				hotbarSlotTouchStart = EagRuntime.steadyTimeMillis();
++ 				if (currentHotbarSlotTouch >= 0 && currentHotbarSlotTouch < 9) {
++ 					if (mc.thePlayer.isSpectator()) {
++ 						hotbarSlotTouchAlreadySelected = false;
++ 						mc.ingameGUI.getSpectatorGui().func_175260_a(currentHotbarSlotTouch);
++ 					} else {
++ 						hotbarSlotTouchAlreadySelected = (mc.thePlayer.inventory.currentItem == currentHotbarSlotTouch);
++ 						mc.thePlayer.inventory.currentItem = currentHotbarSlotTouch;
++ 					}
++ 				} else if (currentHotbarSlotTouch == 9) {
++ 					hotbarSlotTouchAlreadySelected = false;
++ 					currentHotbarSlotTouch = 69;
++ 					if (mc.playerController.isRidingHorse()) {
++ 						mc.thePlayer.sendHorseInventory();
++ 					} else {
++ 						mc.getNetHandler().addToSendQueue(
++ 								new C16PacketClientStatus(C16PacketClientStatus.EnumState.OPEN_INVENTORY_ACHIEVEMENT));
++ 						mc.displayGuiScreen(new GuiInventory(mc.thePlayer));
++ 					}
++ 				}
++ 				return true;
++ 			}
++ 			if (pointX >= interactButtonX && pointY >= interactButtonY && pointX < interactButtonX + interactButtonW
++ 					&& pointY < interactButtonY + interactButtonH) {
++ 				touchEventUID = uid;
++ 				mc.rightClickMouse();
++ 				return true;
++ 			}
++ 		}
++ 		return false;
++ 	}
++ 
++ 	public boolean handleTouchEndEagler(int uid, int pointX, int pointY) {
++ 		if (uid == touchEventUID) {
++ 			if (hotbarSlotTouchStart != -1l && currentHotbarSlotTouch != 69) {
++ 				if (EagRuntime.steadyTimeMillis() - hotbarSlotTouchStart < 350l) {
++ 					if (hotbarSlotTouchAlreadySelected) {
++ 						if (mc.thePlayer != null) {
++ 							mc.thePlayer.dropOneItem(false);
++ 						}
++ 					}
++ 				}
++ 			}
++ 			touchVPosX = -1;
++ 			touchVPosY = -1;
++ 			touchEventUID = -1;
++ 			currentHotbarSlotTouch = -1;
++ 			hotbarSlotTouchStart = -1l;
++ 			hotbarSlotTouchAlreadySelected = false;
++ 			return true;
++ 		}
++ 		return false;
++ 	}
++ 
++ 	public void updateTouchEagler(boolean screenTouched) {
++ 		if (screenTouched) {
++ 			int pointCount = Touch.touchPointCount();
++ 			for (int i = 0; i < pointCount; ++i) {
++ 				int uid = Touch.touchPointUID(i);
++ 				if (TouchControls.touchControls.containsKey(uid)) {
++ 					continue;
++ 				}
++ 				if (touchEventUID == -1 || touchEventUID == uid) {
++ 					touchVPosX = applyTouchHotbarTransformX(Touch.touchPointX(i), false);
++ 					touchVPosY = applyTouchHotbarTransformY(mc.displayHeight - Touch.touchPointY(i) - 1, false);
++ 					long millis = EagRuntime.steadyTimeMillis();
++ 					if (touchEventUID != -1 && hotbarSlotTouchStart != -1l) {
++ 						if (currentHotbarSlotTouch != 69) {
++ 							int slot = getHotbarSlotTouched(touchVPosX);
++ 							if (slot != currentHotbarSlotTouch) {
++ 								hotbarSlotTouchAlreadySelected = false;
++ 								currentHotbarSlotTouch = slot;
++ 								hotbarSlotTouchStart = millis;
++ 								if (slot >= 0 && slot < 9) {
++ 									if (mc.thePlayer.isSpectator()) {
++ 										mc.ingameGUI.getSpectatorGui().func_175260_a(slot);
++ 									} else {
++ 										mc.thePlayer.inventory.currentItem = slot;
++ 									}
++ 								}
++ 							} else {
++ 								if (millis - hotbarSlotTouchStart > 1200l) {
++ 									if (!mc.thePlayer.isSpectator()) {
++ 										hotbarSlotTouchStart = millis;
++ 										this.mc.thePlayer.dropOneItem(true);
++ 									}
++ 								}
++ 							}
++ 						}
++ 					}
++ 					return;
++ 				}
++ 			}
++ 		}
++ 		if (touchEventUID != -1) {
++ 			handleTouchEndEagler(touchEventUID, touchVPosX, touchVPosY);
++ 		}
++ 		touchVPosX = -1;
++ 		touchVPosY = -1;
++ 		touchEventUID = -1;
++ 		currentHotbarSlotTouch = -1;
++ 		hotbarSlotTouchStart = -1l;
++ 		hotbarSlotTouchAlreadySelected = false;
++ 	}
++ 
++ 	public boolean isTouchOverlapEagler(int uid, int tx, int ty) {
++ 		if (touchEventUID == uid) {
++ 			return true;
++ 		}
++ 		ty = mc.displayHeight - ty - 1;
++ 		tx = applyTouchHotbarTransformX(tx, false);
++ 		ty = applyTouchHotbarTransformY(ty, false);
++ 		return (tx >= hotbarAreaX && ty >= hotbarAreaY && tx < hotbarAreaX + hotbarAreaW
++ 				&& ty < hotbarAreaY + hotbarAreaH)
++ 				|| (tx >= interactButtonX && ty >= interactButtonY && tx < interactButtonX + interactButtonW
++ 						&& ty < interactButtonY + interactButtonH);
++ 	}
++ 
+
 > EOF
diff --git a/patches/minecraft/net/minecraft/client/gui/GuiIngameMenu.edit.java b/patches/minecraft/net/minecraft/client/gui/GuiIngameMenu.edit.java
index dcf9da2d..83439317 100644
--- a/patches/minecraft/net/minecraft/client/gui/GuiIngameMenu.edit.java
+++ b/patches/minecraft/net/minecraft/client/gui/GuiIngameMenu.edit.java
@@ -5,10 +5,14 @@
 # Version: 1.0
 # Author: lax1dude
 
-> CHANGE  2 : 14  @  2 : 9
+> CHANGE  2 : 21  @  2 : 9
 
 ~ import net.lax1dude.eaglercraft.v1_8.EagRuntime;
 ~ import net.lax1dude.eaglercraft.v1_8.Mouse;
+~ import net.lax1dude.eaglercraft.v1_8.PauseMenuCustomizeState;
+~ import net.lax1dude.eaglercraft.v1_8.minecraft.GuiButtonWithStupidIcons;
+~ import net.lax1dude.eaglercraft.v1_8.notifications.GuiButtonNotifBell;
+~ import net.lax1dude.eaglercraft.v1_8.notifications.GuiScreenNotifications;
 ~ import net.lax1dude.eaglercraft.v1_8.opengl.GlStateManager;
 ~ import net.lax1dude.eaglercraft.v1_8.sp.SingleplayerServerController;
 ~ import net.lax1dude.eaglercraft.v1_8.sp.gui.GuiScreenLANInfo;
@@ -17,6 +21,9 @@
 ~ import net.lax1dude.eaglercraft.v1_8.sp.lan.LANServerController;
 ~ import net.lax1dude.eaglercraft.v1_8.update.GuiUpdateCheckerOverlay;
 ~ import net.lax1dude.eaglercraft.v1_8.voice.GuiVoiceMenu;
+~ import net.lax1dude.eaglercraft.v1_8.webview.GuiScreenPhishingWaring;
+~ import net.lax1dude.eaglercraft.v1_8.webview.GuiScreenRecieveServerInfo;
+~ import net.lax1dude.eaglercraft.v1_8.webview.GuiScreenServerInfo;
 ~ import net.minecraft.client.Minecraft;
 ~ import net.minecraft.client.audio.PositionedSoundRecord;
 
@@ -28,7 +35,7 @@
 
 > DELETE  2  @  2 : 4
 
-> INSERT  1 : 15  @  1
+> INSERT  1 : 16  @  1
 
 + 	private GuiButton lanButton;
 + 
@@ -36,6 +43,7 @@
 + 
 + 	private GuiUpdateCheckerOverlay updateCheckerOverlay;
 + 	private GuiVoiceMenu voiceMenu;
++ 	private GuiButtonNotifBell notifBellButton;
 + 
 + 	public GuiIngameMenu() {
 + 		updateCheckerOverlay = new GuiUpdateCheckerOverlay(true, this);
@@ -51,14 +59,56 @@
 
 + 		this.updateCheckerOverlay.setResolution(mc, width, height);
 
-> CHANGE  12 : 14  @  12 : 15
+> CHANGE  2 : 6  @  2 : 4
 
-~ 		this.buttonList.add(lanButton = new GuiButton(7, this.width / 2 + 2, this.height / 4 + 96 + b0, 98, 20,
-~ 				I18n.format(LANServerController.isLANOpen() ? "menu.closeLan" : "menu.openToLan", new Object[0])));
+~ 		this.buttonList.add(new GuiButtonWithStupidIcons(1, this.width / 2 - 100, this.height / 4 + 120 + b0,
+~ 				I18n.format("menu.returnToMenu", new Object[0]), PauseMenuCustomizeState.icon_disconnect_L,
+~ 				PauseMenuCustomizeState.icon_disconnect_L_aspect, PauseMenuCustomizeState.icon_disconnect_R,
+~ 				PauseMenuCustomizeState.icon_disconnect_R_aspect));
 
-> CHANGE  4 : 9  @  4 : 5
+> INSERT  2 : 6  @  2
 
++ 			if (this.mc.thePlayer != null && this.mc.thePlayer.sendQueue.getEaglerMessageProtocol().ver >= 4) {
++ 				this.buttonList.add(notifBellButton = new GuiButtonNotifBell(11, width - 22, height - 22));
++ 				notifBellButton.setUnread(mc.thePlayer.sendQueue.getNotifManager().getUnread());
++ 			}
+
+> CHANGE  2 : 40  @  2 : 14
+
+~ 		this.buttonList.add(new GuiButtonWithStupidIcons(4, this.width / 2 - 100, this.height / 4 + 24 + b0,
+~ 				I18n.format("menu.returnToGame", new Object[0]), PauseMenuCustomizeState.icon_backToGame_L,
+~ 				PauseMenuCustomizeState.icon_backToGame_L_aspect, PauseMenuCustomizeState.icon_backToGame_R,
+~ 				PauseMenuCustomizeState.icon_backToGame_R_aspect));
+~ 		this.buttonList.add(new GuiButtonWithStupidIcons(0, this.width / 2 - 100, this.height / 4 + 96 + b0, 98, 20,
+~ 				I18n.format("menu.options", new Object[0]), PauseMenuCustomizeState.icon_options_L,
+~ 				PauseMenuCustomizeState.icon_options_L_aspect, PauseMenuCustomizeState.icon_options_R,
+~ 				PauseMenuCustomizeState.icon_options_R_aspect));
+~ 		this.buttonList
+~ 				.add(lanButton = new GuiButtonWithStupidIcons(7, this.width / 2 + 2, this.height / 4 + 96 + b0, 98, 20,
+~ 						I18n.format(LANServerController.isLANOpen() ? "menu.closeLan" : "menu.openToLan",
+~ 								new Object[0]),
+~ 						PauseMenuCustomizeState.icon_discord_L, PauseMenuCustomizeState.icon_discord_L_aspect,
+~ 						PauseMenuCustomizeState.icon_discord_R, PauseMenuCustomizeState.icon_discord_R_aspect));
+~ 		this.buttonList.add(new GuiButtonWithStupidIcons(5, this.width / 2 - 100, this.height / 4 + 48 + b0, 98, 20,
+~ 				I18n.format("gui.achievements", new Object[0]), PauseMenuCustomizeState.icon_achievements_L,
+~ 				PauseMenuCustomizeState.icon_achievements_L_aspect, PauseMenuCustomizeState.icon_achievements_R,
+~ 				PauseMenuCustomizeState.icon_achievements_R_aspect));
+~ 		this.buttonList.add(new GuiButtonWithStupidIcons(6, this.width / 2 + 2, this.height / 4 + 48 + b0, 98, 20,
+~ 				I18n.format("gui.stats", new Object[0]), PauseMenuCustomizeState.icon_statistics_L,
+~ 				PauseMenuCustomizeState.icon_statistics_L_aspect, PauseMenuCustomizeState.icon_statistics_R,
+~ 				PauseMenuCustomizeState.icon_statistics_R_aspect));
 ~ 		lanButton.enabled = SingleplayerServerController.isWorldRunning();
+~ 		if (PauseMenuCustomizeState.discordButtonMode != PauseMenuCustomizeState.DISCORD_MODE_NONE) {
+~ 			lanButton.enabled = true;
+~ 			lanButton.id = 8;
+~ 			lanButton.displayString = "" + PauseMenuCustomizeState.discordButtonText;
+~ 		}
+~ 		if (PauseMenuCustomizeState.serverInfoMode != PauseMenuCustomizeState.DISCORD_MODE_NONE) {
+~ 			this.buttonList.add(new GuiButtonWithStupidIcons(9, this.width / 2 - 100, this.height / 4 + 72 + b0,
+~ 					PauseMenuCustomizeState.serverInfoButtonText, PauseMenuCustomizeState.icon_serverInfo_L,
+~ 					PauseMenuCustomizeState.icon_serverInfo_L_aspect, PauseMenuCustomizeState.icon_serverInfo_R,
+~ 					PauseMenuCustomizeState.icon_serverInfo_R_aspect));
+~ 		}
 ~ 		if (!hasSentAutoSave) {
 ~ 			hasSentAutoSave = true;
 ~ 			SingleplayerServerController.autoSave();
@@ -80,7 +130,7 @@
 
 ~ 				this.mc.shutdownIntegratedServer(new GuiMultiplayer(new GuiMainMenu()));
 
-> CHANGE  16 : 30  @  16 : 17
+> CHANGE  16 : 69  @  16 : 17
 
 ~ 			if (!LANServerController.supported()) {
 ~ 				mc.displayGuiScreen(new GuiScreenLANNotSupported(this));
@@ -96,8 +146,47 @@
 ~ 						new GuiShareToLan(this, this.mc.playerController.getCurrentGameType().getName())));
 ~ 			}
 ~ 			break;
+~ 		case 8:
+~ 			if (PauseMenuCustomizeState.discordButtonMode == PauseMenuCustomizeState.DISCORD_MODE_INVITE_URL
+~ 					&& PauseMenuCustomizeState.discordInviteURL != null) {
+~ 				EagRuntime.openLink(PauseMenuCustomizeState.discordInviteURL);
+~ 			}
+~ 			break;
+~ 		case 9:
+~ 			switch (PauseMenuCustomizeState.serverInfoMode) {
+~ 			case PauseMenuCustomizeState.SERVER_INFO_MODE_EXTERNAL_URL:
+~ 				if (PauseMenuCustomizeState.serverInfoURL != null) {
+~ 					EagRuntime.openLink(PauseMenuCustomizeState.serverInfoURL);
+~ 				}
+~ 				break;
+~ 			case PauseMenuCustomizeState.SERVER_INFO_MODE_SHOW_EMBED_OVER_HTTP:
+~ 				if (PauseMenuCustomizeState.serverInfoURL != null) {
+~ 					GuiScreen screen = GuiScreenServerInfo.createForCurrentState(this,
+~ 							PauseMenuCustomizeState.serverInfoURL);
+~ 					if (!this.mc.gameSettings.hasHiddenPhishWarning && !GuiScreenPhishingWaring.hasShownMessage) {
+~ 						screen = new GuiScreenPhishingWaring(screen);
+~ 					}
+~ 					this.mc.displayGuiScreen(screen);
+~ 				}
+~ 				break;
+~ 			case PauseMenuCustomizeState.SERVER_INFO_MODE_SHOW_EMBED_OVER_WS:
+~ 				if (PauseMenuCustomizeState.serverInfoHash != null) {
+~ 					GuiScreen screen = new GuiScreenRecieveServerInfo(this, PauseMenuCustomizeState.serverInfoHash);
+~ 					if (!this.mc.gameSettings.hasHiddenPhishWarning && !GuiScreenPhishingWaring.hasShownMessage) {
+~ 						screen = new GuiScreenPhishingWaring(screen);
+~ 					}
+~ 					this.mc.displayGuiScreen(screen);
+~ 				}
+~ 				break;
+~ 			default:
+~ 				break;
+~ 			}
+~ 			break;
+~ 		case 11:
+~ 			this.mc.displayGuiScreen(new GuiScreenNotifications(this));
+~ 			break;
 
-> CHANGE  6 : 13  @  6 : 7
+> CHANGE  6 : 16  @  6 : 7
 
 ~ 		if (EagRuntime.getConfiguration().isAllowVoiceClient()
 ~ 				&& (!mc.isSingleplayer() || LANServerController.isHostingLAN())) {
@@ -106,13 +195,34 @@
 ~ 		if (Mouse.isActuallyGrabbed()) {
 ~ 			Mouse.setGrabbed(false);
 ~ 		}
+~ 		if (notifBellButton != null && mc.thePlayer != null) {
+~ 			notifBellButton.setUnread(mc.thePlayer.sendQueue.getNotifManager().getUnread());
+~ 		}
 
-> CHANGE  4 : 5  @  4 : 5
-
-~ 		this.drawCenteredString(this.fontRendererObj, I18n.format("menu.game", new Object[0]), this.width / 2, 20,
-
-> CHANGE  1 : 55  @  1 : 2
+> CHANGE  4 : 80  @  4 : 7
 
+~ 		String titleStr = I18n.format("menu.game", new Object[0]);
+~ 		int titleStrWidth = fontRendererObj.getStringWidth(titleStr);
+~ 		this.drawString(this.fontRendererObj, titleStr, (this.width - titleStrWidth) / 2, 20, 16777215);
+~ 		if (PauseMenuCustomizeState.icon_title_L != null) {
+~ 			mc.getTextureManager().bindTexture(PauseMenuCustomizeState.icon_title_L);
+~ 			GlStateManager.pushMatrix();
+~ 			GlStateManager.translate(
+~ 					(this.width - titleStrWidth) / 2 - 6 - 16 * PauseMenuCustomizeState.icon_title_L_aspect, 16, 0.0f);
+~ 			float f2 = 16.0f / 256.0f;
+~ 			GlStateManager.scale(f2 * PauseMenuCustomizeState.icon_title_L_aspect, f2, f2);
+~ 			this.drawTexturedModalRect(0, 0, 0, 0, 256, 256);
+~ 			GlStateManager.popMatrix();
+~ 		}
+~ 		if (PauseMenuCustomizeState.icon_title_R != null) {
+~ 			mc.getTextureManager().bindTexture(PauseMenuCustomizeState.icon_title_L);
+~ 			GlStateManager.pushMatrix();
+~ 			GlStateManager.translate((this.width - titleStrWidth) / 2 + titleStrWidth + 6, 16, 0.0f);
+~ 			float f2 = 16.0f / 256.0f;
+~ 			GlStateManager.scale(f2 * PauseMenuCustomizeState.icon_title_R_aspect, f2, f2);
+~ 			this.drawTexturedModalRect(0, 0, 0, 0, 256, 256);
+~ 			GlStateManager.popMatrix();
+~ 		}
 ~ 
 ~ 		this.updateCheckerOverlay.drawScreen(i, j, f);
 ~ 
@@ -168,7 +278,7 @@
 ~ 		} catch (GuiVoiceMenu.AbortedException ex) {
 ~ 		}
 
-> INSERT  1 : 80  @  1
+> INSERT  1 : 84  @  1
 
 + 
 + 	protected void keyTyped(char par1, int par2) {
@@ -249,5 +359,9 @@
 + 		} catch (GuiVoiceMenu.AbortedException ex) {
 + 		}
 + 	}
++ 
++ 	protected boolean isPartOfPauseMenu() {
++ 		return true;
++ 	}
 
 > EOF
diff --git a/patches/minecraft/net/minecraft/client/gui/GuiKeyBindingList.edit.java b/patches/minecraft/net/minecraft/client/gui/GuiKeyBindingList.edit.java
index ba289f0e..3ed0d132 100644
--- a/patches/minecraft/net/minecraft/client/gui/GuiKeyBindingList.edit.java
+++ b/patches/minecraft/net/minecraft/client/gui/GuiKeyBindingList.edit.java
@@ -5,16 +5,21 @@
 # Version: 1.0
 # Author: lax1dude
 
-> INSERT  3 : 5  @  3
+> INSERT  3 : 6  @  3
 
 + 
 + import net.lax1dude.eaglercraft.v1_8.ArrayUtils;
++ import net.lax1dude.eaglercraft.v1_8.PointerInputAbstraction;
 
 > DELETE  1  @  1 : 4
 
 > DELETE  4  @  4 : 5
 
-> CHANGE  17 : 19  @  17 : 18
+> CHANGE  8 : 9  @  8 : 9
+
+~ 		super(mcIn, controls.width, controls.height, 66, controls.height - 32, 20);
+
+> CHANGE  8 : 10  @  8 : 9
 
 ~ 		for (int l = 0; l < akeybinding.length; ++l) {
 ~ 			KeyBinding keybinding = akeybinding[l];
@@ -25,4 +30,27 @@
 ~ 				for (int m = 0; m < kb.length; ++m) {
 ~ 					KeyBinding keybindingx = kb[m];
 
+> CHANGE  19 : 24  @  19 : 20
+
+~ 			if (var4 != 0 && var4 != 12345)
+~ 				return false;
+~ 			boolean touchMode = PointerInputAbstraction.isTouchMode();
+~ 			if ((!touchMode || (this.btnChangeKeyBinding.isSliderTouchEvents() == (var4 == 12345)))
+~ 					&& this.btnChangeKeyBinding.mousePressed(GuiKeyBindingList.this.mc, i, j)) {
+
+> CHANGE  2 : 4  @  2 : 3
+
+~ 			} else if ((!touchMode || (this.btnReset.isSliderTouchEvents() == (var4 == 12345)))
+~ 					&& this.btnReset.mousePressed(GuiKeyBindingList.this.mc, i, j)) {
+
+> CHANGE  10 : 17  @  10 : 12
+
+~ 			if (var4 != 0 && var4 != 12345)
+~ 				return;
+~ 			boolean touchMode = PointerInputAbstraction.isTouchMode();
+~ 			if (!touchMode || (this.btnChangeKeyBinding.isSliderTouchEvents() == (var4 == 12345)))
+~ 				this.btnChangeKeyBinding.mouseReleased(i, j);
+~ 			if (!touchMode || (this.btnReset.isSliderTouchEvents() == (var4 == 12345)))
+~ 				this.btnReset.mouseReleased(i, j);
+
 > EOF
diff --git a/patches/minecraft/net/minecraft/client/gui/GuiLanguage.edit.java b/patches/minecraft/net/minecraft/client/gui/GuiLanguage.edit.java
index 41dd1b8d..3ed88ce3 100644
--- a/patches/minecraft/net/minecraft/client/gui/GuiLanguage.edit.java
+++ b/patches/minecraft/net/minecraft/client/gui/GuiLanguage.edit.java
@@ -16,11 +16,20 @@
 
 > DELETE  1  @  1 : 6
 
-> CHANGE  34 : 35  @  34 : 35
+> CHANGE  34 : 40  @  34 : 35
 
+~ 	public void handleTouchInput() throws IOException {
+~ 		super.handleTouchInput();
+~ 		this.list.handleTouchInput();
+~ 	}
+~ 
 ~ 	protected void actionPerformed(GuiButton parGuiButton) {
 
-> INSERT  56 : 57  @  56
+> CHANGE  12 : 13  @  12 : 13
+
+~ 					ScaledResolution scaledresolution = this.mc.scaledResolution;
+
+> INSERT  43 : 44  @  43
 
 + 			this.mc.loadingScreen.eaglerShowRefreshResources();
 
diff --git a/patches/minecraft/net/minecraft/client/gui/GuiMainMenu.edit.java b/patches/minecraft/net/minecraft/client/gui/GuiMainMenu.edit.java
index 9c5354c8..713bced6 100644
--- a/patches/minecraft/net/minecraft/client/gui/GuiMainMenu.edit.java
+++ b/patches/minecraft/net/minecraft/client/gui/GuiMainMenu.edit.java
@@ -182,16 +182,15 @@
 
 ~ 	protected void keyTyped(char parChar1, int parInt1) {
 
-> CHANGE  3 : 9  @  3 : 7
+> CHANGE  3 : 8  @  3 : 6
 
 ~ 		if (viewportTexture == null) {
 ~ 			viewportTexture = new DynamicTexture(256, 256);
 ~ 			backgroundTexture = this.mc.getTextureManager().getDynamicTextureLocation("background", viewportTexture);
 ~ 		}
 ~ 		this.updateCheckerOverlay.setResolution(mc, width, height);
-~ 		Calendar calendar = EagRuntime.getLocaleCalendar();
 
-> DELETE  9  @  9 : 10
+> DELETE  10  @  10 : 11
 
 > INSERT  1 : 8  @  1
 
diff --git a/patches/minecraft/net/minecraft/client/gui/GuiMultiplayer.edit.java b/patches/minecraft/net/minecraft/client/gui/GuiMultiplayer.edit.java
index ea4be681..215cb262 100644
--- a/patches/minecraft/net/minecraft/client/gui/GuiMultiplayer.edit.java
+++ b/patches/minecraft/net/minecraft/client/gui/GuiMultiplayer.edit.java
@@ -10,12 +10,14 @@
 + import java.io.IOException;
 + 
 
-> CHANGE  2 : 16  @  2 : 15
+> CHANGE  2 : 18  @  2 : 15
 
 ~ 
+~ import net.lax1dude.eaglercraft.v1_8.EagRuntime;
 ~ import net.lax1dude.eaglercraft.v1_8.EaglerXBungeeVersion;
 ~ import net.lax1dude.eaglercraft.v1_8.Keyboard;
 ~ import net.lax1dude.eaglercraft.v1_8.Mouse;
+~ import net.lax1dude.eaglercraft.v1_8.cookie.ServerCookieDataStore;
 ~ import net.lax1dude.eaglercraft.v1_8.internal.EnumCursorType;
 ~ import net.lax1dude.eaglercraft.v1_8.log4j.LogManager;
 ~ import net.lax1dude.eaglercraft.v1_8.log4j.Logger;
@@ -80,7 +82,15 @@
 + 				lanServerList.forceRefresh();
 + 			}
 
-> CHANGE  32 : 35  @  32 : 36
+> INSERT  12 : 17  @  12
+
++ 	public void handleTouchInput() throws IOException {
++ 		super.handleTouchInput();
++ 		this.serverListSelector.handleTouchInput();
++ 	}
++ 
+
+> CHANGE  20 : 23  @  20 : 24
 
 ~ 		this.savedServerList.updateServerPing();
 ~ 		if (lanServerList.update()) {
@@ -111,7 +121,7 @@
 
 > CHANGE  3 : 8  @  3 : 4
 
-~ 				long millis = System.currentTimeMillis();
+~ 				long millis = EagRuntime.steadyTimeMillis();
 ~ 				if (millis - lastRefreshCommit > 700l) {
 ~ 					lastRefreshCommit = millis;
 ~ 					this.refreshServerList();
@@ -123,23 +133,35 @@
 
 > CHANGE  14 : 19  @  14 : 16
 
-~ 			long millis = System.currentTimeMillis();
+~ 			long millis = EagRuntime.steadyTimeMillis();
 ~ 			if (millis - lastRefreshCommit > 700l) {
 ~ 				lastRefreshCommit = millis;
 ~ 				this.refreshServerList();
 ~ 			}
 
-> CHANGE  15 : 20  @  15 : 17
+> INSERT  10 : 13  @  10
 
-~ 			long millis = System.currentTimeMillis();
++ 				if (!this.selectedServer.enableCookies) {
++ 					ServerCookieDataStore.clearCookie(this.selectedServer.serverIP);
++ 				}
+
+> CHANGE  5 : 10  @  5 : 7
+
+~ 			long millis = EagRuntime.steadyTimeMillis();
 ~ 			if (millis - lastRefreshCommit > 700l) {
 ~ 				lastRefreshCommit = millis;
 ~ 				this.refreshServerList();
 ~ 			}
 
-> CHANGE  10 : 15  @  10 : 12
+> INSERT  6 : 9  @  6
 
-~ 			long millis = System.currentTimeMillis();
++ 				if (serverdata.enableCookies && !this.selectedServer.enableCookies) {
++ 					ServerCookieDataStore.clearCookie(this.selectedServer.serverIP);
++ 				}
+
+> CHANGE  4 : 9  @  4 : 6
+
+~ 			long millis = EagRuntime.steadyTimeMillis();
 ~ 			if (millis - lastRefreshCommit > 700l) {
 ~ 				lastRefreshCommit = millis;
 ~ 				this.refreshServerList();
@@ -171,7 +193,11 @@
 + 		relaysButton.drawScreen(i, j);
 + 		drawPluginDownloadLink(i, j);
 
-> INSERT  3 : 4  @  3
+> INSERT  2 : 3  @  2
+
++ 			GlStateManager.disableLighting();
+
+> INSERT  1 : 2  @  1
 
 + 	}
 
diff --git a/patches/minecraft/net/minecraft/client/gui/GuiNewChat.edit.java b/patches/minecraft/net/minecraft/client/gui/GuiNewChat.edit.java
index fb3bda12..f0c9e36d 100644
--- a/patches/minecraft/net/minecraft/client/gui/GuiNewChat.edit.java
+++ b/patches/minecraft/net/minecraft/client/gui/GuiNewChat.edit.java
@@ -28,4 +28,8 @@
 
 ~ 			this.field_146253_i.add(0, new ChatLine(parInt2, (IChatComponent) list.get(j), parInt1));
 
+> CHANGE  62 : 63  @  62 : 63
+
+~ 			ScaledResolution scaledresolution = mc.scaledResolution;
+
 > EOF
diff --git a/patches/minecraft/net/minecraft/client/gui/GuiOptionSlider.edit.java b/patches/minecraft/net/minecraft/client/gui/GuiOptionSlider.edit.java
index 20d8a9ce..7e726ab7 100644
--- a/patches/minecraft/net/minecraft/client/gui/GuiOptionSlider.edit.java
+++ b/patches/minecraft/net/minecraft/client/gui/GuiOptionSlider.edit.java
@@ -11,4 +11,22 @@
 
 > DELETE  1  @  1 : 3
 
+> CHANGE  4 : 5  @  4 : 5
+
+~ 	public float sliderValue;
+
+> INSERT  21 : 25  @  21
+
++ 	public GameSettings.Options getEnumOptions() {
++ 		return options;
++ 	}
++ 
+
+> INSERT  40 : 44  @  40
+
++ 
++ 	public boolean isSliderTouchEvents() {
++ 		return true;
++ 	}
+
 > EOF
diff --git a/patches/minecraft/net/minecraft/client/gui/GuiOptions.edit.java b/patches/minecraft/net/minecraft/client/gui/GuiOptions.edit.java
index 726b582c..d81dd46b 100644
--- a/patches/minecraft/net/minecraft/client/gui/GuiOptions.edit.java
+++ b/patches/minecraft/net/minecraft/client/gui/GuiOptions.edit.java
@@ -5,18 +5,26 @@
 # Version: 1.0
 # Author: lax1dude
 
-> CHANGE  2 : 13  @  2 : 3
+> CHANGE  2 : 21  @  2 : 3
 
 ~ import net.lax1dude.eaglercraft.v1_8.EagRuntime;
 ~ import net.lax1dude.eaglercraft.v1_8.Mouse;
+~ import net.lax1dude.eaglercraft.v1_8.boot_menu.GuiScreenEnterBootMenu;
+~ import net.lax1dude.eaglercraft.v1_8.cookie.GuiScreenRevokeSessionToken;
+~ import net.lax1dude.eaglercraft.v1_8.cookie.ServerCookieDataStore;
 ~ import net.lax1dude.eaglercraft.v1_8.internal.EnumCursorType;
 ~ import net.lax1dude.eaglercraft.v1_8.internal.EnumPlatformType;
+~ import net.lax1dude.eaglercraft.v1_8.internal.KeyboardConstants;
 ~ import net.lax1dude.eaglercraft.v1_8.minecraft.EaglerFolderResourcePack;
+~ import net.lax1dude.eaglercraft.v1_8.minecraft.GuiScreenGenericErrorMessage;
 ~ import net.lax1dude.eaglercraft.v1_8.opengl.GlStateManager;
 ~ import net.lax1dude.eaglercraft.v1_8.opengl.ext.deferred.EaglerDeferredPipeline;
 ~ import net.lax1dude.eaglercraft.v1_8.opengl.ext.deferred.gui.GuiShaderConfig;
 ~ import net.lax1dude.eaglercraft.v1_8.opengl.ext.deferred.gui.GuiShadersNotSupported;
 ~ import net.lax1dude.eaglercraft.v1_8.profile.GuiScreenImportExportProfile;
+~ import net.lax1dude.eaglercraft.v1_8.recording.GuiScreenRecordingNote;
+~ import net.lax1dude.eaglercraft.v1_8.recording.GuiScreenRecordingSettings;
+~ import net.lax1dude.eaglercraft.v1_8.recording.ScreenRecordingController;
 ~ import net.lax1dude.eaglercraft.v1_8.sp.SingleplayerServerController;
 
 > DELETE  1  @  1 : 21
@@ -41,11 +49,12 @@
 
 ~ 				I18n.format("shaders.gui.optionsButton")));
 
-> CHANGE  2 : 5  @  2 : 4
+> CHANGE  2 : 6  @  2 : 4
 
+~ 		boolean support = ScreenRecordingController.isSupported();
 ~ 		this.buttonList.add(broadcastSettings = new GuiButton(107, this.width / 2 + 5, this.height / 6 + 72 - 6, 150,
-~ 				20, I18n.format(EagRuntime.getRecText(), new Object[0])));
-~ 		broadcastSettings.enabled = EagRuntime.recSupported();
+~ 				20, I18n.format(support ? "options.screenRecording.button" : "options.screenRecording.unsupported")));
+~ 		broadcastSettings.enabled = support;
 
 > CHANGE  8 : 10  @  8 : 9
 
@@ -87,24 +96,29 @@
 
 > DELETE  22  @  22 : 27
 
-> CHANGE  16 : 18  @  16 : 23
+> CHANGE  16 : 22  @  16 : 22
 
-~ 				EagRuntime.toggleRec();
-~ 				broadcastSettings.displayString = I18n.format(EagRuntime.getRecText(), new Object[0]);
+~ 				if (ScreenRecordingController.isSupported()) {
+~ 					GuiScreen screen = new GuiScreenRecordingSettings(this);
+~ 					if (!GuiScreenRecordingNote.hasShown) {
+~ 						screen = new GuiScreenRecordingNote(screen);
+~ 					}
+~ 					this.mc.displayGuiScreen(screen);
 
-> INSERT  2 : 5  @  2
+> INSERT  3 : 6  @  3
 
 + 			if (parGuiButton.id == 104) {
 + 				EagRuntime.showDebugConsole();
 + 			}
 
-> INSERT  6 : 24  @  6
+> INSERT  6 : 49  @  6
 
 + 
 + 		if (mc.theWorld == null && !EagRuntime.getConfiguration().isDemo()) {
 + 			GlStateManager.pushMatrix();
 + 			GlStateManager.scale(0.75f, 0.75f, 0.75f);
 + 			GlStateManager.color(1.0f, 1.0f, 1.0f, 1.0f);
++ 
 + 			String text = I18n.format("editProfile.importExport");
 + 
 + 			int w = mc.fontRendererObj.getStringWidth(text);
@@ -118,9 +132,43 @@
 + 			GlStateManager.popMatrix();
 + 		}
 + 
++ 		if (mc.theWorld == null && EagRuntime.getConfiguration().isAllowBootMenu()) {
++ 			drawCenteredString(mc.fontRendererObj, I18n.format("options.pressDeleteText"), width / 2, height / 6 + 22,
++ 					11184810);
++ 		}
++ 
++ 		if (EagRuntime.getConfiguration().isEnableServerCookies() && mc.thePlayer == null) {
++ 			GlStateManager.pushMatrix();
++ 			GlStateManager.scale(0.75f, 0.75f, 0.75f);
++ 			GlStateManager.color(1.0f, 1.0f, 1.0f, 1.0f);
++ 
++ 			String text = I18n.format("revokeSessionToken.button");
++ 
++ 			int w = mc.fontRendererObj.getStringWidth(text);
++ 			boolean hover = i > width - 5 - (w + 5) * 3 / 4 && j > 1 && i < width - 2 && j < 12;
++ 			if (hover) {
++ 				Mouse.showCursor(EnumCursorType.HAND);
++ 			}
++ 
++ 			drawString(mc.fontRendererObj, EnumChatFormatting.UNDERLINE + text, (width - 1) * 4 / 3 - w - 5, 5,
++ 					hover ? 0xFFEEEE22 : 0xFFCCCCCC);
++ 
++ 			GlStateManager.popMatrix();
++ 		}
++ 
 
-> INSERT  2 : 14  @  2
+> INSERT  2 : 35  @  2
 
++ 
++ 	@Override
++ 	protected void keyTyped(char parChar1, int parInt1) {
++ 		super.keyTyped(parChar1, parInt1);
++ 		if (parInt1 == KeyboardConstants.KEY_DELETE || parInt1 == KeyboardConstants.KEY_BACK) {
++ 			if (mc.theWorld == null && EagRuntime.getConfiguration().isAllowBootMenu()) {
++ 				mc.displayGuiScreen(new GuiScreenEnterBootMenu(this));
++ 			}
++ 		}
++ 	}
 + 
 + 	protected void mouseClicked(int mx, int my, int button) {
 + 		super.mouseClicked(mx, my, button);
@@ -132,6 +180,17 @@
 + 						.playSound(PositionedSoundRecord.create(new ResourceLocation("gui.button.press"), 1.0F));
 + 			}
 + 		}
++ 		if (EagRuntime.getConfiguration().isEnableServerCookies() && mc.thePlayer == null) {
++ 			int w = mc.fontRendererObj.getStringWidth(I18n.format("revokeSessionToken.button"));
++ 			if (mx > width - 5 - (w + 5) * 3 / 4 && my > 1 && mx < width - 2 && my < 12) {
++ 				ServerCookieDataStore.flush();
++ 				mc.displayGuiScreen(ServerCookieDataStore.numRevokable() == 0
++ 						? new GuiScreenGenericErrorMessage("errorNoSessions.title", "errorNoSessions.desc", this)
++ 						: new GuiScreenRevokeSessionToken(this));
++ 				mc.getSoundHandler()
++ 						.playSound(PositionedSoundRecord.create(new ResourceLocation("gui.button.press"), 1.0F));
++ 			}
++ 		}
 + 	}
 
 > EOF
diff --git a/patches/minecraft/net/minecraft/client/gui/GuiOptionsRowList.edit.java b/patches/minecraft/net/minecraft/client/gui/GuiOptionsRowList.edit.java
index ad47b72c..a5f47961 100644
--- a/patches/minecraft/net/minecraft/client/gui/GuiOptionsRowList.edit.java
+++ b/patches/minecraft/net/minecraft/client/gui/GuiOptionsRowList.edit.java
@@ -7,12 +7,88 @@
 
 > DELETE  2  @  2 : 3
 
-> INSERT  1 : 4  @  1
+> INSERT  1 : 5  @  1
 
 + 
 + import com.google.common.collect.Lists;
 + 
++ import net.lax1dude.eaglercraft.v1_8.PointerInputAbstraction;
 
 > DELETE  1  @  1 : 5
 
+> CHANGE  72 : 77  @  72 : 73
+
+~ 			if (var4 != 0 && var4 != 12345)
+~ 				return false;
+~ 			boolean touchMode = PointerInputAbstraction.isTouchMode();
+~ 			if ((!touchMode || (this.field_148323_b.isSliderTouchEvents() == (var4 == 12345)))
+~ 					&& this.field_148323_b.mousePressed(this.field_148325_a, i, j)) {
+
+> CHANGE  8 : 11  @  8 : 9
+
+~ 			} else if (this.field_148324_c != null
+~ 					&& (!touchMode || (this.field_148324_c.isSliderTouchEvents() == (var4 == 12345)))
+~ 					&& this.field_148324_c.mousePressed(this.field_148325_a, i, j)) {
+
+> CHANGE  14 : 19  @  14 : 15
+
+~ 			if (var4 != 0 && var4 != 12345)
+~ 				return;
+~ 			boolean touchMode = PointerInputAbstraction.isTouchMode();
+~ 			if (this.field_148323_b != null
+~ 					&& (!touchMode || (this.field_148323_b.isSliderTouchEvents() == (var4 == 12345)))) {
+
+> CHANGE  3 : 5  @  3 : 4
+
+~ 			if (this.field_148324_c != null
+~ 					&& (!touchMode || (this.field_148324_c.isSliderTouchEvents() == (var4 == 12345)))) {
+
+> INSERT  8 : 53  @  8
+
++ 
++ 	public GuiOptionButton getButtonFor(GameSettings.Options enumOption) {
++ 		for (Row r : field_148184_k) {
++ 			if (r.field_148323_b != null) {
++ 				if (r.field_148323_b instanceof GuiOptionButton) {
++ 					GuiOptionButton btn = (GuiOptionButton) r.field_148323_b;
++ 					if (btn.returnEnumOptions() == enumOption) {
++ 						return btn;
++ 					}
++ 				}
++ 			}
++ 			if (r.field_148324_c != null) {
++ 				if (r.field_148324_c instanceof GuiOptionButton) {
++ 					GuiOptionButton btn = (GuiOptionButton) r.field_148324_c;
++ 					if (btn.returnEnumOptions() == enumOption) {
++ 						return btn;
++ 					}
++ 				}
++ 			}
++ 		}
++ 		return null;
++ 	}
++ 
++ 	public GuiOptionSlider getSliderFor(GameSettings.Options enumOption) {
++ 		for (Row r : field_148184_k) {
++ 			if (r.field_148323_b != null) {
++ 				if (r.field_148323_b instanceof GuiOptionSlider) {
++ 					GuiOptionSlider btn = (GuiOptionSlider) r.field_148323_b;
++ 					if (btn.getEnumOptions() == enumOption) {
++ 						return btn;
++ 					}
++ 				}
++ 			}
++ 			if (r.field_148324_c != null) {
++ 				if (r.field_148324_c instanceof GuiOptionSlider) {
++ 					GuiOptionSlider btn = (GuiOptionSlider) r.field_148324_c;
++ 					if (btn.getEnumOptions() == enumOption) {
++ 						return btn;
++ 					}
++ 				}
++ 			}
++ 		}
++ 		return null;
++ 	}
++ 
+
 > EOF
diff --git a/patches/minecraft/net/minecraft/client/gui/GuiOverlayDebug.edit.java b/patches/minecraft/net/minecraft/client/gui/GuiOverlayDebug.edit.java
index 5e45371f..b30c05d1 100644
--- a/patches/minecraft/net/minecraft/client/gui/GuiOverlayDebug.edit.java
+++ b/patches/minecraft/net/minecraft/client/gui/GuiOverlayDebug.edit.java
@@ -18,8 +18,11 @@
 
 + import java.util.Locale;
 
-> INSERT  1 : 14  @  1
+> INSERT  1 : 17  @  1
 
++ 
++ import org.apache.commons.lang3.StringUtils;
++ 
 + import java.util.TimeZone;
 + 
 + import com.google.common.base.Strings;
@@ -52,14 +55,11 @@
 
 + 	public int playerOffset = 0;
 
-> INSERT  7 : 10  @  7
-
-+ 		playerOffset = 0;
-+ 		int ww = scaledResolutionIn.getScaledWidth();
-+ 		int hh = scaledResolutionIn.getScaledHeight();
-
-> CHANGE  1 : 22  @  1 : 7
+> CHANGE  7 : 31  @  7 : 14
 
+~ 		playerOffset = 0;
+~ 		int ww = scaledResolutionIn.getScaledWidth();
+~ 		int hh = scaledResolutionIn.getScaledHeight();
 ~ 		if (this.mc.gameSettings.showDebugInfo) {
 ~ 			GlStateManager.pushMatrix();
 ~ 			this.renderDebugInfoLeft();
@@ -82,34 +82,33 @@
 ~ 			}
 ~ 
 
-> INSERT  2 : 26  @  2
+> CHANGE  2 : 25  @  2 : 3
 
-+ 		if (this.mc.currentScreen == null || !(this.mc.currentScreen instanceof GuiChat)) {
-+ 			if (this.mc.gameSettings.hudStats) {
-+ 				drawStatsHUD(ww - 2, hh - 2);
-+ 			}
-+ 
-+ 			if (this.mc.gameSettings.hudWorld) {
-+ 				drawWorldHUD(2, hh - 2);
-+ 			}
-+ 		}
-+ 
-+ 		if (this.mc.gameSettings.hudCoords && this.mc.joinWorldTickCounter < 80) {
-+ 			if (this.mc.joinWorldTickCounter > 70) {
-+ 				GlStateManager.enableBlend();
-+ 				GlStateManager.blendFunc(770, 771);
-+ 			}
-+ 			int i = this.mc.joinWorldTickCounter - 70;
-+ 			if (i < 0)
-+ 				i = 0;
-+ 			drawHideHUD(ww / 2, hh - 70, (10 - i) * 0xFF / 10);
-+ 			if (this.mc.joinWorldTickCounter > 70) {
-+ 				GlStateManager.disableBlend();
-+ 			}
-+ 		}
-+ 
+~ 		if (this.mc.currentScreen == null || !(this.mc.currentScreen instanceof GuiChat)) {
+~ 			if (this.mc.gameSettings.hudStats) {
+~ 				drawStatsHUD(ww - 2, hh - 2);
+~ 			}
+~ 
+~ 			if (this.mc.gameSettings.hudWorld) {
+~ 				drawWorldHUD(2, hh - 2);
+~ 			}
+~ 		}
+~ 
+~ 		if (this.mc.gameSettings.hudCoords && this.mc.joinWorldTickCounter < 80) {
+~ 			if (this.mc.joinWorldTickCounter > 70) {
+~ 				GlStateManager.enableBlend();
+~ 				GlStateManager.blendFunc(770, 771);
+~ 			}
+~ 			int i = this.mc.joinWorldTickCounter - 70;
+~ 			if (i < 0)
+~ 				i = 0;
+~ 			drawHideHUD(ww / 2, hh - 70, (10 - i) * 0xFF / 10);
+~ 			if (this.mc.joinWorldTickCounter > 70) {
+~ 				GlStateManager.disableBlend();
+~ 			}
+~ 		}
 
-> INSERT  3 : 142  @  3
+> INSERT  2 : 140  @  2
 
 + 	private void drawFPS(int x, int y) {
 + 		this.fontRenderer.drawStringWithShadow(this.mc.renderGlobal.getDebugInfoShort(), x, y, 0xFFFFFF);
@@ -205,7 +204,6 @@
 + 		final double dticks = ticks - minutes * ticksPerMinute;
 + 		final long seconds = (long) Math.floor(dticks / ticksPerSecond);
 + 
-+ 		// TODO: why does desktop JRE not apply "GMT" correctly?
 + 		final Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("GMT"), Locale.ENGLISH);
 + 
 + 		cal.setLenient(true);
@@ -215,10 +213,10 @@
 + 		cal.add(Calendar.MINUTE, (int) minutes);
 + 		cal.add(Calendar.SECOND, (int) seconds + 1);
 + 
++ 		SimpleDateFormat fmt = this.mc.gameSettings.hud24h ? SDFTwentyFour : SDFTwelve;
++ 		fmt.setCalendar(cal);
 + 		String timeString = EnumChatFormatting.WHITE + "Day " + ((totalTicks + 30000l) / 24000l) + " ("
-+ 				+ EnumChatFormatting.YELLOW
-+ 				+ (this.mc.gameSettings.hud24h ? SDFTwentyFour : SDFTwelve).format(cal.getTime())
-+ 				+ EnumChatFormatting.WHITE + ")";
++ 				+ EnumChatFormatting.YELLOW + fmt.format(cal.getTime()) + EnumChatFormatting.WHITE + ")";
 + 
 + 		Entity e = mc.getRenderViewEntity();
 + 		BlockPos blockpos = new BlockPos(e.posX, MathHelper.clamp_double(e.getEntityBoundingBox().minY, 0.0D, 254.0D),
@@ -251,7 +249,7 @@
 + 	}
 + 
 
-> INSERT  4 : 37  @  4
+> INSERT  4 : 44  @  4
 
 + 	private int drawSingleplayerStats(ScaledResolution parScaledResolution) {
 + 		if (mc.isDemo()) {
@@ -263,23 +261,30 @@
 + 			if (tpsAge < 20000l) {
 + 				int color = tpsAge > 2000l ? 0x777777 : 0xFFFFFF;
 + 				List<String> strs = SingleplayerServerController.getTPS();
++ 				if (SingleplayerServerController.isRunningSingleThreadMode()) {
++ 					strs = Lists.newArrayList(strs);
++ 					strs.add("");
++ 					strs.add(I18n.format("singleplayer.tpscounter.singleThreadMode"));
++ 				}
 + 				int l;
 + 				boolean first = true;
 + 				for (int j = 0, m = strs.size(); j < m; ++j) {
 + 					String str = strs.get(j);
-+ 					l = (int) (this.fontRenderer.getStringWidth(str) * (!first ? 0.5f : 1.0f));
-+ 					GlStateManager.pushMatrix();
-+ 					GlStateManager.translate(parScaledResolution.getScaledWidth() - 2 - l, i + 2, 0.0f);
-+ 					if (!first) {
-+ 						GlStateManager.scale(0.5f, 0.5f, 0.5f);
++ 					if (!StringUtils.isAllEmpty(str)) {
++ 						l = (int) (this.fontRenderer.getStringWidth(str) * (!first ? 0.5f : 1.0f));
++ 						GlStateManager.pushMatrix();
++ 						GlStateManager.translate(parScaledResolution.getScaledWidth() - 2 - l, i + 2, 0.0f);
++ 						if (!first) {
++ 							GlStateManager.scale(0.5f, 0.5f, 0.5f);
++ 						}
++ 						this.fontRenderer.drawStringWithShadow(str, 0, 0, color);
++ 						GlStateManager.popMatrix();
++ 						if (color == 0xFFFFFF) {
++ 							color = 14737632;
++ 						}
 + 					}
-+ 					this.fontRenderer.drawStringWithShadow(str, 0, 0, color);
-+ 					GlStateManager.popMatrix();
 + 					i += (int) (this.fontRenderer.FONT_HEIGHT * (!first ? 0.5f : 1.0f));
 + 					first = false;
-+ 					if (color == 0xFFFFFF) {
-+ 						color = 14737632;
-+ 					}
 + 				}
 + 			}
 + 		}
@@ -370,4 +375,8 @@
 
 > DELETE  8  @  8 : 12
 
+> CHANGE  25 : 26  @  25 : 26
+
+~ 		ScaledResolution scaledresolution = this.mc.scaledResolution;
+
 > EOF
diff --git a/patches/minecraft/net/minecraft/client/gui/GuiPageButtonList.edit.java b/patches/minecraft/net/minecraft/client/gui/GuiPageButtonList.edit.java
index 3fe499ad..d5c1e1cc 100644
--- a/patches/minecraft/net/minecraft/client/gui/GuiPageButtonList.edit.java
+++ b/patches/minecraft/net/minecraft/client/gui/GuiPageButtonList.edit.java
@@ -10,9 +10,11 @@
 + import java.util.List;
 + 
 
-> CHANGE  4 : 5  @  4 : 5
+> CHANGE  4 : 7  @  4 : 5
 
 ~ 
+~ import net.lax1dude.eaglercraft.v1_8.PointerInputAbstraction;
+~ import net.lax1dude.eaglercraft.v1_8.minecraft.EnumInputEvent;
 
 > DELETE  1  @  1 : 9
 
@@ -46,4 +48,53 @@
 ~ 				for (int k = 0; k < astring.length; ++k) {
 ~ 					((GuiTextField) this.field_178072_w.get(j)).setText(astring[k]);
 
+> INSERT  31 : 46  @  31
+
++ 	public boolean isTextFieldFocused() {
++ 		for (GuiTextField txt : field_178072_w) {
++ 			if (txt.isFocused()) {
++ 				return true;
++ 			}
++ 		}
++ 		return false;
++ 	}
++ 
++ 	public void fireInputEvent(EnumInputEvent event, String param) {
++ 		for (GuiTextField txt : field_178072_w) {
++ 			txt.fireInputEvent(event, param);
++ 		}
++ 	}
++ 
+
+> CHANGE  93 : 100  @  93 : 95
+
+~ 			if (k != 0 && k != 12345)
+~ 				return false;
+~ 			boolean touchMode = PointerInputAbstraction.isTouchMode();
+~ 			boolean flag = this.field_178029_b != null && (!touchMode || stupidCheck(this.field_178029_b, k))
+~ 					&& this.func_178026_a(this.field_178029_b, i, j, k);
+~ 			boolean flag1 = this.field_178030_c != null && (!touchMode || stupidCheck(this.field_178030_c, k))
+~ 					&& this.func_178026_a(this.field_178030_c, i, j, k);
+
+> INSERT  3 : 11  @  3
+
++ 		private static boolean stupidCheck(Gui gui, int k) {
++ 			if (gui instanceof GuiButton) {
++ 				return ((GuiButton) gui).isSliderTouchEvents() == (k == 12345);
++ 			} else {
++ 				return k != 12345;
++ 			}
++ 		}
++ 
+
+> CHANGE  32 : 39  @  32 : 34
+
+~ 			if (k != 0 && k != 12345)
+~ 				return;
+~ 			boolean touchMode = PointerInputAbstraction.isTouchMode();
+~ 			if (!touchMode || stupidCheck(field_178029_b, k))
+~ 				this.func_178016_b(this.field_178029_b, i, j, k);
+~ 			if (!touchMode || stupidCheck(field_178030_c, k))
+~ 				this.func_178016_b(this.field_178030_c, i, j, k);
+
 > EOF
diff --git a/patches/minecraft/net/minecraft/client/gui/GuiPlayerTabOverlay.edit.java b/patches/minecraft/net/minecraft/client/gui/GuiPlayerTabOverlay.edit.java
index 6d261807..6b048d50 100644
--- a/patches/minecraft/net/minecraft/client/gui/GuiPlayerTabOverlay.edit.java
+++ b/patches/minecraft/net/minecraft/client/gui/GuiPlayerTabOverlay.edit.java
@@ -20,7 +20,16 @@
 
 > DELETE  2  @  2 : 3
 
-> CHANGE  46 : 48  @  46 : 47
+> CHANGE  27 : 29  @  27 : 28
+
+~ 		IChatComponent dname = networkPlayerInfoIn.getDisplayNameProfanityFilter();
+~ 		return dname != null ? dname.getFormattedText()
+
+> CHANGE  1 : 2  @  1 : 2
+
+~ 						networkPlayerInfoIn.getGameProfileNameProfanityFilter());
+
+> CHANGE  16 : 18  @  16 : 17
 
 ~ 		for (int m = 0, n = list.size(); m < n; ++m) {
 ~ 			NetworkPlayerInfo networkplayerinfo = (NetworkPlayerInfo) list.get(m);
diff --git a/patches/minecraft/net/minecraft/client/gui/GuiRenameWorld.edit.java b/patches/minecraft/net/minecraft/client/gui/GuiRenameWorld.edit.java
index b0c9f4ff..3c333a72 100644
--- a/patches/minecraft/net/minecraft/client/gui/GuiRenameWorld.edit.java
+++ b/patches/minecraft/net/minecraft/client/gui/GuiRenameWorld.edit.java
@@ -5,9 +5,10 @@
 # Version: 1.0
 # Author: lax1dude
 
-> CHANGE  2 : 5  @  2 : 6
+> CHANGE  2 : 6  @  2 : 6
 
 ~ import net.lax1dude.eaglercraft.v1_8.Keyboard;
+~ import net.lax1dude.eaglercraft.v1_8.minecraft.EnumInputEvent;
 ~ import net.lax1dude.eaglercraft.v1_8.sp.SingleplayerServerController;
 ~ import net.lax1dude.eaglercraft.v1_8.sp.gui.GuiScreenIntegratedServerBusy;
 
@@ -74,4 +75,18 @@
 ~ 		this.drawCenteredString(this.fontRendererObj,
 ~ 				I18n.format(duplicate ? "selectWorld.duplicate" : "selectWorld.renameTitle", new Object[0]),
 
+> INSERT  6 : 17  @  6
+
++ 
++ 	@Override
++ 	public boolean showCopyPasteButtons() {
++ 		return field_146583_f.isFocused();
++ 	}
++ 
++ 	@Override
++ 	public void fireInputEvent(EnumInputEvent event, String param) {
++ 		field_146583_f.fireInputEvent(event, param);
++ 	}
++ 
+
 > EOF
diff --git a/patches/minecraft/net/minecraft/client/gui/GuiRepair.edit.java b/patches/minecraft/net/minecraft/client/gui/GuiRepair.edit.java
index e57581c0..6550f086 100644
--- a/patches/minecraft/net/minecraft/client/gui/GuiRepair.edit.java
+++ b/patches/minecraft/net/minecraft/client/gui/GuiRepair.edit.java
@@ -7,11 +7,12 @@
 
 > DELETE  2  @  2 : 4
 
-> INSERT  1 : 5  @  1
+> INSERT  1 : 6  @  1
 
 + 
 + import net.lax1dude.eaglercraft.v1_8.netty.Unpooled;
 + import net.lax1dude.eaglercraft.v1_8.Keyboard;
++ import net.lax1dude.eaglercraft.v1_8.minecraft.EnumInputEvent;
 + import net.lax1dude.eaglercraft.v1_8.opengl.GlStateManager;
 
 > DELETE  1  @  1 : 2
@@ -28,11 +29,22 @@
 
 ~ 	protected void mouseClicked(int parInt1, int parInt2, int parInt3) {
 
-> INSERT  46 : 50  @  46
+> INSERT  46 : 61  @  46
 
 + 
 + 	public boolean blockPTTKey() {
 + 		return nameField.isFocused();
 + 	}
++ 
++ 	@Override
++ 	public boolean showCopyPasteButtons() {
++ 		return nameField.isFocused();
++ 	}
++ 
++ 	@Override
++ 	public void fireInputEvent(EnumInputEvent event, String param) {
++ 		nameField.fireInputEvent(event, param);
++ 	}
++ 
 
 > EOF
diff --git a/patches/minecraft/net/minecraft/client/gui/GuiScreen.edit.java b/patches/minecraft/net/minecraft/client/gui/GuiScreen.edit.java
index 2b51878c..511cc426 100644
--- a/patches/minecraft/net/minecraft/client/gui/GuiScreen.edit.java
+++ b/patches/minecraft/net/minecraft/client/gui/GuiScreen.edit.java
@@ -9,9 +9,18 @@
 
 > DELETE  1  @  1 : 3
 
-> INSERT  4 : 20  @  4
+> INSERT  2 : 3  @  2
+
++ import java.util.HashMap;
+
+> INSERT  1 : 2  @  1
+
++ import java.util.Map;
+
+> INSERT  1 : 24  @  1
 
 + 
++ import net.lax1dude.eaglercraft.v1_8.internal.EnumTouchEvent;
 + import org.apache.commons.lang3.StringUtils;
 + 
 + import com.google.common.base.Splitter;
@@ -22,11 +31,17 @@
 + import net.lax1dude.eaglercraft.v1_8.EaglerXBungeeVersion;
 + import net.lax1dude.eaglercraft.v1_8.Keyboard;
 + import net.lax1dude.eaglercraft.v1_8.Mouse;
++ import net.lax1dude.eaglercraft.v1_8.PauseMenuCustomizeState;
++ import net.lax1dude.eaglercraft.v1_8.PointerInputAbstraction;
++ import net.lax1dude.eaglercraft.v1_8.Touch;
 + import net.lax1dude.eaglercraft.v1_8.internal.KeyboardConstants;
 + import net.lax1dude.eaglercraft.v1_8.log4j.LogManager;
 + import net.lax1dude.eaglercraft.v1_8.log4j.Logger;
++ import net.lax1dude.eaglercraft.v1_8.minecraft.EnumInputEvent;
 + import net.lax1dude.eaglercraft.v1_8.opengl.GlStateManager;
 + import net.lax1dude.eaglercraft.v1_8.opengl.WorldRenderer;
++ import net.lax1dude.eaglercraft.v1_8.touch_gui.TouchControls;
++ import net.lax1dude.eaglercraft.v1_8.webview.GuiScreenServerInfo;
 
 > CHANGE  1 : 2  @  1 : 9
 
@@ -38,14 +53,27 @@
 
 + import net.minecraft.client.resources.I18n;
 
-> DELETE  13  @  13 : 19
+> CHANGE  13 : 14  @  13 : 19
 
-> CHANGE  17 : 19  @  17 : 18
+~ import net.minecraft.util.ResourceLocation;
+
+> CHANGE  13 : 14  @  13 : 14
+
+~ 	protected GuiButton selectedButton;
+
+> CHANGE  3 : 5  @  3 : 4
 
 ~ 	private String clickedLinkURI;
 ~ 	protected long showingCloseKey = 0;
 
-> CHANGE  2 : 3  @  2 : 3
+> INSERT  1 : 5  @  1
+
++ 	protected int touchModeCursorPosX = -1;
++ 	protected int touchModeCursorPosY = -1;
++ 	private long lastTouchEvent;
++ 
+
+> CHANGE  1 : 2  @  1 : 2
 
 ~ 		for (int k = 0, l = this.buttonList.size(); k < l; ++k) {
 
@@ -55,7 +83,7 @@
 
 > INSERT  3 : 33  @  3
 
-+ 		long millis = System.currentTimeMillis();
++ 		long millis = EagRuntime.steadyTimeMillis();
 + 		long closeKeyTimeout = millis - showingCloseKey;
 + 		if (closeKeyTimeout < 3000l) {
 + 			int alpha1 = 0xC0000000;
@@ -86,7 +114,7 @@
 + 		}
 + 
 
-> CHANGE  2 : 14  @  2 : 4
+> CHANGE  2 : 16  @  2 : 4
 
 ~ 	protected int getCloseKey() {
 ~ 		if (this instanceof GuiContainer) {
@@ -97,6 +125,8 @@
 ~ 	}
 ~ 
 ~ 	protected void keyTyped(char parChar1, int parInt1) {
+~ 		if (!canCloseGui())
+~ 			return;
 ~ 		if (((this.mc.theWorld == null || this.mc.thePlayer.getHealth() <= 0.0F) && parInt1 == 1)
 ~ 				|| parInt1 == this.mc.gameSettings.keyBindClose.getKeyCode()
 ~ 				|| (parInt1 == 1 && (this.mc.gameSettings.keyBindClose.getKeyCode() == 0 || this.mc.areKeysLocked()))) {
@@ -104,7 +134,7 @@
 > INSERT  4 : 6  @  4
 
 + 		} else if (parInt1 == 1) {
-+ 			showingCloseKey = System.currentTimeMillis();
++ 			showingCloseKey = EagRuntime.steadyTimeMillis();
 
 > DELETE  1  @  1 : 2
 
@@ -116,22 +146,72 @@
 
 ~ 			EagRuntime.setClipboard(copyText);
 
-> CHANGE  6 : 7  @  6 : 7
+> CHANGE  4 : 6  @  4 : 5
 
+~ 		renderToolTip0(itemstack, i, j, false);
+~ 	}
+
+> CHANGE  1 : 5  @  1 : 2
+
+~ 	protected void renderToolTip0(ItemStack itemstack, int i, int j, boolean eagler) {
+~ 		List list = itemstack.getTooltipProfanityFilter(this.mc.thePlayer, this.mc.gameSettings.advancedItemTooltips);
+~ 
 ~ 		for (int k = 0, l = list.size(); k < l; ++k) {
 
-> CHANGE  22 : 24  @  22 : 24
+> CHANGE  7 : 8  @  7 : 8
+
+~ 		this.drawHoveringText0(list, i, j, eagler);
+
+> INSERT  7 : 11  @  7
+
++ 		drawHoveringText0(list, i, j, false);
++ 	}
++ 
++ 	protected void drawHoveringText0(List<String> list, int i, int j, boolean eagler) {
+
+> CHANGE  7 : 9  @  7 : 9
 
 ~ 			for (int m = 0, n = list.size(); m < n; ++m) {
 ~ 				int l = this.fontRendererObj.getStringWidth(list.get(m));
 
-> CHANGE  37 : 40  @  37 : 38
+> CHANGE  5 : 7  @  5 : 7
+
+~ 			int j2 = i;
+~ 			int k2 = j;
+
+> CHANGE  5 : 8  @  5 : 8
+
+~ 			if (!eagler) {
+~ 				j2 += 12;
+~ 				k2 -= 12;
+
+> CHANGE  1 : 10  @  1 : 3
+
+~ 				if (j2 + k > this.width) {
+~ 					j2 -= 28 + k;
+~ 				}
+~ 
+~ 				if (k2 + i1 + 6 > this.height) {
+~ 					k2 = this.height - i1 - 6;
+~ 				}
+~ 			} else {
+~ 				j2 -= (k + 3) >> 1;
+
+> CHANGE  19 : 22  @  19 : 20
 
 ~ 				if (s1.length() > 0) {
 ~ 					this.fontRendererObj.drawStringWithShadow(s1, (float) j2, (float) k2, -1);
 ~ 				}
 
-> INSERT  107 : 108  @  107
+> CHANGE  16 : 17  @  16 : 17
+
+~ 	public void handleComponentHover(IChatComponent parIChatComponent, int parInt1, int parInt2) {
+
+> CHANGE  76 : 77  @  76 : 77
+
+~ 	public boolean handleComponentClick(IChatComponent parIChatComponent) {
+
+> INSERT  13 : 14  @  13
 
 + 					String uri = clickevent.getValue();
 
@@ -165,20 +245,229 @@
 ~ 						LOGGER.error("Invalid plugin download from EPK was blocked: {}",
 ~ 								EaglerXBungeeVersion.pluginFileEPK);
 
-> CHANGE  24 : 25  @  24 : 25
+> CHANGE  24 : 49  @  24 : 26
 
+~ 	protected void touchStarted(int parInt1, int parInt2, int parInt3) {
+~ 		if (shouldTouchGenerateMouseEvents()) {
+~ 			this.mouseClicked(parInt1, parInt2, 12345);
+~ 		}
+~ 	}
+~ 
+~ 	protected void touchTapped(int parInt1, int parInt2, int parInt3) {
+~ 		if (shouldTouchGenerateMouseEvents()) {
+~ 			this.mouseClicked(parInt1, parInt2, 0);
+~ 			this.mouseReleased(parInt1, parInt2, 0);
+~ 		}
+~ 	}
+~ 
+~ 	protected void touchMoved(int parInt1, int parInt2, int parInt3) {
+~ 	}
+~ 
+~ 	protected void touchEndMove(int parInt1, int parInt2, int parInt3) {
+~ 		if (shouldTouchGenerateMouseEvents()) {
+~ 			this.mouseReleased(parInt1, parInt2, 12345);
+~ 		}
+~ 	}
+~ 
 ~ 	protected void mouseClicked(int parInt1, int parInt2, int parInt3) {
+~ 		boolean touchMode = PointerInputAbstraction.isTouchMode();
+~ 		if (parInt3 == 0 || parInt3 == 12345) {
 
-> CHANGE  24 : 25  @  24 : 25
+> INSERT  2 : 4  @  2
+
++ 				if (touchMode && (parInt3 == 12345) != guibutton.isSliderTouchEvents())
++ 					continue;
+
+> CHANGE  11 : 13  @  11 : 12
+
+~ 		if (this.selectedButton != null && (k == 0 || k == 12345)
+~ 				&& (!PointerInputAbstraction.isTouchMode() || (k == 12345) == selectedButton.isSliderTouchEvents())) {
+
+> CHANGE  9 : 10  @  9 : 10
 
 ~ 	protected void actionPerformed(GuiButton parGuiButton) {
 
-> CHANGE  119 : 121  @  119 : 128
+> INSERT  16 : 23  @  16
+
++ 		boolean noTouch = true;
++ 		while (Touch.next()) {
++ 			noTouch = false;
++ 			this.handleTouchInput();
++ 			TouchControls.handleInput();
++ 		}
++ 
+
+> CHANGE  2 : 5  @  2 : 3
+
+~ 				if (noTouch) {
+~ 					this.handleMouseInput();
+~ 				}
+
+> INSERT  11 : 95  @  11
+
++ 	public final Map<Integer, int[]> touchStarts = new HashMap<>();
++ 
++ 	/**
++ 	 * Handles touch input.
++ 	 */
++ 	public void handleTouchInput() throws IOException {
++ 		EnumTouchEvent et = Touch.getEventType();
++ 		if (et == EnumTouchEvent.TOUCHSTART) {
++ 			PointerInputAbstraction.enterTouchModeHook();
++ 		}
++ 		float scaleFac = getEaglerScale();
++ 		for (int t = 0, c = Touch.getEventTouchPointCount(); t < c; ++t) {
++ 			int u = Touch.getEventTouchPointUID(t);
++ 			int i = Touch.getEventTouchX(t);
++ 			int j = Touch.getEventTouchY(t);
++ 			if (et == EnumTouchEvent.TOUCHSTART) {
++ 				if (TouchControls.handleTouchBegin(u, i, j)) {
++ 					continue;
++ 				}
++ 			} else if (et == EnumTouchEvent.TOUCHEND) {
++ 				if (TouchControls.handleTouchEnd(u, i, j)) {
++ 					continue;
++ 				}
++ 			}
++ 			i = applyEaglerScale(scaleFac, i * this.width / this.mc.displayWidth, this.width);
++ 			j = applyEaglerScale(scaleFac, this.height - j * this.height / this.mc.displayHeight - 1, this.height);
++ 			float si = Touch.getEventTouchRadiusX(t) * this.width / this.mc.displayWidth / scaleFac;
++ 			if (si < 1.0f)
++ 				si = 1.0f;
++ 			float sj = Touch.getEventTouchRadiusY(t) * this.height / this.mc.displayHeight / scaleFac;
++ 			if (sj < 1.0f)
++ 				sj = 1.0f;
++ 			int[] ck = touchStarts.remove(u);
++ 			switch (et) {
++ 			case TOUCHSTART:
++ 				if (t == 0) {
++ 					touchModeCursorPosX = i;
++ 					touchModeCursorPosY = j;
++ 				}
++ 				lastTouchEvent = EagRuntime.steadyTimeMillis();
++ 				touchStarts.put(u, new int[] { i, j, 0 });
++ 				this.touchStarted(i, j, u);
++ 				break;
++ 			case TOUCHMOVE:
++ 				if (t == 0) {
++ 					touchModeCursorPosX = i;
++ 					touchModeCursorPosY = j;
++ 				}
++ 				if (ck != null && Math.abs(ck[0] - i) < si && Math.abs(ck[1] - j) < sj) {
++ 					touchStarts.put(u, ck);
++ 					break;
++ 				}
++ 				touchStarts.put(u, new int[] { i, j, (ck != null && isTouchDraggingStateLocked(u)) ? ck[2] : 1 });
++ 				this.touchMoved(i, j, u);
++ 				if (t == 0 && shouldTouchGenerateMouseEvents()) {
++ 					this.mouseClickMove(i, j, 0, EagRuntime.steadyTimeMillis() - lastTouchEvent);
++ 				}
++ 				break;
++ 			case TOUCHEND:
++ 				if (ck == null)
++ 					break;
++ 				if (t == 0) {
++ 					touchModeCursorPosX = -1;
++ 					touchModeCursorPosY = -1;
++ 				}
++ 				if (ck != null && ck[2] == 1) {
++ 					this.touchEndMove(i, j, u);
++ 				} else {
++ 					if (ck != null) {
++ 						i = ck[0];
++ 						j = ck[1];
++ 					}
++ 					this.touchTapped(i, j, u);
++ 				}
++ 				break;
++ 			}
++ 		}
++ 	}
++ 
++ 	public boolean isTouchPointDragging(int uid) {
++ 		int[] ret = touchStarts.get(uid);
++ 		return ret != null && ret[2] == 1;
++ 	}
++ 
+
+> CHANGE  1 : 5  @  1 : 3
+
+~ 		float f = getEaglerScale();
+~ 		int i = applyEaglerScale(f, Mouse.getEventX() * this.width / this.mc.displayWidth, this.width);
+~ 		int j = applyEaglerScale(f, this.height - Mouse.getEventY() * this.height / this.mc.displayHeight - 1,
+~ 				this.height);
+
+> INSERT  2 : 3  @  2
+
++ 			PointerInputAbstraction.enterMouseModeHook();
+
+> INSERT  39 : 43  @  39
+
++ 	protected boolean isPartOfPauseMenu() {
++ 		return false;
++ 	}
++ 
+
+> CHANGE  2 : 53  @  2 : 3
+
+~ 			boolean ingame = isPartOfPauseMenu();
+~ 			ResourceLocation loc = (ingame && PauseMenuCustomizeState.icon_background_pause != null)
+~ 					? PauseMenuCustomizeState.icon_background_pause
+~ 					: PauseMenuCustomizeState.icon_background_all;
+~ 			float aspect = (ingame && PauseMenuCustomizeState.icon_background_pause != null)
+~ 					? 1.0f / PauseMenuCustomizeState.icon_background_pause_aspect
+~ 					: 1.0f / PauseMenuCustomizeState.icon_background_all_aspect;
+~ 			if (loc != null) {
+~ 				GlStateManager.disableLighting();
+~ 				GlStateManager.disableFog();
+~ 				GlStateManager.enableBlend();
+~ 				GlStateManager.disableAlpha();
+~ 				GlStateManager.enableTexture2D();
+~ 				GlStateManager.tryBlendFuncSeparate(770, 771, 1, 0);
+~ 				Tessellator tessellator = Tessellator.getInstance();
+~ 				WorldRenderer worldrenderer = tessellator.getWorldRenderer();
+~ 				this.mc.getTextureManager().bindTexture(loc);
+~ 				GlStateManager.color(1.0F, 1.0F, 1.0F, 1.0F);
+~ 				float f = 64.0F;
+~ 				worldrenderer.begin(7, DefaultVertexFormats.POSITION_TEX_COLOR);
+~ 				worldrenderer.pos(0.0D, (double) this.height, 0.0D).tex(0.0D, (double) ((float) this.height / f))
+~ 						.color(64, 64, 64, 192).endVertex();
+~ 				worldrenderer.pos((double) this.width, (double) this.height, 0.0D)
+~ 						.tex((double) ((float) this.width / f * aspect), (double) ((float) this.height / f))
+~ 						.color(64, 64, 64, 192).endVertex();
+~ 				worldrenderer.pos((double) this.width, 0.0D, 0.0D)
+~ 						.tex((double) ((float) this.width / f * aspect), (double) 0).color(64, 64, 64, 192).endVertex();
+~ 				worldrenderer.pos(0.0D, 0.0D, 0.0D).tex(0.0D, (double) 0).color(64, 64, 64, 192).endVertex();
+~ 				tessellator.draw();
+~ 				GlStateManager.enableAlpha();
+~ 			} else {
+~ 				this.drawGradientRect(0, 0, this.width, this.height, -1072689136, -804253680);
+~ 			}
+~ 			if (!(this instanceof GuiScreenServerInfo)) {
+~ 				loc = (ingame && PauseMenuCustomizeState.icon_watermark_pause != null)
+~ 						? PauseMenuCustomizeState.icon_watermark_pause
+~ 						: PauseMenuCustomizeState.icon_watermark_all;
+~ 				aspect = (ingame && PauseMenuCustomizeState.icon_watermark_pause != null)
+~ 						? PauseMenuCustomizeState.icon_watermark_pause_aspect
+~ 						: PauseMenuCustomizeState.icon_watermark_all_aspect;
+~ 				if (loc != null) {
+~ 					GlStateManager.color(1.0f, 1.0f, 1.0f, 1.0f);
+~ 					mc.getTextureManager().bindTexture(loc);
+~ 					GlStateManager.pushMatrix();
+~ 					GlStateManager.translate(8, height - 72, 0.0f);
+~ 					float f2 = 64.0f / 256.0f;
+~ 					GlStateManager.scale(f2 * aspect, f2, f2);
+~ 					this.drawTexturedModalRect(0, 0, 0, 0, 256, 256);
+~ 					GlStateManager.popMatrix();
+~ 				}
+~ 			}
+
+> CHANGE  42 : 44  @  42 : 51
 
 ~ 	private void openWebLink(String parURI) {
 ~ 		EagRuntime.openLink(parURI);
 
-> INSERT  34 : 42  @  34
+> INSERT  34 : 75  @  34
 
 + 
 + 	public boolean shouldHangupIntegratedServer() {
@@ -188,5 +477,38 @@
 + 	public boolean blockPTTKey() {
 + 		return false;
 + 	}
++ 
++ 	public void fireInputEvent(EnumInputEvent event, String param) {
++ 
++ 	}
++ 
++ 	public boolean showCopyPasteButtons() {
++ 		return false;
++ 	}
++ 
++ 	public static int applyEaglerScale(float scaleFac, int coord, int screenDim) {
++ 		return (int) ((coord - (1.0f - scaleFac) * screenDim * 0.5f) / scaleFac);
++ 	}
++ 
++ 	public float getEaglerScale() {
++ 		return PointerInputAbstraction.isTouchMode() ? getTouchModeScale() : 1.0f;
++ 	}
++ 
++ 	protected float getTouchModeScale() {
++ 		return 1.0f;
++ 	}
++ 
++ 	public boolean canCloseGui() {
++ 		return true;
++ 	}
++ 
++ 	protected boolean isTouchDraggingStateLocked(int uid) {
++ 		return false;
++ 	}
++ 
++ 	protected boolean shouldTouchGenerateMouseEvents() {
++ 		return true;
++ 	}
++ 
 
 > EOF
diff --git a/patches/minecraft/net/minecraft/client/gui/GuiScreenAddServer.edit.java b/patches/minecraft/net/minecraft/client/gui/GuiScreenAddServer.edit.java
index 2b3c03f4..f0c9b4bc 100644
--- a/patches/minecraft/net/minecraft/client/gui/GuiScreenAddServer.edit.java
+++ b/patches/minecraft/net/minecraft/client/gui/GuiScreenAddServer.edit.java
@@ -5,16 +5,18 @@
 # Version: 1.0
 # Author: lax1dude
 
-> CHANGE  2 : 4  @  2 : 8
+> CHANGE  2 : 5  @  2 : 8
 
 ~ import net.lax1dude.eaglercraft.v1_8.EagRuntime;
 ~ import net.lax1dude.eaglercraft.v1_8.Keyboard;
+~ import net.lax1dude.eaglercraft.v1_8.minecraft.EnumInputEvent;
 
 > DELETE  2  @  2 : 3
 
-> CHANGE  7 : 8  @  7 : 26
+> CHANGE  7 : 9  @  7 : 26
 
 ~ 	private GuiButton hideAddress;
+~ 	private GuiButton enableCookies;
 
 > INSERT  13 : 14  @  13
 
@@ -40,11 +42,21 @@
 ~ 		}
 ~ 		this.buttonList.add(this.serverResourcePacks = new GuiButton(2, this.width / 2 - 100, i + 54,
 
-> INSERT  2 : 5  @  2
+> INSERT  2 : 15  @  2
 
-+ 		this.buttonList.add(this.hideAddress = new GuiButton(3, this.width / 2 - 100, i + 78,
-+ 				I18n.format("addServer.hideAddress", new Object[0]) + ": "
-+ 						+ I18n.format(this.serverData.hideAddress ? "gui.yes" : "gui.no", new Object[0])));
++ 		if (EagRuntime.getConfiguration().isEnableServerCookies()) {
++ 			this.buttonList.add(this.enableCookies = new GuiButton(4, this.width / 2 - 100, i + 78, 99, 20,
++ 					I18n.format("addServer.enableCookies") + ": "
++ 							+ I18n.format(this.serverData.enableCookies ? "addServer.enableCookies.enabled"
++ 									: "addServer.enableCookies.disabled")));
++ 			this.buttonList.add(this.hideAddress = new GuiButton(3, this.width / 2 + 1, i + 78, 99, 20,
++ 					I18n.format("addServer.hideAddr", new Object[0]) + ": "
++ 							+ I18n.format(this.serverData.hideAddress ? "gui.yes" : "gui.no", new Object[0])));
++ 		} else {
++ 			this.buttonList.add(this.hideAddress = new GuiButton(3, this.width / 2 - 100, i + 78,
++ 					I18n.format("addServer.hideAddress", new Object[0]) + ": "
++ 							+ I18n.format(this.serverData.hideAddress ? "gui.yes" : "gui.no", new Object[0])));
++ 		}
 
 > CHANGE  6 : 7  @  6 : 9
 
@@ -54,12 +66,19 @@
 
 ~ 	protected void actionPerformed(GuiButton parGuiButton) {
 
-> CHANGE  1 : 6  @  1 : 2
+> CHANGE  1 : 13  @  1 : 2
 
 ~ 			if (parGuiButton.id == 3) {
 ~ 				this.serverData.hideAddress = !this.serverData.hideAddress;
-~ 				this.hideAddress.displayString = I18n.format("addServer.hideAddress", new Object[0]) + ": "
-~ 						+ I18n.format(this.serverData.hideAddress ? "gui.yes" : "gui.no", new Object[0]);
+~ 				this.hideAddress.displayString = I18n
+~ 						.format(EagRuntime.getConfiguration().isEnableServerCookies() ? "addServer.hideAddr"
+~ 								: "addServer.hideAddress", new Object[0])
+~ 						+ ": " + I18n.format(this.serverData.hideAddress ? "gui.yes" : "gui.no", new Object[0]);
+~ 			} else if (parGuiButton.id == 4) {
+~ 				this.serverData.enableCookies = !this.serverData.enableCookies;
+~ 				this.enableCookies.displayString = I18n.format("addServer.enableCookies") + ": "
+~ 						+ I18n.format(this.serverData.enableCookies ? "addServer.enableCookies.enabled"
+~ 								: "addServer.enableCookies.disabled");
 ~ 			} else if (parGuiButton.id == 2) {
 
 > CHANGE  1 : 3  @  1 : 3
@@ -93,4 +112,19 @@
 + 					0xccccff);
 + 		}
 
+> INSERT  4 : 16  @  4
+
++ 
++ 	@Override
++ 	public boolean showCopyPasteButtons() {
++ 		return serverNameField.isFocused() || serverIPField.isFocused();
++ 	}
++ 
++ 	@Override
++ 	public void fireInputEvent(EnumInputEvent event, String param) {
++ 		serverNameField.fireInputEvent(event, param);
++ 		serverIPField.fireInputEvent(event, param);
++ 	}
++ 
+
 > EOF
diff --git a/patches/minecraft/net/minecraft/client/gui/GuiScreenBook.edit.java b/patches/minecraft/net/minecraft/client/gui/GuiScreenBook.edit.java
index 9fde9055..1c1b9def 100644
--- a/patches/minecraft/net/minecraft/client/gui/GuiScreenBook.edit.java
+++ b/patches/minecraft/net/minecraft/client/gui/GuiScreenBook.edit.java
@@ -7,7 +7,7 @@
 
 > DELETE  2  @  2 : 6
 
-> INSERT  1 : 11  @  1
+> INSERT  1 : 12  @  1
 
 + 
 + import org.json.JSONException;
@@ -18,13 +18,23 @@
 + import net.lax1dude.eaglercraft.v1_8.Keyboard;
 + import net.lax1dude.eaglercraft.v1_8.log4j.LogManager;
 + import net.lax1dude.eaglercraft.v1_8.log4j.Logger;
++ import net.lax1dude.eaglercraft.v1_8.minecraft.GuiScreenVisualViewport;
 + import net.lax1dude.eaglercraft.v1_8.opengl.GlStateManager;
 
 > DELETE  1  @  1 : 5
 
 > DELETE  16  @  16 : 19
 
-> CHANGE  139 : 140  @  139 : 140
+> CHANGE  1 : 2  @  1 : 2
+
+~ public class GuiScreenBook extends GuiScreenVisualViewport {
+
+> CHANGE  47 : 49  @  47 : 49
+
+~ 	public void updateScreen0() {
+~ 		super.updateScreen0();
+
+> CHANGE  88 : 89  @  88 : 89
 
 ~ 	protected void actionPerformed(GuiButton parGuiButton) {
 
@@ -34,15 +44,31 @@
 
 > DELETE  6  @  6 : 7
 
-> CHANGE  129 : 130  @  129 : 130
+> CHANGE  78 : 79  @  78 : 79
+
+~ 	public void drawScreen0(int i, int j, float f) {
+
+> CHANGE  50 : 51  @  50 : 51
 
 ~ 					} catch (JSONException var13) {
 
-> CHANGE  34 : 35  @  34 : 35
+> CHANGE  31 : 32  @  31 : 32
 
-~ 	protected void mouseClicked(int parInt1, int parInt2, int parInt3) {
+~ 		super.drawScreen0(i, j, f);
 
-> INSERT  102 : 106  @  102
+> CHANGE  2 : 3  @  2 : 3
+
+~ 	protected void mouseClicked0(int parInt1, int parInt2, int parInt3) {
+
+> CHANGE  7 : 8  @  7 : 8
+
+~ 		super.mouseClicked0(parInt1, parInt2, parInt3);
+
+> CHANGE  2 : 3  @  2 : 3
+
+~ 	public boolean handleComponentClick(IChatComponent ichatcomponent) {
+
+> INSERT  91 : 95  @  91
 
 + 
 + 	public boolean blockPTTKey() {
diff --git a/patches/minecraft/net/minecraft/client/gui/GuiScreenCustomizePresets.edit.java b/patches/minecraft/net/minecraft/client/gui/GuiScreenCustomizePresets.edit.java
index f65476ca..74c12e47 100644
--- a/patches/minecraft/net/minecraft/client/gui/GuiScreenCustomizePresets.edit.java
+++ b/patches/minecraft/net/minecraft/client/gui/GuiScreenCustomizePresets.edit.java
@@ -5,10 +5,11 @@
 # Version: 1.0
 # Author: lax1dude
 
-> CHANGE  5 : 9  @  5 : 11
+> CHANGE  5 : 10  @  5 : 11
 
 ~ 
 ~ import net.lax1dude.eaglercraft.v1_8.Keyboard;
+~ import net.lax1dude.eaglercraft.v1_8.minecraft.EnumInputEvent;
 ~ import net.lax1dude.eaglercraft.v1_8.opengl.GlStateManager;
 ~ import net.lax1dude.eaglercraft.v1_8.opengl.WorldRenderer;
 
@@ -16,7 +17,15 @@
 
 > DELETE  4  @  4 : 5
 
-> CHANGE  41 : 42  @  41 : 42
+> INSERT  37 : 42  @  37
+
++ 	public void handleTouchInput() throws IOException {
++ 		super.handleTouchInput();
++ 		this.field_175311_g.handleTouchInput();
++ 	}
++ 
+
+> CHANGE  4 : 5  @  4 : 5
 
 ~ 	protected void mouseClicked(int parInt1, int parInt2, int parInt3) {
 
@@ -28,4 +37,17 @@
 
 ~ 	protected void actionPerformed(GuiButton parGuiButton) {
 
+> INSERT  35 : 45  @  35
+
++ 	@Override
++ 	public boolean showCopyPasteButtons() {
++ 		return field_175317_i.isFocused();
++ 	}
++ 
++ 	@Override
++ 	public void fireInputEvent(EnumInputEvent event, String param) {
++ 		field_175317_i.fireInputEvent(event, param);
++ 	}
++ 
+
 > EOF
diff --git a/patches/minecraft/net/minecraft/client/gui/GuiScreenOptionsSounds.edit.java b/patches/minecraft/net/minecraft/client/gui/GuiScreenOptionsSounds.edit.java
index a934d7c2..5f6f77ca 100644
--- a/patches/minecraft/net/minecraft/client/gui/GuiScreenOptionsSounds.edit.java
+++ b/patches/minecraft/net/minecraft/client/gui/GuiScreenOptionsSounds.edit.java
@@ -21,4 +21,11 @@
 
 ~ 	protected void actionPerformed(GuiButton parGuiButton) {
 
+> INSERT  90 : 94  @  90
+
++ 
++ 		public boolean isSliderTouchEvents() {
++ 			return true;
++ 		}
+
 > EOF
diff --git a/patches/minecraft/net/minecraft/client/gui/GuiScreenResourcePacks.edit.java b/patches/minecraft/net/minecraft/client/gui/GuiScreenResourcePacks.edit.java
index 37a6e9b6..2c632717 100644
--- a/patches/minecraft/net/minecraft/client/gui/GuiScreenResourcePacks.edit.java
+++ b/patches/minecraft/net/minecraft/client/gui/GuiScreenResourcePacks.edit.java
@@ -40,7 +40,16 @@
 ~ 				this.selectedResourcePacks
 ~ 						.add(new ResourcePackListEntryFound(this, (ResourcePackRepository.Entry) arraylist.get(i)));
 
-> CHANGE  38 : 39  @  38 : 39
+> INSERT  21 : 27  @  21
+
++ 	public void handleTouchInput() throws IOException {
++ 		super.handleTouchInput();
++ 		this.selectedResourcePacksList.handleTouchInput();
++ 		this.availableResourcePacksList.handleTouchInput();
++ 	}
++ 
+
+> CHANGE  17 : 18  @  17 : 18
 
 ~ 	protected void actionPerformed(GuiButton parGuiButton) {
 
diff --git a/patches/minecraft/net/minecraft/client/gui/GuiScreenServerList.edit.java b/patches/minecraft/net/minecraft/client/gui/GuiScreenServerList.edit.java
index fb590b21..824578d7 100644
--- a/patches/minecraft/net/minecraft/client/gui/GuiScreenServerList.edit.java
+++ b/patches/minecraft/net/minecraft/client/gui/GuiScreenServerList.edit.java
@@ -5,10 +5,11 @@
 # Version: 1.0
 # Author: lax1dude
 
-> CHANGE  2 : 4  @  2 : 6
+> CHANGE  2 : 5  @  2 : 6
 
 ~ import net.lax1dude.eaglercraft.v1_8.EagRuntime;
 ~ import net.lax1dude.eaglercraft.v1_8.Keyboard;
+~ import net.lax1dude.eaglercraft.v1_8.minecraft.EnumInputEvent;
 
 > DELETE  2  @  2 : 3
 
@@ -59,4 +60,18 @@
 ~ 					100, 10526880);
 ~ 		}
 
+> INSERT  3 : 14  @  3
+
++ 
++ 	@Override
++ 	public boolean showCopyPasteButtons() {
++ 		return field_146302_g.isFocused();
++ 	}
++ 
++ 	@Override
++ 	public void fireInputEvent(EnumInputEvent event, String param) {
++ 		field_146302_g.fireInputEvent(event, param);
++ 	}
++ 
+
 > EOF
diff --git a/patches/minecraft/net/minecraft/client/gui/GuiSelectWorld.edit.java b/patches/minecraft/net/minecraft/client/gui/GuiSelectWorld.edit.java
index 039a01c9..4969828c 100644
--- a/patches/minecraft/net/minecraft/client/gui/GuiSelectWorld.edit.java
+++ b/patches/minecraft/net/minecraft/client/gui/GuiSelectWorld.edit.java
@@ -9,12 +9,13 @@
 
 + import java.util.ArrayList;
 
-> CHANGE  2 : 7  @  2 : 3
+> CHANGE  2 : 8  @  2 : 3
 
 ~ 
 ~ import net.lax1dude.eaglercraft.v1_8.opengl.GlStateManager;
 ~ import net.lax1dude.eaglercraft.v1_8.sp.gui.GuiScreenLANConnect;
 ~ import net.lax1dude.eaglercraft.v1_8.sp.gui.GuiScreenLANNotSupported;
+~ import net.lax1dude.eaglercraft.v1_8.sp.ipc.IPCPacket1CIssueDetected;
 ~ import net.lax1dude.eaglercraft.v1_8.sp.lan.LANServerController;
 
 > CHANGE  1 : 2  @  1 : 9
@@ -44,18 +45,27 @@
 + import net.lax1dude.eaglercraft.v1_8.sp.gui.GuiScreenLANInfo;
 + 
 
-> INSERT  17 : 19  @  17
+> INSERT  17 : 20  @  17
 
 + 	private boolean hasRequestedWorlds = false;
 + 	private boolean waitingForWorlds = false;
++ 	private boolean ramdiskMode = false;
 
 > INSERT  3 : 4  @  3
 
 + 		this.field_146639_s = new ArrayList();
 
-> DELETE  4  @  4 : 13
+> INSERT  3 : 4  @  3
 
-> INSERT  13 : 30  @  13
++ 		this.ramdiskMode = SingleplayerServerController.isIssueDetected(IPCPacket1CIssueDetected.ISSUE_RAMDISK_MODE);
+
+> DELETE  1  @  1 : 10
+
+> CHANGE  8 : 9  @  8 : 9
+
+~ 		this.field_146638_t = new GuiSelectWorld.List(this.mc, ramdiskMode ? -10 : 0);
+
+> INSERT  4 : 21  @  4
 
 + 	public void updateScreen() {
 + 		if (!hasRequestedWorlds && SingleplayerServerController.isReady()) {
@@ -75,8 +85,13 @@
 + 	}
 + 
 
-> CHANGE  5 : 6  @  5 : 6
+> CHANGE  5 : 11  @  5 : 6
 
+~ 	public void handleTouchInput() throws IOException {
+~ 		super.handleTouchInput();
+~ 		this.field_146638_t.handleTouchInput();
+~ 	}
+~ 
 ~ 	private void func_146627_h() {
 
 > CHANGE  29 : 30  @  29 : 30
@@ -118,8 +133,13 @@
 
 > DELETE  1  @  1 : 3
 
-> INSERT  7 : 22  @  7
+> INSERT  7 : 27  @  7
 
++ 
++ 		if (ramdiskMode) {
++ 			this.drawCenteredString(this.fontRendererObj, I18n.format("selectWorld.ramdiskWarning"), this.width / 2,
++ 					height - 68, 11184810);
++ 		}
 + 
 + 		GlStateManager.pushMatrix();
 + 		GlStateManager.scale(0.75f, 0.75f, 0.75f);
@@ -155,4 +175,10 @@
 + 	}
 + 
 
+> CHANGE  10 : 13  @  10 : 12
+
+~ 		public List(Minecraft mcIn, int i) {
+~ 			super(mcIn, GuiSelectWorld.this.width, GuiSelectWorld.this.height, 32, GuiSelectWorld.this.height - 64 + i,
+~ 					36);
+
 > EOF
diff --git a/patches/minecraft/net/minecraft/client/gui/GuiSlider.edit.java b/patches/minecraft/net/minecraft/client/gui/GuiSlider.edit.java
index b28e0d58..10d2bba7 100644
--- a/patches/minecraft/net/minecraft/client/gui/GuiSlider.edit.java
+++ b/patches/minecraft/net/minecraft/client/gui/GuiSlider.edit.java
@@ -11,4 +11,11 @@
 
 > DELETE  1  @  1 : 4
 
+> INSERT  106 : 110  @  106
+
++ 
++ 	public boolean isSliderTouchEvents() {
++ 		return true;
++ 	}
+
 > EOF
diff --git a/patches/minecraft/net/minecraft/client/gui/GuiSlot.edit.java b/patches/minecraft/net/minecraft/client/gui/GuiSlot.edit.java
index 244974fe..d689e821 100644
--- a/patches/minecraft/net/minecraft/client/gui/GuiSlot.edit.java
+++ b/patches/minecraft/net/minecraft/client/gui/GuiSlot.edit.java
@@ -5,10 +5,13 @@
 # Version: 1.0
 # Author: lax1dude
 
-> INSERT  2 : 8  @  2
+> INSERT  2 : 11  @  2
 
 + import net.lax1dude.eaglercraft.v1_8.Mouse;
++ import net.lax1dude.eaglercraft.v1_8.PointerInputAbstraction;
++ import net.lax1dude.eaglercraft.v1_8.Touch;
 + import net.lax1dude.eaglercraft.v1_8.internal.EnumCursorType;
++ import net.lax1dude.eaglercraft.v1_8.internal.EnumTouchEvent;
 + import net.lax1dude.eaglercraft.v1_8.log4j.LogManager;
 + import net.lax1dude.eaglercraft.v1_8.log4j.Logger;
 + import net.lax1dude.eaglercraft.v1_8.opengl.GlStateManager;
@@ -34,17 +37,44 @@
 
 ~ 			this.drawSelectionBox(k, l, mouseXIn, mouseYIn, this.getSize());
 
-> CHANGE  168 : 169  @  168 : 170
+> INSERT  74 : 84  @  74
+
++ 		handleInput(Mouse.getEventButton(), Mouse.getEventButtonState(), Mouse.getDWheel());
++ 	}
++ 
++ 	public void handleTouchInput() {
++ 		mouseX = PointerInputAbstraction.getVCursorX() * width / mc.displayWidth;
++ 		mouseY = height - PointerInputAbstraction.getVCursorY() * height / mc.displayHeight - 1;
++ 		handleInput(0, Touch.getEventType() == EnumTouchEvent.TOUCHSTART, 0);
++ 	}
++ 
++ 	protected void handleInput(int eventButton, boolean eventState, int dWheel) {
+
+> CHANGE  1 : 2  @  1 : 3
+
+~ 			if (eventButton == 0 && eventState && this.mouseY >= this.top && this.mouseY <= this.bottom) {
+
+> CHANGE  12 : 13  @  12 : 13
+
+~ 			if (PointerInputAbstraction.getVCursorButtonDown(0) && this.getEnabled()) {
+
+> CHANGE  52 : 57  @  52 : 58
+
+~ 			if (dWheel != 0) {
+~ 				if (dWheel > 0) {
+~ 					dWheel = -1;
+~ 				} else if (dWheel < 0) {
+~ 					dWheel = 1;
+
+> CHANGE  2 : 3  @  2 : 3
+
+~ 				this.amountScrolled += (float) (dWheel * this.slotHeight / 2);
+
+> CHANGE  17 : 18  @  17 : 19
 
 ~ 	protected void drawSelectionBox(int mouseXIn, int mouseYIn, int parInt3, int parInt4, int i) {
 
-> INSERT  3 : 6  @  3
-
-+ 		int mx = Mouse.getX();
-+ 		int my = Mouse.getY();
-+ 
-
-> INSERT  31 : 34  @  31
+> INSERT  34 : 37  @  34
 
 + 				if (parInt3 >= i1 && parInt3 <= j1 && parInt4 >= k - 2 && parInt4 <= k + l + 1) {
 + 					Mouse.showCursor(EnumCursorType.HAND);
diff --git a/patches/minecraft/net/minecraft/client/gui/GuiTextField.edit.java b/patches/minecraft/net/minecraft/client/gui/GuiTextField.edit.java
index f378dee4..80740421 100644
--- a/patches/minecraft/net/minecraft/client/gui/GuiTextField.edit.java
+++ b/patches/minecraft/net/minecraft/client/gui/GuiTextField.edit.java
@@ -5,9 +5,10 @@
 # Version: 1.0
 # Author: lax1dude
 
-> CHANGE  4 : 7  @  4 : 9
+> CHANGE  4 : 8  @  4 : 9
 
 ~ 
+~ import net.lax1dude.eaglercraft.v1_8.minecraft.EnumInputEvent;
 ~ import net.lax1dude.eaglercraft.v1_8.opengl.GlStateManager;
 ~ import net.lax1dude.eaglercraft.v1_8.opengl.WorldRenderer;
 
@@ -44,4 +45,25 @@
 
 ~ 		GlStateManager.disableBlend();
 
+> INSERT  104 : 122  @  104
+
++ 
++ 	public void fireInputEvent(EnumInputEvent clipboardPaste, String param) {
++ 		if (!isFocused)
++ 			return;
++ 		switch (clipboardPaste) {
++ 		case CLIPBOARD_COPY:
++ 			GuiScreen.setClipboardString(this.getSelectedText());
++ 			break;
++ 		case CLIPBOARD_PASTE:
++ 			if (this.isEnabled) {
++ 				this.writeText(param != null ? param : GuiScreen.getClipboardString());
++ 			}
++ 			break;
++ 		default:
++ 			break;
++ 		}
++ 	}
++ 
+
 > EOF
diff --git a/patches/minecraft/net/minecraft/client/gui/GuiUtilRenderComponents.edit.java b/patches/minecraft/net/minecraft/client/gui/GuiUtilRenderComponents.edit.java
index 924a79c4..88eb0628 100644
--- a/patches/minecraft/net/minecraft/client/gui/GuiUtilRenderComponents.edit.java
+++ b/patches/minecraft/net/minecraft/client/gui/GuiUtilRenderComponents.edit.java
@@ -15,4 +15,11 @@
 
 > DELETE  1  @  1 : 2
 
+> INSERT  11 : 15  @  11
+
++ 	/**
++ 	 * This function is like the FontRenderer wrap function, except for chat
++ 	 * components
++ 	 */
+
 > EOF
diff --git a/patches/minecraft/net/minecraft/client/gui/GuiVideoSettings.edit.java b/patches/minecraft/net/minecraft/client/gui/GuiVideoSettings.edit.java
index 18744aa1..505bdaf2 100644
--- a/patches/minecraft/net/minecraft/client/gui/GuiVideoSettings.edit.java
+++ b/patches/minecraft/net/minecraft/client/gui/GuiVideoSettings.edit.java
@@ -5,12 +5,17 @@
 # Version: 1.0
 # Author: lax1dude
 
-> CHANGE  3 : 4  @  3 : 9
+> CHANGE  3 : 8  @  3 : 9
 
 ~ 
+~ import net.lax1dude.eaglercraft.v1_8.Display;
+~ import net.lax1dude.eaglercraft.v1_8.opengl.EaglercraftGPU;
+~ import net.lax1dude.eaglercraft.v1_8.opengl.ext.dynamiclights.DynamicLightsStateManager;
+~ import net.lax1dude.eaglercraft.v1_8.recording.ScreenRecordingController;
 
-> INSERT  8 : 11  @  8
+> INSERT  8 : 12  @  8
 
++ 	private boolean vsyncLock = false;
 + 	/**
 + 	 * + An array of all of GameSettings.Options's video options.
 + 	 */
@@ -26,21 +31,77 @@
 ~ 			GameSettings.Options.HUD_COORDS, GameSettings.Options.HUD_PLAYER, GameSettings.Options.HUD_STATS,
 ~ 			GameSettings.Options.HUD_WORLD, GameSettings.Options.HUD_24H, GameSettings.Options.CHUNK_FIX };
 
-> CHANGE  11 : 13  @  11 : 31
+> CHANGE  11 : 18  @  11 : 22
 
 ~ 		this.optionsRowList = new GuiOptionsRowList(this.mc, this.width, this.height, 32, this.height - 32, 25,
 ~ 				videoOptions);
+~ 		if (!DynamicLightsStateManager.isSupported()) {
+~ 			GuiOptionButton btn = ((GuiOptionsRowList) optionsRowList)
+~ 					.getButtonFor(GameSettings.Options.EAGLER_DYNAMIC_LIGHTS);
+~ 			if (btn != null) {
+~ 				btn.enabled = false;
 
-> CHANGE  7 : 8  @  7 : 8
+> DELETE  1  @  1 : 7
 
+> CHANGE  1 : 17  @  1 : 2
+
+~ 		if (EaglercraftGPU.checkOpenGLESVersion() < 300) {
+~ 			GuiOptionSlider btn = ((GuiOptionsRowList) optionsRowList).getSliderFor(GameSettings.Options.MIPMAP_LEVELS);
+~ 			if (btn != null) {
+~ 				btn.displayString = I18n.format(GameSettings.Options.MIPMAP_LEVELS.getEnumString()) + ": N/A";
+~ 				btn.sliderValue = 0.0f;
+~ 				btn.enabled = false;
+~ 			}
+~ 		}
+~ 		if (!Display.supportsFullscreen()) {
+~ 			GuiOptionButton btn = ((GuiOptionsRowList) optionsRowList).getButtonFor(GameSettings.Options.FULLSCREEN);
+~ 			if (btn != null) {
+~ 				btn.displayString = I18n.format(GameSettings.Options.FULLSCREEN.getEnumString()) + ": "
+~ 						+ I18n.format("options.off");
+~ 				btn.enabled = false;
+~ 			}
+~ 		}
+
+> CHANGE  7 : 13  @  7 : 8
+
+~ 	public void handleTouchInput() throws IOException {
+~ 		super.handleTouchInput();
+~ 		this.optionsRowList.handleTouchInput();
+~ 	}
+~ 
 ~ 	protected void actionPerformed(GuiButton parGuiButton) {
 
 > CHANGE  9 : 10  @  9 : 10
 
 ~ 	protected void mouseClicked(int parInt1, int parInt2, int parInt3) {
 
-> INSERT  8 : 9  @  8
+> CHANGE  4 : 5  @  4 : 5
+
+~ 			ScaledResolution scaledresolution = mc.scaledResolution = new ScaledResolution(mc);
+
+> INSERT  3 : 5  @  3
 
 + 			this.mc.voiceOverlay.setResolution(j, k);
++ 			this.mc.notifRenderer.setResolution(this.mc, j, k, scaledresolution.getScaleFactor());
+
+> CHANGE  9 : 10  @  9 : 10
+
+~ 			ScaledResolution scaledresolution = mc.scaledResolution = new ScaledResolution(mc);
+
+> INSERT  13 : 26  @  13
+
++ 
++ 	@Override
++ 	public void updateScreen() {
++ 		boolean vsyncLockEn = ScreenRecordingController.isVSyncLocked();
++ 		if (vsyncLockEn != vsyncLock) {
++ 			vsyncLock = vsyncLockEn;
++ 			GuiOptionButton btn = ((GuiOptionsRowList) optionsRowList).getButtonFor(GameSettings.Options.EAGLER_VSYNC);
++ 			if (btn != null) {
++ 				btn.enabled = !vsyncLockEn;
++ 			}
++ 		}
++ 	}
++ 
 
 > EOF
diff --git a/patches/minecraft/net/minecraft/client/gui/ScaledResolution.edit.java b/patches/minecraft/net/minecraft/client/gui/ScaledResolution.edit.java
new file mode 100644
index 00000000..2d8714a4
--- /dev/null
+++ b/patches/minecraft/net/minecraft/client/gui/ScaledResolution.edit.java
@@ -0,0 +1,20 @@
+
+# Eagler Context Redacted Diff
+# Copyright (c) 2024 lax1dude. All rights reserved.
+
+# Version: 1.0
+# Author: lax1dude
+
+> INSERT  12 : 16  @  12
+
++ 	/**
++ 	 * EAGLER NOTE: This constructor is deprecated! Use
++ 	 * Minecraft.getMinecraft().scaledResolution
++ 	 */
+
+> INSERT  10 : 12  @  10
+
++ 		i = Math.round(i * Math.max(parMinecraft.displayDPI, 0.5f));
++ 
+
+> EOF
diff --git a/patches/minecraft/net/minecraft/client/gui/ScreenChatOptions.edit.java b/patches/minecraft/net/minecraft/client/gui/ScreenChatOptions.edit.java
index 7a83650f..892d37c0 100644
--- a/patches/minecraft/net/minecraft/client/gui/ScreenChatOptions.edit.java
+++ b/patches/minecraft/net/minecraft/client/gui/ScreenChatOptions.edit.java
@@ -5,14 +5,32 @@
 # Version: 1.0
 # Author: lax1dude
 
-> DELETE  2  @  2 : 7
+> CHANGE  2 : 3  @  2 : 7
 
-> CHANGE  22 : 24  @  22 : 23
+~ import net.lax1dude.eaglercraft.v1_8.EagRuntime;
 
-~ 		for (int j = 0; j < field_146399_a.length; ++j) {
-~ 			GameSettings.Options gamesettings$options = field_146399_a[j];
+> INSERT  8 : 14  @  8
 
-> CHANGE  16 : 17  @  16 : 17
++ 			GameSettings.Options.CHAT_WIDTH, GameSettings.Options.REDUCED_DEBUG_INFO,
++ 			GameSettings.Options.EAGLER_PROFANITY_FILTER };
++ 	private static final GameSettings.Options[] no_profanity_filter = new GameSettings.Options[] {
++ 			GameSettings.Options.CHAT_VISIBILITY, GameSettings.Options.CHAT_COLOR, GameSettings.Options.CHAT_LINKS,
++ 			GameSettings.Options.CHAT_OPACITY, GameSettings.Options.CHAT_LINKS_PROMPT, GameSettings.Options.CHAT_SCALE,
++ 			GameSettings.Options.CHAT_HEIGHT_FOCUSED, GameSettings.Options.CHAT_HEIGHT_UNFOCUSED,
+
+> CHANGE  14 : 18  @  14 : 15
+
+~ 		boolean profanityFilterForce = EagRuntime.getConfiguration().isForceProfanityFilter();
+~ 		GameSettings.Options[] opts = profanityFilterForce ? no_profanity_filter : field_146399_a;
+~ 		for (int j = 0; j < opts.length; ++j) {
+~ 			GameSettings.Options gamesettings$options = opts[j];
+
+> CHANGE  12 : 14  @  12 : 14
+
+~ 		this.buttonList.add(new GuiButton(200, this.width / 2 - 100,
+~ 				this.height / 6 + (profanityFilterForce ? 130 : 154), I18n.format("gui.done", new Object[0])));
+
+> CHANGE  2 : 3  @  2 : 3
 
 ~ 	protected void actionPerformed(GuiButton parGuiButton) {
 
diff --git a/patches/minecraft/net/minecraft/client/gui/achievement/GuiAchievement.edit.java b/patches/minecraft/net/minecraft/client/gui/achievement/GuiAchievement.edit.java
index a211f58e..3c0d6ef1 100644
--- a/patches/minecraft/net/minecraft/client/gui/achievement/GuiAchievement.edit.java
+++ b/patches/minecraft/net/minecraft/client/gui/achievement/GuiAchievement.edit.java
@@ -11,7 +11,11 @@
 
 > DELETE  3  @  3 : 4
 
-> INSERT  114 : 146  @  114
+> CHANGE  48 : 49  @  48 : 49
+
+~ 		ScaledResolution scaledresolution = mc.scaledResolution;
+
+> INSERT  65 : 97  @  65
 
 + 	public int getHeight() {
 + 		if (this.theAchievement != null && this.notificationTime != 0L && Minecraft.getMinecraft().thePlayer != null) {
diff --git a/patches/minecraft/net/minecraft/client/gui/achievement/GuiAchievements.edit.java b/patches/minecraft/net/minecraft/client/gui/achievement/GuiAchievements.edit.java
index 42a6e0de..11f866c8 100644
--- a/patches/minecraft/net/minecraft/client/gui/achievement/GuiAchievements.edit.java
+++ b/patches/minecraft/net/minecraft/client/gui/achievement/GuiAchievements.edit.java
@@ -5,11 +5,12 @@
 # Version: 1.0
 # Author: lax1dude
 
-> CHANGE  2 : 7  @  2 : 4
+> CHANGE  2 : 8  @  2 : 4
 
 ~ import net.lax1dude.eaglercraft.v1_8.EaglercraftRandom;
 ~ 
 ~ import net.lax1dude.eaglercraft.v1_8.Mouse;
+~ import net.lax1dude.eaglercraft.v1_8.PointerInputAbstraction;
 ~ import net.lax1dude.eaglercraft.v1_8.minecraft.EaglerTextureAtlasSprite;
 ~ import net.lax1dude.eaglercraft.v1_8.opengl.GlStateManager;
 
@@ -28,7 +29,11 @@
 ~ 	protected int getCloseKey() {
 ~ 		return this.mc.gameSettings.keyBindInventory.getKeyCode();
 
-> CHANGE  76 : 77  @  76 : 77
+> CHANGE  11 : 12  @  11 : 12
+
+~ 			if (PointerInputAbstraction.getVCursorButtonDown(0)) {
+
+> CHANGE  64 : 65  @  64 : 65
 
 ~ 			GlStateManager.disableLighting();
 
diff --git a/patches/minecraft/net/minecraft/client/gui/achievement/GuiStats.edit.java b/patches/minecraft/net/minecraft/client/gui/achievement/GuiStats.edit.java
index 3692a793..35e7d51a 100644
--- a/patches/minecraft/net/minecraft/client/gui/achievement/GuiStats.edit.java
+++ b/patches/minecraft/net/minecraft/client/gui/achievement/GuiStats.edit.java
@@ -12,7 +12,7 @@
 + 
 + import com.google.common.collect.Lists;
 + 
-+ import net.lax1dude.eaglercraft.v1_8.Mouse;
++ import net.lax1dude.eaglercraft.v1_8.PointerInputAbstraction;
 + import net.lax1dude.eaglercraft.v1_8.opengl.GlStateManager;
 + import net.lax1dude.eaglercraft.v1_8.opengl.WorldRenderer;
 
@@ -22,11 +22,25 @@
 
 > DELETE  11  @  11 : 12
 
-> CHANGE  71 : 72  @  71 : 72
+> INSERT  32 : 39  @  32
+
++ 	public void handleTouchInput() throws IOException {
++ 		super.handleTouchInput();
++ 		if (this.displaySlot != null) {
++ 			this.displaySlot.handleTouchInput();
++ 		}
++ 	}
++ 
+
+> CHANGE  39 : 40  @  39 : 40
 
 ~ 	protected void actionPerformed(GuiButton parGuiButton) {
 
-> CHANGE  270 : 272  @  270 : 271
+> CHANGE  111 : 112  @  111 : 112
+
+~ 			if (!PointerInputAbstraction.getVCursorButtonDown(0)) {
+
+> CHANGE  158 : 160  @  158 : 159
 
 ~ 			for (int m = 0, l = StatList.objectMineStats.size(); m < l; ++m) {
 ~ 				StatCrafting statcrafting = StatList.objectMineStats.get(m);
diff --git a/patches/minecraft/net/minecraft/client/gui/inventory/GuiContainer.edit.java b/patches/minecraft/net/minecraft/client/gui/inventory/GuiContainer.edit.java
index 484f4f58..2dc25596 100644
--- a/patches/minecraft/net/minecraft/client/gui/inventory/GuiContainer.edit.java
+++ b/patches/minecraft/net/minecraft/client/gui/inventory/GuiContainer.edit.java
@@ -9,12 +9,14 @@
 
 ~ import java.util.List;
 
-> INSERT  1 : 8  @  1
+> INSERT  1 : 10  @  1
 
 + 
 + import com.google.common.collect.Sets;
 + 
++ import net.lax1dude.eaglercraft.v1_8.EagRuntime;
 + import net.lax1dude.eaglercraft.v1_8.Keyboard;
++ import net.lax1dude.eaglercraft.v1_8.Touch;
 + import net.lax1dude.eaglercraft.v1_8.minecraft.EaglerTextureAtlasSprite;
 + import net.lax1dude.eaglercraft.v1_8.opengl.GlStateManager;
 + import net.lax1dude.eaglercraft.v1_8.opengl.OpenGlHelper;
@@ -25,11 +27,29 @@
 
 > DELETE  8  @  8 : 9
 
-> INSERT  81 : 82  @  81
+> INSERT  39 : 43  @  39
+
++ 		if (primaryTouchPoint != -1 && Touch.fetchPointIdx(primaryTouchPoint) == -1) {
++ 			primaryTouchPoint = -1;
++ 			mouseReleased(lastTouchX, lastTouchY, 0);
++ 		}
+
+> CHANGE  30 : 31  @  30 : 31
+
+~ 			if (!this.mc.gameSettings.touchscreen && slot.canBeHovered() && this.isMouseOverSlot(slot, i, j)) {
+
+> INSERT  11 : 12  @  11
 
 + 			GlStateManager.enableAlpha();
 
-> CHANGE  107 : 108  @  107 : 108
+> DELETE  21  @  21 : 22
+
+> CHANGE  18 : 20  @  18 : 19
+
+~ 		if (!this.mc.gameSettings.touchscreen && inventoryplayer.getItemStack() == null && this.theSlot != null
+~ 				&& this.theSlot.getHasStack()) {
+
+> CHANGE  66 : 67  @  66 : 67
 
 ~ 				EaglerTextureAtlasSprite textureatlassprite = this.mc.getTextureMapBlocks().getAtlasSprite(s1);
 
@@ -37,7 +57,14 @@
 
 ~ 	protected void mouseClicked(int parInt1, int parInt2, int parInt3) {
 
-> CHANGE  126 : 129  @  126 : 127
+> CHANGE  20 : 24  @  20 : 24
+
+~ //			if (this.mc.gameSettings.touchscreen && flag1 && this.mc.thePlayer.inventory.getItemStack() == null) {
+~ //				this.mc.displayGuiScreen((GuiScreen) null);
+~ //				return;
+~ //			}
+
+> CHANGE  102 : 105  @  102 : 103
 
 ~ 					List<Slot> lst = this.inventorySlots.inventorySlots;
 ~ 					for (int n = 0, m = lst.size(); n < m; ++n) {
@@ -58,7 +85,7 @@
 > INSERT  1 : 12  @  1
 
 + 		} else if (parInt1 == 1) {
-+ 			showingCloseKey = System.currentTimeMillis();
++ 			showingCloseKey = EagRuntime.steadyTimeMillis();
 + 		} else {
 + 			this.checkHotbarKeys(parInt1);
 + 			if (this.theSlot != null && this.theSlot.getHasStack()) {
@@ -71,4 +98,67 @@
 
 > DELETE  1  @  1 : 2
 
+> INSERT  29 : 30  @  29
+
++ 			return;
+
+> INSERT  1 : 6  @  1
+
++ 		if (primaryTouchPoint != -1 && Touch.fetchPointIdx(primaryTouchPoint) == -1) {
++ 			primaryTouchPoint = -1;
++ 			mouseReleased(lastTouchX, lastTouchY, 0);
++ 		}
++ 	}
+
+> INSERT  1 : 3  @  1
+
++ 	protected float getTouchModeScale() {
++ 		return 1.25f;
+
+> INSERT  1 : 44  @  1
+
++ 
++ 	private int primaryTouchPoint = -1;
++ 	private int lastTouchX = -1;
++ 	private int lastTouchY = -1;
++ 
++ 	protected void touchStarted(int touchX, int touchY, int uid) {
++ 		if (primaryTouchPoint == -1) {
++ 			primaryTouchPoint = uid;
++ 			lastTouchX = touchX;
++ 			lastTouchY = touchY;
++ 			mouseClicked(touchX, touchY, 0);
++ 		}
++ 	}
++ 
++ 	protected void touchMoved(int touchX, int touchY, int uid) {
++ 		if (primaryTouchPoint == uid) {
++ 			lastTouchX = touchX;
++ 			lastTouchY = touchY;
++ 			mouseClickMove(touchX, touchY, 0, 0l);
++ 		}
++ 	}
++ 
++ 	protected void touchEndMove(int touchX, int touchY, int uid) {
++ 		if (primaryTouchPoint == uid) {
++ 			primaryTouchPoint = -1;
++ 			lastTouchX = touchX;
++ 			lastTouchY = touchY;
++ 			mouseReleased(touchX, touchY, 0);
++ 		}
++ 	}
++ 
++ 	protected void touchTapped(int touchX, int touchY, int uid) {
++ 		if (primaryTouchPoint == uid) {
++ 			primaryTouchPoint = -1;
++ 			lastTouchX = touchX;
++ 			lastTouchY = touchY;
++ 			mouseReleased(touchX, touchY, 0);
++ 		}
++ 	}
++ 
++ 	protected boolean shouldTouchGenerateMouseEvents() {
++ 		return false;
++ 	}
+
 > EOF
diff --git a/patches/minecraft/net/minecraft/client/gui/inventory/GuiContainerCreative.edit.java b/patches/minecraft/net/minecraft/client/gui/inventory/GuiContainerCreative.edit.java
index 80af564d..ce5ef317 100644
--- a/patches/minecraft/net/minecraft/client/gui/inventory/GuiContainerCreative.edit.java
+++ b/patches/minecraft/net/minecraft/client/gui/inventory/GuiContainerCreative.edit.java
@@ -7,14 +7,16 @@
 
 > DELETE  2  @  2 : 3
 
-> INSERT  4 : 11  @  4
+> INSERT  4 : 13  @  4
 
 + 
 + import com.google.common.collect.Lists;
 + 
 + import net.lax1dude.eaglercraft.v1_8.Keyboard;
 + import net.lax1dude.eaglercraft.v1_8.Mouse;
++ import net.lax1dude.eaglercraft.v1_8.PointerInputAbstraction;
 + import net.lax1dude.eaglercraft.v1_8.internal.EnumCursorType;
++ import net.lax1dude.eaglercraft.v1_8.minecraft.EnumInputEvent;
 + import net.lax1dude.eaglercraft.v1_8.opengl.GlStateManager;
 
 > DELETE  4  @  4 : 7
@@ -64,13 +66,41 @@
 ~ 			for (int m = 0; m < CreativeTabs.creativeTabArray.length; ++m) {
 ~ 				CreativeTabs creativetabs = CreativeTabs.creativeTabArray[m];
 
-> CHANGE  127 : 130  @  127 : 129
+> INSERT  10 : 26  @  10
+
++ 	@Override
++ 	protected void touchTapped(int touchX, int touchY, int uid) {
++ 		int l = touchX - this.guiLeft;
++ 		int i1 = touchY - this.guiTop;
++ 
++ 		for (int m = 0; m < CreativeTabs.creativeTabArray.length; ++m) {
++ 			CreativeTabs creativetabs = CreativeTabs.creativeTabArray[m];
++ 			if (this.func_147049_a(creativetabs, l, i1)) {
++ 				this.setCurrentCreativeTab(creativetabs);
++ 				break;
++ 			}
++ 		}
++ 
++ 		super.touchTapped(touchX, touchY, uid);
++ 	}
++ 
+
+> CHANGE  93 : 94  @  93 : 94
+
+~ 		boolean flag = PointerInputAbstraction.getVCursorButtonDown(0);
+
+> CHANGE  23 : 26  @  23 : 25
 
 ~ 		for (int m = 0; m < CreativeTabs.creativeTabArray.length; ++m) {
 ~ 			if (this.renderCreativeInventoryHoveringText(CreativeTabs.creativeTabArray[m], i, j)) {
 ~ 				Mouse.showCursor(EnumCursorType.HAND);
 
-> CHANGE  24 : 26  @  24 : 25
+> CHANGE  16 : 18  @  16 : 17
+
+~ 			List list = itemstack.getTooltipProfanityFilter(this.mc.thePlayer,
+~ 					this.mc.gameSettings.advancedItemTooltips);
+
+> CHANGE  7 : 9  @  7 : 8
 
 ~ 					for (int m = 0; m < CreativeTabs.creativeTabArray.length; ++m) {
 ~ 						CreativeTabs creativetabs1 = CreativeTabs.creativeTabArray[m];
@@ -84,11 +114,22 @@
 
 ~ 	protected void actionPerformed(GuiButton parGuiButton) {
 
-> INSERT  139 : 143  @  139
+> INSERT  139 : 154  @  139
 
 + 
 + 	public boolean blockPTTKey() {
 + 		return searchField.isFocused();
 + 	}
++ 
++ 	@Override
++ 	public boolean showCopyPasteButtons() {
++ 		return searchField.isFocused();
++ 	}
++ 
++ 	@Override
++ 	public void fireInputEvent(EnumInputEvent event, String param) {
++ 		searchField.fireInputEvent(event, param);
++ 	}
++ 
 
 > EOF
diff --git a/patches/minecraft/net/minecraft/client/gui/inventory/GuiEditSign.edit.java b/patches/minecraft/net/minecraft/client/gui/inventory/GuiEditSign.edit.java
index 91e4dea9..dda3843d 100644
--- a/patches/minecraft/net/minecraft/client/gui/inventory/GuiEditSign.edit.java
+++ b/patches/minecraft/net/minecraft/client/gui/inventory/GuiEditSign.edit.java
@@ -5,16 +5,31 @@
 # Version: 1.0
 # Author: lax1dude
 
-> CHANGE  2 : 4  @  2 : 3
+> CHANGE  2 : 7  @  2 : 3
 
+~ import net.lax1dude.eaglercraft.v1_8.Display;
 ~ import net.lax1dude.eaglercraft.v1_8.Keyboard;
+~ import net.lax1dude.eaglercraft.v1_8.PointerInputAbstraction;
+~ import net.lax1dude.eaglercraft.v1_8.minecraft.GuiScreenVisualViewport;
 ~ import net.lax1dude.eaglercraft.v1_8.opengl.GlStateManager;
 
 > DELETE  4  @  4 : 5
 
-> DELETE  7  @  7 : 8
+> INSERT  1 : 2  @  1
 
-> CHANGE  34 : 35  @  34 : 35
++ import net.minecraft.client.renderer.tileentity.TileEntitySignRenderer;
+
+> DELETE  6  @  6 : 7
+
+> CHANGE  1 : 2  @  1 : 2
+
+~ public class GuiEditSign extends GuiScreenVisualViewport {
+
+> CHANGE  28 : 29  @  28 : 29
+
+~ 	public void updateScreen0() {
+
+> CHANGE  3 : 4  @  3 : 4
 
 ~ 	protected void actionPerformed(GuiButton parGuiButton) {
 
@@ -22,11 +37,33 @@
 
 ~ 	protected void keyTyped(char parChar1, int parInt1) {
 
-> INSERT  68 : 72  @  68
+> CHANGE  25 : 26  @  25 : 26
+
+~ 	public void drawScreen0(int i, int j, float f) {
+
+> CHANGE  37 : 47  @  37 : 38
+
+~ 		try {
+~ 			TileEntitySignRenderer.disableProfanityFilter = true;
+~ 			TileEntityRendererDispatcher.instance.renderTileEntityAt(this.tileSign, -0.5D,
+~ 					(PointerInputAbstraction.isTouchMode() && (Display.getVisualViewportH() / mc.displayHeight) < 0.75f)
+~ 							? -0.25D
+~ 							: -0.75D,
+~ 					-0.5D, 0.0F);
+~ 		} finally {
+~ 			TileEntitySignRenderer.disableProfanityFilter = false;
+~ 		}
+
+> CHANGE  2 : 3  @  2 : 3
+
+~ 		super.drawScreen0(i, j, f);
+
+> INSERT  1 : 6  @  1
 
 + 
 + 	public boolean blockPTTKey() {
 + 		return true;
 + 	}
++ 
 
 > EOF
diff --git a/patches/minecraft/net/minecraft/client/multiplayer/ChunkProviderClient.edit.java b/patches/minecraft/net/minecraft/client/multiplayer/ChunkProviderClient.edit.java
index ef37860a..37b40806 100644
--- a/patches/minecraft/net/minecraft/client/multiplayer/ChunkProviderClient.edit.java
+++ b/patches/minecraft/net/minecraft/client/multiplayer/ChunkProviderClient.edit.java
@@ -7,19 +7,32 @@
 
 > DELETE  2  @  2 : 3
 
-> INSERT  1 : 6  @  1
+> INSERT  1 : 7  @  1
 
 + 
 + import com.google.common.collect.Lists;
 + 
++ import net.lax1dude.eaglercraft.v1_8.EagRuntime;
 + import net.lax1dude.eaglercraft.v1_8.log4j.LogManager;
 + import net.lax1dude.eaglercraft.v1_8.log4j.Logger;
 
 > DELETE  10  @  10 : 12
 
-> CHANGE  50 : 52  @  50 : 52
+> CHANGE  48 : 49  @  48 : 49
+
+~ 		long i = EagRuntime.steadyTimeMillis();
+
+> CHANGE  1 : 3  @  1 : 3
 
 ~ 		for (int j = 0, k = this.chunkListing.size(); j < k; ++j) {
-~ 			this.chunkListing.get(j).func_150804_b(System.currentTimeMillis() - i > 5L);
+~ 			this.chunkListing.get(j).func_150804_b(EagRuntime.steadyTimeMillis() - i > 5L);
+
+> CHANGE  2 : 3  @  2 : 3
+
+~ 		if (EagRuntime.steadyTimeMillis() - i > 100L) {
+
+> CHANGE  1 : 2  @  1 : 2
+
+~ 					new Object[] { Long.valueOf(EagRuntime.steadyTimeMillis() - i) });
 
 > EOF
diff --git a/patches/minecraft/net/minecraft/client/multiplayer/GuiConnecting.edit.java b/patches/minecraft/net/minecraft/client/multiplayer/GuiConnecting.edit.java
index db5e1813..430109d9 100644
--- a/patches/minecraft/net/minecraft/client/multiplayer/GuiConnecting.edit.java
+++ b/patches/minecraft/net/minecraft/client/multiplayer/GuiConnecting.edit.java
@@ -5,11 +5,15 @@
 # Version: 1.0
 # Author: lax1dude
 
-> CHANGE  3 : 13  @  3 : 6
+> CHANGE  3 : 21  @  3 : 6
 
+~ import java.util.List;
 ~ 
+~ import net.lax1dude.eaglercraft.v1_8.EagRuntime;
+~ import net.lax1dude.eaglercraft.v1_8.cookie.ServerCookieDataStore;
 ~ import net.lax1dude.eaglercraft.v1_8.internal.EnumEaglerConnectionState;
-~ import net.lax1dude.eaglercraft.v1_8.internal.EnumServerRateLimit;
+~ import net.lax1dude.eaglercraft.v1_8.internal.IWebSocketClient;
+~ import net.lax1dude.eaglercraft.v1_8.internal.IWebSocketFrame;
 ~ import net.lax1dude.eaglercraft.v1_8.internal.PlatformNetworking;
 ~ import net.lax1dude.eaglercraft.v1_8.log4j.LogManager;
 ~ import net.lax1dude.eaglercraft.v1_8.log4j.Logger;
@@ -17,23 +21,31 @@
 ~ import net.lax1dude.eaglercraft.v1_8.socket.ConnectionHandshake;
 ~ import net.lax1dude.eaglercraft.v1_8.socket.EaglercraftNetworkManager;
 ~ import net.lax1dude.eaglercraft.v1_8.socket.RateLimitTracker;
+~ import net.lax1dude.eaglercraft.v1_8.socket.WebSocketNetworkManager;
+~ import net.lax1dude.eaglercraft.v1_8.socket.protocol.GamePluginMessageConstants;
+~ import net.lax1dude.eaglercraft.v1_8.socket.protocol.GamePluginMessageProtocol;
+~ import net.lax1dude.eaglercraft.v1_8.socket.protocol.client.GameProtocolMessageController;
 
 > CHANGE  4 : 5  @  4 : 8
 
 ~ import net.minecraft.client.network.NetHandlerPlayClient;
 
-> DELETE  2  @  2 : 5
+> CHANGE  2 : 3  @  2 : 5
+
+~ import net.minecraft.network.play.client.C17PacketCustomPayload;
 
 > DELETE  1  @  1 : 4
 
 > DELETE  2  @  2 : 3
 
-> CHANGE  1 : 5  @  1 : 2
+> CHANGE  1 : 7  @  1 : 2
 
+~ 	private IWebSocketClient webSocket;
 ~ 	private EaglercraftNetworkManager networkManager;
 ~ 	private String currentAddress;
 ~ 	private String currentPassword;
 ~ 	private boolean allowPlaintext;
+~ 	private boolean allowCookies;
 
 > INSERT  1 : 2  @  1
 
@@ -63,36 +75,52 @@
 
 ~ 		String serveraddress = AddressResolver.resolveURI(parServerData);
 
-> CHANGE  2 : 7  @  2 : 3
+> CHANGE  2 : 8  @  2 : 3
 
 ~ 		if (RateLimitTracker.isLockedOut(serveraddress)) {
 ~ 			logger.error("Server locked this client out on a previous connection, will not attempt to reconnect");
 ~ 		} else {
-~ 			this.connect(serveraddress, password, allowPlaintext);
+~ 			this.connect(serveraddress, password, allowPlaintext,
+~ 					parServerData.enableCookies && EagRuntime.getConfiguration().isEnableServerCookies());
 ~ 		}
 
-> INSERT  3 : 16  @  3
+> CHANGE  3 : 4  @  3 : 7
 
-+ 		this(parGuiScreen, mcIn, hostName, port, false);
-+ 	}
-+ 
-+ 	public GuiConnecting(GuiScreen parGuiScreen, Minecraft mcIn, String hostName, int port, boolean allowPlaintext) {
-+ 		this(parGuiScreen, mcIn, hostName, port, null, allowPlaintext);
-+ 	}
-+ 
-+ 	public GuiConnecting(GuiScreen parGuiScreen, Minecraft mcIn, String hostName, int port, String password) {
-+ 		this(parGuiScreen, mcIn, hostName, port, password, false);
-+ 	}
-+ 
-+ 	public GuiConnecting(GuiScreen parGuiScreen, Minecraft mcIn, String hostName, int port, String password,
-+ 			boolean allowPlaintext) {
-
-> CHANGE  3 : 4  @  3 : 4
-
-~ 		this.connect(hostName, password, allowPlaintext);
+~ 		this(parGuiScreen, mcIn, hostName, port, false, EagRuntime.getConfiguration().isEnableServerCookies());
 
 > CHANGE  2 : 5  @  2 : 7
 
+~ 	public GuiConnecting(GuiScreen parGuiScreen, Minecraft mcIn, String hostName, int port, boolean allowCookies) {
+~ 		this(parGuiScreen, mcIn, hostName, port, false, allowCookies);
+~ 	}
+
+> CHANGE  1 : 5  @  1 : 5
+
+~ 	public GuiConnecting(GuiScreen parGuiScreen, Minecraft mcIn, String hostName, int port, boolean allowPlaintext,
+~ 			boolean allowCookies) {
+~ 		this(parGuiScreen, mcIn, hostName, port, null, allowPlaintext, allowCookies);
+~ 	}
+
+> CHANGE  1 : 5  @  1 : 15
+
+~ 	public GuiConnecting(GuiScreen parGuiScreen, Minecraft mcIn, String hostName, int port, String password,
+~ 			boolean allowCookies) {
+~ 		this(parGuiScreen, mcIn, hostName, port, password, false, allowCookies);
+~ 	}
+
+> CHANGE  1 : 9  @  1 : 9
+
+~ 	public GuiConnecting(GuiScreen parGuiScreen, Minecraft mcIn, String hostName, int port, String password,
+~ 			boolean allowPlaintext, boolean allowCookies) {
+~ 		this.mc = mcIn;
+~ 		this.previousGuiScreen = parGuiScreen;
+~ 		mcIn.loadWorld((WorldClient) null);
+~ 		this.connect(hostName, password, allowPlaintext,
+~ 				allowCookies && EagRuntime.getConfiguration().isEnableServerCookies());
+~ 	}
+
+> CHANGE  1 : 4  @  1 : 7
+
 ~ 	public GuiConnecting(GuiConnecting previous, String password) {
 ~ 		this(previous, password, false);
 ~ 	}
@@ -102,73 +130,87 @@
 ~ 	public GuiConnecting(GuiConnecting previous, String password, boolean allowPlaintext) {
 ~ 		this.mc = previous.mc;
 ~ 		this.previousGuiScreen = previous.previousGuiScreen;
-~ 		this.connect(previous.currentAddress, password, allowPlaintext);
+~ 		this.connect(previous.currentAddress, password, allowPlaintext, previous.allowCookies);
 ~ 	}
 
-> CHANGE  1 : 6  @  1 : 15
+> CHANGE  1 : 6  @  1 : 3
 
-~ 	private void connect(String ip, String password, boolean allowPlaintext) {
+~ 	private void connect(String ip, String password, boolean allowPlaintext, boolean allowCookies) {
 ~ 		this.currentAddress = ip;
 ~ 		this.currentPassword = password;
 ~ 		this.allowPlaintext = allowPlaintext;
-~ 	}
+~ 		this.allowCookies = allowCookies;
 
-> CHANGE  1 : 41  @  1 : 8
+> CHANGE  3 : 14  @  3 : 6
 
-~ 	public void updateScreen() {
 ~ 		++timer;
 ~ 		if (timer > 1) {
 ~ 			if (this.currentAddress == null) {
 ~ 				mc.displayGuiScreen(GuiDisconnected.createRateLimitKick(previousGuiScreen));
-~ 			} else if (this.networkManager == null) {
+~ 			} else if (webSocket == null) {
 ~ 				logger.info("Connecting to: {}", currentAddress);
-~ 				this.networkManager = new EaglercraftNetworkManager(currentAddress);
-~ 				this.networkManager.connect();
-~ 			} else {
-~ 				if (this.networkManager.isChannelOpen()) {
+~ 				webSocket = PlatformNetworking.openWebSocket(currentAddress);
+~ 				if (webSocket == null) {
+~ 					mc.displayGuiScreen(new GuiDisconnected(previousGuiScreen, "connect.failed",
+~ 							new ChatComponentText("Could not open WebSocket to \"" + currentAddress + "\"!")));
+~ 				}
+
+> CHANGE  1 : 79  @  1 : 2
+
+~ 				if (webSocket.getState() == EnumEaglerConnectionState.CONNECTED) {
 ~ 					if (!hasOpened) {
 ~ 						hasOpened = true;
 ~ 						logger.info("Logging in: {}", currentAddress);
-~ 						if (ConnectionHandshake.attemptHandshake(this.mc, this, previousGuiScreen, currentPassword,
-~ 								allowPlaintext)) {
+~ 						byte[] cookieData = null;
+~ 						if (allowCookies) {
+~ 							ServerCookieDataStore.ServerCookie cookie = ServerCookieDataStore
+~ 									.loadCookie(currentAddress);
+~ 							if (cookie != null) {
+~ 								cookieData = cookie.cookie;
+~ 							}
+~ 						}
+~ 						if (ConnectionHandshake.attemptHandshake(this.mc, webSocket, this, previousGuiScreen,
+~ 								currentPassword, allowPlaintext, allowCookies, cookieData)) {
 ~ 							logger.info("Handshake Success");
+~ 							this.networkManager = new WebSocketNetworkManager(webSocket);
 ~ 							this.networkManager.setPluginInfo(ConnectionHandshake.pluginBrand,
 ~ 									ConnectionHandshake.pluginVersion);
 ~ 							mc.bungeeOutdatedMsgTimer = 80;
 ~ 							mc.clearTitles();
 ~ 							this.networkManager.setConnectionState(EnumConnectionState.PLAY);
-~ 							this.networkManager.setNetHandler(new NetHandlerPlayClient(this.mc, previousGuiScreen,
-~ 									this.networkManager, this.mc.getSession().getProfile()));
+~ 							NetHandlerPlayClient netHandler = new NetHandlerPlayClient(this.mc, previousGuiScreen,
+~ 									this.networkManager, this.mc.getSession().getProfile());
+~ 							this.networkManager.setNetHandler(netHandler);
+~ 							netHandler.setEaglerMessageController(new GameProtocolMessageController(
+~ 									GamePluginMessageProtocol.getByVersion(ConnectionHandshake.protocolVersion),
+~ 									GamePluginMessageConstants.CLIENT_TO_SERVER,
+~ 									GameProtocolMessageController
+~ 											.createClientHandler(ConnectionHandshake.protocolVersion, netHandler),
+~ 									(ch, msg) -> netHandler.addToSendQueue(new C17PacketCustomPayload(ch, msg))));
 ~ 						} else {
 ~ 							if (mc.currentScreen == this) {
-~ 								checkLowLevelRatelimit();
-~ 							}
-~ 							if (mc.currentScreen == this) {
+~ 								checkRatelimit();
 ~ 								logger.info("Handshake Failure");
 ~ 								mc.getSession().reset();
 ~ 								mc.displayGuiScreen(
 ~ 										new GuiDisconnected(previousGuiScreen, "connect.failed", new ChatComponentText(
 ~ 												"Handshake Failure\n\nAre you sure this is an eagler 1.8 server?")));
 ~ 							}
-~ 							if (!PlatformNetworking.playConnectionState().isClosed()) {
-~ 								PlatformNetworking.playDisconnect();
-~ 							}
+~ 							webSocket.close();
 ~ 							return;
 ~ 						}
-
-> CHANGE  1 : 4  @  1 : 7
-
-~ 					try {
-~ 						this.networkManager.processReceivedPackets();
-~ 					} catch (IOException ex) {
-
-> CHANGE  1 : 29  @  1 : 5
-
+~ 					}
+~ 					if (this.networkManager != null) {
+~ 						try {
+~ 							this.networkManager.processReceivedPackets();
+~ 						} catch (IOException ex) {
+~ 						}
+~ 					}
 ~ 				} else {
-~ 					if (PlatformNetworking.playConnectionState() == EnumEaglerConnectionState.FAILED) {
+~ 					if (webSocket.getState() == EnumEaglerConnectionState.FAILED) {
 ~ 						if (!hasOpened) {
 ~ 							mc.getSession().reset();
-~ 							checkLowLevelRatelimit();
+~ 							checkRatelimit();
 ~ 							if (mc.currentScreen == this) {
 ~ 								if (RateLimitTracker.isProbablyLockedOut(currentAddress)) {
 ~ 									mc.displayGuiScreen(GuiDisconnected.createRateLimitKick(previousGuiScreen));
@@ -179,9 +221,9 @@
 ~ 							}
 ~ 						}
 ~ 					} else {
-~ 						if (this.networkManager.checkDisconnected()) {
+~ 						if (this.networkManager != null && this.networkManager.checkDisconnected()) {
 ~ 							this.mc.getSession().reset();
-~ 							checkLowLevelRatelimit();
+~ 							checkRatelimit();
 ~ 							if (mc.currentScreen == this) {
 ~ 								if (RateLimitTracker.isProbablyLockedOut(currentAddress)) {
 ~ 									mc.displayGuiScreen(GuiDisconnected.createRateLimitKick(previousGuiScreen));
@@ -192,12 +234,21 @@
 ~ 							}
 ~ 						}
 ~ 					}
+~ 				}
+
+> INSERT  1 : 8  @  1
+
++ 			if (timer > 200) {
++ 				if (webSocket != null) {
++ 					webSocket.close();
++ 				}
++ 				mc.displayGuiScreen(new GuiDisconnected(previousGuiScreen, "connect.failed",
++ 						new ChatComponentText("Handshake timed out")));
++ 			}
 
 > DELETE  1  @  1 : 2
 
-> DELETE  1  @  1 : 11
-
-> CHANGE  4 : 5  @  4 : 5
+> CHANGE  2 : 3  @  2 : 3
 
 ~ 	protected void keyTyped(char parChar1, int parInt1) {
 
@@ -210,25 +261,41 @@
 
 ~ 	protected void actionPerformed(GuiButton parGuiButton) {
 
-> CHANGE  13 : 14  @  13 : 14
+> INSERT  4 : 6  @  4
+
++ 			} else if (this.webSocket != null) {
++ 				this.webSocket.close();
+
+> CHANGE  9 : 10  @  9 : 10
 
 ~ 		if (this.networkManager == null || !this.networkManager.isChannelOpen()) {
 
-> INSERT  9 : 23  @  9
+> INSERT  9 : 34  @  9
 
 + 
-+ 	private void checkLowLevelRatelimit() {
-+ 		EnumServerRateLimit rateLimit = PlatformNetworking.getRateLimit();
-+ 		if (rateLimit == EnumServerRateLimit.BLOCKED) {
-+ 			RateLimitTracker.registerBlock(currentAddress);
-+ 			mc.displayGuiScreen(GuiDisconnected.createRateLimitKick(previousGuiScreen));
-+ 			logger.info("Handshake Failure: Too Many Requests!");
-+ 		} else if (rateLimit == EnumServerRateLimit.LOCKED_OUT) {
-+ 			RateLimitTracker.registerLockOut(currentAddress);
-+ 			mc.displayGuiScreen(GuiDisconnected.createRateLimitKick(previousGuiScreen));
-+ 			logger.info("Handshake Failure: Too Many Requests!");
-+ 			logger.info("Server has locked this client out");
++ 	private void checkRatelimit() {
++ 		if (this.webSocket != null) {
++ 			List<IWebSocketFrame> strFrames = webSocket.getNextStringFrames();
++ 			if (strFrames != null) {
++ 				for (int i = 0; i < strFrames.size(); ++i) {
++ 					String str = strFrames.get(i).getString();
++ 					if (str.equalsIgnoreCase("BLOCKED")) {
++ 						RateLimitTracker.registerBlock(currentAddress);
++ 						mc.displayGuiScreen(GuiDisconnected.createRateLimitKick(previousGuiScreen));
++ 						logger.info("Handshake Failure: Too Many Requests!");
++ 					} else if (str.equalsIgnoreCase("LOCKED")) {
++ 						RateLimitTracker.registerLockOut(currentAddress);
++ 						mc.displayGuiScreen(GuiDisconnected.createRateLimitKick(previousGuiScreen));
++ 						logger.info("Handshake Failure: Too Many Requests!");
++ 						logger.info("Server has locked this client out");
++ 					}
++ 				}
++ 			}
 + 		}
 + 	}
++ 
++ 	public boolean canCloseGui() {
++ 		return false;
++ 	}
 
 > EOF
diff --git a/patches/minecraft/net/minecraft/client/multiplayer/PlayerControllerMP.edit.java b/patches/minecraft/net/minecraft/client/multiplayer/PlayerControllerMP.edit.java
index 979b68aa..057f10a4 100644
--- a/patches/minecraft/net/minecraft/client/multiplayer/PlayerControllerMP.edit.java
+++ b/patches/minecraft/net/minecraft/client/multiplayer/PlayerControllerMP.edit.java
@@ -5,10 +5,11 @@
 # Version: 1.0
 # Author: lax1dude
 
-> INSERT  2 : 5  @  2
+> INSERT  2 : 6  @  2
 
 + import java.io.IOException;
 + 
++ import net.lax1dude.eaglercraft.v1_8.ClientUUIDLoadingCache;
 + import net.lax1dude.eaglercraft.v1_8.socket.EaglercraftNetworkManager;
 
 > DELETE  6  @  6 : 7
@@ -17,7 +18,7 @@
 
 + import net.minecraft.util.ChatComponentText;
 
-> CHANGE  228 : 240  @  228 : 229
+> CHANGE  228 : 242  @  228 : 229
 
 ~ 			try {
 ~ 				this.netClientHandler.getNetworkManager().processReceivedPackets();
@@ -31,6 +32,8 @@
 ~ 			}
 ~ 			this.netClientHandler.getSkinCache().flush();
 ~ 			this.netClientHandler.getCapeCache().flush();
+~ 			this.netClientHandler.getNotifManager().runTick();
+~ 			ClientUUIDLoadingCache.update();
 
 > CHANGE  96 : 98  @  96 : 98
 
diff --git a/patches/minecraft/net/minecraft/client/multiplayer/ServerData.edit.java b/patches/minecraft/net/minecraft/client/multiplayer/ServerData.edit.java
index 2d8c84de..e4f32ad8 100644
--- a/patches/minecraft/net/minecraft/client/multiplayer/ServerData.edit.java
+++ b/patches/minecraft/net/minecraft/client/multiplayer/ServerData.edit.java
@@ -5,13 +5,14 @@
 # Version: 1.0
 # Author: lax1dude
 
-> INSERT  2 : 13  @  2
+> INSERT  2 : 14  @  2
 
 + import java.io.IOException;
 + 
 + import org.json.JSONArray;
 + import org.json.JSONObject;
 + 
++ import net.lax1dude.eaglercraft.v1_8.EagRuntime;
 + import net.lax1dude.eaglercraft.v1_8.internal.IServerQuery;
 + import net.lax1dude.eaglercraft.v1_8.internal.QueryResponse;
 + import net.lax1dude.eaglercraft.v1_8.log4j.LogManager;
@@ -33,7 +34,7 @@
 
 ~ 	public boolean hideAddress = false;
 
-> INSERT  1 : 9  @  1
+> INSERT  1 : 10  @  1
 
 + 	public IServerQuery currentQuery = null;
 + 	public final ResourceLocation iconResourceLocation;
@@ -43,6 +44,7 @@
 + 	public boolean hasPing = false;
 + 	public boolean serverIconEnabled = false;
 + 	public boolean isDefault = false;
++ 	public boolean enableCookies;
 
 > INSERT  1 : 5  @  1
 
@@ -51,35 +53,50 @@
 + 	private static int serverTextureId = 0;
 + 
 
-> INSERT  4 : 5  @  4
+> INSERT  4 : 6  @  4
 
 + 		this.iconResourceLocation = new ResourceLocation("eagler:servers/icons/tex_" + serverTextureId++);
++ 		this.enableCookies = EagRuntime.getConfiguration().isEnableServerCookies();
 
 > DELETE  6  @  6 : 9
 
-> INSERT  7 : 9  @  7
+> INSERT  7 : 10  @  7
 
 + 		nbttagcompound.setBoolean("hideAddress", this.hideAddress);
++ 		nbttagcompound.setBoolean("enableCookies", this.enableCookies);
 + 
 
 > DELETE  13  @  13 : 16
 
-> INSERT  11 : 17  @  11
+> CHANGE  11 : 16  @  11 : 13
 
-+ 		if (nbtCompound.hasKey("hideAddress", 1)) {
-+ 			serverdata.hideAddress = nbtCompound.getBoolean("hideAddress");
-+ 		} else {
-+ 			serverdata.hideAddress = false;
-+ 		}
-+ 
+~ 		if (nbtCompound.hasKey("hideAddress", 1)) {
+~ 			serverdata.hideAddress = nbtCompound.getBoolean("hideAddress");
+~ 		} else {
+~ 			serverdata.hideAddress = false;
+~ 		}
 
-> DELETE  3  @  3 : 11
+> CHANGE  1 : 6  @  1 : 4
 
-> CHANGE  8 : 9  @  8 : 9
+~ 		if (nbtCompound.hasKey("enableCookies", 1)) {
+~ 			serverdata.enableCookies = nbtCompound.getBoolean("enableCookies");
+~ 		} else {
+~ 			serverdata.enableCookies = true;
+~ 		}
+
+> CHANGE  1 : 2  @  1 : 3
+
+~ 		return serverdata;
+
+> CHANGE  10 : 11  @  10 : 11
 
 ~ 		this.hideAddress = serverDataIn.hideAddress;
 
-> INSERT  6 : 8  @  6
+> INSERT  1 : 2  @  1
+
++ 		this.enableCookies = serverDataIn.enableCookies;
+
+> INSERT  5 : 7  @  5
 
 + 		public static final ServerResourceMode[] _VALUES = values();
 + 
diff --git a/patches/minecraft/net/minecraft/client/multiplayer/ServerList.edit.java b/patches/minecraft/net/minecraft/client/multiplayer/ServerList.edit.java
index 1d6a6fcf..5e33c581 100644
--- a/patches/minecraft/net/minecraft/client/multiplayer/ServerList.edit.java
+++ b/patches/minecraft/net/minecraft/client/multiplayer/ServerList.edit.java
@@ -60,7 +60,7 @@
 + 
 + 	public void loadServerList(byte[] localStorage) {
 
-> CHANGE  1 : 8  @  1 : 5
+> CHANGE  1 : 9  @  1 : 5
 
 ~ 			freeServerIcons();
 ~ 
@@ -68,6 +68,7 @@
 ~ 			for (DefaultServer srv : EagRuntime.getConfiguration().getDefaultServerList()) {
 ~ 				ServerData dat = new ServerData(srv.name, srv.addr, true);
 ~ 				dat.isDefault = true;
+~ 				dat.hideAddress = srv.hideAddress;
 ~ 				this.allServers.add(dat);
 
 > CHANGE  2 : 8  @  2 : 3
@@ -135,7 +136,7 @@
 ~ 			data.iconTextureObject = null;
 ~ 		}
 
-> INSERT  36 : 144  @  36
+> INSERT  36 : 145  @  36
 
 + 
 + 	public void freeServerIcons() {
@@ -170,7 +171,7 @@
 + 		for (int i = 0, l = this.servers.size(); i < l; ++i) {
 + 			ServerData dat = this.servers.get(i);
 + 			if (dat.pingSentTime <= 0l) {
-+ 				dat.pingSentTime = System.currentTimeMillis();
++ 				dat.pingSentTime = EagRuntime.steadyTimeMillis();
 + 				if (RateLimitTracker.isLockedOut(dat.serverIP)) {
 + 					logger.error(
 + 							"Server {} locked this client out on a previous connection, will not attempt to reconnect",
@@ -192,6 +193,7 @@
 + 					}
 + 				}
 + 			} else if (dat.currentQuery != null) {
++ 				dat.currentQuery.update();
 + 				if (!dat.hasPing) {
 + 					++total;
 + 					EnumServerRateLimit rateLimit = dat.currentQuery.getRateLimit();
@@ -228,7 +230,7 @@
 + 					dat.setIconPacket(r);
 + 				}
 + 				if (!dat.currentQuery.isOpen() && dat.pingSentTime > 0l
-+ 						&& (System.currentTimeMillis() - dat.pingSentTime) > 2000l && !dat.hasPing) {
++ 						&& (EagRuntime.steadyTimeMillis() - dat.pingSentTime) > 2000l && !dat.hasPing) {
 + 					if (RateLimitTracker.isProbablyLockedOut(dat.serverIP)) {
 + 						logger.error("Server {} ratelimited this client out on a previous connection, assuming lockout",
 + 								dat.serverIP);
diff --git a/patches/minecraft/net/minecraft/client/multiplayer/WorldClient.edit.java b/patches/minecraft/net/minecraft/client/multiplayer/WorldClient.edit.java
index 7bf823cc..927cc2f9 100644
--- a/patches/minecraft/net/minecraft/client/multiplayer/WorldClient.edit.java
+++ b/patches/minecraft/net/minecraft/client/multiplayer/WorldClient.edit.java
@@ -17,7 +17,29 @@
 
 > DELETE  5  @  5 : 6
 
-> CHANGE  211 : 212  @  211 : 212
+> DELETE  9  @  9 : 10
+
+> CHANGE  25 : 26  @  25 : 26
+
+~ 			EnumDifficulty parEnumDifficulty) {
+
+> CHANGE  1 : 2  @  1 : 2
+
+~ 				WorldProvider.getProviderForDimension(parInt1), true);
+
+> DELETE  17  @  17 : 19
+
+> DELETE  8  @  8 : 9
+
+> DELETE  1  @  1 : 2
+
+> DELETE  1  @  1 : 2
+
+> DELETE  24  @  24 : 25
+
+> DELETE  2  @  2 : 3
+
+> CHANGE  113 : 114  @  113 : 114
 
 ~ 		EaglercraftRandom random = new EaglercraftRandom();
 
diff --git a/patches/minecraft/net/minecraft/client/network/NetHandlerPlayClient.edit.java b/patches/minecraft/net/minecraft/client/network/NetHandlerPlayClient.edit.java
index 7e1f3bad..e4253bea 100644
--- a/patches/minecraft/net/minecraft/client/network/NetHandlerPlayClient.edit.java
+++ b/patches/minecraft/net/minecraft/client/network/NetHandlerPlayClient.edit.java
@@ -9,25 +9,27 @@
 
 > DELETE  4  @  4 : 6
 
-> INSERT  1 : 22  @  1
+> INSERT  1 : 24  @  1
 
 + 
-+ import net.lax1dude.eaglercraft.v1_8.EagRuntime;
++ import net.lax1dude.eaglercraft.v1_8.ClientUUIDLoadingCache;
 + import net.lax1dude.eaglercraft.v1_8.EaglercraftRandom;
 + import net.lax1dude.eaglercraft.v1_8.EaglercraftUUID;
 + 
 + import com.google.common.collect.Maps;
 + 
 + import net.lax1dude.eaglercraft.v1_8.netty.Unpooled;
-+ import net.lax1dude.eaglercraft.v1_8.profile.CapePackets;
++ import net.lax1dude.eaglercraft.v1_8.notifications.ServerNotificationManager;
 + import net.lax1dude.eaglercraft.v1_8.profile.ServerCapeCache;
 + import net.lax1dude.eaglercraft.v1_8.profile.ServerSkinCache;
-+ import net.lax1dude.eaglercraft.v1_8.profile.SkinPackets;
 + import net.lax1dude.eaglercraft.v1_8.socket.EaglercraftNetworkManager;
++ import net.lax1dude.eaglercraft.v1_8.socket.protocol.GamePluginMessageProtocol;
++ import net.lax1dude.eaglercraft.v1_8.socket.protocol.client.GameProtocolMessageController;
++ import net.lax1dude.eaglercraft.v1_8.socket.protocol.pkt.GameMessagePacket;
 + import net.lax1dude.eaglercraft.v1_8.sp.lan.LANClientNetworkManager;
 + import net.lax1dude.eaglercraft.v1_8.sp.socket.ClientIntegratedServerNetworkManager;
-+ import net.lax1dude.eaglercraft.v1_8.update.UpdateService;
 + import net.lax1dude.eaglercraft.v1_8.voice.VoiceClientController;
++ import net.lax1dude.eaglercraft.v1_8.webview.WebViewOverlayController;
 + import net.lax1dude.eaglercraft.v1_8.log4j.LogManager;
 + import net.lax1dude.eaglercraft.v1_8.log4j.Logger;
 + import net.lax1dude.eaglercraft.v1_8.minecraft.EaglerFolderResourcePack;
@@ -67,31 +69,38 @@
 
 ~ 	private final Map<EaglercraftUUID, NetworkPlayerInfo> playerInfoMap = Maps.newHashMap();
 
-> CHANGE  2 : 7  @  2 : 3
+> CHANGE  2 : 12  @  2 : 3
 
 ~ 	private boolean isIntegratedServer = false;
 ~ 	private final EaglercraftRandom avRandomizer = new EaglercraftRandom();
 ~ 	private final ServerSkinCache skinCache;
 ~ 	private final ServerCapeCache capeCache;
+~ 	private final ServerNotificationManager notifManager;
 ~ 	public boolean currentFNAWSkinAllowedState = true;
+~ 	public boolean currentFNAWSkinForcedState = true;
+~ 	private GameProtocolMessageController eaglerMessageController = null;
+~ 	public boolean hasRequestedServerInfo = false;
+~ 	public byte[] cachedServerInfoData = null;
 
 > CHANGE  1 : 2  @  1 : 2
 
 ~ 	public NetHandlerPlayClient(Minecraft mcIn, GuiScreen parGuiScreen, EaglercraftNetworkManager parNetworkManager,
 
-> INSERT  5 : 9  @  5
+> INSERT  5 : 10  @  5
 
-+ 		this.skinCache = new ServerSkinCache(parNetworkManager, mcIn.getTextureManager());
-+ 		this.capeCache = new ServerCapeCache(parNetworkManager, mcIn.getTextureManager());
++ 		this.skinCache = new ServerSkinCache(this, mcIn.getTextureManager());
++ 		this.capeCache = new ServerCapeCache(this, mcIn.getTextureManager());
++ 		this.notifManager = new ServerNotificationManager();
 + 		this.isIntegratedServer = (parNetworkManager instanceof ClientIntegratedServerNetworkManager)
 + 				|| (parNetworkManager instanceof LANClientNetworkManager);
 
-> INSERT  4 : 6  @  4
+> INSERT  4 : 7  @  4
 
 + 		this.skinCache.destroy();
 + 		this.capeCache.destroy();
++ 		this.notifManager.destroy();
 
-> INSERT  2 : 10  @  2
+> INSERT  2 : 51  @  2
 
 + 	public ServerSkinCache getSkinCache() {
 + 		return this.skinCache;
@@ -101,15 +110,61 @@
 + 		return this.capeCache;
 + 	}
 + 
++ 	public ServerNotificationManager getNotifManager() {
++ 		return this.notifManager;
++ 	}
++ 
++ 	public GameProtocolMessageController getEaglerMessageController() {
++ 		return eaglerMessageController;
++ 	}
++ 
++ 	public void setEaglerMessageController(GameProtocolMessageController eaglerMessageController) {
++ 		this.eaglerMessageController = eaglerMessageController;
++ 	}
++ 
++ 	public GamePluginMessageProtocol getEaglerMessageProtocol() {
++ 		return eaglerMessageController != null ? eaglerMessageController.protocol : null;
++ 	}
++ 
++ 	public void sendEaglerMessage(GameMessagePacket packet) {
++ 		try {
++ 			eaglerMessageController.sendPacket(packet);
++ 		} catch (IOException e) {
++ 			logger.error("Failed to send eaglercraft plugin message packet: " + packet);
++ 			logger.error(e);
++ 		}
++ 	}
++ 
++ 	public boolean webViewSendHandler(GameMessagePacket pkt) {
++ 		if (eaglerMessageController == null) {
++ 			return false;
++ 		}
++ 		if (this.gameController.thePlayer == null || this.gameController.thePlayer.sendQueue != this) {
++ 			logger.error("WebView sent message on a dead handler!");
++ 			return false;
++ 		}
++ 		if (eaglerMessageController.protocol.ver >= 4) {
++ 			sendEaglerMessage(pkt);
++ 			return true;
++ 		} else {
++ 			return false;
++ 		}
++ 	}
++ 
 
 > DELETE  1  @  1 : 2
 
-> INSERT  16 : 20  @  16
+> CHANGE  1 : 3  @  1 : 5
+
+~ 		this.clientWorldController = new WorldClient(this, new WorldSettings(0L, packetIn.getGameType(), false,
+~ 				packetIn.isHardcoreMode(), packetIn.getWorldType()), packetIn.getDimension(), packetIn.getDifficulty());
+
+> INSERT  11 : 15  @  11
 
 + 		if (VoiceClientController.isClientSupported()) {
-+ 			VoiceClientController.initializeVoiceClient((pkt) -> this.netManager
-+ 					.sendPacket(new C17PacketCustomPayload(VoiceClientController.SIGNAL_CHANNEL, pkt)));
++ 			VoiceClientController.initializeVoiceClient(this::sendEaglerMessage, eaglerMessageController.protocol.ver);
 + 		}
++ 		WebViewOverlayController.setPacketSendCallback(this::webViewSendHandler);
 
 > DELETE  3  @  3 : 4
 
@@ -191,7 +246,11 @@
 
 > DELETE  5  @  5 : 6
 
-> DELETE  17  @  17 : 18
+> CHANGE  5 : 6  @  5 : 6
+
+~ 					packetIn.getDimensionID(), packetIn.getDifficulty());
+
+> DELETE  11  @  11 : 12
 
 > DELETE  9  @  9 : 10
 
@@ -205,7 +264,11 @@
 
 > DELETE  11  @  11 : 12
 
-> DELETE  22  @  22 : 23
+> INSERT  8 : 9  @  8
+
++ 					tileentitysign.clearProfanityFilterCache();
+
+> DELETE  14  @  14 : 15
 
 > DELETE  16  @  16 : 17
 
@@ -262,12 +325,13 @@
 ~ 		for (int i = 0, l = lst.size(); i < l; ++i) {
 ~ 			S38PacketPlayerListItem.AddPlayerData s38packetplayerlistitem$addplayerdata = lst.get(i);
 
-> CHANGE  1 : 5  @  1 : 2
+> CHANGE  1 : 6  @  1 : 2
 
 ~ 				EaglercraftUUID uuid = s38packetplayerlistitem$addplayerdata.getProfile().getId();
 ~ 				this.playerInfoMap.remove(uuid);
 ~ 				this.skinCache.evictSkin(uuid);
 ~ 				this.capeCache.evictCape(uuid);
+~ 				ClientUUIDLoadingCache.evict(uuid);
 
 > DELETE  34  @  34 : 35
 
@@ -357,42 +421,16 @@
 
 > DELETE  11  @  11 : 13
 
-> INSERT  9 : 43  @  9
+> INSERT  9 : 17  @  9
 
-+ 		} else if ("EAG|Skins-1.8".equals(packetIn.getChannelName())) {
++ 		} else {
 + 			try {
-+ 				SkinPackets.readPluginMessage(packetIn.getBufferData(), skinCache);
++ 				eaglerMessageController.handlePacket(packetIn.getChannelName(), packetIn.getBufferData());
 + 			} catch (IOException e) {
-+ 				logger.error("Couldn't read EAG|Skins-1.8 packet!");
++ 				logger.error("Couldn't read \"{}\" packet as an eaglercraft plugin message!",
++ 						packetIn.getChannelName());
 + 				logger.error(e);
 + 			}
-+ 		} else if ("EAG|Capes-1.8".equals(packetIn.getChannelName())) {
-+ 			try {
-+ 				CapePackets.readPluginMessage(packetIn.getBufferData(), capeCache);
-+ 			} catch (IOException e) {
-+ 				logger.error("Couldn't read EAG|Capes-1.8 packet!");
-+ 				logger.error(e);
-+ 			}
-+ 		} else if ("EAG|UpdateCert-1.8".equals(packetIn.getChannelName())) {
-+ 			if (EagRuntime.getConfiguration().allowUpdateSvc()) {
-+ 				try {
-+ 					PacketBuffer pb = packetIn.getBufferData();
-+ 					byte[] c = new byte[pb.readableBytes()];
-+ 					pb.readBytes(c);
-+ 					UpdateService.addCertificateToSet(c);
-+ 				} catch (Throwable e) {
-+ 					logger.error("Couldn't process EAG|UpdateCert-1.8 packet!");
-+ 					logger.error(e);
-+ 				}
-+ 			}
-+ 		} else if (VoiceClientController.SIGNAL_CHANNEL.equals(packetIn.getChannelName())) {
-+ 			if (VoiceClientController.isClientSupported()) {
-+ 				VoiceClientController.handleVoiceSignalPacket(packetIn.getBufferData());
-+ 			}
-+ 		} else if ("EAG|FNAWSEn-1.8".equals(packetIn.getChannelName())) {
-+ 			this.currentFNAWSkinAllowedState = packetIn.getBufferData().readBoolean();
-+ 			Minecraft.getMinecraft().getRenderManager().setEnableFNAWSkins(
-+ 					this.currentFNAWSkinAllowedState && Minecraft.getMinecraft().gameSettings.enableFNAWSkins);
 
 > DELETE  1  @  1 : 2
 
diff --git a/patches/minecraft/net/minecraft/client/network/NetworkPlayerInfo.edit.java b/patches/minecraft/net/minecraft/client/network/NetworkPlayerInfo.edit.java
index 41f67141..0d3b9611 100644
--- a/patches/minecraft/net/minecraft/client/network/NetworkPlayerInfo.edit.java
+++ b/patches/minecraft/net/minecraft/client/network/NetworkPlayerInfo.edit.java
@@ -5,16 +5,29 @@
 # Version: 1.0
 # Author: lax1dude
 
-> CHANGE  2 : 4  @  2 : 6
+> CHANGE  2 : 5  @  2 : 6
 
 ~ import net.lax1dude.eaglercraft.v1_8.mojang.authlib.GameProfile;
+~ import net.lax1dude.eaglercraft.v1_8.profanity_filter.ProfanityFilter;
 ~ import net.lax1dude.eaglercraft.v1_8.profile.SkinModel;
 
 > DELETE  1  @  1 : 3
 
-> DELETE  10  @  10 : 13
+> INSERT  8 : 9  @  8
 
-> CHANGE  40 : 41  @  40 : 41
++ 	private String gameProfileProfanityFilter;
+
+> DELETE  2  @  2 : 5
+
+> INSERT  2 : 3  @  2
+
++ 	private IChatComponent displayNameProfanityFilter;
+
+> INSERT  15 : 16  @  15
+
++ 		this.displayNameProfanityFilter = null;
+
+> CHANGE  23 : 24  @  23 : 24
 
 ~ 		return true;
 
@@ -41,4 +54,39 @@
 
 > DELETE  6  @  6 : 33
 
+> INSERT  2 : 3  @  2
+
++ 		this.displayNameProfanityFilter = null;
+
+> INSERT  6 : 34  @  6
+
++ 	public IChatComponent getDisplayNameProfanityFilter() {
++ 		if (Minecraft.getMinecraft().isEnableProfanityFilter()) {
++ 			if (this.displayName != null) {
++ 				if (this.displayNameProfanityFilter == null) {
++ 					this.displayNameProfanityFilter = ProfanityFilter.getInstance()
++ 							.profanityFilterChatComponent(this.displayName);
++ 				}
++ 				return this.displayNameProfanityFilter;
++ 			} else {
++ 				return null;
++ 			}
++ 		} else {
++ 			return this.displayName;
++ 		}
++ 	}
++ 
++ 	public String getGameProfileNameProfanityFilter() {
++ 		if (Minecraft.getMinecraft().isEnableProfanityFilter()) {
++ 			if (this.gameProfileProfanityFilter == null) {
++ 				this.gameProfileProfanityFilter = ProfanityFilter.getInstance()
++ 						.profanityFilterString(this.gameProfile.getName());
++ 			}
++ 			return this.gameProfileProfanityFilter;
++ 		} else {
++ 			return this.gameProfile.getName();
++ 		}
++ 	}
++ 
+
 > EOF
diff --git a/patches/minecraft/net/minecraft/client/particle/EffectRenderer.edit.java b/patches/minecraft/net/minecraft/client/particle/EffectRenderer.edit.java
index c81df64b..606886fc 100644
--- a/patches/minecraft/net/minecraft/client/particle/EffectRenderer.edit.java
+++ b/patches/minecraft/net/minecraft/client/particle/EffectRenderer.edit.java
@@ -14,12 +14,13 @@
 ~ import net.lax1dude.eaglercraft.v1_8.minecraft.IAcceleratedParticleEngine;
 ~ 
 
-> INSERT  1 : 9  @  1
+> INSERT  1 : 10  @  1
 
 + 
 + import com.google.common.collect.Lists;
 + import com.google.common.collect.Maps;
 + 
++ import net.lax1dude.eaglercraft.v1_8.opengl.EaglercraftGPU;
 + import net.lax1dude.eaglercraft.v1_8.opengl.GlStateManager;
 + import net.lax1dude.eaglercraft.v1_8.opengl.WorldRenderer;
 + import net.lax1dude.eaglercraft.v1_8.opengl.ext.deferred.DeferredStateManager;
@@ -43,10 +44,15 @@
 > INSERT  2 : 5  @  2
 
 + 	public static final AcceleratedEffectRenderer vanillaAcceleratedParticleRenderer = new AcceleratedEffectRenderer();
-+ 	public IAcceleratedParticleEngine acceleratedParticleRenderer = vanillaAcceleratedParticleRenderer;
++ 	public IAcceleratedParticleEngine acceleratedParticleRenderer = null;
 + 
 
-> CHANGE  104 : 106  @  104 : 105
+> INSERT  13 : 15  @  13
+
++ 		this.acceleratedParticleRenderer = EaglercraftGPU.checkInstancingCapable() ? vanillaAcceleratedParticleRenderer
++ 				: null;
+
+> CHANGE  91 : 93  @  91 : 92
 
 ~ 		for (int i = 0, l = this.particleEmitters.size(); i < l; ++i) {
 ~ 			EntityParticleEmitter entityparticleemitter = this.particleEmitters.get(i);
@@ -117,17 +123,20 @@
 + 						texCoordWidth = 1.0f / blockMap.getWidth();
 + 						texCoordHeight = 1.0f / blockMap.getHeight();
 
-> INSERT  7 : 11  @  7
+> INSERT  7 : 13  @  7
 
 + 					boolean legacyRenderingHasOccured = false;
 + 
-+ 					acceleratedParticleRenderer.begin(partialTicks);
++ 					if (acceleratedParticleRenderer != null) {
++ 						acceleratedParticleRenderer.begin(partialTicks);
++ 					}
 + 
 
-> CHANGE  4 : 9  @  4 : 5
+> CHANGE  4 : 10  @  4 : 5
 
-~ 							if (!entityfx.renderAccelerated(acceleratedParticleRenderer, entityIn, partialTicks, f, f4,
-~ 									f1, f2, f3)) {
+~ 							if (acceleratedParticleRenderer == null
+~ 									|| !entityfx.renderAccelerated(acceleratedParticleRenderer, entityIn, partialTicks,
+~ 											f, f4, f1, f2, f3)) {
 ~ 								entityfx.renderParticle(worldrenderer, entityIn, partialTicks, f, f4, f1, f2, f3);
 ~ 								legacyRenderingHasOccured = true;
 ~ 							}
@@ -142,7 +151,7 @@
 ~ 											: (l == 1 ? "TERRAIN_TEXTURE"
 ~ 													: (l == 3 ? "ENTITY_PARTICLE_TEXTURE" : "Unknown - " + l));
 
-> CHANGE  6 : 13  @  6 : 7
+> CHANGE  6 : 15  @  6 : 7
 
 ~ 					if (legacyRenderingHasOccured) {
 ~ 						tessellator.draw();
@@ -150,6 +159,8 @@
 ~ 						worldrenderer.finishDrawing();
 ~ 					}
 ~ 
-~ 					acceleratedParticleRenderer.draw(texCoordWidth, texCoordHeight);
+~ 					if (acceleratedParticleRenderer != null) {
+~ 						acceleratedParticleRenderer.draw(texCoordWidth, texCoordHeight);
+~ 					}
 
 > EOF
diff --git a/patches/minecraft/net/minecraft/client/renderer/EntityRenderer.edit.java b/patches/minecraft/net/minecraft/client/renderer/EntityRenderer.edit.java
index 309af9a3..c1c54ac6 100644
--- a/patches/minecraft/net/minecraft/client/renderer/EntityRenderer.edit.java
+++ b/patches/minecraft/net/minecraft/client/renderer/EntityRenderer.edit.java
@@ -11,10 +11,12 @@
 ~ 
 ~ import java.util.Arrays;
 
-> CHANGE  1 : 3  @  1 : 2
+> CHANGE  1 : 5  @  1 : 2
 
 ~ import net.lax1dude.eaglercraft.v1_8.EaglercraftRandom;
 ~ import net.lax1dude.eaglercraft.v1_8.HString;
+~ import net.lax1dude.eaglercraft.v1_8.PointerInputAbstraction;
+~ 
 
 > INSERT  1 : 29  @  1
 
@@ -23,7 +25,7 @@
 + import com.google.common.base.Predicates;
 + 
 + import net.lax1dude.eaglercraft.v1_8.Display;
-+ import net.lax1dude.eaglercraft.v1_8.Mouse;
++ import net.lax1dude.eaglercraft.v1_8.EagRuntime;
 + import net.lax1dude.eaglercraft.v1_8.log4j.LogManager;
 + import net.lax1dude.eaglercraft.v1_8.log4j.Logger;
 + import net.lax1dude.eaglercraft.v1_8.opengl.EaglercraftGPU;
@@ -47,7 +49,11 @@
 + import net.lax1dude.eaglercraft.v1_8.voice.VoiceTagRenderer;
 + import net.lax1dude.eaglercraft.v1_8.vector.Matrix4f;
 
-> CHANGE  10 : 13  @  10 : 20
+> INSERT  6 : 7  @  6
+
++ import net.minecraft.client.gui.GuiScreen;
+
+> CHANGE  4 : 7  @  4 : 14
 
 ~ import net.minecraft.client.particle.EntityFX;
 ~ import net.minecraft.client.renderer.RenderGlobal.ChunkCullAdapter;
@@ -137,7 +143,11 @@
 
 > DELETE  1  @  1 : 8
 
-> CHANGE  111 : 112  @  111 : 112
+> DELETE  6  @  6 : 7
+
+> DELETE  79  @  79 : 81
+
+> CHANGE  23 : 24  @  23 : 24
 
 ~ 	public float getFOVModifier(float partialTicks, boolean parFlag) {
 
@@ -179,7 +189,9 @@
 + 	}
 + 
 
-> CHANGE  117 : 118  @  117 : 118
+> DELETE  10  @  10 : 11
+
+> CHANGE  106 : 107  @  106 : 107
 
 ~ 					this.lightmapColors[i] = short1 << 24 | j | k << 8 | l << 16;
 
@@ -201,17 +213,45 @@
 + 				GlStateManager.setActiveTexture(OpenGlHelper.defaultTexUnit);
 + 
 
-> DELETE  23  @  23 : 28
+> DELETE  1  @  1 : 2
 
-> INSERT  4 : 7  @  4
+> CHANGE  10 : 11  @  10 : 11
+
+~ 		boolean flag = Display.isActive() || mc.gameSettings.touchscreen;
+
+> CHANGE  1 : 2  @  1 : 2
+
+~ 				&& (!this.mc.gameSettings.touchscreen || !PointerInputAbstraction.getVCursorButtonDown(1))) {
+
+> DELETE  7  @  7 : 14
+
+> INSERT  3 : 6  @  3
 
 + 			if (this.mc.gameSettings.keyBindZoomCamera.isKeyDown()) {
 + 				f *= 0.7f;
 + 			}
 
-> DELETE  39  @  39 : 52
+> DELETE  23  @  23 : 24
 
-> CHANGE  4 : 45  @  4 : 5
+> CHANGE  2 : 3  @  2 : 3
+
+~ 			final ScaledResolution scaledresolution = mc.scaledResolution;
+
+> CHANGE  2 : 4  @  2 : 4
+
+~ 			final int j1 = PointerInputAbstraction.getVCursorX() * l / this.mc.displayWidth;
+~ 			final int k1 = i1 - PointerInputAbstraction.getVCursorY() * i1 / this.mc.displayHeight - 1;
+
+> DELETE  2  @  2 : 3
+
+> DELETE  5  @  5 : 18
+
+> CHANGE  1 : 3  @  1 : 3
+
+~ 				final boolean b = !this.mc.gameSettings.hideGUI || this.mc.currentScreen != null;
+~ 				if (b) {
+
+> CHANGE  1 : 14  @  1 : 2
 
 ~ 					long framebufferAge = this.overlayFramebuffer.getAge();
 ~ 					if (framebufferAge == -1l || framebufferAge > (Minecraft.getDebugFPS() < 25 ? 125l : 75l)) {
@@ -220,10 +260,16 @@
 ~ 						GlStateManager.clearColor(0.0f, 0.0f, 0.0f, 0.0f);
 ~ 						GlStateManager.clear(16640);
 ~ 						GlStateManager.enableOverlayFramebufferBlending();
-~ 						this.mc.ingameGUI.renderGameOverlay(parFloat1);
+~ 						if (b) {
+~ 							this.mc.ingameGUI.renderGameOverlay(parFloat1);
+~ 						}
 ~ 						GlStateManager.disableOverlayFramebufferBlending();
 ~ 						this.overlayFramebuffer.endRender();
 ~ 					}
+
+> CHANGE  1 : 32  @  1 : 3
+
+~ 				if (b) {
 ~ 					this.setupOverlayRendering();
 ~ 					GlStateManager.disableLighting();
 ~ 					GlStateManager.enableBlend();
@@ -235,7 +281,7 @@
 ~ 					GlStateManager.color(1.0f, 1.0f, 1.0f, 1.0f);
 ~ 					GlStateManager.enableBlend();
 ~ 					GlStateManager.blendFunc(1, 771);
-~ 					GlStateManager.disableAlpha();
+~ 					GlStateManager.enableAlpha();
 ~ 					GlStateManager.disableDepth();
 ~ 					GlStateManager.depthMask(false);
 ~ 					Tessellator tessellator = Tessellator.getInstance();
@@ -248,14 +294,45 @@
 ~ 					tessellator.draw();
 ~ 					GlStateManager.depthMask(true);
 ~ 					GlStateManager.enableDepth();
-~ 					GlStateManager.enableAlpha();
 ~ 					GlStateManager.disableBlend();
 ~ 					if (this.mc.gameSettings.hudPlayer) { // give the player model HUD good fps
 ~ 						this.mc.ingameGUI.drawEaglerPlayerOverlay(l - 3,
 ~ 								3 + this.mc.ingameGUI.overlayDebug.playerOffset, parFloat1);
 ~ 					}
+~ 				}
 
-> CHANGE  23 : 24  @  23 : 24
+> INSERT  10 : 12  @  10
+
++ 			this.mc.notifRenderer.renderOverlay(j1, k1);
++ 
+
+> INSERT  2 : 4  @  2
+
++ 				float f = 1.0f;
++ 				final float[] ff = new float[] { 1.0f };
+
+> CHANGE  2 : 20  @  2 : 3
+
+~ 					f = mc.currentScreen.getEaglerScale();
+~ 					int mx, my;
+~ 					if (f == 1.0f) {
+~ 						mx = j1;
+~ 						my = k1;
+~ 					} else {
+~ 						mx = GuiScreen.applyEaglerScale(f, j1, l);
+~ 						my = GuiScreen.applyEaglerScale(f, k1, i1);
+~ 						GlStateManager.pushMatrix();
+~ 						float fff = (1.0f - f) * 0.5f;
+~ 						GlStateManager.translate(fff * l, fff * i1, 0.0f);
+~ 						GlStateManager.scale(f, f, f);
+~ 					}
+~ 					ff[0] = f;
+~ 					this.mc.currentScreen.drawScreen(mx, my, parFloat1);
+~ 					if (f != 1.0f) {
+~ 						GlStateManager.popMatrix();
+~ 					}
+
+> CHANGE  5 : 6  @  5 : 6
 
 ~ 							return EntityRenderer.this.mc.currentScreen.getClass().getName();
 
@@ -263,16 +340,31 @@
 
 ~ 							return HString.format("Scaled: (%d, %d). Absolute: (%d, %d)",
 
-> CHANGE  6 : 7  @  6 : 7
+> CHANGE  1 : 3  @  1 : 2
+
+~ 											Integer.valueOf(PointerInputAbstraction.getVCursorX()),
+~ 											Integer.valueOf(PointerInputAbstraction.getVCursorY()) });
+
+> CHANGE  4 : 5  @  4 : 5
 
 ~ 							return HString.format("Scaled: (%d, %d). Absolute: (%d, %d). Scale factor of %d",
 
-> INSERT  9 : 11  @  9
+> INSERT  7 : 12  @  7
+
++ 					crashreportcategory.addCrashSectionCallable("Eagler Scale", new Callable<String>() {
++ 						public String call() throws Exception {
++ 							return "" + ff[0];
++ 						}
++ 					});
+
+> DELETE  2  @  2 : 3
+
+> INSERT  1 : 3  @  1
 
-+ 
 + 				this.mc.voiceOverlay.drawOverlay();
++ 			}
 
-> DELETE  6  @  6 : 8
+> DELETE  4  @  4 : 6
 
 > CHANGE  32 : 33  @  32 : 33
 
@@ -291,7 +383,7 @@
 + 		VoiceTagRenderer.clearTagsDrawnSet();
 + 
 
-> CHANGE  4 : 25  @  4 : 12
+> CHANGE  3 : 24  @  3 : 12
 
 ~ 		boolean dlights = DynamicLightsStateManager.isDynamicLightsRender();
 ~ 		if (dlights) {
@@ -315,7 +407,7 @@
 ~ 				}
 ~ 			}
 
-> CHANGE  1 : 26  @  1 : 2
+> CHANGE  1 : 28  @  1 : 2
 
 ~ 			if (this.mc.gameSettings.shaders) {
 ~ 				try {
@@ -330,7 +422,9 @@
 ~ 				}
 ~ 				mc.effectRenderer.acceleratedParticleRenderer = EffectRenderer.vanillaAcceleratedParticleRenderer;
 ~ 			} else {
-~ 				mc.effectRenderer.acceleratedParticleRenderer = EffectRenderer.vanillaAcceleratedParticleRenderer;
+~ 				mc.effectRenderer.acceleratedParticleRenderer = EaglercraftGPU.checkInstancingCapable()
+~ 						? EffectRenderer.vanillaAcceleratedParticleRenderer
+~ 						: null;
 ~ 				if (dlights) {
 ~ 					GlStateManager.enableExtensionPipeline();
 ~ 				}
@@ -343,29 +437,34 @@
 ~ 				}
 ~ 			}
 
-> INSERT  2 : 6  @  2
+> CHANGE  2 : 5  @  2 : 3
 
-+ 		if (fxaa) {
-+ 			EffectPipelineFXAA.end();
-+ 		}
-+ 
+~ 		if (fxaa) {
+~ 			EffectPipelineFXAA.end();
+~ 		}
 
-> INSERT  14 : 18  @  14
+> DELETE  7  @  7 : 8
+
+> DELETE  3  @  3 : 4
+
+> INSERT  1 : 5  @  1
 
 + 		boolean isDynamicLights = DynamicLightsStateManager.isDynamicLightsRender();
 + 		if (isDynamicLights) {
 + 			DynamicLightsStateManager.setupInverseViewMatrix();
 + 		}
 
-> DELETE  1  @  1 : 3
+> DELETE  1  @  1 : 4
 
-> INSERT  6 : 9  @  6
+> INSERT  5 : 8  @  5
 
 + 		TileEntityRendererDispatcher.staticPlayerX = d0; // hack, needed for some eagler stuff
 + 		TileEntityRendererDispatcher.staticPlayerY = d1;
 + 		TileEntityRendererDispatcher.staticPlayerZ = d2;
 
-> CHANGE  6 : 9  @  6 : 8
+> DELETE  3  @  3 : 4
+
+> CHANGE  2 : 5  @  2 : 4
 
 ~ 			float vigg = this.getFOVModifier(partialTicks, true);
 ~ 			GlStateManager.gluPerspective(vigg, (float) this.mc.displayWidth / (float) this.mc.displayHeight, 0.05F,
@@ -375,7 +474,15 @@
 
 ~ 			GlStateManager.gluPerspective(vigg, (float) this.mc.displayWidth / (float) this.mc.displayHeight, 0.05F,
 
-> INSERT  26 : 27  @  26
+> DELETE  10  @  10 : 11
+
+> DELETE  3  @  3 : 4
+
+> DELETE  3  @  3 : 4
+
+> DELETE  3  @  3 : 4
+
+> INSERT  3 : 4  @  3
 
 + 		GlStateManager.disableBlend();
 
@@ -385,11 +492,13 @@
 
 + 		GlStateManager.shadeModel(7424);
 
-> INSERT  16 : 19  @  16
+> DELETE  5  @  5 : 6
 
-+ 				if (isDynamicLights) {
-+ 					GlStateManager.disableExtensionPipeline();
-+ 				}
+> CHANGE  9 : 12  @  9 : 10
+
+~ 				if (isDynamicLights) {
+~ 					GlStateManager.disableExtensionPipeline();
+~ 				}
 
 > INSERT  2 : 5  @  2
 
@@ -397,19 +506,23 @@
 + 					GlStateManager.enableExtensionPipeline();
 + 				}
 
-> INSERT  8 : 11  @  8
+> CHANGE  8 : 11  @  8 : 9
 
-+ 			if (isDynamicLights) {
-+ 				GlStateManager.disableExtensionPipeline();
-+ 			}
+~ 			if (isDynamicLights) {
+~ 				GlStateManager.disableExtensionPipeline();
+~ 			}
 
-> INSERT  3 : 6  @  3
+> INSERT  2 : 5  @  2
 
 + 			if (isDynamicLights) {
 + 				GlStateManager.enableExtensionPipeline();
 + 			}
 
-> CHANGE  17 : 25  @  17 : 18
+> DELETE  2  @  2 : 3
+
+> DELETE  9  @  9 : 10
+
+> CHANGE  3 : 11  @  3 : 5
 
 ~ 			if (isDynamicLights) {
 ~ 				DynamicLightsStateManager.bindAcceleratedEffectRenderer(effectrenderer);
@@ -420,7 +533,15 @@
 ~ 				effectrenderer.acceleratedParticleRenderer = null;
 ~ 			}
 
-> INSERT  39 : 53  @  39
+> DELETE  5  @  5 : 6
+
+> DELETE  12  @  12 : 13
+
+> DELETE  7  @  7 : 8
+
+> DELETE  3  @  3 : 4
+
+> INSERT  8 : 22  @  8
 
 + 	private void updateDynamicLightListEagler(float partialTicks) {
 + 		DynamicLightsStateManager.clearRenderList();
@@ -437,7 +558,9 @@
 + 	}
 + 
 
-> CHANGE  5 : 6  @  5 : 6
+> DELETE  2  @  2 : 3
+
+> CHANGE  2 : 3  @  2 : 3
 
 ~ 			GlStateManager.gluPerspective(this.getFOVModifier(partialTicks, true),
 
@@ -523,7 +646,11 @@
 ~ 				EaglerDeferredPipeline.instance.setForwardRenderLightFactors(1.0f, 1.0f, 1.0f, 1.0f);
 ~ 			}
 
-> CHANGE  153 : 154  @  153 : 154
+> CHANGE  6 : 7  @  6 : 7
+
+~ 		ScaledResolution scaledresolution = mc.scaledResolution;
+
+> CHANGE  146 : 147  @  146 : 147
 
 ~ 		GlStateManager.clearColor(this.fogColorRed, this.fogColorGreen, this.fogColorBlue, 1.0F);
 
@@ -539,7 +666,7 @@
 
 > INSERT  14 : 17  @  14
 
-+ 		} else if (!this.mc.gameSettings.fog) {
++ 		} else if (partialTicks != -1 && !this.mc.gameSettings.fog) {
 + 			GlStateManager.setFog(2048);
 + 			GlStateManager.setFogDensity(0.0F);
 
@@ -553,7 +680,7 @@
 
 > DELETE  9  @  9 : 10
 
-> INSERT  12 : 988  @  12
+> INSERT  12 : 952  @  12
 
 + 
 + 	private static final Vector4f tmpVec4f_1 = new Vector4f();
@@ -570,28 +697,23 @@
 + 			EaglerDeferredPipeline.renderSuspended();
 + 			return;
 + 		}
-+ 		mc.mcProfiler.endStartSection("eaglercraftShaders");
 + 		EaglerDeferredPipeline.instance.setPartialTicks(partialTicks);
 + 		eagPartialTicks = partialTicks;
 + 		EaglerDeferredConfig conf = mc.gameSettings.deferredShaderConf;
 + 		boolean flag = isDrawBlockOutline();
 + 		GlStateManager.viewport(0, 0, mc.displayWidth, mc.displayHeight);
-+ 		mc.mcProfiler.startSection("camera");
 + 		setupCameraTransform(partialTicks, 2);
 + 		EaglerDeferredPipeline.instance.loadViewMatrix();
 + 		ActiveRenderInfo.updateRenderInfo(mc.thePlayer, mc.gameSettings.thirdPersonView == 2);
-+ 		mc.mcProfiler.endStartSection("culling");
 + 		Frustum frustum = new Frustum();
 + 		Entity entity = mc.getRenderViewEntity();
 + 		if (entity == null) {
 + 			entity = mc.thePlayer;
 + 		}
-+ 		double d0 = EaglerDeferredPipeline.instance.currentRenderX = entity.lastTickPosX
-+ 				+ (entity.posX - entity.lastTickPosX) * (double) partialTicks;
-+ 		double d1 = EaglerDeferredPipeline.instance.currentRenderY = entity.lastTickPosY
-+ 				+ (entity.posY - entity.lastTickPosY) * (double) partialTicks;
-+ 		double d2 = EaglerDeferredPipeline.instance.currentRenderZ = entity.lastTickPosZ
-+ 				+ (entity.posZ - entity.lastTickPosZ) * (double) partialTicks;
++ 		double d0 = entity.lastTickPosX + (entity.posX - entity.lastTickPosX) * (double) partialTicks;
++ 		double d1 = entity.lastTickPosY + (entity.posY - entity.lastTickPosY) * (double) partialTicks;
++ 		double d2 = entity.lastTickPosZ + (entity.posZ - entity.lastTickPosZ) * (double) partialTicks;
++ 		EaglerDeferredPipeline.instance.setRenderPosGlobal(d0, d1, d2);
 + 		EaglerDeferredPipeline.instance.updateReprojectionCoordinates(d0, d1, d2);
 + 		float eyeHeight = entity.getEyeHeight();
 + 		frustum.setPosition(d0, d1, d2);
@@ -603,7 +725,7 @@
 + //		}
 + //		System.out.println(builder.toString());
 + 
-+ 		float waveTimer = (float) ((System.currentTimeMillis() % 600000l) * 0.001);
++ 		float waveTimer = (float) ((EagRuntime.steadyTimeMillis() % 600000l) * 0.001);
 + 		DeferredStateManager.setWaterWindOffset(0.0f, 0.0f, waveTimer, waveTimer);
 + 
 + 		float blockWaveDistX = (float) (d0 - blockWaveOffsetX);
@@ -628,7 +750,6 @@
 + 
 + 		// if (mc.gameSettings.renderDistanceChunks >= 4) vanilla shows sky not fog
 + 
-+ 		mc.mcProfiler.endStartSection("terrain_setup");
 + 		mc.renderGlobal.setupTerrain(entity, (double) partialTicks, frustum, frameCount++, mc.thePlayer.isSpectator());
 + 
 + 		// clear some state:
@@ -646,11 +767,8 @@
 + 
 + 		EaglerDeferredPipeline.instance.beginDrawMainGBufferTerrain();
 + 
-+ 		mc.mcProfiler.endStartSection("updatechunks");
 + 		mc.renderGlobal.updateChunks(finishTimeNano);
 + 
-+ 		mc.mcProfiler.endStartSection("terrain");
-+ 
 + 		mc.renderGlobal.renderBlockLayer(EnumWorldBlockLayer.SOLID, (double) partialTicks, 2, entity);
 + 		GlStateManager.enableAlpha();
 + 		GlStateManager.alphaFunc(516, 0.5F);
@@ -679,20 +797,17 @@
 + 		NameTagRenderer.doRenderNameTags = true;
 + 		NameTagRenderer.nameTagsCount = 0;
 + 		GlStateManager.pushMatrix();
-+ 		mc.mcProfiler.endStartSection("entities");
 + 		DeferredStateManager.setDefaultMaterialConstants();
 + 		DeferredStateManager.startUsingEnvMap();
 + 		mc.renderGlobal.renderEntities(entity, frustum, partialTicks);
 + 		GlStateManager.matrixMode(5888);
 + 		GlStateManager.popMatrix();
-+ 		mc.mcProfiler.endStartSection("litParticles");
 + 		EntityFX.interpPosX = d0;
 + 		EntityFX.interpPosY = d1;
 + 		EntityFX.interpPosZ = d2;
 + 		enableLightmap();
 + 		GlStateManager.pushMatrix();
 + 		mc.effectRenderer.renderLitParticles(entity, partialTicks);
-+ 		mc.mcProfiler.endStartSection("gbufferParticles");
 + 		GlStateManager.matrixMode(5888);
 + 		GlStateManager.popMatrix();
 + 		GlStateManager.pushMatrix();
@@ -706,9 +821,7 @@
 + 		DynamicLightManager.setIsRenderingLights(false);
 + 		NameTagRenderer.doRenderNameTags = false;
 + 
-+ 		mc.mcProfiler.endStartSection("endDrawMainGBuffer");
 + 		EaglerDeferredPipeline.instance.endDrawMainGBuffer();
-+ 		mc.mcProfiler.endStartSection("shadowSetup");
 + 
 + 		// calculate sun matrix and angle:
 + 
@@ -1113,11 +1226,9 @@
 + 			}
 + 		}
 + 
-+ 		mc.mcProfiler.endStartSection("combineGBuffersAndIlluminate");
 + 		EaglerDeferredPipeline.instance.combineGBuffersAndIlluminate();
 + 
 + 		if (conf.is_rendering_useEnvMap) {
-+ 			mc.mcProfiler.endStartSection("envMap");
 + 			DeferredStateManager.forwardCallbackHandler = null;
 + 			EaglerDeferredPipeline.instance.beginDrawEnvMap();
 + 			GlStateManager.enableCull();
@@ -1188,7 +1299,6 @@
 + 		}
 + 
 + 		if (conf.is_rendering_realisticWater) {
-+ 			mc.mcProfiler.endStartSection("realisticWaterMask");
 + 			EaglerDeferredPipeline.instance.beginDrawRealisticWaterMask();
 + 			enableLightmap();
 + 			mc.renderGlobal.renderBlockLayer(EnumWorldBlockLayer.REALISTIC_WATER, (double) partialTicks, 2, entity);
@@ -1196,8 +1306,6 @@
 + 			EaglerDeferredPipeline.instance.endDrawRealisticWaterMask();
 + 		}
 + 
-+ 		mc.mcProfiler.endStartSection("setupShaderFog");
-+ 
 + 		int dim = mc.theWorld.provider.getDimensionId();
 + 		float ff;
 + 		if (dim == 0) {
@@ -1262,16 +1370,13 @@
 + 		DeferredStateManager.setDefaultMaterialConstants();
 + 
 + 		if (conf.is_rendering_realisticWater) {
-+ 			mc.mcProfiler.endStartSection("realisticWaterSurface");
 + 			EaglerDeferredPipeline.instance.beginDrawRealisticWaterSurface();
 + 			mc.renderGlobal.renderBlockLayer(EnumWorldBlockLayer.REALISTIC_WATER, (double) partialTicks, 2, entity);
 + 			EaglerDeferredPipeline.instance.endDrawRealisticWaterSurface();
 + 		}
 + 
-+ 		mc.mcProfiler.endStartSection("gbufferFog");
 + 		EaglerDeferredPipeline.instance.applyGBufferFog();
 + 
-+ 		mc.mcProfiler.endStartSection("translucentEntities");
 + 		EaglerDeferredPipeline.instance.beginDrawTranslucentEntities();
 + 
 + 		TileEntityRendererDispatcher.staticPlayerX = d0;
@@ -1295,14 +1400,11 @@
 + 		DeferredStateManager.forwardCallbackGBuffer.reset();
 + 
 + 		EaglerDeferredPipeline.instance.beginDrawTranslucentBlocks();
-+ 		mc.mcProfiler.endStartSection("translucentBlocks");
 + 		mc.getTextureManager().bindTexture(TextureMap.locationBlocksTexture);
 + 		mc.renderGlobal.renderBlockLayer(EnumWorldBlockLayer.TRANSLUCENT, (double) partialTicks, 2, entity);
 + 
 + 		EaglerDeferredPipeline.instance.beginDrawMainGBufferDestroyProgress();
 + 
-+ 		mc.mcProfiler.endStartSection("destroyProgress");
-+ 
 + 		GlStateManager.enableBlend();
 + 		GlStateManager.tryBlendFuncSeparate(0, 770, 0, 0);
 + 		GlStateManager.color(1.0f, 1.0f, 1.0f, 0.5f);
@@ -1314,7 +1416,6 @@
 + 		EaglerDeferredPipeline.instance.endDrawMainGBufferDestroyProgress();
 + 
 + 		if (mc.effectRenderer.hasParticlesInAlphaLayer()) {
-+ 			mc.mcProfiler.endStartSection("transparentParticles");
 + 			GlStateManager.pushMatrix();
 + 			mc.effectRenderer.acceleratedParticleRenderer = EaglerDeferredPipeline.instance.forwardEffectRenderer;
 + 			DeferredStateManager.setHDRTranslucentPassBlendFunc();
@@ -1330,22 +1431,18 @@
 + 		}
 + 
 + 		if (conf.is_rendering_useEnvMap) {
-+ 			mc.mcProfiler.endStartSection("glassHighlights");
 + 			EaglerDeferredPipeline.instance.beginDrawGlassHighlights();
 + 			mc.renderGlobal.renderBlockLayer(EnumWorldBlockLayer.GLASS_HIGHLIGHTS, (double) partialTicks, 2, entity);
 + 			EaglerDeferredPipeline.instance.endDrawGlassHighlights();
 + 		}
 + 
-+ 		mc.mcProfiler.endStartSection("saveReprojData");
 + 		EaglerDeferredPipeline.instance.saveReprojData();
 + 
-+ 		mc.mcProfiler.endStartSection("rainSnow");
 + 		renderRainSnow(partialTicks);
 + 
 + 		GlStateManager.disableBlend();
 + 
 + 		if (renderHand) {
-+ 			mc.mcProfiler.endStartSection("renderHandOverlay");
 + 			EaglerDeferredPipeline.instance.beginDrawHandOverlay();
 + 			DeferredStateManager.reportForwardRenderObjectPosition2(0.0f, 0.0f, 0.0f);
 + 			DeferredStateManager.forwardCallbackHandler = DeferredStateManager.forwardCallbackGBuffer;
@@ -1371,7 +1468,6 @@
 + 			GlStateManager.disableAlpha();
 + 		}
 + 
-+ 		mc.mcProfiler.endStartSection("endDrawDeferred");
 + 		EaglerDeferredPipeline.instance.endDrawHDRTranslucent();
 + 
 + 		EaglerDeferredPipeline.instance.endDrawDeferred();
@@ -1391,11 +1487,9 @@
 + 		if (!DebugFramebufferView.debugViewShown) {
 + 			GlStateManager.disableAlpha();
 + 			if (isDrawBlockOutline()) {
-+ 				this.mc.mcProfiler.endStartSection("outline");
 + 				mc.renderGlobal.drawSelectionBox(mc.thePlayer, this.mc.objectMouseOver, 0, partialTicks);
 + 			}
 + 			GlStateManager.enableAlpha();
-+ 			this.mc.mcProfiler.endStartSection("nameTags");
 + 			if (NameTagRenderer.nameTagsCount > 0) {
 + 				enableLightmap();
 + 				Arrays.sort(NameTagRenderer.nameTagsThisFrame, 0, NameTagRenderer.nameTagsCount, (n1, n2) -> {
@@ -1422,11 +1516,8 @@
 + 			}
 + 			disableLightmap();
 + 			GlStateManager.disableLighting();
-+ 			this.mc.mcProfiler.endStartSection("worldBorder");
 + 			mc.renderGlobal.renderWorldBorder(entity, partialTicks);
 + 		}
-+ 
-+ 		mc.mcProfiler.endSection();
 + 	}
 + 
 + 	public boolean renderHeldItemLight(EntityLivingBase entityLiving, float mag) {
diff --git a/patches/minecraft/net/minecraft/client/renderer/RenderGlobal.edit.java b/patches/minecraft/net/minecraft/client/renderer/RenderGlobal.edit.java
index 7fc3db90..7aaa170e 100644
--- a/patches/minecraft/net/minecraft/client/renderer/RenderGlobal.edit.java
+++ b/patches/minecraft/net/minecraft/client/renderer/RenderGlobal.edit.java
@@ -7,8 +7,10 @@
 
 > DELETE  2  @  2 : 7
 
-> CHANGE  6 : 10  @  6 : 7
+> CHANGE  6 : 12  @  6 : 7
 
+~ 
+~ import net.lax1dude.eaglercraft.v1_8.EagRuntime;
 ~ import net.lax1dude.eaglercraft.v1_8.EaglercraftRandom;
 ~ import net.lax1dude.eaglercraft.v1_8.HString;
 ~ import net.lax1dude.eaglercraft.v1_8.Keyboard;
@@ -220,7 +222,11 @@
 
 + 			boolean light = DynamicLightManager.isRenderingLights();
 
-> CHANGE  27 : 36  @  27 : 54
+> DELETE  6  @  6 : 7
+
+> DELETE  16  @  16 : 17
+
+> CHANGE  3 : 12  @  3 : 30
 
 ~ 			if (!DeferredStateManager.isDeferredRenderer()) {
 ~ 				for (int i = 0; i < this.theWorld.weatherEffects.size(); ++i) {
@@ -234,7 +240,7 @@
 
 > DELETE  2  @  2 : 16
 
-> CHANGE  4 : 7  @  4 : 5
+> CHANGE  2 : 5  @  2 : 5
 
 ~ 			label738: for (int ii = 0, ll = this.renderInfos.size(); ii < ll; ++ii) {
 ~ 				RenderGlobal.ContainerLocalRenderInformation renderglobal$containerlocalrenderinformation = this.renderInfos
@@ -246,7 +252,9 @@
 + 								entity2.renderDynamicLightsEagler(partialTicks, flag2);
 + 							}
 
-> CHANGE  27 : 30  @  27 : 28
+> DELETE  24  @  24 : 25
+
+> CHANGE  2 : 5  @  2 : 3
 
 ~ 			for (int ii = 0, ll = this.renderInfos.size(); ii < ll; ++ii) {
 ~ 				RenderGlobal.ContainerLocalRenderInformation renderglobal$containerlocalrenderinformation1 = this.renderInfos
@@ -258,7 +266,9 @@
 ~ 						TileEntityRendererDispatcher.instance.renderTileEntity((TileEntity) list1.get(m), partialTicks,
 ~ 								-1);
 
-> INSERT  40 : 199  @  40
+> DELETE  36  @  36 : 37
+
+> INSERT  3 : 154  @  3
 
 + 	public static interface EntityChunkCullAdapter {
 + 		boolean shouldCull(RenderChunk renderChunk);
@@ -271,8 +281,6 @@
 + 	public void renderShadowLODEntities(Entity renderViewEntity, float partialTicks,
 + 			EntityChunkCullAdapter entityChunkCull, EntityObjectCullAdapter entityObjectCull) { // TODO
 + 		if (renderEntitiesStartupCounter <= 0) {
-+ 			theWorld.theProfiler.startSection("shadow_entity_prepare");
-+ 
 + 			TileEntityRendererDispatcher.instance.cacheActiveRenderInfo(theWorld, mc.getTextureManager(),
 + 					mc.fontRendererObj, renderViewEntity, partialTicks);
 + 			renderManager.cacheActiveRenderInfo(theWorld, mc.fontRendererObj, renderViewEntity, mc.pointedEntity,
@@ -289,7 +297,6 @@
 + 			TileEntityRendererDispatcher.staticPlayerZ = d5;
 + 			renderManager.setRenderPosition(d3, d4, d5);
 + 
-+ 			this.theWorld.theProfiler.endStartSection("shadow_entities");
 + 			for (RenderGlobal.ContainerLocalRenderInformation containerlocalrenderinformation : this.renderInfos) {
 + 				RenderChunk currentRenderChunk = containerlocalrenderinformation.renderChunk;
 + 
@@ -343,14 +350,11 @@
 + 					GlStateManager.depthMask(true);
 + 				}
 + 			}
-+ 			theWorld.theProfiler.endSection();
 + 		}
 + 	}
 + 
 + 	public void renderParaboloidTileEntities(Entity renderViewEntity, float partialTicks, int up) {
 + 		if (renderEntitiesStartupCounter <= 0) {
-+ 			theWorld.theProfiler.startSection("paraboloid_entity_prepare");
-+ 
 + 			TileEntityRendererDispatcher.instance.cacheActiveRenderInfo(theWorld, mc.getTextureManager(),
 + 					mc.fontRendererObj, renderViewEntity, partialTicks);
 + 			renderManager.cacheActiveRenderInfo(theWorld, mc.fontRendererObj, renderViewEntity, mc.pointedEntity,
@@ -391,7 +395,6 @@
 + 			maxY = MathHelper.floor_double(maxY / 16.0) * 16;
 + 			maxZ = MathHelper.floor_double(maxZ / 16.0) * 16;
 + 
-+ 			this.theWorld.theProfiler.endStartSection("paraboloid_entities");
 + 			for (int cx = minX; cx <= maxX; cx += 16) {
 + 				for (int cz = minZ; cz <= maxZ; cz += 16) {
 + 					for (int cy = minY; cy <= maxY; cy += 16) {
@@ -414,7 +417,6 @@
 + 					}
 + 				}
 + 			}
-+ 			theWorld.theProfiler.endSection();
 + 			mc.entityRenderer.disableLightmap();
 + 		}
 + 	}
@@ -430,7 +432,15 @@
 
 ~ 		return HString.format("C: %d/%d %sD: %d, %s",
 
-> CHANGE  53 : 55  @  53 : 54
+> DELETE  15  @  15 : 16
+
+> DELETE  15  @  15 : 16
+
+> DELETE  4  @  4 : 5
+
+> DELETE  7  @  7 : 8
+
+> CHANGE  8 : 10  @  8 : 9
 
 ~ 				|| (double) viewEntity.rotationYaw != this.lastViewEntityYaw
 ~ 				|| this.mc.entityRenderer.currentProjMatrixFOV != this.lastViewProjMatrixFOV;
@@ -457,12 +467,16 @@
 ~ 			RenderGlobal.ContainerLocalRenderInformation renderglobal$containerlocalrenderinformation2 = this.renderInfos
 ~ 					.get(ii);
 
-> CHANGE  3 : 5  @  3 : 4
+> CHANGE  3 : 5  @  3 : 5
 
 ~ 				if (this.mc.gameSettings.chunkFix ? this.isPositionInRenderChunkHack(blockpos1, renderchunk4)
 ~ 						: this.isPositionInRenderChunk(blockpos, renderchunk4)) {
 
-> INSERT  21 : 31  @  21
+> DELETE  2  @  2 : 3
+
+> DELETE  7  @  7 : 8
+
+> INSERT  9 : 19  @  9
 
 + 	/**
 + 	 * WARNING: use only in the above "build near" logic
@@ -479,13 +493,23 @@
 
 + 		((ClippingHelperImpl) this.debugFixedClippingHelper).destroy();
 
-> CHANGE  58 : 61  @  58 : 59
+> DELETE  48  @  48 : 49
+
+> CHANGE  9 : 12  @  9 : 10
 
 ~ 				for (int ii = 0, ll = this.renderInfos.size(); ii < ll; ++ii) {
 ~ 					RenderGlobal.ContainerLocalRenderInformation renderglobal$containerlocalrenderinformation = this.renderInfos
 ~ 							.get(ii);
 
-> INSERT  33 : 70  @  33
+> DELETE  7  @  7 : 9
+
+> DELETE  2  @  2 : 3
+
+> DELETE  15  @  15 : 16
+
+> DELETE  1  @  1 : 2
+
+> INSERT  3 : 39  @  3
 
 + 	public static interface ChunkCullAdapter {
 + 		boolean shouldCull(RenderChunk chunk);
@@ -518,7 +542,6 @@
 + 			}
 + 		}
 + 		if (i > 0) {
-+ 			this.mc.mcProfiler.endStartSection("render_shadow_" + blockLayerIn);
 + 			this.renderContainer.renderChunkLayer(blockLayerIn);
 + 		}
 + 		return i;
@@ -579,10 +602,9 @@
 ~ 						++i;
 ~ 					}
 
-> CHANGE  3 : 10  @  3 : 5
+> CHANGE  3 : 9  @  3 : 5
 
 ~ 		if (i > 0) {
-~ 			this.mc.mcProfiler.endStartSection("render_paraboloid_" + up + "_" + blockLayerIn);
 ~ 			this.mc.entityRenderer.enableLightmap();
 ~ 			this.renderContainer.renderChunkLayer(blockLayerIn);
 ~ 			this.mc.entityRenderer.disableLightmap();
@@ -609,7 +631,11 @@
 
 ~ 		this.displayListEntitiesDirty |= this.renderDispatcher.updateChunks(finishTimeNano);
 
-> DELETE  17  @  17 : 18
+> CHANGE  11 : 12  @  11 : 12
+
+~ 				long i = finishTimeNano - EagRuntime.nanoTime();
+
+> DELETE  5  @  5 : 6
 
 > CHANGE  155 : 159  @  155 : 156
 
diff --git a/patches/minecraft/net/minecraft/client/renderer/entity/Render.edit.java b/patches/minecraft/net/minecraft/client/renderer/entity/Render.edit.java
index 331e4262..6223d48a 100644
--- a/patches/minecraft/net/minecraft/client/renderer/entity/Render.edit.java
+++ b/patches/minecraft/net/minecraft/client/renderer/entity/Render.edit.java
@@ -35,7 +35,11 @@
 + 			return true;
 + 		}
 
-> INSERT  21 : 25  @  21
+> CHANGE  17 : 18  @  17 : 18
+
+~ 			this.renderLivingLabel(entity, entity.getDisplayNameProfanityFilter().getFormattedText(), x, y, z, 64);
+
+> INSERT  3 : 7  @  3
 
 + 	public static void renderNameAdapter(Render r, Entity e, double x, double y, double z) {
 + 		r.renderName(e, x, y, z);
diff --git a/patches/minecraft/net/minecraft/client/renderer/entity/RenderPlayer.edit.java b/patches/minecraft/net/minecraft/client/renderer/entity/RenderPlayer.edit.java
index e02a7be6..21709fb5 100644
--- a/patches/minecraft/net/minecraft/client/renderer/entity/RenderPlayer.edit.java
+++ b/patches/minecraft/net/minecraft/client/renderer/entity/RenderPlayer.edit.java
@@ -62,7 +62,11 @@
 ~ 				modelplayer_.bipedRightArmwear.showModel = clientPlayer.isWearing(EnumPlayerModelParts.RIGHT_SLEEVE);
 ~ 			}
 
-> CHANGE  50 : 60  @  50 : 58
+> CHANGE  41 : 42  @  41 : 42
+
+~ 						score.getScorePoints() + " " + scoreobjective.getDisplayNameProfanityFilter(), d0, d1, d2, 64);
+
+> CHANGE  8 : 18  @  8 : 16
 
 ~ 		if (!zombieModel) {
 ~ 			float f = 1.0F;
diff --git a/patches/minecraft/net/minecraft/client/renderer/entity/RendererLivingEntity.edit.java b/patches/minecraft/net/minecraft/client/renderer/entity/RendererLivingEntity.edit.java
index b60a41f5..455565d8 100644
--- a/patches/minecraft/net/minecraft/client/renderer/entity/RendererLivingEntity.edit.java
+++ b/patches/minecraft/net/minecraft/client/renderer/entity/RendererLivingEntity.edit.java
@@ -147,7 +147,11 @@
 ~ 		for (int i = 0, l = this.layerRenderers.size(); i < l; ++i) {
 ~ 			LayerRenderer layerrenderer = this.layerRenderers.get(i);
 
-> INSERT  30 : 34  @  30
+> CHANGE  26 : 27  @  26 : 27
+
+~ 				String s = entitylivingbase.getDisplayNameProfanityFilter().getFormattedText();
+
+> INSERT  3 : 7  @  3
 
 + 					if (DeferredStateManager.isInDeferredPass()) {
 + 						NameTagRenderer.renderNameTag(entitylivingbase, null, d0, d1, d2, -69);
diff --git a/patches/minecraft/net/minecraft/client/renderer/texture/AbstractTexture.edit.java b/patches/minecraft/net/minecraft/client/renderer/texture/AbstractTexture.edit.java
index 1c2f70a4..81fc2047 100644
--- a/patches/minecraft/net/minecraft/client/renderer/texture/AbstractTexture.edit.java
+++ b/patches/minecraft/net/minecraft/client/renderer/texture/AbstractTexture.edit.java
@@ -38,7 +38,7 @@
 
 + 			hasAllocated = false;
 
-> INSERT  12 : 26  @  12
+> INSERT  12 : 28  @  12
 
 + 
 + 	/**
@@ -49,7 +49,9 @@
 + 	protected void regenerateIfNotAllocated() {
 + 		if (this.glTextureId != -1) {
 + 			if (hasAllocated) {
-+ 				EaglercraftGPU.regenerateTexture(glTextureId);
++ 				if (EaglercraftGPU.checkTexStorageCapable()) {
++ 					EaglercraftGPU.regenerateTexture(glTextureId);
++ 				}
 + 			}
 + 			hasAllocated = true;
 + 		}
diff --git a/patches/minecraft/net/minecraft/client/renderer/texture/TextureMap.edit.java b/patches/minecraft/net/minecraft/client/renderer/texture/TextureMap.edit.java
index 184c9f17..6c0afd2d 100644
--- a/patches/minecraft/net/minecraft/client/renderer/texture/TextureMap.edit.java
+++ b/patches/minecraft/net/minecraft/client/renderer/texture/TextureMap.edit.java
@@ -43,7 +43,7 @@
 ~ 	private final Map<String, EaglerTextureAtlasSprite> mapRegisteredSprites;
 ~ 	private final Map<String, EaglerTextureAtlasSprite> mapUploadedSprites;
 
-> CHANGE  3 : 10  @  3 : 4
+> CHANGE  3 : 11  @  3 : 4
 
 ~ 	private final EaglerTextureAtlasSprite missingImage;
 ~ 	private final EaglerTextureAtlasSpritePBR missingImagePBR;
@@ -52,6 +52,7 @@
 ~ 	private boolean isEaglerPBRMode = false;
 ~ 	public int eaglerPBRMaterialTexture = -1;
 ~ 	private boolean hasAllocatedEaglerPBRMaterialTexture = false;
+~ 	private boolean isGLES2 = false;
 
 > INSERT  1 : 7  @  1
 
@@ -67,7 +68,11 @@
 ~ 		this.missingImage = new EaglerTextureAtlasSprite("missingno");
 ~ 		this.missingImagePBR = new EaglerTextureAtlasSpritePBR("missingno");
 
-> INSERT  11 : 27  @  11
+> INSERT  2 : 3  @  2
+
++ 		this.isGLES2 = EaglercraftGPU.checkOpenGLESVersion() == 200;
+
+> INSERT  9 : 25  @  9
 
 + 		this.missingImagePBR.setIconWidth(16);
 + 		this.missingImagePBR.setIconHeight(16);
@@ -308,8 +313,9 @@
 
 + 		regenerateIfNotAllocated();
 
-> INSERT  2 : 23  @  2
+> INSERT  2 : 24  @  2
 
++ 
 + 		if (isEaglerPBRMode) {
 + 			if (hasAllocatedEaglerPBRMaterialTexture) {
 + 				EaglercraftGPU.regenerateTexture(eaglerPBRMaterialTexture);
@@ -423,12 +429,21 @@
 ~ 					textureatlassprite = EaglerTextureAtlasSprite.makeAtlasSprite(location);
 ~ 				}
 
-> CHANGE  15 : 17  @  15 : 17
+> CHANGE  12 : 18  @  12 : 13
+
+~ 		if (!isGLES2) {
+~ 			this.mipmapLevels = mipmapLevelsIn;
+~ 		} else {
+~ 			this.mipmapLevels = 0; // Due to limitations in OpenGL ES 2.0 texture completeness, its easier to just
+~ 									// make this zero
+~ 		}
+
+> CHANGE  2 : 4  @  2 : 4
 
 ~ 	public EaglerTextureAtlasSprite getMissingSprite() {
 ~ 		return isEaglerPBRMode ? missingImagePBR : missingImage;
 
-> INSERT  1 : 23  @  1
+> INSERT  1 : 27  @  1
 
 + 
 + 	public int getWidth() {
@@ -444,12 +459,16 @@
 + 	}
 + 
 + 	public void setBlurMipmapDirect0(boolean parFlag, boolean parFlag2) {
-+ 		super.setBlurMipmapDirect0(parFlag, parFlag2);
-+ 		if (isEaglerPBRMode && eaglerPBRMaterialTexture != -1) {
-+ 			GlStateManager.setActiveTexture(33986);
-+ 			GlStateManager.bindTexture(eaglerPBRMaterialTexture);
++ 		if (isGLES2) {
++ 			super.setBlurMipmapDirect0(parFlag, false);
++ 		} else {
 + 			super.setBlurMipmapDirect0(parFlag, parFlag2);
-+ 			GlStateManager.setActiveTexture(33984);
++ 			if (isEaglerPBRMode && eaglerPBRMaterialTexture != -1) {
++ 				GlStateManager.setActiveTexture(33986);
++ 				GlStateManager.bindTexture(eaglerPBRMaterialTexture);
++ 				super.setBlurMipmapDirect0(parFlag, parFlag2);
++ 				GlStateManager.setActiveTexture(33984);
++ 			}
 + 		}
 + 	}
 
diff --git a/patches/minecraft/net/minecraft/client/renderer/texture/TextureUtil.edit.java b/patches/minecraft/net/minecraft/client/renderer/texture/TextureUtil.edit.java
index 1dc65448..f17a7443 100644
--- a/patches/minecraft/net/minecraft/client/renderer/texture/TextureUtil.edit.java
+++ b/patches/minecraft/net/minecraft/client/renderer/texture/TextureUtil.edit.java
@@ -29,7 +29,15 @@
 
 ~ 	public static int uploadTextureImage(int parInt1, ImageData parBufferedImage) {
 
-> CHANGE  120 : 122  @  120 : 121
+> INSERT  112 : 117  @  112
+
++ 		if (!parFlag2 && !EaglercraftGPU.checkNPOTCapable() && ImageData.isNPOTStatic(parInt2, parInt3)) {
++ 			parFlag2 = true;
++ 			logger.warn(
++ 					"An NPOT (non-power-of-two) texture was allocated with GL_REPEAT wrapping in an OpenGL context where that isn't supported, changing to GL_CLAMP_TO_EDGE to avoid errors");
++ 		}
+
+> CHANGE  8 : 10  @  8 : 9
 
 ~ 			EaglercraftGPU.glTexSubImage2D(GL_TEXTURE_2D, parInt1, parInt4, parInt5 + k, parInt2, l, GL_RGBA,
 ~ 					GL_UNSIGNED_BYTE, dataBuffer);
@@ -46,12 +54,14 @@
 
 ~ 		// deleteTexture(parInt1); //TODO: why
 
-> CHANGE  2 : 6  @  2 : 6
+> CHANGE  2 : 8  @  2 : 6
 
-~ 			EaglercraftGPU.glTexParameteri(GL_TEXTURE_2D, '\u813d', parInt2);
-~ 			EaglercraftGPU.glTexParameterf(GL_TEXTURE_2D, '\u813a', 0.0F);
-~ 			EaglercraftGPU.glTexParameterf(GL_TEXTURE_2D, '\u813b', (float) parInt2);
-~ 			// EaglercraftGPU.glTexParameterf(GL_TEXTURE_2D, '\u8501', 0.0F);
+~ 			if (EaglercraftGPU.checkOpenGLESVersion() >= 300) {
+~ 				EaglercraftGPU.glTexParameteri(GL_TEXTURE_2D, '\u813d', parInt2);
+~ 				EaglercraftGPU.glTexParameterf(GL_TEXTURE_2D, '\u813a', 0.0F);
+~ 				EaglercraftGPU.glTexParameterf(GL_TEXTURE_2D, '\u813b', (float) parInt2);
+~ 				// EaglercraftGPU.glTexParameterf(GL_TEXTURE_2D, '\u8501', 0.0F);
+~ 			}
 
 > CHANGE  1 : 2  @  1 : 6
 
@@ -68,7 +78,15 @@
 ~ 		int i = parBufferedImage.width;
 ~ 		int j = parBufferedImage.height;
 
-> CHANGE  11 : 13  @  11 : 12
+> INSERT  3 : 8  @  3
+
++ 		if (!parFlag2 && !EaglercraftGPU.checkNPOTCapable() && parBufferedImage.isNPOT()) {
++ 			parFlag2 = true;
++ 			logger.warn(
++ 					"An NPOT (non-power-of-two) texture was allocated with GL_REPEAT wrapping in an OpenGL context where that isn't supported, changing to GL_CLAMP_TO_EDGE to avoid errors");
++ 		}
+
+> CHANGE  8 : 10  @  8 : 9
 
 ~ 			EaglercraftGPU.glTexSubImage2D(GL_TEXTURE_2D, 0, parInt1, parInt2 + i1, i, j1, GL_RGBA, GL_UNSIGNED_BYTE,
 ~ 					dataBuffer);
diff --git a/patches/minecraft/net/minecraft/client/renderer/tileentity/RenderItemFrame.edit.java b/patches/minecraft/net/minecraft/client/renderer/tileentity/RenderItemFrame.edit.java
index ceb73e10..72a7ff3a 100644
--- a/patches/minecraft/net/minecraft/client/renderer/tileentity/RenderItemFrame.edit.java
+++ b/patches/minecraft/net/minecraft/client/renderer/tileentity/RenderItemFrame.edit.java
@@ -52,7 +52,11 @@
 ~ 				if (emissive) {
 ~ 					DeferredStateManager.setEmissionConstant(0.0f);
 
-> INSERT  19 : 23  @  19
+> CHANGE  17 : 18  @  17 : 18
+
+~ 				String s = entityitemframe.getDisplayedItem().getDisplayNameProfanityFilter();
+
+> INSERT  1 : 5  @  1
 
 + 					if (DeferredStateManager.isInDeferredPass()) {
 + 						NameTagRenderer.renderNameTag(entityitemframe, null, d0, d1, d2, -69);
diff --git a/patches/minecraft/net/minecraft/client/renderer/tileentity/TileEntityBannerRenderer.edit.java b/patches/minecraft/net/minecraft/client/renderer/tileentity/TileEntityBannerRenderer.edit.java
index e670e4cb..116da42f 100644
--- a/patches/minecraft/net/minecraft/client/renderer/tileentity/TileEntityBannerRenderer.edit.java
+++ b/patches/minecraft/net/minecraft/client/renderer/tileentity/TileEntityBannerRenderer.edit.java
@@ -7,22 +7,31 @@
 
 > DELETE  2  @  2 : 4
 
-> INSERT  4 : 9  @  4
+> INSERT  4 : 10  @  4
 
 + 
 + import com.google.common.collect.Lists;
 + import com.google.common.collect.Maps;
 + 
++ import net.lax1dude.eaglercraft.v1_8.EagRuntime;
 + import net.lax1dude.eaglercraft.v1_8.opengl.GlStateManager;
 
 > DELETE  2  @  2 : 3
 
 > DELETE  1  @  1 : 2
 
-> CHANGE  95 : 98  @  95 : 98
+> CHANGE  72 : 73  @  72 : 73
+
+~ 					long i = EagRuntime.steadyTimeMillis();
+
+> CHANGE  22 : 25  @  22 : 25
 
 ~ 				for (int i = 0, l = list1.size(); i < l; ++i) {
 ~ 					arraylist.add("textures/entity/banner/"
 ~ 							+ ((TileEntityBanner.EnumBannerPattern) list1.get(i)).getPatternName() + ".png");
 
+> CHANGE  10 : 11  @  10 : 11
+
+~ 			tileentitybannerrenderer$timedbannertexture.systemTime = EagRuntime.steadyTimeMillis();
+
 > EOF
diff --git a/patches/minecraft/net/minecraft/client/renderer/tileentity/TileEntityChestRenderer.edit.java b/patches/minecraft/net/minecraft/client/renderer/tileentity/TileEntityChestRenderer.edit.java
index c94fc0ea..dea0afda 100644
--- a/patches/minecraft/net/minecraft/client/renderer/tileentity/TileEntityChestRenderer.edit.java
+++ b/patches/minecraft/net/minecraft/client/renderer/tileentity/TileEntityChestRenderer.edit.java
@@ -5,19 +5,14 @@
 # Version: 1.0
 # Author: lax1dude
 
-> INSERT  3 : 6  @  3
+> INSERT  3 : 5  @  3
 
 + 
-+ import net.lax1dude.eaglercraft.v1_8.EagRuntime;
 + import net.lax1dude.eaglercraft.v1_8.opengl.GlStateManager;
 
 > DELETE  4  @  4 : 6
 
-> CHANGE  19 : 20  @  19 : 20
-
-~ 		Calendar calendar = EagRuntime.getLocaleCalendar();
-
-> DELETE  36  @  36 : 38
+> DELETE  56  @  56 : 58
 
 > INSERT  2 : 4  @  2
 
diff --git a/patches/minecraft/net/minecraft/client/renderer/tileentity/TileEntitySignRenderer.edit.java b/patches/minecraft/net/minecraft/client/renderer/tileentity/TileEntitySignRenderer.edit.java
index 227bdaa5..f29ef566 100644
--- a/patches/minecraft/net/minecraft/client/renderer/tileentity/TileEntitySignRenderer.edit.java
+++ b/patches/minecraft/net/minecraft/client/renderer/tileentity/TileEntitySignRenderer.edit.java
@@ -23,19 +23,39 @@
 
 > DELETE  4  @  4 : 5
 
-> CHANGE  55 : 56  @  55 : 56
+> INSERT  5 : 7  @  5
+
++ 	public static boolean disableProfanityFilter = false;
++ 
+
+> CHANGE  50 : 51  @  50 : 51
 
 ~ 		EaglercraftGPU.glNormal3f(0.0F, 0.0F, -1.0F * f3);
 
-> INSERT  3 : 8  @  3
+> CHANGE  3 : 13  @  3 : 6
 
-+ 			if (DeferredStateManager.isInDeferredPass()) {
-+ 				_wglDrawBuffers(_GL_COLOR_ATTACHMENT0);
-+ 				GlStateManager.colorMask(true, true, true, false);
-+ 				GlStateManager.color(1.0f, 1.0f, 1.0f, 1.0f);
-+ 			}
+~ 			if (DeferredStateManager.isInDeferredPass()) {
+~ 				_wglDrawBuffers(_GL_COLOR_ATTACHMENT0);
+~ 				GlStateManager.colorMask(true, true, true, false);
+~ 				GlStateManager.color(1.0f, 1.0f, 1.0f, 1.0f);
+~ 			}
+~ 			IChatComponent[] signText = disableProfanityFilter ? tileentitysign.signText
+~ 					: tileentitysign.getSignTextProfanityFilter();
+~ 			for (int j = 0; j < signText.length; ++j) {
+~ 				if (signText[j] != null) {
+~ 					IChatComponent ichatcomponent = signText[j];
 
-> INSERT  15 : 19  @  15
+> CHANGE  4 : 6  @  4 : 6
+
+~ 						fontrenderer.drawString(s, -fontrenderer.getStringWidth(s) / 2, j * 10 - signText.length * 5,
+~ 								b0);
+
+> CHANGE  1 : 3  @  1 : 3
+
+~ 						fontrenderer.drawString(s, -fontrenderer.getStringWidth(s) / 2, j * 10 - signText.length * 5,
+~ 								b0);
+
+> INSERT  3 : 7  @  3
 
 + 			if (DeferredStateManager.isInDeferredPass()) {
 + 				_wglDrawBuffers(EaglerDeferredPipeline.instance.gBufferDrawBuffers);
diff --git a/patches/minecraft/net/minecraft/client/resources/DefaultResourcePack.edit.java b/patches/minecraft/net/minecraft/client/resources/DefaultResourcePack.edit.java
index 90c6935c..7b3cd4c9 100644
--- a/patches/minecraft/net/minecraft/client/resources/DefaultResourcePack.edit.java
+++ b/patches/minecraft/net/minecraft/client/resources/DefaultResourcePack.edit.java
@@ -34,20 +34,22 @@
 ~ 		return EagRuntime
 ~ 				.getResourceStream("/assets/" + location.getResourceDomain() + "/" + location.getResourcePath());
 
-> CHANGE  3 : 4  @  3 : 5
+> CHANGE  2 : 5  @  2 : 5
 
-~ 		return this.getResourceStream(resourcelocation) != null;
+~ 	public boolean resourceExists(ResourceLocation location) {
+~ 		return EagRuntime
+~ 				.getResourceExists("/assets/" + location.getResourceDomain() + "/" + location.getResourcePath());
 
 > CHANGE  9 : 11  @  9 : 11
 
 ~ 			return AbstractResourcePack.readMetadata(parIMetadataSerializer,
-~ 					EagRuntime.getResourceStream("pack.mcmeta"), parString1);
+~ 					EagRuntime.getRequiredResourceStream("pack.mcmeta"), parString1);
 
 > DELETE  2  @  2 : 4
 
 > CHANGE  3 : 5  @  3 : 6
 
 ~ 	public ImageData getPackImage() throws IOException {
-~ 		return TextureUtil.readBufferedImage(EagRuntime.getResourceStream("pack.png"));
+~ 		return TextureUtil.readBufferedImage(EagRuntime.getRequiredResourceStream("pack.png"));
 
 > EOF
diff --git a/patches/minecraft/net/minecraft/client/resources/Locale.edit.java b/patches/minecraft/net/minecraft/client/resources/Locale.edit.java
index eba9bf1c..79305514 100644
--- a/patches/minecraft/net/minecraft/client/resources/Locale.edit.java
+++ b/patches/minecraft/net/minecraft/client/resources/Locale.edit.java
@@ -31,7 +31,7 @@
 
 > INSERT  7 : 9  @  7
 
-+ 	private static final Set<String> hasShownMissing = new HashSet();
++ 	private static final Set<String> hasShownMissing = new HashSet<>();
 + 
 
 > CHANGE  4 : 5  @  4 : 5
diff --git a/patches/minecraft/net/minecraft/client/settings/GameSettings.edit.java b/patches/minecraft/net/minecraft/client/settings/GameSettings.edit.java
index c2b73915..b99e5cee 100644
--- a/patches/minecraft/net/minecraft/client/settings/GameSettings.edit.java
+++ b/patches/minecraft/net/minecraft/client/settings/GameSettings.edit.java
@@ -14,7 +14,7 @@
 
 > DELETE  1  @  1 : 3
 
-> INSERT  3 : 27  @  3
+> INSERT  3 : 31  @  3
 
 + 
 + import net.lax1dude.eaglercraft.v1_8.sp.relay.RelayManager;
@@ -34,12 +34,16 @@
 + import net.lax1dude.eaglercraft.v1_8.EaglerZLIB;
 + import net.lax1dude.eaglercraft.v1_8.HString;
 + import net.lax1dude.eaglercraft.v1_8.Keyboard;
-+ import net.lax1dude.eaglercraft.v1_8.Mouse;
++ import net.lax1dude.eaglercraft.v1_8.PointerInputAbstraction;
 + import net.lax1dude.eaglercraft.v1_8.internal.EnumPlatformType;
 + import net.lax1dude.eaglercraft.v1_8.internal.KeyboardConstants;
 + import net.lax1dude.eaglercraft.v1_8.log4j.LogManager;
 + import net.lax1dude.eaglercraft.v1_8.log4j.Logger;
 + import net.lax1dude.eaglercraft.v1_8.opengl.ext.deferred.EaglerDeferredConfig;
++ import net.lax1dude.eaglercraft.v1_8.opengl.ext.deferred.EaglerDeferredPipeline;
++ import net.lax1dude.eaglercraft.v1_8.opengl.ext.dynamiclights.DynamicLightsStateManager;
++ import net.lax1dude.eaglercraft.v1_8.recording.EnumScreenRecordingCodec;
++ import net.lax1dude.eaglercraft.v1_8.recording.ScreenRecordingController;
 
 > DELETE  5  @  5 : 7
 
@@ -91,7 +95,7 @@
 
 ~ 	public int guiScale = 3;
 
-> INSERT  3 : 18  @  3
+> INSERT  3 : 22  @  3
 
 + 	public boolean hudFps = true;
 + 	public boolean hudCoords = true;
@@ -108,14 +112,26 @@
 + 	public boolean enableUpdateSvc = true;
 + 	public boolean enableFNAWSkins = true;
 + 	public boolean enableDynamicLights = false;
++ 	public boolean hasHiddenPhishWarning = false;
++ 	public boolean enableProfanityFilter = false;
++ 	public boolean hasShownProfanityFilter = false;
++ 	public float touchControlOpacity = 1.0f;
 
-> CHANGE  1 : 7  @  1 : 2
+> CHANGE  1 : 15  @  1 : 2
 
 ~ 	public int voiceListenRadius = 16;
 ~ 	public float voiceListenVolume = 0.5f;
 ~ 	public float voiceSpeakVolume = 0.5f;
 ~ 	public int voicePTTKey = 47; // V
 ~ 
+~ 	public EnumScreenRecordingCodec screenRecordCodec;
+~ 	public int screenRecordFPS = ScreenRecordingController.DEFAULT_FPS;
+~ 	public int screenRecordResolution = ScreenRecordingController.DEFAULT_RESOLUTION;
+~ 	public int screenRecordAudioBitrate = ScreenRecordingController.DEFAULT_AUDIO_BITRATE;
+~ 	public int screenRecordVideoBitrate = ScreenRecordingController.DEFAULT_VIDEO_BITRATE;
+~ 	public float screenRecordGameVolume = ScreenRecordingController.DEFAULT_GAME_VOLUME;
+~ 	public float screenRecordMicVolume = ScreenRecordingController.DEFAULT_MIC_VOLUME;
+~ 
 ~ 	public GameSettings(Minecraft mcIn) {
 
 > CHANGE  4 : 6  @  4 : 7
@@ -133,13 +149,10 @@
 ~ 		this.gammaSetting = 1.0F;
 ~ 		this.language = EagRuntime.getConfiguration().getDefaultLocale();
 
-> CHANGE  2 : 3  @  2 : 8
-
-~ 		GameSettings.Options.RENDER_DISTANCE.setValueMax(18.0F);
-
-> CHANGE  1 : 2  @  1 : 2
+> CHANGE  2 : 4  @  2 : 10
 
 ~ 		this.renderDistanceChunks = 4;
+~ 		this.screenRecordCodec = ScreenRecordingController.getDefaultCodec();
 
 > DELETE  3  @  3 : 18
 
@@ -147,55 +160,106 @@
 
 ~ 						: HString.format("%c", new Object[] { Character.valueOf((char) (parInt1 - 256)) })
 
-> DELETE  76  @  76 : 99
+> CHANGE  5 : 7  @  5 : 6
+
+~ 				: (parKeyBinding.getKeyCode() < 0
+~ 						? PointerInputAbstraction.getVCursorButtonDown(parKeyBinding.getKeyCode() + 100)
+
+> CHANGE  71 : 73  @  71 : 73
+
+~ 		if (parOptions == GameSettings.Options.EAGLER_TOUCH_CONTROL_OPACITY) {
+~ 			this.touchControlOpacity = parFloat1;
+
+> DELETE  1  @  1 : 20
 
 > INSERT  35 : 37  @  35
 
 + 			this.mc.loadingScreen.eaglerShow(I18n.format("resourcePack.load.refreshing"),
 + 					I18n.format("resourcePack.load.pleaseWait"));
 
-> DELETE  18  @  18 : 38
+> CHANGE  18 : 20  @  18 : 20
 
-> DELETE  20  @  20 : 37
+~ 		if (parOptions == GameSettings.Options.CHAT_COLOR) {
+~ 			this.chatColours = !this.chatColours;
 
-> INSERT  13 : 67  @  13
+> CHANGE  2 : 4  @  2 : 4
+
+~ 		if (parOptions == GameSettings.Options.CHAT_LINKS) {
+~ 			this.chatLinks = !this.chatLinks;
+
+> CHANGE  2 : 4  @  2 : 4
+
+~ 		if (parOptions == GameSettings.Options.CHAT_LINKS_PROMPT) {
+~ 			this.chatLinksPrompt = !this.chatLinksPrompt;
+
+> CHANGE  2 : 4  @  2 : 4
+
+~ 		if (parOptions == GameSettings.Options.SNOOPER_ENABLED) {
+~ 			this.snooperEnabled = !this.snooperEnabled;
+
+> CHANGE  2 : 5  @  2 : 4
+
+~ 		if (parOptions == GameSettings.Options.BLOCK_ALTERNATIVES) {
+~ 			this.allowBlockAlternatives = !this.allowBlockAlternatives;
+~ 			this.mc.renderGlobal.loadRenderers();
+
+> CHANGE  2 : 4  @  2 : 4
+
+~ 		if (parOptions == GameSettings.Options.REDUCED_DEBUG_INFO) {
+~ 			this.reducedDebugInfo = !this.reducedDebugInfo;
+
+> CHANGE  2 : 4  @  2 : 4
+
+~ 		if (parOptions == GameSettings.Options.ENTITY_SHADOWS) {
+~ 			this.field_181151_V = !this.field_181151_V;
+
+> CHANGE  2 : 4  @  2 : 4
+
+~ 		if (parOptions == GameSettings.Options.HUD_FPS) {
+~ 			this.hudFps = !this.hudFps;
+
+> CHANGE  2 : 4  @  2 : 4
+
+~ 		if (parOptions == GameSettings.Options.HUD_COORDS) {
+~ 			this.hudCoords = !this.hudCoords;
+
+> CHANGE  2 : 4  @  2 : 4
+
+~ 		if (parOptions == GameSettings.Options.HUD_PLAYER) {
+~ 			this.hudPlayer = !this.hudPlayer;
+
+> CHANGE  2 : 4  @  2 : 7
+
+~ 		if (parOptions == GameSettings.Options.HUD_STATS) {
+~ 			this.hudStats = !this.hudStats;
+
+> CHANGE  2 : 4  @  2 : 5
+
+~ 		if (parOptions == GameSettings.Options.HUD_WORLD) {
+~ 			this.hudWorld = !this.hudWorld;
+
+> CHANGE  2 : 4  @  2 : 5
+
+~ 		if (parOptions == GameSettings.Options.HUD_24H) {
+~ 			this.hud24h = !this.hud24h;
+
+> CHANGE  2 : 4  @  2 : 5
+
+~ 		if (parOptions == GameSettings.Options.CHUNK_FIX) {
+~ 			this.chunkFix = !this.chunkFix;
+
+> CHANGE  2 : 4  @  2 : 4
+
+~ 		if (parOptions == GameSettings.Options.FOG) {
+~ 			this.fog = !this.fog;
+
+> CHANGE  2 : 4  @  2 : 4
+
+~ 		if (parOptions == GameSettings.Options.FXAA) {
+~ 			this.fxaa = (this.fxaa + parInt1) % 3;
+
+> INSERT  2 : 24  @  2
 
-+ 		if (parOptions == GameSettings.Options.HUD_FPS) {
-+ 			this.hudFps = !this.hudFps;
-+ 		}
-+ 
-+ 		if (parOptions == GameSettings.Options.HUD_COORDS) {
-+ 			this.hudCoords = !this.hudCoords;
-+ 		}
-+ 
-+ 		if (parOptions == GameSettings.Options.HUD_PLAYER) {
-+ 			this.hudPlayer = !this.hudPlayer;
-+ 		}
-+ 
-+ 		if (parOptions == GameSettings.Options.HUD_STATS) {
-+ 			this.hudStats = !this.hudStats;
-+ 		}
-+ 
-+ 		if (parOptions == GameSettings.Options.HUD_WORLD) {
-+ 			this.hudWorld = !this.hudWorld;
-+ 		}
-+ 
-+ 		if (parOptions == GameSettings.Options.HUD_24H) {
-+ 			this.hud24h = !this.hud24h;
-+ 		}
-+ 
-+ 		if (parOptions == GameSettings.Options.CHUNK_FIX) {
-+ 			this.chunkFix = !this.chunkFix;
-+ 		}
-+ 
-+ 		if (parOptions == GameSettings.Options.FOG) {
-+ 			this.fog = !this.fog;
-+ 		}
-+ 
-+ 		if (parOptions == GameSettings.Options.FXAA) {
-+ 			this.fxaa = (this.fxaa + parInt1) % 3;
-+ 		}
-+ 
 + 		if (parOptions == GameSettings.Options.FULLSCREEN) {
 + 			this.mc.toggleFullscreen();
 + 		}
@@ -214,16 +278,20 @@
 + 			this.mc.renderGlobal.loadRenderers();
 + 		}
 + 
++ 		if (parOptions == GameSettings.Options.EAGLER_PROFANITY_FILTER) {
++ 			this.enableProfanityFilter = !this.enableProfanityFilter;
++ 		}
++ 
 
-> CHANGE  23 : 24  @  23 : 34
+> CHANGE  23 : 26  @  23 : 34
 
-~ 																										: 0.0F)))))))))));
+~ 																										: (parOptions == GameSettings.Options.EAGLER_TOUCH_CONTROL_OPACITY
+~ 																												? this.touchControlOpacity
+~ 																												: 0.0F))))))))))));
 
-> DELETE  20  @  20 : 26
+> DELETE  20  @  20 : 30
 
-> DELETE  2  @  2 : 4
-
-> INSERT  8 : 32  @  8
+> INSERT  8 : 34  @  8
 
 + 		case HUD_COORDS:
 + 			return this.hudCoords;
@@ -249,6 +317,8 @@
 + 			return this.enableVsync;
 + 		case EAGLER_DYNAMIC_LIGHTS:
 + 			return this.enableDynamicLights;
++ 		case EAGLER_PROFANITY_FILTER:
++ 			return this.enableProfanityFilter;
 
 > CHANGE  43 : 46  @  43 : 47
 
@@ -264,7 +334,7 @@
 
 ~ 																									.calculateChatboxHeight(
 
-> CHANGE  2 : 21  @  2 : 36
+> CHANGE  2 : 25  @  2 : 36
 
 ~ 																							: (parOptions == GameSettings.Options.CHAT_WIDTH
 ~ 																									? s + GuiNewChat
@@ -284,7 +354,11 @@
 ~ 																															: s + (int) (f
 ~ 																																	* 100.0F)
 ~ 																																	+ "%")
-~ 																													: "yee"))))))))))));
+~ 																													: (parOptions == GameSettings.Options.EAGLER_TOUCH_CONTROL_OPACITY
+~ 																															? (s + (int) (f
+~ 																																	* 100.0F)
+~ 																																	+ "%")
+~ 																															: "yee")))))))))))));
 
 > DELETE  11  @  11 : 19
 
@@ -354,7 +428,9 @@
 
 > DELETE  3  @  3 : 7
 
-> CHANGE  52 : 54  @  52 : 54
+> DELETE  12  @  12 : 16
+
+> CHANGE  36 : 38  @  36 : 38
 
 ~ 					if (astring[0].equals("forceUnicodeFont")) {
 ~ 						this.forceUnicodeFont = astring[1].equals("true");
@@ -459,7 +535,7 @@
 
 ~ 					for (EnumPlayerModelParts enumplayermodelparts : EnumPlayerModelParts._VALUES) {
 
-> INSERT  4 : 14  @  4
+> INSERT  4 : 66  @  4
 
 + 
 + 					if (astring[0].equals("enableFNAWSkins")) {
@@ -470,17 +546,79 @@
 + 						this.enableDynamicLights = astring[1].equals("true");
 + 					}
 + 
++ 					if (astring[0].equals("hasHiddenPhishWarning")) {
++ 						this.hasHiddenPhishWarning = astring[1].equals("true");
++ 					}
++ 
++ 					if (astring[0].equals("enableProfanityFilter")) {
++ 						this.enableProfanityFilter = astring[1].equals("true");
++ 					}
++ 
++ 					if (astring[0].equals("hasShownProfanityFilter")) {
++ 						this.hasShownProfanityFilter = astring[1].equals("true");
++ 					}
++ 
++ 					if (astring[0].equals("screenRecordCodec")) {
++ 						EnumScreenRecordingCodec codec = EnumScreenRecordingCodec.valueOf(astring[1]);
++ 						if (!ScreenRecordingController.codecs.contains(codec)) {
++ 							throw new IllegalStateException("Selected codec is not supported: " + codec.name);
++ 						}
++ 						screenRecordCodec = codec;
++ 					}
++ 
++ 					if (astring[0].equals("screenRecordFPS")) {
++ 						screenRecordFPS = Integer.parseInt(astring[1]);
++ 					}
++ 
++ 					if (astring[0].equals("screenRecordFPS")) {
++ 						screenRecordFPS = Integer.parseInt(astring[1]);
++ 					}
++ 
++ 					if (astring[0].equals("screenRecordResolution")) {
++ 						screenRecordResolution = Integer.parseInt(astring[1]);
++ 					}
++ 
++ 					if (astring[0].equals("screenRecordAudioBitrate")) {
++ 						screenRecordAudioBitrate = Integer.parseInt(astring[1]);
++ 					}
++ 
++ 					if (astring[0].equals("screenRecordVideoBitrate")) {
++ 						screenRecordVideoBitrate = Integer.parseInt(astring[1]);
++ 					}
++ 
++ 					if (astring[0].equals("screenRecordGameVolume")) {
++ 						screenRecordGameVolume = parseFloat(astring[1]);
++ 					}
++ 
++ 					if (astring[0].equals("screenRecordMicVolume")) {
++ 						screenRecordMicVolume = parseFloat(astring[1]);
++ 					}
++ 
++ 					if (astring[0].equals("touchControlOpacity")) {
++ 						touchControlOpacity = parseFloat(astring[1]);
++ 					}
++ 
 + 					deferredShaderConf.readOption(astring[0], astring[1]);
 
-> CHANGE  6 : 13  @  6 : 7
+> CHANGE  6 : 23  @  6 : 7
 
 ~ 
 ~ 			Keyboard.setFunctionKeyModifier(keyBindFunction.getKeyCode());
 ~ 			VoiceClientController.setVoiceListenVolume(voiceListenVolume);
 ~ 			VoiceClientController.setVoiceSpeakVolume(voiceSpeakVolume);
 ~ 			VoiceClientController.setVoiceProximity(voiceListenRadius);
+~ 			ScreenRecordingController.setGameVolume(screenRecordGameVolume);
+~ 			ScreenRecordingController.setMicrophoneVolume(screenRecordMicVolume);
 ~ 			if (this.mc.getRenderManager() != null)
 ~ 				this.mc.getRenderManager().setEnableFNAWSkins(this.enableFNAWSkins);
+~ 			if (this.shaders && !EaglerDeferredPipeline.isSupported()) {
+~ 				logger.error("Setting shaders to false because they are not supported");
+~ 				this.shaders = false;
+~ 			}
+~ 			if (this.enableDynamicLights && !DynamicLightsStateManager.isSupported()) {
+~ 				logger.error("Setting dynamic lights to false because they are not supported");
+~ 				this.enableDynamicLights = false;
+~ 			}
 
 > CHANGE  1 : 3  @  1 : 2
 
@@ -519,9 +657,11 @@
 
 ~ 			printwriter.println("enableVsyncEag:" + this.enableVsync);
 
-> DELETE  13  @  13 : 24
+> DELETE  3  @  3 : 4
 
-> INSERT  5 : 22  @  5
+> DELETE  9  @  9 : 20
+
+> INSERT  5 : 35  @  5
 
 + 			printwriter.println("hudFps:" + this.hudFps);
 + 			printwriter.println("hudWorld:" + this.hudWorld);
@@ -540,6 +680,19 @@
 + 			printwriter.println("voicePTTKey:" + this.voicePTTKey);
 + 			printwriter.println("enableFNAWSkins:" + this.enableFNAWSkins);
 + 			printwriter.println("enableDynamicLights:" + this.enableDynamicLights);
++ 			printwriter.println("hasHiddenPhishWarning:" + this.hasHiddenPhishWarning);
++ 			printwriter.println("enableProfanityFilter:" + this.enableProfanityFilter);
++ 			printwriter.println("hasShownProfanityFilter:" + this.hasShownProfanityFilter);
++ 			if (screenRecordCodec != null) {
++ 				printwriter.println("screenRecordCodec:" + this.screenRecordCodec);
++ 			}
++ 			printwriter.println("screenRecordFPS:" + this.screenRecordFPS);
++ 			printwriter.println("screenRecordResolution:" + this.screenRecordResolution);
++ 			printwriter.println("screenRecordAudioBitrate:" + this.screenRecordAudioBitrate);
++ 			printwriter.println("screenRecordVideoBitrate:" + this.screenRecordVideoBitrate);
++ 			printwriter.println("screenRecordGameVolume:" + this.screenRecordGameVolume);
++ 			printwriter.println("screenRecordMicVolume:" + this.screenRecordMicVolume);
++ 			printwriter.println("touchControlOpacity:" + this.touchControlOpacity);
 
 > CHANGE  5 : 8  @  5 : 6
 
@@ -568,11 +721,7 @@
 
 > DELETE  2  @  2 : 3
 
-> CHANGE  5 : 6  @  5 : 6
-
-~ 				: (parSoundCategory == SoundCategory.VOICE ? 0.0F : 1.0F);
-
-> CHANGE  16 : 17  @  16 : 17
+> CHANGE  22 : 23  @  22 : 23
 
 ~ 					Math.max(this.renderDistanceChunks, 2), this.chatVisibility, this.chatColours, i));
 
@@ -591,12 +740,9 @@
 
 ~ 		RENDER_DISTANCE("options.renderDistance", true, false, 1.0F, 18.0F, 1.0F),
 
-> CHANGE  8 : 10  @  8 : 12
+> DELETE  8  @  8 : 10
 
-~ 		TOUCHSCREEN("options.touchscreen", false, true), CHAT_SCALE("options.chat.scale", true, false),
-~ 		CHAT_WIDTH("options.chat.width", true, false), CHAT_HEIGHT_FOCUSED("options.chat.height.focused", true, false),
-
-> CHANGE  14 : 22  @  14 : 15
+> CHANGE  16 : 26  @  16 : 17
 
 ~ 		ENTITY_SHADOWS("options.entityShadows", false, true), HUD_FPS("options.hud.fps", false, true),
 ~ 		HUD_COORDS("options.hud.coords", false, true), HUD_STATS("options.hud.stats", false, true),
@@ -605,6 +751,8 @@
 ~ 		FOG("options.fog", false, true), FXAA("options.fxaa", false, false),
 ~ 		FULLSCREEN("options.fullscreen", false, true),
 ~ 		FNAW_SKINS("options.skinCustomisation.enableFNAWSkins", false, true),
-~ 		EAGLER_VSYNC("options.vsync", false, true), EAGLER_DYNAMIC_LIGHTS("options.dynamicLights", false, true);
+~ 		EAGLER_VSYNC("options.vsync", false, true), EAGLER_DYNAMIC_LIGHTS("options.dynamicLights", false, true),
+~ 		EAGLER_PROFANITY_FILTER("options.profanityFilterButton", false, true),
+~ 		EAGLER_TOUCH_CONTROL_OPACITY("options.touchControlOpacity", true, false);
 
 > EOF
diff --git a/patches/minecraft/net/minecraft/entity/Entity.edit.java b/patches/minecraft/net/minecraft/entity/Entity.edit.java
index bcd091bd..e7263859 100644
--- a/patches/minecraft/net/minecraft/entity/Entity.edit.java
+++ b/patches/minecraft/net/minecraft/entity/Entity.edit.java
@@ -5,21 +5,23 @@
 # Version: 1.0
 # Author: lax1dude
 
-> CHANGE  3 : 9  @  3 : 5
+> CHANGE  3 : 10  @  3 : 5
 
 ~ import net.lax1dude.eaglercraft.v1_8.EaglercraftRandom;
 ~ import net.lax1dude.eaglercraft.v1_8.EaglercraftUUID;
 ~ import net.lax1dude.eaglercraft.v1_8.HString;
 ~ import net.lax1dude.eaglercraft.v1_8.opengl.ext.deferred.DynamicLightManager;
 ~ import net.lax1dude.eaglercraft.v1_8.opengl.ext.dynamiclights.DynamicLightsStateManager;
+~ import net.lax1dude.eaglercraft.v1_8.profanity_filter.ProfanityFilter;
 ~ 
 
 > INSERT  1 : 2  @  1
 
 + 
 
-> INSERT  8 : 9  @  8
+> INSERT  8 : 10  @  8
 
++ import net.minecraft.client.Minecraft;
 + import net.minecraft.client.renderer.tileentity.TileEntityRendererDispatcher;
 
 > DELETE  6  @  6 : 9
@@ -36,7 +38,17 @@
 
 ~ 		this.rand = new EaglercraftRandom();
 
-> CHANGE  294 : 296  @  294 : 295
+> DELETE  100  @  100 : 101
+
+> DELETE  11  @  11 : 12
+
+> DELETE  32  @  32 : 34
+
+> DELETE  35  @  35 : 36
+
+> DELETE  44  @  44 : 45
+
+> CHANGE  66 : 68  @  66 : 67
 
 ~ 			List<AxisAlignedBB> list1 = this.worldObj.getCollidingBoundingBoxes(this,
 ~ 					this.getEntityBoundingBox().addCoord(x, y, z));
@@ -95,7 +107,11 @@
 ~ 				for (int i = 0, l = list.size(); i < l; ++i) {
 ~ 					y = list.get(i).calculateYOffset(this.getEntityBoundingBox(), y);
 
-> CHANGE  347 : 353  @  347 : 348
+> DELETE  11  @  11 : 13
+
+> DELETE  93  @  93 : 95
+
+> CHANGE  239 : 245  @  239 : 240
 
 ~ 		int i = 0;
 ~ 		if (DynamicLightsStateManager.isDynamicLightsRender()) {
@@ -135,15 +151,74 @@
 
 ~ 			for (AxisAlignedBB axisalignedbb : (List<AxisAlignedBB>) list) {
 
-> CHANGE  256 : 257  @  256 : 257
+> INSERT  229 : 242  @  229
+
++ 	public String getNameProfanityFilter() {
++ 		if (this.hasCustomName()) {
++ 			return this.getCustomNameTagProfanityFilter();
++ 		} else {
++ 			String s = EntityList.getEntityString(this);
++ 			if (s == null) {
++ 				s = "generic";
++ 			}
++ 
++ 			return StatCollector.translateToLocal("entity." + s + ".name");
++ 		}
++ 	}
++ 
+
+> CHANGE  27 : 28  @  27 : 28
 
 ~ 		return HString.format("%s[\'%s\'/%d, l=\'%s\', x=%.2f, y=%.2f, z=%.2f]",
 
-> CHANGE  121 : 122  @  121 : 122
+> DELETE  26  @  26 : 27
+
+> DELETE  12  @  12 : 13
+
+> DELETE  1  @  1 : 2
+
+> DELETE  12  @  12 : 13
+
+> DELETE  2  @  2 : 3
+
+> CHANGE  63 : 64  @  63 : 64
 
 ~ 	public EaglercraftUUID getUniqueID() {
 
-> INSERT  151 : 205  @  151
+> INSERT  14 : 21  @  14
+
++ 	public IChatComponent getDisplayNameProfanityFilter() {
++ 		ChatComponentText chatcomponenttext = new ChatComponentText(this.getNameProfanityFilter());
++ 		chatcomponenttext.getChatStyle().setChatHoverEvent(this.getHoverEvent());
++ 		chatcomponenttext.getChatStyle().setInsertion(this.getUniqueID().toString());
++ 		return chatcomponenttext;
++ 	}
++ 
+
+> INSERT  8 : 28  @  8
+
++ 	private String lastNameTagForFilter = null;
++ 	private String lastFilteredNameTagForFilter = null;
++ 
++ 	public String getCustomNameTagProfanityFilter() {
++ 		if (Minecraft.getMinecraft().isEnableProfanityFilter()) {
++ 			String str = getCustomNameTag();
++ 			if (str != null) {
++ 				if (!str.equals(lastNameTagForFilter)) {
++ 					lastNameTagForFilter = str;
++ 					lastFilteredNameTagForFilter = ProfanityFilter.getInstance().profanityFilterString(str);
++ 				}
++ 				return lastFilteredNameTagForFilter;
++ 			} else {
++ 				return null;
++ 			}
++ 		} else {
++ 			return getCustomNameTag();
++ 		}
++ 	}
++ 
+
+> INSERT  129 : 183  @  129
 
 + 
 + 	public void renderDynamicLightsEagler(float partialTicks, boolean isInFrustum) {
diff --git a/patches/minecraft/net/minecraft/entity/EntityLiving.edit.java b/patches/minecraft/net/minecraft/entity/EntityLiving.edit.java
index 2abff347..5860c561 100644
--- a/patches/minecraft/net/minecraft/entity/EntityLiving.edit.java
+++ b/patches/minecraft/net/minecraft/entity/EntityLiving.edit.java
@@ -13,14 +13,47 @@
 
 > DELETE  1  @  1 : 8
 
-> CHANGE  316 : 320  @  316 : 318
+> CHANGE  56 : 58  @  56 : 59
+
+~ 		this.tasks = new EntityAITasks();
+~ 		this.targetTasks = new EntityAITasks();
+
+> DELETE  76  @  76 : 77
+
+> DELETE  4  @  4 : 6
+
+> DELETE  171  @  171 : 172
+
+> CHANGE  2 : 6  @  2 : 4
 
 ~ 			List<EntityItem> lst = this.worldObj.getEntitiesWithinAABB(EntityItem.class,
 ~ 					this.getEntityBoundingBox().expand(1.0D, 0.0D, 1.0D));
 ~ 			for (int i = 0, l = lst.size(); i < l; ++i) {
 ~ 				EntityItem entityitem = lst.get(i);
 
-> CHANGE  497 : 499  @  497 : 498
+> DELETE  5  @  5 : 7
+
+> DELETE  98  @  98 : 99
+
+> DELETE  1  @  1 : 3
+
+> DELETE  1  @  1 : 3
+
+> DELETE  1  @  1 : 3
+
+> DELETE  1  @  1 : 3
+
+> DELETE  1  @  1 : 3
+
+> DELETE  1  @  1 : 4
+
+> DELETE  1  @  1 : 2
+
+> DELETE  1  @  1 : 2
+
+> DELETE  1  @  1 : 3
+
+> CHANGE  365 : 367  @  365 : 366
 
 ~ 				EaglercraftUUID uuid = new EaglercraftUUID(this.leashNBTTag.getLong("UUIDMost"),
 ~ 						this.leashNBTTag.getLong("UUIDLeast"));
diff --git a/patches/minecraft/net/minecraft/entity/EntityLivingBase.edit.java b/patches/minecraft/net/minecraft/entity/EntityLivingBase.edit.java
index a8491ab4..87a11157 100644
--- a/patches/minecraft/net/minecraft/entity/EntityLivingBase.edit.java
+++ b/patches/minecraft/net/minecraft/entity/EntityLivingBase.edit.java
@@ -25,7 +25,11 @@
 ~ 	private static final EaglercraftUUID sprintingSpeedBoostModifierUUID = EaglercraftUUID
 ~ 			.fromString("662A6B8D-DA3E-4C1C-8813-96EA6097278D");
 
-> CHANGE  264 : 265  @  264 : 265
+> DELETE  120  @  120 : 121
+
+> DELETE  88  @  88 : 89
+
+> CHANGE  54 : 55  @  54 : 55
 
 ~ 	public EaglercraftRandom getRNG() {
 
@@ -40,7 +44,27 @@
 ~ 		for (int i = 0; i < inv.length; ++i) {
 ~ 			ItemStack itemstack1 = inv[i];
 
-> INSERT  1254 : 1277  @  1254
+> DELETE  941  @  941 : 942
+
+> DELETE  1  @  1 : 3
+
+> DELETE  33  @  33 : 34
+
+> DELETE  62  @  62 : 63
+
+> DELETE  6  @  6 : 7
+
+> DELETE  1  @  1 : 2
+
+> DELETE  2  @  2 : 4
+
+> DELETE  13  @  13 : 15
+
+> DELETE  4  @  4 : 6
+
+> DELETE  3  @  3 : 5
+
+> INSERT  173 : 196  @  173
 
 + 
 + 	protected void renderDynamicLightsEaglerAt(double entityX, double entityY, double entityZ, double renderX,
@@ -59,7 +83,7 @@
 + 		if (itm != null && itm.stackSize > 0) {
 + 			Item item = itm.getItem();
 + 			if (item != null) {
-+ 				float f2 = item.getHeldItemBrightnessEagler();
++ 				float f2 = item.getHeldItemBrightnessEagler(itm);
 + 				f = Math.min(f + f2 * 0.5f, 1.0f) + f2 * 0.5f;
 + 			}
 + 		}
diff --git a/patches/minecraft/net/minecraft/entity/ai/EntityAITasks.edit.java b/patches/minecraft/net/minecraft/entity/ai/EntityAITasks.edit.java
index 9396d140..ff0dbb7c 100644
--- a/patches/minecraft/net/minecraft/entity/ai/EntityAITasks.edit.java
+++ b/patches/minecraft/net/minecraft/entity/ai/EntityAITasks.edit.java
@@ -5,19 +5,25 @@
 # Version: 1.0
 # Author: lax1dude
 
-> DELETE  5  @  5 : 6
-
-> CHANGE  1 : 3  @  1 : 3
+> CHANGE  5 : 7  @  5 : 9
 
 ~ import net.lax1dude.eaglercraft.v1_8.log4j.LogManager;
 ~ import net.lax1dude.eaglercraft.v1_8.log4j.Logger;
 
-> CHANGE  84 : 86  @  84 : 86
+> DELETE  5  @  5 : 6
+
+> DELETE  3  @  3 : 7
+
+> DELETE  24  @  24 : 25
+
+> CHANGE  43 : 45  @  43 : 48
 
 ~ 		for (int i = 0, l = this.executingTaskEntries.size(); i < l; ++i) {
 ~ 			this.executingTaskEntries.get(i).action.updateTask();
 
-> CHANGE  11 : 13  @  11 : 12
+> DELETE  1  @  1 : 3
+
+> CHANGE  8 : 10  @  8 : 9
 
 ~ 		for (int i = 0, l = this.taskEntries.size(); i < l; ++i) {
 ~ 			EntityAITasks.EntityAITaskEntry entityaitasks$entityaitaskentry = this.taskEntries.get(i);
diff --git a/patches/minecraft/net/minecraft/entity/ai/EntitySenses.edit.java b/patches/minecraft/net/minecraft/entity/ai/EntitySenses.edit.java
new file mode 100644
index 00000000..4c2454bc
--- /dev/null
+++ b/patches/minecraft/net/minecraft/entity/ai/EntitySenses.edit.java
@@ -0,0 +1,12 @@
+
+# Eagler Context Redacted Diff
+# Copyright (c) 2024 lax1dude. All rights reserved.
+
+# Version: 1.0
+# Author: lax1dude
+
+> DELETE  27  @  27 : 28
+
+> DELETE  1  @  1 : 2
+
+> EOF
diff --git a/patches/minecraft/net/minecraft/entity/item/EntityItem.edit.java b/patches/minecraft/net/minecraft/entity/item/EntityItem.edit.java
index 05f4831a..ddd7664b 100644
--- a/patches/minecraft/net/minecraft/entity/item/EntityItem.edit.java
+++ b/patches/minecraft/net/minecraft/entity/item/EntityItem.edit.java
@@ -43,7 +43,7 @@
 + 		if (itm != null && itm.stackSize > 0) {
 + 			Item item = itm.getItem();
 + 			if (item != null) {
-+ 				float f2 = item.getHeldItemBrightnessEagler() * 0.75f;
++ 				float f2 = item.getHeldItemBrightnessEagler(itm) * 0.75f;
 + 				f = Math.min(f + f2 * 0.5f, 1.0f) + f2 * 0.5f;
 + 			}
 + 		}
diff --git a/patches/minecraft/net/minecraft/entity/item/EntityItemFrame.edit.java b/patches/minecraft/net/minecraft/entity/item/EntityItemFrame.edit.java
index d391f9b2..1f829a95 100644
--- a/patches/minecraft/net/minecraft/entity/item/EntityItemFrame.edit.java
+++ b/patches/minecraft/net/minecraft/entity/item/EntityItemFrame.edit.java
@@ -31,7 +31,7 @@
 + 		if (itm != null && itm.stackSize > 0) {
 + 			Item item = itm.getItem();
 + 			if (item != null) {
-+ 				float f2 = item.getHeldItemBrightnessEagler() * 0.75f;
++ 				float f2 = item.getHeldItemBrightnessEagler(itm) * 0.75f;
 + 				f = Math.min(f + f2 * 0.5f, 1.0f) + f2 * 0.5f;
 + 			}
 + 		}
diff --git a/patches/minecraft/net/minecraft/entity/item/EntityMinecart.edit.java b/patches/minecraft/net/minecraft/entity/item/EntityMinecart.edit.java
index 99531860..cab34da0 100644
--- a/patches/minecraft/net/minecraft/entity/item/EntityMinecart.edit.java
+++ b/patches/minecraft/net/minecraft/entity/item/EntityMinecart.edit.java
@@ -25,14 +25,32 @@
 ~ 		this.dataWatcher.addObject(20, Integer.valueOf(0));
 ~ 		this.dataWatcher.addObject(21, Integer.valueOf(6));
 
-> CHANGE  198 : 202  @  198 : 200
+> DELETE  101  @  101 : 102
+
+> DELETE  32  @  32 : 34
+
+> CHANGE  62 : 66  @  62 : 64
 
 ~ 			List<Entity> lst = this.worldObj.getEntitiesWithinAABBExcludingEntity(this,
 ~ 					this.getEntityBoundingBox().expand(0.20000000298023224D, 0.0D, 0.20000000298023224D));
 ~ 			for (int i = 0, m = lst.size(); i < m; ++i) {
 ~ 				Entity entity = lst.get(i);
 
-> CHANGE  585 : 588  @  585 : 588
+> INSERT  533 : 537  @  533
+
++ 	public String getNameProfanityFilter() {
++ 		return getName();
++ 	}
++ 
+
+> INSERT  23 : 27  @  23
+
++ 	public IChatComponent getDisplayNameProfanityFilter() {
++ 		return getDisplayName();
++ 	}
++ 
+
+> CHANGE  29 : 32  @  29 : 32
 
 ~ 			EntityMinecart.EnumMinecartType[] types = values();
 ~ 			for (int i = 0; i < types.length; ++i) {
diff --git a/patches/minecraft/net/minecraft/entity/passive/EntityHorse.edit.java b/patches/minecraft/net/minecraft/entity/passive/EntityHorse.edit.java
index 4778f2d5..1bc3f89b 100644
--- a/patches/minecraft/net/minecraft/entity/passive/EntityHorse.edit.java
+++ b/patches/minecraft/net/minecraft/entity/passive/EntityHorse.edit.java
@@ -19,7 +19,22 @@
 
 > DELETE  12  @  12 : 13
 
-> CHANGE  381 : 385  @  381 : 383
+> INSERT  99 : 107  @  99
+
++ 		return getNameImpl(false);
++ 	}
++ 
++ 	public String getNameProfanityFilter() {
++ 		return getNameImpl(true);
++ 	}
++ 
++ 	private String getNameImpl(boolean filter) {
+
+> CHANGE  1 : 2  @  1 : 2
+
+~ 			return filter ? this.getCustomNameTagProfanityFilter() : this.getCustomNameTag();
+
+> CHANGE  280 : 284  @  280 : 282
 
 ~ 		List<Entity> lst = this.worldObj.getEntitiesInAABBexcluding(entityIn,
 ~ 				entityIn.getEntityBoundingBox().addCoord(distance, distance, distance), horseBreedingSelector);
diff --git a/patches/minecraft/net/minecraft/entity/passive/EntityOcelot.edit.java b/patches/minecraft/net/minecraft/entity/passive/EntityOcelot.edit.java
index c0a52cd2..76e70e8b 100644
--- a/patches/minecraft/net/minecraft/entity/passive/EntityOcelot.edit.java
+++ b/patches/minecraft/net/minecraft/entity/passive/EntityOcelot.edit.java
@@ -7,4 +7,21 @@
 
 > DELETE  20  @  20 : 23
 
+> CHANGE  215 : 216  @  215 : 217
+
+~ 		return getNameImpl(false);
+
+> INSERT  2 : 12  @  2
+
++ 	public String getNameProfanityFilter() {
++ 		return getNameImpl(true);
++ 	}
++ 
++ 	private String getNameImpl(boolean filter) {
++ 		return this.hasCustomName() ? (filter ? this.getCustomNameTagProfanityFilter() : this.getCustomNameTag())
++ 				: (this.isTamed() ? StatCollector.translateToLocal("entity.Cat.name")
++ 						: (filter ? super.getNameProfanityFilter() : super.getName()));
++ 	}
++ 
+
 > EOF
diff --git a/patches/minecraft/net/minecraft/entity/passive/EntityTameable.edit.java b/patches/minecraft/net/minecraft/entity/passive/EntityTameable.edit.java
index e741155e..cd234599 100644
--- a/patches/minecraft/net/minecraft/entity/passive/EntityTameable.edit.java
+++ b/patches/minecraft/net/minecraft/entity/passive/EntityTameable.edit.java
@@ -5,8 +5,10 @@
 # Version: 1.0
 # Author: lax1dude
 
-> CHANGE  2 : 4  @  2 : 3
+> CHANGE  2 : 6  @  2 : 3
 
+~ import org.apache.commons.lang3.StringUtils;
+~ 
 ~ import net.lax1dude.eaglercraft.v1_8.EaglercraftUUID;
 ~ import net.lax1dude.eaglercraft.v1_8.sp.SingleplayerServerController;
 
@@ -48,8 +50,19 @@
 ~ 				s = nbttagcompound.getString("Owner");
 ~ 			}
 
-> CHANGE  83 : 84  @  83 : 84
+> INSERT  82 : 86  @  82
 
-~ 			EaglercraftUUID uuid = EaglercraftUUID.fromString(this.getOwnerId());
++ 		String ownerName = this.getOwnerId();
++ 		if (StringUtils.isEmpty(ownerName)) {
++ 			return null;
++ 		}
+
+> CHANGE  1 : 2  @  1 : 2
+
+~ 			EaglercraftUUID uuid = EaglercraftUUID.fromString(ownerName);
+
+> CHANGE  2 : 3  @  2 : 3
+
+~ 			return this.worldObj.getPlayerEntityByName(ownerName);
 
 > EOF
diff --git a/patches/minecraft/net/minecraft/entity/passive/EntityVillager.edit.java b/patches/minecraft/net/minecraft/entity/passive/EntityVillager.edit.java
index 5f1f0f9b..731fb6f6 100644
--- a/patches/minecraft/net/minecraft/entity/passive/EntityVillager.edit.java
+++ b/patches/minecraft/net/minecraft/entity/passive/EntityVillager.edit.java
@@ -257,7 +257,23 @@
 ~ 			for (int k = 0, l = aentityvillager$itradelist2.size(); k < l; ++k) {
 ~ 				aentityvillager$itradelist2.get(k).modifyMerchantRecipeList(this.buyingList, this.rand);
 
-> CHANGE  236 : 237  @  236 : 237
+> CHANGE  9 : 18  @  9 : 10
+
+~ 		return getDisplayNameImpl(false);
+~ 	}
+~ 
+~ 	public IChatComponent getDisplayNameProfanityFilter() {
+~ 		return getDisplayNameImpl(true);
+~ 	}
+~ 
+~ 	private IChatComponent getDisplayNameImpl(boolean filter) {
+~ 		String s = filter ? this.getCustomNameTagProfanityFilter() : this.getCustomNameTag();
+
+> CHANGE  53 : 54  @  53 : 54
+
+~ 				return filter ? super.getDisplayNameProfanityFilter() : super.getDisplayName();
+
+> CHANGE  172 : 173  @  172 : 173
 
 ~ 		public void modifyMerchantRecipeList(MerchantRecipeList recipeList, EaglercraftRandom random) {
 
diff --git a/patches/minecraft/net/minecraft/entity/player/EntityPlayer.edit.java b/patches/minecraft/net/minecraft/entity/player/EntityPlayer.edit.java
index b7ffecdf..dade11d8 100644
--- a/patches/minecraft/net/minecraft/entity/player/EntityPlayer.edit.java
+++ b/patches/minecraft/net/minecraft/entity/player/EntityPlayer.edit.java
@@ -24,7 +24,19 @@
 
 ~ public abstract class EntityPlayer extends EntityLivingBase implements ICommandSender {
 
-> CHANGE  458 : 459  @  458 : 459
+> INSERT  77 : 86  @  77
+
++ 	public boolean getItemShouldUseOnTouchEagler() {
++ 		if (itemInUse != null) {
++ 			return itemInUse.getItem().shouldUseOnTouchEagler(itemInUse);
++ 		} else {
++ 			ItemStack st = getHeldItem();
++ 			return st != null && st.getItem().shouldUseOnTouchEagler(st);
++ 		}
++ 	}
++ 
+
+> CHANGE  381 : 382  @  381 : 382
 
 ~ 		Collection<ScoreObjective> collection = this.getWorldScoreboard()
 
diff --git a/patches/minecraft/net/minecraft/entity/player/EntityPlayerMP.edit.java b/patches/minecraft/net/minecraft/entity/player/EntityPlayerMP.edit.java
index 7afbaf13..8963e4d2 100644
--- a/patches/minecraft/net/minecraft/entity/player/EntityPlayerMP.edit.java
+++ b/patches/minecraft/net/minecraft/entity/player/EntityPlayerMP.edit.java
@@ -14,8 +14,10 @@
 
 > DELETE  51  @  51 : 52
 
-> CHANGE  22 : 24  @  22 : 24
+> CHANGE  22 : 26  @  22 : 24
 
+~ import net.lax1dude.eaglercraft.v1_8.EagRuntime;
+~ import net.lax1dude.eaglercraft.v1_8.EaglercraftUUID;
 ~ import net.lax1dude.eaglercraft.v1_8.log4j.LogManager;
 ~ import net.lax1dude.eaglercraft.v1_8.log4j.Logger;
 
@@ -23,9 +25,14 @@
 
 + 
 
-> INSERT  24 : 25  @  24
+> CHANGE  18 : 19  @  18 : 19
+
+~ 	private long playerLastActiveTime = EagRuntime.steadyTimeMillis();
+
+> INSERT  5 : 7  @  5
 
 + 	public byte[] updateCertificate = null;
++ 	public EaglercraftUUID clientBrandUUID = null;
 
 > CHANGE  87 : 88  @  87 : 88
 
diff --git a/patches/minecraft/net/minecraft/item/Item.edit.java b/patches/minecraft/net/minecraft/item/Item.edit.java
index d0f520c0..b0c1e92d 100644
--- a/patches/minecraft/net/minecraft/item/Item.edit.java
+++ b/patches/minecraft/net/minecraft/item/Item.edit.java
@@ -28,11 +28,15 @@
 
 ~ 	protected static EaglercraftRandom itemRand = new EaglercraftRandom();
 
-> INSERT  884 : 888  @  884
+> INSERT  884 : 892  @  884
 
 + 
-+ 	public float getHeldItemBrightnessEagler() {
++ 	public float getHeldItemBrightnessEagler(ItemStack itemStack) {
 + 		return 0.0f;
 + 	}
++ 
++ 	public boolean shouldUseOnTouchEagler(ItemStack itemStack) {
++ 		return getItemUseAction(itemStack) != EnumAction.NONE;
++ 	}
 
 > EOF
diff --git a/patches/minecraft/net/minecraft/item/ItemBlock.edit.java b/patches/minecraft/net/minecraft/item/ItemBlock.edit.java
index 262e5986..34701ff2 100644
--- a/patches/minecraft/net/minecraft/item/ItemBlock.edit.java
+++ b/patches/minecraft/net/minecraft/item/ItemBlock.edit.java
@@ -10,7 +10,7 @@
 > INSERT  120 : 124  @  120
 
 + 
-+ 	public float getHeldItemBrightnessEagler() {
++ 	public float getHeldItemBrightnessEagler(ItemStack itemStack) {
 + 		return this.block.getLightValue() * 0.06667f;
 + 	}
 
diff --git a/patches/minecraft/net/minecraft/item/ItemEgg.edit.java b/patches/minecraft/net/minecraft/item/ItemEgg.edit.java
index 41da09fc..e49d647d 100644
--- a/patches/minecraft/net/minecraft/item/ItemEgg.edit.java
+++ b/patches/minecraft/net/minecraft/item/ItemEgg.edit.java
@@ -7,4 +7,11 @@
 
 > DELETE  5  @  5 : 7
 
+> INSERT  22 : 26  @  22
+
++ 
++ 	public boolean shouldUseOnTouchEagler(ItemStack itemStack) {
++ 		return true;
++ 	}
+
 > EOF
diff --git a/patches/minecraft/net/minecraft/item/ItemEnderEye.edit.java b/patches/minecraft/net/minecraft/item/ItemEnderEye.edit.java
index b723c560..97f5521b 100644
--- a/patches/minecraft/net/minecraft/item/ItemEnderEye.edit.java
+++ b/patches/minecraft/net/minecraft/item/ItemEnderEye.edit.java
@@ -7,4 +7,11 @@
 
 > DELETE  8  @  8 : 10
 
+> INSERT  134 : 138  @  134
+
++ 
++ 	public boolean shouldUseOnTouchEagler(ItemStack itemStack) {
++ 		return true;
++ 	}
+
 > EOF
diff --git a/patches/minecraft/net/minecraft/item/ItemEnderPearl.edit.java b/patches/minecraft/net/minecraft/item/ItemEnderPearl.edit.java
index c8d222df..76ddab46 100644
--- a/patches/minecraft/net/minecraft/item/ItemEnderPearl.edit.java
+++ b/patches/minecraft/net/minecraft/item/ItemEnderPearl.edit.java
@@ -22,4 +22,11 @@
 ~ 				--itemstack.stackSize;
 ~ 			}
 
+> INSERT  9 : 13  @  9
+
++ 
++ 	public boolean shouldUseOnTouchEagler(ItemStack itemStack) {
++ 		return true;
++ 	}
+
 > EOF
diff --git a/patches/minecraft/net/minecraft/item/ItemExpBottle.edit.java b/patches/minecraft/net/minecraft/item/ItemExpBottle.edit.java
index 41da09fc..85734f1c 100644
--- a/patches/minecraft/net/minecraft/item/ItemExpBottle.edit.java
+++ b/patches/minecraft/net/minecraft/item/ItemExpBottle.edit.java
@@ -7,4 +7,11 @@
 
 > DELETE  5  @  5 : 7
 
+> INSERT  25 : 29  @  25
+
++ 
++ 	public boolean shouldUseOnTouchEagler(ItemStack itemStack) {
++ 		return true;
++ 	}
+
 > EOF
diff --git a/patches/minecraft/net/minecraft/item/ItemFirework.edit.java b/patches/minecraft/net/minecraft/item/ItemFirework.edit.java
index a2b2fd67..f9c9b4d7 100644
--- a/patches/minecraft/net/minecraft/item/ItemFirework.edit.java
+++ b/patches/minecraft/net/minecraft/item/ItemFirework.edit.java
@@ -11,4 +11,11 @@
 
 + 
 
+> INSERT  45 : 49  @  45
+
++ 
++ 	public boolean shouldUseOnTouchEagler(ItemStack itemStack) {
++ 		return true;
++ 	}
+
 > EOF
diff --git a/patches/minecraft/net/minecraft/item/ItemSnowball.edit.java b/patches/minecraft/net/minecraft/item/ItemSnowball.edit.java
index 41da09fc..e49d647d 100644
--- a/patches/minecraft/net/minecraft/item/ItemSnowball.edit.java
+++ b/patches/minecraft/net/minecraft/item/ItemSnowball.edit.java
@@ -7,4 +7,11 @@
 
 > DELETE  5  @  5 : 7
 
+> INSERT  22 : 26  @  22
+
++ 
++ 	public boolean shouldUseOnTouchEagler(ItemStack itemStack) {
++ 		return true;
++ 	}
+
 > EOF
diff --git a/patches/minecraft/net/minecraft/item/ItemStack.edit.java b/patches/minecraft/net/minecraft/item/ItemStack.edit.java
index a616fd58..2133a4c1 100644
--- a/patches/minecraft/net/minecraft/item/ItemStack.edit.java
+++ b/patches/minecraft/net/minecraft/item/ItemStack.edit.java
@@ -9,10 +9,12 @@
 
 > DELETE  3  @  3 : 4
 
-> INSERT  1 : 9  @  1
+> INSERT  1 : 11  @  1
 
 + import net.lax1dude.eaglercraft.v1_8.EaglercraftRandom;
 + import net.lax1dude.eaglercraft.v1_8.HString;
++ import net.lax1dude.eaglercraft.v1_8.profanity_filter.ProfanityFilter;
++ 
 + import java.util.Set;
 + 
 + import com.google.common.collect.HashMultimap;
@@ -20,13 +22,61 @@
 + import com.google.common.collect.Multimap;
 + 
 
-> DELETE  13  @  13 : 17
+> INSERT  1 : 2  @  1
 
-> CHANGE  185 : 186  @  185 : 186
++ import net.minecraft.client.Minecraft;
+
+> DELETE  12  @  12 : 16
+
+> INSERT  19 : 21  @  19
+
++ 	private String profanityFilteredName;
++ 	private String profanityFilteredNameFiltered;
+
+> CHANGE  166 : 167  @  166 : 167
 
 ~ 	public boolean attemptDamageItem(int amount, EaglercraftRandom rand) {
 
-> CHANGE  249 : 250  @  249 : 250
+> INSERT  197 : 218  @  197
+
++ 	public String getDisplayNameProfanityFilter() {
++ 		String s = this.getItem().getItemStackDisplayName(this);
++ 		if (this.stackTagCompound != null && this.stackTagCompound.hasKey("display", 10)) {
++ 			NBTTagCompound nbttagcompound = this.stackTagCompound.getCompoundTag("display");
++ 			if (nbttagcompound.hasKey("Name", 8)) {
++ 				s = nbttagcompound.getString("Name");
++ 				if (Minecraft.getMinecraft().isEnableProfanityFilter()) {
++ 					if (!s.equals(profanityFilteredName)) {
++ 						profanityFilteredName = s;
++ 						profanityFilteredNameFiltered = ProfanityFilter.getInstance().profanityFilterString(s);
++ 					}
++ 					if (profanityFilteredNameFiltered != null) {
++ 						s = profanityFilteredNameFiltered;
++ 					}
++ 				}
++ 			}
++ 		}
++ 
++ 		return s;
++ 	}
++ 
+
+> INSERT  36 : 44  @  36
+
++ 		return getTooltipImpl(playerIn, advanced, false);
++ 	}
++ 
++ 	public List<String> getTooltipProfanityFilter(EntityPlayer playerIn, boolean advanced) {
++ 		return getTooltipImpl(playerIn, advanced, true);
++ 	}
++ 
++ 	public List<String> getTooltipImpl(EntityPlayer playerIn, boolean advanced, boolean profanityFilter) {
+
+> CHANGE  1 : 2  @  1 : 2
+
+~ 		String s = profanityFilter ? this.getDisplayNameProfanityFilter() : this.getDisplayName();
+
+> CHANGE  14 : 15  @  14 : 15
 
 ~ 				s = s + HString.format("#%04d/%d%s",
 
diff --git a/patches/minecraft/net/minecraft/network/NetHandlerPlayServer.edit.java b/patches/minecraft/net/minecraft/network/NetHandlerPlayServer.edit.java
index be1699a0..63c6b730 100644
--- a/patches/minecraft/net/minecraft/network/NetHandlerPlayServer.edit.java
+++ b/patches/minecraft/net/minecraft/network/NetHandlerPlayServer.edit.java
@@ -5,56 +5,94 @@
 # Version: 1.0
 # Author: lax1dude
 
-> CHANGE  5 : 6  @  5 : 9
+> CHANGE  5 : 10  @  5 : 9
 
-~ import net.lax1dude.eaglercraft.v1_8.netty.Unpooled;
+~ import net.lax1dude.eaglercraft.v1_8.socket.protocol.GamePluginMessageProtocol;
+~ import net.lax1dude.eaglercraft.v1_8.socket.protocol.client.GameProtocolMessageController;
+~ import net.lax1dude.eaglercraft.v1_8.socket.protocol.pkt.GameMessagePacket;
+~ import net.lax1dude.eaglercraft.v1_8.socket.protocol.pkt.server.SPacketUpdateCertEAG;
+~ 
 
 > CHANGE  3 : 4  @  3 : 4
 
 ~ import java.util.List;
 
-> INSERT  2 : 4  @  2
-
-+ 
-+ import net.lax1dude.eaglercraft.v1_8.sp.server.EaglerMinecraftServer;
-
-> DELETE  25  @  25 : 29
-
-> INSERT  33 : 34  @  33
-
-+ import net.minecraft.network.play.server.S3FPacketCustomPayload;
-
-> DELETE  2  @  2 : 3
-
-> INSERT  16 : 19  @  16
-
-+ import net.lax1dude.eaglercraft.v1_8.sp.server.socket.IntegratedServerPlayerNetworkManager;
-+ import net.lax1dude.eaglercraft.v1_8.sp.server.voice.IntegratedVoiceService;
-+ 
-
-> CHANGE  1 : 3  @  1 : 3
-
-~ import net.lax1dude.eaglercraft.v1_8.log4j.LogManager;
-~ import net.lax1dude.eaglercraft.v1_8.log4j.Logger;
-
 > INSERT  2 : 3  @  2
 
 + 
 
-> CHANGE  1 : 2  @  1 : 2
+> DELETE  25  @  25 : 29
+
+> DELETE  35  @  35 : 36
+
+> INSERT  16 : 18  @  16
+
++ import net.lax1dude.eaglercraft.v1_8.sp.server.socket.IntegratedServerPlayerNetworkManager;
++ 
+
+> DELETE  1  @  1 : 3
+
+> INSERT  1 : 5  @  1
+
++ import net.lax1dude.eaglercraft.v1_8.EagRuntime;
++ import net.lax1dude.eaglercraft.v1_8.log4j.LogManager;
++ import net.lax1dude.eaglercraft.v1_8.log4j.Logger;
++ 
+
+> INSERT  1 : 2  @  1
+
++ 
+
+> CHANGE  1 : 3  @  1 : 3
 
 ~ 	public final IntegratedServerPlayerNetworkManager netManager;
+~ 	public final MinecraftServer serverController;
 
-> INSERT  16 : 17  @  16
+> INSERT  15 : 17  @  15
 
 + 	private boolean hasDisconnected = false;
++ 	private GameProtocolMessageController eaglerMessageController = null;
 
 > CHANGE  1 : 3  @  1 : 2
 
 ~ 	public NetHandlerPlayServer(MinecraftServer server, IntegratedServerPlayerNetworkManager networkManagerIn,
 ~ 			EntityPlayerMP playerIn) {
 
-> CHANGE  35 : 36  @  35 : 36
+> INSERT  7 : 28  @  7
+
++ 	public GameProtocolMessageController getEaglerMessageController() {
++ 		return eaglerMessageController;
++ 	}
++ 
++ 	public void setEaglerMessageController(GameProtocolMessageController eaglerMessageController) {
++ 		this.eaglerMessageController = eaglerMessageController;
++ 	}
++ 
++ 	public GamePluginMessageProtocol getEaglerMessageProtocol() {
++ 		return eaglerMessageController != null ? eaglerMessageController.protocol : null;
++ 	}
++ 
++ 	public void sendEaglerMessage(GameMessagePacket packet) {
++ 		try {
++ 			eaglerMessageController.sendPacket(packet);
++ 		} catch (IOException e) {
++ 			logger.error("Failed to send eaglercraft plugin message packet: " + packet);
++ 			logger.error(e);
++ 		}
++ 	}
++ 
+
+> DELETE  3  @  3 : 4
+
+> DELETE  7  @  7 : 8
+
+> INSERT  14 : 17  @  14
+
++ 		if (this.eaglerMessageController != null) {
++ 			this.eaglerMessageController.flush();
++ 		}
+
+> CHANGE  2 : 3  @  2 : 3
 
 ~ 	public IntegratedServerPlayerNetworkManager getNetworkManager() {
 
@@ -140,7 +178,11 @@
 ~ 				}
 ~ 				tileentitysign.signText[i] = new ChatComponentText(s);
 
-> DELETE  21  @  21 : 22
+> CHANGE  17 : 18  @  17 : 18
+
+~ 		return EagRuntime.steadyTimeMillis();
+
+> DELETE  3  @  3 : 4
 
 > CHANGE  5 : 10  @  5 : 11
 
@@ -187,21 +229,8 @@
 + 						s = net.minecraft.util.StringUtils.translateControlCodesAlternate(s);
 + 					}
 
-> INSERT  5 : 33  @  5
+> INSERT  5 : 28  @  5
 
-+ 		} else if ("EAG|Skins-1.8".equals(c17packetcustompayload.getChannelName())) {
-+ 			byte[] r = new byte[c17packetcustompayload.getBufferData().readableBytes()];
-+ 			c17packetcustompayload.getBufferData().readBytes(r);
-+ 			((EaglerMinecraftServer) serverController).getSkinService().processPacket(r, playerEntity);
-+ 		} else if ("EAG|Capes-1.8".equals(c17packetcustompayload.getChannelName())) {
-+ 			byte[] r = new byte[c17packetcustompayload.getBufferData().readableBytes()];
-+ 			c17packetcustompayload.getBufferData().readBytes(r);
-+ 			((EaglerMinecraftServer) serverController).getCapeService().processPacket(r, playerEntity);
-+ 		} else if ("EAG|Voice-1.8".equals(c17packetcustompayload.getChannelName())) {
-+ 			IntegratedVoiceService vcs = ((EaglerMinecraftServer) serverController).getVoiceService();
-+ 			if (vcs != null) {
-+ 				vcs.processPacket(c17packetcustompayload.getBufferData(), playerEntity);
-+ 			}
 + 		} else if ("EAG|MyUpdCert-1.8".equals(c17packetcustompayload.getChannelName())) {
 + 			if (playerEntity.updateCertificate == null) {
 + 				PacketBuffer pb = c17packetcustompayload.getBufferData();
@@ -212,11 +241,19 @@
 + 				for (int i = 0, l = lst.size(); i < l; ++i) {
 + 					EntityPlayerMP player = lst.get(i);
 + 					if (player != playerEntity) {
-+ 						player.playerNetServerHandler.sendPacket(new S3FPacketCustomPayload("EAG|UpdateCert-1.8",
-+ 								new PacketBuffer(Unpooled.buffer(cert, cert.length).writerIndex(cert.length))));
++ 						player.playerNetServerHandler.sendEaglerMessage(new SPacketUpdateCertEAG(cert));
 + 					}
 + 				}
 + 			}
++ 		} else {
++ 			try {
++ 				eaglerMessageController.handlePacket(c17packetcustompayload.getChannelName(),
++ 						c17packetcustompayload.getBufferData());
++ 			} catch (IOException e) {
++ 				logger.error("Couldn't read \"{}\" packet as an eaglercraft plugin message!",
++ 						c17packetcustompayload.getChannelName());
++ 				logger.error(e);
++ 			}
 
 > DELETE  1  @  1 : 2
 
diff --git a/patches/minecraft/net/minecraft/network/login/client/C00PacketLoginStart.edit.java b/patches/minecraft/net/minecraft/network/login/client/C00PacketLoginStart.edit.java
index 2bcf0dd6..f45ef6a7 100644
--- a/patches/minecraft/net/minecraft/network/login/client/C00PacketLoginStart.edit.java
+++ b/patches/minecraft/net/minecraft/network/login/client/C00PacketLoginStart.edit.java
@@ -13,32 +13,41 @@
 
 ~ import net.lax1dude.eaglercraft.v1_8.EaglercraftUUID;
 
-> INSERT  6 : 8  @  6
+> INSERT  6 : 10  @  6
 
 + 	private byte[] skin;
 + 	private byte[] cape;
++ 	private byte[] protocols;
++ 	private EaglercraftUUID brandUUID;
 
-> CHANGE  4 : 5  @  4 : 5
+> CHANGE  4 : 6  @  4 : 5
 
-~ 	public C00PacketLoginStart(GameProfile profileIn, byte[] skin, byte[] cape) {
+~ 	public C00PacketLoginStart(GameProfile profileIn, byte[] skin, byte[] cape, byte[] protocols,
+~ 			EaglercraftUUID brandUUID) {
 
-> INSERT  1 : 3  @  1
+> INSERT  1 : 5  @  1
 
 + 		this.skin = skin;
 + 		this.cape = cape;
++ 		this.protocols = protocols;
++ 		this.brandUUID = brandUUID;
 
-> CHANGE  3 : 6  @  3 : 4
+> CHANGE  3 : 8  @  3 : 4
 
 ~ 		this.profile = new GameProfile((EaglercraftUUID) null, parPacketBuffer.readStringFromBuffer(16));
 ~ 		this.skin = parPacketBuffer.readByteArray();
 ~ 		this.cape = parPacketBuffer.readableBytes() > 0 ? parPacketBuffer.readByteArray() : null;
+~ 		this.protocols = parPacketBuffer.readableBytes() > 0 ? parPacketBuffer.readByteArray() : null;
+~ 		this.brandUUID = parPacketBuffer.readableBytes() > 0 ? parPacketBuffer.readUuid() : null;
 
-> INSERT  4 : 6  @  4
+> INSERT  4 : 8  @  4
 
 + 		parPacketBuffer.writeByteArray(this.skin);
 + 		parPacketBuffer.writeByteArray(this.cape);
++ 		parPacketBuffer.writeByteArray(this.protocols);
++ 		parPacketBuffer.writeUuid(brandUUID);
 
-> INSERT  9 : 17  @  9
+> INSERT  9 : 25  @  9
 
 + 
 + 	public byte[] getSkin() {
@@ -48,5 +57,13 @@
 + 	public byte[] getCape() {
 + 		return this.cape;
 + 	}
++ 
++ 	public byte[] getProtocols() {
++ 		return this.protocols;
++ 	}
++ 
++ 	public EaglercraftUUID getBrandUUID() {
++ 		return this.brandUUID;
++ 	}
 
 > EOF
diff --git a/patches/minecraft/net/minecraft/network/login/server/S02PacketLoginSuccess.edit.java b/patches/minecraft/net/minecraft/network/login/server/S02PacketLoginSuccess.edit.java
index 1d6e01eb..4893bd47 100644
--- a/patches/minecraft/net/minecraft/network/login/server/S02PacketLoginSuccess.edit.java
+++ b/patches/minecraft/net/minecraft/network/login/server/S02PacketLoginSuccess.edit.java
@@ -13,12 +13,38 @@
 ~ 
 ~ import net.lax1dude.eaglercraft.v1_8.mojang.authlib.GameProfile;
 
-> CHANGE  17 : 18  @  17 : 18
+> INSERT  6 : 7  @  6
 
++ 	private int selectedProtocol = 3;
+
+> CHANGE  4 : 5  @  4 : 5
+
+~ 	public S02PacketLoginSuccess(GameProfile profileIn, int selectedProtocol) {
+
+> INSERT  1 : 2  @  1
+
++ 		this.selectedProtocol = selectedProtocol;
+
+> CHANGE  5 : 7  @  5 : 6
+
+~ 		selectedProtocol = parPacketBuffer.readableBytes() > 0 ? parPacketBuffer.readShort() : 3;
 ~ 		EaglercraftUUID uuid = EaglercraftUUID.fromString(s);
 
 > CHANGE  4 : 5  @  4 : 5
 
 ~ 		EaglercraftUUID uuid = this.profile.getId();
 
+> INSERT  2 : 5  @  2
+
++ 		if (selectedProtocol != 3) {
++ 			parPacketBuffer.writeShort(selectedProtocol);
++ 		}
+
+> INSERT  9 : 13  @  9
+
++ 
++ 	public int getSelectedProtocol() {
++ 		return selectedProtocol;
++ 	}
+
 > EOF
diff --git a/patches/minecraft/net/minecraft/pathfinding/PathNavigate.edit.java b/patches/minecraft/net/minecraft/pathfinding/PathNavigate.edit.java
index eb2d4efd..f3e387b1 100644
--- a/patches/minecraft/net/minecraft/pathfinding/PathNavigate.edit.java
+++ b/patches/minecraft/net/minecraft/pathfinding/PathNavigate.edit.java
@@ -7,7 +7,15 @@
 
 > DELETE  7  @  7 : 9
 
-> CHANGE  134 : 135  @  134 : 135
+> DELETE  45  @  45 : 46
+
+> DELETE  4  @  4 : 5
+
+> DELETE  19  @  19 : 20
+
+> DELETE  5  @  5 : 6
+
+> CHANGE  57 : 58  @  57 : 58
 
 ~ 					List<AxisAlignedBB> list = this.worldObj.getCollidingBoundingBoxes(this.theEntity,
 
diff --git a/patches/minecraft/net/minecraft/profiler/Profiler.edit.java b/patches/minecraft/net/minecraft/profiler/Profiler.edit.java
deleted file mode 100644
index c8bfb9d9..00000000
--- a/patches/minecraft/net/minecraft/profiler/Profiler.edit.java
+++ /dev/null
@@ -1,21 +0,0 @@
-
-# Eagler Context Redacted Diff
-# Copyright (c) 2024 lax1dude. All rights reserved.
-
-# Version: 1.0
-# Author: lax1dude
-
-> DELETE  2  @  2 : 4
-
-> DELETE  4  @  4 : 6
-
-> INSERT  1 : 7  @  1
-
-+ import com.google.common.collect.Lists;
-+ import com.google.common.collect.Maps;
-+ 
-+ import net.lax1dude.eaglercraft.v1_8.log4j.LogManager;
-+ import net.lax1dude.eaglercraft.v1_8.log4j.Logger;
-+ 
-
-> EOF
diff --git a/patches/minecraft/net/minecraft/scoreboard/ScoreObjective.edit.java b/patches/minecraft/net/minecraft/scoreboard/ScoreObjective.edit.java
index 0c659788..791e0c67 100644
--- a/patches/minecraft/net/minecraft/scoreboard/ScoreObjective.edit.java
+++ b/patches/minecraft/net/minecraft/scoreboard/ScoreObjective.edit.java
@@ -5,6 +5,27 @@
 # Version: 1.0
 # Author: lax1dude
 
-> DELETE  2  @  2 : 5
+> CHANGE  2 : 4  @  2 : 4
+
+~ import net.lax1dude.eaglercraft.v1_8.profanity_filter.ProfanityFilter;
+~ import net.minecraft.client.Minecraft;
+
+> INSERT  7 : 8  @  7
+
++ 	private String displayNameProfanityFilter;
+
+> INSERT  25 : 36  @  25
+
++ 	public String getDisplayNameProfanityFilter() {
++ 		if (Minecraft.getMinecraft().isEnableProfanityFilter()) {
++ 			if (displayNameProfanityFilter == null) {
++ 				displayNameProfanityFilter = ProfanityFilter.getInstance().profanityFilterString(displayName);
++ 			}
++ 			return displayNameProfanityFilter;
++ 		} else {
++ 			return this.displayName;
++ 		}
++ 	}
++ 
 
 > EOF
diff --git a/patches/minecraft/net/minecraft/server/MinecraftServer.edit.java b/patches/minecraft/net/minecraft/server/MinecraftServer.edit.java
index a5f3a732..dbf2e050 100644
--- a/patches/minecraft/net/minecraft/server/MinecraftServer.edit.java
+++ b/patches/minecraft/net/minecraft/server/MinecraftServer.edit.java
@@ -20,9 +20,10 @@
 
 > DELETE  2  @  2 : 4
 
-> CHANGE  1 : 6  @  1 : 4
+> CHANGE  1 : 7  @  1 : 4
 
 ~ 
+~ import net.lax1dude.eaglercraft.v1_8.EagRuntime;
 ~ import net.lax1dude.eaglercraft.v1_8.EaglercraftRandom;
 ~ import net.lax1dude.eaglercraft.v1_8.EaglercraftUUID;
 ~ import net.lax1dude.eaglercraft.v1_8.futures.FutureTask;
@@ -30,12 +31,10 @@
 
 > DELETE  8  @  8 : 11
 
-> CHANGE  1 : 2  @  1 : 3
+> CHANGE  1 : 2  @  1 : 5
 
 ~ import net.minecraft.network.play.server.S41PacketServerDifficulty;
 
-> DELETE  1  @  1 : 2
-
 > DELETE  7  @  7 : 8
 
 > CHANGE  10 : 11  @  10 : 12
@@ -59,7 +58,7 @@
 
 ~ 	protected final List<ITickable> playersOnline = Lists.newArrayList();
 
-> CHANGE  2 : 3  @  2 : 5
+> CHANGE  1 : 2  @  1 : 5
 
 ~ 	private final EaglercraftRandom random = new EaglercraftRandom();
 
@@ -81,7 +80,7 @@
 
 > CHANGE  1 : 2  @  1 : 4
 
-~ 	protected final Queue<FutureTask<?>> futureTaskQueue = new LinkedList();
+~ 	protected final Queue<FutureTask<?>> futureTaskQueue = new LinkedList<>();
 
 > CHANGE  1 : 4  @  1 : 2
 
@@ -128,7 +127,21 @@
 + 		}
 + 
 
-> DELETE  26  @  26 : 29
+> CHANGE  12 : 14  @  12 : 14
+
+~ 					this.worldServers[j] = (WorldServer) (new DemoWorldServer(this, isavehandler, worldinfo, b0))
+~ 							.init();
+
+> CHANGE  1 : 2  @  1 : 3
+
+~ 					this.worldServers[j] = (WorldServer) (new WorldServer(this, isavehandler, worldinfo, b0)).init();
+
+> CHANGE  4 : 6  @  4 : 6
+
+~ 				this.worldServers[j] = (WorldServer) (new WorldServerMulti(this, isavehandler, b0,
+~ 						this.worldServers[0])).init();
+
+> DELETE  3  @  3 : 6
 
 > CHANGE  3 : 11  @  3 : 5
 
@@ -206,7 +219,15 @@
 
 > DELETE  15  @  15 : 40
 
-> DELETE  17  @  17 : 24
+> CHANGE  7 : 8  @  7 : 8
+
+~ 		long i = EagRuntime.nanoTime();
+
+> DELETE  3  @  3 : 5
+
+> DELETE  2  @  2 : 3
+
+> DELETE  1  @  1 : 8
 
 > CHANGE  1 : 8  @  1 : 4
 
@@ -222,21 +243,57 @@
 
 ~ 			this.isSpawnChunksLoaded = loadSpawnChunks;
 
-> DELETE  13  @  13 : 16
+> DELETE  3  @  3 : 4
 
-> DELETE  1  @  1 : 5
+> DELETE  2  @  2 : 3
 
-> CHANGE  58 : 59  @  58 : 59
+> CHANGE  2 : 3  @  2 : 16
+
+~ 		this.tickTimeArray[this.tickCounter % 100] = EagRuntime.nanoTime() - i;
+
+> DELETE  3  @  3 : 4
+
+> DELETE  6  @  6 : 8
+
+> CHANGE  1 : 2  @  1 : 2
+
+~ 			long i = EagRuntime.nanoTime();
+
+> DELETE  2  @  2 : 3
+
+> DELETE  1  @  1 : 2
+
+> DELETE  4  @  4 : 5
+
+> DELETE  2  @  2 : 4
+
+> DELETE  17  @  17 : 19
+
+> DELETE  1  @  1 : 3
+
+> CHANGE  2 : 3  @  2 : 3
+
+~ 			this.timeOfLastDimensionTick[j][this.tickCounter % 100] = EagRuntime.nanoTime() - i;
+
+> CHANGE  2 : 3  @  2 : 5
 
 ~ 		EaglerIntegratedServerWorker.tick();
 
-> DELETE  20  @  20 : 24
+> DELETE  1  @  1 : 2
+
+> DELETE  4  @  4 : 6
+
+> DELETE  11  @  11 : 15
 
 > CHANGE  29 : 30  @  29 : 30
 
 ~ 		return "eagler";
 
-> CHANGE  28 : 29  @  28 : 29
+> CHANGE  5 : 6  @  5 : 8
+
+~ 				return "N/A (disabled)";
+
+> CHANGE  20 : 21  @  20 : 21
 
 ~ 			List<String> list = this.commandManager.getTabCompletionOptions(sender, input, pos);
 
@@ -290,7 +347,11 @@
 
 > DELETE  28  @  28 : 32
 
-> DELETE  20  @  20 : 36
+> CHANGE  1 : 2  @  1 : 2
+
+~ 		return EagRuntime.steadyTimeMillis();
+
+> DELETE  18  @  18 : 34
 
 > CHANGE  4 : 7  @  4 : 6
 
diff --git a/patches/minecraft/net/minecraft/server/management/ServerConfigurationManager.edit.java b/patches/minecraft/net/minecraft/server/management/ServerConfigurationManager.edit.java
index 412e71cd..95bed2d7 100644
--- a/patches/minecraft/net/minecraft/server/management/ServerConfigurationManager.edit.java
+++ b/patches/minecraft/net/minecraft/server/management/ServerConfigurationManager.edit.java
@@ -26,9 +26,14 @@
 
 + import net.minecraft.util.ChatComponentText;
 
-> CHANGE  12 : 17  @  12 : 14
+> CHANGE  12 : 22  @  12 : 14
 
+~ import net.lax1dude.eaglercraft.v1_8.socket.protocol.GamePluginMessageConstants;
+~ import net.lax1dude.eaglercraft.v1_8.socket.protocol.GamePluginMessageProtocol;
+~ import net.lax1dude.eaglercraft.v1_8.socket.protocol.client.GameProtocolMessageController;
+~ import net.lax1dude.eaglercraft.v1_8.socket.protocol.pkt.server.SPacketUpdateCertEAG;
 ~ import net.lax1dude.eaglercraft.v1_8.sp.server.EaglerMinecraftServer;
+~ import net.lax1dude.eaglercraft.v1_8.sp.server.WorldsDB;
 ~ import net.lax1dude.eaglercraft.v1_8.sp.server.socket.IntegratedServerPlayerNetworkManager;
 ~ import net.lax1dude.eaglercraft.v1_8.sp.server.voice.IntegratedVoiceService;
 ~ import net.lax1dude.eaglercraft.v1_8.log4j.LogManager;
@@ -57,16 +62,25 @@
 
 ~ 		this.maxPlayers = 100;
 
-> CHANGE  2 : 4  @  2 : 8
+> CHANGE  2 : 6  @  2 : 8
 
-~ 	public void initializeConnectionToPlayer(IntegratedServerPlayerNetworkManager netManager, EntityPlayerMP playerIn) {
+~ 	public void initializeConnectionToPlayer(IntegratedServerPlayerNetworkManager netManager, EntityPlayerMP playerIn,
+~ 			int protocolVersion, EaglercraftUUID clientBrandUUID) {
+~ 		playerIn.clientBrandUUID = clientBrandUUID;
 ~ 		GameProfile gameprofile1 = playerIn.getGameProfile();
 
 > CHANGE  3 : 4  @  3 : 7
 
 ~ 		String s1 = "channel:" + netManager.playerChannel;
 
-> DELETE  12  @  12 : 14
+> INSERT  8 : 12  @  8
+
++ 		nethandlerplayserver.setEaglerMessageController(new GameProtocolMessageController(
++ 				GamePluginMessageProtocol.getByVersion(protocolVersion), GamePluginMessageConstants.SERVER_TO_CLIENT,
++ 				GameProtocolMessageController.createServerHandler(protocolVersion, nethandlerplayserver),
++ 				(ch, msg) -> nethandlerplayserver.sendPacket(new S3FPacketCustomPayload(ch, msg))));
+
+> DELETE  4  @  4 : 6
 
 > INSERT  1 : 4  @  1
 
@@ -90,17 +104,13 @@
 + 			playerIn.addChatMessage(shaderF4Msg);
 + 		}
 
-> INSERT  23 : 35  @  23
+> INSERT  23 : 31  @  23
 
 + 		if (EagRuntime.getConfiguration().allowUpdateSvc()) {
 + 			for (int i = 0, l = playerEntityList.size(); i < l; ++i) {
 + 				EntityPlayerMP playerItr = playerEntityList.get(i);
 + 				if (playerItr != playerIn && playerItr.updateCertificate != null) {
-+ 					nethandlerplayserver
-+ 							.sendPacket(new S3FPacketCustomPayload("EAG|UpdateCert-1.8",
-+ 									new PacketBuffer(Unpooled
-+ 											.buffer(playerItr.updateCertificate, playerItr.updateCertificate.length)
-+ 											.writerIndex(playerItr.updateCertificate.length))));
++ 					nethandlerplayserver.sendEaglerMessage(new SPacketUpdateCertEAG(playerItr.updateCertificate));
 + 				}
 + 			}
 + 		}
@@ -175,7 +185,20 @@
 ~ 		for (int i = 0, l = arraylist.size(); i < l; ++i) {
 ~ 			arraylist.get(i).playerNetServerHandler.kickPlayerFromServer("You logged in from another location");
 
-> CHANGE  205 : 206  @  205 : 206
+> INSERT  32 : 34  @  32
+
++ 		entityplayermp.updateCertificate = playerIn.updateCertificate;
++ 		entityplayermp.clientBrandUUID = playerIn.clientBrandUUID;
+
+> DELETE  75  @  75 : 76
+
+> DELETE  35  @  35 : 36
+
+> DELETE  1  @  1 : 2
+
+> DELETE  8  @  8 : 10
+
+> CHANGE  49 : 50  @  49 : 50
 
 ~ 			for (int i = 0, l = this.playerEntityList.size(); i < l; ++i) {
 
@@ -237,13 +260,11 @@
 ~ 		String name = playerIn.getName();
 ~ 		StatisticsFile statisticsfile = (StatisticsFile) this.playerStatFiles.get(name);
 
-> CHANGE  1 : 2  @  1 : 2
+> CHANGE  1 : 4  @  1 : 11
 
-~ 			VFile2 file1 = new VFile2(this.mcServer.worldServerForDimension(0).getSaveHandler().getWorldDirectory(),
-
-> CHANGE  1 : 2  @  1 : 9
-
-~ 			VFile2 file2 = new VFile2(file1, name + ".json");
+~ 			VFile2 file1 = WorldsDB
+~ 					.newVFile(this.mcServer.worldServerForDimension(0).getSaveHandler().getWorldDirectory(), "stats");
+~ 			VFile2 file2 = WorldsDB.newVFile(file1, name + ".json");
 
 > CHANGE  2 : 3  @  2 : 3
 
diff --git a/patches/minecraft/net/minecraft/server/network/NetHandlerLoginServer.edit.java b/patches/minecraft/net/minecraft/server/network/NetHandlerLoginServer.edit.java
index fc78fa73..3570a719 100644
--- a/patches/minecraft/net/minecraft/server/network/NetHandlerLoginServer.edit.java
+++ b/patches/minecraft/net/minecraft/server/network/NetHandlerLoginServer.edit.java
@@ -5,11 +5,13 @@
 # Version: 1.0
 # Author: lax1dude
 
-> CHANGE  3 : 7  @  3 : 15
+> CHANGE  3 : 9  @  3 : 15
 
 ~ import net.lax1dude.eaglercraft.v1_8.mojang.authlib.GameProfile;
-~ import net.lax1dude.eaglercraft.v1_8.EaglercraftRandom;
+~ import net.lax1dude.eaglercraft.v1_8.ClientUUIDLoadingCache;
+~ import net.lax1dude.eaglercraft.v1_8.EaglerInputStream;
 ~ import net.lax1dude.eaglercraft.v1_8.EaglercraftUUID;
+~ import net.lax1dude.eaglercraft.v1_8.EaglercraftVersion;
 ~ import net.lax1dude.eaglercraft.v1_8.sp.server.EaglerMinecraftServer;
 
 > CHANGE  1 : 2  @  1 : 2
@@ -22,11 +24,14 @@
 
 > DELETE  2  @  2 : 3
 
-> INSERT  2 : 5  @  2
+> INSERT  2 : 8  @  2
 
 + import net.lax1dude.eaglercraft.v1_8.sp.server.socket.IntegratedServerPlayerNetworkManager;
 + import net.lax1dude.eaglercraft.v1_8.sp.server.voice.IntegratedVoiceService;
 + 
++ import java.io.DataInputStream;
++ import java.io.IOException;
++ 
 
 > CHANGE  1 : 3  @  1 : 3
 
@@ -35,18 +40,18 @@
 
 > DELETE  2  @  2 : 3
 
+> DELETE  1  @  1 : 3
+
 > CHANGE  1 : 2  @  1 : 2
 
-~ 	private static final EaglercraftRandom RANDOM = new EaglercraftRandom();
-
-> CHANGE  2 : 3  @  2 : 3
-
 ~ 	public final IntegratedServerPlayerNetworkManager networkManager;
 
-> INSERT  3 : 5  @  3
+> INSERT  3 : 7  @  3
 
 + 	private byte[] loginSkinPacket;
 + 	private byte[] loginCapePacket;
++ 	private int selectedProtocol = 3;
++ 	private EaglercraftUUID clientBrandUUID;
 
 > DELETE  1  @  1 : 2
 
@@ -55,35 +60,40 @@
 ~ 	public NetHandlerLoginServer(MinecraftServer parMinecraftServer,
 ~ 			IntegratedServerPlayerNetworkManager parNetworkManager) {
 
-> INSERT  15 : 25  @  15
+> DELETE  2  @  2 : 3
 
-+ 				((EaglerMinecraftServer) field_181025_l.mcServer).getSkinService()
-+ 						.processLoginPacket(this.loginSkinPacket, field_181025_l);
-+ 				if (this.loginCapePacket != null) {
-+ 					((EaglerMinecraftServer) field_181025_l.mcServer).getCapeService()
-+ 							.processLoginPacket(this.loginCapePacket, field_181025_l);
-+ 				}
-+ 				IntegratedVoiceService svc = ((EaglerMinecraftServer) field_181025_l.mcServer).getVoiceService();
-+ 				if (svc != null) {
-+ 					svc.handlePlayerLoggedIn(entityplayermp);
-+ 				}
+> CHANGE  11 : 23  @  11 : 12
+
+~ 						this.field_181025_l, this.selectedProtocol, this.clientBrandUUID);
+~ 				((EaglerMinecraftServer) field_181025_l.mcServer).getSkinService()
+~ 						.processLoginPacket(this.loginSkinPacket, field_181025_l, 3); // singleplayer always sends V3
+~ 																						// skin in handshake
+~ 				if (this.loginCapePacket != null) {
+~ 					((EaglerMinecraftServer) field_181025_l.mcServer).getCapeService()
+~ 							.processLoginPacket(this.loginCapePacket, field_181025_l);
+~ 				}
+~ 				IntegratedVoiceService svc = ((EaglerMinecraftServer) field_181025_l.mcServer).getVoiceService();
+~ 				if (svc != null) {
+~ 					svc.handlePlayerLoggedIn(entityplayermp);
+~ 				}
 
 > CHANGE  23 : 24  @  23 : 29
 
 ~ 		String s = this.server.getConfigurationManager().allowUserToConnect(this.loginGameProfile);
 
-> DELETE  4  @  4 : 15
+> CHANGE  4 : 6  @  4 : 16
 
-> INSERT  1 : 2  @  1
+~ 			this.networkManager.sendPacket(new S02PacketLoginSuccess(this.loginGameProfile, this.selectedProtocol));
+~ 			this.networkManager.setConnectionState(EnumConnectionState.PLAY);
 
-+ 			this.networkManager.setConnectionState(EnumConnectionState.PLAY);
-
-> CHANGE  6 : 18  @  6 : 8
+> CHANGE  6 : 20  @  6 : 8
 
 ~ 				entityplayermp = this.server.getConfigurationManager().createPlayerForUser(this.loginGameProfile);
-~ 				this.server.getConfigurationManager().initializeConnectionToPlayer(this.networkManager, entityplayermp);
+~ 				this.server.getConfigurationManager().initializeConnectionToPlayer(this.networkManager, entityplayermp,
+~ 						this.selectedProtocol, this.clientBrandUUID);
 ~ 				((EaglerMinecraftServer) entityplayermp.mcServer).getSkinService()
-~ 						.processLoginPacket(this.loginSkinPacket, entityplayermp);
+~ 						.processLoginPacket(this.loginSkinPacket, entityplayermp, 3); // singleplayer always sends V3
+~ 																						// skin in handshake
 ~ 				if (this.loginCapePacket != null) {
 ~ 					((EaglerMinecraftServer) entityplayermp.mcServer).getCapeService()
 ~ 							.processLoginPacket(this.loginCapePacket, entityplayermp);
@@ -98,11 +108,44 @@
 ~ 				? this.loginGameProfile.toString() + " (channel:" + this.networkManager.playerChannel + ")"
 ~ 				: ("channel:" + this.networkManager.playerChannel);
 
-> CHANGE  5 : 9  @  5 : 14
+> CHANGE  5 : 25  @  5 : 10
+
+~ 		if (c00packetloginstart.getProtocols() != null) {
+~ 			try {
+~ 				DataInputStream dis = new DataInputStream(new EaglerInputStream(c00packetloginstart.getProtocols()));
+~ 				int maxSupported = -1;
+~ 				int protocolCount = dis.readUnsignedShort();
+~ 				for (int i = 0; i < protocolCount; ++i) {
+~ 					int p = dis.readUnsignedShort();
+~ 					if ((p == 3 || p == 4) && p > maxSupported) {
+~ 						maxSupported = p;
+~ 					}
+~ 				}
+~ 				if (maxSupported != -1) {
+~ 					selectedProtocol = maxSupported;
+~ 				} else {
+~ 					this.closeConnection("Unknown protocol!");
+~ 					return;
+~ 				}
+~ 			} catch (IOException ex) {
+~ 				selectedProtocol = 3;
+~ 			}
+
+> CHANGE  1 : 2  @  1 : 2
+
+~ 			selectedProtocol = 3;
+
+> CHANGE  1 : 11  @  1 : 2
 
 ~ 		this.loginGameProfile = this.getOfflineProfile(c00packetloginstart.getProfile());
 ~ 		this.loginSkinPacket = c00packetloginstart.getSkin();
 ~ 		this.loginCapePacket = c00packetloginstart.getCape();
+~ 		this.clientBrandUUID = selectedProtocol <= 3 ? EaglercraftVersion.legacyClientUUIDInSharedWorld
+~ 				: c00packetloginstart.getBrandUUID();
+~ 		if (ClientUUIDLoadingCache.PENDING_UUID.equals(clientBrandUUID)
+~ 				|| ClientUUIDLoadingCache.VANILLA_UUID.equals(clientBrandUUID)) {
+~ 			this.clientBrandUUID = null;
+~ 		}
 ~ 		this.currentLoginState = NetHandlerLoginServer.LoginState.READY_TO_ACCEPT;
 
 > DELETE  3  @  3 : 15
diff --git a/patches/minecraft/net/minecraft/tileentity/TileEntitySign.edit.java b/patches/minecraft/net/minecraft/tileentity/TileEntitySign.edit.java
index 0aa6b770..1605d22e 100644
--- a/patches/minecraft/net/minecraft/tileentity/TileEntitySign.edit.java
+++ b/patches/minecraft/net/minecraft/tileentity/TileEntitySign.edit.java
@@ -5,7 +5,10 @@
 # Version: 1.0
 # Author: lax1dude
 
-> DELETE  2  @  2 : 3
+> CHANGE  2 : 4  @  2 : 3
+
+~ import net.lax1dude.eaglercraft.v1_8.profanity_filter.ProfanityFilter;
+~ import net.minecraft.client.Minecraft;
 
 > DELETE  10  @  10 : 11
 
@@ -14,7 +17,33 @@
 + import org.json.JSONException;
 + 
 
-> CHANGE  75 : 76  @  75 : 76
+> INSERT  3 : 4  @  3
+
++ 	protected IChatComponent[] signTextProfanityFilter = null;
+
+> INSERT  16 : 35  @  16
+
++ 	public IChatComponent[] getSignTextProfanityFilter() {
++ 		if (Minecraft.getMinecraft().isEnableProfanityFilter()) {
++ 			if (signTextProfanityFilter == null) {
++ 				signTextProfanityFilter = new IChatComponent[4];
++ 				ProfanityFilter filter = ProfanityFilter.getInstance();
++ 				for (int i = 0; i < 4; ++i) {
++ 					signTextProfanityFilter[i] = filter.profanityFilterChatComponent(signText[i]);
++ 				}
++ 			}
++ 			return signTextProfanityFilter;
++ 		} else {
++ 			return signText;
++ 		}
++ 	}
++ 
++ 	public void clearProfanityFilterCache() {
++ 		signTextProfanityFilter = null;
++ 	}
++ 
+
+> CHANGE  56 : 57  @  56 : 57
 
 ~ 			} catch (JSONException var8) {
 
diff --git a/patches/minecraft/net/minecraft/util/ChatComponentStyle.edit.java b/patches/minecraft/net/minecraft/util/ChatComponentStyle.edit.java
index 9b30fde2..41e7323a 100644
--- a/patches/minecraft/net/minecraft/util/ChatComponentStyle.edit.java
+++ b/patches/minecraft/net/minecraft/util/ChatComponentStyle.edit.java
@@ -23,4 +23,11 @@
 ~ 			for (int i = 0, l = this.siblings.size(); i < l; ++i) {
 ~ 				this.siblings.get(i).getChatStyle().setParentStyle(this.style);
 
+> INSERT  6 : 10  @  6
+
++ 	public ChatStyle getChatStyleIfPresent() {
++ 		return this.style;
++ 	}
++ 
+
 > EOF
diff --git a/patches/minecraft/net/minecraft/util/ChatStyle.edit.java b/patches/minecraft/net/minecraft/util/ChatStyle.edit.java
index 457178d8..d4a9a956 100644
--- a/patches/minecraft/net/minecraft/util/ChatStyle.edit.java
+++ b/patches/minecraft/net/minecraft/util/ChatStyle.edit.java
@@ -80,7 +80,7 @@
 
 + 				}
 
-> CHANGE  1 : 12  @  1 : 13
+> CHANGE  1 : 13  @  1 : 12
 
 ~ 				if (jsonobject.has("hoverEvent")) {
 ~ 					JSONObject jsonobject2 = jsonobject.getJSONObject("hoverEvent");
@@ -88,13 +88,22 @@
 ~ 						String jsonprimitive2 = jsonobject2.getString("action");
 ~ 						HoverEvent.Action hoverevent$action = jsonprimitive2 == null ? null
 ~ 								: HoverEvent.Action.getValueByCanonicalName(jsonprimitive2);
-~ 						IChatComponent ichatcomponent = JSONTypeProvider.deserializeNoCast(jsonobject2.get("value"),
-~ 								IChatComponent.class);
-~ 						if (hoverevent$action != null && ichatcomponent != null
-~ 								&& hoverevent$action.shouldAllowInChat()) {
-~ 							chatstyle.chatHoverEvent = new HoverEvent(hoverevent$action, ichatcomponent);
+~ 						Object val = jsonobject2.opt("value");
+~ 						if (val == null) {
+~ 							val = jsonobject2.opt("contents");
+~ 							if (val == null) {
+~ 								throw new JSONException(
+~ 										"JSONObject[\"value\"] or JSONObject[\"contents\"] could not be found");
 
-> DELETE  2  @  2 : 4
+> INSERT  2 : 7  @  2
+
++ 						IChatComponent ichatcomponent = JSONTypeProvider.deserializeNoCast(val, IChatComponent.class);
++ 						if (hoverevent$action != null && ichatcomponent != null
++ 								&& hoverevent$action.shouldAllowInChat()) {
++ 							chatstyle.chatHoverEvent = new HoverEvent(hoverevent$action, ichatcomponent);
++ 						}
+
+> DELETE  1  @  1 : 3
 
 > CHANGE  1 : 3  @  1 : 3
 
diff --git a/patches/minecraft/net/minecraft/util/MouseHelper.edit.java b/patches/minecraft/net/minecraft/util/MouseHelper.edit.java
index 6a2c4b6d..38ec9493 100644
--- a/patches/minecraft/net/minecraft/util/MouseHelper.edit.java
+++ b/patches/minecraft/net/minecraft/util/MouseHelper.edit.java
@@ -5,9 +5,15 @@
 # Version: 1.0
 # Author: lax1dude
 
-> CHANGE  2 : 4  @  2 : 4
+> CHANGE  2 : 5  @  2 : 4
 
 ~ import net.lax1dude.eaglercraft.v1_8.Display;
 ~ import net.lax1dude.eaglercraft.v1_8.Mouse;
+~ import net.lax1dude.eaglercraft.v1_8.PointerInputAbstraction;
+
+> CHANGE  17 : 19  @  17 : 19
+
+~ 		this.deltaX = PointerInputAbstraction.getVCursorDX();
+~ 		this.deltaY = PointerInputAbstraction.getVCursorDY();
 
 > EOF
diff --git a/patches/minecraft/net/minecraft/util/MovementInputFromOptions.edit.java b/patches/minecraft/net/minecraft/util/MovementInputFromOptions.edit.java
index a8dd6648..20acaad8 100644
--- a/patches/minecraft/net/minecraft/util/MovementInputFromOptions.edit.java
+++ b/patches/minecraft/net/minecraft/util/MovementInputFromOptions.edit.java
@@ -5,6 +5,38 @@
 # Version: 1.0
 # Author: lax1dude
 
-> DELETE  3  @  3 : 4
+> INSERT  2 : 4  @  2
+
++ import net.lax1dude.eaglercraft.v1_8.touch_gui.EnumTouchControl;
++ import net.lax1dude.eaglercraft.v1_8.touch_gui.TouchControls;
+
+> DELETE  1  @  1 : 2
+
+> CHANGE  11 : 14  @  11 : 12
+
+~ 		if (this.gameSettings.keyBindForward.isKeyDown() || TouchControls.isPressed(EnumTouchControl.DPAD_UP)
+~ 				|| TouchControls.isPressed(EnumTouchControl.DPAD_UP_LEFT)
+~ 				|| TouchControls.isPressed(EnumTouchControl.DPAD_UP_RIGHT)) {
+
+> CHANGE  3 : 4  @  3 : 4
+
+~ 		if (this.gameSettings.keyBindBack.isKeyDown() || TouchControls.isPressed(EnumTouchControl.DPAD_DOWN)) {
+
+> CHANGE  3 : 5  @  3 : 4
+
+~ 		if (this.gameSettings.keyBindLeft.isKeyDown() || TouchControls.isPressed(EnumTouchControl.DPAD_LEFT)
+~ 				|| TouchControls.isPressed(EnumTouchControl.DPAD_UP_LEFT)) {
+
+> CHANGE  3 : 5  @  3 : 4
+
+~ 		if (this.gameSettings.keyBindRight.isKeyDown() || TouchControls.isPressed(EnumTouchControl.DPAD_RIGHT)
+~ 				|| TouchControls.isPressed(EnumTouchControl.DPAD_UP_RIGHT)) {
+
+> CHANGE  3 : 7  @  3 : 5
+
+~ 		this.jump = this.gameSettings.keyBindJump.isKeyDown() || TouchControls.isPressed(EnumTouchControl.JUMP)
+~ 				|| TouchControls.isPressed(EnumTouchControl.FLY_UP);
+~ 		this.sneak = this.gameSettings.keyBindSneak.isKeyDown() || TouchControls.getSneakToggled()
+~ 				|| TouchControls.isPressed(EnumTouchControl.FLY_DOWN);
 
 > EOF
diff --git a/patches/minecraft/net/minecraft/util/Session.edit.java b/patches/minecraft/net/minecraft/util/Session.edit.java
index f799854b..6dc89810 100644
--- a/patches/minecraft/net/minecraft/util/Session.edit.java
+++ b/patches/minecraft/net/minecraft/util/Session.edit.java
@@ -19,7 +19,7 @@
 
 > CHANGE  1 : 2  @  1 : 7
 
-~ 	private static final EaglercraftUUID offlineUUID;
+~ 	private static final EaglercraftUUID outOfGameUUID;
 
 > CHANGE  1 : 3  @  1 : 3
 
@@ -39,7 +39,7 @@
 > CHANGE  2 : 4  @  2 : 4
 
 ~ 	public void reset() {
-~ 		update(EaglerProfile.getName(), offlineUUID);
+~ 		update(EaglerProfile.getName(), outOfGameUUID);
 
 > CHANGE  2 : 4  @  2 : 9
 
@@ -51,7 +51,7 @@
 ~ 	static {
 ~ 		byte[] bytes = new byte[16];
 ~ 		(new EaglercraftRandom()).nextBytes(bytes);
-~ 		offlineUUID = new EaglercraftUUID(bytes);
+~ 		outOfGameUUID = new EaglercraftUUID(bytes);
 
 > DELETE  2  @  2 : 23
 
diff --git a/patches/minecraft/net/minecraft/util/StringTranslate.edit.java b/patches/minecraft/net/minecraft/util/StringTranslate.edit.java
index 7ff5bb50..b9f1116d 100644
--- a/patches/minecraft/net/minecraft/util/StringTranslate.edit.java
+++ b/patches/minecraft/net/minecraft/util/StringTranslate.edit.java
@@ -41,7 +41,7 @@
 > CHANGE  1 : 25  @  1 : 9
 
 ~ 	public static void initClient() {
-~ 		try (InputStream inputstream = EagRuntime.getResourceStream("/assets/minecraft/lang/en_US.lang")) {
+~ 		try (InputStream inputstream = EagRuntime.getRequiredResourceStream("/assets/minecraft/lang/en_US.lang")) {
 ~ 			initServer(IOUtils.readLines(inputstream, StandardCharsets.UTF_8));
 ~ 			fallbackInstance = new StringTranslate();
 ~ 			fallbackInstance.replaceWith(instance.languageList);
@@ -69,13 +69,17 @@
 
 > INSERT  2 : 3  @  2
 
-+ 		instance.lastUpdateTimeInMilliseconds = System.currentTimeMillis();
++ 		instance.lastUpdateTimeInMilliseconds = EagRuntime.steadyTimeMillis();
 
 > CHANGE  6 : 7  @  6 : 7
 
 ~ 	public static void replaceWith(Map<String, String> parMap) {
 
-> CHANGE  5 : 6  @  5 : 6
+> CHANGE  2 : 3  @  2 : 3
+
+~ 		instance.lastUpdateTimeInMilliseconds = EagRuntime.steadyTimeMillis();
+
+> CHANGE  2 : 3  @  2 : 3
 
 ~ 	public String translateKey(String key) {
 
diff --git a/patches/minecraft/net/minecraft/util/StringUtils.edit.java b/patches/minecraft/net/minecraft/util/StringUtils.edit.java
index b0b57824..3f2fc2d0 100644
--- a/patches/minecraft/net/minecraft/util/StringUtils.edit.java
+++ b/patches/minecraft/net/minecraft/util/StringUtils.edit.java
@@ -11,7 +11,7 @@
 + 	private static final Pattern patternControlCodeAlternate = Pattern.compile("(?i)&([0-9A-FK-OR])");
 + 
 + 	public static String translateControlCodesAlternate(String parString1) {
-+ 		return patternControlCodeAlternate.matcher(parString1).replaceAll("\u00A7$1");
++ 		return patternControlCodeAlternate.matcher(parString1).replaceAll(new String(new char[] { 0xA7, '$', '1' }));
 + 	}
 
 > EOF
diff --git a/patches/minecraft/net/minecraft/util/Timer.edit.java b/patches/minecraft/net/minecraft/util/Timer.edit.java
index f2d94130..e5c2d1bc 100644
--- a/patches/minecraft/net/minecraft/util/Timer.edit.java
+++ b/patches/minecraft/net/minecraft/util/Timer.edit.java
@@ -5,8 +5,20 @@
 # Version: 1.0
 # Author: lax1dude
 
-> DELETE  3  @  3 : 4
+> INSERT  2 : 3  @  2
 
-> DELETE  52  @  52 : 53
++ import net.lax1dude.eaglercraft.v1_8.EagRuntime;
+
+> DELETE  1  @  1 : 2
+
+> CHANGE  16 : 17  @  16 : 17
+
+~ 		this.lastSyncHRClock = EagRuntime.nanoTime() / 1000000L;
+
+> CHANGE  5 : 6  @  5 : 6
+
+~ 		long k = EagRuntime.nanoTime() / 1000000L;
+
+> DELETE  29  @  29 : 30
 
 > EOF
diff --git a/patches/minecraft/net/minecraft/world/GameRules.edit.java b/patches/minecraft/net/minecraft/world/GameRules.edit.java
index a0dab682..138dc999 100644
--- a/patches/minecraft/net/minecraft/world/GameRules.edit.java
+++ b/patches/minecraft/net/minecraft/world/GameRules.edit.java
@@ -9,7 +9,7 @@
 
 + 
 
-> INSERT  21 : 27  @  21
+> INSERT  21 : 28  @  21
 
 + 		this.addGameRule("loadSpawnChunks", "false", GameRules.ValueType.BOOLEAN_VALUE);
 + 		this.addGameRule("bedSpawnPoint", "true", GameRules.ValueType.BOOLEAN_VALUE);
@@ -17,5 +17,6 @@
 + 		this.addGameRule("clickToSit", "true", GameRules.ValueType.BOOLEAN_VALUE);
 + 		this.addGameRule("colorCodes", "true", GameRules.ValueType.BOOLEAN_VALUE);
 + 		this.addGameRule("doSignEditing", "true", GameRules.ValueType.BOOLEAN_VALUE);
++ 		this.addGameRule("doWeatherCycle", "true", GameRules.ValueType.BOOLEAN_VALUE);
 
 > EOF
diff --git a/patches/minecraft/net/minecraft/world/World.edit.java b/patches/minecraft/net/minecraft/world/World.edit.java
index b59977a1..5e84e694 100644
--- a/patches/minecraft/net/minecraft/world/World.edit.java
+++ b/patches/minecraft/net/minecraft/world/World.edit.java
@@ -9,10 +9,9 @@
 
 + 
 
-> CHANGE  5 : 8  @  5 : 6
+> CHANGE  5 : 7  @  5 : 6
 
 ~ 
-~ import net.lax1dude.eaglercraft.v1_8.EagRuntime;
 ~ import net.lax1dude.eaglercraft.v1_8.EaglercraftRandom;
 
 > CHANGE  1 : 4  @  1 : 2
@@ -25,7 +24,9 @@
 
 + 
 
-> DELETE  32  @  32 : 46
+> DELETE  16  @  16 : 17
+
+> DELETE  15  @  15 : 29
 
 > CHANGE  24 : 25  @  24 : 25
 
@@ -35,17 +36,21 @@
 
 ~ 	public final EaglercraftRandom rand = new EaglercraftRandom();
 
-> CHANGE  9 : 10  @  9 : 10
+> DELETE  8  @  8 : 9
 
-~ 	private final Calendar theCalendar = EagRuntime.getLocaleCalendar();
-
-> DELETE  1  @  1 : 2
+> DELETE  2  @  2 : 3
 
 > INSERT  7 : 8  @  7
 
 + 	public final boolean isRemote;
 
-> DELETE  11  @  11 : 12
+> CHANGE  1 : 2  @  1 : 3
+
+~ 	protected World(ISaveHandler saveHandlerIn, WorldInfo info, WorldProvider providerIn, boolean client) {
+
+> DELETE  5  @  5 : 6
+
+> DELETE  2  @  2 : 3
 
 > INSERT  1 : 2  @  1
 
@@ -56,7 +61,11 @@
 ~ 						return CrashReportCategory
 ~ 								.getCoordinateInfo(new net.minecraft.util.BlockPos(pos.getX(), pos.getY(), pos.getZ()));
 
-> CHANGE  257 : 258  @  257 : 258
+> DELETE  123  @  123 : 124
+
+> DELETE  1  @  1 : 2
+
+> CHANGE  131 : 132  @  131 : 132
 
 ~ 							return HString.format("ID #%d (%s // %s)",
 
@@ -73,7 +82,33 @@
 ~ 			}
 ~ 		} else if (j < lightValue) {
 
-> CHANGE  1224 : 1225  @  1224 : 1225
+> DELETE  579  @  579 : 582
+
+> DELETE  23  @  23 : 24
+
+> DELETE  16  @  16 : 17
+
+> DELETE  12  @  12 : 13
+
+> DELETE  11  @  11 : 13
+
+> DELETE  11  @  11 : 12
+
+> DELETE  2  @  2 : 3
+
+> DELETE  36  @  36 : 37
+
+> DELETE  20  @  20 : 22
+
+> DELETE  48  @  48 : 49
+
+> DELETE  38  @  38 : 39
+
+> CHANGE  400 : 401  @  400 : 401
+
+~ 		if (!this.provider.getHasNoSky() && this.getGameRules().getBoolean("doWeatherCycle")) {
+
+> CHANGE  12 : 13  @  12 : 13
 
 ~ 						this.worldInfo.setThunderTime((this.rand.nextInt(12000) / 2) + 3600);
 
@@ -89,7 +124,19 @@
 
 ~ 						this.worldInfo.setRainTime((this.rand.nextInt(168000) + 12000) * 2);
 
-> CHANGE  91 : 92  @  91 : 92
+> DELETE  23  @  23 : 24
+
+> DELETE  14  @  14 : 15
+
+> DELETE  4  @  4 : 5
+
+> DELETE  9  @  9 : 10
+
+> DELETE  5  @  5 : 6
+
+> DELETE  23  @  23 : 24
+
+> CHANGE  7 : 8  @  7 : 8
 
 ~ 	public void forceBlockUpdateTick(Block blockType, BlockPos pos, EaglercraftRandom random) {
 
@@ -99,13 +146,19 @@
 ~ 				for (int m = 0; m < facings.length; ++m) {
 ~ 					EnumFacing enumfacing = facings[m];
 
-> CHANGE  50 : 53  @  50 : 51
+> DELETE  22  @  22 : 23
+
+> CHANGE  27 : 30  @  27 : 28
 
 ~ 								EnumFacing[] facings = EnumFacing._VALUES;
 ~ 								for (int m = 0; m < facings.length; ++m) {
 ~ 									EnumFacing enumfacing = facings[m];
 
-> CHANGE  117 : 120  @  117 : 119
+> DELETE  20  @  20 : 23
+
+> DELETE  50  @  50 : 51
+
+> CHANGE  43 : 46  @  43 : 45
 
 ~ 		for (int i = 0, l = this.loadedEntityList.size(); i < l; ++i) {
 ~ 			Entity entity = this.loadedEntityList.get(i);
diff --git a/patches/minecraft/net/minecraft/world/WorldServer.edit.java b/patches/minecraft/net/minecraft/world/WorldServer.edit.java
index 57e9e43b..2429e2b4 100644
--- a/patches/minecraft/net/minecraft/world/WorldServer.edit.java
+++ b/patches/minecraft/net/minecraft/world/WorldServer.edit.java
@@ -16,7 +16,9 @@
 ~ import net.lax1dude.eaglercraft.v1_8.EaglercraftUUID;
 ~ import net.lax1dude.eaglercraft.v1_8.sp.server.EaglerMinecraftServer;
 
-> DELETE  42  @  42 : 53
+> DELETE  25  @  25 : 26
+
+> DELETE  16  @  16 : 27
 
 > CHANGE  12 : 14  @  12 : 14
 
@@ -27,7 +29,28 @@
 
 ~ 	private final Map<EaglercraftUUID, Entity> entitiesByUuid = Maps.newHashMap();
 
-> CHANGE  143 : 145  @  143 : 144
+> CHANGE  23 : 25  @  23 : 26
+
+~ 	public WorldServer(MinecraftServer server, ISaveHandler saveHandlerIn, WorldInfo info, int dimensionId) {
+~ 		super(saveHandlerIn, info, WorldProvider.getProviderForDimension(dimensionId), false);
+
+> DELETE  64  @  64 : 65
+
+> DELETE  6  @  6 : 7
+
+> DELETE  11  @  11 : 12
+
+> DELETE  1  @  1 : 2
+
+> DELETE  1  @  1 : 2
+
+> DELETE  1  @  1 : 2
+
+> DELETE  2  @  2 : 3
+
+> DELETE  1  @  1 : 2
+
+> CHANGE  22 : 24  @  22 : 23
 
 ~ 			for (int k = 0, l = this.playerEntities.size(); k < l; ++k) {
 ~ 				EntityPlayer entityplayer = this.playerEntities.get(k);
@@ -43,7 +66,17 @@
 ~ 			for (int k = 0, l = this.playerEntities.size(); k < l; ++k) {
 ~ 				EntityPlayer entityplayer = this.playerEntities.get(k);
 
-> CHANGE  88 : 91  @  88 : 89
+> DELETE  48  @  48 : 49
+
+> DELETE  2  @  2 : 3
+
+> DELETE  1  @  1 : 2
+
+> DELETE  11  @  11 : 12
+
+> DELETE  19  @  19 : 20
+
+> CHANGE  2 : 5  @  2 : 3
 
 ~ 					ExtendedBlockStorage[] vigg = chunk.getBlockStorageArray();
 ~ 					for (int m = 0; m < vigg.length; ++m) {
@@ -53,15 +86,25 @@
 
 + 									++EaglerMinecraftServer.counterTileUpdate;
 
-> INSERT  47 : 48  @  47
+> DELETE  5  @  5 : 7
+
+> DELETE  1  @  1 : 2
+
+> INSERT  38 : 39  @  38
 
 + 						++EaglerMinecraftServer.counterTileUpdate;
 
-> INSERT  95 : 96  @  95
+> DELETE  65  @  65 : 67
+
+> DELETE  12  @  12 : 14
+
+> INSERT  14 : 15  @  14
 
 + 								++EaglerMinecraftServer.counterTileUpdate;
 
-> CHANGE  160 : 161  @  160 : 161
+> DELETE  15  @  15 : 16
+
+> CHANGE  144 : 145  @  144 : 145
 
 ~ 			EaglercraftRandom random = new EaglercraftRandom(this.getSeed());
 
diff --git a/patches/minecraft/net/minecraft/world/WorldServerMulti.edit.java b/patches/minecraft/net/minecraft/world/WorldServerMulti.edit.java
index 3e397c6f..f8851dec 100644
--- a/patches/minecraft/net/minecraft/world/WorldServerMulti.edit.java
+++ b/patches/minecraft/net/minecraft/world/WorldServerMulti.edit.java
@@ -5,6 +5,13 @@
 # Version: 1.0
 # Author: lax1dude
 
-> DELETE  5  @  5 : 8
+> DELETE  2  @  2 : 3
+
+> DELETE  2  @  2 : 5
+
+> CHANGE  8 : 10  @  8 : 11
+
+~ 	public WorldServerMulti(MinecraftServer server, ISaveHandler saveHandlerIn, int dimensionId, WorldServer delegate) {
+~ 		super(server, saveHandlerIn, new DerivedWorldInfo(delegate.getWorldInfo()), dimensionId);
 
 > EOF
diff --git a/patches/minecraft/net/minecraft/world/border/WorldBorder.edit.java b/patches/minecraft/net/minecraft/world/border/WorldBorder.edit.java
index 2f9f3400..e1038cac 100644
--- a/patches/minecraft/net/minecraft/world/border/WorldBorder.edit.java
+++ b/patches/minecraft/net/minecraft/world/border/WorldBorder.edit.java
@@ -7,11 +7,12 @@
 
 > DELETE  2  @  2 : 3
 
-> INSERT  1 : 4  @  1
+> INSERT  1 : 5  @  1
 
 + 
 + import com.google.common.collect.Lists;
 + 
++ import net.lax1dude.eaglercraft.v1_8.EagRuntime;
 
 > DELETE  4  @  4 : 6
 
@@ -21,13 +22,29 @@
 ~ 		for (int i = 0, l = lst.size(); i < l; ++i) {
 ~ 			lst.get(i).onCenterChanged(this, x, z);
 
-> CHANGE  32 : 35  @  32 : 34
+> CHANGE  6 : 7  @  6 : 7
+
+~ 			double d0 = (double) ((float) (EagRuntime.steadyTimeMillis() - this.startTime)
+
+> CHANGE  12 : 13  @  12 : 13
+
+~ 		return this.getStatus() != EnumBorderStatus.STATIONARY ? this.endTime - EagRuntime.steadyTimeMillis() : 0L;
+
+> CHANGE  9 : 10  @  9 : 10
+
+~ 		this.endTime = EagRuntime.steadyTimeMillis();
+
+> CHANGE  2 : 5  @  2 : 4
 
 ~ 		List<IBorderListener> lst = this.getListeners();
 ~ 		for (int i = 0, l = lst.size(); i < l; ++i) {
 ~ 			lst.get(i).onSizeChanged(this, newSize);
 
-> CHANGE  10 : 13  @  10 : 12
+> CHANGE  7 : 8  @  7 : 8
+
+~ 		this.startTime = EagRuntime.steadyTimeMillis();
+
+> CHANGE  2 : 5  @  2 : 4
 
 ~ 		List<IBorderListener> lst = this.getListeners();
 ~ 		for (int i = 0, l = lst.size(); i < l; ++i) {
diff --git a/patches/minecraft/net/minecraft/world/chunk/Chunk.edit.java b/patches/minecraft/net/minecraft/world/chunk/Chunk.edit.java
index 40157c10..ba65f3b3 100644
--- a/patches/minecraft/net/minecraft/world/chunk/Chunk.edit.java
+++ b/patches/minecraft/net/minecraft/world/chunk/Chunk.edit.java
@@ -45,7 +45,9 @@
 + 			++EaglerMinecraftServer.counterLightUpdate;
 + 		}
 
-> CHANGE  20 : 23  @  20 : 21
+> DELETE  9  @  9 : 10
+
+> CHANGE  10 : 13  @  10 : 11
 
 ~ 						EnumFacing[] facings = EnumFacing.Plane.HORIZONTAL.facingsArray;
 ~ 						for (int m = 0; m < facings.length; ++m) {
@@ -56,7 +58,11 @@
 ~ 						for (int m = 0; m < facings.length; ++m) {
 ~ 							EnumFacing enumfacing1 = facings[m];
 
-> CHANGE  110 : 113  @  110 : 111
+> DELETE  5  @  5 : 6
+
+> DELETE  8  @  8 : 10
+
+> CHANGE  94 : 97  @  94 : 95
 
 ~ 				EnumFacing[] facings = EnumFacing.Plane.HORIZONTAL.facingsArray;
 ~ 				for (int m = 0; m < facings.length; ++m) {
diff --git a/patches/minecraft/net/minecraft/world/demo/DemoWorldServer.edit.java b/patches/minecraft/net/minecraft/world/demo/DemoWorldServer.edit.java
index cf86a389..407f74b1 100644
--- a/patches/minecraft/net/minecraft/world/demo/DemoWorldServer.edit.java
+++ b/patches/minecraft/net/minecraft/world/demo/DemoWorldServer.edit.java
@@ -5,7 +5,9 @@
 # Version: 1.0
 # Author: lax1dude
 
-> INSERT  10 : 12  @  10
+> DELETE  2  @  2 : 3
+
+> INSERT  7 : 9  @  7
 
 + import net.lax1dude.eaglercraft.v1_8.EaglercraftVersion;
 + 
@@ -14,4 +16,9 @@
 
 ~ 	private static final long demoWorldSeed = EaglercraftVersion.demoWorldSeed;
 
+> CHANGE  3 : 5  @  3 : 6
+
+~ 	public DemoWorldServer(MinecraftServer server, ISaveHandler saveHandlerIn, WorldInfo worldInfoIn, int dimensionId) {
+~ 		super(server, saveHandlerIn, worldInfoIn, dimensionId);
+
 > EOF
diff --git a/patches/minecraft/net/minecraft/world/storage/MapStorage.edit.java b/patches/minecraft/net/minecraft/world/storage/MapStorage.edit.java
index 94639279..cb10e24e 100644
--- a/patches/minecraft/net/minecraft/world/storage/MapStorage.edit.java
+++ b/patches/minecraft/net/minecraft/world/storage/MapStorage.edit.java
@@ -28,7 +28,7 @@
 + 		WorldSavedData createInstance(String mapFileName);
 + 	}
 + 
-+ 	public static final Map<Class<? extends WorldSavedData>, MapStorageProvider> storageProviders = new HashMap();
++ 	public static final Map<Class<? extends WorldSavedData>, MapStorageProvider> storageProviders = new HashMap<>();
 + 
 + 	static {
 + 		storageProviders.put(MapData.class, MapData::new);
diff --git a/patches/minecraft/net/minecraft/world/storage/SaveFormatOld.edit.java b/patches/minecraft/net/minecraft/world/storage/SaveFormatOld.edit.java
index 20217c76..72bfbca5 100644
--- a/patches/minecraft/net/minecraft/world/storage/SaveFormatOld.edit.java
+++ b/patches/minecraft/net/minecraft/world/storage/SaveFormatOld.edit.java
@@ -13,9 +13,10 @@
 
 > DELETE  2  @  2 : 3
 
-> INSERT  2 : 3  @  2
+> INSERT  2 : 4  @  2
 
 + import net.lax1dude.eaglercraft.v1_8.sp.server.EaglerIntegratedServerWorker;
++ import net.lax1dude.eaglercraft.v1_8.sp.server.WorldsDB;
 
 > CHANGE  1 : 4  @  1 : 8
 
@@ -41,11 +42,11 @@
 
 > CHANGE  10 : 11  @  10 : 11
 
-~ 		VFile2 file1 = new VFile2(this.savesDirectory, saveName);
+~ 		VFile2 file1 = WorldsDB.newVFile(this.savesDirectory, saveName);
 
 > CHANGE  3 : 4  @  3 : 4
 
-~ 			VFile2 file2 = new VFile2(file1, "level.dat");
+~ 			VFile2 file2 = WorldsDB.newVFile(file1, "level.dat");
 
 > CHANGE  2 : 6  @  2 : 3
 
@@ -56,7 +57,7 @@
 
 > CHANGE  7 : 8  @  7 : 8
 
-~ 			file2 = new VFile2(file1, "level.dat_old");
+~ 			file2 = WorldsDB.newVFile(file1, "level.dat_old");
 
 > CHANGE  2 : 6  @  2 : 3
 
@@ -68,8 +69,8 @@
 > CHANGE  11 : 15  @  11 : 15
 
 ~ 	public boolean renameWorld(String dirName, String newName) {
-~ 		VFile2 file1 = new VFile2(this.savesDirectory, dirName);
-~ 		VFile2 file2 = new VFile2(file1, "level.dat");
+~ 		VFile2 file1 = WorldsDB.newVFile(this.savesDirectory, dirName);
+~ 		VFile2 file2 = WorldsDB.newVFile(file1, "level.dat");
 ~ 		{
 
 > CHANGE  2 : 6  @  2 : 3
@@ -99,7 +100,7 @@
 
 > CHANGE  3 : 5  @  3 : 8
 
-~ 		VFile2 file1 = new VFile2(this.savesDirectory, parString1);
+~ 		VFile2 file1 = WorldsDB.newVFile(this.savesDirectory, parString1);
 ~ 		logger.info("Deleting level " + parString1);
 
 > CHANGE  1 : 6  @  1 : 6
@@ -148,7 +149,7 @@
 
 > CHANGE  15 : 17  @  15 : 17
 
-~ 		return (new VFile2(this.savesDirectory, parString1, "level.dat")).exists()
-~ 				|| (new VFile2(this.savesDirectory, parString1, "level.dat_old")).exists();
+~ 		return (WorldsDB.newVFile(this.savesDirectory, parString1, "level.dat")).exists()
+~ 				|| (WorldsDB.newVFile(this.savesDirectory, parString1, "level.dat_old")).exists();
 
 > EOF
diff --git a/patches/minecraft/net/minecraft/world/storage/SaveHandler.edit.java b/patches/minecraft/net/minecraft/world/storage/SaveHandler.edit.java
index 9f2e41fc..26191aff 100644
--- a/patches/minecraft/net/minecraft/world/storage/SaveHandler.edit.java
+++ b/patches/minecraft/net/minecraft/world/storage/SaveHandler.edit.java
@@ -12,11 +12,12 @@
 ~ import java.util.List;
 ~ 
 
-> CHANGE  7 : 10  @  7 : 12
+> CHANGE  7 : 11  @  7 : 12
 
 ~ import net.lax1dude.eaglercraft.v1_8.internal.vfs2.VFile2;
 ~ import net.lax1dude.eaglercraft.v1_8.log4j.LogManager;
 ~ import net.lax1dude.eaglercraft.v1_8.log4j.Logger;
+~ import net.lax1dude.eaglercraft.v1_8.sp.server.WorldsDB;
 
 > CHANGE  3 : 6  @  3 : 6
 
@@ -27,9 +28,9 @@
 > CHANGE  3 : 7  @  3 : 9
 
 ~ 	public SaveHandler(VFile2 savesDirectory, String directoryName) {
-~ 		this.worldDirectory = new VFile2(savesDirectory, directoryName);
-~ 		this.playersDirectory = new VFile2(this.worldDirectory, "player");
-~ 		this.mapDataDir = new VFile2(this.worldDirectory, "data");
+~ 		this.worldDirectory = WorldsDB.newVFile(savesDirectory, directoryName);
+~ 		this.playersDirectory = WorldsDB.newVFile(this.worldDirectory, "player");
+~ 		this.mapDataDir = WorldsDB.newVFile(this.worldDirectory, "data");
 
 > DELETE  1  @  1 : 4
 
@@ -47,7 +48,7 @@
 
 > CHANGE  3 : 4  @  3 : 4
 
-~ 		VFile2 file1 = new VFile2(this.worldDirectory, "level.dat");
+~ 		VFile2 file1 = WorldsDB.newVFile(this.worldDirectory, "level.dat");
 
 > CHANGE  1 : 3  @  1 : 3
 
@@ -61,7 +62,7 @@
 
 > CHANGE  3 : 4  @  3 : 4
 
-~ 		file1 = new VFile2(this.worldDirectory, "level.dat_old");
+~ 		file1 = WorldsDB.newVFile(this.worldDirectory, "level.dat_old");
 
 > CHANGE  1 : 3  @  1 : 3
 
@@ -75,9 +76,9 @@
 
 > CHANGE  12 : 18  @  12 : 16
 
-~ 			VFile2 file1 = new VFile2(this.worldDirectory, "level.dat_new");
-~ 			VFile2 file2 = new VFile2(this.worldDirectory, "level.dat_old");
-~ 			VFile2 file3 = new VFile2(this.worldDirectory, "level.dat");
+~ 			VFile2 file1 = WorldsDB.newVFile(this.worldDirectory, "level.dat_new");
+~ 			VFile2 file2 = WorldsDB.newVFile(this.worldDirectory, "level.dat_old");
+~ 			VFile2 file3 = WorldsDB.newVFile(this.worldDirectory, "level.dat");
 ~ 			try (OutputStream os = file1.getOutputStream()) {
 ~ 				CompressedStreamTools.writeCompressed(nbttagcompound2, os);
 ~ 			}
@@ -89,9 +90,9 @@
 
 > CHANGE  10 : 16  @  10 : 14
 
-~ 			VFile2 file1 = new VFile2(this.worldDirectory, "level.dat_new");
-~ 			VFile2 file2 = new VFile2(this.worldDirectory, "level.dat_old");
-~ 			VFile2 file3 = new VFile2(this.worldDirectory, "level.dat");
+~ 			VFile2 file1 = WorldsDB.newVFile(this.worldDirectory, "level.dat_new");
+~ 			VFile2 file2 = WorldsDB.newVFile(this.worldDirectory, "level.dat_old");
+~ 			VFile2 file3 = WorldsDB.newVFile(this.worldDirectory, "level.dat");
 ~ 			try (OutputStream os = file1.getOutputStream()) {
 ~ 				CompressedStreamTools.writeCompressed(nbttagcompound1, os);
 ~ 			}
@@ -104,8 +105,8 @@
 > CHANGE  8 : 14  @  8 : 11
 
 ~ 			String s = player.getName().toLowerCase();
-~ 			VFile2 file1 = new VFile2(this.playersDirectory, s + ".dat.tmp");
-~ 			VFile2 file2 = new VFile2(this.playersDirectory, s + ".dat");
+~ 			VFile2 file1 = WorldsDB.newVFile(this.playersDirectory, s + ".dat.tmp");
+~ 			VFile2 file2 = WorldsDB.newVFile(this.playersDirectory, s + ".dat");
 ~ 			try (OutputStream os = file1.getOutputStream()) {
 ~ 				CompressedStreamTools.writeCompressed(nbttagcompound, os);
 ~ 			}
@@ -117,7 +118,7 @@
 
 > CHANGE  8 : 13  @  8 : 11
 
-~ 			VFile2 file1 = new VFile2(this.playersDirectory, player.getName().toLowerCase() + ".dat");
+~ 			VFile2 file1 = WorldsDB.newVFile(this.playersDirectory, player.getName().toLowerCase() + ".dat");
 ~ 			if (file1.exists()) {
 ~ 				try (InputStream is = file1.getInputStream()) {
 ~ 					nbttagcompound = CompressedStreamTools.readCompressed(is);
@@ -146,6 +147,6 @@
 > CHANGE  5 : 7  @  5 : 7
 
 ~ 	public VFile2 getMapFileFromName(String mapName) {
-~ 		return new VFile2(this.mapDataDir, mapName + ".dat");
+~ 		return WorldsDB.newVFile(this.mapDataDir, mapName + ".dat");
 
 > EOF
diff --git a/patches/minecraft/net/minecraft/world/storage/WorldInfo.edit.java b/patches/minecraft/net/minecraft/world/storage/WorldInfo.edit.java
index 78992be2..c03cd0fb 100644
--- a/patches/minecraft/net/minecraft/world/storage/WorldInfo.edit.java
+++ b/patches/minecraft/net/minecraft/world/storage/WorldInfo.edit.java
@@ -5,7 +5,9 @@
 # Version: 1.0
 # Author: lax1dude
 
-> INSERT  12 : 14  @  12
+> DELETE  5  @  5 : 6
+
+> INSERT  6 : 8  @  6
 
 + import net.lax1dude.eaglercraft.v1_8.HString;
 + 
@@ -20,7 +22,11 @@
 
 + 		this.eaglerVersion = nbt.getInteger("eaglerVersionSerial");
 
-> INSERT  102 : 103  @  102
+> CHANGE  82 : 83  @  82 : 83
+
+~ 		nbt.setLong("LastPlayed", System.currentTimeMillis());
+
+> INSERT  19 : 20  @  19
 
 + 		nbt.setInteger("eaglerVersionSerial", this.eaglerVersion);
 
diff --git a/patches/resources/assets/minecraft/lang/en_US.edit.lang b/patches/resources/assets/minecraft/lang/en_US.edit.lang
index 9b7099f0..26b05afe 100644
--- a/patches/resources/assets/minecraft/lang/en_US.edit.lang
+++ b/patches/resources/assets/minecraft/lang/en_US.edit.lang
@@ -5,24 +5,19 @@
 # Version: 1.0
 # Author: lax1dude
 
-> CHANGE  17 : 21  @  17 : 24
+> CHANGE  17 : 25  @  17 : 24
 
-~ eaglercraft.recording.unsupported=Recording Unsupported!
-~ eaglercraft.recording.stop=Stop Recording
-~ eaglercraft.recording.start=Record Screen...
-~ eaglercraft.soundCategory.voice=Recording Voice
+~ eaglercraft.resourcePack.prompt.title=What do you want to do with '%s'?
+~ eaglercraft.resourcePack.prompt.text=Tip: Hold Shift to skip this screen when selecting a resource pack!
+~ eaglercraft.resourcePack.prompt.delete=Delete this resource pack
+~ eaglercraft.resourcePack.prompt.add=Select this resource pack
+~ eaglercraft.resourcePack.load.refreshing=Refreshing Resources...
+~ eaglercraft.resourcePack.load.pleaseWait=Please Wait.
+~ eaglercraft.resourcePack.load.loading=Loading resource pack...
+~ eaglercraft.resourcePack.load.deleting=Deleting resource pack...
 
-> INSERT  1 : 239  @  1
+> INSERT  1 : 231  @  1
 
-+ eaglercraft.resourcePack.prompt.title=What do you want to do with '%s'?
-+ eaglercraft.resourcePack.prompt.text=Tip: Hold Shift to skip this screen when selecting a resource pack!
-+ eaglercraft.resourcePack.prompt.delete=Delete this resource pack
-+ eaglercraft.resourcePack.prompt.add=Select this resource pack
-+ eaglercraft.resourcePack.load.refreshing=Refreshing Resources...
-+ eaglercraft.resourcePack.load.pleaseWait=Please Wait.
-+ eaglercraft.resourcePack.load.loading=Loading resource pack...
-+ eaglercraft.resourcePack.load.deleting=Deleting resource pack...
-+ 
 + eaglercraft.gui.exitKey=Use '%s' to close this screen!
 + eaglercraft.gui.exitKeyRetarded=Use Backtick (`) to close this screen!
 + eaglercraft.gui.continue=Continue
@@ -240,6 +235,7 @@
 + 
 + eaglercraft.shaders.gui.unsupported.title=Shaders are unavailable on this device!
 + eaglercraft.shaders.gui.unsupported.reason.hdrFramebuffer=Reason: No HDR render target support
++ eaglercraft.shaders.gui.unsupported.reason.oldOpenGLVersion=Reason: OpenGL ES 3.0 (WebGL 2.0) is not supported!
 + 
 + eaglercraft.shaders.debugMenuTip=Press %s+4 to access the shader debug menu
 + 
@@ -247,13 +243,13 @@
 + eaglercraft.command.skull.usage=/eagskull
 + eaglercraft.command.skull.nopermission=Cheats are not enabled!
 + eaglercraft.command.skull.feedback=Created new skull: "%s"
-+ eaglercraft.command.skull.error.invalid.png=Invalid PNG file!
++ eaglercraft.command.skull.error.invalid.format=Invalid or unsupported image file!
 + eaglercraft.command.skull.error.invalid.skin=Image with size %dx%d is not a valid minecraft skin!
 + 
 + eaglercraft.command.clientStub=This command is client side!
 + 
 
-> INSERT  163 : 409  @  163
+> INSERT  163 : 545  @  163
 
 + eaglercraft.singleplayer.busy.killTask=Cancel Task
 + eaglercraft.singleplayer.busy.cancelWarning=Are you sure?
@@ -262,13 +258,14 @@
 + eaglercraft.singleplayer.crashed.title=Recieved a crash report from integrated server!
 + eaglercraft.singleplayer.crashed.checkConsole=Check the console for more details
 + eaglercraft.singleplayer.crashed.continue=Continue
++ eaglercraft.singleplayer.crashed.singleThreadCont=Single Thread Mode
 + 
 + eaglercraft.singleplayer.failed.title=Singleplayer Task Failed!
 + eaglercraft.singleplayer.failed.killed=The worker process was killed
 + eaglercraft.singleplayer.failed.notStarted=The worker process could not start
 + 
-+ eaglercraft.singleplayer.failed.singleThreadWarning.1=Worker Thread Startup Failure!
-+ eaglercraft.singleplayer.failed.singleThreadWarning.2=The integrated server will run in single-threaded mode
++ eaglercraft.singleplayer.failed.singleThreadWarning.1=Worker Thread Issue Detected
++ eaglercraft.singleplayer.failed.singleThreadWarning.2=The integrated server is running in single-threaded mode
 + 
 + eaglercraft.singleplayer.busy.listingworlds=Loading worlds
 + eaglercraft.singleplayer.failed.listingworlds=Could not fetch worlds list!
@@ -342,11 +339,21 @@
 + eaglercraft.singleplayer.backup.clearPlayerData.warning1=Are you sure you want to delete all player data?
 + eaglercraft.singleplayer.backup.clearPlayerData.warning2=All players in '%s' will lose their inventories (besides %s)
 + 
++ eaglercraft.singleplayer.ramdiskdetected.title=Worker Issues Detected
++ eaglercraft.singleplayer.ramdiskdetected.text0=Running in "RAMDisk mode", worlds cannot be saved!
++ eaglercraft.singleplayer.ramdiskdetected.text1=Single thread mode may solve this issue
++ eaglercraft.singleplayer.ramdiskdetected.continue=Continue
++ eaglercraft.singleplayer.ramdiskdetected.singleThreadCont=Single Thread Mode
++ 
 + eaglercraft.selectWorld.backup=Backup
 + 
 + eaglercraft.selectWorld.duplicate=Duplicate World:
 + eaglercraft.selectWorld.duplicateButton=Duplicate
 + 
++ eaglercraft.selectWorld.ramdiskWarning=WARNING: Running in "RAMDisk mode", worlds will NOT be saved to local storage!
++ 
++ eaglercraft.singleplayer.tpscounter.singleThreadMode=Single Thread Mode
++ 
 + eaglercraft.networkSettings.title=Shared World Relay Servers
 + eaglercraft.networkSettings.add=Add Relay
 + eaglercraft.networkSettings.delete=Delete Relay
@@ -447,6 +454,27 @@
 + eaglercraft.updateList.note.0=Note: Updates are digitally signed, EaglercraftX will block any
 + eaglercraft.updateList.note.1=updates that were not created by lax1dude or ayunami2000
 + 
++ eaglercraft.updateSuccess.title=Update Successful
++ eaglercraft.updateSuccess.installToBootMenu=Install to Boot Menu
++ eaglercraft.updateSuccess.downloadOffline=Download Offline
++ 
++ eaglercraft.updateSuccess.downloading=Downloading Offline...
++ eaglercraft.updateSuccess.installing=Installing Client...
++ 
++ eaglercraft.updateFailed.title=Update Failed
++ 
++ eaglercraft.installFailed.title=Installation Failed
++ 
++ eaglercraft.updateInstall.title=Install to Boot Menu
++ eaglercraft.updateInstall.setDefault=Make Default
++ eaglercraft.updateInstall.setCountdown=Enable Countdown
++ eaglercraft.updateInstall.install=Install
++ 
++ eaglercraft.options.pressDeleteText=Press DEL to enter boot menu
++ 
++ eaglercraft.enterBootMenu.title=Enter Boot Menu
++ eaglercraft.enterBootMenu.text0=Refresh the page to enter the boot menu
++ 
 + eaglercraft.voice.title=Voice Channel
 + eaglercraft.voice.titleNoVoice=Voice is disabled on this server
 + eaglercraft.voice.titleVoiceUnavailable=Voice is unavailable
@@ -477,14 +505,15 @@
 + eaglercraft.voice.volumeMicrophoneLabel=Microphone:
 + 
 + eaglercraft.voice.unsupportedWarning1=Voice Warning
-+ eaglercraft.voice.unsupportedWarning2=Your network's firewall may not support
++ eaglercraft.voice.unsupportedWarning2=Your network configuration may not support
 + eaglercraft.voice.unsupportedWarning3=eaglercraft's voice chat.
-+ eaglercraft.voice.unsupportedWarning4=If your game doesn't work it's your issue
-+ eaglercraft.voice.unsupportedWarning5=to solve, not ayunami2000's or lax1dude's.
-+ eaglercraft.voice.unsupportedWarning6=Don't ask them to 'fix' it for you because
-+ eaglercraft.voice.unsupportedWarning7=they won't help you fix a problem that only
-+ eaglercraft.voice.unsupportedWarning8=you or your network's administrator has the
-+ eaglercraft.voice.unsupportedWarning9=ability to correctly resolve.
++ eaglercraft.voice.unsupportedWarning4=Voice chat is based on WebRTC and is
++ eaglercraft.voice.unsupportedWarning5=normally meant to be peer-to-peer, if your
++ eaglercraft.voice.unsupportedWarning6=firewall blocks peer-to-peer connections
++ eaglercraft.voice.unsupportedWarning7=a TURN server will be required.
++ eaglercraft.voice.unsupportedWarning8=The default OpenRelayProject TURN servers
++ eaglercraft.voice.unsupportedWarning9=are no longer working in 2024!
++ 
 + eaglercraft.voice.unsupportedWarning10=Continue
 + eaglercraft.voice.unsupportedWarning11=Cancel
 + 
@@ -494,16 +523,126 @@
 + eaglercraft.voice.ipGrabWarning4=also using voice on the server.
 + eaglercraft.voice.ipGrabWarning5=This issue will not be fixed, it is an
 + eaglercraft.voice.ipGrabWarning6=internal browser issue, not a mistake in the
-+ eaglercraft.voice.ipGrabWarning7=game. Fortunately, this can only be done if
-+ eaglercraft.voice.ipGrabWarning8=the other player uses a hacked web browser
-+ eaglercraft.voice.ipGrabWarning9=or has Wireshark to capture the voice
-+ eaglercraft.voice.ipGrabWarning10=packets, as there exists no real javascript
-+ eaglercraft.voice.ipGrabWarning11=method to log IPs using a normal skidded
-+ eaglercraft.voice.ipGrabWarning12=eaglercraft hacked client.
++ eaglercraft.voice.ipGrabWarning7=game. Sorry about that.
++ 
++ eaglercraft.revokeSessionToken.button=Revoke Session Token
++ eaglercraft.revokeSessionToken.title=Select session to revoke:
++ eaglercraft.revokeSessionToken.inspect=Inspect
++ eaglercraft.revokeSessionToken.revoke=Revoke
++ eaglercraft.revokeSessionToken.note.0=Use this tool when you believe someone has stolen your cookies
++ eaglercraft.revokeSessionToken.note.1=Eagler will request the server invalidate all session tokens
++ 
++ eaglercraft.inspectSessionToken.title=Cookie Details
++ eaglercraft.inspectSessionToken.details.server=Server Address:
++ eaglercraft.inspectSessionToken.details.expires=Expires At:
++ eaglercraft.inspectSessionToken.details.length=Byte Length:
++ 
++ eaglercraft.errorNoSessions.title=No Sessions Active!
++ eaglercraft.errorNoSessions.desc=There are no revokable sessions
++ 
++ eaglercraft.revokeSendingScreen.title=Revoking Session
++ eaglercraft.revokeSendingScreen.message.opening=Connecting to %s...
++ eaglercraft.revokeSendingScreen.message.sending=Sending Request...
++ 
++ eaglercraft.revokeSuccess.title=Revoke Success
++ eaglercraft.revokeSuccess.desc=The session was revoked sucessfully!
++ 
++ eaglercraft.revokeFailure.title=Revoke Failed
++ eaglercraft.revokeFailure.desc.notSupported=The server does not support this feature!
++ eaglercraft.revokeFailure.desc.notAllowed=The server does not allow revoking this token!
++ eaglercraft.revokeFailure.desc.notFound=The session was not found on the server!
++ eaglercraft.revokeFailure.desc.serverError=Internal server error!
++ eaglercraft.revokeFailure.desc.clientError=Error handling server's response!
++ eaglercraft.revokeFailure.desc.genericCode=Error code received! (Check Console)
++ eaglercraft.revokeFailure.desc.connectionError=Failed to connect to the server!
++ eaglercraft.revokeFailure.desc.cancelled=Connection closed
++ 
++ eaglercraft.recieveServerInfo.title=Retrieving Server Info
++ eaglercraft.recieveServerInfo.checkingCache=Checking Cache
++ eaglercraft.recieveServerInfo.contactingServer=Contacting Server
++ eaglercraft.recieveServerInfo.recievingData=Recieving Data
++ eaglercraft.recieveServerInfo.decompressing=Decompressing + Verifying
++ 
++ eaglercraft.serverInfoFailure.title=Retrieval Failed
++ eaglercraft.serverInfoFailure.desc=Failed to retrieve server info!
++ 
++ eaglercraft.webviewNotSupported.title=WebView Error
++ eaglercraft.webviewNotSupported.desc=WebView is not supported on this platform!
++ 
++ eaglercraft.webviewInvalidURL.title=WebView Error
++ eaglercraft.webviewInvalidURL.desc=Server provided an invalid URL!
++ 
++ eaglercraft.fallbackWebViewScreen.text0=View in your browser at:
++ eaglercraft.fallbackWebViewScreen.startingUp=Starting Up...
++ eaglercraft.fallbackWebViewScreen.pleaseWait=Please Wait...
++ eaglercraft.fallbackWebViewScreen.exited=(exited)
++ eaglercraft.fallbackWebViewScreen.openButton=Open
++ eaglercraft.fallbackWebViewScreen.exitButton=Exit
++ 
++ eaglercraft.webviewPhishingWaring.title=WARNING!!!
++ eaglercraft.webviewPhishingWaring.text0=If you see a login page, think before you enter a password
++ eaglercraft.webviewPhishingWaring.text1=Passwords can be stolen by the owner of this server or website
++ eaglercraft.webviewPhishingWaring.text2=Do not log in to accounts you don't want hackers to steal
++ eaglercraft.webviewPhishingWaring.dontShowAgain=Do not show this message again
++ eaglercraft.webviewPhishingWaring.continue=Continue
++ 
++ eaglercraft.notifications.title=Notifications
++ eaglercraft.notifications.priority=Priority: %s
++ eaglercraft.notifications.priority.low=All
++ eaglercraft.notifications.priority.normal=Info
++ eaglercraft.notifications.priority.higher=Warning
++ eaglercraft.notifications.priority.highest=Severe
++ eaglercraft.notifications.clearAll=Clear All
++ 
++ eaglercraft.options.touchControlOpacity=Touch Ctrls Opacity
++ 
++ eaglercraft.options.profanityFilterButton=Profanity Filter
++ 
++ eaglercraft.profanityFilterWarning.title=Content Warning
++ eaglercraft.profanityFilterWarning.text0=If you are streaming this game on Twitch, or
++ eaglercraft.profanityFilterWarning.text1=are under the wise old age of 14, please enable
++ eaglercraft.profanityFilterWarning.text2=the profanity filter before playing Multiplayer
++ eaglercraft.profanityFilterWarning.text4=(Disable in the 'Options' -> 'Chat Settings' menu)
++ 
++ eaglercraft.options.screenRecording.unsupported=Recording Unsupported!
++ eaglercraft.options.screenRecording.button=Record Screen...
++ 
++ eaglercraft.options.screenRecording.title=Screen Recording
++ eaglercraft.options.screenRecording.codec=Output Format: %s
++ eaglercraft.options.screenRecording.codecButton=Change...
++ eaglercraft.options.screenRecording.start=Start Recording
++ eaglercraft.options.screenRecording.stop=Stop Recording
++ eaglercraft.options.screenRecording.status=Status: %s
++ eaglercraft.options.screenRecording.status.0=Not Recording
++ eaglercraft.options.screenRecording.status.1=Recording!
++ eaglercraft.options.screenRecording.audioBitrate=Audio Bitrate
++ eaglercraft.options.screenRecording.videoBitrate=Video Bitrate
++ eaglercraft.options.screenRecording.videoResolution=Video Resolution
++ eaglercraft.options.screenRecording.microphoneVolume=Microphone Volume
++ eaglercraft.options.screenRecording.gameVolume=Game Volume
++ eaglercraft.options.screenRecording.videoFPS=Video Frame Rate
++ eaglercraft.options.screenRecording.onVSync=VSync
++ eaglercraft.options.screenRecording.failed=Failed to begin recording!
++ 
++ eaglercraft.options.recordingCodec.title=Select Codec
++ eaglercraft.options.recordingCodec.showAdvancedCodecs=Show Advanced: %s
++ 
++ eaglercraft.options.recordingNote.title=Recording Note
++ eaglercraft.options.recordingNote.text0=If the recorded video does not play,
++ eaglercraft.options.recordingNote.text1=try opening the file in your browser
++ 
++ eaglercraft.touch.interact.entity=Interact
 + 
 
-> CHANGE  22 : 23  @  22 : 23
+> INSERT  18 : 19  @  18
 
++ eaglercraft.addServer.hideAddr=Hide Addr
+
+> CHANGE  4 : 8  @  4 : 5
+
+~ eaglercraft.addServer.enableCookies=Cookies
+~ eaglercraft.addServer.enableCookies.enabled=Enabled
+~ eaglercraft.addServer.enableCookies.disabled=Disabled
 ~ lanServer.title=Shared World
 
 > CHANGE  1 : 2  @  1 : 2
diff --git a/sources/lwjgl/java/fi/iki/elonen/NanoHTTPD.java b/sources/lwjgl/java/fi/iki/elonen/NanoHTTPD.java
new file mode 100644
index 00000000..3cc7199a
--- /dev/null
+++ b/sources/lwjgl/java/fi/iki/elonen/NanoHTTPD.java
@@ -0,0 +1,2333 @@
+package fi.iki.elonen;
+
+/*
+ * #%L
+ * NanoHttpd-Core
+ * %%
+ * Copyright (C) 2012 - 2015 nanohttpd
+ * %%
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ * 
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ * 
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ * 
+ * 3. Neither the name of the nanohttpd nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software without
+ *    specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ * #L%
+ */
+
+import java.io.BufferedInputStream;
+import java.io.BufferedReader;
+import java.io.BufferedWriter;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.Closeable;
+import java.io.DataOutput;
+import java.io.DataOutputStream;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.FilterOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.io.PrintWriter;
+import java.io.RandomAccessFile;
+import java.io.UnsupportedEncodingException;
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.net.ServerSocket;
+import java.net.Socket;
+import java.net.SocketException;
+import java.net.SocketTimeoutException;
+import java.net.URL;
+import java.net.URLDecoder;
+import java.nio.ByteBuffer;
+import java.nio.channels.FileChannel;
+import java.nio.charset.Charset;
+import java.nio.charset.CharsetEncoder;
+import java.security.KeyStore;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Calendar;
+import java.util.Collections;
+import java.util.Date;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Properties;
+import java.util.StringTokenizer;
+import java.util.TimeZone;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import java.util.zip.GZIPOutputStream;
+
+import javax.net.ssl.KeyManager;
+import javax.net.ssl.KeyManagerFactory;
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLException;
+import javax.net.ssl.SSLServerSocket;
+import javax.net.ssl.SSLServerSocketFactory;
+import javax.net.ssl.TrustManagerFactory;
+
+import fi.iki.elonen.NanoHTTPD.Response.IStatus;
+import fi.iki.elonen.NanoHTTPD.Response.Status;
+
+/**
+ * A simple, tiny, nicely embeddable HTTP server in Java
+ * <p/>
+ * <p/>
+ * NanoHTTPD
+ * <p>
+ * Copyright (c) 2012-2013 by Paul S. Hawke, 2001,2005-2013 by Jarno Elonen,
+ * 2010 by Konstantinos Togias
+ * </p>
+ * <p/>
+ * <p/>
+ * <b>Features + limitations: </b>
+ * <ul>
+ * <p/>
+ * <li>Only one Java file</li>
+ * <li>Java 5 compatible</li>
+ * <li>Released as open source, Modified BSD licence</li>
+ * <li>No fixed config files, logging, authorization etc. (Implement yourself if
+ * you need them.)</li>
+ * <li>Supports parameter parsing of GET and POST methods (+ rudimentary PUT
+ * support in 1.25)</li>
+ * <li>Supports both dynamic content and file serving</li>
+ * <li>Supports file upload (since version 1.2, 2010)</li>
+ * <li>Supports partial content (streaming)</li>
+ * <li>Supports ETags</li>
+ * <li>Never caches anything</li>
+ * <li>Doesn't limit bandwidth, request time or simultaneous connections</li>
+ * <li>Default code serves files and shows all HTTP parameters and headers</li>
+ * <li>File server supports directory listing, index.html and index.htm</li>
+ * <li>File server supports partial content (streaming)</li>
+ * <li>File server supports ETags</li>
+ * <li>File server does the 301 redirection trick for directories without
+ * '/'</li>
+ * <li>File server supports simple skipping for files (continue download)</li>
+ * <li>File server serves also very long files without memory overhead</li>
+ * <li>Contains a built-in list of most common MIME types</li>
+ * <li>All header names are converted to lower case so they don't vary between
+ * browsers/clients</li>
+ * <p/>
+ * </ul>
+ * <p/>
+ * <p/>
+ * <b>How to use: </b>
+ * <ul>
+ * <p/>
+ * <li>Subclass and implement serve() and embed to your own program</li>
+ * <p/>
+ * </ul>
+ * <p/>
+ * See the separate "LICENSE.md" file for the distribution license (Modified BSD
+ * licence)
+ */
+public abstract class NanoHTTPD {
+
+	/**
+	 * Pluggable strategy for asynchronously executing requests.
+	 */
+	public interface AsyncRunner {
+
+		void closeAll();
+
+		void closed(ClientHandler clientHandler);
+
+		void exec(ClientHandler code);
+	}
+
+	/**
+	 * The runnable that will be used for every new client connection.
+	 */
+	public class ClientHandler implements Runnable {
+
+		private final InputStream inputStream;
+
+		private final Socket acceptSocket;
+
+		public ClientHandler(InputStream inputStream, Socket acceptSocket) {
+			this.inputStream = inputStream;
+			this.acceptSocket = acceptSocket;
+		}
+
+		public void close() {
+			safeClose(this.inputStream);
+			safeClose(this.acceptSocket);
+		}
+
+		@Override
+		public void run() {
+			OutputStream outputStream = null;
+			try {
+				outputStream = this.acceptSocket.getOutputStream();
+				TempFileManager tempFileManager = NanoHTTPD.this.tempFileManagerFactory.create();
+				HTTPSession session = new HTTPSession(tempFileManager, this.inputStream, outputStream,
+						this.acceptSocket.getInetAddress());
+				while (!this.acceptSocket.isClosed()) {
+					session.execute();
+				}
+			} catch (Exception e) {
+				// When the socket is closed by the client,
+				// we throw our own SocketException
+				// to break the "keep alive" loop above. If
+				// the exception was anything other
+				// than the expected SocketException OR a
+				// SocketTimeoutException, print the
+				// stacktrace
+				if (!(e instanceof SocketException && "NanoHttpd Shutdown".equals(e.getMessage()))
+						&& !(e instanceof SocketTimeoutException)) {
+					NanoHTTPD.LOG.log(Level.SEVERE,
+							"Communication with the client broken, or an bug in the handler code", e);
+				}
+			} finally {
+				safeClose(outputStream);
+				safeClose(this.inputStream);
+				safeClose(this.acceptSocket);
+				NanoHTTPD.this.asyncRunner.closed(this);
+			}
+		}
+	}
+
+	public static class Cookie {
+
+		public static String getHTTPTime(int days) {
+			Calendar calendar = Calendar.getInstance();
+			SimpleDateFormat dateFormat = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss z", Locale.US);
+			dateFormat.setTimeZone(TimeZone.getTimeZone("GMT"));
+			calendar.add(Calendar.DAY_OF_MONTH, days);
+			return dateFormat.format(calendar.getTime());
+		}
+
+		private final String n, v, e;
+
+		public Cookie(String name, String value) {
+			this(name, value, 30);
+		}
+
+		public Cookie(String name, String value, int numDays) {
+			this.n = name;
+			this.v = value;
+			this.e = getHTTPTime(numDays);
+		}
+
+		public Cookie(String name, String value, String expires) {
+			this.n = name;
+			this.v = value;
+			this.e = expires;
+		}
+
+		public String getHTTPHeader() {
+			String fmt = "%s=%s; expires=%s";
+			return String.format(fmt, this.n, this.v, this.e);
+		}
+	}
+
+	/**
+	 * Provides rudimentary support for cookies. Doesn't support 'path', 'secure'
+	 * nor 'httpOnly'. Feel free to improve it and/or add unsupported features.
+	 * 
+	 * @author LordFokas
+	 */
+	public class CookieHandler implements Iterable<String> {
+
+		private final HashMap<String, String> cookies = new HashMap<String, String>();
+
+		private final ArrayList<Cookie> queue = new ArrayList<Cookie>();
+
+		public CookieHandler(Map<String, String> httpHeaders) {
+			String raw = httpHeaders.get("cookie");
+			if (raw != null) {
+				String[] tokens = raw.split(";");
+				for (String token : tokens) {
+					String[] data = token.trim().split("=");
+					if (data.length == 2) {
+						this.cookies.put(data[0], data[1]);
+					}
+				}
+			}
+		}
+
+		/**
+		 * Set a cookie with an expiration date from a month ago, effectively deleting
+		 * it on the client side.
+		 * 
+		 * @param name The cookie name.
+		 */
+		public void delete(String name) {
+			set(name, "-delete-", -30);
+		}
+
+		@Override
+		public Iterator<String> iterator() {
+			return this.cookies.keySet().iterator();
+		}
+
+		/**
+		 * Read a cookie from the HTTP Headers.
+		 * 
+		 * @param name The cookie's name.
+		 * @return The cookie's value if it exists, null otherwise.
+		 */
+		public String read(String name) {
+			return this.cookies.get(name);
+		}
+
+		public void set(Cookie cookie) {
+			this.queue.add(cookie);
+		}
+
+		/**
+		 * Sets a cookie.
+		 * 
+		 * @param name    The cookie's name.
+		 * @param value   The cookie's value.
+		 * @param expires How many days until the cookie expires.
+		 */
+		public void set(String name, String value, int expires) {
+			this.queue.add(new Cookie(name, value, Cookie.getHTTPTime(expires)));
+		}
+
+		/**
+		 * Internally used by the webserver to add all queued cookies into the
+		 * Response's HTTP Headers.
+		 * 
+		 * @param response The Response object to which headers the queued cookies will
+		 *                 be added.
+		 */
+		public void unloadQueue(Response response) {
+			for (Cookie cookie : this.queue) {
+				response.addHeader("Set-Cookie", cookie.getHTTPHeader());
+			}
+		}
+	}
+
+	/**
+	 * Default threading strategy for NanoHTTPD.
+	 * <p/>
+	 * <p>
+	 * By default, the server spawns a new Thread for every incoming request. These
+	 * are set to <i>daemon</i> status, and named according to the request number.
+	 * The name is useful when profiling the application.
+	 * </p>
+	 */
+	public static class DefaultAsyncRunner implements AsyncRunner {
+
+		private long requestCount;
+
+		private final List<ClientHandler> running = Collections
+				.synchronizedList(new ArrayList<NanoHTTPD.ClientHandler>());
+
+		/**
+		 * @return a list with currently running clients.
+		 */
+		public List<ClientHandler> getRunning() {
+			return running;
+		}
+
+		@Override
+		public void closeAll() {
+			// copy of the list for concurrency
+			for (ClientHandler clientHandler : new ArrayList<ClientHandler>(this.running)) {
+				clientHandler.close();
+			}
+		}
+
+		@Override
+		public void closed(ClientHandler clientHandler) {
+			this.running.remove(clientHandler);
+		}
+
+		@Override
+		public void exec(ClientHandler clientHandler) {
+			++this.requestCount;
+			Thread t = new Thread(clientHandler);
+			t.setDaemon(true);
+			t.setName("NanoHttpd Request Processor (#" + this.requestCount + ")");
+			this.running.add(clientHandler);
+			t.start();
+		}
+	}
+
+	/**
+	 * Default strategy for creating and cleaning up temporary files.
+	 * <p/>
+	 * <p>
+	 * By default, files are created by <code>File.createTempFile()</code> in the
+	 * directory specified.
+	 * </p>
+	 */
+	public static class DefaultTempFile implements TempFile {
+
+		private final File file;
+
+		private final OutputStream fstream;
+
+		public DefaultTempFile(File tempdir) throws IOException {
+			this.file = File.createTempFile("NanoHTTPD-", "", tempdir);
+			this.fstream = new FileOutputStream(this.file);
+		}
+
+		@Override
+		public void delete() throws Exception {
+			safeClose(this.fstream);
+			if (!this.file.delete()) {
+				throw new Exception("could not delete temporary file: " + this.file.getAbsolutePath());
+			}
+		}
+
+		@Override
+		public String getName() {
+			return this.file.getAbsolutePath();
+		}
+
+		@Override
+		public OutputStream open() throws Exception {
+			return this.fstream;
+		}
+	}
+
+	/**
+	 * Default strategy for creating and cleaning up temporary files.
+	 * <p/>
+	 * <p>
+	 * This class stores its files in the standard location (that is, wherever
+	 * <code>java.io.tmpdir</code> points to). Files are added to an internal list,
+	 * and deleted when no longer needed (that is, when <code>clear()</code> is
+	 * invoked at the end of processing a request).
+	 * </p>
+	 */
+	public static class DefaultTempFileManager implements TempFileManager {
+
+		private final File tmpdir;
+
+		private final List<TempFile> tempFiles;
+
+		public DefaultTempFileManager() {
+			this.tmpdir = new File(System.getProperty("java.io.tmpdir"));
+			if (!tmpdir.exists()) {
+				tmpdir.mkdirs();
+			}
+			this.tempFiles = new ArrayList<TempFile>();
+		}
+
+		@Override
+		public void clear() {
+			for (TempFile file : this.tempFiles) {
+				try {
+					file.delete();
+				} catch (Exception ignored) {
+					NanoHTTPD.LOG.log(Level.WARNING, "could not delete file ", ignored);
+				}
+			}
+			this.tempFiles.clear();
+		}
+
+		@Override
+		public TempFile createTempFile(String filename_hint) throws Exception {
+			DefaultTempFile tempFile = new DefaultTempFile(this.tmpdir);
+			this.tempFiles.add(tempFile);
+			return tempFile;
+		}
+	}
+
+	/**
+	 * Default strategy for creating and cleaning up temporary files.
+	 */
+	private class DefaultTempFileManagerFactory implements TempFileManagerFactory {
+
+		@Override
+		public TempFileManager create() {
+			return new DefaultTempFileManager();
+		}
+	}
+
+	/**
+	 * Creates a normal ServerSocket for TCP connections
+	 */
+	public static class DefaultServerSocketFactory implements ServerSocketFactory {
+
+		@Override
+		public ServerSocket create() throws IOException {
+			return new ServerSocket();
+		}
+
+	}
+
+	/**
+	 * Creates a new SSLServerSocket
+	 */
+	public static class SecureServerSocketFactory implements ServerSocketFactory {
+
+		private SSLServerSocketFactory sslServerSocketFactory;
+
+		private String[] sslProtocols;
+
+		public SecureServerSocketFactory(SSLServerSocketFactory sslServerSocketFactory, String[] sslProtocols) {
+			this.sslServerSocketFactory = sslServerSocketFactory;
+			this.sslProtocols = sslProtocols;
+		}
+
+		@Override
+		public ServerSocket create() throws IOException {
+			SSLServerSocket ss = null;
+			ss = (SSLServerSocket) this.sslServerSocketFactory.createServerSocket();
+			if (this.sslProtocols != null) {
+				ss.setEnabledProtocols(this.sslProtocols);
+			} else {
+				ss.setEnabledProtocols(ss.getSupportedProtocols());
+			}
+			ss.setUseClientMode(false);
+			ss.setWantClientAuth(false);
+			ss.setNeedClientAuth(false);
+			return ss;
+		}
+
+	}
+
+	private static final String CONTENT_DISPOSITION_REGEX = "([ |\t]*Content-Disposition[ |\t]*:)(.*)";
+
+	private static final Pattern CONTENT_DISPOSITION_PATTERN = Pattern.compile(CONTENT_DISPOSITION_REGEX,
+			Pattern.CASE_INSENSITIVE);
+
+	private static final String CONTENT_TYPE_REGEX = "([ |\t]*content-type[ |\t]*:)(.*)";
+
+	private static final Pattern CONTENT_TYPE_PATTERN = Pattern.compile(CONTENT_TYPE_REGEX, Pattern.CASE_INSENSITIVE);
+
+	private static final String CONTENT_DISPOSITION_ATTRIBUTE_REGEX = "[ |\t]*([a-zA-Z]*)[ |\t]*=[ |\t]*['|\"]([^\"^']*)['|\"]";
+
+	private static final Pattern CONTENT_DISPOSITION_ATTRIBUTE_PATTERN = Pattern
+			.compile(CONTENT_DISPOSITION_ATTRIBUTE_REGEX);
+
+	protected static class ContentType {
+
+		private static final String ASCII_ENCODING = "US-ASCII";
+
+		private static final String MULTIPART_FORM_DATA_HEADER = "multipart/form-data";
+
+		private static final String CONTENT_REGEX = "[ |\t]*([^/^ ^;^,]+/[^ ^;^,]+)";
+
+		private static final Pattern MIME_PATTERN = Pattern.compile(CONTENT_REGEX, Pattern.CASE_INSENSITIVE);
+
+		private static final String CHARSET_REGEX = "[ |\t]*(charset)[ |\t]*=[ |\t]*['|\"]?([^\"^'^;^,]*)['|\"]?";
+
+		private static final Pattern CHARSET_PATTERN = Pattern.compile(CHARSET_REGEX, Pattern.CASE_INSENSITIVE);
+
+		private static final String BOUNDARY_REGEX = "[ |\t]*(boundary)[ |\t]*=[ |\t]*['|\"]?([^\"^'^;^,]*)['|\"]?";
+
+		private static final Pattern BOUNDARY_PATTERN = Pattern.compile(BOUNDARY_REGEX, Pattern.CASE_INSENSITIVE);
+
+		private final String contentTypeHeader;
+
+		private final String contentType;
+
+		private final String encoding;
+
+		private final String boundary;
+
+		public ContentType(String contentTypeHeader) {
+			this.contentTypeHeader = contentTypeHeader;
+			if (contentTypeHeader != null) {
+				contentType = getDetailFromContentHeader(contentTypeHeader, MIME_PATTERN, "", 1);
+				encoding = getDetailFromContentHeader(contentTypeHeader, CHARSET_PATTERN, null, 2);
+			} else {
+				contentType = "";
+				encoding = "UTF-8";
+			}
+			if (MULTIPART_FORM_DATA_HEADER.equalsIgnoreCase(contentType)) {
+				boundary = getDetailFromContentHeader(contentTypeHeader, BOUNDARY_PATTERN, null, 2);
+			} else {
+				boundary = null;
+			}
+		}
+
+		private String getDetailFromContentHeader(String contentTypeHeader, Pattern pattern, String defaultValue,
+				int group) {
+			Matcher matcher = pattern.matcher(contentTypeHeader);
+			return matcher.find() ? matcher.group(group) : defaultValue;
+		}
+
+		public String getContentTypeHeader() {
+			return contentTypeHeader;
+		}
+
+		public String getContentType() {
+			return contentType;
+		}
+
+		public String getEncoding() {
+			return encoding == null ? ASCII_ENCODING : encoding;
+		}
+
+		public String getBoundary() {
+			return boundary;
+		}
+
+		public boolean isMultipart() {
+			return MULTIPART_FORM_DATA_HEADER.equalsIgnoreCase(contentType);
+		}
+
+		public ContentType tryUTF8() {
+			if (encoding == null) {
+				return new ContentType(this.contentTypeHeader + "; charset=UTF-8");
+			}
+			return this;
+		}
+	}
+
+	protected class HTTPSession implements IHTTPSession {
+
+		private static final int REQUEST_BUFFER_LEN = 512;
+
+		private static final int MEMORY_STORE_LIMIT = 1024;
+
+		public static final int BUFSIZE = 8192;
+
+		public static final int MAX_HEADER_SIZE = 1024;
+
+		private final TempFileManager tempFileManager;
+
+		private final OutputStream outputStream;
+
+		private final BufferedInputStream inputStream;
+
+		private int splitbyte;
+
+		private int rlen;
+
+		private String uri;
+
+		private Method method;
+
+		private Map<String, List<String>> parms;
+
+		private Map<String, String> headers;
+
+		private CookieHandler cookies;
+
+		private String queryParameterString;
+
+		private String remoteIp;
+
+		private String remoteHostname;
+
+		private String protocolVersion;
+
+		public HTTPSession(TempFileManager tempFileManager, InputStream inputStream, OutputStream outputStream) {
+			this.tempFileManager = tempFileManager;
+			this.inputStream = new BufferedInputStream(inputStream, HTTPSession.BUFSIZE);
+			this.outputStream = outputStream;
+		}
+
+		public HTTPSession(TempFileManager tempFileManager, InputStream inputStream, OutputStream outputStream,
+				InetAddress inetAddress) {
+			this.tempFileManager = tempFileManager;
+			this.inputStream = new BufferedInputStream(inputStream, HTTPSession.BUFSIZE);
+			this.outputStream = outputStream;
+			this.remoteIp = inetAddress.isLoopbackAddress() || inetAddress.isAnyLocalAddress() ? "127.0.0.1"
+					: inetAddress.getHostAddress().toString();
+			this.remoteHostname = inetAddress.isLoopbackAddress() || inetAddress.isAnyLocalAddress() ? "localhost"
+					: inetAddress.getHostName().toString();
+			this.headers = new HashMap<String, String>();
+		}
+
+		/**
+		 * Decodes the sent headers and loads the data into Key/value pairs
+		 */
+		private void decodeHeader(BufferedReader in, Map<String, String> pre, Map<String, List<String>> parms,
+				Map<String, String> headers) throws ResponseException {
+			try {
+				// Read the request line
+				String inLine = in.readLine();
+				if (inLine == null) {
+					return;
+				}
+
+				StringTokenizer st = new StringTokenizer(inLine);
+				if (!st.hasMoreTokens()) {
+					throw new ResponseException(Response.Status.BAD_REQUEST,
+							"BAD REQUEST: Syntax error. Usage: GET /example/file.html");
+				}
+
+				pre.put("method", st.nextToken());
+
+				if (!st.hasMoreTokens()) {
+					throw new ResponseException(Response.Status.BAD_REQUEST,
+							"BAD REQUEST: Missing URI. Usage: GET /example/file.html");
+				}
+
+				String uri = st.nextToken();
+
+				// Decode parameters from the URI
+				int qmi = uri.indexOf('?');
+				if (qmi >= 0) {
+					decodeParms(uri.substring(qmi + 1), parms);
+					uri = decodePercent(uri.substring(0, qmi));
+				} else {
+					uri = decodePercent(uri);
+				}
+
+				// If there's another token, its protocol version,
+				// followed by HTTP headers.
+				// NOTE: this now forces header names lower case since they are
+				// case insensitive and vary by client.
+				if (st.hasMoreTokens()) {
+					protocolVersion = st.nextToken();
+				} else {
+					protocolVersion = "HTTP/1.1";
+					NanoHTTPD.LOG.log(Level.FINE, "no protocol version specified, strange. Assuming HTTP/1.1.");
+				}
+				String line = in.readLine();
+				while (line != null && !line.trim().isEmpty()) {
+					int p = line.indexOf(':');
+					if (p >= 0) {
+						headers.put(line.substring(0, p).trim().toLowerCase(Locale.US), line.substring(p + 1).trim());
+					}
+					line = in.readLine();
+				}
+
+				pre.put("uri", uri);
+			} catch (IOException ioe) {
+				throw new ResponseException(Response.Status.INTERNAL_ERROR,
+						"SERVER INTERNAL ERROR: IOException: " + ioe.getMessage(), ioe);
+			}
+		}
+
+		/**
+		 * Decodes the Multipart Body data and put it into Key/Value pairs.
+		 */
+		private void decodeMultipartFormData(ContentType contentType, ByteBuffer fbuf, Map<String, List<String>> parms,
+				Map<String, String> files) throws ResponseException {
+			int pcount = 0;
+			try {
+				int[] boundaryIdxs = getBoundaryPositions(fbuf, contentType.getBoundary().getBytes());
+				if (boundaryIdxs.length < 2) {
+					throw new ResponseException(Response.Status.BAD_REQUEST,
+							"BAD REQUEST: Content type is multipart/form-data but contains less than two boundary strings.");
+				}
+
+				byte[] partHeaderBuff = new byte[MAX_HEADER_SIZE];
+				for (int boundaryIdx = 0; boundaryIdx < boundaryIdxs.length - 1; boundaryIdx++) {
+					fbuf.position(boundaryIdxs[boundaryIdx]);
+					int len = (fbuf.remaining() < MAX_HEADER_SIZE) ? fbuf.remaining() : MAX_HEADER_SIZE;
+					fbuf.get(partHeaderBuff, 0, len);
+					BufferedReader in = new BufferedReader(
+							new InputStreamReader(new ByteArrayInputStream(partHeaderBuff, 0, len),
+									Charset.forName(contentType.getEncoding())),
+							len);
+
+					int headerLines = 0;
+					// First line is boundary string
+					String mpline = in.readLine();
+					headerLines++;
+					if (mpline == null || !mpline.contains(contentType.getBoundary())) {
+						throw new ResponseException(Response.Status.BAD_REQUEST,
+								"BAD REQUEST: Content type is multipart/form-data but chunk does not start with boundary.");
+					}
+
+					String partName = null, fileName = null, partContentType = null;
+					// Parse the reset of the header lines
+					mpline = in.readLine();
+					headerLines++;
+					while (mpline != null && mpline.trim().length() > 0) {
+						Matcher matcher = CONTENT_DISPOSITION_PATTERN.matcher(mpline);
+						if (matcher.matches()) {
+							String attributeString = matcher.group(2);
+							matcher = CONTENT_DISPOSITION_ATTRIBUTE_PATTERN.matcher(attributeString);
+							while (matcher.find()) {
+								String key = matcher.group(1);
+								if ("name".equalsIgnoreCase(key)) {
+									partName = matcher.group(2);
+								} else if ("filename".equalsIgnoreCase(key)) {
+									fileName = matcher.group(2);
+									// add these two line to support multiple
+									// files uploaded using the same field Id
+									if (!fileName.isEmpty()) {
+										if (pcount > 0)
+											partName = partName + String.valueOf(pcount++);
+										else
+											pcount++;
+									}
+								}
+							}
+						}
+						matcher = CONTENT_TYPE_PATTERN.matcher(mpline);
+						if (matcher.matches()) {
+							partContentType = matcher.group(2).trim();
+						}
+						mpline = in.readLine();
+						headerLines++;
+					}
+					int partHeaderLength = 0;
+					while (headerLines-- > 0) {
+						partHeaderLength = scipOverNewLine(partHeaderBuff, partHeaderLength);
+					}
+					// Read the part data
+					if (partHeaderLength >= len - 4) {
+						throw new ResponseException(Response.Status.INTERNAL_ERROR,
+								"Multipart header size exceeds MAX_HEADER_SIZE.");
+					}
+					int partDataStart = boundaryIdxs[boundaryIdx] + partHeaderLength;
+					int partDataEnd = boundaryIdxs[boundaryIdx + 1] - 4;
+
+					fbuf.position(partDataStart);
+
+					List<String> values = parms.get(partName);
+					if (values == null) {
+						values = new ArrayList<String>();
+						parms.put(partName, values);
+					}
+
+					if (partContentType == null) {
+						// Read the part into a string
+						byte[] data_bytes = new byte[partDataEnd - partDataStart];
+						fbuf.get(data_bytes);
+
+						values.add(new String(data_bytes, contentType.getEncoding()));
+					} else {
+						// Read it into a file
+						String path = saveTmpFile(fbuf, partDataStart, partDataEnd - partDataStart, fileName);
+						if (!files.containsKey(partName)) {
+							files.put(partName, path);
+						} else {
+							int count = 2;
+							while (files.containsKey(partName + count)) {
+								count++;
+							}
+							files.put(partName + count, path);
+						}
+						values.add(fileName);
+					}
+				}
+			} catch (ResponseException re) {
+				throw re;
+			} catch (Exception e) {
+				throw new ResponseException(Response.Status.INTERNAL_ERROR, e.toString());
+			}
+		}
+
+		private int scipOverNewLine(byte[] partHeaderBuff, int index) {
+			while (partHeaderBuff[index] != '\n') {
+				index++;
+			}
+			return ++index;
+		}
+
+		/**
+		 * Decodes parameters in percent-encoded URI-format ( e.g.
+		 * "name=Jack%20Daniels&pass=Single%20Malt" ) and adds them to given Map.
+		 */
+		private void decodeParms(String parms, Map<String, List<String>> p) {
+			if (parms == null) {
+				this.queryParameterString = "";
+				return;
+			}
+
+			this.queryParameterString = parms;
+			StringTokenizer st = new StringTokenizer(parms, "&");
+			while (st.hasMoreTokens()) {
+				String e = st.nextToken();
+				int sep = e.indexOf('=');
+				String key = null;
+				String value = null;
+
+				if (sep >= 0) {
+					key = decodePercent(e.substring(0, sep)).trim();
+					value = decodePercent(e.substring(sep + 1));
+				} else {
+					key = decodePercent(e).trim();
+					value = "";
+				}
+
+				List<String> values = p.get(key);
+				if (values == null) {
+					values = new ArrayList<String>();
+					p.put(key, values);
+				}
+
+				values.add(value);
+			}
+		}
+
+		@Override
+		public void execute() throws IOException {
+			Response r = null;
+			try {
+				// Read the first 8192 bytes.
+				// The full header should fit in here.
+				// Apache's default header limit is 8KB.
+				// Do NOT assume that a single read will get the entire header
+				// at once!
+				byte[] buf = new byte[HTTPSession.BUFSIZE];
+				this.splitbyte = 0;
+				this.rlen = 0;
+
+				int read = -1;
+				this.inputStream.mark(HTTPSession.BUFSIZE);
+				try {
+					read = this.inputStream.read(buf, 0, HTTPSession.BUFSIZE);
+				} catch (SSLException e) {
+					throw e;
+				} catch (IOException e) {
+					safeClose(this.inputStream);
+					safeClose(this.outputStream);
+					throw new SocketException("NanoHttpd Shutdown");
+				}
+				if (read == -1) {
+					// socket was been closed
+					safeClose(this.inputStream);
+					safeClose(this.outputStream);
+					throw new SocketException("NanoHttpd Shutdown");
+				}
+				while (read > 0) {
+					this.rlen += read;
+					this.splitbyte = findHeaderEnd(buf, this.rlen);
+					if (this.splitbyte > 0) {
+						break;
+					}
+					read = this.inputStream.read(buf, this.rlen, HTTPSession.BUFSIZE - this.rlen);
+				}
+
+				if (this.splitbyte < this.rlen) {
+					this.inputStream.reset();
+					this.inputStream.skip(this.splitbyte);
+				}
+
+				this.parms = new HashMap<String, List<String>>();
+				if (null == this.headers) {
+					this.headers = new HashMap<String, String>();
+				} else {
+					this.headers.clear();
+				}
+
+				// Create a BufferedReader for parsing the header.
+				BufferedReader hin = new BufferedReader(
+						new InputStreamReader(new ByteArrayInputStream(buf, 0, this.rlen)));
+
+				// Decode the header into parms and header java properties
+				Map<String, String> pre = new HashMap<String, String>();
+				decodeHeader(hin, pre, this.parms, this.headers);
+
+				if (null != this.remoteIp) {
+					this.headers.put("remote-addr", this.remoteIp);
+					this.headers.put("http-client-ip", this.remoteIp);
+				}
+
+				this.method = Method.lookup(pre.get("method"));
+				if (this.method == null) {
+					throw new ResponseException(Response.Status.BAD_REQUEST,
+							"BAD REQUEST: Syntax error. HTTP verb " + pre.get("method") + " unhandled.");
+				}
+
+				this.uri = pre.get("uri");
+
+				this.cookies = new CookieHandler(this.headers);
+
+				String connection = this.headers.get("connection");
+				boolean keepAlive = "HTTP/1.1".equals(protocolVersion)
+						&& (connection == null || !connection.matches("(?i).*close.*"));
+
+				// Ok, now do the serve()
+
+				// TODO: long body_size = getBodySize();
+				// TODO: long pos_before_serve = this.inputStream.totalRead()
+				// (requires implementation for totalRead())
+				r = serve(this);
+				// TODO: this.inputStream.skip(body_size -
+				// (this.inputStream.totalRead() - pos_before_serve))
+
+				if (r == null) {
+					throw new ResponseException(Response.Status.INTERNAL_ERROR,
+							"SERVER INTERNAL ERROR: Serve() returned a null response.");
+				} else {
+					String acceptEncoding = this.headers.get("accept-encoding");
+					this.cookies.unloadQueue(r);
+					r.setRequestMethod(this.method);
+					r.setGzipEncoding(
+							useGzipWhenAccepted(r) && acceptEncoding != null && acceptEncoding.contains("gzip"));
+					r.setKeepAlive(keepAlive);
+					r.send(this.outputStream);
+				}
+				if (!keepAlive || r.isCloseConnection()) {
+					throw new SocketException("NanoHttpd Shutdown");
+				}
+			} catch (SocketException e) {
+				// throw it out to close socket object (finalAccept)
+				throw e;
+			} catch (SocketTimeoutException ste) {
+				// treat socket timeouts the same way we treat socket exceptions
+				// i.e. close the stream & finalAccept object by throwing the
+				// exception up the call stack.
+				throw ste;
+			} catch (SSLException ssle) {
+				Response resp = newFixedLengthResponse(Response.Status.INTERNAL_ERROR, NanoHTTPD.MIME_PLAINTEXT,
+						"SSL PROTOCOL FAILURE: " + ssle.getMessage());
+				resp.send(this.outputStream);
+				safeClose(this.outputStream);
+			} catch (IOException ioe) {
+				Response resp = newFixedLengthResponse(Response.Status.INTERNAL_ERROR, NanoHTTPD.MIME_PLAINTEXT,
+						"SERVER INTERNAL ERROR: IOException: " + ioe.getMessage());
+				resp.send(this.outputStream);
+				safeClose(this.outputStream);
+			} catch (ResponseException re) {
+				Response resp = newFixedLengthResponse(re.getStatus(), NanoHTTPD.MIME_PLAINTEXT, re.getMessage());
+				resp.send(this.outputStream);
+				safeClose(this.outputStream);
+			} finally {
+				safeClose(r);
+				this.tempFileManager.clear();
+			}
+		}
+
+		/**
+		 * Find byte index separating header from body. It must be the last byte of the
+		 * first two sequential new lines.
+		 */
+		private int findHeaderEnd(final byte[] buf, int rlen) {
+			int splitbyte = 0;
+			while (splitbyte + 1 < rlen) {
+
+				// RFC2616
+				if (buf[splitbyte] == '\r' && buf[splitbyte + 1] == '\n' && splitbyte + 3 < rlen
+						&& buf[splitbyte + 2] == '\r' && buf[splitbyte + 3] == '\n') {
+					return splitbyte + 4;
+				}
+
+				// tolerance
+				if (buf[splitbyte] == '\n' && buf[splitbyte + 1] == '\n') {
+					return splitbyte + 2;
+				}
+				splitbyte++;
+			}
+			return 0;
+		}
+
+		/**
+		 * Find the byte positions where multipart boundaries start. This reads a large
+		 * block at a time and uses a temporary buffer to optimize (memory mapped) file
+		 * access.
+		 */
+		private int[] getBoundaryPositions(ByteBuffer b, byte[] boundary) {
+			int[] res = new int[0];
+			if (b.remaining() < boundary.length) {
+				return res;
+			}
+
+			int search_window_pos = 0;
+			byte[] search_window = new byte[4 * 1024 + boundary.length];
+
+			int first_fill = (b.remaining() < search_window.length) ? b.remaining() : search_window.length;
+			b.get(search_window, 0, first_fill);
+			int new_bytes = first_fill - boundary.length;
+
+			do {
+				// Search the search_window
+				for (int j = 0; j < new_bytes; j++) {
+					for (int i = 0; i < boundary.length; i++) {
+						if (search_window[j + i] != boundary[i])
+							break;
+						if (i == boundary.length - 1) {
+							// Match found, add it to results
+							int[] new_res = new int[res.length + 1];
+							System.arraycopy(res, 0, new_res, 0, res.length);
+							new_res[res.length] = search_window_pos + j;
+							res = new_res;
+						}
+					}
+				}
+				search_window_pos += new_bytes;
+
+				// Copy the end of the buffer to the start
+				System.arraycopy(search_window, search_window.length - boundary.length, search_window, 0,
+						boundary.length);
+
+				// Refill search_window
+				new_bytes = search_window.length - boundary.length;
+				new_bytes = (b.remaining() < new_bytes) ? b.remaining() : new_bytes;
+				b.get(search_window, boundary.length, new_bytes);
+			} while (new_bytes > 0);
+			return res;
+		}
+
+		@Override
+		public CookieHandler getCookies() {
+			return this.cookies;
+		}
+
+		@Override
+		public final Map<String, String> getHeaders() {
+			return this.headers;
+		}
+
+		@Override
+		public final InputStream getInputStream() {
+			return this.inputStream;
+		}
+
+		@Override
+		public final Method getMethod() {
+			return this.method;
+		}
+
+		/**
+		 * @deprecated use {@link #getParameters()} instead.
+		 */
+		@Override
+		@Deprecated
+		public final Map<String, String> getParms() {
+			Map<String, String> result = new HashMap<String, String>();
+			for (String key : this.parms.keySet()) {
+				result.put(key, this.parms.get(key).get(0));
+			}
+
+			return result;
+		}
+
+		@Override
+		public final Map<String, List<String>> getParameters() {
+			return this.parms;
+		}
+
+		@Override
+		public String getQueryParameterString() {
+			return this.queryParameterString;
+		}
+
+		private RandomAccessFile getTmpBucket() {
+			try {
+				TempFile tempFile = this.tempFileManager.createTempFile(null);
+				return new RandomAccessFile(tempFile.getName(), "rw");
+			} catch (Exception e) {
+				throw new Error(e); // we won't recover, so throw an error
+			}
+		}
+
+		@Override
+		public final String getUri() {
+			return this.uri;
+		}
+
+		/**
+		 * Deduce body length in bytes. Either from "content-length" header or read
+		 * bytes.
+		 */
+		public long getBodySize() {
+			if (this.headers.containsKey("content-length")) {
+				return Long.parseLong(this.headers.get("content-length"));
+			} else if (this.splitbyte < this.rlen) {
+				return this.rlen - this.splitbyte;
+			}
+			return 0;
+		}
+
+		@Override
+		public void parseBody(Map<String, String> files) throws IOException, ResponseException {
+			RandomAccessFile randomAccessFile = null;
+			try {
+				long size = getBodySize();
+				ByteArrayOutputStream baos = null;
+				DataOutput requestDataOutput = null;
+
+				// Store the request in memory or a file, depending on size
+				if (size < MEMORY_STORE_LIMIT) {
+					baos = new ByteArrayOutputStream();
+					requestDataOutput = new DataOutputStream(baos);
+				} else {
+					randomAccessFile = getTmpBucket();
+					requestDataOutput = randomAccessFile;
+				}
+
+				// Read all the body and write it to request_data_output
+				byte[] buf = new byte[REQUEST_BUFFER_LEN];
+				while (this.rlen >= 0 && size > 0) {
+					this.rlen = this.inputStream.read(buf, 0, (int) Math.min(size, REQUEST_BUFFER_LEN));
+					size -= this.rlen;
+					if (this.rlen > 0) {
+						requestDataOutput.write(buf, 0, this.rlen);
+					}
+				}
+
+				ByteBuffer fbuf = null;
+				if (baos != null) {
+					fbuf = ByteBuffer.wrap(baos.toByteArray(), 0, baos.size());
+				} else {
+					fbuf = randomAccessFile.getChannel().map(FileChannel.MapMode.READ_ONLY, 0,
+							randomAccessFile.length());
+					randomAccessFile.seek(0);
+				}
+
+				// If the method is POST, there may be parameters
+				// in data section, too, read it:
+				if (Method.POST.equals(this.method)) {
+					ContentType contentType = new ContentType(this.headers.get("content-type"));
+					if (contentType.isMultipart()) {
+						String boundary = contentType.getBoundary();
+						if (boundary == null) {
+							throw new ResponseException(Response.Status.BAD_REQUEST,
+									"BAD REQUEST: Content type is multipart/form-data but boundary missing. Usage: GET /example/file.html");
+						}
+						decodeMultipartFormData(contentType, fbuf, this.parms, files);
+					} else {
+						byte[] postBytes = new byte[fbuf.remaining()];
+						fbuf.get(postBytes);
+						String postLine = new String(postBytes, contentType.getEncoding()).trim();
+						// Handle application/x-www-form-urlencoded
+						if ("application/x-www-form-urlencoded".equalsIgnoreCase(contentType.getContentType())) {
+							decodeParms(postLine, this.parms);
+						} else if (postLine.length() != 0) {
+							// Special case for raw POST data => create a
+							// special files entry "postData" with raw content
+							// data
+							files.put("postData", postLine);
+						}
+					}
+				} else if (Method.PUT.equals(this.method)) {
+					files.put("content", saveTmpFile(fbuf, 0, fbuf.limit(), null));
+				}
+			} finally {
+				safeClose(randomAccessFile);
+			}
+		}
+
+		/**
+		 * Retrieves the content of a sent file and saves it to a temporary file. The
+		 * full path to the saved file is returned.
+		 */
+		private String saveTmpFile(ByteBuffer b, int offset, int len, String filename_hint) {
+			String path = "";
+			if (len > 0) {
+				FileOutputStream fileOutputStream = null;
+				try {
+					TempFile tempFile = this.tempFileManager.createTempFile(filename_hint);
+					ByteBuffer src = b.duplicate();
+					fileOutputStream = new FileOutputStream(tempFile.getName());
+					FileChannel dest = fileOutputStream.getChannel();
+					src.position(offset).limit(offset + len);
+					dest.write(src.slice());
+					path = tempFile.getName();
+				} catch (Exception e) { // Catch exception if any
+					throw new Error(e); // we won't recover, so throw an error
+				} finally {
+					safeClose(fileOutputStream);
+				}
+			}
+			return path;
+		}
+
+		@Override
+		public String getRemoteIpAddress() {
+			return this.remoteIp;
+		}
+
+		@Override
+		public String getRemoteHostName() {
+			return this.remoteHostname;
+		}
+	}
+
+	/**
+	 * Handles one session, i.e. parses the HTTP request and returns the response.
+	 */
+	public interface IHTTPSession {
+
+		void execute() throws IOException;
+
+		CookieHandler getCookies();
+
+		Map<String, String> getHeaders();
+
+		InputStream getInputStream();
+
+		Method getMethod();
+
+		/**
+		 * This method will only return the first value for a given parameter. You will
+		 * want to use getParameters if you expect multiple values for a given key.
+		 * 
+		 * @deprecated use {@link #getParameters()} instead.
+		 */
+		@Deprecated
+		Map<String, String> getParms();
+
+		Map<String, List<String>> getParameters();
+
+		String getQueryParameterString();
+
+		/**
+		 * @return the path part of the URL.
+		 */
+		String getUri();
+
+		/**
+		 * Adds the files in the request body to the files map.
+		 * 
+		 * @param files map to modify
+		 */
+		void parseBody(Map<String, String> files) throws IOException, ResponseException;
+
+		/**
+		 * Get the remote ip address of the requester.
+		 * 
+		 * @return the IP address.
+		 */
+		String getRemoteIpAddress();
+
+		/**
+		 * Get the remote hostname of the requester.
+		 * 
+		 * @return the hostname.
+		 */
+		String getRemoteHostName();
+	}
+
+	/**
+	 * HTTP Request methods, with the ability to decode a <code>String</code> back
+	 * to its enum value.
+	 */
+	public enum Method {
+		GET, PUT, POST, DELETE, HEAD, OPTIONS, TRACE, CONNECT, PATCH, PROPFIND, PROPPATCH, MKCOL, MOVE, COPY, LOCK,
+		UNLOCK;
+
+		static Method lookup(String method) {
+			if (method == null)
+				return null;
+
+			try {
+				return valueOf(method);
+			} catch (IllegalArgumentException e) {
+				// TODO: Log it?
+				return null;
+			}
+		}
+	}
+
+	/**
+	 * HTTP response. Return one of these from serve().
+	 */
+	public static class Response implements Closeable {
+
+		public interface IStatus {
+
+			String getDescription();
+
+			int getRequestStatus();
+		}
+
+		/**
+		 * Some HTTP response status codes
+		 */
+		public enum Status implements IStatus {
+			SWITCH_PROTOCOL(101, "Switching Protocols"),
+
+			OK(200, "OK"), CREATED(201, "Created"), ACCEPTED(202, "Accepted"), NO_CONTENT(204, "No Content"),
+			PARTIAL_CONTENT(206, "Partial Content"), MULTI_STATUS(207, "Multi-Status"),
+
+			REDIRECT(301, "Moved Permanently"),
+			/**
+			 * Many user agents mishandle 302 in ways that violate the RFC1945 spec (i.e.,
+			 * redirect a POST to a GET). 303 and 307 were added in RFC2616 to address this.
+			 * You should prefer 303 and 307 unless the calling user agent does not support
+			 * 303 and 307 functionality
+			 */
+			@Deprecated
+			FOUND(302, "Found"), REDIRECT_SEE_OTHER(303, "See Other"), NOT_MODIFIED(304, "Not Modified"),
+			TEMPORARY_REDIRECT(307, "Temporary Redirect"),
+
+			BAD_REQUEST(400, "Bad Request"), UNAUTHORIZED(401, "Unauthorized"), FORBIDDEN(403, "Forbidden"),
+			NOT_FOUND(404, "Not Found"), METHOD_NOT_ALLOWED(405, "Method Not Allowed"),
+			NOT_ACCEPTABLE(406, "Not Acceptable"), REQUEST_TIMEOUT(408, "Request Timeout"), CONFLICT(409, "Conflict"),
+			GONE(410, "Gone"), LENGTH_REQUIRED(411, "Length Required"), PRECONDITION_FAILED(412, "Precondition Failed"),
+			PAYLOAD_TOO_LARGE(413, "Payload Too Large"), UNSUPPORTED_MEDIA_TYPE(415, "Unsupported Media Type"),
+			RANGE_NOT_SATISFIABLE(416, "Requested Range Not Satisfiable"),
+			EXPECTATION_FAILED(417, "Expectation Failed"), TOO_MANY_REQUESTS(429, "Too Many Requests"),
+
+			INTERNAL_ERROR(500, "Internal Server Error"), NOT_IMPLEMENTED(501, "Not Implemented"),
+			SERVICE_UNAVAILABLE(503, "Service Unavailable"),
+			UNSUPPORTED_HTTP_VERSION(505, "HTTP Version Not Supported");
+
+			private final int requestStatus;
+
+			private final String description;
+
+			Status(int requestStatus, String description) {
+				this.requestStatus = requestStatus;
+				this.description = description;
+			}
+
+			public static Status lookup(int requestStatus) {
+				for (Status status : Status.values()) {
+					if (status.getRequestStatus() == requestStatus) {
+						return status;
+					}
+				}
+				return null;
+			}
+
+			@Override
+			public String getDescription() {
+				return "" + this.requestStatus + " " + this.description;
+			}
+
+			@Override
+			public int getRequestStatus() {
+				return this.requestStatus;
+			}
+
+		}
+
+		/**
+		 * Output stream that will automatically send every write to the wrapped
+		 * OutputStream according to chunked transfer:
+		 * http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.6.1
+		 */
+		private static class ChunkedOutputStream extends FilterOutputStream {
+
+			public ChunkedOutputStream(OutputStream out) {
+				super(out);
+			}
+
+			@Override
+			public void write(int b) throws IOException {
+				byte[] data = { (byte) b };
+				write(data, 0, 1);
+			}
+
+			@Override
+			public void write(byte[] b) throws IOException {
+				write(b, 0, b.length);
+			}
+
+			@Override
+			public void write(byte[] b, int off, int len) throws IOException {
+				if (len == 0)
+					return;
+				out.write(String.format("%x\r\n", len).getBytes());
+				out.write(b, off, len);
+				out.write("\r\n".getBytes());
+			}
+
+			public void finish() throws IOException {
+				out.write("0\r\n\r\n".getBytes());
+			}
+
+		}
+
+		/**
+		 * HTTP status code after processing, e.g. "200 OK", Status.OK
+		 */
+		private IStatus status;
+
+		/**
+		 * MIME type of content, e.g. "text/html"
+		 */
+		private String mimeType;
+
+		/**
+		 * Data of the response, may be null.
+		 */
+		private InputStream data;
+
+		private long contentLength;
+
+		/**
+		 * Headers for the HTTP response. Use addHeader() to add lines. the lowercase
+		 * map is automatically kept up to date.
+		 */
+		@SuppressWarnings("serial")
+		private final Map<String, String> header = new HashMap<String, String>() {
+
+			public String put(String key, String value) {
+				lowerCaseHeader.put(key == null ? key : key.toLowerCase(), value);
+				return super.put(key, value);
+			};
+		};
+
+		/**
+		 * copy of the header map with all the keys lowercase for faster searching.
+		 */
+		private final Map<String, String> lowerCaseHeader = new HashMap<String, String>();
+
+		/**
+		 * The request method that spawned this response.
+		 */
+		private Method requestMethod;
+
+		/**
+		 * Use chunkedTransfer
+		 */
+		private boolean chunkedTransfer;
+
+		private boolean encodeAsGzip;
+
+		private boolean keepAlive;
+
+		/**
+		 * Creates a fixed length response if totalBytes>=0, otherwise chunked.
+		 */
+		protected Response(IStatus status, String mimeType, InputStream data, long totalBytes) {
+			this.status = status;
+			this.mimeType = mimeType;
+			if (data == null) {
+				this.data = new ByteArrayInputStream(new byte[0]);
+				this.contentLength = 0L;
+			} else {
+				this.data = data;
+				this.contentLength = totalBytes;
+			}
+			this.chunkedTransfer = this.contentLength < 0;
+			keepAlive = true;
+		}
+
+		@Override
+		public void close() throws IOException {
+			if (this.data != null) {
+				this.data.close();
+			}
+		}
+
+		/**
+		 * Adds given line to the header.
+		 */
+		public void addHeader(String name, String value) {
+			this.header.put(name, value);
+		}
+
+		/**
+		 * Indicate to close the connection after the Response has been sent.
+		 * 
+		 * @param close {@code true} to hint connection closing, {@code false} to let
+		 *              connection be closed by client.
+		 */
+		public void closeConnection(boolean close) {
+			if (close)
+				this.header.put("connection", "close");
+			else
+				this.header.remove("connection");
+		}
+
+		/**
+		 * @return {@code true} if connection is to be closed after this Response has
+		 *         been sent.
+		 */
+		public boolean isCloseConnection() {
+			return "close".equals(getHeader("connection"));
+		}
+
+		public InputStream getData() {
+			return this.data;
+		}
+
+		public String getHeader(String name) {
+			return this.lowerCaseHeader.get(name.toLowerCase());
+		}
+
+		public String getMimeType() {
+			return this.mimeType;
+		}
+
+		public Method getRequestMethod() {
+			return this.requestMethod;
+		}
+
+		public IStatus getStatus() {
+			return this.status;
+		}
+
+		public void setGzipEncoding(boolean encodeAsGzip) {
+			this.encodeAsGzip = encodeAsGzip;
+		}
+
+		public void setKeepAlive(boolean useKeepAlive) {
+			this.keepAlive = useKeepAlive;
+		}
+
+		/**
+		 * Sends given response to the socket.
+		 */
+		protected void send(OutputStream outputStream) {
+			SimpleDateFormat gmtFrmt = new SimpleDateFormat("E, d MMM yyyy HH:mm:ss 'GMT'", Locale.US);
+			gmtFrmt.setTimeZone(TimeZone.getTimeZone("GMT"));
+
+			try {
+				if (this.status == null) {
+					throw new Error("sendResponse(): Status can't be null.");
+				}
+				PrintWriter pw = new PrintWriter(
+						new BufferedWriter(
+								new OutputStreamWriter(outputStream, new ContentType(this.mimeType).getEncoding())),
+						false);
+				pw.append("HTTP/1.1 ").append(this.status.getDescription()).append(" \r\n");
+				if (this.mimeType != null) {
+					printHeader(pw, "Content-Type", this.mimeType);
+				}
+				if (getHeader("date") == null) {
+					printHeader(pw, "Date", gmtFrmt.format(new Date()));
+				}
+				for (Entry<String, String> entry : this.header.entrySet()) {
+					printHeader(pw, entry.getKey(), entry.getValue());
+				}
+				if (getHeader("connection") == null) {
+					printHeader(pw, "Connection", (this.keepAlive ? "keep-alive" : "close"));
+				}
+				if (getHeader("content-length") != null) {
+					encodeAsGzip = false;
+				}
+				if (encodeAsGzip) {
+					printHeader(pw, "Content-Encoding", "gzip");
+					setChunkedTransfer(true);
+				}
+				long pending = this.data != null ? this.contentLength : 0;
+				if (this.requestMethod != Method.HEAD && this.chunkedTransfer) {
+					printHeader(pw, "Transfer-Encoding", "chunked");
+				} else if (!encodeAsGzip) {
+					pending = sendContentLengthHeaderIfNotAlreadyPresent(pw, pending);
+				}
+				pw.append("\r\n");
+				pw.flush();
+				sendBodyWithCorrectTransferAndEncoding(outputStream, pending);
+				outputStream.flush();
+				safeClose(this.data);
+			} catch (IOException ioe) {
+				NanoHTTPD.LOG.log(Level.SEVERE, "Could not send response to the client", ioe);
+			}
+		}
+
+		@SuppressWarnings("static-method")
+		protected void printHeader(PrintWriter pw, String key, String value) {
+			pw.append(key).append(": ").append(value).append("\r\n");
+		}
+
+		protected long sendContentLengthHeaderIfNotAlreadyPresent(PrintWriter pw, long defaultSize) {
+			String contentLengthString = getHeader("content-length");
+			long size = defaultSize;
+			if (contentLengthString != null) {
+				try {
+					size = Long.parseLong(contentLengthString);
+				} catch (NumberFormatException ex) {
+					LOG.severe("content-length was no number " + contentLengthString);
+				}
+			}
+			pw.print("Content-Length: " + size + "\r\n");
+			return size;
+		}
+
+		private void sendBodyWithCorrectTransferAndEncoding(OutputStream outputStream, long pending)
+				throws IOException {
+			if (this.requestMethod != Method.HEAD && this.chunkedTransfer) {
+				ChunkedOutputStream chunkedOutputStream = new ChunkedOutputStream(outputStream);
+				sendBodyWithCorrectEncoding(chunkedOutputStream, -1);
+				chunkedOutputStream.finish();
+			} else {
+				sendBodyWithCorrectEncoding(outputStream, pending);
+			}
+		}
+
+		private void sendBodyWithCorrectEncoding(OutputStream outputStream, long pending) throws IOException {
+			if (encodeAsGzip) {
+				GZIPOutputStream gzipOutputStream = new GZIPOutputStream(outputStream);
+				sendBody(gzipOutputStream, -1);
+				gzipOutputStream.finish();
+			} else {
+				sendBody(outputStream, pending);
+			}
+		}
+
+		/**
+		 * Sends the body to the specified OutputStream. The pending parameter limits
+		 * the maximum amounts of bytes sent unless it is -1, in which case everything
+		 * is sent.
+		 * 
+		 * @param outputStream the OutputStream to send data to
+		 * @param pending      -1 to send everything, otherwise sets a max limit to the
+		 *                     number of bytes sent
+		 * @throws IOException if something goes wrong while sending the data.
+		 */
+		private void sendBody(OutputStream outputStream, long pending) throws IOException {
+			long BUFFER_SIZE = 16 * 1024;
+			byte[] buff = new byte[(int) BUFFER_SIZE];
+			boolean sendEverything = pending == -1;
+			while (pending > 0 || sendEverything) {
+				long bytesToRead = sendEverything ? BUFFER_SIZE : Math.min(pending, BUFFER_SIZE);
+				int read = this.data.read(buff, 0, (int) bytesToRead);
+				if (read <= 0) {
+					break;
+				}
+				outputStream.write(buff, 0, read);
+				if (!sendEverything) {
+					pending -= read;
+				}
+			}
+		}
+
+		public void setChunkedTransfer(boolean chunkedTransfer) {
+			this.chunkedTransfer = chunkedTransfer;
+		}
+
+		public void setData(InputStream data) {
+			this.data = data;
+		}
+
+		public void setMimeType(String mimeType) {
+			this.mimeType = mimeType;
+		}
+
+		public void setRequestMethod(Method requestMethod) {
+			this.requestMethod = requestMethod;
+		}
+
+		public void setStatus(IStatus status) {
+			this.status = status;
+		}
+	}
+
+	public static final class ResponseException extends Exception {
+
+		private static final long serialVersionUID = 6569838532917408380L;
+
+		private final Response.Status status;
+
+		public ResponseException(Response.Status status, String message) {
+			super(message);
+			this.status = status;
+		}
+
+		public ResponseException(Response.Status status, String message, Exception e) {
+			super(message, e);
+			this.status = status;
+		}
+
+		public Response.Status getStatus() {
+			return this.status;
+		}
+	}
+
+	/**
+	 * The runnable that will be used for the main listening thread.
+	 */
+	public class ServerRunnable implements Runnable {
+
+		private final int timeout;
+
+		private IOException bindException;
+
+		private boolean hasBinded = false;
+
+		public ServerRunnable(int timeout) {
+			this.timeout = timeout;
+		}
+
+		@Override
+		public void run() {
+			try {
+				myServerSocket.bind(
+						hostname != null ? new InetSocketAddress(hostname, myPort) : new InetSocketAddress(myPort));
+				hasBinded = true;
+			} catch (IOException e) {
+				this.bindException = e;
+				return;
+			}
+			do {
+				try {
+					final Socket finalAccept = NanoHTTPD.this.myServerSocket.accept();
+					if (this.timeout > 0) {
+						finalAccept.setSoTimeout(this.timeout);
+					}
+					final InputStream inputStream = finalAccept.getInputStream();
+					NanoHTTPD.this.asyncRunner.exec(createClientHandler(finalAccept, inputStream));
+				} catch (IOException e) {
+					NanoHTTPD.LOG.log(Level.FINE, "Communication with the client broken", e);
+				}
+			} while (!NanoHTTPD.this.myServerSocket.isClosed());
+		}
+	}
+
+	/**
+	 * A temp file.
+	 * <p/>
+	 * <p>
+	 * Temp files are responsible for managing the actual temporary storage and
+	 * cleaning themselves up when no longer needed.
+	 * </p>
+	 */
+	public interface TempFile {
+
+		public void delete() throws Exception;
+
+		public String getName();
+
+		public OutputStream open() throws Exception;
+	}
+
+	/**
+	 * Temp file manager.
+	 * <p/>
+	 * <p>
+	 * Temp file managers are created 1-to-1 with incoming requests, to create and
+	 * cleanup temporary files created as a result of handling the request.
+	 * </p>
+	 */
+	public interface TempFileManager {
+
+		void clear();
+
+		public TempFile createTempFile(String filename_hint) throws Exception;
+	}
+
+	/**
+	 * Factory to create temp file managers.
+	 */
+	public interface TempFileManagerFactory {
+
+		public TempFileManager create();
+	}
+
+	/**
+	 * Factory to create ServerSocketFactories.
+	 */
+	public interface ServerSocketFactory {
+
+		public ServerSocket create() throws IOException;
+
+	}
+
+	/**
+	 * Maximum time to wait on Socket.getInputStream().read() (in milliseconds) This
+	 * is required as the Keep-Alive HTTP connections would otherwise block the
+	 * socket reading thread forever (or as long the browser is open).
+	 */
+	public static final int SOCKET_READ_TIMEOUT = 5000;
+
+	/**
+	 * Common MIME type for dynamic content: plain text
+	 */
+	public static final String MIME_PLAINTEXT = "text/plain";
+
+	/**
+	 * Common MIME type for dynamic content: html
+	 */
+	public static final String MIME_HTML = "text/html";
+
+	/**
+	 * Pseudo-Parameter to use to store the actual query string in the parameters
+	 * map for later re-processing.
+	 */
+	private static final String QUERY_STRING_PARAMETER = "NanoHttpd.QUERY_STRING";
+
+	/**
+	 * logger to log to.
+	 */
+	private static final Logger LOG = Logger.getLogger(NanoHTTPD.class.getName());
+
+	/**
+	 * Hashtable mapping (String)FILENAME_EXTENSION -> (String)MIME_TYPE
+	 */
+	protected static Map<String, String> MIME_TYPES;
+
+	public static Map<String, String> mimeTypes() {
+		if (MIME_TYPES == null) {
+			MIME_TYPES = new HashMap<String, String>();
+			loadMimeTypes(MIME_TYPES, "META-INF/nanohttpd/default-mimetypes.properties");
+			loadMimeTypes(MIME_TYPES, "META-INF/nanohttpd/mimetypes.properties");
+			if (MIME_TYPES.isEmpty()) {
+				LOG.log(Level.WARNING, "no mime types found in the classpath! please provide mimetypes.properties");
+			}
+		}
+		return MIME_TYPES;
+	}
+
+	@SuppressWarnings({ "unchecked", "rawtypes" })
+	private static void loadMimeTypes(Map<String, String> result, String resourceName) {
+		try {
+			Enumeration<URL> resources = NanoHTTPD.class.getClassLoader().getResources(resourceName);
+			while (resources.hasMoreElements()) {
+				URL url = (URL) resources.nextElement();
+				Properties properties = new Properties();
+				InputStream stream = null;
+				try {
+					stream = url.openStream();
+					properties.load(stream);
+				} catch (IOException e) {
+					LOG.log(Level.SEVERE, "could not load mimetypes from " + url, e);
+				} finally {
+					safeClose(stream);
+				}
+				result.putAll((Map) properties);
+			}
+		} catch (IOException e) {
+			LOG.log(Level.INFO, "no mime types available at " + resourceName);
+		}
+	};
+
+	/**
+	 * Creates an SSLSocketFactory for HTTPS. Pass a loaded KeyStore and an array of
+	 * loaded KeyManagers. These objects must properly loaded/initialized by the
+	 * caller.
+	 */
+	public static SSLServerSocketFactory makeSSLSocketFactory(KeyStore loadedKeyStore, KeyManager[] keyManagers)
+			throws IOException {
+		SSLServerSocketFactory res = null;
+		try {
+			TrustManagerFactory trustManagerFactory = TrustManagerFactory
+					.getInstance(TrustManagerFactory.getDefaultAlgorithm());
+			trustManagerFactory.init(loadedKeyStore);
+			SSLContext ctx = SSLContext.getInstance("TLS");
+			ctx.init(keyManagers, trustManagerFactory.getTrustManagers(), null);
+			res = ctx.getServerSocketFactory();
+		} catch (Exception e) {
+			throw new IOException(e.getMessage());
+		}
+		return res;
+	}
+
+	/**
+	 * Creates an SSLSocketFactory for HTTPS. Pass a loaded KeyStore and a loaded
+	 * KeyManagerFactory. These objects must properly loaded/initialized by the
+	 * caller.
+	 */
+	public static SSLServerSocketFactory makeSSLSocketFactory(KeyStore loadedKeyStore,
+			KeyManagerFactory loadedKeyFactory) throws IOException {
+		try {
+			return makeSSLSocketFactory(loadedKeyStore, loadedKeyFactory.getKeyManagers());
+		} catch (Exception e) {
+			throw new IOException(e.getMessage());
+		}
+	}
+
+	/**
+	 * Creates an SSLSocketFactory for HTTPS. Pass a KeyStore resource with your
+	 * certificate and passphrase
+	 */
+	public static SSLServerSocketFactory makeSSLSocketFactory(String keyAndTrustStoreClasspathPath, char[] passphrase)
+			throws IOException {
+		try {
+			KeyStore keystore = KeyStore.getInstance(KeyStore.getDefaultType());
+			InputStream keystoreStream = NanoHTTPD.class.getResourceAsStream(keyAndTrustStoreClasspathPath);
+
+			if (keystoreStream == null) {
+				throw new IOException("Unable to load keystore from classpath: " + keyAndTrustStoreClasspathPath);
+			}
+
+			keystore.load(keystoreStream, passphrase);
+			KeyManagerFactory keyManagerFactory = KeyManagerFactory
+					.getInstance(KeyManagerFactory.getDefaultAlgorithm());
+			keyManagerFactory.init(keystore, passphrase);
+			return makeSSLSocketFactory(keystore, keyManagerFactory);
+		} catch (Exception e) {
+			throw new IOException(e.getMessage());
+		}
+	}
+
+	/**
+	 * Get MIME type from file name extension, if possible
+	 * 
+	 * @param uri the string representing a file
+	 * @return the connected mime/type
+	 */
+	public static String getMimeTypeForFile(String uri) {
+		int dot = uri.lastIndexOf('.');
+		String mime = null;
+		if (dot >= 0) {
+			mime = mimeTypes().get(uri.substring(dot + 1).toLowerCase());
+		}
+		return mime == null ? "application/octet-stream" : mime;
+	}
+
+	private static final void safeClose(Object closeable) {
+		try {
+			if (closeable != null) {
+				if (closeable instanceof Closeable) {
+					((Closeable) closeable).close();
+				} else if (closeable instanceof Socket) {
+					((Socket) closeable).close();
+				} else if (closeable instanceof ServerSocket) {
+					((ServerSocket) closeable).close();
+				} else {
+					throw new IllegalArgumentException("Unknown object to close");
+				}
+			}
+		} catch (IOException e) {
+			NanoHTTPD.LOG.log(Level.SEVERE, "Could not close", e);
+		}
+	}
+
+	private final String hostname;
+
+	private final int myPort;
+
+	private volatile ServerSocket myServerSocket;
+
+	private ServerSocketFactory serverSocketFactory = new DefaultServerSocketFactory();
+
+	private Thread myThread;
+
+	/**
+	 * Pluggable strategy for asynchronously executing requests.
+	 */
+	protected AsyncRunner asyncRunner;
+
+	/**
+	 * Pluggable strategy for creating and cleaning up temporary files.
+	 */
+	private TempFileManagerFactory tempFileManagerFactory;
+
+	/**
+	 * Constructs an HTTP server on given port.
+	 */
+	public NanoHTTPD(int port) {
+		this(null, port);
+	}
+
+	// -------------------------------------------------------------------------------
+	// //
+	//
+	// Threading Strategy.
+	//
+	// -------------------------------------------------------------------------------
+	// //
+
+	/**
+	 * Constructs an HTTP server on given hostname and port.
+	 */
+	public NanoHTTPD(String hostname, int port) {
+		this.hostname = hostname;
+		this.myPort = port;
+		setTempFileManagerFactory(new DefaultTempFileManagerFactory());
+		setAsyncRunner(new DefaultAsyncRunner());
+	}
+
+	/**
+	 * Forcibly closes all connections that are open.
+	 */
+	public synchronized void closeAllConnections() {
+		stop();
+	}
+
+	/**
+	 * create a instance of the client handler, subclasses can return a subclass of
+	 * the ClientHandler.
+	 * 
+	 * @param finalAccept the socket the cleint is connected to
+	 * @param inputStream the input stream
+	 * @return the client handler
+	 */
+	protected ClientHandler createClientHandler(final Socket finalAccept, final InputStream inputStream) {
+		return new ClientHandler(inputStream, finalAccept);
+	}
+
+	/**
+	 * Instantiate the server runnable, can be overwritten by subclasses to provide
+	 * a subclass of the ServerRunnable.
+	 * 
+	 * @param timeout the socet timeout to use.
+	 * @return the server runnable.
+	 */
+	protected ServerRunnable createServerRunnable(final int timeout) {
+		return new ServerRunnable(timeout);
+	}
+
+	/**
+	 * Decode parameters from a URL, handing the case where a single parameter name
+	 * might have been supplied several times, by return lists of values. In general
+	 * these lists will contain a single element.
+	 * 
+	 * @param parms original <b>NanoHTTPD</b> parameters values, as passed to the
+	 *              <code>serve()</code> method.
+	 * @return a map of <code>String</code> (parameter name) to
+	 *         <code>List&lt;String&gt;</code> (a list of the values supplied).
+	 */
+	protected static Map<String, List<String>> decodeParameters(Map<String, String> parms) {
+		return decodeParameters(parms.get(NanoHTTPD.QUERY_STRING_PARAMETER));
+	}
+
+	// -------------------------------------------------------------------------------
+	// //
+
+	/**
+	 * Decode parameters from a URL, handing the case where a single parameter name
+	 * might have been supplied several times, by return lists of values. In general
+	 * these lists will contain a single element.
+	 * 
+	 * @param queryString a query string pulled from the URL.
+	 * @return a map of <code>String</code> (parameter name) to
+	 *         <code>List&lt;String&gt;</code> (a list of the values supplied).
+	 */
+	protected static Map<String, List<String>> decodeParameters(String queryString) {
+		Map<String, List<String>> parms = new HashMap<String, List<String>>();
+		if (queryString != null) {
+			StringTokenizer st = new StringTokenizer(queryString, "&");
+			while (st.hasMoreTokens()) {
+				String e = st.nextToken();
+				int sep = e.indexOf('=');
+				String propertyName = sep >= 0 ? decodePercent(e.substring(0, sep)).trim() : decodePercent(e).trim();
+				if (!parms.containsKey(propertyName)) {
+					parms.put(propertyName, new ArrayList<String>());
+				}
+				String propertyValue = sep >= 0 ? decodePercent(e.substring(sep + 1)) : null;
+				if (propertyValue != null) {
+					parms.get(propertyName).add(propertyValue);
+				}
+			}
+		}
+		return parms;
+	}
+
+	/**
+	 * Decode percent encoded <code>String</code> values.
+	 * 
+	 * @param str the percent encoded <code>String</code>
+	 * @return expanded form of the input, for example "foo%20bar" becomes "foo bar"
+	 */
+	protected static String decodePercent(String str) {
+		String decoded = null;
+		try {
+			decoded = URLDecoder.decode(str, "UTF8");
+		} catch (UnsupportedEncodingException ignored) {
+			NanoHTTPD.LOG.log(Level.WARNING, "Encoding not supported, ignored", ignored);
+		}
+		return decoded;
+	}
+
+	/**
+	 * @return true if the gzip compression should be used if the client accespts
+	 *         it. Default this option is on for text content and off for
+	 *         everything. Override this for custom semantics.
+	 */
+	@SuppressWarnings("static-method")
+	protected boolean useGzipWhenAccepted(Response r) {
+		return r.getMimeType() != null
+				&& (r.getMimeType().toLowerCase().contains("text/") || r.getMimeType().toLowerCase().contains("/json"));
+	}
+
+	public final int getListeningPort() {
+		return this.myServerSocket == null ? -1 : this.myServerSocket.getLocalPort();
+	}
+
+	public final boolean isAlive() {
+		return wasStarted() && !this.myServerSocket.isClosed() && this.myThread.isAlive();
+	}
+
+	public ServerSocketFactory getServerSocketFactory() {
+		return serverSocketFactory;
+	}
+
+	public void setServerSocketFactory(ServerSocketFactory serverSocketFactory) {
+		this.serverSocketFactory = serverSocketFactory;
+	}
+
+	public String getHostname() {
+		return hostname;
+	}
+
+	public TempFileManagerFactory getTempFileManagerFactory() {
+		return tempFileManagerFactory;
+	}
+
+	/**
+	 * Call before start() to serve over HTTPS instead of HTTP
+	 */
+	public void makeSecure(SSLServerSocketFactory sslServerSocketFactory, String[] sslProtocols) {
+		this.serverSocketFactory = new SecureServerSocketFactory(sslServerSocketFactory, sslProtocols);
+	}
+
+	/**
+	 * Create a response with unknown length (using HTTP 1.1 chunking).
+	 */
+	public static Response newChunkedResponse(IStatus status, String mimeType, InputStream data) {
+		return new Response(status, mimeType, data, -1);
+	}
+
+	/**
+	 * Create a response with known length.
+	 */
+	public static Response newFixedLengthResponse(IStatus status, String mimeType, InputStream data, long totalBytes) {
+		return new Response(status, mimeType, data, totalBytes);
+	}
+
+	/**
+	 * Create a text response with known length.
+	 */
+	public static Response newFixedLengthResponse(IStatus status, String mimeType, String txt) {
+		ContentType contentType = new ContentType(mimeType);
+		if (txt == null) {
+			return newFixedLengthResponse(status, mimeType, new ByteArrayInputStream(new byte[0]), 0);
+		} else {
+			byte[] bytes;
+			try {
+				CharsetEncoder newEncoder = Charset.forName(contentType.getEncoding()).newEncoder();
+				if (!newEncoder.canEncode(txt)) {
+					contentType = contentType.tryUTF8();
+				}
+				bytes = txt.getBytes(contentType.getEncoding());
+			} catch (UnsupportedEncodingException e) {
+				NanoHTTPD.LOG.log(Level.SEVERE, "encoding problem, responding nothing", e);
+				bytes = new byte[0];
+			}
+			return newFixedLengthResponse(status, contentType.getContentTypeHeader(), new ByteArrayInputStream(bytes),
+					bytes.length);
+		}
+	}
+
+	/**
+	 * Create a text response with known length.
+	 */
+	public static Response newFixedLengthResponse(String msg) {
+		return newFixedLengthResponse(Status.OK, NanoHTTPD.MIME_HTML, msg);
+	}
+
+	/**
+	 * Override this to customize the server.
+	 * <p/>
+	 * <p/>
+	 * (By default, this returns a 404 "Not Found" plain text error response.)
+	 * 
+	 * @param session The HTTP session
+	 * @return HTTP response, see class Response for details
+	 */
+	public Response serve(IHTTPSession session) {
+		Map<String, String> files = new HashMap<String, String>();
+		Method method = session.getMethod();
+		if (Method.PUT.equals(method) || Method.POST.equals(method)) {
+			try {
+				session.parseBody(files);
+			} catch (IOException ioe) {
+				return newFixedLengthResponse(Response.Status.INTERNAL_ERROR, NanoHTTPD.MIME_PLAINTEXT,
+						"SERVER INTERNAL ERROR: IOException: " + ioe.getMessage());
+			} catch (ResponseException re) {
+				return newFixedLengthResponse(re.getStatus(), NanoHTTPD.MIME_PLAINTEXT, re.getMessage());
+			}
+		}
+
+		Map<String, String> parms = session.getParms();
+		parms.put(NanoHTTPD.QUERY_STRING_PARAMETER, session.getQueryParameterString());
+		return serve(session.getUri(), method, session.getHeaders(), parms, files);
+	}
+
+	/**
+	 * Override this to customize the server.
+	 * <p/>
+	 * <p/>
+	 * (By default, this returns a 404 "Not Found" plain text error response.)
+	 * 
+	 * @param uri     Percent-decoded URI without parameters, for example
+	 *                "/index.cgi"
+	 * @param method  "GET", "POST" etc.
+	 * @param parms   Parsed, percent decoded parameters from URI and, in case of
+	 *                POST, data.
+	 * @param headers Header entries, percent decoded
+	 * @return HTTP response, see class Response for details
+	 */
+	@Deprecated
+	public Response serve(String uri, Method method, Map<String, String> headers, Map<String, String> parms,
+			Map<String, String> files) {
+		return newFixedLengthResponse(Response.Status.NOT_FOUND, NanoHTTPD.MIME_PLAINTEXT, "Not Found");
+	}
+
+	/**
+	 * Pluggable strategy for asynchronously executing requests.
+	 * 
+	 * @param asyncRunner new strategy for handling threads.
+	 */
+	public void setAsyncRunner(AsyncRunner asyncRunner) {
+		this.asyncRunner = asyncRunner;
+	}
+
+	/**
+	 * Pluggable strategy for creating and cleaning up temporary files.
+	 * 
+	 * @param tempFileManagerFactory new strategy for handling temp files.
+	 */
+	public void setTempFileManagerFactory(TempFileManagerFactory tempFileManagerFactory) {
+		this.tempFileManagerFactory = tempFileManagerFactory;
+	}
+
+	/**
+	 * Start the server.
+	 * 
+	 * @throws IOException if the socket is in use.
+	 */
+	public void start() throws IOException {
+		start(NanoHTTPD.SOCKET_READ_TIMEOUT);
+	}
+
+	/**
+	 * Starts the server (in setDaemon(true) mode).
+	 */
+	public void start(final int timeout) throws IOException {
+		start(timeout, true);
+	}
+
+	/**
+	 * Start the server.
+	 * 
+	 * @param timeout timeout to use for socket connections.
+	 * @param daemon  start the thread daemon or not.
+	 * @throws IOException if the socket is in use.
+	 */
+	public void start(final int timeout, boolean daemon) throws IOException {
+		this.myServerSocket = this.getServerSocketFactory().create();
+		this.myServerSocket.setReuseAddress(true);
+
+		ServerRunnable serverRunnable = createServerRunnable(timeout);
+		this.myThread = new Thread(serverRunnable);
+		this.myThread.setDaemon(daemon);
+		this.myThread.setName("NanoHttpd Main Listener");
+		this.myThread.start();
+		while (!serverRunnable.hasBinded && serverRunnable.bindException == null) {
+			try {
+				Thread.sleep(10L);
+			} catch (Throwable e) {
+				// on android this may not be allowed, that's why we
+				// catch throwable the wait should be very short because we are
+				// just waiting for the bind of the socket
+			}
+		}
+		if (serverRunnable.bindException != null) {
+			throw serverRunnable.bindException;
+		}
+	}
+
+	/**
+	 * Stop the server.
+	 */
+	public void stop() {
+		try {
+			safeClose(this.myServerSocket);
+			this.asyncRunner.closeAll();
+			if (this.myThread != null) {
+				this.myThread.join();
+			}
+		} catch (Exception e) {
+			NanoHTTPD.LOG.log(Level.SEVERE, "Could not stop all connections", e);
+		}
+	}
+
+	public final boolean wasStarted() {
+		return this.myServerSocket != null && this.myThread != null;
+	}
+}
diff --git a/sources/lwjgl/java/net/lax1dude/eaglercraft/v1_8/internal/OpenGLObjects.java b/sources/lwjgl/java/net/lax1dude/eaglercraft/v1_8/internal/OpenGLObjects.java
index f1cfad66..693cbbe6 100644
--- a/sources/lwjgl/java/net/lax1dude/eaglercraft/v1_8/internal/OpenGLObjects.java
+++ b/sources/lwjgl/java/net/lax1dude/eaglercraft/v1_8/internal/OpenGLObjects.java
@@ -25,6 +25,10 @@ class OpenGLObjects {
 			this.ptr = ptr;
 		}
 
+		public int hashCode() {
+			return ptr;
+		}
+
 		@Override
 		public void free() {
 			PlatformOpenGL._wglDeleteBuffers(this);
@@ -40,6 +44,10 @@ class OpenGLObjects {
 			this.ptr = ptr;
 		}
 
+		public int hashCode() {
+			return ptr;
+		}
+
 		@Override
 		public void free() {
 			PlatformOpenGL._wglDeleteVertexArrays(this);
@@ -55,6 +63,10 @@ class OpenGLObjects {
 			this.ptr = ptr;
 		}
 
+		public int hashCode() {
+			return ptr;
+		}
+
 		@Override
 		public void free() {
 			PlatformOpenGL._wglDeleteTextures(this);
@@ -70,6 +82,10 @@ class OpenGLObjects {
 			this.ptr = ptr;
 		}
 
+		public int hashCode() {
+			return ptr;
+		}
+
 		@Override
 		public void free() {
 			PlatformOpenGL._wglDeleteProgram(this);
@@ -85,6 +101,10 @@ class OpenGLObjects {
 			this.ptr = ptr;
 		}
 
+		public int hashCode() {
+			return ptr;
+		}
+
 		@Override
 		public void free() {
 		}
@@ -99,6 +119,10 @@ class OpenGLObjects {
 			this.ptr = ptr;
 		}
 
+		public int hashCode() {
+			return ptr;
+		}
+
 		@Override
 		public void free() {
 			PlatformOpenGL._wglDeleteShader(this);
@@ -114,6 +138,10 @@ class OpenGLObjects {
 			this.ptr = ptr;
 		}
 
+		public int hashCode() {
+			return ptr;
+		}
+
 		@Override
 		public void free() {
 			PlatformOpenGL._wglDeleteFramebuffer(this);
@@ -129,6 +157,10 @@ class OpenGLObjects {
 			this.ptr = ptr;
 		}
 
+		public int hashCode() {
+			return ptr;
+		}
+
 		@Override
 		public void free() {
 			PlatformOpenGL._wglDeleteRenderbuffer(this);
@@ -144,6 +176,10 @@ class OpenGLObjects {
 			this.ptr = ptr;
 		}
 
+		public int hashCode() {
+			return ptr;
+		}
+
 		@Override
 		public void free() {
 			PlatformOpenGL._wglDeleteQueries(this);
diff --git a/sources/lwjgl/java/net/lax1dude/eaglercraft/v1_8/internal/PlatformApplication.java b/sources/lwjgl/java/net/lax1dude/eaglercraft/v1_8/internal/PlatformApplication.java
index 463efe63..d4985bf2 100644
--- a/sources/lwjgl/java/net/lax1dude/eaglercraft/v1_8/internal/PlatformApplication.java
+++ b/sources/lwjgl/java/net/lax1dude/eaglercraft/v1_8/internal/PlatformApplication.java
@@ -7,6 +7,7 @@ import java.awt.Desktop;
 import java.awt.EventQueue;
 import java.awt.HeadlessException;
 import java.awt.Toolkit;
+import java.awt.image.BufferedImage;
 import java.awt.Dialog.ModalExclusionType;
 import java.awt.Dialog.ModalityType;
 import java.io.File;
@@ -14,16 +15,23 @@ import java.io.FileInputStream;
 import java.io.FileOutputStream;
 import java.io.IOException;
 import java.net.URI;
+import java.net.URISyntaxException;
+import java.text.DateFormat;
+import java.text.SimpleDateFormat;
+import java.util.Date;
 
+import javax.imageio.ImageIO;
 import javax.swing.JDialog;
 import javax.swing.JFileChooser;
 import javax.swing.JOptionPane;
 import javax.swing.filechooser.FileFilter;
 
 import net.lax1dude.eaglercraft.v1_8.EagRuntime;
+import net.lax1dude.eaglercraft.v1_8.internal.buffer.ByteBuffer;
 import net.lax1dude.eaglercraft.v1_8.internal.lwjgl.MainMenuCreditsDialog;
 import net.lax1dude.eaglercraft.v1_8.log4j.LogManager;
 import net.lax1dude.eaglercraft.v1_8.log4j.Logger;
+import net.lax1dude.eaglercraft.v1_8.opengl.RealOpenGLEnums;
 
 /**
  * Copyright (c) 2022-2023 lax1dude, ayunami2000. All Rights Reserved.
@@ -49,10 +57,23 @@ public class PlatformApplication {
 	}
 
 	public static void openLink(String url) {
+		URI safeURL;
 		try {
-			Desktop.getDesktop().browse(new URI(url));
+			safeURL = new URI(url);
+			String proto = safeURL.getScheme();
+			if(!proto.equalsIgnoreCase("http") && !proto.equalsIgnoreCase("https")) {
+				throw new IllegalArgumentException("Suspicious protocol: " + proto);
+			}
+		}catch(URISyntaxException | IllegalArgumentException ex) {
+			PlatformRuntime.logger.error("Refusing to open invalid URL: {}", url);
+			PlatformRuntime.logger.error(ex);
+			return;
+		}
+		try {
+			Desktop.getDesktop().browse(safeURL);
 		} catch (Throwable var5) {
-			EagRuntime.debugPrintStackTrace(var5);
+			PlatformRuntime.logger.error("Failed to browse to URL: {}", safeURL.toString());
+			PlatformRuntime.logger.error(var5);
 		}
 	}
 
@@ -98,9 +119,40 @@ public class PlatformApplication {
 			return null;
 		}
 	}
+
+	private static final DateFormat dateFormatSS = new SimpleDateFormat("yyyy-MM-dd_HH.mm.ss");
+	private static final File screeshotsDir = new File("screenshots");
 	
 	public static String saveScreenshot() {
-		return "nothing";
+		if(!screeshotsDir.isDirectory() && !screeshotsDir.mkdirs()) {
+			PlatformRuntime.logger.error("Failed to create screenshots directory: {}", screeshotsDir.getAbsolutePath());
+			return "nothing";
+		}
+		String name = "screenshot_" + dateFormatSS.format(new Date()).toString() + ".png";
+		int w = PlatformInput.getWindowWidth();
+		int h = PlatformInput.getWindowHeight();
+		ByteBuffer screenshotBuffer = PlatformRuntime.allocateByteBuffer(w * h * 4);
+		PlatformOpenGL._wglReadPixels(0, 0, w, h, RealOpenGLEnums.GL_RGBA, RealOpenGLEnums.GL_UNSIGNED_BYTE, screenshotBuffer);
+		BufferedImage bufferedImage = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB);
+		int i;
+		for(int y = 0; y < h; ++y) {
+			for(int x = 0; x < w; ++x) {
+				i = (x + (h - y - 1) * w) << 2;
+				bufferedImage.setRGB(x, y,
+						((screenshotBuffer.get(i) & 0xFF) << 16) | ((screenshotBuffer.get(i + 1) & 0xFF) << 8)
+								| (screenshotBuffer.get(i + 2) & 0xFF) | 0xFF000000);
+			}
+		}
+		PlatformRuntime.freeByteBuffer(screenshotBuffer);
+		File screenshotFile = new File(screeshotsDir, name);
+		try {
+			ImageIO.write(bufferedImage, "PNG", screenshotFile);
+		}catch(IOException ex) {
+			PlatformRuntime.logger.error("Failed to write screenshot: {}", screenshotFile.getAbsolutePath());
+			return "nothing";
+		}
+		PlatformRuntime.logger.info("Saved screenshot to: {}", screenshotFile.getAbsolutePath());
+		return name;
 	}
 	
 	public static void showPopup(String msg) {
@@ -127,6 +179,7 @@ public class PlatformApplication {
 	public static void displayFileChooser(final String mime, final String ext) {
 		if(!fileChooserOpen) {
 			fileChooserOpen = true;
+			clearFileChooserResult();
 			EventQueue.invokeLater(new Runnable() {
 				@Override
 				public void run() {
diff --git a/sources/lwjgl/java/net/lax1dude/eaglercraft/v1_8/internal/PlatformAssets.java b/sources/lwjgl/java/net/lax1dude/eaglercraft/v1_8/internal/PlatformAssets.java
index 615e3e95..54eb330d 100644
--- a/sources/lwjgl/java/net/lax1dude/eaglercraft/v1_8/internal/PlatformAssets.java
+++ b/sources/lwjgl/java/net/lax1dude/eaglercraft/v1_8/internal/PlatformAssets.java
@@ -43,7 +43,11 @@ public class PlatformAssets {
 		}
 	}
 	
-	public static final byte[] getResourceBytes(String path) {
+	public static boolean getResourceExists(String path) {
+		return (new File("resources", path)).isFile();
+	}
+	
+	public static byte[] getResourceBytes(String path) {
 		File loadFile = new File("resources", path);
 		byte[] ret = new byte[(int) loadFile.length()];
 		try(FileInputStream is = new FileInputStream(loadFile)) {
@@ -56,8 +60,12 @@ public class PlatformAssets {
 			return null;
 		}
 	}
-	
-	public static final ImageData loadImageFile(InputStream data) {
+
+	public static ImageData loadImageFile(InputStream data) {
+		return loadImageFile(data, "image/png");
+	}
+
+	public static ImageData loadImageFile(InputStream data, String mime) {
 		try {
 			BufferedImage img = ImageIO.read(data);
 			if(img == null) {
@@ -81,9 +89,13 @@ public class PlatformAssets {
 			return null;
 		}
 	}
-	
-	public static final ImageData loadImageFile(byte[] data) {
-		return loadImageFile(new EaglerInputStream(data));
+
+	public static ImageData loadImageFile(byte[] data) {
+		return loadImageFile(new EaglerInputStream(data), "image/png");
 	}
-	
+
+	public static ImageData loadImageFile(byte[] data, String mime) {
+		return loadImageFile(new EaglerInputStream(data), mime);
+	}
+
 }
diff --git a/sources/lwjgl/java/net/lax1dude/eaglercraft/v1_8/internal/PlatformAudio.java b/sources/lwjgl/java/net/lax1dude/eaglercraft/v1_8/internal/PlatformAudio.java
index 7c74b708..0656d64f 100644
--- a/sources/lwjgl/java/net/lax1dude/eaglercraft/v1_8/internal/PlatformAudio.java
+++ b/sources/lwjgl/java/net/lax1dude/eaglercraft/v1_8/internal/PlatformAudio.java
@@ -46,7 +46,7 @@ public class PlatformAudio {
 		
 		protected PaulscodeAudioHandle(String sourceName) {
 			this.sourceName = sourceName;
-			this.stall = System.currentTimeMillis();
+			this.stall = PlatformRuntime.steadyTimeMillis();
 		}
 
 		@Override
@@ -64,7 +64,7 @@ public class PlatformAudio {
 
 		@Override
 		public void restart() {
-			this.stall = System.currentTimeMillis();
+			this.stall = PlatformRuntime.steadyTimeMillis();
 			sndSystem.rewind(sourceName);
 			sndSystem.play(sourceName);
 		}
@@ -91,7 +91,7 @@ public class PlatformAudio {
 
 		@Override
 		public boolean shouldFree() {
-			return !sndSystem.playing(sourceName) && System.currentTimeMillis() - this.stall > 250l; //TODO: I hate this hack
+			return !sndSystem.playing(sourceName) && PlatformRuntime.steadyTimeMillis() - this.stall > 250l; //TODO: I hate this hack
 		}
 		
 	}
@@ -125,7 +125,7 @@ public class PlatformAudio {
 	private static SoundSystem sndSystem = null;
 	
 	static void platformInitialize() {
-		logger.info("Eaglercraft still uses Paul Lamb's SoundSystem but with LWJGL3");
+		logger.info("Eaglercraft uses Paul Lamb's SoundSystem (with LWJGL3)");
 		logger.info("    \"Author: Paul Lamb, www.paulscode.com\"");
 		try {
 			SoundSystemConfig.addLibrary(LibraryLWJGLOpenAL.class);
diff --git a/sources/lwjgl/java/net/lax1dude/eaglercraft/v1_8/internal/PlatformFilesystem.java b/sources/lwjgl/java/net/lax1dude/eaglercraft/v1_8/internal/PlatformFilesystem.java
index e8ae9daa..c8562c58 100644
--- a/sources/lwjgl/java/net/lax1dude/eaglercraft/v1_8/internal/PlatformFilesystem.java
+++ b/sources/lwjgl/java/net/lax1dude/eaglercraft/v1_8/internal/PlatformFilesystem.java
@@ -2,7 +2,6 @@ package net.lax1dude.eaglercraft.v1_8.internal;
 
 import java.io.File;
 
-import net.lax1dude.eaglercraft.v1_8.internal.buffer.ByteBuffer;
 import net.lax1dude.eaglercraft.v1_8.internal.lwjgl.DebugFilesystem;
 import net.lax1dude.eaglercraft.v1_8.internal.lwjgl.JDBCFilesystem;
 import net.lax1dude.eaglercraft.v1_8.internal.lwjgl.JDBCFilesystemConverter;
@@ -28,104 +27,50 @@ public class PlatformFilesystem {
 
 	public static final Logger logger = LogManager.getLogger("PlatformFilesystem");
 
+	@Deprecated
 	public static final File debugFilesystemRoot = (new File("filesystem/sp")).getAbsoluteFile();
 
-	private static IFilesystemProvider provider = null;
+	public static final File filesystemsRoot = (new File("filesystem")).getAbsoluteFile();
 
-	public static String jdbcUri = null;
-	public static String jdbcDriver = null;
+	private static final boolean isLegacyFolder = checkLegacy();
 
-	public static void initialize() {
-		if(provider == null) {
-			if(jdbcUri != null && jdbcDriver != null) {
-				provider = JDBCFilesystem.initialize(jdbcUri, jdbcDriver);
+	private static boolean checkLegacy() {
+		if(!debugFilesystemRoot.isDirectory()) return false;
+		String[] str = debugFilesystemRoot.list();
+		return str != null && str.length > 0;
+	}
+
+	public static IEaglerFilesystem initializePersist(String dbName) {
+		String jdbcUri = System.getProperty("eagler.jdbc." + dbName + ".uri");
+		String jdbcDriver = System.getProperty("eagler.jdbc." + dbName + ".driver");
+		if(jdbcUri != null && jdbcDriver != null) {
+			try {
+				IEaglerFilesystem provider = JDBCFilesystem.initialize(dbName, jdbcUri, jdbcDriver);
 				if(((JDBCFilesystem)provider).isNewFilesystem() && debugFilesystemRoot.isDirectory() && debugFilesystemRoot.list().length > 0) {
 					JDBCFilesystemConverter.convertFilesystem("Converting filesystem, please wait...", debugFilesystemRoot, provider, true);
 				}
+				return provider;
+			}catch(Throwable t) {
+				logger.error("Could not open jdbc-based filesystem: {}", dbName);
+				logger.error(t);
+				return null;
+			}
+		}else {
+			File f;
+			if(isLegacyFolder && (dbName.equals("worlds") || dbName.equals("resourcePacks"))) {
+				f = debugFilesystemRoot;
+				logger.info("Note: filesystem \"{}\" will be stored in the legacy \"sp\" folder because it exists and is not empty", dbName);
 			}else {
-				provider = DebugFilesystem.initialize(debugFilesystemRoot);
+				f = new File(filesystemsRoot, dbName);
+			}
+			try {
+				return DebugFilesystem.initialize(dbName, f);
+			}catch(Throwable t) {
+				logger.error("Could not open folder-based filesystem: {}", dbName);
+				logger.error(t);
+				return null;
 			}
 		}
 	}
 
-	public static void setUseJDBC(String uri) {
-		jdbcUri = uri;
-	}
-
-	public static void setJDBCDriverClass(String driver) {
-		jdbcDriver = driver;
-	}
-
-	public static interface IFilesystemProvider {
-
-		boolean eaglerDelete(String pathName);
-
-		ByteBuffer eaglerRead(String pathName);
-
-		void eaglerWrite(String pathName, ByteBuffer data);
-
-		boolean eaglerExists(String pathName);
-
-		boolean eaglerMove(String pathNameOld, String pathNameNew);
-
-		int eaglerCopy(String pathNameOld, String pathNameNew);
-
-		int eaglerSize(String pathName);
-
-		void eaglerIterate(String pathName, VFSFilenameIterator itr, boolean recursive);
-
-	}
-
-	private static void throwNotInitialized() {
-		throw new UnsupportedOperationException("Filesystem has not been initialized!");
-	}
-
-	public static boolean eaglerDelete(String pathName) {
-		if(provider == null) throwNotInitialized();
-		return provider.eaglerDelete(pathName);
-	}
-
-	public static ByteBuffer eaglerRead(String pathName) {
-		if(provider == null) throwNotInitialized();
-		return provider.eaglerRead(pathName);
-	}
-
-	public static void eaglerWrite(String pathName, ByteBuffer data) {
-		if(provider == null) throwNotInitialized();
-		provider.eaglerWrite(pathName, data);
-	}
-
-	public static boolean eaglerExists(String pathName) {
-		if(provider == null) throwNotInitialized();
-		return provider.eaglerExists(pathName);
-	}
-
-	public static boolean eaglerMove(String pathNameOld, String pathNameNew) {
-		if(provider == null) throwNotInitialized();
-		return provider.eaglerMove(pathNameOld, pathNameNew);
-	}
-
-	public static int eaglerCopy(String pathNameOld, String pathNameNew) {
-		if(provider == null) throwNotInitialized();
-		return provider.eaglerCopy(pathNameOld, pathNameNew);
-	}
-
-	public static int eaglerSize(String pathName) {
-		if(provider == null) throwNotInitialized();
-		return provider.eaglerSize(pathName);
-	}
-
-	public static void eaglerIterate(String pathName, VFSFilenameIterator itr, boolean recursive) {
-		if(provider == null) throwNotInitialized();
-		provider.eaglerIterate(pathName, itr, recursive);
-	}
-
-	public static void platformShutdown() {
-		if(provider != null) {
-			if(provider instanceof JDBCFilesystem) {
-				((JDBCFilesystem)provider).shutdown();
-			}
-			provider = null;
-		}
-	}
 }
diff --git a/sources/lwjgl/java/net/lax1dude/eaglercraft/v1_8/internal/PlatformInput.java b/sources/lwjgl/java/net/lax1dude/eaglercraft/v1_8/internal/PlatformInput.java
index d8648711..d8d15cd5 100644
--- a/sources/lwjgl/java/net/lax1dude/eaglercraft/v1_8/internal/PlatformInput.java
+++ b/sources/lwjgl/java/net/lax1dude/eaglercraft/v1_8/internal/PlatformInput.java
@@ -2,15 +2,20 @@ package net.lax1dude.eaglercraft.v1_8.internal;
 
 import static org.lwjgl.glfw.GLFW.*;
 
+import java.util.ArrayList;
+import java.util.HashSet;
 import java.util.LinkedList;
 import java.util.List;
+import java.util.Objects;
+import java.util.Set;
 
 import org.lwjgl.PointerBuffer;
+import org.lwjgl.glfw.GLFWGamepadState;
 import org.lwjgl.glfw.GLFWVidMode;
 import org.lwjgl.system.MemoryStack;
 
 /**
- * Copyright (c) 2022-2023 lax1dude, ayunami2000. All Rights Reserved.
+ * Copyright (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved.
  * 
  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
@@ -34,6 +39,7 @@ public class PlatformInput {
 	
 	private static boolean windowFocused = true;
 	private static boolean windowResized = true;
+	private static boolean windowResized2 = true;
 	
 	private static boolean windowCursorEntered = true;
 	private static boolean windowMouseGrabbed = false;
@@ -46,7 +52,7 @@ public class PlatformInput {
 	private static int windowWidth = 640;
 	private static int windowHeight = 480;
 	
-	private static final List<KeyboardEvent> keyboardEventList = new LinkedList();
+	private static final List<KeyboardEvent> keyboardEventList = new LinkedList<>();
 	private static KeyboardEvent currentKeyboardEvent = null;
 	
 	private static final char[] keyboardReleaseEventChars = new char[256];
@@ -56,7 +62,7 @@ public class PlatformInput {
 
 	public static boolean lockKeys = false;
 
-	private static final List<Character> keyboardCharList = new LinkedList();
+	private static final List<Character> keyboardCharList = new LinkedList<>();
 
 	private static boolean vsync = true;
 	private static boolean glfwVSyncState = false;
@@ -75,8 +81,8 @@ public class PlatformInput {
 		}
 		
 	}
-	
-	private static final List<MouseEvent> mouseEventList = new LinkedList();
+
+	private static final List<MouseEvent> mouseEventList = new LinkedList<>();
 	private static MouseEvent currentMouseEvent = null;
 	
 	private static class MouseEvent {
@@ -97,6 +103,44 @@ public class PlatformInput {
 		
 	}
 
+	private static final List<Gamepad> gamepadList = new ArrayList<>();
+	private static int selectedGamepad = -1;
+	private static String selectedGamepadName = null;
+	private static String selectedGamepadUUID = null;
+	private static final boolean[] gamepadButtonStates = new boolean[24];
+	private static final float[] gamepadAxisStates = new float[4];
+	
+	private static class Gamepad {
+		
+		protected final int gamepadId;
+		protected final String gamepadName;
+		protected final String gamepadUUID;
+		
+		protected Gamepad(int gamepadId, String gamepadName, String gamepadUUID) {
+			this.gamepadId = gamepadId;
+			this.gamepadName = gamepadName;
+			this.gamepadUUID = gamepadUUID;
+		}
+
+		@Override
+		public int hashCode() {
+			return Objects.hash(gamepadId, gamepadName, gamepadUUID);
+		}
+
+		@Override
+		public boolean equals(Object obj) {
+			if (this == obj)
+				return true;
+			if (obj == null)
+				return false;
+			if (getClass() != obj.getClass())
+				return false;
+			Gamepad other = (Gamepad) obj;
+			return gamepadId == other.gamepadId && Objects.equals(gamepadName, other.gamepadName)
+					&& Objects.equals(gamepadUUID, other.gamepadUUID);
+		}
+	}
+
 	static void initHooks(long glfwWindow) {
 		win = glfwWindow;
 		
@@ -121,13 +165,20 @@ public class PlatformInput {
 		
 		windowWidth = v1[0];
 		windowHeight = v2[0];
+		windowResized = true;
+		windowResized2 = true;
 		
 		glfwSetFramebufferSizeCallback(glfwWindow, (window, width, height) -> {
-			windowWidth = width;
-			windowHeight = height;
-			windowResized = true;
+			if(windowWidth != width || windowHeight != height) {
+				windowWidth = width;
+				windowHeight = height;
+				windowResized = true;
+				windowResized2 = true;
+			}
 		});
 		
+		windowFocused = true;
+		
 		glfwSetWindowFocusCallback(glfwWindow, (window, focused) -> {
 			windowFocused = focused;
 		});
@@ -199,6 +250,15 @@ public class PlatformInput {
 		if(!fullscreen && startupFullscreen) {
 			toggleFullscreen();
 		}
+		
+		gamepadEnumerateDevices();
+		
+		glfwSetJoystickCallback((jid, event) -> {
+			if(event == GLFW_DISCONNECTED && jid == selectedGamepad) {
+				selectedGamepad = -1;
+			}
+			gamepadEnumerateDevices();
+		});
 	}
 	
 	public static int getWindowWidth() {
@@ -209,6 +269,22 @@ public class PlatformInput {
 		return windowHeight;
 	}
 
+	public static int getVisualViewportX() {
+		return 0;
+	}
+
+	public static int getVisualViewportY() {
+		return 0;
+	}
+
+	public static int getVisualViewportW() {
+		return windowWidth;
+	}
+
+	public static int getVisualViewportH() {
+		return windowHeight;
+	}
+
 	public static boolean getWindowFocused() {
 		return windowFocused;
 	}
@@ -240,6 +316,12 @@ public class PlatformInput {
 		return b;
 	}
 
+	public static boolean wasVisualViewportResized() {
+		boolean b = windowResized2;
+		windowResized2 = false;
+		return b;
+	}
+
 	public static boolean keyboardNext() {
 		if(keyboardEventList.size() > 0) {
 			currentKeyboardEvent = keyboardEventList.remove(0);
@@ -274,6 +356,33 @@ public class PlatformInput {
 		}
 	}
 
+	public static void keyboardFireEvent(EnumFireKeyboardEvent eventType, int eagKey, char keyChar) {
+		switch(eventType) {
+		case KEY_DOWN:
+			keyboardCharList.add(keyChar);
+			keyboardEventList.add(new KeyboardEvent(eagKey, true, false));
+			break;
+		case KEY_UP:
+			if(eagKey >= 0 && eagKey < keyboardReleaseEventChars.length) {
+				keyboardReleaseEventChars[eagKey] = keyChar;
+			}
+			keyboardEventList.add(new KeyboardEvent(eagKey, false, false));
+			break;
+		case KEY_REPEAT:
+			keyboardCharList.add(keyChar);
+			keyboardEventList.add(new KeyboardEvent(eagKey, true, true));
+			break;
+		default:
+			throw new UnsupportedOperationException();
+		}
+		if(keyboardEventList.size() > 64) {
+			keyboardEventList.remove(0);
+		}
+		if(keyboardCharList.size() > 64) {
+			keyboardCharList.remove(0);
+		}
+	}
+
 	public static boolean keyboardGetEventKeyState() {
 		return currentKeyboardEvent.pressed;
 	}
@@ -315,6 +424,44 @@ public class PlatformInput {
 		}
 	}
 
+	public static void mouseFireMoveEvent(EnumFireMouseEvent eventType, int posX, int posY) {
+		if(eventType == EnumFireMouseEvent.MOUSE_MOVE) {
+			mouseEventList.add(new MouseEvent(-1, false, posX, posY, 0.0f));
+			if(mouseEventList.size() > 64) {
+				mouseEventList.remove(0);
+			}
+		}else {
+			throw new UnsupportedOperationException();
+		}
+	}
+
+	public static void mouseFireButtonEvent(EnumFireMouseEvent eventType, int posX, int posY, int button) {
+		switch(eventType) {
+		case MOUSE_DOWN:
+			mouseEventList.add(new MouseEvent(button, true, posX, posY, 0.0f));
+			break;
+		case MOUSE_UP:
+			mouseEventList.add(new MouseEvent(button, false, posX, posY, 0.0f));
+			break;
+		default:
+			throw new UnsupportedOperationException();
+		}
+		if(mouseEventList.size() > 64) {
+			mouseEventList.remove(0);
+		}
+	}
+
+	public static void mouseFireWheelEvent(EnumFireMouseEvent eventType, int posX, int posY, float wheel) {
+		if(eventType == EnumFireMouseEvent.MOUSE_WHEEL) {
+			mouseEventList.add(new MouseEvent(-1, false, posX, posY, wheel));
+			if(mouseEventList.size() > 64) {
+				mouseEventList.remove(0);
+			}
+		}else {
+			throw new UnsupportedOperationException();
+		}
+	}
+
 	public static boolean mouseGetEventButtonState() {
 		return currentMouseEvent.pressed;
 	}
@@ -366,6 +513,10 @@ public class PlatformInput {
 		}
 	}
 
+	public static boolean mouseGrabSupported() {
+		return true;
+	}
+
 	public static boolean isPointerLocked() {
 		return windowMouseGrabbed;
 	}
@@ -404,6 +555,10 @@ public class PlatformInput {
 		functionKeyModifier = KeyboardConstants.getGLFWKeyFromEagler(key);
 	}
 
+	public static boolean supportsFullscreen() {
+		return true;
+	}
+
 	private static boolean fullscreen = false;
 	private static boolean startupFullscreen = false;
 	private static int[] lastPos = new int[4];
@@ -483,4 +638,247 @@ public class PlatformInput {
 			break;
 		}
 	}
+
+	public static boolean touchNext() {
+		return false;
+	}
+
+	public static EnumTouchEvent touchGetEventType() {
+		return null;
+	}
+
+	public static int touchGetEventTouchPointCount() {
+		return 0;
+	}
+
+	public static int touchGetEventTouchX(int pointId) {
+		return 0;
+	}
+
+	public static int touchGetEventTouchY(int pointId) {
+		return 0;
+	}
+
+	public static float touchGetEventTouchRadiusX(int pointId) {
+		return 0.0f;
+	}
+
+	public static float touchGetEventTouchRadiusY(int pointId) {
+		return 0.0f;
+	}
+
+	public static float touchGetEventTouchRadiusMixed(int pointId) {
+		return touchGetEventTouchRadiusX(pointId) * 0.5f + touchGetEventTouchRadiusY(pointId) * 0.5f;
+	}
+
+	public static float touchGetEventTouchForce(int pointId) {
+		return 0.0f;
+	}
+
+	public static int touchGetEventTouchPointUID(int pointId) {
+		return 0;
+	}
+
+	public static int touchPointCount() {
+		return 0;
+	}
+
+	public static int touchPointX(int pointId) {
+		return 0;
+	}
+
+	public static int touchPointY(int pointId) {
+		return 0;
+	}
+
+	public static float touchRadiusX(int pointId) {
+		return 0.0f;
+	}
+
+	public static float touchRadiusY(int pointId) {
+		return 0.0f;
+	}
+
+	public static float touchRadiusMixed(int pointId) {
+		return touchRadiusX(pointId) * 0.5f + touchRadiusY(pointId) * 0.5f;
+	}
+
+	public static float touchForce(int pointId) {
+		return 0.0f;
+	}
+
+	public static int touchPointUID(int pointId) {
+		return 0;
+	}
+
+	public static void touchSetOpenKeyboardZone(int x, int y, int w, int h) {
+		
+	}
+
+	public static void touchCloseDeviceKeyboard() {
+		
+	}
+
+	public static boolean touchIsDeviceKeyboardOpenMAYBE() {
+		return false;
+	}
+
+	public static String touchGetPastedString() {
+		return null;
+	}
+
+	private static void gamepadEnumerateDevices() {
+		if(selectedGamepad != -1 && !glfwJoystickIsGamepad(selectedGamepad)) {
+			selectedGamepad = -1;
+		}
+		List<Gamepad> oldList = null;
+		if(!gamepadList.isEmpty()) {
+			oldList = new ArrayList<>(gamepadList);
+			gamepadList.clear();
+		}
+		for(int i = GLFW_JOYSTICK_1; i <= GLFW_JOYSTICK_16; ++i) {
+			if(glfwJoystickIsGamepad(i)) {
+				gamepadList.add(new Gamepad(i, gamepadMakeName(i), glfwGetJoystickGUID(i)));
+			}
+		}
+		vigg: if(selectedGamepad != -1) {
+			for(int i = 0, l = gamepadList.size(); i < l; ++i) {
+				Gamepad gp = gamepadList.get(i);
+				if(gp.gamepadId == selectedGamepad && gp.gamepadUUID.equals(selectedGamepadUUID)) {
+					break vigg;
+				}
+			}
+			selectedGamepad = -1;
+		}
+		if(oldList == null) {
+			if(!gamepadList.isEmpty()) {
+				for(int i = 0, l = gamepadList.size(); i < l; ++i) {
+					PlatformRuntime.logger.info("Found controller: {}", gamepadList.get(i).gamepadName);
+				}
+			}
+		}else {
+			if(gamepadList.isEmpty()) {
+				for(int i = 0, l = oldList.size(); i < l; ++i) {
+					PlatformRuntime.logger.info("Lost controller: {}", oldList.get(i).gamepadName);
+				}
+			}else {
+				Set<String> oldGamepadUUIDs = new HashSet<>();
+				for(int i = 0, l = oldList.size(); i < l; ++i) {
+					oldGamepadUUIDs.add(oldList.get(i).gamepadUUID);
+				}
+				Set<String> newGamepadUUIDs = new HashSet<>();
+				for(int i = 0, l = gamepadList.size(); i < l; ++i) {
+					newGamepadUUIDs.add(gamepadList.get(i).gamepadUUID);
+				}
+				for(int i = 0, l = oldList.size(); i < l; ++i) {
+					Gamepad g = oldList.get(i);
+					if(!newGamepadUUIDs.contains(g.gamepadUUID)) {
+						PlatformRuntime.logger.info("Lost controller: {}", g.gamepadName);
+					}
+				}
+				for(int i = 0, l = gamepadList.size(); i < l; ++i) {
+					Gamepad g = gamepadList.get(i);
+					if(!oldGamepadUUIDs.contains(g.gamepadUUID)) {
+						PlatformRuntime.logger.info("Found controller: {}", g.gamepadName);
+					}
+				}
+			}
+		}
+		
+	}
+
+	private static String gamepadMakeName(int glfwId) {
+		String s = glfwGetGamepadName(glfwId);
+		if(s.endsWith(" (GLFW)")) {
+			s = s.substring(0, s.length() - 7);
+		}
+		return glfwGetJoystickName(glfwId) + " (" + s + ")";
+	}
+
+	public static int gamepadGetValidDeviceCount() {
+		return gamepadList.size();
+	}
+
+	public static String gamepadGetDeviceName(int deviceId) {
+		if(deviceId >= 0 && deviceId < gamepadList.size()) {
+			return gamepadList.get(deviceId).gamepadName;
+		}else {
+			return "Unknown";
+		}
+	}
+
+	public static void gamepadSetSelectedDevice(int deviceId) {
+		gamepadReset();
+		if(deviceId >= 0 && deviceId < gamepadList.size()) {
+			selectedGamepad = gamepadList.get(deviceId).gamepadId;
+			if(!glfwJoystickIsGamepad(selectedGamepad)) {
+				selectedGamepad = -1;
+			}
+		}else {
+			selectedGamepad = -1;
+		}
+	}
+
+	private static void gamepadReset() {
+		for(int i = 0; i < gamepadButtonStates.length; ++i) {
+			gamepadButtonStates[i] = false;
+		}
+		for(int i = 0; i < gamepadAxisStates.length; ++i) {
+			gamepadAxisStates[i] = 0.0f;
+		}
+	}
+
+	public static void gamepadUpdate() {
+		gamepadReset();
+		if(selectedGamepad != -1) {
+			if(!glfwJoystickIsGamepad(selectedGamepad)) {
+				selectedGamepad = -1;
+				return;
+			}
+			try(MemoryStack ms = MemoryStack.stackPush()) {
+				GLFWGamepadState state = GLFWGamepadState.calloc(ms);
+				glfwGetGamepadState(selectedGamepad, state);
+				java.nio.FloatBuffer axes = state.axes();
+				axes.get(gamepadAxisStates);
+				java.nio.ByteBuffer buttons = state.buttons();
+				for(int i = 0, l = buttons.remaining(); i < l && i < gamepadButtonStates.length; ++i) {
+					boolean v = buttons.get() != (byte)0;
+					int j = GamepadConstants.getEaglerButtonFromGLFW(i);
+					if(j != -1) {
+						gamepadButtonStates[j] = v;
+					}
+				}
+				gamepadButtonStates[GamepadConstants.GAMEPAD_LEFT_TRIGGER] = axes.get() > 0.4f;
+				gamepadButtonStates[GamepadConstants.GAMEPAD_RIGHT_TRIGGER] = axes.get() > 0.4f;
+			}
+		}
+	}
+
+	public static boolean gamepadIsValid() {
+		return selectedGamepad != -1;
+	}
+
+	public static String gamepadGetName() {
+		return selectedGamepad != -1 ? selectedGamepadName : "Unknown";
+	}
+
+	public static boolean gamepadGetButtonState(int button) {
+		return selectedGamepad != -1 && button >= 0 && button < gamepadButtonStates.length ? gamepadButtonStates[button] : false;
+	}
+
+	public static float gamepadGetAxis(int axis) {
+		return selectedGamepad != -1 && axis >= 0 && axis < gamepadAxisStates.length ? gamepadAxisStates[axis] : 0.0f;
+	}
+
+	public static float getDPI() {
+		float[] dpiX = new float[1];
+		float[] dpiY = new float[1];
+		glfwGetWindowContentScale(win, dpiX, dpiY);
+		float ret = dpiX[0] * 0.5f + dpiY[0] * 0.5f;
+		if(ret <= 0.0f) {
+			ret = 1.0f;
+		}
+		return ret;
+	}
+
 }
diff --git a/sources/lwjgl/java/net/lax1dude/eaglercraft/v1_8/internal/PlatformNetworking.java b/sources/lwjgl/java/net/lax1dude/eaglercraft/v1_8/internal/PlatformNetworking.java
index 2989e560..3b81f5d0 100644
--- a/sources/lwjgl/java/net/lax1dude/eaglercraft/v1_8/internal/PlatformNetworking.java
+++ b/sources/lwjgl/java/net/lax1dude/eaglercraft/v1_8/internal/PlatformNetworking.java
@@ -2,17 +2,13 @@ package net.lax1dude.eaglercraft.v1_8.internal;
 
 import java.net.URI;
 import java.net.URISyntaxException;
-import java.util.ArrayList;
-import java.util.LinkedList;
-import java.util.List;
-
-import org.java_websocket.enums.ReadyState;
 
+import net.lax1dude.eaglercraft.v1_8.internal.lwjgl.DesktopWebSocketClient;
 import net.lax1dude.eaglercraft.v1_8.log4j.LogManager;
 import net.lax1dude.eaglercraft.v1_8.log4j.Logger;
 
 /**
- * Copyright (c) 2022-2023 lax1dude, ayunami2000. All Rights Reserved.
+ * Copyright (c) 2022-2024 lax1dude. All Rights Reserved.
  * 
  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
@@ -28,124 +24,22 @@ import net.lax1dude.eaglercraft.v1_8.log4j.Logger;
  */
 public class PlatformNetworking {
 	
-	static final Logger networkLogger = LogManager.getLogger("PlatformNetworking");
+	private static final Logger logger = LogManager.getLogger("PlatformNetworking");
 	
-	private static WebSocketPlayClient wsPlayClient = null;
-	static EnumEaglerConnectionState playConnectState = EnumEaglerConnectionState.CLOSED;
-	static EnumServerRateLimit serverRateLimit = null;
-	
-	static String currentURI = null;
-	
-	public static EnumEaglerConnectionState playConnectionState() {
-		return ((wsPlayClient == null || wsPlayClient.isClosed()) && playConnectState == EnumEaglerConnectionState.CONNECTING) ? EnumEaglerConnectionState.FAILED :
-			((wsPlayClient != null && wsPlayClient.getReadyState() == ReadyState.NOT_YET_CONNECTED) ? EnumEaglerConnectionState.CONNECTING : 
-				(((wsPlayClient == null || wsPlayClient.isClosed()) && playConnectState != EnumEaglerConnectionState.FAILED) ? EnumEaglerConnectionState.CLOSED : playConnectState));
-	}
-	
-	public static void startPlayConnection(String destination) {
-		if(!playConnectionState().isClosed()) {
-			networkLogger.warn("Tried connecting to a server while already connected to a different server!");
-			playDisconnect();
-		}
-		
-		currentURI = destination;
-		
-		synchronized(playPackets) {
-			playPackets.clear();
-		}
-		
-		playConnectState = EnumEaglerConnectionState.CONNECTING;
-		networkLogger.info("Connecting to server: {}", destination);
-		
-		URI u;
-		
+	public static IWebSocketClient openWebSocket(String socketURI) {
 		try {
-			u = new URI(destination);
-		}catch(URISyntaxException ex) {
-			networkLogger.error("Invalid server URI: {}", destination);
-			playConnectState = EnumEaglerConnectionState.FAILED;
-			return;
-		}
-		
-		wsPlayClient = new WebSocketPlayClient(u);
-		wsPlayClient.connect();
-	}
-	
-	public static void playDisconnect() {
-		if(!playConnectionState().isClosed() && wsPlayClient != null) {
-			try {
-				wsPlayClient.closeBlocking();
-			} catch (InterruptedException e) {
-				// :(
-			}
-			playConnectState = EnumEaglerConnectionState.CLOSED;
-		}
-	}
-	
-	private static final List<byte[]> playPackets = new LinkedList();
-	
-	public static byte[] readPlayPacket() {
-		synchronized(playPackets) {
-			return playPackets.size() > 0 ? playPackets.remove(0) : null;
-		}
-	}
-	
-	public static List<byte[]> readAllPacket() {
-		synchronized(playPackets) {
-			if(!playPackets.isEmpty()) {
-				List<byte[]> ret = new ArrayList<>(playPackets);
-				playPackets.clear();
-				return ret;
-			}else {
-				return null;
-			}
-		}
-	}
-	
-	public static int countAvailableReadData() {
-		int total = 0;
-		synchronized(playPackets) {
-			for(int i = 0, l = playPackets.size(); i < l; ++i) {
-				total += playPackets.get(i).length;
-			}
-		}
-		return total;
-	}
-	
-	static void recievedPlayPacket(byte[] arg0) {
-		synchronized(playPackets) {
-			playPackets.add(arg0);
-		}
-	}
-	
-	public static void writePlayPacket(byte[] pkt) {
-		if(wsPlayClient == null || wsPlayClient.isClosed()) {
-			networkLogger.error("Tried to send {} byte play packet while the socket was closed!", pkt.length);
-		}else {
-			wsPlayClient.send(pkt);
-		}
-	}
-	
-	public static IServerQuery sendServerQuery(String uri, String accept) {
-		URI u;
-		
-		try {
-			u = new URI(uri);
-		}catch(URISyntaxException ex) {
-			networkLogger.error("Invalid server URI: {}", uri);
-			playConnectState = EnumEaglerConnectionState.FAILED;
+			URI uri = new URI(socketURI);
+			return new DesktopWebSocketClient(uri);
+		}catch(Throwable t) {
+			logger.error("Could not open WebSocket to \"{}\"!", socketURI);
+			logger.error(t);
 			return null;
 		}
-		
-		return new WebSocketServerQuery(accept, u);
 	}
 	
-	public static EnumServerRateLimit getRateLimit() {
-		return serverRateLimit == null ? EnumServerRateLimit.OK : serverRateLimit;
-	}
-	
-	public static String getCurrentURI() {
-		return currentURI;
+	public static IWebSocketClient openWebSocketUnsafe(String socketURI) throws URISyntaxException {
+		URI uri = new URI(socketURI);
+		return new DesktopWebSocketClient(uri);
 	}
 	
 }
diff --git a/sources/lwjgl/java/net/lax1dude/eaglercraft/v1_8/internal/PlatformOpenGL.java b/sources/lwjgl/java/net/lax1dude/eaglercraft/v1_8/internal/PlatformOpenGL.java
index 7fffdcfd..768dbb91 100644
--- a/sources/lwjgl/java/net/lax1dude/eaglercraft/v1_8/internal/PlatformOpenGL.java
+++ b/sources/lwjgl/java/net/lax1dude/eaglercraft/v1_8/internal/PlatformOpenGL.java
@@ -6,6 +6,13 @@ import net.lax1dude.eaglercraft.v1_8.internal.buffer.FloatBuffer;
 import net.lax1dude.eaglercraft.v1_8.internal.buffer.IntBuffer;
 
 import static org.lwjgl.opengles.GLES30.*;
+import static org.lwjgl.opengles.ANGLEInstancedArrays.*;
+import static org.lwjgl.opengles.EXTInstancedArrays.*;
+import static org.lwjgl.opengles.EXTTextureStorage.*;
+import static org.lwjgl.opengles.OESVertexArrayObject.*;
+
+import java.util.ArrayList;
+import java.util.List;
 
 import org.lwjgl.opengles.GLESCapabilities;
 
@@ -26,10 +33,103 @@ import org.lwjgl.opengles.GLESCapabilities;
  */
 public class PlatformOpenGL {
 
+	private static int glesVers = -1;
+
+	private static boolean hasANGLEInstancedArrays = false;
+	private static boolean hasEXTColorBufferFloat = false;
+	private static boolean hasEXTColorBufferHalfFloat = false;
+	private static boolean hasEXTGPUShader5 = false;
+	private static boolean hasEXTInstancedArrays = false;
+	private static boolean hasEXTShaderTextureLOD = false;
+	private static boolean hasEXTTextureStorage = false;
+	private static boolean hasOESFBORenderMipmap = false;
+	private static boolean hasOESGPUShader5 = false;
+	private static boolean hasOESVertexArrayObject = false;
+	private static boolean hasOESTextureFloat = false;
+	private static boolean hasOESTextureFloatLinear = false;
+	private static boolean hasOESTextureHalfFloat = false;
+	private static boolean hasOESTextureHalfFloatLinear = false;
+	private static boolean hasEXTTextureFilterAnisotropic = false;
+
+	private static boolean hasFBO16FSupport = false;
+	private static boolean hasFBO32FSupport = false;
+	private static boolean hasLinearHDR16FSupport = false;
 	private static boolean hasLinearHDR32FSupport = false;
 
-	static void setCurrentContext(GLESCapabilities caps) {
+	private static final int VAO_IMPL_NONE = -1;
+	private static final int VAO_IMPL_CORE = 0;
+	private static final int VAO_IMPL_OES = 1;
+	private static int vertexArrayImpl = VAO_IMPL_NONE;
+
+	private static final int INSTANCE_IMPL_NONE = -1;
+	private static final int INSTANCE_IMPL_CORE = 0;
+	private static final int INSTANCE_IMPL_ANGLE = 1;
+	private static final int INSTANCE_IMPL_EXT = 2;
+	private static int instancingImpl = INSTANCE_IMPL_NONE;
+
+	private static final int TEX_STORAGE_IMPL_NONE = -1;
+	private static final int TEX_STORAGE_IMPL_CORE = 0;
+	private static final int TEX_STORAGE_IMPL_EXT = 1;
+	private static int texStorageImpl = TEX_STORAGE_IMPL_NONE;
+
+	static void setCurrentContext(int glesVersIn, GLESCapabilities caps) {
+		glesVers = glesVersIn;
+
+		hasANGLEInstancedArrays = glesVersIn == 200 && caps.GL_ANGLE_instanced_arrays;
+		hasOESTextureFloat = glesVersIn == 200 && caps.GL_OES_texture_float;
+		hasOESTextureFloatLinear = glesVersIn >= 300 && caps.GL_OES_texture_float_linear;
+		hasOESTextureHalfFloat = glesVersIn == 200 && caps.GL_OES_texture_half_float;
+		hasOESTextureHalfFloatLinear = glesVersIn == 200 && caps.GL_OES_texture_half_float_linear;
+		hasEXTColorBufferFloat = (glesVersIn == 310 || glesVersIn == 300) && caps.GL_EXT_color_buffer_float;
+		hasEXTColorBufferHalfFloat = !hasEXTColorBufferFloat
+				&& (glesVersIn == 310 || glesVersIn == 300 || glesVersIn == 200) && caps.GL_EXT_color_buffer_half_float;
+		hasEXTInstancedArrays = !hasANGLEInstancedArrays && glesVersIn == 200 && caps.GL_EXT_instanced_arrays;
+		hasEXTShaderTextureLOD = glesVersIn == 200 && caps.GL_EXT_shader_texture_lod;
+		hasEXTTextureStorage = glesVersIn == 200 && caps.GL_EXT_texture_storage;
+		hasOESGPUShader5 = glesVersIn == 310 && caps.GL_OES_gpu_shader5;
+		hasEXTGPUShader5 = !hasOESGPUShader5 && glesVersIn == 310 && caps.GL_EXT_gpu_shader5;
+		hasOESFBORenderMipmap = glesVersIn == 200 && caps.GL_OES_fbo_render_mipmap;
+		hasOESVertexArrayObject = glesVersIn == 200 && caps.GL_OES_vertex_array_object;
 		hasLinearHDR32FSupport = caps.GL_OES_texture_float_linear;
+		hasEXTTextureFilterAnisotropic = caps.GL_EXT_texture_filter_anisotropic;
+		
+		hasFBO16FSupport = glesVersIn >= 320 || ((glesVersIn >= 300 || hasOESTextureFloat) && (hasEXTColorBufferFloat || hasEXTColorBufferHalfFloat));
+		hasFBO32FSupport = glesVersIn >= 320 || ((glesVersIn >= 300 || hasOESTextureHalfFloat) && hasEXTColorBufferFloat);
+		hasLinearHDR16FSupport = glesVersIn >= 300 || hasOESTextureHalfFloatLinear;
+		hasLinearHDR32FSupport = glesVersIn >= 300 && hasOESTextureFloatLinear;
+		
+		if(glesVersIn >= 300) {
+			vertexArrayImpl = VAO_IMPL_CORE;
+			instancingImpl = INSTANCE_IMPL_CORE;
+			texStorageImpl = TEX_STORAGE_IMPL_CORE;
+		}else if(glesVersIn == 200) {
+			vertexArrayImpl = hasOESVertexArrayObject ? VAO_IMPL_OES : VAO_IMPL_NONE;
+			instancingImpl = hasANGLEInstancedArrays ? INSTANCE_IMPL_ANGLE : (hasEXTInstancedArrays ? INSTANCE_IMPL_EXT : INSTANCE_IMPL_NONE);
+			texStorageImpl = hasEXTTextureStorage ? TEX_STORAGE_IMPL_EXT : TEX_STORAGE_IMPL_NONE;
+		}else {
+			vertexArrayImpl = VAO_IMPL_NONE;
+			instancingImpl = INSTANCE_IMPL_NONE;
+			texStorageImpl = TEX_STORAGE_IMPL_NONE;
+		}
+	}
+
+	public static final List<String> dumpActiveExtensions() {
+		List<String> exts = new ArrayList<>();
+		if(hasANGLEInstancedArrays) exts.add("ANGLE_instanced_arrays");
+		if(hasEXTColorBufferFloat) exts.add("EXT_color_buffer_float");
+		if(hasEXTColorBufferHalfFloat) exts.add("EXT_color_buffer_half_float");
+		if(hasEXTGPUShader5) exts.add("EXT_gpu_shader5");
+		if(hasEXTInstancedArrays) exts.add("EXT_instanced_arrays");
+		if(hasEXTTextureStorage) exts.add("EXT_texture_storage");
+		if(hasOESFBORenderMipmap) exts.add("OES_fbo_render_mipmap");
+		if(hasOESGPUShader5) exts.add("OES_gpu_shader5");
+		if(hasOESVertexArrayObject) exts.add("OES_vertex_array_object");
+		if(hasOESTextureFloat) exts.add("OES_texture_float");
+		if(hasOESTextureFloatLinear) exts.add("OES_texture_float_linear");
+		if(hasOESTextureHalfFloat) exts.add("OES_texture_half_float");
+		if(hasOESTextureHalfFloatLinear) exts.add("OES_texture_half_float_linear");
+		if(hasEXTTextureFilterAnisotropic) exts.add("EXT_texture_filter_anisotropic");
+		return exts;
 	}
 
 	public static final void _wglEnable(int glEnum) {
@@ -89,17 +189,45 @@ public class PlatformOpenGL {
 	}
 
 	public static final void _wglDrawBuffers(int buffer) {
-		glDrawBuffers(buffer);
+		if(glesVers == 200) {
+			if(buffer != 0x8CE0) { // GL_COLOR_ATTACHMENT0
+				throw new UnsupportedOperationException();
+			}
+		}else {
+			glDrawBuffers(buffer);
+		}
 	}
 
 	public static final void _wglDrawBuffers(int[] buffers) {
-		glDrawBuffers(buffers);
+		if(glesVers == 200) {
+			if(buffers.length != 1 || buffers[0] != 0x8CE0) { // GL_COLOR_ATTACHMENT0
+				throw new UnsupportedOperationException();
+			}
+		}else {
+			glDrawBuffers(buffers);
+		}
 	}
 
 	public static final void _wglReadBuffer(int buffer) {
 		glReadBuffer(buffer);
 	}
 
+	public static final void _wglReadPixels(int x, int y, int width, int height, int format, int type, ByteBuffer data) {
+		nglReadPixels(x, y, width, height, format, type, EaglerLWJGLAllocator.getAddress(data));
+	}
+
+	public static final void _wglReadPixels_u16(int x, int y, int width, int height, int format, int type, ByteBuffer data) {
+		nglReadPixels(x, y, width, height, format, type, EaglerLWJGLAllocator.getAddress(data));
+	}
+
+	public static final void _wglReadPixels(int x, int y, int width, int height, int format, int type, IntBuffer data) {
+		nglReadPixels(x, y, width, height, format, type, EaglerLWJGLAllocator.getAddress(data));
+	}
+
+	public static final void _wglReadPixels(int x, int y, int width, int height, int format, int type, FloatBuffer data) {
+		nglReadPixels(x, y, width, height, format, type, EaglerLWJGLAllocator.getAddress(data));
+	}
+
 	public static final void _wglPolygonOffset(float f1, float f2) {
 		glPolygonOffset(f1, f2);
 	}
@@ -117,7 +245,14 @@ public class PlatformOpenGL {
 	}
 
 	public static final IBufferArrayGL _wglGenVertexArrays() {
-		return new OpenGLObjects.BufferArrayGL(glGenVertexArrays());
+		switch(vertexArrayImpl) {
+		case VAO_IMPL_CORE:
+			return new OpenGLObjects.BufferArrayGL(glGenVertexArrays());
+		case VAO_IMPL_OES:
+			return new OpenGLObjects.BufferArrayGL(glGenVertexArraysOES());
+		default:
+			throw new UnsupportedOperationException();
+		}
 	}
 
 	public static final IProgramGL _wglCreateProgram() {
@@ -149,7 +284,17 @@ public class PlatformOpenGL {
 	}
 
 	public static final void _wglDeleteVertexArrays(IBufferArrayGL obj) {
-		glDeleteVertexArrays(((OpenGLObjects.BufferArrayGL) obj).ptr);
+		int ptr = ((OpenGLObjects.BufferArrayGL) obj).ptr;
+		switch(vertexArrayImpl) {
+		case VAO_IMPL_CORE:
+			glDeleteVertexArrays(ptr);
+			break;
+		case VAO_IMPL_OES:
+			glDeleteVertexArraysOES(ptr);
+			break;
+		default:
+			throw new UnsupportedOperationException();
+		}
 	}
 
 	public static final void _wglDeleteProgram(IProgramGL obj) {
@@ -211,7 +356,17 @@ public class PlatformOpenGL {
 	}
 
 	public static final void _wglBindVertexArray(IBufferArrayGL obj) {
-		glBindVertexArray(obj == null ? 0 : ((OpenGLObjects.BufferArrayGL) obj).ptr);
+		int ptr = obj == null ? 0 : ((OpenGLObjects.BufferArrayGL) obj).ptr;
+		switch(vertexArrayImpl) {
+		case VAO_IMPL_CORE:
+			glBindVertexArray(ptr);
+			break;
+		case VAO_IMPL_OES:
+			glBindVertexArrayOES(ptr);
+			break;
+		default:
+			throw new UnsupportedOperationException();
+		}
 	}
 
 	public static final void _wglEnableVertexAttribArray(int index) {
@@ -228,7 +383,19 @@ public class PlatformOpenGL {
 	}
 
 	public static final void _wglVertexAttribDivisor(int index, int divisor) {
-		glVertexAttribDivisor(index, divisor);
+		switch(instancingImpl) {
+		case INSTANCE_IMPL_CORE:
+			glVertexAttribDivisor(index, divisor);
+			break;
+		case INSTANCE_IMPL_ANGLE:
+			glVertexAttribDivisorANGLE(index, divisor);
+			break;
+		case INSTANCE_IMPL_EXT:
+			glVertexAttribDivisorEXT(index, divisor);
+			break;
+		default:
+			throw new UnsupportedOperationException();
+		}
 	}
 
 	public static final void _wglActiveTexture(int texture) {
@@ -313,7 +480,16 @@ public class PlatformOpenGL {
 	}
 
 	public static final void _wglTexStorage2D(int target, int levels, int internalFormat, int w, int h) {
-		glTexStorage2D(target, levels, internalFormat, w, h);
+		switch(texStorageImpl) {
+		case TEX_STORAGE_IMPL_CORE:
+			glTexStorage2D(target, levels, internalFormat, w, h);
+			break;
+		case TEX_STORAGE_IMPL_EXT:
+			glTexStorage2DEXT(target, levels, internalFormat, w, h);
+			break;
+		default:
+			throw new UnsupportedOperationException();
+		}
 	}
 
 	public static final void _wglPixelStorei(int pname, int value) {
@@ -377,7 +553,19 @@ public class PlatformOpenGL {
 	}
 
 	public static final void _wglDrawArraysInstanced(int mode, int first, int count, int instanced) {
-		glDrawArraysInstanced(mode, first, count, instanced);
+		switch(instancingImpl) {
+		case INSTANCE_IMPL_CORE:
+			glDrawArraysInstanced(mode, first, count, instanced);
+			break;
+		case INSTANCE_IMPL_ANGLE:
+			glDrawArraysInstancedANGLE(mode, first, count, instanced);
+			break;
+		case INSTANCE_IMPL_EXT:
+			glDrawArraysInstancedEXT(mode, first, count, instanced);
+			break;
+		default:
+			throw new UnsupportedOperationException();
+		}
 	}
 
 	public static final void _wglDrawElements(int mode, int count, int type, int offset) {
@@ -385,7 +573,19 @@ public class PlatformOpenGL {
 	}
 
 	public static final void _wglDrawElementsInstanced(int mode, int count, int type, int offset, int instanced) {
-		glDrawElementsInstanced(mode, count, type, offset, instanced);
+		switch(instancingImpl) {
+		case INSTANCE_IMPL_CORE:
+			glDrawElementsInstanced(mode, count, type, offset, instanced);
+			break;
+		case INSTANCE_IMPL_ANGLE:
+			glDrawElementsInstancedANGLE(mode, count, type, offset, instanced);
+			break;
+		case INSTANCE_IMPL_EXT:
+			glDrawElementsInstancedEXT(mode, count, type, offset, instanced);
+			break;
+		default:
+			throw new UnsupportedOperationException();
+		}
 	}
 
 	public static final IUniformGL _wglGetUniformLocation(IProgramGL obj, String name) {
@@ -533,11 +733,79 @@ public class PlatformOpenGL {
 		return glGetError();
 	}
 
-	public static final boolean checkHDRFramebufferSupport(int bits) {
-		return true;
+	public static final int checkOpenGLESVersion() {
+		return glesVers;
 	}
 
+	public static final boolean checkEXTGPUShader5Capable() {
+		return hasEXTGPUShader5;
+	}
+
+	public static final boolean checkOESGPUShader5Capable() {
+		return hasOESGPUShader5;
+	}
+
+	public static final boolean checkFBORenderMipmapCapable() {
+		return hasOESFBORenderMipmap;
+	}
+
+	public static final boolean checkVAOCapable() {
+		return vertexArrayImpl != VAO_IMPL_NONE;
+	}
+
+	public static final boolean checkInstancingCapable() {
+		return instancingImpl != INSTANCE_IMPL_NONE;
+	}
+
+	public static final boolean checkTexStorageCapable() {
+		return texStorageImpl != TEX_STORAGE_IMPL_NONE;
+	}
+
+	public static final boolean checkTextureLODCapable() {
+		return glesVers >= 300 || hasEXTShaderTextureLOD;
+	}
+
+	public static final boolean checkNPOTCapable() {
+		return glesVers >= 300;
+	}
+
+	public static final boolean checkHDRFramebufferSupport(int bits) {
+		switch(bits) {
+		case 16:
+			return hasFBO16FSupport;
+		case 32:
+			return hasFBO32FSupport;
+		default:
+			return false;
+		}
+	}
+
+	public static final boolean checkLinearHDRFilteringSupport(int bits) {
+		switch(bits) {
+		case 16:
+			return hasLinearHDR16FSupport;
+		case 32:
+			return hasLinearHDR32FSupport;
+		default:
+			return false;
+		}
+	}
+
+	// legacy
 	public static final boolean checkLinearHDR32FSupport() {
 		return hasLinearHDR32FSupport;
 	}
+
+	public static final boolean checkAnisotropicFilteringSupport() {
+		return hasEXTTextureFilterAnisotropic;
+	}
+
+	public static final String[] getAllExtensions() {
+		return glGetString(GL_EXTENSIONS).split(" ");
+	}
+
+	public static final void enterVAOEmulationHook() {
+		
+	}
+
 }
diff --git a/sources/lwjgl/java/net/lax1dude/eaglercraft/v1_8/internal/PlatformRuntime.java b/sources/lwjgl/java/net/lax1dude/eaglercraft/v1_8/internal/PlatformRuntime.java
index ee6dcc8a..28b9bcb5 100644
--- a/sources/lwjgl/java/net/lax1dude/eaglercraft/v1_8/internal/PlatformRuntime.java
+++ b/sources/lwjgl/java/net/lax1dude/eaglercraft/v1_8/internal/PlatformRuntime.java
@@ -13,7 +13,9 @@ import java.io.OutputStream;
 import java.net.URL;
 import java.nio.charset.StandardCharsets;
 import java.text.SimpleDateFormat;
+import java.util.Collections;
 import java.util.Date;
+import java.util.List;
 import java.util.Random;
 import java.util.function.Consumer;
 import java.util.zip.DeflaterOutputStream;
@@ -31,6 +33,7 @@ import org.lwjgl.opengles.GLDebugMessageKHRCallback;
 import org.lwjgl.opengles.GLDebugMessageKHRCallbackI;
 import org.lwjgl.opengles.GLES;
 import org.lwjgl.opengles.GLES30;
+import org.lwjgl.opengles.GLESCapabilities;
 import org.lwjgl.opengles.KHRDebug;
 import org.lwjgl.system.MemoryStack;
 import org.lwjgl.system.MemoryUtil;
@@ -38,16 +41,19 @@ import org.lwjgl.system.jemalloc.JEmalloc;
 
 import net.lax1dude.eaglercraft.v1_8.internal.buffer.EaglerLWJGLAllocator;
 import net.lax1dude.eaglercraft.v1_8.EaglerOutputStream;
+import net.lax1dude.eaglercraft.v1_8.Filesystem;
 import net.lax1dude.eaglercraft.v1_8.internal.buffer.ByteBuffer;
 import net.lax1dude.eaglercraft.v1_8.internal.buffer.FloatBuffer;
 import net.lax1dude.eaglercraft.v1_8.internal.buffer.IntBuffer;
 import net.lax1dude.eaglercraft.v1_8.internal.lwjgl.DesktopClientConfigAdapter;
+import net.lax1dude.eaglercraft.v1_8.internal.vfs2.VFile2;
 import net.lax1dude.eaglercraft.v1_8.log4j.LogManager;
 import net.lax1dude.eaglercraft.v1_8.log4j.Logger;
 import net.lax1dude.eaglercraft.v1_8.minecraft.EaglerFolderResourcePack;
+import net.lax1dude.eaglercraft.v1_8.sp.server.internal.ServerPlatformSingleplayer;
 
 /**
- * Copyright (c) 2022-2023 lax1dude, ayunami2000. All Rights Reserved.
+ * Copyright (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved.
  * 
  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
@@ -74,7 +80,22 @@ public class PlatformRuntime {
 
 	public static void create() {
 		logger.info("Starting Desktop Runtime...");
-		PlatformFilesystem.initialize();
+		
+		ByteBuffer endiannessTestBytes = allocateByteBuffer(4);
+		try {
+			endiannessTestBytes.asIntBuffer().put(0x6969420);
+			if (((endiannessTestBytes.get(0) & 0xFF) | ((endiannessTestBytes.get(1) & 0xFF) << 8)
+					| ((endiannessTestBytes.get(2) & 0xFF) << 16) | ((endiannessTestBytes.get(3) & 0xFF) << 24)) != 0x6969420) {
+				throw new UnsupportedOperationException("Big endian CPU detected! (somehow)");
+			}else {
+				logger.info("Endianness: this CPU is little endian");
+			}
+		}finally {
+			freeByteBuffer(endiannessTestBytes);
+		}
+		
+		IEaglerFilesystem resourcePackFilesystem = Filesystem.getHandleFor(getClientConfigAdapter().getResourcePacksDB());
+		VFile2.setPrimaryFilesystem(resourcePackFilesystem);
 		EaglerFolderResourcePack.setSupported(true);
 		
 		if(requestedANGLEPlatform != EnumPlatformANGLE.DEFAULT) {
@@ -91,23 +112,54 @@ public class PlatformRuntime {
 
 		glfwWindowHint(GLFW_CONTEXT_CREATION_API, GLFW_EGL_CONTEXT_API);
 		glfwWindowHint(GLFW_CLIENT_API, GLFW_OPENGL_ES_API);
-		glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
-		glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 0);
 
 		glfwWindowHint(GLFW_CENTER_CURSOR, GLFW_TRUE);
 		glfwWindowHint(GLFW_OPENGL_DEBUG_CONTEXT, GLFW_TRUE);
-		
 
 		PointerBuffer buf = glfwGetMonitors();
 		GLFWVidMode mon = glfwGetVideoMode(buf.get(0));
 
 		int windowWidth = mon.width() - 200;
 		int windowHeight = mon.height() - 250;
+		String title = "Eaglercraft Desktop Runtime";
 
 		int winX = (mon.width() - windowWidth) / 2;
 		int winY = (mon.height() - windowHeight - 20) / 2;
 		
-		windowHandle = glfwCreateWindow(windowWidth, windowHeight, "Eaglercraft Desktop Runtime", 0l, 0l);
+		int myGLVersion = -1;
+		if(requestedGLVersion >= 310 && windowHandle == 0) {
+			glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
+			glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 1);
+			windowHandle = glfwCreateWindow(windowWidth, windowHeight, title, 0l, 0l);
+			if(windowHandle == 0l) {
+				logger.error("Failed to create OpenGL ES 3.1 context!");
+			}else {
+				myGLVersion = 310;
+			}
+		}
+		if(requestedGLVersion >= 300 && windowHandle == 0) {
+			glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
+			glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 0);
+			windowHandle = glfwCreateWindow(windowWidth, windowHeight, title, 0l, 0l);
+			if(windowHandle == 0l) {
+				logger.error("Failed to create OpenGL ES 3.0 context!");
+			}else {
+				myGLVersion = 300;
+			}
+		}
+		if(requestedGLVersion >= 200 && windowHandle == 0) {
+			glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 2);
+			glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 0);
+			windowHandle = glfwCreateWindow(windowWidth, windowHeight, title, 0l, 0l);
+			if(windowHandle == 0l) {
+				logger.error("Failed to create OpenGL ES 2.0 context!");
+			}else {
+				myGLVersion = 200;
+			}
+		}
+		if(myGLVersion == -1) {
+			throw new RuntimeException("Could not create a supported OpenGL ES context!");
+		}
 		
 		glfwSetWindowPos(windowHandle, winX, winY);
 		
@@ -171,13 +223,28 @@ public class PlatformRuntime {
 		
 		EGL.createDisplayCapabilities(glfw_eglHandle, major[0], minor[0]);
 		glfwMakeContextCurrent(windowHandle);
-		PlatformOpenGL.setCurrentContext(GLES.createCapabilities());
+		GLESCapabilities caps = GLES.createCapabilities();
+		PlatformOpenGL.setCurrentContext(myGLVersion, caps);
 		
 		logger.info("OpenGL Version: {}", (glVersion = GLES30.glGetString(GLES30.GL_VERSION)));
 		logger.info("OpenGL Renderer: {}", (glRenderer = GLES30.glGetString(GLES30.GL_RENDERER)));
-		
 		rendererANGLEPlatform = EnumPlatformANGLE.fromGLRendererString(glRenderer);
 		
+		int realGLVersion = (glVersion != null && probablyGLES2(glVersion)) ? 200
+				: (GLES30.glGetInteger(GLES30.GL_MAJOR_VERSION) * 100
+						+ GLES30.glGetInteger(GLES30.GL_MINOR_VERSION) * 10);
+		if(realGLVersion != myGLVersion) {
+			logger.warn("Unexpected GLES verison resolved for requested {} context: {}", myGLVersion, realGLVersion);
+			if(myGLVersion == 200) {
+				logger.warn("Note: try adding the \"d3d9\" option if you are on windows trying to get GLES 2.0");
+			}
+			if(realGLVersion != 320 && realGLVersion != 310 && realGLVersion != 300 && realGLVersion != 200) {
+				throw new RuntimeException("Unsupported OpenGL ES version detected: " + realGLVersion);
+			}
+			myGLVersion = realGLVersion;
+			PlatformOpenGL.setCurrentContext(myGLVersion, caps);
+		}
+		
 		if(requestedANGLEPlatform != EnumPlatformANGLE.DEFAULT
 				&& rendererANGLEPlatform != requestedANGLEPlatform) {
 			logger.warn("Incorrect ANGLE Platform: {}", rendererANGLEPlatform.name);
@@ -187,6 +254,18 @@ public class PlatformRuntime {
 			logger.info("ANGLE Platform: {}", rendererANGLEPlatform.name);
 		}
 		
+		List<String> exts = PlatformOpenGL.dumpActiveExtensions();
+		if(exts.isEmpty()) {
+			logger.info("Unlocked the following OpenGL ES extensions: (NONE)");
+		}else {
+			Collections.sort(exts);
+			logger.info("Unlocked the following OpenGL ES extensions:");
+			for(int i = 0, l = exts.size(); i < l; ++i) {
+				logger.info(" - " + exts.get(i));
+			}
+		}
+		
+		
 		glfwSwapInterval(0);
 		
 		KHRDebug.glDebugMessageCallbackKHR(new GLDebugMessageKHRCallbackI() {
@@ -245,13 +324,20 @@ public class PlatformRuntime {
 	
 	public static void destroy() {
 		PlatformAudio.platformShutdown();
-		PlatformFilesystem.platformShutdown();
+		Filesystem.closeAllHandles();
+		ServerPlatformSingleplayer.platformShutdown();
 		GLES.destroy();
 		EGL.destroy();
 		glfwDestroyWindow(windowHandle);
 		glfwTerminate();
 	}
 
+	private static boolean probablyGLES2(String glVersion) {
+		if(glVersion == null) return false;
+		glVersion = glVersion.toLowerCase();
+		return glVersion.contains("opengl es 2.0") || glVersion.contains("ES 2.0");
+	}
+
 	public static EnumPlatformType getPlatformType() {
 		return EnumPlatformType.DESKTOP;
 	}
@@ -274,11 +360,16 @@ public class PlatformRuntime {
 	}
 	
 	private static EnumPlatformANGLE requestedANGLEPlatform = EnumPlatformANGLE.DEFAULT;
+	private static int requestedGLVersion = 300;
 	
 	public static void requestANGLE(EnumPlatformANGLE plaf) {
 		requestedANGLEPlatform = plaf;
 	}
 
+	public static void requestGL(int i) {
+		requestedGLVersion = i;
+	}
+
 	public static EnumPlatformANGLE getPlatformANGLE() {
 		return rendererANGLEPlatform;
 	}
@@ -499,18 +590,6 @@ public class PlatformRuntime {
 		return DesktopClientConfigAdapter.instance;
 	}
 
-	public static String getRecText() {
-		return "recording.unsupported";
-	}
-
-	public static boolean recSupported() {
-		return false;
-	}
-
-	public static void toggleRec() {
-		//
-	}
-
 	private static final Random seedProvider = new Random();
 
 	public static long randomSeed() {
@@ -530,4 +609,25 @@ public class PlatformRuntime {
 	public static long getWindowHandle() {
 		return windowHandle;
 	}
+
+	public static long steadyTimeMillis() {
+		return System.nanoTime() / 1000000l;
+	}
+
+	public static long nanoTime() {
+		return System.nanoTime();
+	}
+
+	public static void postCreate() {
+		
+	}
+
+	public static void setDisplayBootMenuNextRefresh(boolean en) {
+		
+	}
+
+	public static void immediateContinue() {
+		// nope
+	}
+
 }
diff --git a/sources/lwjgl/java/net/lax1dude/eaglercraft/v1_8/internal/PlatformScreenRecord.java b/sources/lwjgl/java/net/lax1dude/eaglercraft/v1_8/internal/PlatformScreenRecord.java
new file mode 100644
index 00000000..1568d60c
--- /dev/null
+++ b/sources/lwjgl/java/net/lax1dude/eaglercraft/v1_8/internal/PlatformScreenRecord.java
@@ -0,0 +1,59 @@
+package net.lax1dude.eaglercraft.v1_8.internal;
+
+import net.lax1dude.eaglercraft.v1_8.recording.EnumScreenRecordingCodec;
+
+/**
+ * Copyright (c) 2024 lax1dude. All Rights Reserved.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ * 
+ */
+public class PlatformScreenRecord {
+
+	public static boolean isSupported() {
+		return false;
+	}
+
+	public static boolean isCodecSupported(EnumScreenRecordingCodec codec) {
+		return false;
+	}
+
+	public static void setGameVolume(float volume) {
+		
+	}
+
+	public static void setMicrophoneVolume(float volume) {
+		
+	}
+
+	public static void startRecording(ScreenRecordParameters params) {
+		
+	}
+
+	public static void endRecording() {
+		
+	}
+
+	public static boolean isRecording() {
+		return false;
+	}
+
+	public static boolean isMicVolumeLocked() {
+		return false;
+	}
+
+	public static boolean isVSyncLocked() {
+		return false;
+	}
+
+
+}
diff --git a/sources/lwjgl/java/net/lax1dude/eaglercraft/v1_8/internal/PlatformUpdateSvc.java b/sources/lwjgl/java/net/lax1dude/eaglercraft/v1_8/internal/PlatformUpdateSvc.java
index cd3cc71a..ae4529f6 100644
--- a/sources/lwjgl/java/net/lax1dude/eaglercraft/v1_8/internal/PlatformUpdateSvc.java
+++ b/sources/lwjgl/java/net/lax1dude/eaglercraft/v1_8/internal/PlatformUpdateSvc.java
@@ -2,6 +2,7 @@ package net.lax1dude.eaglercraft.v1_8.internal;
 
 import net.lax1dude.eaglercraft.v1_8.update.UpdateCertificate;
 import net.lax1dude.eaglercraft.v1_8.update.UpdateProgressStruct;
+import net.lax1dude.eaglercraft.v1_8.update.UpdateResultObj;
 
 /**
  * Copyright (c) 2024 lax1dude. All Rights Reserved.
@@ -46,6 +47,15 @@ public class PlatformUpdateSvc {
 		return dummyStruct;
 	}
 
+	public static UpdateResultObj getUpdateResult() {
+		return null;
+	}
+
+	public static void installSignedClient(UpdateCertificate clientCert, byte[] clientPayload, boolean setDefault,
+			boolean setTimeout) {
+
+	}
+
 	public static void quine(String filename, byte[] cert, byte[] data, String date) {
 		
 	}
diff --git a/sources/lwjgl/java/net/lax1dude/eaglercraft/v1_8/internal/PlatformWebRTC.java b/sources/lwjgl/java/net/lax1dude/eaglercraft/v1_8/internal/PlatformWebRTC.java
index 9b7eef75..cfea7c39 100644
--- a/sources/lwjgl/java/net/lax1dude/eaglercraft/v1_8/internal/PlatformWebRTC.java
+++ b/sources/lwjgl/java/net/lax1dude/eaglercraft/v1_8/internal/PlatformWebRTC.java
@@ -4,20 +4,22 @@ import dev.onvoid.webrtc.*;
 import dev.onvoid.webrtc.internal.NativeLoader;
 import net.lax1dude.eaglercraft.v1_8.EagRuntime;
 import net.lax1dude.eaglercraft.v1_8.EagUtils;
-import net.lax1dude.eaglercraft.v1_8.EaglerInputStream;
 import net.lax1dude.eaglercraft.v1_8.log4j.LogManager;
 import net.lax1dude.eaglercraft.v1_8.log4j.Logger;
 import net.lax1dude.eaglercraft.v1_8.sp.lan.LANPeerEvent;
-import net.lax1dude.eaglercraft.v1_8.sp.relay.RelayManager;
+import net.lax1dude.eaglercraft.v1_8.sp.relay.RelayLoggerImpl;
 import net.lax1dude.eaglercraft.v1_8.sp.relay.RelayQuery;
+import net.lax1dude.eaglercraft.v1_8.sp.relay.RelayQueryImpl;
+import net.lax1dude.eaglercraft.v1_8.sp.relay.RelayQueryRateLimitDummy;
+import net.lax1dude.eaglercraft.v1_8.sp.relay.RelayServerRateLimitTracker;
 import net.lax1dude.eaglercraft.v1_8.sp.relay.RelayServerSocket;
+import net.lax1dude.eaglercraft.v1_8.sp.relay.RelayServerSocketImpl;
+import net.lax1dude.eaglercraft.v1_8.sp.relay.RelayServerSocketRateLimitDummy;
 import net.lax1dude.eaglercraft.v1_8.sp.relay.RelayWorldsQuery;
-import net.lax1dude.eaglercraft.v1_8.sp.relay.pkt.*;
-import net.lax1dude.eaglercraft.v1_8.update.UpdateService;
+import net.lax1dude.eaglercraft.v1_8.sp.relay.RelayWorldsQueryImpl;
+import net.lax1dude.eaglercraft.v1_8.sp.relay.RelayWorldsQueryRateLimitDummy;
 
 import org.apache.commons.lang3.SystemUtils;
-import org.java_websocket.client.WebSocketClient;
-import org.java_websocket.handshake.ServerHandshake;
 import org.json.JSONArray;
 import org.json.JSONObject;
 import org.json.JSONWriter;
@@ -25,10 +27,7 @@ import org.json.JSONWriter;
 import com.google.common.collect.LinkedListMultimap;
 import com.google.common.collect.ListMultimap;
 
-import java.io.DataInputStream;
-import java.io.IOException;
 import java.lang.reflect.Field;
-import java.net.URI;
 import java.nio.ByteBuffer;
 import java.nio.file.Paths;
 import java.util.*;
@@ -52,10 +51,25 @@ public class PlatformWebRTC {
 
 	private static final Logger logger = LogManager.getLogger("PlatformWebRTC");
 
+	private static final RelayLoggerImpl loggerImpl = new RelayLoggerImpl(LogManager.getLogger("RelayPacket"));
+
 	private static final Object lock1 = new Object();
 	private static final Object lock2 = new Object();
 	private static final Object lock3 = new Object();
-	private static final Object lock4 = new Object();
+
+	private static final List<ScheduledRunnable> scheduledRunnables = new LinkedList<>();
+
+	private static class ScheduledRunnable {
+		
+		private final long runAt;
+		private final Runnable runnable;
+		
+		private ScheduledRunnable(long runAt, Runnable runnable) {
+			this.runAt = runAt;
+			this.runnable = runnable;
+		}
+		
+	}
 
 	public static PeerConnectionFactory pcFactory;
 
@@ -72,7 +86,8 @@ public class PlatformWebRTC {
 				Runtime.getRuntime().addShutdownHook(new Thread(() -> pcFactory.dispose()));
 				supported = true;
 			} catch (Exception e) {
-				EagRuntime.debugPrintStackTrace(e);
+				logger.error("Failed to load WebRTC native library!");
+				logger.error(e);
 				supported = false;
 			}
 		}
@@ -81,6 +96,46 @@ public class PlatformWebRTC {
 
 	private static final Map<String, RTCDataChannel> fuckTeaVM = new HashMap<>();
 
+	private static final Comparator<ScheduledRunnable> sortTasks = (r1, r2) -> {
+		return (int)(r1.runAt - r2.runAt);
+	};
+
+	public static void runScheduledTasks() {
+		List<ScheduledRunnable> toRun = null;
+		synchronized(scheduledRunnables) {
+			if(scheduledRunnables.isEmpty()) return;
+			long millis = PlatformRuntime.steadyTimeMillis();
+			Iterator<ScheduledRunnable> itr = scheduledRunnables.iterator();
+			while(itr.hasNext()) {
+				ScheduledRunnable r = itr.next();
+				if(r.runAt < millis) {
+					itr.remove();
+					if(toRun == null) {
+						toRun = new ArrayList<>(1);
+					}
+					toRun.add(r);
+				}
+			}
+		}
+		if(toRun != null) {
+			Collections.sort(toRun, sortTasks);
+			for(int i = 0, l = toRun.size(); i < l; ++i) {
+				try {
+					toRun.get(i).runnable.run();
+				}catch(Throwable t) {
+					logger.error("Caught exception running scheduled WebRTC task!");
+					logger.error(t);
+				}
+			}
+		}
+	}
+
+	static void scheduleTask(long runAfter, Runnable runnable) {
+		synchronized(scheduledRunnables) {
+			scheduledRunnables.add(new ScheduledRunnable(PlatformRuntime.steadyTimeMillis() + runAfter, runnable));
+		}
+	}
+
 	public static class LANClient {
 		public static final byte READYSTATE_INIT_FAILED = -2;
 		public static final byte READYSTATE_FAILED = -1;
@@ -123,15 +178,14 @@ public class PlatformWebRTC {
 							synchronized (lock1) {
 								if (iceCandidate.sdp != null && !iceCandidate.sdp.isEmpty()) {
 									if (iceCandidates.isEmpty()) {
-										new Thread(() -> {
-											EagUtils.sleep(3000);
+										scheduleTask(3000l, () -> {
 											synchronized (lock1) {
 												if (peerConnection != null && peerConnection.getConnectionState() != RTCPeerConnectionState.DISCONNECTED) {
 													clientICECandidate = JSONWriter.valueToString(iceCandidates);
 													iceCandidates.clear();
 												}
 											}
-										}).start();
+										});
 									}
 									Map<String, String> m = new HashMap<>();
 									m.put("sdpMLineIndex", "" + iceCandidate.sdpMLineIndex);
@@ -203,7 +257,7 @@ public class PlatformWebRTC {
 				@Override
 				public void onStateChange() {
 					if (dataChannel != null && dataChannel.getState() == RTCDataChannelState.OPEN) {
-						new Thread(() -> {
+						scheduleTask(-1l, () -> {
 							while (true) {
 								synchronized (lock1) {
 									if (iceCandidates.isEmpty()) {
@@ -216,7 +270,7 @@ public class PlatformWebRTC {
 								clientDataChannelClosed = false;
 								clientDataChannelOpen = true;
 							}
-						}).start();
+						});
 					}
 				}
 
@@ -486,8 +540,7 @@ public class PlatformWebRTC {
 						synchronized (lock3) {
 							if (iceCandidate.sdp != null && !iceCandidate.sdp.isEmpty()) {
 								if (iceCandidates.isEmpty()) {
-									new Thread(() -> {
-										EagUtils.sleep(3000);
+									scheduleTask(3000l, () -> {
 										synchronized (lock3) {
 											if (peerConnection[0] != null && peerConnection[0].getConnectionState() != RTCPeerConnectionState.DISCONNECTED) {
 												LANPeerEvent.LANPeerICECandidateEvent e = new LANPeerEvent.LANPeerICECandidateEvent(peerId, JSONWriter.valueToString(iceCandidates));
@@ -497,7 +550,7 @@ public class PlatformWebRTC {
 												iceCandidates.clear();
 											}
 										}
-									}).start();
+									});
 								}
 								Map<String, String> m = new HashMap<>();
 								m.put("sdpMLineIndex", "" + iceCandidate.sdpMLineIndex);
@@ -509,7 +562,7 @@ public class PlatformWebRTC {
 
 					@Override
 					public void onDataChannel(RTCDataChannel dataChannel) {
-						new Thread(() -> {
+						scheduleTask(-1l, () -> {
 							while (true) {
 								synchronized (lock3) {
 									if (iceCandidates.isEmpty()) {
@@ -547,7 +600,7 @@ public class PlatformWebRTC {
 									}
 								}
 							});
-						}).start();
+						});
 					}
 
 					@Override
@@ -625,795 +678,27 @@ public class PlatformWebRTC {
 			return peerList.size();
 		}
 	}
-
-	private static final Map<String,Long> relayQueryLimited = new HashMap<>();
-	private static final Map<String,Long> relayQueryBlocked = new HashMap<>();
-
-	private static class RelayQueryImpl implements RelayQuery {
-
-		private final WebSocketClient sock;
-		private final String uri;
-
-		private boolean open;
-		private boolean failed;
-
-		private boolean hasRecievedAnyData = false;
-
-		private int vers = -1;
-		private String comment = "<no comment>";
-		private String brand = "<no brand>";
-
-		private long connectionOpenedAt;
-		private long connectionPingStart = -1;
-		private long connectionPingTimer = -1;
-
-		private RateLimit rateLimitStatus = RateLimit.NONE;
-
-		private VersionMismatch versError = VersionMismatch.UNKNOWN;
-
-		private RelayQueryImpl(String uri) {
-			this.uri = uri;
-			WebSocketClient s;
-			try {
-				connectionOpenedAt = System.currentTimeMillis();
-				s = new WebSocketClient(new URI(uri)) {
-					@Override
-					public void onOpen(ServerHandshake serverHandshake) {
-						try {
-							connectionPingStart = System.currentTimeMillis();
-							sock.send(IPacket.writePacket(new IPacket00Handshake(0x03, RelayManager.preferredRelayVersion, "")));
-						} catch (IOException e) {
-							logger.error(e.toString());
-							sock.close();
-							failed = true;
-						}
-					}
-
-					@Override
-					public void onMessage(String s) {
-						//
-					}
-
-					@Override
-					public void onMessage(ByteBuffer bb) {
-						if(bb != null) {
-							hasRecievedAnyData = true;
-							byte[] arr = new byte[bb.remaining()];
-							bb.get(arr);
-							if(arr.length == 2 && arr[0] == (byte)0xFC) {
-								long millis = System.currentTimeMillis();
-								if(arr[1] == (byte)0x00 || arr[1] == (byte)0x01) {
-									rateLimitStatus = RateLimit.BLOCKED;
-									relayQueryLimited.put(RelayQueryImpl.this.uri, millis);
-								}else if(arr[1] == (byte)0x02) {
-									rateLimitStatus = RateLimit.NOW_LOCKED;
-									relayQueryLimited.put(RelayQueryImpl.this.uri, millis);
-									relayQueryBlocked.put(RelayQueryImpl.this.uri, millis);
-								}else {
-									rateLimitStatus = RateLimit.LOCKED;
-									relayQueryBlocked.put(RelayQueryImpl.this.uri, millis);
-								}
-								failed = true;
-								open = false;
-								sock.close();
-							}else {
-								if(open) {
-									try {
-										IPacket pkt = IPacket.readPacket(new DataInputStream(new EaglerInputStream(arr)));
-										if(pkt instanceof IPacket69Pong) {
-											IPacket69Pong ipkt = (IPacket69Pong)pkt;
-											versError = VersionMismatch.COMPATIBLE;
-											if(connectionPingTimer == -1) {
-												connectionPingTimer = System.currentTimeMillis() - connectionPingStart;
-											}
-											vers = ipkt.protcolVersion;
-											comment = ipkt.comment;
-											brand = ipkt.brand;
-											open = false;
-											failed = false;
-											sock.close();
-										}else if(pkt instanceof IPacket70SpecialUpdate) {
-											IPacket70SpecialUpdate ipkt = (IPacket70SpecialUpdate)pkt;
-											if(ipkt.operation == IPacket70SpecialUpdate.OPERATION_UPDATE_CERTIFICATE) {
-												UpdateService.addCertificateToSet(ipkt.updatePacket);
-											}
-										}else if(pkt instanceof IPacketFFErrorCode) {
-											IPacketFFErrorCode ipkt = (IPacketFFErrorCode)pkt;
-											if(ipkt.code == IPacketFFErrorCode.TYPE_PROTOCOL_VERSION) {
-												String s1 = ipkt.desc.toLowerCase();
-												if(s1.contains("outdated client") || s1.contains("client outdated")) {
-													versError = VersionMismatch.CLIENT_OUTDATED;
-												}else if(s1.contains("outdated server") || s1.contains("server outdated") ||
-														s1.contains("outdated relay") || s1.contains("server relay")) {
-													versError = VersionMismatch.RELAY_OUTDATED;
-												}else {
-													versError = VersionMismatch.UNKNOWN;
-												}
-											}
-											logger.error("{}\": Recieved query error code {}: {}", uri, ipkt.code, ipkt.desc);
-											open = false;
-											failed = true;
-											sock.close();
-										}else {
-											throw new IOException("Unexpected packet '" + pkt.getClass().getSimpleName() + "'");
-										}
-									} catch (IOException e) {
-										logger.error("Relay Query Error: {}", e.toString());
-										EagRuntime.debugPrintStackTrace(e);
-										open = false;
-										failed = true;
-										sock.close();
-									}
-								}
-							}
-						}
-					}
-
-					@Override
-					public void onClose(int i, String s, boolean b) {
-						open = false;
-						if(!hasRecievedAnyData) {
-							failed = true;
-							Long l = relayQueryBlocked.get(uri);
-							if(l != null) {
-								if(System.currentTimeMillis() - l.longValue() < 400000l) {
-									rateLimitStatus = RateLimit.LOCKED;
-									return;
-								}
-							}
-							l = relayQueryLimited.get(uri);
-							if(l != null) {
-								if(System.currentTimeMillis() - l.longValue() < 900000l) {
-									rateLimitStatus = RateLimit.BLOCKED;
-									return;
-								}
-							}
-						}
-					}
-
-					@Override
-					public void onError(Exception e) {
-						EagRuntime.debugPrintStackTrace(e);
-					}
-				};
-				s.connect();
-				open = true;
-				failed = false;
-			}catch(Throwable t) {
-				connectionOpenedAt = 0l;
-				sock = null;
-				open = false;
-				failed = true;
-				return;
-			}
-			sock = s;
-		}
-
-		@Override
-		public boolean isQueryOpen() {
-			return open;
-		}
-
-		@Override
-		public boolean isQueryFailed() {
-			return failed;
-		}
-
-		@Override
-		public RateLimit isQueryRateLimit() {
-			return rateLimitStatus;
-		}
-
-		@Override
-		public void close() {
-			if(sock != null && open) {
-				sock.close();
-			}
-			open = false;
-		}
-
-		@Override
-		public int getVersion() {
-			return vers;
-		}
-
-		@Override
-		public String getComment() {
-			return comment;
-		}
-
-		@Override
-		public String getBrand() {
-			return brand;
-		}
-
-		@Override
-		public long getPing() {
-			return connectionPingTimer < 1 ? 1 : connectionPingTimer;
-		}
-
-		@Override
-		public VersionMismatch getCompatible() {
-			return versError;
-		}
-
-	}
-
-	private static class RelayQueryRatelimitDummy implements RelayQuery {
-
-		private final RateLimit type;
-
-		private RelayQueryRatelimitDummy(RateLimit type) {
-			this.type = type;
-		}
-
-		@Override
-		public boolean isQueryOpen() {
-			return false;
-		}
-
-		@Override
-		public boolean isQueryFailed() {
-			return true;
-		}
-
-		@Override
-		public RateLimit isQueryRateLimit() {
-			return type;
-		}
-
-		@Override
-		public void close() {
-		}
-
-		@Override
-		public int getVersion() {
-			return RelayManager.preferredRelayVersion;
-		}
-
-		@Override
-		public String getComment() {
-			return "this query was rate limited";
-		}
-
-		@Override
-		public String getBrand() {
-			return "lax1dude";
-		}
-
-		@Override
-		public long getPing() {
-			return 0l;
-		}
-
-		@Override
-		public VersionMismatch getCompatible() {
-			return VersionMismatch.COMPATIBLE;
-		}
-
-	}
-
 	public static RelayQuery openRelayQuery(String addr) {
-		long millis = System.currentTimeMillis();
-
-		Long l = relayQueryBlocked.get(addr);
-		if(l != null && millis - l.longValue() < 60000l) {
-			return new RelayQueryRatelimitDummy(RelayQuery.RateLimit.LOCKED);
+		RelayQuery.RateLimit limit = RelayServerRateLimitTracker.isLimited(addr);
+		if(limit == RelayQuery.RateLimit.LOCKED || limit == RelayQuery.RateLimit.BLOCKED) {
+			return new RelayQueryRateLimitDummy(limit);
 		}
-
-		l = relayQueryLimited.get(addr);
-		if(l != null && millis - l.longValue() < 10000l) {
-			return new RelayQueryRatelimitDummy(RelayQuery.RateLimit.BLOCKED);
-		}
-
 		return new RelayQueryImpl(addr);
 	}
 
-	private static class RelayWorldsQueryImpl implements RelayWorldsQuery {
-
-		private final WebSocketClient sock;
-		private final String uri;
-
-		private boolean open;
-		private boolean failed;
-
-		private boolean hasRecievedAnyData = false;
-		private RelayQuery.RateLimit rateLimitStatus = RelayQuery.RateLimit.NONE;
-
-		private RelayQuery.VersionMismatch versError = RelayQuery.VersionMismatch.UNKNOWN;
-
-		private List<IPacket07LocalWorlds.LocalWorld> worlds = null;
-
-		private RelayWorldsQueryImpl(String uri) {
-			this.uri = uri;
-			WebSocketClient s;
-			try {
-				s = new WebSocketClient(new URI(uri)) {
-					@Override
-					public void onOpen(ServerHandshake serverHandshake) {
-						try {
-							sock.send(IPacket.writePacket(new IPacket00Handshake(0x04, RelayManager.preferredRelayVersion, "")));
-						} catch (IOException e) {
-							logger.error(e.toString());
-							sock.close();
-							open = false;
-							failed = true;
-						}
-					}
-
-					@Override
-					public void onMessage(String s) {
-						//
-					}
-
-					@Override
-					public void onMessage(ByteBuffer bb) {
-						if(bb != null) {
-							hasRecievedAnyData = true;
-							byte[] arr = new byte[bb.remaining()];
-							bb.get(arr);
-							if(arr.length == 2 && arr[0] == (byte)0xFC) {
-								long millis = System.currentTimeMillis();
-								if(arr[1] == (byte)0x00 || arr[1] == (byte)0x01) {
-									rateLimitStatus = RelayQuery.RateLimit.BLOCKED;
-									relayQueryLimited.put(RelayWorldsQueryImpl.this.uri, millis);
-								}else if(arr[1] == (byte)0x02) {
-									rateLimitStatus = RelayQuery.RateLimit.NOW_LOCKED;
-									relayQueryLimited.put(RelayWorldsQueryImpl.this.uri, millis);
-									relayQueryBlocked.put(RelayWorldsQueryImpl.this.uri, millis);
-								}else {
-									rateLimitStatus = RelayQuery.RateLimit.LOCKED;
-									relayQueryBlocked.put(RelayWorldsQueryImpl.this.uri, millis);
-								}
-								open = false;
-								failed = true;
-								sock.close();
-							}else {
-								if(open) {
-									try {
-										IPacket pkt = IPacket.readPacket(new DataInputStream(new EaglerInputStream(arr)));
-										if(pkt instanceof IPacket07LocalWorlds) {
-											worlds = ((IPacket07LocalWorlds)pkt).worldsList;
-											sock.close();
-											open = false;
-											failed = false;
-										}else if(pkt instanceof IPacket70SpecialUpdate) {
-											IPacket70SpecialUpdate ipkt = (IPacket70SpecialUpdate)pkt;
-											if(ipkt.operation == IPacket70SpecialUpdate.OPERATION_UPDATE_CERTIFICATE) {
-												UpdateService.addCertificateToSet(ipkt.updatePacket);
-											}
-										}else if(pkt instanceof IPacketFFErrorCode) {
-											IPacketFFErrorCode ipkt = (IPacketFFErrorCode)pkt;
-											if(ipkt.code == IPacketFFErrorCode.TYPE_PROTOCOL_VERSION) {
-												String s1 = ipkt.desc.toLowerCase();
-												if(s1.contains("outdated client") || s1.contains("client outdated")) {
-													versError = RelayQuery.VersionMismatch.CLIENT_OUTDATED;
-												}else if(s1.contains("outdated server") || s1.contains("server outdated") ||
-														s1.contains("outdated relay") || s1.contains("server relay")) {
-													versError = RelayQuery.VersionMismatch.RELAY_OUTDATED;
-												}else {
-													versError = RelayQuery.VersionMismatch.UNKNOWN;
-												}
-											}
-											logger.error("{}: Recieved query error code {}: {}", uri, ipkt.code, ipkt.desc);
-											open = false;
-											failed = true;
-											sock.close();
-										}else {
-											throw new IOException("Unexpected packet '" + pkt.getClass().getSimpleName() + "'");
-										}
-									} catch (IOException e) {
-										logger.error("Relay World Query Error: {}", e.toString());
-										EagRuntime.debugPrintStackTrace(e);
-										open = false;
-										failed = true;
-										sock.close();
-									}
-								}
-							}
-						}
-					}
-
-					@Override
-					public void onClose(int i, String s, boolean b) {
-						open = false;
-						if(!hasRecievedAnyData) {
-							failed = true;
-							Long l = relayQueryBlocked.get(uri);
-							if(l != null) {
-								if(System.currentTimeMillis() - l.longValue() < 400000l) {
-									rateLimitStatus = RelayQuery.RateLimit.LOCKED;
-									return;
-								}
-							}
-							l = relayQueryLimited.get(uri);
-							if(l != null) {
-								if(System.currentTimeMillis() - l.longValue() < 900000l) {
-									rateLimitStatus = RelayQuery.RateLimit.BLOCKED;
-									return;
-								}
-							}
-						}
-					}
-
-					@Override
-					public void onError(Exception e) {
-						EagRuntime.debugPrintStackTrace(e);
-					}
-				};
-				s.connect();
-				open = true;
-				failed = false;
-			}catch(Throwable t) {
-				sock = null;
-				open = false;
-				failed = true;
-				return;
-			}
-			sock = s;
-		}
-
-		@Override
-		public boolean isQueryOpen() {
-			return open;
-		}
-
-		@Override
-		public boolean isQueryFailed() {
-			return failed;
-		}
-
-		@Override
-		public RelayQuery.RateLimit isQueryRateLimit() {
-			return rateLimitStatus;
-		}
-
-		@Override
-		public void close() {
-			if(open && sock != null) {
-				sock.close();
-			}
-			open = false;
-		}
-
-		@Override
-		public List<IPacket07LocalWorlds.LocalWorld> getWorlds() {
-			return worlds;
-		}
-
-		@Override
-		public RelayQuery.VersionMismatch getCompatible() {
-			return versError;
-		}
-
-	}
-
-	private static class RelayWorldsQueryRatelimitDummy implements RelayWorldsQuery {
-
-		private final RelayQuery.RateLimit rateLimit;
-
-		private RelayWorldsQueryRatelimitDummy(RelayQuery.RateLimit rateLimit) {
-			this.rateLimit = rateLimit;
-		}
-
-		@Override
-		public boolean isQueryOpen() {
-			return false;
-		}
-
-		@Override
-		public boolean isQueryFailed() {
-			return true;
-		}
-
-		@Override
-		public RelayQuery.RateLimit isQueryRateLimit() {
-			return rateLimit;
-		}
-
-		@Override
-		public void close() {
-		}
-
-		@Override
-		public List<IPacket07LocalWorlds.LocalWorld> getWorlds() {
-			return new ArrayList(0);
-		}
-
-		@Override
-		public RelayQuery.VersionMismatch getCompatible() {
-			return RelayQuery.VersionMismatch.COMPATIBLE;
-		}
-	}
-
 	public static RelayWorldsQuery openRelayWorldsQuery(String addr) {
-		long millis = System.currentTimeMillis();
-
-		Long l = relayQueryBlocked.get(addr);
-		if(l != null && millis - l.longValue() < 60000l) {
-			return new RelayWorldsQueryRatelimitDummy(RelayQuery.RateLimit.LOCKED);
+		RelayQuery.RateLimit limit = RelayServerRateLimitTracker.isLimited(addr);
+		if(limit == RelayQuery.RateLimit.LOCKED || limit == RelayQuery.RateLimit.BLOCKED) {
+			return new RelayWorldsQueryRateLimitDummy(limit);
 		}
-
-		l = relayQueryLimited.get(addr);
-		if(l != null && millis - l.longValue() < 10000l) {
-			return new RelayWorldsQueryRatelimitDummy(RelayQuery.RateLimit.BLOCKED);
-		}
-
 		return new RelayWorldsQueryImpl(addr);
 	}
 
-	private static class RelayServerSocketImpl implements RelayServerSocket {
-
-		private final WebSocketClient sock;
-		private final String uri;
-
-		private boolean open;
-		private boolean closed;
-		private boolean failed;
-
-		private boolean hasRecievedAnyData;
-
-		private final List<Throwable> exceptions = new LinkedList();
-		private final List<IPacket> packets = new LinkedList();
-
-		private RelayServerSocketImpl(String uri, int timeout) {
-			this.uri = uri;
-			WebSocketClient s;
-			try {
-				s = new WebSocketClient(new URI(uri)) {
-					@Override
-					public void onOpen(ServerHandshake serverHandshake) {
-						synchronized (lock4) {
-							open = true;
-						}
-					}
-
-					@Override
-					public void onMessage(String s) {
-						//
-					}
-
-					@Override
-					public void onMessage(ByteBuffer bb) {
-						if(bb != null) {
-							hasRecievedAnyData = true;
-							try {
-								byte[] arr = new byte[bb.remaining()];
-								bb.get(arr);
-								IPacket pkt = IPacket.readPacket(new DataInputStream(new EaglerInputStream(arr)));
-								if(pkt instanceof IPacket70SpecialUpdate) {
-									IPacket70SpecialUpdate ipkt = (IPacket70SpecialUpdate)pkt;
-									if(ipkt.operation == IPacket70SpecialUpdate.OPERATION_UPDATE_CERTIFICATE) {
-										UpdateService.addCertificateToSet(ipkt.updatePacket);
-									}
-								}else {
-									packets.add(pkt);
-								}
-							} catch (IOException e) {
-								exceptions.add(e);
-								logger.error("Relay Socket Error: {}", e.toString());
-								EagRuntime.debugPrintStackTrace(e);
-								synchronized (lock4) {
-									open = false;
-									failed = true;
-								}
-								closed = true;
-								synchronized (lock4) {
-									sock.close();
-								}
-							}
-						}
-					}
-
-					@Override
-					public void onClose(int i, String s, boolean b) {
-						if (!hasRecievedAnyData) {
-							failed = true;
-						}
-						synchronized (lock4) {
-							open = false;
-							closed = true;
-						}
-					}
-
-					@Override
-					public void onError(Exception e) {
-						EagRuntime.debugPrintStackTrace(e);
-					}
-				};
-				s.connect();
-				synchronized (lock4) {
-					open = false;
-					closed = false;
-				}
-				failed = false;
-			}catch(Throwable t) {
-				exceptions.add(t);
-				synchronized (lock4) {
-					sock = null;
-					open = false;
-					closed = true;
-				}
-				failed = true;
-				return;
-			}
-			synchronized (lock4) {
-				sock = s;
-			}
-			new Thread(() -> {
-				EagUtils.sleep(timeout);
-				synchronized (lock4) {
-					if (!open && !closed) {
-						closed = true;
-						sock.close();
-					}
-				}
-			}).start();
-		}
-
-		@Override
-		public boolean isOpen() {
-			return open;
-		}
-
-		@Override
-		public boolean isClosed() {
-			synchronized (lock4) {
-				return closed;
-			}
-		}
-
-		@Override
-		public void close() {
-			if(open && sock != null) {
-				synchronized (lock4) {
-					sock.close();
-				}
-			}
-			synchronized (lock4) {
-				open = false;
-				closed = true;
-			}
-		}
-
-		@Override
-		public boolean isFailed() {
-			return failed;
-		}
-
-		@Override
-		public Throwable getException() {
-			if(!exceptions.isEmpty()) {
-				return exceptions.remove(0);
-			}else {
-				return null;
-			}
-		}
-
-		@Override
-		public void writePacket(IPacket pkt) {
-			try {
-				sock.send(IPacket.writePacket(pkt));
-			} catch (Throwable e) {
-				logger.error("Relay connection error: {}", e.toString());
-				EagRuntime.debugPrintStackTrace(e);
-				exceptions.add(e);
-				failed = true;
-				synchronized (lock4) {
-					open = false;
-					closed = true;
-					sock.close();
-				}
-			}
-		}
-
-		@Override
-		public IPacket readPacket() {
-			if(!packets.isEmpty()) {
-				return packets.remove(0);
-			}else {
-				return null;
-			}
-		}
-
-		@Override
-		public IPacket nextPacket() {
-			if(!packets.isEmpty()) {
-				return packets.get(0);
-			}else {
-				return null;
-			}
-		}
-
-		@Override
-		public RelayQuery.RateLimit getRatelimitHistory() {
-			if(relayQueryBlocked.containsKey(uri)) {
-				return RelayQuery.RateLimit.LOCKED;
-			}
-			if(relayQueryLimited.containsKey(uri)) {
-				return RelayQuery.RateLimit.BLOCKED;
-			}
-			return RelayQuery.RateLimit.NONE;
-		}
-
-		@Override
-		public String getURI() {
-			return uri;
-		}
-
-	}
-
-	private static class RelayServerSocketRatelimitDummy implements RelayServerSocket {
-
-		private final RelayQuery.RateLimit limit;
-
-		private RelayServerSocketRatelimitDummy(RelayQuery.RateLimit limit) {
-			this.limit = limit;
-		}
-
-		@Override
-		public boolean isOpen() {
-			return false;
-		}
-
-		@Override
-		public boolean isClosed() {
-			return true;
-		}
-
-		@Override
-		public void close() {
-		}
-
-		@Override
-		public boolean isFailed() {
-			return true;
-		}
-
-		@Override
-		public Throwable getException() {
-			return null;
-		}
-
-		@Override
-		public void writePacket(IPacket pkt) {
-		}
-
-		@Override
-		public IPacket readPacket() {
-			return null;
-		}
-
-		@Override
-		public IPacket nextPacket() {
-			return null;
-		}
-
-		@Override
-		public RelayQuery.RateLimit getRatelimitHistory() {
-			return limit;
-		}
-
-		@Override
-		public String getURI() {
-			return "<disconnected>";
-		}
-
-	}
-
 	public static RelayServerSocket openRelayConnection(String addr, int timeout) {
-		long millis = System.currentTimeMillis();
-
-		Long l = relayQueryBlocked.get(addr);
-		if(l != null && millis - l.longValue() < 60000l) {
-			return new RelayServerSocketRatelimitDummy(RelayQuery.RateLimit.LOCKED);
+		RelayQuery.RateLimit limit = RelayServerRateLimitTracker.isLimited(addr);
+		if(limit == RelayQuery.RateLimit.LOCKED || limit == RelayQuery.RateLimit.BLOCKED) {
+			return new RelayServerSocketRateLimitDummy(limit);
 		}
-
-		l = relayQueryLimited.get(addr);
-		if(l != null && millis - l.longValue() < 10000l) {
-			return new RelayServerSocketRatelimitDummy(RelayQuery.RateLimit.BLOCKED);
-		}
-
 		return new RelayServerSocketImpl(addr, timeout);
 	}
 
@@ -1453,7 +738,7 @@ public class PlatformWebRTC {
 	public static List<byte[]> clientLANReadAllPacket() {
 		synchronized(clientLANPacketBuffer) {
 			if(!clientLANPacketBuffer.isEmpty()) {
-				List<byte[]> ret = new ArrayList(clientLANPacketBuffer);
+				List<byte[]> ret = new ArrayList<>(clientLANPacketBuffer);
 				clientLANPacketBuffer.clear();
 				return ret;
 			}else {
diff --git a/sources/lwjgl/java/net/lax1dude/eaglercraft/v1_8/internal/PlatformWebView.java b/sources/lwjgl/java/net/lax1dude/eaglercraft/v1_8/internal/PlatformWebView.java
new file mode 100644
index 00000000..650c9451
--- /dev/null
+++ b/sources/lwjgl/java/net/lax1dude/eaglercraft/v1_8/internal/PlatformWebView.java
@@ -0,0 +1,93 @@
+package net.lax1dude.eaglercraft.v1_8.internal;
+
+import net.lax1dude.eaglercraft.v1_8.internal.lwjgl.FallbackWebViewServer;
+import net.lax1dude.eaglercraft.v1_8.socket.protocol.pkt.server.SPacketWebViewMessageV4EAG;
+import net.lax1dude.eaglercraft.v1_8.webview.WebViewOverlayController.IPacketSendCallback;
+
+/**
+ * Copyright (c) 2024 lax1dude. All Rights Reserved.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ * 
+ */
+public class PlatformWebView {
+
+	private static FallbackWebViewServer fallbackServer = null;
+	private static IPacketSendCallback packetCallback = null;
+
+	public static boolean supported() {
+		return false;
+	}
+
+	public static boolean isShowing() {
+		return false;
+	}
+
+	public static void beginShowing(WebViewOptions options, int x, int y, int w, int h) {
+		
+	}
+
+	public static void resize(int x, int y, int w, int h) {
+		
+	}
+
+	public static void endShowing() {
+		
+	}
+
+	public static boolean fallbackSupported() {
+		return true;
+	}
+
+	public static void launchFallback(WebViewOptions options) {
+		fallbackServer = new FallbackWebViewServer(options);
+		fallbackServer.setPacketSendCallback(packetCallback);
+		fallbackServer.start();
+	}
+
+	public static boolean fallbackRunning() {
+		return fallbackServer != null && !fallbackServer.isDead();
+	}
+
+	public static String getFallbackURL() {
+		return fallbackServer != null ? fallbackServer.getURL() : null;
+	}
+
+	public static void endFallbackServer() {
+		if(fallbackServer != null && !fallbackServer.isDead()) {
+			fallbackServer.killServer();
+		}
+	}
+
+	public static void handleMessageFromServer(SPacketWebViewMessageV4EAG packet) {
+		if(fallbackServer != null && !fallbackServer.isDead()) {
+			fallbackServer.handleMessageFromServer(packet);
+		}
+	}
+
+	public static void setPacketSendCallback(IPacketSendCallback callback) {
+		packetCallback = callback;
+		if(fallbackServer != null) {
+			fallbackServer.setPacketSendCallback(callback);
+		}
+	}
+
+	public static void runTick() {
+		if(fallbackServer != null) {
+			fallbackServer.runTick();
+			if(fallbackServer.isDead()) {
+				fallbackServer = null;
+			}
+		}
+	}
+
+}
diff --git a/sources/lwjgl/java/net/lax1dude/eaglercraft/v1_8/internal/WebSocketServerQuery.java b/sources/lwjgl/java/net/lax1dude/eaglercraft/v1_8/internal/WebSocketServerQuery.java
deleted file mode 100644
index 42feb107..00000000
--- a/sources/lwjgl/java/net/lax1dude/eaglercraft/v1_8/internal/WebSocketServerQuery.java
+++ /dev/null
@@ -1,173 +0,0 @@
-package net.lax1dude.eaglercraft.v1_8.internal;
-
-import java.net.URI;
-import java.nio.ByteBuffer;
-import java.util.LinkedList;
-import java.util.List;
-
-import org.java_websocket.client.WebSocketClient;
-import org.java_websocket.drafts.Draft;
-import org.java_websocket.drafts.Draft_6455;
-import org.java_websocket.extensions.permessage_deflate.PerMessageDeflateExtension;
-import org.java_websocket.handshake.ServerHandshake;
-import org.json.JSONObject;
-
-import net.lax1dude.eaglercraft.v1_8.log4j.LogManager;
-import net.lax1dude.eaglercraft.v1_8.log4j.Logger;
-
-/**
- * Copyright (c) 2022-2023 lax1dude, ayunami2000. All Rights Reserved.
- * 
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
- * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- * 
- */
-class WebSocketServerQuery extends WebSocketClient implements IServerQuery {
-
-	private static final Draft perMessageDeflateDraft = new Draft_6455(new PerMessageDeflateExtension());
-
-	public static final Logger logger = LogManager.getLogger("WebSocketQuery");
-
-	private final List<QueryResponse> queryResponses = new LinkedList();
-	private final List<byte[]> queryResponsesBytes = new LinkedList();
-	private final String type;
-	private boolean open = true;
-	private boolean alive = false;
-	private long pingStart = -1l;
-	private long pingTimer = -1l;
-	private EnumServerRateLimit rateLimit = EnumServerRateLimit.OK;
-
-	WebSocketServerQuery(String type, URI serverUri) {
-		super(serverUri, perMessageDeflateDraft);
-		this.type = type;
-		this.setConnectionLostTimeout(5);
-		this.setTcpNoDelay(true);
-		this.connect();
-	}
-
-	@Override
-	public int responsesAvailable() {
-		synchronized(queryResponses) {
-			return queryResponses.size();
-		}
-	}
-
-	@Override
-	public QueryResponse getResponse() {
-		synchronized(queryResponses) {
-			if(queryResponses.size() > 0) {
-				return queryResponses.remove(0);
-			}else {
-				return null;
-			}
-		}
-	}
-
-	@Override
-	public int binaryResponsesAvailable() {
-		synchronized(queryResponsesBytes) {
-			return queryResponsesBytes.size();
-		}
-	}
-
-	@Override
-	public byte[] getBinaryResponse() {
-		synchronized(queryResponsesBytes) {
-			if(queryResponsesBytes.size() > 0) {
-				return queryResponsesBytes.remove(0);
-			}else {
-				return null;
-			}
-		}
-	}
-
-	@Override
-	public QueryReadyState readyState() {
-		return open ? (alive ? QueryReadyState.OPEN : QueryReadyState.CONNECTING)
-				: (alive ? QueryReadyState.CLOSED : QueryReadyState.FAILED);
-	}
-
-	@Override
-	public EnumServerRateLimit getRateLimit() {
-		return rateLimit;
-	}
-
-	@Override
-	public void onClose(int arg0, String arg1, boolean arg2) {
-		open = false;
-	}
-
-	@Override
-	public void onError(Exception arg0) {
-		logger.error("Exception thrown by websocket query \"" + this.getURI().toString() + "\"!");
-		logger.error(arg0);
-	}
-
-	@Override
-	public void onMessage(String arg0) {
-		alive = true;
-		if(pingTimer == -1) {
-			pingTimer = System.currentTimeMillis() - pingStart;
-			if(pingTimer < 1) {
-				pingTimer = 1;
-			}
-		}
-		if(arg0.equalsIgnoreCase("BLOCKED")) {
-			logger.error("Reached full IP ratelimit for {}!", this.uri.toString());
-			rateLimit = EnumServerRateLimit.BLOCKED;
-			return;
-		}
-		if(arg0.equalsIgnoreCase("LOCKED")) {
-			logger.error("Reached full IP ratelimit lockout for {}!", this.uri.toString());
-			rateLimit = EnumServerRateLimit.LOCKED_OUT;
-			return;
-		}
-		try {
-			JSONObject obj = new JSONObject(arg0);
-			if("blocked".equalsIgnoreCase(obj.optString("type", null))) {
-				logger.error("Reached query ratelimit for {}!", this.uri.toString());
-				rateLimit = EnumServerRateLimit.BLOCKED;
-			}else if("locked".equalsIgnoreCase(obj.optString("type", null))) {
-				logger.error("Reached query ratelimit lockout for {}!", this.uri.toString());
-				rateLimit = EnumServerRateLimit.LOCKED_OUT;
-			}else {
-				QueryResponse response = new QueryResponse(obj, pingTimer);
-				synchronized(queryResponses) {
-					queryResponses.add(response);
-				}
-			}
-		}catch(Throwable t) {
-			logger.error("Exception thrown parsing websocket query response from \"" + this.getURI().toString() + "\"!");
-			logger.error(t);
-		}
-	}
-
-	@Override
-	public void onMessage(ByteBuffer arg0) {
-		alive = true;
-		if(pingTimer == -1) {
-			pingTimer = System.currentTimeMillis() - pingStart;
-			if(pingTimer < 1) {
-				pingTimer = 1;
-			}
-		}
-		synchronized(queryResponsesBytes) {
-			queryResponsesBytes.add(arg0.array());
-		}
-	}
-
-	@Override
-	public void onOpen(ServerHandshake arg0) {
-		pingStart = System.currentTimeMillis();
-		send("Accept: " + type);
-	}
-
-}
diff --git a/sources/lwjgl/java/net/lax1dude/eaglercraft/v1_8/internal/buffer/EaglerLWJGLByteBuffer.java b/sources/lwjgl/java/net/lax1dude/eaglercraft/v1_8/internal/buffer/EaglerLWJGLByteBuffer.java
index 5cb11422..74902975 100644
--- a/sources/lwjgl/java/net/lax1dude/eaglercraft/v1_8/internal/buffer/EaglerLWJGLByteBuffer.java
+++ b/sources/lwjgl/java/net/lax1dude/eaglercraft/v1_8/internal/buffer/EaglerLWJGLByteBuffer.java
@@ -1,7 +1,5 @@
 package net.lax1dude.eaglercraft.v1_8.internal.buffer;
 
-import org.lwjgl.system.jemalloc.JEmalloc;
-
 import net.lax1dude.unsafememcpy.UnsafeMemcpy;
 import net.lax1dude.unsafememcpy.UnsafeUtils;
 
@@ -29,7 +27,7 @@ public class EaglerLWJGLByteBuffer implements ByteBuffer {
 	private int position;
 	private int limit;
 	private int mark;
-	
+
 	EaglerLWJGLByteBuffer(long address, int capacity, boolean original) {
 		this(address, capacity, 0, capacity, -1, original);
 	}
@@ -68,18 +66,13 @@ public class EaglerLWJGLByteBuffer implements ByteBuffer {
 		return position < limit;
 	}
 
-	@Override
-	public boolean isReadOnly() {
-		return false;
-	}
-
 	@Override
 	public boolean hasArray() {
 		return false;
 	}
 
 	@Override
-	public Object array() {
+	public byte[] array() {
 		throw new UnsupportedOperationException();
 	}
 
@@ -88,50 +81,40 @@ public class EaglerLWJGLByteBuffer implements ByteBuffer {
 		return true;
 	}
 
-	@Override
-	public ByteBuffer slice() {
-		return new EaglerLWJGLByteBuffer(address + position, limit - position, false);
-	}
-
 	@Override
 	public ByteBuffer duplicate() {
 		return new EaglerLWJGLByteBuffer(address, capacity, position, limit, mark, false);
 	}
 
-	@Override
-	public ByteBuffer asReadOnlyBuffer() {
-		return new EaglerLWJGLByteBuffer(address, capacity, position, limit, mark, false);
-	}
-
 	@Override
 	public byte get() {
-		if(position >= limit) throw new ArrayIndexOutOfBoundsException(position);
+		if(position >= limit) throw Buffer.makeIOOBE(position);
 		return UnsafeUtils.getMemByte(address + position++);
 	}
 
 	@Override
 	public ByteBuffer put(byte b) {
-		if(position >= limit) throw new ArrayIndexOutOfBoundsException(position);
+		if(position >= limit) throw Buffer.makeIOOBE(position);
 		UnsafeUtils.setMemByte(address + position++, b);
 		return this;
 	}
 
 	@Override
 	public byte get(int index) {
-		if(index >= limit) throw new ArrayIndexOutOfBoundsException(index);
+		if(index < 0 || index >= limit) throw Buffer.makeIOOBE(index);
 		return UnsafeUtils.getMemByte(address + index);
 	}
 
 	@Override
 	public ByteBuffer put(int index, byte b) {
-		if(index >= limit) throw new ArrayIndexOutOfBoundsException(index);
+		if(index < 0 || index >= limit) throw Buffer.makeIOOBE(index);
 		UnsafeUtils.setMemByte(address + index, b);
 		return this;
 	}
 
 	@Override
 	public ByteBuffer get(byte[] dst, int offset, int length) {
-		if(position + length > limit) throw new ArrayIndexOutOfBoundsException(position + length - 1);
+		if(position + length > limit) throw Buffer.makeIOOBE(position + length - 1);
 		UnsafeMemcpy.memcpy(dst, offset, address + position, length);
 		position += length;
 		return this;
@@ -139,7 +122,7 @@ public class EaglerLWJGLByteBuffer implements ByteBuffer {
 
 	@Override
 	public ByteBuffer get(byte[] dst) {
-		if(position + dst.length > limit) throw new ArrayIndexOutOfBoundsException(position + dst.length - 1);
+		if(position + dst.length > limit) throw Buffer.makeIOOBE(position + dst.length - 1);
 		UnsafeMemcpy.memcpy(dst, 0, address + position, dst.length);
 		position += dst.length;
 		return this;
@@ -150,13 +133,13 @@ public class EaglerLWJGLByteBuffer implements ByteBuffer {
 		if(src instanceof EaglerLWJGLByteBuffer) {
 			EaglerLWJGLByteBuffer c = (EaglerLWJGLByteBuffer)src;
 			int l = c.limit - c.position;
-			if(position + l > limit) throw new ArrayIndexOutOfBoundsException(position + l - 1);
+			if(position + l > limit) throw Buffer.makeIOOBE(position + l - 1);
 			UnsafeMemcpy.memcpy(address + position, c.address + c.position, l);
 			position += l;
 			c.position += l;
 		}else {
 			int l = src.remaining();
-			if(position + l > limit) throw new ArrayIndexOutOfBoundsException(position + l - 1);
+			if(position + l > limit) throw Buffer.makeIOOBE(position + l - 1);
 			for(int i = 0; i < l; ++i) {
 				UnsafeUtils.setMemByte(address + position + l, src.get());
 			}
@@ -167,7 +150,7 @@ public class EaglerLWJGLByteBuffer implements ByteBuffer {
 
 	@Override
 	public ByteBuffer put(byte[] src, int offset, int length) {
-		if(position + length > limit) throw new ArrayIndexOutOfBoundsException(position + length - 1);
+		if(position + length > limit) throw Buffer.makeIOOBE(position + length - 1);
 		UnsafeMemcpy.memcpy(address + position, src, offset, length);
 		position += length;
 		return this;
@@ -175,39 +158,15 @@ public class EaglerLWJGLByteBuffer implements ByteBuffer {
 
 	@Override
 	public ByteBuffer put(byte[] src) {
-		if(position + src.length > limit) throw new ArrayIndexOutOfBoundsException(position + src.length - 1);
+		if(position + src.length > limit) throw Buffer.makeIOOBE(position + src.length - 1);
 		UnsafeMemcpy.memcpy(address + position, src, 0, src.length);
 		position += src.length;
 		return this;
 	}
 
-	@Override
-	public int arrayOffset() {
-		return position;
-	}
-
-	@Override
-	public ByteBuffer compact() {
-		if(limit > capacity) throw new ArrayIndexOutOfBoundsException(limit);
-		if(position > limit) throw new ArrayIndexOutOfBoundsException(position);
-		
-		if(position == limit) {
-			return new EaglerLWJGLByteBuffer(0l, 0, false);
-		}
-		
-		int newLen = limit - position;
-		long newAlloc = JEmalloc.nje_malloc(newLen);
-		if(newAlloc == 0l) {
-			throw new OutOfMemoryError("Native je_malloc call returned null pointer!");
-		}
-		UnsafeMemcpy.memcpy(newAlloc, address + position, newLen);
-		
-		return new EaglerLWJGLByteBuffer(newAlloc, newLen, true);
-	}
-
 	@Override
 	public char getChar() {
-		if(position + 2 > limit) throw new ArrayIndexOutOfBoundsException(position);
+		if(position + 2 > limit) throw Buffer.makeIOOBE(position);
 		char c = UnsafeUtils.getMemChar(address + position);
 		position += 2;
 		return c;
@@ -215,7 +174,7 @@ public class EaglerLWJGLByteBuffer implements ByteBuffer {
 
 	@Override
 	public ByteBuffer putChar(char value) {
-		if(position + 2 > limit) throw new ArrayIndexOutOfBoundsException(position);
+		if(position + 2 > limit) throw Buffer.makeIOOBE(position);
 		UnsafeUtils.setMemChar(address + position, value);
 		position += 2;
 		return this;
@@ -223,20 +182,20 @@ public class EaglerLWJGLByteBuffer implements ByteBuffer {
 
 	@Override
 	public char getChar(int index) {
-		if(index + 2 > limit) throw new ArrayIndexOutOfBoundsException(index);
+		if(index < 0 || index + 2 > limit) throw Buffer.makeIOOBE(index);
 		return UnsafeUtils.getMemChar(address + index);
 	}
 
 	@Override
 	public ByteBuffer putChar(int index, char value) {
-		if(index + 2 > limit) throw new ArrayIndexOutOfBoundsException(index);
+		if(index < 0 || index + 2 > limit) throw Buffer.makeIOOBE(index);
 		UnsafeUtils.setMemChar(address + index, value);
 		return this;
 	}
 
 	@Override
 	public short getShort() {
-		if(position + 2 > limit) throw new ArrayIndexOutOfBoundsException(position);
+		if(position + 2 > limit) throw Buffer.makeIOOBE(position);
 		short s = UnsafeUtils.getMemShort(address + position);
 		position += 2;
 		return s;
@@ -244,7 +203,7 @@ public class EaglerLWJGLByteBuffer implements ByteBuffer {
 
 	@Override
 	public ByteBuffer putShort(short value) {
-		if(position + 2 > limit) throw new ArrayIndexOutOfBoundsException(position);
+		if(position + 2 > limit) throw Buffer.makeIOOBE(position);
 		UnsafeUtils.setMemShort(address + position, value);
 		position += 2;
 		return this;
@@ -252,13 +211,13 @@ public class EaglerLWJGLByteBuffer implements ByteBuffer {
 
 	@Override
 	public short getShort(int index) {
-		if(index + 2 > limit) throw new ArrayIndexOutOfBoundsException(index);
+		if(index < 0 || index + 2 > limit) throw Buffer.makeIOOBE(index);
 		return UnsafeUtils.getMemShort(address + index);
 	}
 
 	@Override
 	public ByteBuffer putShort(int index, short value) {
-		if(index + 2 > limit) throw new ArrayIndexOutOfBoundsException(index);
+		if(index < 0 || index + 2 > limit) throw Buffer.makeIOOBE(index);
 		UnsafeUtils.setMemShort(address + index, value);
 		return this;
 	}
@@ -270,7 +229,7 @@ public class EaglerLWJGLByteBuffer implements ByteBuffer {
 
 	@Override
 	public int getInt() {
-		if(position + 4 > limit) throw new ArrayIndexOutOfBoundsException(position);
+		if(position + 4 > limit) throw Buffer.makeIOOBE(position);
 		int i = UnsafeUtils.getMemInt(address + position);
 		position += 4;
 		return i;
@@ -278,7 +237,7 @@ public class EaglerLWJGLByteBuffer implements ByteBuffer {
 
 	@Override
 	public ByteBuffer putInt(int value) {
-		if(position + 4 > limit) throw new ArrayIndexOutOfBoundsException(position);
+		if(position + 4 > limit) throw Buffer.makeIOOBE(position);
 		UnsafeUtils.setMemInt(address + position, value);
 		position += 4;
 		return this;
@@ -286,13 +245,13 @@ public class EaglerLWJGLByteBuffer implements ByteBuffer {
 
 	@Override
 	public int getInt(int index) {
-		if(index + 4 > limit) throw new ArrayIndexOutOfBoundsException(index);
+		if(index < 0 || index + 4 > limit) throw Buffer.makeIOOBE(index);
 		return UnsafeUtils.getMemInt(address + index);
 	}
 
 	@Override
 	public ByteBuffer putInt(int index, int value) {
-		if(index + 4 > limit) throw new ArrayIndexOutOfBoundsException(index);
+		if(index < 0 || index + 4 > limit) throw Buffer.makeIOOBE(index);
 		UnsafeUtils.setMemInt(address + index, value);
 		return this;
 	}
@@ -304,7 +263,7 @@ public class EaglerLWJGLByteBuffer implements ByteBuffer {
 
 	@Override
 	public long getLong() {
-		if(position + 8 > limit) throw new ArrayIndexOutOfBoundsException(position);
+		if(position + 8 > limit) throw Buffer.makeIOOBE(position);
 		long l = UnsafeUtils.getMemLong(address + position);
 		position += 8;
 		return l;
@@ -312,7 +271,7 @@ public class EaglerLWJGLByteBuffer implements ByteBuffer {
 
 	@Override
 	public ByteBuffer putLong(long value) {
-		if(position + 8 > limit) throw new ArrayIndexOutOfBoundsException(position);
+		if(position + 8 > limit) throw Buffer.makeIOOBE(position);
 		UnsafeUtils.setMemLong(address + position, value);
 		position += 8;
 		return this;
@@ -320,20 +279,20 @@ public class EaglerLWJGLByteBuffer implements ByteBuffer {
 
 	@Override
 	public long getLong(int index) {
-		if(index + 8 > limit) throw new ArrayIndexOutOfBoundsException(index);
+		if(index < 0 || index + 8 > limit) throw Buffer.makeIOOBE(index);
 		return UnsafeUtils.getMemLong(address + index);
 	}
 
 	@Override
 	public ByteBuffer putLong(int index, long value) {
-		if(index + 8 > limit) throw new ArrayIndexOutOfBoundsException(index);
+		if(index < 0 || index + 8 > limit) throw Buffer.makeIOOBE(index);
 		UnsafeUtils.setMemLong(address + index, value);
 		return this;
 	}
 
 	@Override
 	public float getFloat() {
-		if(position + 4 > limit) throw new ArrayIndexOutOfBoundsException(position);
+		if(position + 4 > limit) throw Buffer.makeIOOBE(position);
 		float f = UnsafeUtils.getMemFloat(address + position);
 		position += 4;
 		return f;
@@ -341,7 +300,7 @@ public class EaglerLWJGLByteBuffer implements ByteBuffer {
 
 	@Override
 	public ByteBuffer putFloat(float value) {
-		if(position + 4 > limit) throw new ArrayIndexOutOfBoundsException(position);
+		if(position + 4 > limit) throw Buffer.makeIOOBE(position);
 		UnsafeUtils.setMemFloat(address + position, value);
 		position += 4;
 		return this;
@@ -349,13 +308,13 @@ public class EaglerLWJGLByteBuffer implements ByteBuffer {
 
 	@Override
 	public float getFloat(int index) {
-		if(index + 4 > limit) throw new ArrayIndexOutOfBoundsException(index);
+		if(index < 0 || index + 4 > limit) throw Buffer.makeIOOBE(index);
 		return UnsafeUtils.getMemFloat(address + index);
 	}
 
 	@Override
 	public ByteBuffer putFloat(int index, float value) {
-		if(index + 4 > limit) throw new ArrayIndexOutOfBoundsException(index);
+		if(index < 0 || index + 4 > limit) throw Buffer.makeIOOBE(index);
 		UnsafeUtils.setMemFloat(address + index, value);
 		return this;
 	}
@@ -374,7 +333,7 @@ public class EaglerLWJGLByteBuffer implements ByteBuffer {
 	@Override
 	public ByteBuffer reset() {
 		int m = mark;
-		if(m < 0) throw new ArrayIndexOutOfBoundsException("Invalid mark: " + m);
+		if(m < 0) throw new IndexOutOfBoundsException("Invalid mark: " + m);
 		position = m;
 		return this;
 	}
@@ -404,14 +363,14 @@ public class EaglerLWJGLByteBuffer implements ByteBuffer {
 
 	@Override
 	public ByteBuffer limit(int newLimit) {
-		if(newLimit < 0 || newLimit > capacity) throw new ArrayIndexOutOfBoundsException(newLimit);
+		if(newLimit < 0 || newLimit > capacity) throw Buffer.makeIOOBE(newLimit);
 		limit = newLimit;
 		return this;
 	}
 
 	@Override
 	public ByteBuffer position(int newPosition) {
-		if(newPosition < 0 || newPosition > limit) throw new ArrayIndexOutOfBoundsException(newPosition);
+		if(newPosition < 0 || newPosition > limit) throw Buffer.makeIOOBE(newPosition);
 		position = newPosition;
 		return this;
 	}
diff --git a/sources/lwjgl/java/net/lax1dude/eaglercraft/v1_8/internal/buffer/EaglerLWJGLFloatBuffer.java b/sources/lwjgl/java/net/lax1dude/eaglercraft/v1_8/internal/buffer/EaglerLWJGLFloatBuffer.java
index a163fe79..aa862fda 100644
--- a/sources/lwjgl/java/net/lax1dude/eaglercraft/v1_8/internal/buffer/EaglerLWJGLFloatBuffer.java
+++ b/sources/lwjgl/java/net/lax1dude/eaglercraft/v1_8/internal/buffer/EaglerLWJGLFloatBuffer.java
@@ -1,7 +1,5 @@
 package net.lax1dude.eaglercraft.v1_8.internal.buffer;
 
-import org.lwjgl.system.jemalloc.JEmalloc;
-
 import net.lax1dude.unsafememcpy.UnsafeMemcpy;
 import net.lax1dude.unsafememcpy.UnsafeUtils;
 
@@ -29,9 +27,9 @@ public class EaglerLWJGLFloatBuffer implements FloatBuffer {
 	private int position;
 	private int limit;
 	private int mark;
-	
+
 	private static final int SHIFT = 2;
-	
+
 	EaglerLWJGLFloatBuffer(long address, int capacity, boolean original) {
 		this(address, capacity, 0, capacity, -1, original);
 	}
@@ -70,82 +68,62 @@ public class EaglerLWJGLFloatBuffer implements FloatBuffer {
 		return position < limit;
 	}
 
-	@Override
-	public boolean isReadOnly() {
-		return false;
-	}
-
 	@Override
 	public boolean hasArray() {
 		return false;
 	}
 
 	@Override
-	public Object array() {
+	public float[] array() {
 		throw new UnsupportedOperationException();
 	}
 
-	@Override
-	public int arrayOffset() {
-		return position;
-	}
-
-	@Override
-	public FloatBuffer slice() {
-		return new EaglerLWJGLFloatBuffer(address + (position << SHIFT), limit - position, false);
-	}
-
 	@Override
 	public FloatBuffer duplicate() {
 		return new EaglerLWJGLFloatBuffer(address, capacity, position, limit, mark, false);
 	}
 
-	@Override
-	public FloatBuffer asReadOnlyBuffer() {
-		return new EaglerLWJGLFloatBuffer(address, capacity, position, limit, mark, false);
-	}
-
 	@Override
 	public float get() {
-		if(position >= limit) throw new ArrayIndexOutOfBoundsException(position);
+		if(position >= limit) throw Buffer.makeIOOBE(position);
 		return UnsafeUtils.getMemFloat(address + ((position++) << SHIFT));
 	}
 
 	@Override
 	public FloatBuffer put(float b) {
-		if(position >= limit) throw new ArrayIndexOutOfBoundsException(position);
+		if(position >= limit) throw Buffer.makeIOOBE(position);
 		UnsafeUtils.setMemFloat(address + ((position++) << SHIFT), b);
 		return this;
 	}
 
 	@Override
 	public float get(int index) {
-		if(index >= limit) throw new ArrayIndexOutOfBoundsException(index);
+		if(index < 0 || index >= limit) throw Buffer.makeIOOBE(index);
 		return UnsafeUtils.getMemFloat(address + (index << SHIFT));
 	}
 
 	@Override
 	public FloatBuffer put(int index, float b) {
-		if(index >= limit) throw new ArrayIndexOutOfBoundsException(index);
+		if(index < 0 || index >= limit) throw Buffer.makeIOOBE(index);
 		UnsafeUtils.setMemFloat(address + (index << SHIFT), b);
 		return this;
 	}
 
 	@Override
 	public float getElement(int index) {
-		if(index >= limit) throw new ArrayIndexOutOfBoundsException(index);
+		if(index < 0 || index >= limit) throw Buffer.makeIOOBE(index);
 		return UnsafeUtils.getMemFloat(address + (index << SHIFT));
 	}
 
 	@Override
 	public void putElement(int index, float value) {
-		if(position >= limit) throw new ArrayIndexOutOfBoundsException(position);
-		UnsafeUtils.setMemFloat(address + ((position++) << SHIFT), value);
+		if(index < 0 || index >= limit) throw Buffer.makeIOOBE(index);
+		UnsafeUtils.setMemFloat(address + (index << SHIFT), value);
 	}
 
 	@Override
 	public FloatBuffer get(float[] dst, int offset, int length) {
-		if(position + length > limit) throw new ArrayIndexOutOfBoundsException(position + length - 1);
+		if(position + length > limit) throw Buffer.makeIOOBE(position + length - 1);
 		UnsafeMemcpy.memcpyAlignDst(dst, offset << SHIFT, address + (position << SHIFT), length);
 		position += length;
 		return this;
@@ -153,7 +131,7 @@ public class EaglerLWJGLFloatBuffer implements FloatBuffer {
 
 	@Override
 	public FloatBuffer get(float[] dst) {
-		if(position + dst.length > limit) throw new ArrayIndexOutOfBoundsException(position + dst.length - 1);
+		if(position + dst.length > limit) throw Buffer.makeIOOBE(position + dst.length - 1);
 		UnsafeMemcpy.memcpyAlignDst(dst, 0, address + (position << SHIFT), dst.length);
 		position += dst.length;
 		return this;
@@ -164,13 +142,13 @@ public class EaglerLWJGLFloatBuffer implements FloatBuffer {
 		if(src instanceof EaglerLWJGLFloatBuffer) {
 			EaglerLWJGLFloatBuffer c = (EaglerLWJGLFloatBuffer)src;
 			int l = c.limit - c.position;
-			if(position + l > limit) throw new ArrayIndexOutOfBoundsException(position + l - 1);
+			if(position + l > limit) throw Buffer.makeIOOBE(position + l - 1);
 			UnsafeMemcpy.memcpy(address + (position << SHIFT), c.address + (c.position << SHIFT), l << SHIFT);
 			position += l;
 			c.position += l;
 		}else {
 			int l = src.remaining();
-			if(position + l > limit) throw new ArrayIndexOutOfBoundsException(position + l - 1);
+			if(position + l > limit) throw Buffer.makeIOOBE(position + l - 1);
 			for(int i = 0; i < l; ++i) {
 				UnsafeUtils.setMemFloat(address + ((position + l) << SHIFT), src.get());
 			}
@@ -181,7 +159,7 @@ public class EaglerLWJGLFloatBuffer implements FloatBuffer {
 
 	@Override
 	public FloatBuffer put(float[] src, int offset, int length) {
-		if(position + length > limit) throw new ArrayIndexOutOfBoundsException(position + length - 1);
+		if(position + length > limit) throw Buffer.makeIOOBE(position + length - 1);
 		UnsafeMemcpy.memcpyAlignSrc(address + (position << SHIFT), src, offset << SHIFT, length);
 		position += length;
 		return this;
@@ -189,36 +167,12 @@ public class EaglerLWJGLFloatBuffer implements FloatBuffer {
 
 	@Override
 	public FloatBuffer put(float[] src) {
-		if(position + src.length > limit) throw new ArrayIndexOutOfBoundsException(position + src.length - 1);
+		if(position + src.length > limit) throw Buffer.makeIOOBE(position + src.length - 1);
 		UnsafeMemcpy.memcpyAlignSrc(address + (position << SHIFT), src, 0, src.length);
 		position += src.length;
 		return this;
 	}
 
-	@Override
-	public int getArrayOffset() {
-		return position;
-	}
-
-	@Override
-	public FloatBuffer compact() {
-		if(limit > capacity) throw new ArrayIndexOutOfBoundsException(limit);
-		if(position > limit) throw new ArrayIndexOutOfBoundsException(position);
-		
-		if(position == limit) {
-			return new EaglerLWJGLFloatBuffer(0l, 0, false);
-		}
-		
-		int newLen = limit - position;
-		long newAlloc = JEmalloc.nje_malloc(newLen);
-		if(newAlloc == 0l) {
-			throw new OutOfMemoryError("Native je_malloc call returned null pointer!");
-		}
-		UnsafeMemcpy.memcpy(newAlloc, address + (position << SHIFT), newLen << SHIFT);
-		
-		return new EaglerLWJGLFloatBuffer(newAlloc, newLen, true);
-	}
-
 	@Override
 	public boolean isDirect() {
 		return true;
@@ -233,7 +187,7 @@ public class EaglerLWJGLFloatBuffer implements FloatBuffer {
 	@Override
 	public FloatBuffer reset() {
 		int m = mark;
-		if(m < 0) throw new ArrayIndexOutOfBoundsException("Invalid mark: " + m);
+		if(m < 0) throw new IndexOutOfBoundsException("Invalid mark: " + m);
 		position = m;
 		return this;
 	}
@@ -263,14 +217,14 @@ public class EaglerLWJGLFloatBuffer implements FloatBuffer {
 
 	@Override
 	public FloatBuffer limit(int newLimit) {
-		if(newLimit < 0 || newLimit > capacity) throw new ArrayIndexOutOfBoundsException(newLimit);
+		if(newLimit < 0 || newLimit > capacity) throw Buffer.makeIOOBE(newLimit);
 		limit = newLimit;
 		return this;
 	}
 
 	@Override
 	public FloatBuffer position(int newPosition) {
-		if(newPosition < 0 || newPosition > limit) throw new ArrayIndexOutOfBoundsException(newPosition);
+		if(newPosition < 0 || newPosition > limit) throw Buffer.makeIOOBE(newPosition);
 		position = newPosition;
 		return this;
 	}
diff --git a/sources/lwjgl/java/net/lax1dude/eaglercraft/v1_8/internal/buffer/EaglerLWJGLIntBuffer.java b/sources/lwjgl/java/net/lax1dude/eaglercraft/v1_8/internal/buffer/EaglerLWJGLIntBuffer.java
index bf306a2c..030c3a7b 100644
--- a/sources/lwjgl/java/net/lax1dude/eaglercraft/v1_8/internal/buffer/EaglerLWJGLIntBuffer.java
+++ b/sources/lwjgl/java/net/lax1dude/eaglercraft/v1_8/internal/buffer/EaglerLWJGLIntBuffer.java
@@ -1,7 +1,5 @@
 package net.lax1dude.eaglercraft.v1_8.internal.buffer;
 
-import org.lwjgl.system.jemalloc.JEmalloc;
-
 import net.lax1dude.unsafememcpy.UnsafeMemcpy;
 import net.lax1dude.unsafememcpy.UnsafeUtils;
 
@@ -21,7 +19,7 @@ import net.lax1dude.unsafememcpy.UnsafeUtils;
  * 
  */
 public class EaglerLWJGLIntBuffer implements IntBuffer {
-	
+
 	final long address;
 	final boolean original;
 
@@ -29,9 +27,9 @@ public class EaglerLWJGLIntBuffer implements IntBuffer {
 	private int position;
 	private int limit;
 	private int mark;
-	
+
 	private static final int SHIFT = 2;
-	
+
 	EaglerLWJGLIntBuffer(long address, int capacity, boolean original) {
 		this(address, capacity, 0, capacity, -1, original);
 	}
@@ -44,7 +42,7 @@ public class EaglerLWJGLIntBuffer implements IntBuffer {
 		this.mark = mark;
 		this.original = original;
 	}
-	
+
 	@Override
 	public int capacity() {
 		return capacity;
@@ -70,82 +68,62 @@ public class EaglerLWJGLIntBuffer implements IntBuffer {
 		return position < limit;
 	}
 
-	@Override
-	public boolean isReadOnly() {
-		return false;
-	}
-
 	@Override
 	public boolean hasArray() {
 		return false;
 	}
 
 	@Override
-	public Object array() {
+	public int[] array() {
 		throw new UnsupportedOperationException();
 	}
 
-	@Override
-	public int arrayOffset() {
-		return position;
-	}
-
-	@Override
-	public IntBuffer slice() {
-		return new EaglerLWJGLIntBuffer(address + (position << SHIFT), limit - position, false);
-	}
-
 	@Override
 	public IntBuffer duplicate() {
 		return new EaglerLWJGLIntBuffer(address, capacity, position, limit, mark, false);
 	}
 
-	@Override
-	public IntBuffer asReadOnlyBuffer() {
-		return new EaglerLWJGLIntBuffer(address, capacity, position, limit, mark, false);
-	}
-
 	@Override
 	public int get() {
-		if(position >= limit) throw new ArrayIndexOutOfBoundsException(position);
+		if(position >= limit) throw Buffer.makeIOOBE(position);
 		return UnsafeUtils.getMemInt(address + ((position++) << SHIFT));
 	}
 
 	@Override
 	public IntBuffer put(int b) {
-		if(position >= limit) throw new ArrayIndexOutOfBoundsException(position);
+		if(position >= limit) throw Buffer.makeIOOBE(position);
 		UnsafeUtils.setMemInt(address + ((position++) << SHIFT), b);
 		return this;
 	}
 
 	@Override
 	public int get(int index) {
-		if(index >= limit) throw new ArrayIndexOutOfBoundsException(index);
+		if(index < 0 || index >= limit) throw Buffer.makeIOOBE(index);
 		return UnsafeUtils.getMemInt(address + (index << SHIFT));
 	}
 
 	@Override
 	public IntBuffer put(int index, int b) {
-		if(index >= limit) throw new ArrayIndexOutOfBoundsException(index);
+		if(index < 0 || index >= limit) throw Buffer.makeIOOBE(index);
 		UnsafeUtils.setMemInt(address + (index << SHIFT), b);
 		return this;
 	}
 
 	@Override
 	public int getElement(int index) {
-		if(index >= limit) throw new ArrayIndexOutOfBoundsException(index);
+		if(index < 0 || index >= limit) throw Buffer.makeIOOBE(index);
 		return UnsafeUtils.getMemInt(address + (index << SHIFT));
 	}
 
 	@Override
 	public void putElement(int index, int value) {
-		if(index >= limit) throw new ArrayIndexOutOfBoundsException(index);
+		if(index < 0 || index >= limit) throw Buffer.makeIOOBE(index);
 		UnsafeUtils.setMemInt(address + (index << SHIFT), value);
 	}
 
 	@Override
 	public IntBuffer get(int[] dst, int offset, int length) {
-		if(position + length > limit) throw new ArrayIndexOutOfBoundsException(position + length - 1);
+		if(position + length > limit) throw Buffer.makeIOOBE(position + length - 1);
 		UnsafeMemcpy.memcpyAlignDst(dst, offset << SHIFT, address + (position << SHIFT), length);
 		position += length;
 		return this;
@@ -153,7 +131,7 @@ public class EaglerLWJGLIntBuffer implements IntBuffer {
 
 	@Override
 	public IntBuffer get(int[] dst) {
-		if(position + dst.length > limit) throw new ArrayIndexOutOfBoundsException(position + dst.length - 1);
+		if(position + dst.length > limit) throw Buffer.makeIOOBE(position + dst.length - 1);
 		UnsafeMemcpy.memcpyAlignDst(dst, 0, address + (position << SHIFT), dst.length);
 		position += dst.length;
 		return this;
@@ -164,13 +142,13 @@ public class EaglerLWJGLIntBuffer implements IntBuffer {
 		if(src instanceof EaglerLWJGLIntBuffer) {
 			EaglerLWJGLIntBuffer c = (EaglerLWJGLIntBuffer)src;
 			int l = c.limit - c.position;
-			if(position + l > limit) throw new ArrayIndexOutOfBoundsException(position + l - 1);
+			if(position + l > limit) throw Buffer.makeIOOBE(position + l - 1);
 			UnsafeMemcpy.memcpy(address + (position << SHIFT), c.address + (c.position << SHIFT), l << SHIFT);
 			position += l;
 			c.position += l;
 		}else {
 			int l = src.remaining();
-			if(position + l > limit) throw new ArrayIndexOutOfBoundsException(position + l - 1);
+			if(position + l > limit) throw Buffer.makeIOOBE(position + l - 1);
 			for(int i = 0; i < l; ++i) {
 				UnsafeUtils.setMemInt(address + ((position + l) << SHIFT), src.get());
 			}
@@ -181,7 +159,7 @@ public class EaglerLWJGLIntBuffer implements IntBuffer {
 
 	@Override
 	public IntBuffer put(int[] src, int offset, int length) {
-		if(position + length > limit) throw new ArrayIndexOutOfBoundsException(position + length - 1);
+		if(position + length > limit) throw Buffer.makeIOOBE(position + length - 1);
 		UnsafeMemcpy.memcpyAlignSrc(address + (position << SHIFT), src, offset << SHIFT, length);
 		position += length;
 		return this;
@@ -189,36 +167,12 @@ public class EaglerLWJGLIntBuffer implements IntBuffer {
 
 	@Override
 	public IntBuffer put(int[] src) {
-		if(position + src.length > limit) throw new ArrayIndexOutOfBoundsException(position + src.length - 1);
+		if(position + src.length > limit) throw Buffer.makeIOOBE(position + src.length - 1);
 		UnsafeMemcpy.memcpyAlignSrc(address + (position << SHIFT), src, 0, src.length);
 		position += src.length;
 		return this;
 	}
 
-	@Override
-	public int getArrayOffset() {
-		return position;
-	}
-
-	@Override
-	public IntBuffer compact() {
-		if(limit > capacity) throw new ArrayIndexOutOfBoundsException(limit);
-		if(position > limit) throw new ArrayIndexOutOfBoundsException(position);
-		
-		if(position == limit) {
-			return new EaglerLWJGLIntBuffer(0l, 0, false);
-		}
-		
-		int newLen = limit - position;
-		long newAlloc = JEmalloc.nje_malloc(newLen);
-		if(newAlloc == 0l) {
-			throw new OutOfMemoryError("Native je_malloc call returned null pointer!");
-		}
-		UnsafeMemcpy.memcpy(newAlloc, address + (position << SHIFT), newLen << SHIFT);
-		
-		return new EaglerLWJGLIntBuffer(newAlloc, newLen, true);
-	}
-
 	@Override
 	public boolean isDirect() {
 		return true;
@@ -233,7 +187,7 @@ public class EaglerLWJGLIntBuffer implements IntBuffer {
 	@Override
 	public IntBuffer reset() {
 		int m = mark;
-		if(m < 0) throw new ArrayIndexOutOfBoundsException("Invalid mark: " + m);
+		if(m < 0) throw new IndexOutOfBoundsException("Invalid mark: " + m);
 		position = m;
 		return this;
 	}
@@ -263,14 +217,14 @@ public class EaglerLWJGLIntBuffer implements IntBuffer {
 
 	@Override
 	public IntBuffer limit(int newLimit) {
-		if(newLimit < 0 || newLimit > capacity) throw new ArrayIndexOutOfBoundsException(newLimit);
+		if(newLimit < 0 || newLimit > capacity) throw Buffer.makeIOOBE(newLimit);
 		limit = newLimit;
 		return this;
 	}
 
 	@Override
 	public IntBuffer position(int newPosition) {
-		if(newPosition < 0 || newPosition > limit) throw new ArrayIndexOutOfBoundsException(newPosition);
+		if(newPosition < 0 || newPosition > limit) throw Buffer.makeIOOBE(newPosition);
 		position = newPosition;
 		return this;
 	}
diff --git a/sources/lwjgl/java/net/lax1dude/eaglercraft/v1_8/internal/buffer/EaglerLWJGLShortBuffer.java b/sources/lwjgl/java/net/lax1dude/eaglercraft/v1_8/internal/buffer/EaglerLWJGLShortBuffer.java
index eba363d1..41d45f61 100644
--- a/sources/lwjgl/java/net/lax1dude/eaglercraft/v1_8/internal/buffer/EaglerLWJGLShortBuffer.java
+++ b/sources/lwjgl/java/net/lax1dude/eaglercraft/v1_8/internal/buffer/EaglerLWJGLShortBuffer.java
@@ -1,7 +1,5 @@
 package net.lax1dude.eaglercraft.v1_8.internal.buffer;
 
-import org.lwjgl.system.jemalloc.JEmalloc;
-
 import net.lax1dude.unsafememcpy.UnsafeMemcpy;
 import net.lax1dude.unsafememcpy.UnsafeUtils;
 
@@ -21,7 +19,7 @@ import net.lax1dude.unsafememcpy.UnsafeUtils;
  * 
  */
 public class EaglerLWJGLShortBuffer implements ShortBuffer {
-	
+
 	final long address;
 	final boolean original;
 
@@ -29,9 +27,9 @@ public class EaglerLWJGLShortBuffer implements ShortBuffer {
 	private int position;
 	private int limit;
 	private int mark;
-	
+
 	private static final int SHIFT = 1;
-	
+
 	EaglerLWJGLShortBuffer(long address, int capacity, boolean original) {
 		this(address, capacity, 0, capacity, -1, original);
 	}
@@ -44,7 +42,7 @@ public class EaglerLWJGLShortBuffer implements ShortBuffer {
 		this.mark = mark;
 		this.original = original;
 	}
-	
+
 	@Override
 	public int capacity() {
 		return capacity;
@@ -70,82 +68,62 @@ public class EaglerLWJGLShortBuffer implements ShortBuffer {
 		return position < limit;
 	}
 
-	@Override
-	public boolean isReadOnly() {
-		return false;
-	}
-
 	@Override
 	public boolean hasArray() {
 		return false;
 	}
 
 	@Override
-	public Object array() {
+	public short[] array() {
 		throw new UnsupportedOperationException();
 	}
 
-	@Override
-	public int arrayOffset() {
-		return position;
-	}
-
-	@Override
-	public ShortBuffer slice() {
-		return new EaglerLWJGLShortBuffer(address + (position << SHIFT), limit - position, false);
-	}
-
 	@Override
 	public ShortBuffer duplicate() {
 		return new EaglerLWJGLShortBuffer(address, capacity, position, limit, mark, false);
 	}
 
-	@Override
-	public ShortBuffer asReadOnlyBuffer() {
-		return new EaglerLWJGLShortBuffer(address, capacity, position, limit, mark, false);
-	}
-
 	@Override
 	public short get() {
-		if(position >= limit) throw new ArrayIndexOutOfBoundsException(position);
+		if(position >= limit) throw Buffer.makeIOOBE(position);
 		return UnsafeUtils.getMemShort(address + ((position++) << SHIFT));
 	}
 
 	@Override
 	public ShortBuffer put(short b) {
-		if(position >= limit) throw new ArrayIndexOutOfBoundsException(position);
+		if(position >= limit) throw Buffer.makeIOOBE(position);
 		UnsafeUtils.setMemShort(address + ((position++) << SHIFT), b);
 		return this;
 	}
 
 	@Override
 	public short get(int index) {
-		if(index >= limit) throw new ArrayIndexOutOfBoundsException(index);
+		if(index < 0 || index >= limit) throw Buffer.makeIOOBE(index);
 		return UnsafeUtils.getMemShort(address + (index << SHIFT));
 	}
 
 	@Override
 	public ShortBuffer put(int index, short b) {
-		if(index >= limit) throw new ArrayIndexOutOfBoundsException(index);
+		if(index < 0 || index >= limit) throw Buffer.makeIOOBE(index);
 		UnsafeUtils.setMemShort(address + (index << SHIFT), b);
 		return this;
 	}
 
 	@Override
 	public short getElement(int index) {
-		if(index >= limit) throw new ArrayIndexOutOfBoundsException(index);
+		if(index < 0 || index >= limit) throw Buffer.makeIOOBE(index);
 		return UnsafeUtils.getMemShort(address + (index << SHIFT));
 	}
 
 	@Override
 	public void putElement(int index, short value) {
-		if(index >= limit) throw new ArrayIndexOutOfBoundsException(index);
+		if(index < 0 || index >= limit) throw Buffer.makeIOOBE(index);
 		UnsafeUtils.setMemShort(address + (index << SHIFT), value);
 	}
 
 	@Override
 	public ShortBuffer get(short[] dst, int offset, int length) {
-		if(position + length > limit) throw new ArrayIndexOutOfBoundsException(position + length - 1);
+		if(position + length > limit) throw Buffer.makeIOOBE(position + length - 1);
 		UnsafeMemcpy.memcpyAlignDst(dst, offset << SHIFT, address + (position << SHIFT), length);
 		position += length;
 		return this;
@@ -153,7 +131,7 @@ public class EaglerLWJGLShortBuffer implements ShortBuffer {
 
 	@Override
 	public ShortBuffer get(short[] dst) {
-		if(position + dst.length > limit) throw new ArrayIndexOutOfBoundsException(position + dst.length - 1);
+		if(position + dst.length > limit) throw Buffer.makeIOOBE(position + dst.length - 1);
 		UnsafeMemcpy.memcpyAlignDst(dst, 0, address + (position << SHIFT), dst.length);
 		position += dst.length;
 		return this;
@@ -164,13 +142,13 @@ public class EaglerLWJGLShortBuffer implements ShortBuffer {
 		if(src instanceof EaglerLWJGLShortBuffer) {
 			EaglerLWJGLShortBuffer c = (EaglerLWJGLShortBuffer)src;
 			int l = c.limit - c.position;
-			if(position + l > limit) throw new ArrayIndexOutOfBoundsException(position + l - 1);
+			if(position + l > limit) throw Buffer.makeIOOBE(position + l - 1);
 			UnsafeMemcpy.memcpy(address + (position << SHIFT), c.address + (c.position << SHIFT), l << SHIFT);
 			position += l;
 			c.position += l;
 		}else {
 			int l = src.remaining();
-			if(position + l > limit) throw new ArrayIndexOutOfBoundsException(position + l - 1);
+			if(position + l > limit) throw Buffer.makeIOOBE(position + l - 1);
 			for(int i = 0; i < l; ++i) {
 				UnsafeUtils.setMemInt(address + ((position + l) << SHIFT), src.get());
 			}
@@ -181,7 +159,7 @@ public class EaglerLWJGLShortBuffer implements ShortBuffer {
 
 	@Override
 	public ShortBuffer put(short[] src, int offset, int length) {
-		if(position + length > limit) throw new ArrayIndexOutOfBoundsException(position + length - 1);
+		if(position + length > limit) throw Buffer.makeIOOBE(position + length - 1);
 		UnsafeMemcpy.memcpyAlignSrc(address + (position << SHIFT), src, offset << SHIFT, length);
 		position += length;
 		return this;
@@ -189,36 +167,12 @@ public class EaglerLWJGLShortBuffer implements ShortBuffer {
 
 	@Override
 	public ShortBuffer put(short[] src) {
-		if(position + src.length > limit) throw new ArrayIndexOutOfBoundsException(position + src.length - 1);
+		if(position + src.length > limit) throw Buffer.makeIOOBE(position + src.length - 1);
 		UnsafeMemcpy.memcpyAlignSrc(address + (position << SHIFT), src, 0, src.length);
 		position += src.length;
 		return this;
 	}
 
-	@Override
-	public int getArrayOffset() {
-		return position;
-	}
-
-	@Override
-	public ShortBuffer compact() {
-		if(limit > capacity) throw new ArrayIndexOutOfBoundsException(limit);
-		if(position > limit) throw new ArrayIndexOutOfBoundsException(position);
-		
-		if(position == limit) {
-			return new EaglerLWJGLShortBuffer(0l, 0, false);
-		}
-		
-		int newLen = limit - position;
-		long newAlloc = JEmalloc.nje_malloc(newLen);
-		if(newAlloc == 0l) {
-			throw new OutOfMemoryError("Native je_malloc call returned null pointer!");
-		}
-		UnsafeMemcpy.memcpy(newAlloc, address + (position << SHIFT), newLen << SHIFT);
-		
-		return new EaglerLWJGLShortBuffer(newAlloc, newLen, true);
-	}
-
 	@Override
 	public boolean isDirect() {
 		return true;
@@ -233,7 +187,7 @@ public class EaglerLWJGLShortBuffer implements ShortBuffer {
 	@Override
 	public ShortBuffer reset() {
 		int m = mark;
-		if(m < 0) throw new ArrayIndexOutOfBoundsException("Invalid mark: " + m);
+		if(m < 0) throw new IndexOutOfBoundsException("Invalid mark: " + m);
 		position = m;
 		return this;
 	}
@@ -263,14 +217,14 @@ public class EaglerLWJGLShortBuffer implements ShortBuffer {
 
 	@Override
 	public ShortBuffer limit(int newLimit) {
-		if(newLimit < 0 || newLimit > capacity) throw new ArrayIndexOutOfBoundsException(newLimit);
+		if(newLimit < 0 || newLimit > capacity) throw Buffer.makeIOOBE(newLimit);
 		limit = newLimit;
 		return this;
 	}
 
 	@Override
 	public ShortBuffer position(int newPosition) {
-		if(newPosition < 0 || newPosition > limit) throw new ArrayIndexOutOfBoundsException(newPosition);
+		if(newPosition < 0 || newPosition > limit) throw Buffer.makeIOOBE(newPosition);
 		position = newPosition;
 		return this;
 	}
diff --git a/sources/lwjgl/java/net/lax1dude/eaglercraft/v1_8/internal/lwjgl/DebugFilesystem.java b/sources/lwjgl/java/net/lax1dude/eaglercraft/v1_8/internal/lwjgl/DebugFilesystem.java
index a5ee8df6..eb5cbcd8 100644
--- a/sources/lwjgl/java/net/lax1dude/eaglercraft/v1_8/internal/lwjgl/DebugFilesystem.java
+++ b/sources/lwjgl/java/net/lax1dude/eaglercraft/v1_8/internal/lwjgl/DebugFilesystem.java
@@ -5,6 +5,7 @@ import java.io.FileInputStream;
 import java.io.FileOutputStream;
 import java.io.IOException;
 
+import net.lax1dude.eaglercraft.v1_8.internal.IEaglerFilesystem;
 import net.lax1dude.eaglercraft.v1_8.internal.PlatformFilesystem;
 import net.lax1dude.eaglercraft.v1_8.internal.PlatformRuntime;
 import net.lax1dude.eaglercraft.v1_8.internal.VFSFilenameIterator;
@@ -27,21 +28,33 @@ import net.lax1dude.eaglercraft.v1_8.internal.vfs2.VFSIterator2.BreakLoop;
  * POSSIBILITY OF SUCH DAMAGE.
  * 
  */
-public class DebugFilesystem implements PlatformFilesystem.IFilesystemProvider {
+public class DebugFilesystem implements IEaglerFilesystem {
 
-	public static DebugFilesystem initialize(File filesystemRoot) {
+	public static DebugFilesystem initialize(String fsName, File filesystemRoot) {
 		if(!filesystemRoot.isDirectory() && !filesystemRoot.mkdirs()) {
 			throw new EaglerFileSystemException("Could not create directory for virtual filesystem: " + filesystemRoot.getAbsolutePath());
 		}
-		return new DebugFilesystem(filesystemRoot);
+		return new DebugFilesystem(fsName, filesystemRoot);
 	}
 
 	private final File filesystemRoot;
+	private final String fsName;
 
-	private DebugFilesystem(File root) {
+	private DebugFilesystem(String fsName, File root) {
+		this.fsName = fsName;
 		this.filesystemRoot = root;
 	}
 
+	@Override
+	public String getFilesystemName() {
+		return fsName;
+	}
+
+	@Override
+	public String getInternalDBName() {
+		return "desktopruntime:" + filesystemRoot.getAbsolutePath();
+	}
+
 	@Override
 	public boolean eaglerDelete(String pathName) {
 		File f = getJREFile(pathName);
@@ -78,7 +91,7 @@ public class DebugFilesystem implements PlatformFilesystem.IFilesystemProvider {
 				return tmp;
 			}catch (IOException e) {
 				throw new EaglerFileSystemException("Failed to read: " + f.getAbsolutePath(), e);
-			}catch(ArrayIndexOutOfBoundsException ex) {
+			}catch(IndexOutOfBoundsException ex) {
 				throw new EaglerFileSystemException("ERROR: Expected " + fileSize + " bytes, buffer overflow reading: " + f.getAbsolutePath(), ex);
 			}finally {
 				if(buf != null) {
@@ -221,4 +234,15 @@ public class DebugFilesystem implements PlatformFilesystem.IFilesystemProvider {
 			f.delete();
 		}
 	}
+
+	@Override
+	public boolean isRamdisk() {
+		return false;
+	}
+
+	@Override
+	public void closeHandle() {
+		
+	}
+
 }
diff --git a/sources/lwjgl/java/net/lax1dude/eaglercraft/v1_8/internal/lwjgl/DesktopClientConfigAdapter.java b/sources/lwjgl/java/net/lax1dude/eaglercraft/v1_8/internal/lwjgl/DesktopClientConfigAdapter.java
index 3c1fd1de..5de69dc5 100644
--- a/sources/lwjgl/java/net/lax1dude/eaglercraft/v1_8/internal/lwjgl/DesktopClientConfigAdapter.java
+++ b/sources/lwjgl/java/net/lax1dude/eaglercraft/v1_8/internal/lwjgl/DesktopClientConfigAdapter.java
@@ -31,7 +31,7 @@ public class DesktopClientConfigAdapter implements IClientConfigAdapter {
 
 	public static final IClientConfigAdapter instance = new DesktopClientConfigAdapter();
 
-	public final List<DefaultServer> defaultServers = new ArrayList();
+	public final List<DefaultServer> defaultServers = new ArrayList<>();
 
 	private final DesktopClientConfigAdapterHooks hooks = new DesktopClientConfigAdapterHooks();
 
@@ -52,17 +52,17 @@ public class DesktopClientConfigAdapter implements IClientConfigAdapter {
 
 	@Override
 	public String getWorldsDB() {
-		return "desktop";
+		return "worlds";
 	}
 
 	@Override
 	public String getResourcePacksDB() {
-		return "desktop";
+		return "resourcePacks";
 	}
 
 	@Override
 	public JSONObject getIntegratedServerOpts() {
-		return new JSONObject("{\"container\":null,\"worldsDB\":\"desktop\"}");
+		return new JSONObject("{\"container\":null,\"worldsDB\":\"worlds\"}");
 	}
 
 	private final List<RelayEntry> relays = new ArrayList<>();
@@ -148,6 +148,51 @@ public class DesktopClientConfigAdapter implements IClientConfigAdapter {
 		return true;
 	}
 
+	@Override
+	public boolean isEnableServerCookies() {
+		return true;
+	}
+
+	@Override
+	public boolean isAllowServerRedirects() {
+		return true;
+	}
+
+	@Override
+	public boolean isOpenDebugConsoleOnLaunch() {
+		return false;
+	}
+
+	@Override
+	public boolean isForceWebViewSupport() {
+		return false;
+	}
+
+	@Override
+	public boolean isEnableWebViewCSP() {
+		return true;
+	}
+
+	@Override
+	public boolean isAllowBootMenu() {
+		return false;
+	}
+
+	@Override
+	public boolean isForceProfanityFilter() {
+		return false;
+	}
+
+	@Override
+	public boolean isEaglerNoDelay() {
+		return false;
+	}
+
+	@Override
+	public boolean isRamdiskMode() {
+		return false;
+	}
+
 	@Override
 	public IClientConfigAdapterHooks getHooks() {
 		return hooks;
@@ -170,5 +215,12 @@ public class DesktopClientConfigAdapter implements IClientConfigAdapter {
 			
 		}
 
+		@Override
+		public void callScreenChangedHook(String screenName, int scaledWidth, int scaledHeight, int realWidth,
+				int realHeight, int scaleFactor) {
+			
+		}
+
 	}
+
 }
diff --git a/sources/lwjgl/java/net/lax1dude/eaglercraft/v1_8/internal/lwjgl/DesktopWebSocketClient.java b/sources/lwjgl/java/net/lax1dude/eaglercraft/v1_8/internal/lwjgl/DesktopWebSocketClient.java
new file mode 100644
index 00000000..a3b72a89
--- /dev/null
+++ b/sources/lwjgl/java/net/lax1dude/eaglercraft/v1_8/internal/lwjgl/DesktopWebSocketClient.java
@@ -0,0 +1,109 @@
+package net.lax1dude.eaglercraft.v1_8.internal.lwjgl;
+
+import java.net.URI;
+
+import net.lax1dude.eaglercraft.v1_8.EaglercraftVersion;
+import net.lax1dude.eaglercraft.v1_8.internal.AbstractWebSocketClient;
+import net.lax1dude.eaglercraft.v1_8.internal.EnumEaglerConnectionState;
+import net.lax1dude.eaglercraft.v1_8.log4j.LogManager;
+import net.lax1dude.eaglercraft.v1_8.log4j.Logger;
+
+/**
+ * Copyright (c) 2024 lax1dude. All Rights Reserved.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ * 
+ */
+public class DesktopWebSocketClient extends AbstractWebSocketClient {
+
+	static final Logger logger = LogManager.getLogger("DesktopWebSocketClient");
+	
+	volatile EnumEaglerConnectionState playConnectState = EnumEaglerConnectionState.CONNECTING;
+	final Object connectOpenMutex = new Object();
+	final WebSocketClientImpl clientImpl;
+	final URI currentURI;
+	final String currentURIStr;
+
+	public DesktopWebSocketClient(URI currentURI) {
+		super(currentURI.toString());
+		this.currentURI = currentURI;
+		currentURIStr = currentURI.toString();
+		clientImpl = new WebSocketClientImpl(this, currentURI);
+		clientImpl.addHeader("Origin", "EAG_LWJGL_" + (EaglercraftVersion.projectForkName + "_"
+				+ EaglercraftVersion.projectOriginVersion).replaceAll("[^a-zA-Z0-9\\-_\\.]", "_"));
+	}
+
+	@Override
+	public EnumEaglerConnectionState getState() {
+		return playConnectState;
+	}
+
+	@Override
+	public boolean connectBlocking(int timeoutMS) {
+		synchronized(connectOpenMutex) {
+			try {
+				connectOpenMutex.wait(timeoutMS);
+			} catch (InterruptedException e) {
+				return false;
+			}
+		}
+		return playConnectState.isOpen();
+	}
+
+	@Override
+	public boolean isOpen() {
+		return playConnectState.isOpen();
+	}
+
+	@Override
+	public boolean isClosed() {
+		return playConnectState.isClosed();
+	}
+
+	@Override
+	public void close() {
+		if(!playConnectState.isClosed()) {
+			try {
+				clientImpl.closeBlocking();
+			} catch (InterruptedException e) {
+			}
+			playConnectState = EnumEaglerConnectionState.CLOSED;
+		}
+	}
+
+	@Override
+	public void send(String str) {
+		if(clientImpl.isClosed()) {
+			logger.error("[{}]: Client tried to send {} char packet while the socket was closed!", currentURIStr, str.length());
+		}else {
+			clientImpl.send(str);
+		}
+	}
+
+	@Override
+	public void send(byte[] bytes) {
+		if(clientImpl.isClosed()) {
+			logger.error("[{}]: Client tried to send {} byte packet while the socket was closed!", currentURIStr, bytes.length);
+		}else {
+			clientImpl.send(bytes);
+		}
+	}
+
+	public void handleString(String str) {
+		addRecievedFrame(new DesktopWebSocketFrameString(str));
+	}
+
+	public void handleBytes(byte[] array) {
+		addRecievedFrame(new DesktopWebSocketFrameBinary(array));
+	}
+
+}
diff --git a/sources/lwjgl/java/net/lax1dude/eaglercraft/v1_8/internal/lwjgl/DesktopWebSocketFrameBinary.java b/sources/lwjgl/java/net/lax1dude/eaglercraft/v1_8/internal/lwjgl/DesktopWebSocketFrameBinary.java
new file mode 100644
index 00000000..c8919714
--- /dev/null
+++ b/sources/lwjgl/java/net/lax1dude/eaglercraft/v1_8/internal/lwjgl/DesktopWebSocketFrameBinary.java
@@ -0,0 +1,64 @@
+package net.lax1dude.eaglercraft.v1_8.internal.lwjgl;
+
+import java.io.InputStream;
+
+import net.lax1dude.eaglercraft.v1_8.EaglerInputStream;
+import net.lax1dude.eaglercraft.v1_8.internal.IWebSocketFrame;
+import net.lax1dude.eaglercraft.v1_8.internal.PlatformRuntime;
+
+/**
+ * Copyright (c) 2024 lax1dude. All Rights Reserved.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ * 
+ */
+public class DesktopWebSocketFrameBinary implements IWebSocketFrame {
+
+	private final byte[] byteArray;
+	private final long timestamp;
+
+	public DesktopWebSocketFrameBinary(byte[] byteArray) {
+		this.byteArray = byteArray;
+		this.timestamp = PlatformRuntime.steadyTimeMillis();
+	}
+
+	@Override
+	public boolean isString() {
+		return false;
+	}
+
+	@Override
+	public String getString() {
+		return null;
+	}
+
+	@Override
+	public byte[] getByteArray() {
+		return byteArray;
+	}
+
+	@Override
+	public InputStream getInputStream() {
+		return new EaglerInputStream(byteArray);
+	}
+
+	@Override
+	public int getLength() {
+		return byteArray.length;
+	}
+
+	@Override
+	public long getTimestamp() {
+		return timestamp;
+	}
+
+}
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/relay/pkt/IPacket70SpecialUpdate.java b/sources/lwjgl/java/net/lax1dude/eaglercraft/v1_8/internal/lwjgl/DesktopWebSocketFrameString.java
similarity index 50%
rename from sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/relay/pkt/IPacket70SpecialUpdate.java
rename to sources/lwjgl/java/net/lax1dude/eaglercraft/v1_8/internal/lwjgl/DesktopWebSocketFrameString.java
index 1bdd4630..3be7a6b2 100644
--- a/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/relay/pkt/IPacket70SpecialUpdate.java
+++ b/sources/lwjgl/java/net/lax1dude/eaglercraft/v1_8/internal/lwjgl/DesktopWebSocketFrameString.java
@@ -1,8 +1,9 @@
-package net.lax1dude.eaglercraft.v1_8.sp.relay.pkt;
+package net.lax1dude.eaglercraft.v1_8.internal.lwjgl;
 
-import java.io.DataInputStream;
-import java.io.DataOutputStream;
-import java.io.IOException;
+import java.io.InputStream;
+
+import net.lax1dude.eaglercraft.v1_8.internal.IWebSocketFrame;
+import net.lax1dude.eaglercraft.v1_8.internal.PlatformRuntime;
 
 /**
  * Copyright (c) 2024 lax1dude. All Rights Reserved.
@@ -19,37 +20,44 @@ import java.io.IOException;
  * POSSIBILITY OF SUCH DAMAGE.
  * 
  */
-public class IPacket70SpecialUpdate extends IPacket {
+public class DesktopWebSocketFrameString implements IWebSocketFrame {
 
-	public static final int OPERATION_UPDATE_CERTIFICATE = 0x69;
+	private final String string;
+	private final long timestamp;
 
-	public int operation;
-	public byte[] updatePacket;
-
-	public IPacket70SpecialUpdate() {
-	}
-
-	public IPacket70SpecialUpdate(int operation, byte[] updatePacket) {
-		this.operation = operation;
-		this.updatePacket = updatePacket;
+	public DesktopWebSocketFrameString(String string) {
+		this.string = string;
+		this.timestamp = PlatformRuntime.steadyTimeMillis();
 	}
 
 	@Override
-	public void read(DataInputStream input) throws IOException {
-		operation = input.read();
-		updatePacket = new byte[input.readUnsignedShort()];
-		input.read(updatePacket);
+	public boolean isString() {
+		return true;
 	}
 
 	@Override
-	public void write(DataOutputStream output) throws IOException {
-		output.write(operation);
-		output.writeShort(updatePacket.length);
-		output.write(updatePacket);
+	public String getString() {
+		return string;
 	}
 
 	@Override
-	public int packetLength() {
-		return 3 + updatePacket.length;
+	public byte[] getByteArray() {
+		return null;
 	}
+
+	@Override
+	public InputStream getInputStream() {
+		return null;
+	}
+
+	@Override
+	public int getLength() {
+		return string.length();
+	}
+
+	@Override
+	public long getTimestamp() {
+		return timestamp;
+	}
+
 }
diff --git a/sources/lwjgl/java/net/lax1dude/eaglercraft/v1_8/internal/lwjgl/FallbackWebViewHTTPD.java b/sources/lwjgl/java/net/lax1dude/eaglercraft/v1_8/internal/lwjgl/FallbackWebViewHTTPD.java
new file mode 100644
index 00000000..f2eabebf
--- /dev/null
+++ b/sources/lwjgl/java/net/lax1dude/eaglercraft/v1_8/internal/lwjgl/FallbackWebViewHTTPD.java
@@ -0,0 +1,41 @@
+package net.lax1dude.eaglercraft.v1_8.internal.lwjgl;
+
+import fi.iki.elonen.NanoHTTPD;
+import fi.iki.elonen.NanoHTTPD.Response.Status;
+import net.lax1dude.eaglercraft.v1_8.log4j.Logger;
+
+/**
+ * Copyright (c) 2024 lax1dude. All Rights Reserved.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ * 
+ */
+class FallbackWebViewHTTPD extends NanoHTTPD {
+
+	static final Logger logger = FallbackWebViewServer.logger;
+
+	private String index;
+
+	FallbackWebViewHTTPD(String hostname, int port, String index) {
+		super(hostname, port);
+		this.index = index;
+	}
+
+	@Override
+    public Response serve(IHTTPSession session) {
+		if("/RTWebViewClient".equals(session.getUri())) {
+			return newFixedLengthResponse(Status.OK, MIME_HTML, index);
+		}else {
+			return newFixedLengthResponse(Status.NOT_FOUND, MIME_HTML, "<!DOCTYPE html><html><head><title>Eaglercraft Desktop Runtime</title></head><body><h1>404 Not Found</h1></body></html>");
+		}
+	}
+}
diff --git a/sources/lwjgl/java/net/lax1dude/eaglercraft/v1_8/internal/lwjgl/FallbackWebViewProtocol.java b/sources/lwjgl/java/net/lax1dude/eaglercraft/v1_8/internal/lwjgl/FallbackWebViewProtocol.java
new file mode 100644
index 00000000..8516510e
--- /dev/null
+++ b/sources/lwjgl/java/net/lax1dude/eaglercraft/v1_8/internal/lwjgl/FallbackWebViewProtocol.java
@@ -0,0 +1,299 @@
+package net.lax1dude.eaglercraft.v1_8.internal.lwjgl;
+
+import java.nio.charset.StandardCharsets;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import net.lax1dude.eaglercraft.v1_8.internal.WebViewOptions;
+import net.lax1dude.eaglercraft.v1_8.log4j.Logger;
+import net.lax1dude.eaglercraft.v1_8.webview.PermissionsCache;
+
+/**
+ * Copyright (c) 2024 lax1dude. All Rights Reserved.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ * 
+ */
+class FallbackWebViewProtocol {
+
+	static final Logger logger = FallbackWebViewServer.logger;
+
+	private static final Map<Integer,Class<? extends FallbackWebViewPacket>> packetIDToClass = new HashMap<>();
+	private static final Map<Class<? extends FallbackWebViewPacket>,Integer> packetClassToID = new HashMap<>();
+
+	private static final int CLIENT_TO_SERVER = 0;
+	private static final int SERVER_TO_CLIENT = 1;
+
+	static {
+		register(0x00, CLIENT_TO_SERVER, CPacketClientHandshake.class);
+		register(0x01, SERVER_TO_CLIENT, SPacketServerHandshake.class);
+		register(0x02, SERVER_TO_CLIENT, SPacketServerError.class);
+		register(0x03, CLIENT_TO_SERVER, CPacketWebViewChannelOpen.class);
+		register(0x04, CLIENT_TO_SERVER, CPacketWebViewChannelClose.class);
+		register(0x05, CLIENT_TO_SERVER, CPacketWebViewMessage.class);
+		register(0x06, SERVER_TO_CLIENT, SPacketWebViewMessage.class);
+		register(0x07, CLIENT_TO_SERVER, CPacketWebViewJSPermission.class);
+	}
+
+	private static void register(int id, int dir, Class<? extends FallbackWebViewPacket> packet) {
+		if(dir == CLIENT_TO_SERVER) {
+			packetIDToClass.put(id, packet);
+		}else if(dir == SERVER_TO_CLIENT) {
+			packetClassToID.put(packet, id);
+		}else {
+			throw new IllegalArgumentException();
+		}
+	}
+
+	static String writePacket(FallbackWebViewPacket packet) {
+		Class<? extends FallbackWebViewPacket> cls = packet.getClass();
+		Integer id = packetClassToID.get(cls);
+		if(id == null) {
+			throw new RuntimeException("Tried to send unknown packet to client: " + cls.getSimpleName());
+		}
+		JSONObject json = new JSONObject();
+		json.put("$", id);
+		packet.writePacket(json);
+		return json.toString();
+	}
+
+	static FallbackWebViewPacket readPacket(String data) {
+		try {
+			JSONObject json = new JSONObject(data);
+			int id = json.getInt("$");
+			Class<? extends FallbackWebViewPacket> cls = packetIDToClass.get(id);
+			if(cls == null) {
+				logger.error("Unknown packet ID {} recieved from webview controller", id);
+				return null;
+			}
+			FallbackWebViewPacket ret;
+			try {
+				ret = cls.newInstance();
+			}catch(Throwable t) {
+				throw new RuntimeException("Failed to call packet constructor for \"" + cls.getSimpleName() + "\"! (is it defined?)");
+			}
+			ret.readPacket(json);
+			return ret;
+		}catch(Throwable ex) {
+			logger.error("Failed to parse message from webview controller: \"{}\"", data);
+			logger.error(ex);
+			return null;
+		}
+	}
+
+	static interface FallbackWebViewPacket {
+		
+		void readPacket(JSONObject json);
+		
+		void writePacket(JSONObject json);
+		
+	}
+
+	static class CPacketClientHandshake implements FallbackWebViewPacket {
+
+		public boolean cspSupport;
+
+		public CPacketClientHandshake() {
+		}
+
+		@Override
+		public void readPacket(JSONObject json) {
+			cspSupport = json.getBoolean("cspSupport");
+		}
+
+		@Override
+		public void writePacket(JSONObject json) {
+			throw new UnsupportedOperationException("Client only!");
+		}
+
+	}
+
+	static class CPacketWebViewChannelOpen implements FallbackWebViewPacket {
+
+		public String messageChannel;
+
+		public CPacketWebViewChannelOpen() {
+		}
+
+		public CPacketWebViewChannelOpen(String messageChannel) {
+			this.messageChannel = messageChannel;
+		}
+
+		@Override
+		public void readPacket(JSONObject json) {
+			messageChannel = json.getString("channel");
+			if(messageChannel.length() > 255) {
+				throw new JSONException("Channel name too long!");
+			}
+		}
+
+		@Override
+		public void writePacket(JSONObject json) {
+			throw new UnsupportedOperationException("Client only!");
+		}
+
+	}
+
+	static class CPacketWebViewChannelClose implements FallbackWebViewPacket {
+
+		public CPacketWebViewChannelClose() {
+		}
+
+		@Override
+		public void readPacket(JSONObject json) {
+			
+		}
+
+		@Override
+		public void writePacket(JSONObject json) {
+			throw new UnsupportedOperationException("Client only!");
+		}
+
+	}
+
+	// for string messages, binary are sent as a binary frame
+	static class CPacketWebViewMessage implements FallbackWebViewPacket {
+
+		public String messageContent;
+
+		public CPacketWebViewMessage() {
+		}
+
+		public CPacketWebViewMessage(String messageContent) {
+			this.messageContent = messageContent;
+		}
+
+		@Override
+		public void readPacket(JSONObject json) {
+			messageContent = json.getString("msg");
+		}
+
+		@Override
+		public void writePacket(JSONObject json) {
+			throw new UnsupportedOperationException("Client only!");
+		}
+
+	}
+
+	static class SPacketServerHandshake implements FallbackWebViewPacket {
+
+		public WebViewOptions options;
+		public EnumWebViewJSPermission hasApprovedJS;
+
+		public SPacketServerHandshake() {
+		}
+
+		public SPacketServerHandshake(WebViewOptions options, EnumWebViewJSPermission hasApprovedJS) {
+			this.options = options;
+			this.hasApprovedJS = hasApprovedJS;
+		}
+
+		@Override
+		public void readPacket(JSONObject json) {
+			throw new UnsupportedOperationException("Server only!");
+		}
+
+		@Override
+		public void writePacket(JSONObject json) {
+			json.put("contentMode", options.contentMode.toString());
+			json.put("fallbackTitle", options.fallbackTitle);
+			json.put("scriptEnabled", options.scriptEnabled);
+			json.put("strictCSPEnable", options.strictCSPEnable);
+			json.put("serverMessageAPIEnabled", options.serverMessageAPIEnabled);
+			json.put("url", options.url);
+			json.put("blob", options.blob != null ? new String(options.blob, StandardCharsets.UTF_8) : null);
+			json.put("hasApprovedJS", hasApprovedJS.toString());
+		}
+
+	}
+
+	static class SPacketServerError implements FallbackWebViewPacket {
+
+		public String errorMessage;
+
+		public SPacketServerError() {
+		}
+
+		public SPacketServerError(String errorMessage) {
+			this.errorMessage = errorMessage;
+		}
+
+		@Override
+		public void readPacket(JSONObject json) {
+			throw new UnsupportedOperationException("Server only!");
+		}
+
+		@Override
+		public void writePacket(JSONObject json) {
+			json.put("msg", errorMessage);
+		}
+
+	}
+
+	static class SPacketWebViewMessage implements FallbackWebViewPacket {
+
+		public String message;
+
+		public SPacketWebViewMessage() {
+		}
+
+		public SPacketWebViewMessage(String message) {
+			this.message = message;
+		}
+
+		@Override
+		public void readPacket(JSONObject json) {
+			throw new UnsupportedOperationException("Server only!");
+		}
+
+		@Override
+		public void writePacket(JSONObject json) {
+			json.put("msg", message);
+		}
+
+	}
+
+	static enum EnumWebViewJSPermission {
+		NOT_SET, ALLOW, BLOCK;
+
+		static EnumWebViewJSPermission fromPermission(PermissionsCache.Permission perm) {
+			if(perm != null) {
+				return perm.choice ? ALLOW : BLOCK;
+			}else {
+				return NOT_SET;
+			}
+		}
+	}
+
+	static class CPacketWebViewJSPermission implements FallbackWebViewPacket {
+
+		public EnumWebViewJSPermission permission;
+
+		public CPacketWebViewJSPermission() {
+		}
+
+		@Override
+		public void readPacket(JSONObject json) {
+			permission = EnumWebViewJSPermission.valueOf(json.getString("perm"));
+		}
+
+		@Override
+		public void writePacket(JSONObject json) {
+			throw new UnsupportedOperationException("Client only!");
+		}
+
+	}
+
+}
diff --git a/sources/lwjgl/java/net/lax1dude/eaglercraft/v1_8/internal/lwjgl/FallbackWebViewServer.java b/sources/lwjgl/java/net/lax1dude/eaglercraft/v1_8/internal/lwjgl/FallbackWebViewServer.java
new file mode 100644
index 00000000..79da7b11
--- /dev/null
+++ b/sources/lwjgl/java/net/lax1dude/eaglercraft/v1_8/internal/lwjgl/FallbackWebViewServer.java
@@ -0,0 +1,190 @@
+package net.lax1dude.eaglercraft.v1_8.internal.lwjgl;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.net.InetSocketAddress;
+import java.net.ServerSocket;
+import java.nio.charset.StandardCharsets;
+
+import org.json.JSONObject;
+
+import net.lax1dude.eaglercraft.v1_8.internal.IClientConfigAdapter;
+import net.lax1dude.eaglercraft.v1_8.internal.PlatformRuntime;
+import net.lax1dude.eaglercraft.v1_8.internal.WebViewOptions;
+import net.lax1dude.eaglercraft.v1_8.log4j.LogManager;
+import net.lax1dude.eaglercraft.v1_8.log4j.Logger;
+import net.lax1dude.eaglercraft.v1_8.socket.protocol.pkt.server.SPacketWebViewMessageV4EAG;
+import net.lax1dude.eaglercraft.v1_8.webview.WebViewOverlayController.IPacketSendCallback;
+
+/**
+ * Copyright (c) 2024 lax1dude. All Rights Reserved.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ * 
+ */
+public class FallbackWebViewServer {
+
+	static final Logger logger = LogManager.getLogger("FallbackWebViewServer");
+
+	public static final String LISTEN_ADDR = "127.69.69.69";
+
+	public static final File webViewClientHTML = new File("RTWebViewClient.html");
+
+	public final WebViewOptions options;
+
+	private FallbackWebViewWSD websocketServer;
+	private FallbackWebViewHTTPD httpServer;
+
+	private String currentURL;
+	private volatile boolean dead;
+
+	private IPacketSendCallback callback = null;
+
+	public FallbackWebViewServer(WebViewOptions options) {
+		this.options = options;
+	}
+
+	public void start() throws RuntimeException {
+		dead = false;
+		StringBuilder vigg = new StringBuilder();
+		try(BufferedReader reader = new BufferedReader(
+				new InputStreamReader(new FileInputStream(webViewClientHTML), StandardCharsets.UTF_8))) {
+			String line;
+			while((line = reader.readLine()) != null) {
+				vigg.append(line).append('\n');
+			}
+		}catch(IOException ex) {
+			logger.error("Failed to read \"{}\"!");
+		}
+		String indexHTML = vigg.toString();
+		
+		Object mutex = new Object();
+		websocketServer = new FallbackWebViewWSD(LISTEN_ADDR, randomPort(), options);
+		websocketServer.setEaglerPacketSendCallback(callback);
+		synchronized(mutex) {
+			websocketServer.doStartup(mutex);
+			try {
+				mutex.wait(5000l);
+			} catch (InterruptedException e) {
+			}
+		}
+		if(!websocketServer.hasStarted) {
+			logger.error("Failed to start WebSocket in time!");
+			try {
+				websocketServer.stop(5000);
+			}catch(Throwable t) {
+			}
+			websocketServer = null;
+			throw new RuntimeException("Failed to start WebSocket server!");
+		}
+		InetSocketAddress addr = websocketServer.getAddress();
+		String wsAddr = "ws://" + addr.getHostString() + ":" + addr.getPort() + "/";
+		logger.info("Listening for WebSocket on {}", wsAddr);
+		indexHTML = indexHTML.replace("${client_websocket_uri}", wsAddr);
+		
+		JSONObject optsExport = new JSONObject();
+		IClientConfigAdapter cfgAdapter = PlatformRuntime.getClientConfigAdapter();
+		optsExport.put("forceWebViewSupport", cfgAdapter.isForceWebViewSupport());
+		optsExport.put("enableWebViewCSP", cfgAdapter.isEnableWebViewCSP());
+		indexHTML = indexHTML.replace("{eaglercraftXOpts}", optsExport.toString());
+		
+		httpServer = new FallbackWebViewHTTPD(LISTEN_ADDR, 0, indexHTML);
+		try {
+			httpServer.start(5000, true);
+		} catch (IOException e) {
+			logger.error("Failed to start NanoHTTPD!");
+			try {
+				websocketServer.stop(5000);
+			}catch(Throwable t) {
+			}
+			websocketServer = null;
+			httpServer = null;
+			throw new RuntimeException("Failed to start NanoHTTPD!", e);
+		}
+		int httpPort = httpServer.getListeningPort();
+		currentURL = "http://" + LISTEN_ADDR + ":" + httpPort + "/RTWebViewClient";
+		logger.info("Listening for HTTP on {}", currentURL);
+	}
+
+	private int randomPort() {
+		try(ServerSocket sockler = new ServerSocket(0)) {
+			return sockler.getLocalPort();
+		}catch(IOException ex) {
+			throw new RuntimeException("Failed to find random port to bind to!", ex);
+		}
+	}
+
+	public boolean isDead() {
+		return dead;
+	}
+
+	public String getURL() {
+		return !dead ? currentURL : null;
+	}
+
+	public void handleMessageFromServer(SPacketWebViewMessageV4EAG packet) {
+		if(packet.type == SPacketWebViewMessageV4EAG.TYPE_STRING) {
+			if(websocketServer != null) {
+				websocketServer.handleServerMessageStr(new String(packet.data, StandardCharsets.UTF_8));
+			}else {
+				logger.error("Recieved string message, but the webview server is not running!");
+			}
+		}else if(packet.type == SPacketWebViewMessageV4EAG.TYPE_BINARY) {
+			if(websocketServer != null) {
+				websocketServer.handleServerMessageBytes(packet.data);
+			}else {
+				logger.error("Recieved string message, but the webview server is not running!");
+			}
+		}else {
+			logger.error("Unknown server webview message type {}", packet.type);
+		}
+	}
+
+	public void setPacketSendCallback(IPacketSendCallback callback) {
+		this.callback = callback;
+		if(websocketServer != null) {
+			websocketServer.setEaglerPacketSendCallback(callback);
+		}
+	}
+
+	public void runTick() {
+		
+	}
+
+	public void killServer() {
+		if(!dead) {
+			dead = true;
+			if(websocketServer != null) {
+				try {
+					websocketServer.stop(10000);
+				} catch (Throwable th) {
+					logger.error("Failed to stop WebSocket server, aborting");
+					logger.error(th);
+				}
+				websocketServer = null;
+			}
+			if(httpServer != null) {
+				try {
+					httpServer.stop();
+				} catch (Throwable th) {
+					logger.error("Failed to stop HTTP server, aborting");
+					logger.error(th);
+				}
+				httpServer = null;
+			}
+		}
+	}
+
+}
diff --git a/sources/lwjgl/java/net/lax1dude/eaglercraft/v1_8/internal/lwjgl/FallbackWebViewWSD.java b/sources/lwjgl/java/net/lax1dude/eaglercraft/v1_8/internal/lwjgl/FallbackWebViewWSD.java
new file mode 100644
index 00000000..bb941103
--- /dev/null
+++ b/sources/lwjgl/java/net/lax1dude/eaglercraft/v1_8/internal/lwjgl/FallbackWebViewWSD.java
@@ -0,0 +1,273 @@
+package net.lax1dude.eaglercraft.v1_8.internal.lwjgl;
+
+import java.net.InetSocketAddress;
+import java.nio.ByteBuffer;
+
+import org.java_websocket.WebSocket;
+import org.java_websocket.handshake.ClientHandshake;
+import org.java_websocket.server.WebSocketServer;
+
+import net.lax1dude.eaglercraft.v1_8.internal.PlatformRuntime;
+import net.lax1dude.eaglercraft.v1_8.internal.WebViewOptions;
+import net.lax1dude.eaglercraft.v1_8.log4j.Logger;
+import net.lax1dude.eaglercraft.v1_8.socket.protocol.pkt.GameMessagePacket;
+import net.lax1dude.eaglercraft.v1_8.socket.protocol.pkt.client.CPacketWebViewMessageEnV4EAG;
+import net.lax1dude.eaglercraft.v1_8.socket.protocol.pkt.client.CPacketWebViewMessageV4EAG;
+import net.lax1dude.eaglercraft.v1_8.webview.PermissionsCache;
+import net.lax1dude.eaglercraft.v1_8.webview.PermissionsCache.Permission;
+import net.lax1dude.eaglercraft.v1_8.webview.WebViewOverlayController.IPacketSendCallback;
+
+import static net.lax1dude.eaglercraft.v1_8.internal.lwjgl.FallbackWebViewProtocol.*;
+
+/**
+ * Copyright (c) 2024 lax1dude. All Rights Reserved.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ * 
+ */
+class FallbackWebViewWSD extends WebSocketServer {
+
+	static final Logger logger = FallbackWebViewServer.logger;
+
+	private Object onStartNotify;
+
+	volatile boolean hasStarted = false;
+
+	private final Object webSockMutex = new Object();
+	volatile WebSocket webSocket = null;
+
+	volatile boolean hasHandshake = false;
+	volatile String currentChannelName = null;
+
+	private IPacketSendCallback callback = null;
+	WebViewOptions options;
+
+	private boolean enableCSP;
+	private boolean cspSupport;
+
+	FallbackWebViewWSD(String address, int port, WebViewOptions options) {
+		super(new InetSocketAddress(address, port), 1);
+		this.setTcpNoDelay(true);
+		this.setReuseAddr(true);
+		this.setConnectionLostTimeout(30);
+		this.options = options;
+		this.enableCSP = PlatformRuntime.getClientConfigAdapter().isEnableWebViewCSP();
+		this.cspSupport = true;
+	}
+
+	public void doStartup(Object onStartNotify) {
+		this.onStartNotify = onStartNotify;
+		this.start();
+	}
+
+	private void handleOpen() {
+		hasHandshake = false;
+		currentChannelName = null;
+	}
+
+	private void handleClose() {
+		if(currentChannelName != null && callback != null) {
+			callback.sendPacket(new CPacketWebViewMessageEnV4EAG(false, null));
+		}
+		currentChannelName = null;
+	}
+
+	private int hashPermissionFlags() {
+		int i = (options.scriptEnabled ? 1 : 0);
+		i |= ((enableCSP && cspSupport && options.strictCSPEnable) ? 0 : 2);
+		i |= (options.serverMessageAPIEnabled ? 4 : 0);
+		return i;
+	}
+
+	private void handleMessage(String str) {
+		WebSocket ws = webSocket;
+		FallbackWebViewPacket _packet = readPacket(str);
+		if(_packet != null) {
+			if(!hasHandshake) {
+				if(_packet instanceof CPacketClientHandshake) {
+					hasHandshake = true;
+					Permission perm = PermissionsCache.getJavaScriptAllowed(options.permissionsOriginUUID, hashPermissionFlags());
+					ws.send(writePacket(new SPacketServerHandshake(options, EnumWebViewJSPermission.fromPermission(perm))));
+				}else {
+					terminate("Unknown or unexpected packet: " + _packet.getClass().getSimpleName());
+				}
+			}else {
+				if(_packet instanceof CPacketWebViewChannelOpen) {
+					CPacketWebViewChannelOpen packet = (CPacketWebViewChannelOpen)_packet;
+					if(currentChannelName == null) {
+						currentChannelName = packet.messageChannel;
+						logger.info("[{}]: opened WebView channel \"{}\"", ws.getRemoteSocketAddress(), packet.messageChannel);
+						safeCallbackSend(new CPacketWebViewMessageEnV4EAG(true, packet.messageChannel));
+					}else {
+						terminate("Tried to open multiple channels");
+					}
+				}else if(_packet instanceof CPacketWebViewMessage) {
+					CPacketWebViewMessage packet = (CPacketWebViewMessage)_packet;
+					if(currentChannelName != null) {
+						safeCallbackSend(new CPacketWebViewMessageV4EAG(packet.messageContent));
+					}else {
+						terminate("Tried to send message without opening channel");
+					}
+				}else if(_packet instanceof CPacketWebViewChannelClose) {
+					if(currentChannelName != null) {
+						currentChannelName = null;
+						safeCallbackSend(new CPacketWebViewMessageEnV4EAG(false, null));
+					}else {
+						terminate("Tried to close missing channel");
+					}
+				}else if(_packet instanceof CPacketWebViewJSPermission) {
+					CPacketWebViewJSPermission packet = (CPacketWebViewJSPermission)_packet;
+					switch(packet.permission) {
+					case NOT_SET:
+						PermissionsCache.clearJavaScriptAllowed(options.permissionsOriginUUID);
+						break;
+					case ALLOW:
+						PermissionsCache.setJavaScriptAllowed(options.permissionsOriginUUID, hashPermissionFlags(), true);
+						break;
+					case BLOCK:
+						PermissionsCache.setJavaScriptAllowed(options.permissionsOriginUUID, hashPermissionFlags(), false);
+						break;
+					default:
+						terminate("Unknown permission state selected!");
+						break;
+					}
+					
+				}else {
+					terminate("Unknown or unexpected packet: " + _packet.getClass().getSimpleName());
+				}
+			}
+		}else {
+			terminate("Invalid packet recieved");
+		}
+	}
+
+	private void handleMessage(ByteBuffer buffer) {
+		if(currentChannelName != null) {
+			safeCallbackSend(new CPacketWebViewMessageV4EAG(buffer.array()));
+		}else {
+			terminate("Sent binary webview message while channel was closed");
+		}
+	}
+
+	private void terminate(String msg) {
+		if(webSocket != null) {
+			logger.error("[{}]: Terminating connection, reason: \"{}\"", webSocket.getRemoteSocketAddress(), msg);
+			webSocket.send(writePacket(new SPacketServerError(msg)));
+			webSocket.close();
+		}
+	}
+
+	private void safeCallbackSend(GameMessagePacket packet) {
+		if(callback != null) {
+			callback.sendPacket(packet);
+		}else {
+			logger.error("webview sent packet to server, but there's no callback registered to send packets!");
+		}
+	}
+
+	void handleServerMessageStr(String msg) {
+		if(webSocket != null) {
+			if(currentChannelName != null) {
+				webSocket.send(writePacket(new SPacketWebViewMessage(msg)));
+			}else {
+				logger.error("Recieved string message from server, but the channel is not open!");
+			}
+		}else {
+			logger.error("Recieved string message from server, but there is no active websocket!");
+		}
+	}
+
+	void handleServerMessageBytes(byte[] msg) {
+		if(webSocket != null) {
+			if(currentChannelName != null) {
+				webSocket.send(msg);
+			}else {
+				logger.error("Recieved binary message from server, but the channel is not open!");
+			}
+		}else {
+			logger.error("Recieved binary message from server, but there is no active websocket!");
+		}
+	}
+
+	@Override
+	public void onStart() {
+		hasStarted = true;
+		if(onStartNotify != null) {
+			synchronized(onStartNotify) {
+				onStartNotify.notifyAll();
+			}
+			onStartNotify = null;
+		}else {
+			logger.warn("No mutex to notify!");
+		}
+	}
+
+	@Override
+	public void onOpen(WebSocket arg0, ClientHandshake arg1) {
+		boolean result;
+		synchronized(webSockMutex) {
+			if(webSocket == null) {
+				webSocket = arg0;
+				result = true;
+			}else {
+				result = false;
+			}
+		}
+		if(result) {
+			logger.info("[{}]: WebSocket connection opened", arg0.getRemoteSocketAddress());
+			handleOpen();
+		}else {
+			logger.error("[{}]: Rejecting duplicate connection", arg0.getRemoteSocketAddress());
+			arg0.send(writePacket(new SPacketServerError("You already have a tab open!")));
+			arg0.close();
+		}
+	}
+
+	@Override
+	public void onMessage(WebSocket arg0, String arg1) {
+		if(arg0 == webSocket) {
+			handleMessage(arg1);
+		}
+	}
+
+	@Override
+	public void onMessage(WebSocket arg0, ByteBuffer arg1) {
+		if(arg0 == webSocket) {
+			handleMessage(arg1);
+		}
+	}
+
+	@Override
+	public void onClose(WebSocket arg0, int arg1, String arg2, boolean arg3) {
+		synchronized(webSockMutex) {
+			if(arg0 == webSocket) {
+				logger.info("[{}]: WebSocket connection closed", arg0.getRemoteSocketAddress());
+				try {
+					handleClose();
+				}finally {
+					webSocket = null;
+				}
+			}
+		}
+	}
+
+	@Override
+	public void onError(WebSocket arg0, Exception arg1) {
+		logger.error("[{}]: WebSocket caught exception", arg0 != null ? arg0.getRemoteSocketAddress() : "null");
+		logger.error(arg1);
+	}
+
+	public void setEaglerPacketSendCallback(IPacketSendCallback callback) {
+		this.callback = callback;
+	}
+
+}
diff --git a/sources/lwjgl/java/net/lax1dude/eaglercraft/v1_8/internal/lwjgl/JDBCFilesystem.java b/sources/lwjgl/java/net/lax1dude/eaglercraft/v1_8/internal/lwjgl/JDBCFilesystem.java
index c6aae923..34d5c71a 100644
--- a/sources/lwjgl/java/net/lax1dude/eaglercraft/v1_8/internal/lwjgl/JDBCFilesystem.java
+++ b/sources/lwjgl/java/net/lax1dude/eaglercraft/v1_8/internal/lwjgl/JDBCFilesystem.java
@@ -13,8 +13,8 @@ import java.util.LinkedList;
 import java.util.Map.Entry;
 import java.util.Properties;
 
-import net.lax1dude.eaglercraft.v1_8.internal.PlatformFilesystem.IFilesystemProvider;
 import net.lax1dude.eaglercraft.v1_8.internal.PlatformRuntime;
+import net.lax1dude.eaglercraft.v1_8.internal.IEaglerFilesystem;
 import net.lax1dude.eaglercraft.v1_8.internal.PlatformFilesystem;
 import net.lax1dude.eaglercraft.v1_8.internal.VFSFilenameIterator;
 import net.lax1dude.eaglercraft.v1_8.internal.buffer.ByteBuffer;
@@ -38,15 +38,16 @@ import net.lax1dude.eaglercraft.v1_8.log4j.Logger;
  * POSSIBILITY OF SUCH DAMAGE.
  * 
  */
-public class JDBCFilesystem implements IFilesystemProvider {
+public class JDBCFilesystem implements IEaglerFilesystem {
 
 	public static final Logger logger = LogManager.getLogger("JDBCFilesystem");
 
 	private boolean newFilesystem = true;
 
 	private static volatile boolean cleanupThreadStarted = false;
-	private static final Collection<JDBCFilesystem> jdbcFilesystems = new LinkedList();
+	private static final Collection<JDBCFilesystem> jdbcFilesystems = new LinkedList<>();
 
+	private final String dbName;
 	private final String jdbcUri;
 	private final String jdbcDriver;
 
@@ -64,8 +65,8 @@ public class JDBCFilesystem implements IFilesystemProvider {
 
 	private final Object mutex = new Object();
 
-	public static IFilesystemProvider initialize(String jdbcUri, String jdbcDriver) {
-		Class driver;
+	public static IEaglerFilesystem initialize(String dbName, String jdbcUri, String jdbcDriver) {
+		Class<?> driver;
 		try {
 			driver = Class.forName(jdbcDriver);
 		} catch (ClassNotFoundException e) {
@@ -87,8 +88,8 @@ public class JDBCFilesystem implements IFilesystemProvider {
 		for(Entry<Object, Object> etr : System.getProperties().entrySet()) {
 			if(etr.getKey() instanceof String) {
 				String str = (String)etr.getKey();
-				if(str.startsWith("eagler.jdbc.opts.")) {
-					props.put(str.substring(17), etr.getValue());
+				if(str.startsWith("eagler.jdbc." + dbName + ".opts.")) {
+					props.put(str.substring(18 + dbName.length()), etr.getValue());
 				}
 			}
 		}
@@ -104,7 +105,7 @@ public class JDBCFilesystem implements IFilesystemProvider {
 			throw new EaglerFileSystemException("Failed to connect to database: \"" + jdbcUri + "\"", ex);
 		}
 		try {
-			return new JDBCFilesystem(conn, jdbcUri, jdbcDriver);
+			return new JDBCFilesystem(dbName, conn, jdbcUri, jdbcDriver);
 		} catch (SQLException ex) {
 			try {
 				conn.close();
@@ -114,7 +115,8 @@ public class JDBCFilesystem implements IFilesystemProvider {
 		}
 	}
 
-	private JDBCFilesystem(Connection conn, String jdbcUri, String jdbcDriver) throws SQLException {
+	private JDBCFilesystem(String dbName, Connection conn, String jdbcUri, String jdbcDriver) throws SQLException {
+		this.dbName = dbName;
 		this.conn = conn;
 		this.jdbcUri = jdbcUri;
 		this.jdbcDriver = jdbcDriver;
@@ -152,6 +154,16 @@ public class JDBCFilesystem implements IFilesystemProvider {
 		}
 	}
 
+	@Override
+	public String getFilesystemName() {
+		return dbName;
+	}
+
+	@Override
+	public String getInternalDBName() {
+		return "desktopruntime:" + jdbcUri;
+	}
+
 	public boolean isNewFilesystem() {
 		return newFilesystem;
 	}
@@ -172,7 +184,8 @@ public class JDBCFilesystem implements IFilesystemProvider {
 		}
 	}
 
-	public void shutdown() {
+	@Override
+	public void closeHandle() {
 		shutdown0();
 		synchronized(jdbcFilesystems) {
 			jdbcFilesystems.remove(this);
@@ -438,4 +451,9 @@ public class JDBCFilesystem implements IFilesystemProvider {
 		}
 	}
 
+	@Override
+	public boolean isRamdisk() {
+		return false;
+	}
+
 }
diff --git a/sources/lwjgl/java/net/lax1dude/eaglercraft/v1_8/internal/lwjgl/JDBCFilesystemConverter.java b/sources/lwjgl/java/net/lax1dude/eaglercraft/v1_8/internal/lwjgl/JDBCFilesystemConverter.java
index 62d19b2d..eef8d922 100644
--- a/sources/lwjgl/java/net/lax1dude/eaglercraft/v1_8/internal/lwjgl/JDBCFilesystemConverter.java
+++ b/sources/lwjgl/java/net/lax1dude/eaglercraft/v1_8/internal/lwjgl/JDBCFilesystemConverter.java
@@ -7,7 +7,7 @@ import java.io.InputStream;
 import java.util.ArrayList;
 import java.util.List;
 
-import net.lax1dude.eaglercraft.v1_8.internal.PlatformFilesystem.IFilesystemProvider;
+import net.lax1dude.eaglercraft.v1_8.internal.IEaglerFilesystem;
 import net.lax1dude.eaglercraft.v1_8.internal.PlatformRuntime;
 import net.lax1dude.eaglercraft.v1_8.internal.buffer.ByteBuffer;
 import net.lax1dude.eaglercraft.v1_8.internal.vfs2.EaglerFileSystemException;
@@ -33,7 +33,7 @@ public class JDBCFilesystemConverter {
 
 	private static final Logger logger = LogManager.getLogger("JDBCFilesystemConverter");
 
-	public static void convertFilesystem(String title, File oldFS, IFilesystemProvider newFS, boolean deleteOld) {
+	public static void convertFilesystem(String title, File oldFS, IEaglerFilesystem newFS, boolean deleteOld) {
 		FilesystemConvertingDialog progressDialog = new FilesystemConvertingDialog(title);
 		try {
 			progressDialog.setProgressIndeterminate(true);
@@ -41,7 +41,7 @@ public class JDBCFilesystemConverter {
 			progressDialog.setVisible(true);
 			
 			String slug = oldFS.getAbsolutePath();
-			List<String> filesToCopy = new ArrayList();
+			List<String> filesToCopy = new ArrayList<>();
 			logger.info("Discovering files to convert...");
 			iterateFolder(slug.length(), oldFS, filesToCopy);
 			logger.info("Found {} files in the old directory", filesToCopy.size());
diff --git a/sources/lwjgl/java/net/lax1dude/eaglercraft/v1_8/internal/lwjgl/LWJGLEntryPoint.java b/sources/lwjgl/java/net/lax1dude/eaglercraft/v1_8/internal/lwjgl/LWJGLEntryPoint.java
index 849e836c..23b13589 100644
--- a/sources/lwjgl/java/net/lax1dude/eaglercraft/v1_8/internal/lwjgl/LWJGLEntryPoint.java
+++ b/sources/lwjgl/java/net/lax1dude/eaglercraft/v1_8/internal/lwjgl/LWJGLEntryPoint.java
@@ -6,7 +6,6 @@ import javax.swing.UnsupportedLookAndFeelException;
 import net.lax1dude.eaglercraft.v1_8.EagRuntime;
 import net.lax1dude.eaglercraft.v1_8.EagUtils;
 import net.lax1dude.eaglercraft.v1_8.internal.EnumPlatformANGLE;
-import net.lax1dude.eaglercraft.v1_8.internal.PlatformFilesystem;
 import net.lax1dude.eaglercraft.v1_8.internal.PlatformInput;
 import net.lax1dude.eaglercraft.v1_8.internal.PlatformRuntime;
 import net.lax1dude.eaglercraft.v1_8.opengl.ext.deferred.program.ShaderSource;
@@ -82,11 +81,12 @@ public class LWJGLEntryPoint {
 				PlatformInput.setStartupFullscreen(true);
 			}else if(args[i].equalsIgnoreCase("highp")) {
 				ShaderSource.setHighP(true);
-			}else if(args[i].startsWith("jdbc:")) {
-				if(i < args.length - 1) {
-					PlatformFilesystem.setUseJDBC(args[i]);
-					PlatformFilesystem.setJDBCDriverClass(args[++i]);
-				}
+			}else if(args[i].equalsIgnoreCase("gles=200")) {
+				PlatformRuntime.requestGL(200);
+			}else if(args[i].equalsIgnoreCase("gles=300")) {
+				PlatformRuntime.requestGL(300);
+			}else if(args[i].equalsIgnoreCase("gles=310")) {
+				PlatformRuntime.requestGL(310);
 			}else {
 				EnumPlatformANGLE angle = EnumPlatformANGLE.fromId(args[i]);
 				if(angle != EnumPlatformANGLE.DEFAULT) {
diff --git a/sources/lwjgl/java/net/lax1dude/eaglercraft/v1_8/internal/WebSocketPlayClient.java b/sources/lwjgl/java/net/lax1dude/eaglercraft/v1_8/internal/lwjgl/WebSocketClientImpl.java
similarity index 57%
rename from sources/lwjgl/java/net/lax1dude/eaglercraft/v1_8/internal/WebSocketPlayClient.java
rename to sources/lwjgl/java/net/lax1dude/eaglercraft/v1_8/internal/lwjgl/WebSocketClientImpl.java
index 0e201823..feed7751 100644
--- a/sources/lwjgl/java/net/lax1dude/eaglercraft/v1_8/internal/WebSocketPlayClient.java
+++ b/sources/lwjgl/java/net/lax1dude/eaglercraft/v1_8/internal/lwjgl/WebSocketClientImpl.java
@@ -1,4 +1,4 @@
-package net.lax1dude.eaglercraft.v1_8.internal;
+package net.lax1dude.eaglercraft.v1_8.internal.lwjgl;
 
 import java.net.URI;
 import java.nio.ByteBuffer;
@@ -9,11 +9,10 @@ import org.java_websocket.drafts.Draft_6455;
 import org.java_websocket.extensions.permessage_deflate.PerMessageDeflateExtension;
 import org.java_websocket.handshake.ServerHandshake;
 
-import net.lax1dude.eaglercraft.v1_8.log4j.LogManager;
-import net.lax1dude.eaglercraft.v1_8.log4j.Logger;
+import net.lax1dude.eaglercraft.v1_8.internal.EnumEaglerConnectionState;
 
 /**
- * Copyright (c) 2022-2023 lax1dude, ayunami2000. All Rights Reserved.
+ * Copyright (c) 2024 lax1dude. All Rights Reserved.
  * 
  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
@@ -27,51 +26,54 @@ import net.lax1dude.eaglercraft.v1_8.log4j.Logger;
  * POSSIBILITY OF SUCH DAMAGE.
  * 
  */
-class WebSocketPlayClient extends WebSocketClient {
+class WebSocketClientImpl extends WebSocketClient {
 
 	private static final Draft perMessageDeflateDraft = new Draft_6455(new PerMessageDeflateExtension());
 	
-	public static final Logger logger = LogManager.getLogger("WebSocket");
+	protected final DesktopWebSocketClient clientObj;
 
-	WebSocketPlayClient(URI serverUri) {
+	WebSocketClientImpl(DesktopWebSocketClient clientObj, URI serverUri) {
 		super(serverUri, perMessageDeflateDraft);
+		this.clientObj = clientObj;
 		this.setConnectionLostTimeout(15);
 		this.setTcpNoDelay(true);
+		this.connect();
 	}
 
 	@Override
 	public void onOpen(ServerHandshake arg0) {
-		PlatformNetworking.playConnectState = EnumEaglerConnectionState.CONNECTED;
-		PlatformNetworking.serverRateLimit = EnumServerRateLimit.OK;
-		logger.info("Connection opened: {}", this.uri.toString());
-	}
-
-	@Override
-	public void onClose(int arg0, String arg1, boolean arg2) {
-		logger.info("Connection closed: {}", this.uri.toString());
-	}
-
-	@Override
-	public void onError(Exception arg0) {
-		logger.error("Exception thrown by websocket \"" + this.getURI().toString() + "\"!");
-		logger.error(arg0);
-		PlatformNetworking.playConnectState = EnumEaglerConnectionState.FAILED;
-	}
-
-	@Override
-	public void onMessage(String arg0) {
-		if(arg0.equalsIgnoreCase("BLOCKED")) {
-			logger.error("Reached full IP ratelimit!");
-			PlatformNetworking.serverRateLimit = EnumServerRateLimit.BLOCKED;
-		}else if(arg0.equalsIgnoreCase("LOCKED")) {
-			logger.error("Reached full IP ratelimit lockout!");
-			PlatformNetworking.serverRateLimit = EnumServerRateLimit.LOCKED_OUT;
+		clientObj.playConnectState = EnumEaglerConnectionState.CONNECTED;
+		DesktopWebSocketClient.logger.info("Connection opened: {}", this.uri.toString());
+		synchronized(clientObj.connectOpenMutex) {
+			clientObj.connectOpenMutex.notifyAll();
 		}
 	}
 
 	@Override
-	public void onMessage(ByteBuffer arg0) {
-		PlatformNetworking.recievedPlayPacket(arg0.array());
+	public void onClose(int arg0, String arg1, boolean arg2) {
+		DesktopWebSocketClient.logger.info("Connection closed: {}", this.uri.toString());
+		if(clientObj.playConnectState != EnumEaglerConnectionState.FAILED) {
+			clientObj.playConnectState = EnumEaglerConnectionState.CLOSED;
+		}
 	}
-	
+
+	@Override
+	public void onError(Exception arg0) {
+		DesktopWebSocketClient.logger.error("Exception thrown by websocket \"" + this.getURI().toString() + "\"!");
+		DesktopWebSocketClient.logger.error(arg0);
+		if(clientObj.playConnectState == EnumEaglerConnectionState.CONNECTING) {
+			clientObj.playConnectState = EnumEaglerConnectionState.FAILED;
+		}
+	}
+
+	@Override
+	public void onMessage(String arg0) {
+		clientObj.handleString(arg0);
+	}
+
+	@Override
+	public void onMessage(ByteBuffer arg0) {
+		clientObj.handleBytes(arg0.array());
+	}
+
 }
diff --git a/sources/lwjgl/java/net/lax1dude/eaglercraft/v1_8/sp/internal/ClientPlatformSingleplayer.java b/sources/lwjgl/java/net/lax1dude/eaglercraft/v1_8/sp/internal/ClientPlatformSingleplayer.java
index 380acb53..8981e803 100644
--- a/sources/lwjgl/java/net/lax1dude/eaglercraft/v1_8/sp/internal/ClientPlatformSingleplayer.java
+++ b/sources/lwjgl/java/net/lax1dude/eaglercraft/v1_8/sp/internal/ClientPlatformSingleplayer.java
@@ -28,7 +28,7 @@ public class ClientPlatformSingleplayer {
 
 	private static CrashScreenPopup crashOverlay = null;
 
-	public static void startIntegratedServer() {
+	public static void startIntegratedServer(boolean forceSingleThread) {
 		DesktopIntegratedServer.startIntegratedServer();
 	}
 
@@ -52,7 +52,7 @@ public class ClientPlatformSingleplayer {
 			if(MemoryConnection.serverToClientQueue.size() == 0) {
 				return null;
 			}else {
-				List<IPCPacketData> ret = new ArrayList(MemoryConnection.serverToClientQueue);
+				List<IPCPacketData> ret = new ArrayList<>(MemoryConnection.serverToClientQueue);
 				MemoryConnection.serverToClientQueue.clear();
 				return ret;
 			}
@@ -71,6 +71,14 @@ public class ClientPlatformSingleplayer {
 		return false;
 	}
 
+	public static boolean isSingleThreadModeSupported() {
+		return false;
+	}
+
+	public static void updateSingleThreadMode() {
+		
+	}
+
 	public static void showCrashReportOverlay(String report, int x, int y, int w, int h) {
 		if(crashOverlay == null) {
 			crashOverlay = new CrashScreenPopup();
diff --git a/sources/lwjgl/java/net/lax1dude/eaglercraft/v1_8/sp/server/internal/ServerPlatformSingleplayer.java b/sources/lwjgl/java/net/lax1dude/eaglercraft/v1_8/sp/server/internal/ServerPlatformSingleplayer.java
index 5c6af429..f1a54681 100644
--- a/sources/lwjgl/java/net/lax1dude/eaglercraft/v1_8/sp/server/internal/ServerPlatformSingleplayer.java
+++ b/sources/lwjgl/java/net/lax1dude/eaglercraft/v1_8/sp/server/internal/ServerPlatformSingleplayer.java
@@ -2,10 +2,12 @@ package net.lax1dude.eaglercraft.v1_8.sp.server.internal;
 
 import java.util.ArrayList;
 import java.util.List;
+import java.util.function.Consumer;
 
+import net.lax1dude.eaglercraft.v1_8.Filesystem;
 import net.lax1dude.eaglercraft.v1_8.internal.IClientConfigAdapter;
+import net.lax1dude.eaglercraft.v1_8.internal.IEaglerFilesystem;
 import net.lax1dude.eaglercraft.v1_8.internal.IPCPacketData;
-import net.lax1dude.eaglercraft.v1_8.internal.PlatformFilesystem;
 import net.lax1dude.eaglercraft.v1_8.internal.lwjgl.DesktopClientConfigAdapter;
 import net.lax1dude.eaglercraft.v1_8.sp.server.internal.lwjgl.MemoryConnection;
 
@@ -26,8 +28,20 @@ import net.lax1dude.eaglercraft.v1_8.sp.server.internal.lwjgl.MemoryConnection;
  */
 public class ServerPlatformSingleplayer {
 
+	private static IEaglerFilesystem filesystem = null;
+
 	public static void initializeContext() {
-		PlatformFilesystem.initialize();
+		if(filesystem == null) {
+			filesystem = Filesystem.getHandleFor(getClientConfigAdapter().getWorldsDB());
+		}
+	}
+
+	public static void initializeContextSingleThread(Consumer<IPCPacketData> packetSendCallback) {
+		throw new UnsupportedOperationException();
+	}
+
+	public static IEaglerFilesystem getWorldsDatabase() {
+		return filesystem;
 	}
 
 	public static void sendPacket(IPCPacketData packet) {
@@ -50,7 +64,7 @@ public class ServerPlatformSingleplayer {
 			if(MemoryConnection.clientToServerQueue.size() == 0) {
 				return null;
 			}else {
-				List<IPCPacketData> ret = new ArrayList(MemoryConnection.clientToServerQueue);
+				List<IPCPacketData> ret = new ArrayList<>(MemoryConnection.clientToServerQueue);
 				MemoryConnection.clientToServerQueue.clear();
 				return ret;
 			}
@@ -60,4 +74,17 @@ public class ServerPlatformSingleplayer {
 	public static IClientConfigAdapter getClientConfigAdapter() {
 		return DesktopClientConfigAdapter.instance;
 	}
+
+	public static void immediateContinue() {
+		
+	}
+
+	public static void platformShutdown() {
+		filesystem = null;
+	}
+
+	public static boolean isSingleThreadMode() {
+		return false;
+	}
+
 }
diff --git a/sources/lwjgl/java/net/lax1dude/eaglercraft/v1_8/sp/server/internal/lwjgl/MemoryConnection.java b/sources/lwjgl/java/net/lax1dude/eaglercraft/v1_8/sp/server/internal/lwjgl/MemoryConnection.java
index 3398d3d0..e77091c9 100644
--- a/sources/lwjgl/java/net/lax1dude/eaglercraft/v1_8/sp/server/internal/lwjgl/MemoryConnection.java
+++ b/sources/lwjgl/java/net/lax1dude/eaglercraft/v1_8/sp/server/internal/lwjgl/MemoryConnection.java
@@ -22,7 +22,7 @@ import net.lax1dude.eaglercraft.v1_8.internal.IPCPacketData;
  */
 public class MemoryConnection {
 
-	public static final List<IPCPacketData> clientToServerQueue = new LinkedList();
-	public static final List<IPCPacketData> serverToClientQueue = new LinkedList();
+	public static final List<IPCPacketData> clientToServerQueue = new LinkedList<>();
+	public static final List<IPCPacketData> serverToClientQueue = new LinkedList<>();
 
 }
diff --git a/sources/main/java/com/google/common/base/CharMatcher.java b/sources/main/java/com/google/common/base/CharMatcher.java
index e84449d4..97f9b3a4 100644
--- a/sources/main/java/com/google/common/base/CharMatcher.java
+++ b/sources/main/java/com/google/common/base/CharMatcher.java
@@ -140,9 +140,9 @@ public abstract class CharMatcher implements Predicate<Character> {
 	}
 
 	// Must be in ascending order.
-	private static final String ZEROES = "0\u0660\u06f0\u07c0\u0966\u09e6\u0a66\u0ae6\u0b66\u0be6"
-			+ "\u0c66\u0ce6\u0d66\u0e50\u0ed0\u0f20\u1040\u1090\u17e0\u1810\u1946\u19d0\u1b50\u1bb0"
-			+ "\u1c40\u1c50\ua620\ua8d0\ua900\uaa50\uff10";
+	private static final String ZEROES = new String(new char[] { '0', 0x0660, 0x06f0, 0x07c0, 0x0966, 0x09e6, 0x0a66,
+			0x0ae6, 0x0b66, 0x0be6, 0x0c66, 0x0ce6, 0x0d66, 0x0e50, 0x0ed0, 0x0f20, 0x1040, 0x1090, 0x17e0, 0x1810,
+			0x1946, 0x19d0, 0x1b50, 0x1bb0, 0x1c40, 0x1c50, 0xa620, 0xa8d0, 0xa900, 0xaa50, 0xff10 });
 
 	private static final String NINES;
 	static {
@@ -234,10 +234,10 @@ public abstract class CharMatcher implements Predicate<Character> {
 	 * FORMAT, SURROGATE, and PRIVATE_USE according to ICU4J.
 	 */
 	public static final CharMatcher INVISIBLE = new RangesMatcher("CharMatcher.INVISIBLE",
-			("\u0000\u007f\u00ad\u0600\u061c\u06dd\u070f\u1680\u180e\u2000\u2028\u205f\u2066\u2067\u2068"
-					+ "\u2069\u206a\u3000\ud800\ufeff\ufff9\ufffa").toCharArray(),
-			("\u0020\u00a0\u00ad\u0604\u061c\u06dd\u070f\u1680\u180e\u200f\u202f\u2064\u2066\u2067\u2068"
-					+ "\u2069\u206f\u3000\uf8ff\ufeff\ufff9\ufffb").toCharArray());
+			new char[] { 0x0000, 0x007f, 0x00ad, 0x0600, 0x061c, 0x06dd, 0x070f, 0x1680, 0x180e, 0x2000, 0x2028, 0x205f,
+					0x2066, 0x2067, 0x2068, 0x2069, 0x206a, 0x3000, 0xd800, 0xfeff, 0xfff9, 0xfffa },
+			new char[] { 0x0020, 0x00a0, 0x00ad, 0x0604, 0x061c, 0x06dd, 0x070f, 0x1680, 0x180e, 0x200f, 0x202f, 0x2064,
+					0x2066, 0x2067, 0x2068, 0x2069, 0x206f, 0x3000, 0xf8ff, 0xfeff, 0xfff9, 0xfffb });
 
 	private static String showCharacter(char c) {
 		String hex = "0123456789ABCDEF";
@@ -260,8 +260,8 @@ public abstract class CharMatcher implements Predicate<Character> {
 	 * keep it up to date.
 	 */
 	public static final CharMatcher SINGLE_WIDTH = new RangesMatcher("CharMatcher.SINGLE_WIDTH",
-			"\u0000\u05be\u05d0\u05f3\u0600\u0750\u0e00\u1e00\u2100\ufb50\ufe70\uff61".toCharArray(),
-			"\u04f9\u05be\u05ea\u05f4\u06ff\u077f\u0e7f\u20af\u213a\ufdff\ufeff\uffdc".toCharArray());
+			new char[] { 0x0000, 0x05be, 0x05d0, 0x05f3, 0x0600, 0x0750, 0x0e00, 0x1e00, 0x2100, 0xfb50, 0xfe70, 0xff61 },
+			new char[] { 0x04f9, 0x05be, 0x05ea, 0x05f4, 0x06ff, 0x077f, 0x0e7f, 0x20af, 0x213a, 0xfdff, 0xfeff, 0xffdc });
 
 	/** Matches any character. */
 	public static final CharMatcher ANY = new FastMatcher("CharMatcher.ANY") {
@@ -1474,9 +1474,9 @@ public abstract class CharMatcher implements Predicate<Character> {
 		return description;
 	}
 
-	static final String WHITESPACE_TABLE = "" + "\u2002\u3000\r\u0085\u200A\u2005\u2000\u3000"
-			+ "\u2029\u000B\u3000\u2008\u2003\u205F\u3000\u1680" + "\u0009\u0020\u2006\u2001\u202F\u00A0\u000C\u2009"
-			+ "\u3000\u2004\u3000\u3000\u2028\n\u2007\u3000";
+	static final String WHITESPACE_TABLE = new String(new char[] { 0x2002, 0x3000, '\r', 0x0085, 0x200A, 0x2005, 0x2000,
+			0x3000, 0x2029, 0x000B, 0x3000, 0x2008, 0x2003, 0x205F, 0x3000, 0x1680, 0x0009, 0x0020, 0x2006, 0x2001,
+			0x202F, 0x00A0, 0x000C, 0x2009, 0x3000, 0x2004, 0x3000, 0x3000, 0x2028, '\n', 0x2007, 0x3000 });
 	static final int WHITESPACE_MULTIPLIER = 1682554634;
 	static final int WHITESPACE_SHIFT = Integer.numberOfLeadingZeros(WHITESPACE_TABLE.length() - 1);
 
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/Base64.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/Base64.java
index 7fcf7cf1..177b54ee 100644
--- a/sources/main/java/net/lax1dude/eaglercraft/v1_8/Base64.java
+++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/Base64.java
@@ -116,6 +116,14 @@ public class Base64 extends BaseNCodec {
 			41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51 // 70-7a p-z
 	};
 
+	public static int lookupCharInt(char c) {
+		return c < 123 ? DECODE_TABLE[c] : -1;
+	}
+
+	public static char lookupIntChar(int i) {
+		return (char)STANDARD_ENCODE_TABLE[i];
+	}
+
 	/**
 	 * Base64 uses 6-bit fields.
 	 */
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/ClientUUIDLoadingCache.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/ClientUUIDLoadingCache.java
new file mode 100644
index 00000000..aa60cda4
--- /dev/null
+++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/ClientUUIDLoadingCache.java
@@ -0,0 +1,152 @@
+package net.lax1dude.eaglercraft.v1_8;
+
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+
+import net.lax1dude.eaglercraft.v1_8.log4j.LogManager;
+import net.lax1dude.eaglercraft.v1_8.log4j.Logger;
+import net.lax1dude.eaglercraft.v1_8.socket.protocol.pkt.client.CPacketGetOtherClientUUIDV4EAG;
+import net.minecraft.client.Minecraft;
+import net.minecraft.client.entity.AbstractClientPlayer;
+import net.minecraft.entity.player.EntityPlayer;
+import net.minecraft.entity.player.EntityPlayerMP;
+
+/**
+ * Copyright (c) 2024 lax1dude. All Rights Reserved.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ * 
+ */
+public class ClientUUIDLoadingCache {
+
+	private static final Logger logger = LogManager.getLogger("ClientUUIDLoadingCache");
+
+	public static final EaglercraftUUID NULL_UUID = new EaglercraftUUID(0l, 0l);
+	public static final EaglercraftUUID PENDING_UUID = new EaglercraftUUID(0x6969696969696969l, 0x6969696969696969l);
+	public static final EaglercraftUUID VANILLA_UUID = new EaglercraftUUID(0x1DCE015CD384374El, 0x85030A4DE95E5736l);
+
+	/**
+	 * For client devs, allows you to get EaglercraftVersion.clientBrandUUID of
+	 * other players on a server, to detect other players who also use your client.
+	 * 
+	 * Requires EaglerXBungee 1.3.0 or EaglerXVelocity 1.1.0
+	 * 
+	 * @return NULL_UUID if not found, PENDING_UUID if pending,
+	 *         VANILLA_UUID if vanilla, or the remote player's
+	 *         client's EaglercraftVersion.clientBrandUUID
+	 */
+	public static EaglercraftUUID getPlayerClientBrandUUID(EntityPlayer player) {
+		EaglercraftUUID ret = null;
+		if(player instanceof AbstractClientPlayer) {
+			ret = ((AbstractClientPlayer)player).clientBrandUUIDCache;
+			if(ret == null) {
+				Minecraft mc = Minecraft.getMinecraft();
+				if(mc != null && mc.thePlayer != null && mc.thePlayer.sendQueue.getEaglerMessageProtocol().ver >= 4) {
+					ret = PENDING_UUID;
+					EaglercraftUUID playerUUID = player.getUniqueID();
+					if(!waitingUUIDs.containsKey(playerUUID) && !evictedUUIDs.containsKey(playerUUID)) {
+						int reqID = ++requestId & 0x3FFF;
+						WaitingLookup newLookup = new WaitingLookup(reqID, playerUUID, EagRuntime.steadyTimeMillis(),
+								(AbstractClientPlayer) player);
+						waitingIDs.put(reqID, newLookup);
+						waitingUUIDs.put(playerUUID, newLookup);
+						mc.thePlayer.sendQueue.sendEaglerMessage(
+								new CPacketGetOtherClientUUIDV4EAG(reqID, newLookup.uuid.msb, newLookup.uuid.lsb));
+					}
+				}
+			}
+		}else if(player instanceof EntityPlayerMP) {
+			ret = ((EntityPlayerMP)player).clientBrandUUID;
+		}
+		if(ret == null) {
+			ret = NULL_UUID;
+		}
+		return ret;
+	}
+
+	private static final Map<Integer,WaitingLookup> waitingIDs = new HashMap<>();
+	private static final Map<EaglercraftUUID,WaitingLookup> waitingUUIDs = new HashMap<>();
+	private static final Map<EaglercraftUUID,Long> evictedUUIDs = new HashMap<>();
+
+	private static int requestId = 0;
+	private static long lastFlushReq = EagRuntime.steadyTimeMillis();
+	private static long lastFlushEvict = EagRuntime.steadyTimeMillis();
+
+	public static void update() {
+		long timestamp = EagRuntime.steadyTimeMillis();
+		if(timestamp - lastFlushReq > 5000l) {
+			lastFlushReq = timestamp;
+			if(!waitingIDs.isEmpty()) {
+				Iterator<WaitingLookup> itr = waitingIDs.values().iterator();
+				while(itr.hasNext()) {
+					WaitingLookup lookup = itr.next();
+					if(timestamp - lookup.timestamp > 15000l) {
+						itr.remove();
+						waitingUUIDs.remove(lookup.uuid);
+					}
+				}
+			}
+		}
+		if(timestamp - lastFlushEvict > 1000l) {
+			lastFlushEvict = timestamp;
+			if(!evictedUUIDs.isEmpty()) {
+				Iterator<Long> evictItr = evictedUUIDs.values().iterator();
+				while(evictItr.hasNext()) {
+					if(timestamp - evictItr.next().longValue() > 3000l) {
+						evictItr.remove();
+					}
+				}
+			}
+		}
+	}
+
+	public static void flushRequestCache() {
+		waitingIDs.clear();
+		waitingUUIDs.clear();
+		evictedUUIDs.clear();
+	}
+
+	public static void handleResponse(int requestId, EaglercraftUUID clientId) {
+		WaitingLookup lookup = waitingIDs.remove(requestId);
+		if(lookup != null) {
+			lookup.player.clientBrandUUIDCache = clientId;
+			waitingUUIDs.remove(lookup.uuid);
+		}else {
+			logger.warn("Unsolicited client brand UUID lookup response #{} recieved! (Brand UUID: {})", requestId, clientId);
+		}
+	}
+
+	public static void evict(EaglercraftUUID clientId) {
+		evictedUUIDs.put(clientId, Long.valueOf(EagRuntime.steadyTimeMillis()));
+		WaitingLookup lk = waitingUUIDs.remove(clientId);
+		if(lk != null) {
+			waitingIDs.remove(lk.reqID);
+		}
+	}
+
+	private static class WaitingLookup {
+
+		private final int reqID;
+		private final EaglercraftUUID uuid;
+		private final long timestamp;
+		private final AbstractClientPlayer player;
+
+		public WaitingLookup(int reqID, EaglercraftUUID uuid, long timestamp, AbstractClientPlayer player) {
+			this.reqID = reqID;
+			this.uuid = uuid;
+			this.timestamp = timestamp;
+			this.player = player;
+		}
+
+	}
+}
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/Display.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/Display.java
index 956ae1ea..db9f1587 100644
--- a/sources/main/java/net/lax1dude/eaglercraft/v1_8/Display.java
+++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/Display.java
@@ -20,6 +20,8 @@ import net.lax1dude.eaglercraft.v1_8.internal.PlatformInput;
 public class Display {
 
 	private static long lastSwap = 0l;
+	private static long lastDPIUpdate = -250l;
+	private static float cacheDPI = 1.0f;
 
 	public static int getWidth() {
 		return PlatformInput.getWindowWidth();
@@ -29,6 +31,22 @@ public class Display {
 		return PlatformInput.getWindowHeight();
 	}
 
+	public static int getVisualViewportX() {
+		return PlatformInput.getVisualViewportX();
+	}
+
+	public static int getVisualViewportY() {
+		return PlatformInput.getVisualViewportY();
+	}
+
+	public static int getVisualViewportW() {
+		return PlatformInput.getVisualViewportW();
+	}
+
+	public static int getVisualViewportH() {
+		return PlatformInput.getVisualViewportH();
+	}
+
 	public static boolean isActive() {
 		return PlatformInput.getWindowFocused();
 	}
@@ -61,24 +79,32 @@ public class Display {
 		boolean limitFPS = limitFramerate > 0 && limitFramerate < 1000;
 		
 		if(limitFPS) {
-			long millis = System.currentTimeMillis();
+			long millis = EagRuntime.steadyTimeMillis();
 			long frameMillis = (1000l / limitFramerate) - (millis - lastSwap);
 			if(frameMillis > 0l) {
 				EagUtils.sleep(frameMillis);
 			}
 		}
 		
-		lastSwap = System.currentTimeMillis();
+		lastSwap = EagRuntime.steadyTimeMillis();
 	}
 
 	public static boolean contextLost() {
 		return PlatformInput.contextLost();
 	}
-	
+
 	public static boolean wasResized() {
 		return PlatformInput.wasResized();
 	}
 
+	public static boolean wasVisualViewportResized() {
+		return PlatformInput.wasVisualViewportResized();
+	}
+
+	public static boolean supportsFullscreen() {
+		return PlatformInput.supportsFullscreen();
+	}
+
 	public static boolean isFullscreen() {
 		return PlatformInput.isFullscreen();
 	}
@@ -87,4 +113,13 @@ public class Display {
 		PlatformInput.toggleFullscreen();
 	}
 
+	public static float getDPI() {
+		long millis = EagRuntime.steadyTimeMillis();
+		if(millis - lastDPIUpdate > 250l) {
+			lastDPIUpdate = millis;
+			cacheDPI = PlatformInput.getDPI();
+		}
+		return cacheDPI;
+	}
+
 }
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/EagRuntime.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/EagRuntime.java
index e0ff3b01..9aeb060d 100644
--- a/sources/main/java/net/lax1dude/eaglercraft/v1_8/EagRuntime.java
+++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/EagRuntime.java
@@ -3,17 +3,16 @@ package net.lax1dude.eaglercraft.v1_8;
 import java.io.BufferedReader;
 import java.io.IOException;
 import java.io.InputStream;
-import java.io.StringReader;
+import java.io.InputStreamReader;
 import net.lax1dude.eaglercraft.v1_8.internal.buffer.ByteBuffer;
 import net.lax1dude.eaglercraft.v1_8.internal.buffer.FloatBuffer;
 import net.lax1dude.eaglercraft.v1_8.internal.buffer.IntBuffer;
 import java.nio.charset.StandardCharsets;
-import java.text.DateFormat;
 import java.util.ArrayList;
-import java.util.Calendar;
 import java.util.List;
 import java.util.function.Consumer;
 
+import net.lax1dude.eaglercraft.v1_8.internal.EaglerMissingResourceException;
 import net.lax1dude.eaglercraft.v1_8.internal.EnumPlatformANGLE;
 import net.lax1dude.eaglercraft.v1_8.internal.EnumPlatformAgent;
 import net.lax1dude.eaglercraft.v1_8.internal.EnumPlatformOS;
@@ -26,6 +25,7 @@ import net.lax1dude.eaglercraft.v1_8.internal.PlatformRuntime;
 import net.lax1dude.eaglercraft.v1_8.log4j.LogManager;
 import net.lax1dude.eaglercraft.v1_8.log4j.Logger;
 import net.lax1dude.eaglercraft.v1_8.opengl.EaglercraftGPU;
+import net.lax1dude.eaglercraft.v1_8.recording.ScreenRecordingController;
 import net.lax1dude.eaglercraft.v1_8.update.UpdateService;
 
 /**
@@ -70,6 +70,8 @@ public class EagRuntime {
 		UpdateService.initialize();
 		EaglerXBungeeVersion.initialize();
 		EaglercraftGPU.warmUpCache();
+		ScreenRecordingController.initialize();
+		PlatformRuntime.postCreate();
 	}
 
 	public static void destroy() {
@@ -119,11 +121,23 @@ public class EagRuntime {
 	public static void freeFloatBuffer(FloatBuffer byteBuffer) {
 		PlatformRuntime.freeFloatBuffer(byteBuffer);
 	}
-	
+
+	public static boolean getResourceExists(String path) {
+		return PlatformAssets.getResourceExists(path);
+	}
+
 	public static byte[] getResourceBytes(String path) {
 		return PlatformAssets.getResourceBytes(path);
 	}
-	
+
+	public static byte[] getRequiredResourceBytes(String path) {
+		byte[] ret = PlatformAssets.getResourceBytes(path);
+		if(ret == null) {
+			throw new EaglerMissingResourceException("Could not load required resource from EPK: " + path);
+		}
+		return ret;
+	}
+
 	public static InputStream getResourceStream(String path) {
 		byte[] b = PlatformAssets.getResourceBytes(path);
 		if(b != null) {
@@ -132,24 +146,41 @@ public class EagRuntime {
 			return null;
 		}
 	}
-	
+
+	public static InputStream getRequiredResourceStream(String path) {
+		byte[] ret = PlatformAssets.getResourceBytes(path);
+		if(ret == null) {
+			throw new EaglerMissingResourceException("Could not load required resource from EPK: " + path);
+		}
+		return new EaglerInputStream(ret);
+	}
+
 	public static String getResourceString(String path) {
 		byte[] bytes = PlatformAssets.getResourceBytes(path);
 		return bytes != null ? new String(bytes, StandardCharsets.UTF_8) : null;
 	}
-	
+
+	public static String getRequiredResourceString(String path) {
+		byte[] ret = PlatformAssets.getResourceBytes(path);
+		if(ret == null) {
+			throw new EaglerMissingResourceException("Could not load required resource from EPK: " + path);
+		}
+		return new String(ret, StandardCharsets.UTF_8);
+	}
+
 	public static List<String> getResourceLines(String path) {
 		byte[] bytes = PlatformAssets.getResourceBytes(path);
 		if(bytes != null) {
-			List<String> ret = new ArrayList();
+			List<String> ret = new ArrayList<>();
 			try {
-				BufferedReader rd = new BufferedReader(new StringReader(path));
+				BufferedReader rd = new BufferedReader(new InputStreamReader(new EaglerInputStream(bytes), StandardCharsets.UTF_8));
 				String s;
 				while((s = rd.readLine()) != null) {
 					ret.add(s);
 				}
 			}catch(IOException ex) {
 				// ??
+				return null;
 			}
 			return ret;
 		}else {
@@ -157,6 +188,14 @@ public class EagRuntime {
 		}
 	}
 
+	public static List<String> getRequiredResourceLines(String path) {
+		List<String> ret = getResourceLines(path);
+		if(ret == null) {
+			throw new EaglerMissingResourceException("Could not load required resource from EPK: " + path);
+		}
+		return ret;
+	}
+
 	public static void debugPrintStackTraceToSTDERR(Throwable t) {
 		debugPrintStackTraceToSTDERR0("", t);
 		Throwable c = t.getCause();
@@ -180,7 +219,7 @@ public class EagRuntime {
 	}
 	
 	public static String[] getStackTraceElements(Throwable t) {
-		List<String> lst = new ArrayList();
+		List<String> lst = new ArrayList<>();
 		PlatformRuntime.getStackTrace(t, (s) -> {
 			lst.add(s);
 		});
@@ -222,17 +261,23 @@ public class EagRuntime {
 		PlatformRuntime.exit();
 	}
 
+	/**
+	 * Note to skids: This doesn't do anything in javascript runtime!
+	 */
 	public static long maxMemory() {
 		return PlatformRuntime.maxMemory();
 	}
 
 	/**
-	 * Note to skids: This doesn't do anything in TeaVM runtime!
+	 * Note to skids: This doesn't do anything in javascript runtime!
 	 */
 	public static long totalMemory() {
 		return PlatformRuntime.totalMemory();
 	}
 
+	/**
+	 * Note to skids: This doesn't do anything in javascript runtime!
+	 */
 	public static long freeMemory() {
 		return PlatformRuntime.freeMemory();
 	}
@@ -289,18 +334,6 @@ public class EagRuntime {
 		return PlatformRuntime.getClientConfigAdapter();
 	}
 
-	public static String getRecText() {
-		return PlatformRuntime.getRecText();
-	}
-
-	public static void toggleRec() {
-		PlatformRuntime.toggleRec();
-	}
-
-	public static boolean recSupported() {
-		return PlatformRuntime.recSupported();
-	}
-
 	public static void openCreditsPopup(String text) {
 		PlatformApplication.openCreditsPopup(text);
 	}
@@ -317,16 +350,24 @@ public class EagRuntime {
 		PlatformApplication.showDebugConsole();
 	}
 
-	public static Calendar getLocaleCalendar() {
-		return Calendar.getInstance(); //TODO: fix teavm calendar's time zone offset
-	}
-
-	public static <T extends DateFormat> T fixDateFormat(T input) {
-		input.setCalendar(getLocaleCalendar());
-		return input;
+	public static void setDisplayBootMenuNextRefresh(boolean en) {
+		PlatformRuntime.setDisplayBootMenuNextRefresh(en);
 	}
 
 	public static void setMCServerWindowGlobal(String url) {
 		PlatformApplication.setMCServerWindowGlobal(url);
 	}
+
+	public static long steadyTimeMillis() {
+		return PlatformRuntime.steadyTimeMillis();
+	}
+
+	public static long nanoTime() {
+		return PlatformRuntime.nanoTime();
+	}
+
+	public static void immediateContinue() {
+		PlatformRuntime.immediateContinue();
+	}
+
 }
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/EagUtils.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/EagUtils.java
index 4246350c..808aa6c5 100644
--- a/sources/main/java/net/lax1dude/eaglercraft/v1_8/EagUtils.java
+++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/EagUtils.java
@@ -1,5 +1,6 @@
 package net.lax1dude.eaglercraft.v1_8;
 
+import java.nio.charset.StandardCharsets;
 import java.util.Arrays;
 import java.util.List;
 import java.util.regex.Pattern;
@@ -85,4 +86,12 @@ public class EagUtils {
 		}
 	}
 
+	public static EaglercraftUUID makeClientBrandUUID(String name) {
+		return EaglercraftUUID.nameUUIDFromBytes(("EaglercraftXClient:" + name).getBytes(StandardCharsets.UTF_8));
+	}
+
+	public static EaglercraftUUID makeClientBrandUUIDLegacy(String name) {
+		return EaglercraftUUID.nameUUIDFromBytes(("EaglercraftXClientOld:" + name).getBytes(StandardCharsets.UTF_8));
+	}
+
 }
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/EaglerOutputStream.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/EaglerOutputStream.java
index a39c268f..3f4864bc 100644
--- a/sources/main/java/net/lax1dude/eaglercraft/v1_8/EaglerOutputStream.java
+++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/EaglerOutputStream.java
@@ -74,6 +74,11 @@ public class EaglerOutputStream extends OutputStream {
 		return count;
 	}
 
+	public void skipBytes(int num) {
+		ensureCapacity(count + num);
+		count += num;
+	}
+
 	public void close() throws IOException {
 	}
 }
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/EaglerXBungeeVersion.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/EaglerXBungeeVersion.java
index 9a53c774..d1bd0fdf 100644
--- a/sources/main/java/net/lax1dude/eaglercraft/v1_8/EaglerXBungeeVersion.java
+++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/EaglerXBungeeVersion.java
@@ -28,10 +28,7 @@ public class EaglerXBungeeVersion {
 	private static String pluginFilename = null;
 
 	public static void initialize() {
-		String pluginVersionJson = EagRuntime.getResourceString("plugin_version.json");
-		if(pluginVersionJson == null) {
-			throw new RuntimeException("File \"plugin_version.json\" is missing in the epk!");
-		}
+		String pluginVersionJson = EagRuntime.getRequiredResourceString("plugin_version.json");
 		JSONObject json = new JSONObject(pluginVersionJson);
 		pluginName = json.getString("pluginName");
 		pluginVersion = json.getString("pluginVersion");
@@ -76,11 +73,7 @@ public class EaglerXBungeeVersion {
 	}
 
 	public static byte[] getPluginDownload() {
-		byte[] ret = EagRuntime.getResourceBytes(pluginFileEPK);
-		if(ret == null) {
-			throw new RuntimeException("File \"" + pluginFileEPK + "\" is missing in the epk!");
-		}
-		return ret;
+		return EagRuntime.getRequiredResourceBytes(pluginFileEPK);
 	}
 
 	public static void startPluginDownload() {
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/EaglercraftSoundManager.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/EaglercraftSoundManager.java
index 98b96649..86fff434 100644
--- a/sources/main/java/net/lax1dude/eaglercraft/v1_8/EaglercraftSoundManager.java
+++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/EaglercraftSoundManager.java
@@ -130,10 +130,10 @@ public class EaglercraftSoundManager {
 				settings.getSoundLevel(SoundCategory.RECORDS), settings.getSoundLevel(SoundCategory.WEATHER),
 				settings.getSoundLevel(SoundCategory.BLOCKS), settings.getSoundLevel(SoundCategory.MOBS),
 				settings.getSoundLevel(SoundCategory.ANIMALS), settings.getSoundLevel(SoundCategory.PLAYERS),
-				settings.getSoundLevel(SoundCategory.AMBIENT), settings.getSoundLevel(SoundCategory.VOICE)
+				settings.getSoundLevel(SoundCategory.AMBIENT)
 		};
-		activeSounds = new LinkedList();
-		queuedSounds = new LinkedList();
+		activeSounds = new LinkedList<>();
+		queuedSounds = new LinkedList<>();
 	}
 
 	public void unloadSoundSystem() {
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/EaglercraftUUID.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/EaglercraftUUID.java
index d3d771d4..8e75d8bb 100644
--- a/sources/main/java/net/lax1dude/eaglercraft/v1_8/EaglercraftUUID.java
+++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/EaglercraftUUID.java
@@ -21,6 +21,8 @@ public class EaglercraftUUID implements Comparable<EaglercraftUUID> {
 
 	public final long msb;
 	public final long lsb;
+	private int hash = 0;
+	private boolean hasHash;
 
 	public EaglercraftUUID(long msb, long lsb) {
 		this.msb = msb;
@@ -125,13 +127,21 @@ public class EaglercraftUUID implements Comparable<EaglercraftUUID> {
 
 	@Override
 	public int hashCode() {
-		long hilo = msb ^ lsb;
-		return ((int) (hilo >> 32)) ^ (int) hilo;
+		if(hash == 0 && !hasHash) {
+			long hilo = msb ^ lsb;
+			hash = ((int) (hilo >> 32)) ^ (int) hilo;
+			hasHash = true;
+		}
+		return hash;
 	}
 
 	@Override
 	public boolean equals(Object o) {
-		return (o instanceof EaglercraftUUID) && ((EaglercraftUUID) o).lsb == lsb && ((EaglercraftUUID) o).msb == msb;
+		if(!(o instanceof EaglercraftUUID)) return false;
+		EaglercraftUUID oo = (EaglercraftUUID)o;
+		return (hasHash && oo.hasHash)
+				? (hash == oo.hash && msb == oo.msb && lsb == oo.lsb)
+				: (msb == oo.msb && lsb == oo.lsb);
 	}
 
 	public long getMostSignificantBits() {
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/EaglercraftVersion.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/EaglercraftVersion.java
index d09b0400..2dae9373 100644
--- a/sources/main/java/net/lax1dude/eaglercraft/v1_8/EaglercraftVersion.java
+++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/EaglercraftVersion.java
@@ -10,7 +10,7 @@ public class EaglercraftVersion {
 	/// Customize these to fit your fork:
 	
 	public static final String projectForkName = "EaglercraftX";
-	public static final String projectForkVersion = "u36";
+	public static final String projectForkVersion = "u37";
 	public static final String projectForkVendor = "lax1dude";
 	
 	public static final String projectForkURL = "https://gitlab.com/lax1dude/eaglercraftx-1.8";
@@ -20,7 +20,7 @@ public class EaglercraftVersion {
 	public static final String projectOriginName = "EaglercraftX";
 	public static final String projectOriginAuthor = "lax1dude";
 	public static final String projectOriginRevision = "1.8";
-	public static final String projectOriginVersion = "u36";
+	public static final String projectOriginVersion = "u37";
 	
 	public static final String projectOriginURL = "https://gitlab.com/lax1dude/eaglercraftx-1.8"; // rest in peace
 	
@@ -31,7 +31,7 @@ public class EaglercraftVersion {
 	public static final boolean enableUpdateService = true;
 
 	public static final String updateBundlePackageName = "net.lax1dude.eaglercraft.v1_8.client";
-	public static final int updateBundlePackageVersionInt = 36;
+	public static final int updateBundlePackageVersionInt = 37;
 
 	public static final String updateLatestLocalStorageKey = "latestUpdate_" + updateBundlePackageName;
 
@@ -40,6 +40,13 @@ public class EaglercraftVersion {
 	
 	
 	
+	// Client brand identification system configuration
+	
+	public static final EaglercraftUUID clientBrandUUID = EagUtils.makeClientBrandUUID(projectForkName);
+
+	public static final EaglercraftUUID legacyClientUUIDInSharedWorld = EagUtils.makeClientBrandUUIDLegacy(projectOriginName);
+	
+	
 	// Miscellaneous variables:
 
 	public static final String mainMenuStringA = "Minecraft 1.8.8";
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/Filesystem.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/Filesystem.java
new file mode 100644
index 00000000..2755d2d1
--- /dev/null
+++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/Filesystem.java
@@ -0,0 +1,158 @@
+package net.lax1dude.eaglercraft.v1_8;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import net.lax1dude.eaglercraft.v1_8.internal.IEaglerFilesystem;
+import net.lax1dude.eaglercraft.v1_8.internal.PlatformFilesystem;
+import net.lax1dude.eaglercraft.v1_8.internal.RamdiskFilesystemImpl;
+import net.lax1dude.eaglercraft.v1_8.internal.VFSFilenameIterator;
+import net.lax1dude.eaglercraft.v1_8.internal.buffer.ByteBuffer;
+import net.lax1dude.eaglercraft.v1_8.log4j.LogManager;
+import net.lax1dude.eaglercraft.v1_8.log4j.Logger;
+
+/**
+ * Copyright (c) 2024 lax1dude. All Rights Reserved.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ * 
+ */
+public class Filesystem {
+
+	private static final Logger logger = LogManager.getLogger("PlatformFilesystem");
+
+	private static final Map<String,FilesystemHandle> openFilesystems = new HashMap<>();
+
+	public static IEaglerFilesystem getHandleFor(String dbName) {
+		FilesystemHandle handle = openFilesystems.get(dbName);
+		if(handle != null) {
+			++handle.refCount;
+			return new FilesystemHandleWrapper(handle);
+		}
+		IEaglerFilesystem handleImpl = null;
+		if(!EagRuntime.getConfiguration().isRamdiskMode()) {
+			handleImpl = PlatformFilesystem.initializePersist(dbName);
+		}
+		if(handleImpl == null) {
+			handleImpl = new RamdiskFilesystemImpl(dbName);
+		}
+		if(handleImpl.isRamdisk()) {
+			logger.warn("Using RAMDisk filesystem for database \"{}\", data will not be saved to local storage!", dbName);
+		}
+		handle = new FilesystemHandle(handleImpl);
+		openFilesystems.put(dbName, handle);
+		return new FilesystemHandleWrapper(handle);
+	}
+
+	public static void closeAllHandles() {
+		for(FilesystemHandle handle : openFilesystems.values()) {
+			handle.refCount = 0;
+			handle.handle.closeHandle();
+		}
+		openFilesystems.clear();
+	}
+
+	private static class FilesystemHandle {
+
+		private final IEaglerFilesystem handle;
+		private int refCount;
+		
+		private FilesystemHandle(IEaglerFilesystem handle) {
+			this.handle = handle;
+			this.refCount = 1;
+		}
+
+	}
+
+	private static class FilesystemHandleWrapper implements IEaglerFilesystem {
+
+		private final FilesystemHandle handle;
+		private final IEaglerFilesystem handleImpl;
+		private boolean closed;
+
+		private FilesystemHandleWrapper(FilesystemHandle handle) {
+			this.handle = handle;
+			this.handleImpl = handle.handle;
+			this.closed = false;
+		}
+
+		@Override
+		public String getFilesystemName() {
+			return handleImpl.getFilesystemName();
+		}
+
+		@Override
+		public String getInternalDBName() {
+			return handleImpl.getInternalDBName();
+		}
+
+		@Override
+		public boolean isRamdisk() {
+			return handleImpl.isRamdisk();
+		}
+
+		@Override
+		public boolean eaglerDelete(String pathName) {
+			return handleImpl.eaglerDelete(pathName);
+		}
+
+		@Override
+		public ByteBuffer eaglerRead(String pathName) {
+			return handleImpl.eaglerRead(pathName);
+		}
+
+		@Override
+		public void eaglerWrite(String pathName, ByteBuffer data) {
+			handleImpl.eaglerWrite(pathName, data);
+		}
+
+		@Override
+		public boolean eaglerExists(String pathName) {
+			return handleImpl.eaglerExists(pathName);
+		}
+
+		@Override
+		public boolean eaglerMove(String pathNameOld, String pathNameNew) {
+			return handleImpl.eaglerMove(pathNameOld, pathNameNew);
+		}
+
+		@Override
+		public int eaglerCopy(String pathNameOld, String pathNameNew) {
+			return handleImpl.eaglerCopy(pathNameOld, pathNameNew);
+		}
+
+		@Override
+		public int eaglerSize(String pathName) {
+			return handleImpl.eaglerSize(pathName);
+		}
+
+		@Override
+		public void eaglerIterate(String pathName, VFSFilenameIterator itr, boolean recursive) {
+			handleImpl.eaglerIterate(pathName, itr, recursive);
+		}
+
+		@Override
+		public void closeHandle() {
+			if(!closed && handle.refCount > 0) {
+				closed = true;
+				--handle.refCount;
+				if(handle.refCount <= 0) {
+					logger.info("Releasing filesystem handle for: \"{}\"", handleImpl.getFilesystemName());
+					handleImpl.closeHandle();
+					openFilesystems.remove(handleImpl.getFilesystemName());
+				}
+			}
+		}
+
+	}
+
+}
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/Gamepad.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/Gamepad.java
new file mode 100644
index 00000000..2c90683c
--- /dev/null
+++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/Gamepad.java
@@ -0,0 +1,115 @@
+package net.lax1dude.eaglercraft.v1_8;
+
+import java.util.LinkedList;
+import java.util.List;
+
+import net.lax1dude.eaglercraft.v1_8.internal.GamepadConstants;
+import net.lax1dude.eaglercraft.v1_8.internal.PlatformInput;
+
+/**
+ * Copyright (c) 2024 lax1dude. All Rights Reserved.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ * 
+ */
+public class Gamepad {
+
+	private static final boolean[] buttonsLastState = new boolean[24];
+	private static final List<VirtualButtonEvent> buttonEvents = new LinkedList<>();
+	private static VirtualButtonEvent currentVEvent = null;
+
+	private static class VirtualButtonEvent {
+
+		private final int button;
+		private final boolean state;
+
+		public VirtualButtonEvent(int button, boolean state) {
+			this.button = button;
+			this.state = state;
+		}
+
+	}
+
+	public static int getValidDeviceCount() {
+		return PlatformInput.gamepadGetValidDeviceCount();
+	}
+
+	public static String getDeviceName(int deviceId) {
+		return PlatformInput.gamepadGetDeviceName(deviceId);
+	}
+
+	public static void setSelectedDevice(int deviceId) {
+		PlatformInput.gamepadSetSelectedDevice(deviceId);
+	}
+
+	public static void update() {
+		PlatformInput.gamepadUpdate();
+		if(isValid()) {
+			for(int i = 0; i < buttonsLastState.length; ++i) {
+				boolean b = PlatformInput.gamepadGetButtonState(i);
+				if(b != buttonsLastState[i]) {
+					buttonsLastState[i] = b;
+					buttonEvents.add(new VirtualButtonEvent(i, b));
+					if(buttonEvents.size() > 64) {
+						buttonEvents.remove(0);
+					}
+				}
+			}
+		}else {
+			for(int i = 0; i < buttonsLastState.length; ++i) {
+				buttonsLastState[i] = false;
+			}
+		}
+	}
+
+	public static boolean next() {
+		currentVEvent = null;
+		return !buttonEvents.isEmpty() && (currentVEvent = buttonEvents.remove(0)) != null;
+	}
+
+	public static int getEventButton() {
+		return currentVEvent != null ? currentVEvent.button : -1;
+	}
+
+	public static boolean getEventButtonState() {
+		return currentVEvent != null ? currentVEvent.state : false;
+	}
+
+	public static boolean isValid() {
+		return PlatformInput.gamepadIsValid();
+	}
+
+	public static String getName() {
+		return PlatformInput.gamepadGetName();
+	}
+
+	public static boolean getButtonState(int button) {
+		return PlatformInput.gamepadGetButtonState(button);
+	}
+
+	public static String getButtonName(int button) {
+		return GamepadConstants.getButtonName(button);
+	}
+
+	public static float getAxis(int axis) {
+		return PlatformInput.gamepadGetAxis(axis);
+	}
+
+	public static String getAxisName(int button) {
+		return GamepadConstants.getAxisName(button);
+	}
+
+	public static void clearEventBuffer() {
+		buttonEvents.clear();
+	}
+
+}
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/HashKey.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/HashKey.java
new file mode 100644
index 00000000..75cd5582
--- /dev/null
+++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/HashKey.java
@@ -0,0 +1,54 @@
+package net.lax1dude.eaglercraft.v1_8;
+
+import java.util.Arrays;
+
+/**
+ * Copyright (c) 2024 lax1dude. All Rights Reserved.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ * 
+ */
+public class HashKey {
+
+	public final byte[] key;
+	public final int hash;
+
+	public HashKey(byte[] key, int hashCode) {
+		this.key = key;
+		this.hash = hashCode;
+	}
+
+	public HashKey(byte[] key) {
+		this.key = key;
+		this.hash = Arrays.hashCode(key);
+	}
+
+	public Object clone() {
+		return new HashKey(key, hash);
+	}
+
+	@Override
+	public int hashCode() {
+		return hash;
+	}
+
+	@Override
+	public boolean equals(Object obj) {
+		if (this == obj)
+			return true;
+		if (obj == null || !(obj instanceof HashKey))
+			return false;
+		HashKey other = (HashKey) obj;
+		return hash == other.hash && Arrays.equals(key, other.key);
+	}
+
+}
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/IOUtils.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/IOUtils.java
index e42561fe..83655734 100644
--- a/sources/main/java/net/lax1dude/eaglercraft/v1_8/IOUtils.java
+++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/IOUtils.java
@@ -32,7 +32,7 @@ public class IOUtils {
 			return Arrays.asList(
 					new String(((EaglerInputStream) parInputStream).getAsArray(), charset).split("(\\r\\n|\\n|\\r)"));
 		}else {
-			List<String> ret = new ArrayList();
+			List<String> ret = new ArrayList<>();
 			try(InputStream is = parInputStream) {
 				BufferedReader rd = new BufferedReader(new InputStreamReader(is, charset));
 				String s;
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/Keyboard.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/Keyboard.java
index c93c53f9..9355a7f0 100644
--- a/sources/main/java/net/lax1dude/eaglercraft/v1_8/Keyboard.java
+++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/Keyboard.java
@@ -1,5 +1,6 @@
 package net.lax1dude.eaglercraft.v1_8;
 
+import net.lax1dude.eaglercraft.v1_8.internal.EnumFireKeyboardEvent;
 import net.lax1dude.eaglercraft.v1_8.internal.KeyboardConstants;
 import net.lax1dude.eaglercraft.v1_8.internal.PlatformInput;
 
@@ -60,4 +61,8 @@ public class Keyboard {
 		return PlatformInput.keyboardIsRepeatEvent();
 	}
 
+	public static void fireEvent(EnumFireKeyboardEvent eventType, int eagKey, char keyChar) {
+		PlatformInput.keyboardFireEvent(eventType, eagKey, keyChar);
+	}
+
 }
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/Mouse.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/Mouse.java
index 9f1f3f98..da236bac 100644
--- a/sources/main/java/net/lax1dude/eaglercraft/v1_8/Mouse.java
+++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/Mouse.java
@@ -1,6 +1,7 @@
 package net.lax1dude.eaglercraft.v1_8;
 
 import net.lax1dude.eaglercraft.v1_8.internal.EnumCursorType;
+import net.lax1dude.eaglercraft.v1_8.internal.EnumFireMouseEvent;
 import net.lax1dude.eaglercraft.v1_8.internal.PlatformInput;
 
 /**
@@ -92,6 +93,22 @@ public class Mouse {
 		return PlatformInput.isMouseGrabbed();
 	}
 
+	public static boolean isMouseGrabSupported() {
+		return PlatformInput.mouseGrabSupported();
+	}
+
+	public static void fireMoveEvent(EnumFireMouseEvent eventType, int posX, int posY) {
+		PlatformInput.mouseFireMoveEvent(eventType, posX, posY);
+	}
+
+	public static void fireButtonEvent(EnumFireMouseEvent eventType, int posX, int posY, int button) {
+		PlatformInput.mouseFireButtonEvent(eventType, posX, posY, button);
+	}
+
+	public static void fireWheelEvent(EnumFireMouseEvent eventType, int posX, int posY, float wheel) {
+		PlatformInput.mouseFireWheelEvent(eventType, posX, posY, wheel);
+	}
+
 	private static int customCursorCounter = 0;
 	private static EnumCursorType currentCursorType = EnumCursorType.DEFAULT;
 
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/PauseMenuCustomizeState.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/PauseMenuCustomizeState.java
new file mode 100644
index 00000000..3dc81252
--- /dev/null
+++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/PauseMenuCustomizeState.java
@@ -0,0 +1,257 @@
+package net.lax1dude.eaglercraft.v1_8;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.function.Consumer;
+
+import net.lax1dude.eaglercraft.v1_8.log4j.LogManager;
+import net.lax1dude.eaglercraft.v1_8.log4j.Logger;
+import net.lax1dude.eaglercraft.v1_8.opengl.ImageData;
+import net.lax1dude.eaglercraft.v1_8.profile.EaglerSkinTexture;
+import net.lax1dude.eaglercraft.v1_8.socket.protocol.pkt.server.SPacketCustomizePauseMenuV4EAG;
+import net.lax1dude.eaglercraft.v1_8.socket.protocol.util.PacketImageData;
+import net.minecraft.client.Minecraft;
+import net.minecraft.client.renderer.texture.TextureManager;
+import net.minecraft.util.ResourceLocation;
+
+/**
+ * Copyright (c) 2024 lax1dude. All Rights Reserved.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ * 
+ */
+public class PauseMenuCustomizeState {
+
+	private static final Logger logger = LogManager.getLogger("PauseMenuCustomizeState");
+
+	public static ResourceLocation icon_title_L;
+	public static float icon_title_L_aspect = 1.0f;
+	public static ResourceLocation icon_title_R;
+	public static float icon_title_R_aspect = 1.0f;
+	public static ResourceLocation icon_backToGame_L;
+	public static float icon_backToGame_L_aspect = 1.0f;
+	public static ResourceLocation icon_backToGame_R;
+	public static float icon_backToGame_R_aspect = 1.0f;
+	public static ResourceLocation icon_achievements_L;
+	public static float icon_achievements_L_aspect = 1.0f;
+	public static ResourceLocation icon_achievements_R;
+	public static float icon_achievements_R_aspect = 1.0f;
+	public static ResourceLocation icon_statistics_L;
+	public static float icon_statistics_L_aspect = 1.0f;
+	public static ResourceLocation icon_statistics_R;
+	public static float icon_statistics_R_aspect = 1.0f;
+	public static ResourceLocation icon_serverInfo_L;
+	public static float icon_serverInfo_L_aspect = 1.0f;
+	public static ResourceLocation icon_serverInfo_R;
+	public static float icon_serverInfo_R_aspect = 1.0f;
+	public static ResourceLocation icon_options_L;
+	public static float icon_options_L_aspect = 1.0f;
+	public static ResourceLocation icon_options_R;
+	public static float icon_options_R_aspect = 1.0f;
+	public static ResourceLocation icon_discord_L;
+	public static float icon_discord_L_aspect = 1.0f;
+	public static ResourceLocation icon_discord_R;
+	public static float icon_discord_R_aspect = 1.0f;
+	public static ResourceLocation icon_disconnect_L;
+	public static float icon_disconnect_L_aspect = 1.0f;
+	public static ResourceLocation icon_disconnect_R;
+	public static float icon_disconnect_R_aspect = 1.0f;
+	public static ResourceLocation icon_background_pause;
+	public static float icon_background_pause_aspect = 1.0f;
+	public static ResourceLocation icon_background_all;
+	public static float icon_background_all_aspect = 1.0f;
+	public static ResourceLocation icon_watermark_pause;
+	public static float icon_watermark_pause_aspect = 1.0f;
+	public static ResourceLocation icon_watermark_all;
+	public static float icon_watermark_all_aspect = 1.0f;
+
+	public static final int SERVER_INFO_MODE_NONE = SPacketCustomizePauseMenuV4EAG.SERVER_INFO_MODE_NONE;
+	public static final int SERVER_INFO_MODE_EXTERNAL_URL = SPacketCustomizePauseMenuV4EAG.SERVER_INFO_MODE_EXTERNAL_URL;
+	public static final int SERVER_INFO_MODE_SHOW_EMBED_OVER_HTTP = SPacketCustomizePauseMenuV4EAG.SERVER_INFO_MODE_SHOW_EMBED_OVER_HTTP;
+	public static final int SERVER_INFO_MODE_SHOW_EMBED_OVER_WS = SPacketCustomizePauseMenuV4EAG.SERVER_INFO_MODE_SHOW_EMBED_OVER_WS;
+
+	public static final int SERVER_INFO_EMBED_PERMS_JAVASCRIPT = SPacketCustomizePauseMenuV4EAG.SERVER_INFO_EMBED_PERMS_JAVASCRIPT;
+	public static final int SERVER_INFO_EMBED_PERMS_MESSAGE_API = SPacketCustomizePauseMenuV4EAG.SERVER_INFO_EMBED_PERMS_MESSAGE_API;
+	public static final int SERVER_INFO_EMBED_PERMS_STRICT_CSP = SPacketCustomizePauseMenuV4EAG.SERVER_INFO_EMBED_PERMS_STRICT_CSP;
+
+	public static final int DISCORD_MODE_NONE = SPacketCustomizePauseMenuV4EAG.DISCORD_MODE_NONE;
+	public static final int DISCORD_MODE_INVITE_URL = SPacketCustomizePauseMenuV4EAG.DISCORD_MODE_INVITE_URL;
+
+	public static int serverInfoMode;
+	public static int serverInfoEmbedPerms = SERVER_INFO_EMBED_PERMS_STRICT_CSP;
+	public static String serverInfoEmbedTitle;
+	public static String serverInfoButtonText;
+	public static String serverInfoURL;
+	public static byte[] serverInfoHash;
+
+	public static int discordButtonMode;
+	public static String discordButtonText;
+	public static String discordInviteURL;
+
+	private static final List<PauseMenuSprite> toFree = new ArrayList<>();
+
+	private static int textureId = 0;
+
+	private static class PauseMenuSprite {
+		
+		private final ResourceLocation loc;
+		private final EaglerSkinTexture tex;
+		
+		public PauseMenuSprite(EaglerSkinTexture tex) {
+			this.loc = newLoc();
+			this.tex = tex;
+		}
+		
+	}
+
+	public static void loadPacket(SPacketCustomizePauseMenuV4EAG packet) {
+		reset();
+		
+		serverInfoMode = packet.serverInfoMode;
+		switch(packet.serverInfoMode) {
+		case SERVER_INFO_MODE_NONE:
+		default:
+			serverInfoButtonText = null;
+			serverInfoURL = null;
+			serverInfoHash = null;
+			break;
+		case SERVER_INFO_MODE_EXTERNAL_URL:
+			serverInfoButtonText = packet.serverInfoButtonText;
+			serverInfoURL = packet.serverInfoURL;
+			break;
+		case SERVER_INFO_MODE_SHOW_EMBED_OVER_HTTP:
+			serverInfoButtonText = packet.serverInfoButtonText;
+			serverInfoEmbedPerms = packet.serverInfoEmbedPerms;
+			serverInfoURL = packet.serverInfoURL;
+			serverInfoEmbedTitle = packet.serverInfoEmbedTitle;
+			break;
+		case SERVER_INFO_MODE_SHOW_EMBED_OVER_WS:
+			serverInfoButtonText = packet.serverInfoButtonText;
+			serverInfoEmbedPerms = packet.serverInfoEmbedPerms;
+			serverInfoHash = packet.serverInfoHash;
+			serverInfoEmbedTitle = packet.serverInfoEmbedTitle;
+			break;
+		}
+		
+		discordButtonMode = packet.discordButtonMode;
+		switch(packet.discordButtonMode) {
+		case DISCORD_MODE_NONE:
+		default:
+			discordButtonText = null;
+			serverInfoURL = null;
+			serverInfoHash = null;
+			break;
+		case DISCORD_MODE_INVITE_URL:
+			discordButtonText = packet.discordButtonText;
+			discordInviteURL = packet.discordInviteURL;
+			break;
+		}
+		
+		if(packet.imageMappings != null) {
+			Map<Integer, PauseMenuSprite> spriteCache = new HashMap<>();
+			icon_title_L = cacheLoadHelperFunction("icon_title_L", packet.imageMappings, spriteCache, packet.imageData, (a) -> icon_title_L_aspect = a);
+			icon_title_R = cacheLoadHelperFunction("icon_title_R", packet.imageMappings, spriteCache, packet.imageData, (a) -> icon_title_R_aspect = a);
+			icon_backToGame_L = cacheLoadHelperFunction("icon_backToGame_L", packet.imageMappings, spriteCache, packet.imageData, (a) -> icon_backToGame_L_aspect = a);
+			icon_backToGame_R = cacheLoadHelperFunction("icon_backToGame_R", packet.imageMappings, spriteCache, packet.imageData, (a) -> icon_backToGame_R_aspect = a);
+			icon_achievements_L = cacheLoadHelperFunction("icon_achievements_L", packet.imageMappings, spriteCache, packet.imageData, (a) -> icon_achievements_L_aspect = a);
+			icon_achievements_R = cacheLoadHelperFunction("icon_achievements_R", packet.imageMappings, spriteCache, packet.imageData, (a) -> icon_achievements_R_aspect = a);
+			icon_statistics_L = cacheLoadHelperFunction("icon_statistics_L", packet.imageMappings, spriteCache, packet.imageData, (a) -> icon_statistics_L_aspect = a);
+			icon_statistics_R = cacheLoadHelperFunction("icon_statistics_R", packet.imageMappings, spriteCache, packet.imageData, (a) -> icon_statistics_R_aspect = a);
+			icon_serverInfo_L = cacheLoadHelperFunction("icon_serverInfo_L", packet.imageMappings, spriteCache, packet.imageData, (a) -> icon_serverInfo_L_aspect = a);
+			icon_serverInfo_R = cacheLoadHelperFunction("icon_serverInfo_R", packet.imageMappings, spriteCache, packet.imageData, (a) -> icon_serverInfo_R_aspect = a);
+			icon_options_L = cacheLoadHelperFunction("icon_options_L", packet.imageMappings, spriteCache, packet.imageData, (a) -> icon_options_L_aspect = a);
+			icon_options_R = cacheLoadHelperFunction("icon_options_R", packet.imageMappings, spriteCache, packet.imageData, (a) -> icon_options_R_aspect = a);
+			icon_discord_L = cacheLoadHelperFunction("icon_discord_L", packet.imageMappings, spriteCache, packet.imageData, (a) -> icon_discord_L_aspect = a);
+			icon_discord_R = cacheLoadHelperFunction("icon_discord_R", packet.imageMappings, spriteCache, packet.imageData, (a) -> icon_discord_R_aspect = a);
+			icon_disconnect_L = cacheLoadHelperFunction("icon_disconnect_L", packet.imageMappings, spriteCache, packet.imageData, (a) -> icon_disconnect_L_aspect = a);
+			icon_disconnect_R = cacheLoadHelperFunction("icon_disconnect_R", packet.imageMappings, spriteCache, packet.imageData, (a) -> icon_disconnect_R_aspect = a);
+			icon_background_pause = cacheLoadHelperFunction("icon_background_pause", packet.imageMappings, spriteCache, packet.imageData, (a) -> icon_background_pause_aspect = a);
+			icon_background_all = cacheLoadHelperFunction("icon_background_all", packet.imageMappings, spriteCache, packet.imageData, (a) -> icon_background_all_aspect = a);
+			icon_watermark_pause = cacheLoadHelperFunction("icon_watermark_pause", packet.imageMappings, spriteCache, packet.imageData, (a) -> icon_watermark_pause_aspect = a);
+			icon_watermark_all = cacheLoadHelperFunction("icon_watermark_all", packet.imageMappings, spriteCache, packet.imageData, (a) -> icon_watermark_all_aspect = a);
+		}
+	}
+
+	private static ResourceLocation cacheLoadHelperFunction(String name, Map<String, Integer> lookup,
+			Map<Integer, PauseMenuSprite> spriteCache,
+			List<PacketImageData> sourceData, Consumer<Float> aspectCB) {
+		Integer i = lookup.get(name);
+		if(i == null) {
+			return null;
+		}
+		PauseMenuSprite ret = spriteCache.get(i);
+		if(ret != null) {
+			if(name.startsWith("icon_background_") && ImageData.isNPOTStatic(ret.tex.getWidth(), ret.tex.getHeight())) {
+				logger.warn("An NPOT (non-power-of-two) texture was used for \"{}\", this texture's width and height must be powers of two for this texture to display properly on all hardware");
+			}
+			aspectCB.accept((float)ret.tex.getWidth() / ret.tex.getHeight());
+			return ret.loc;
+		}
+		int ii = i.intValue();
+		if(ii < 0 || ii >= sourceData.size()) {
+			return null;
+		}
+		PacketImageData data = sourceData.get(ii);
+		ret = new PauseMenuSprite(new EaglerSkinTexture(ImageData.swapRB(data.rgba), data.width, data.height));
+		Minecraft.getMinecraft().getTextureManager().loadTexture(ret.loc, ret.tex);
+		spriteCache.put(i, ret);
+		toFree.add(ret);
+		aspectCB.accept((float)data.width / data.height);
+		return ret.loc;
+	}
+
+	private static ResourceLocation newLoc() {
+		return new ResourceLocation("eagler:gui/server/custom_pause_menu/tex_" + textureId++);
+	}
+
+	public static void reset() {
+		icon_title_L = icon_title_R = null;
+		icon_backToGame_L = icon_backToGame_R = null;
+		icon_achievements_L = icon_achievements_R = null;
+		icon_statistics_L = icon_statistics_R = null;
+		icon_serverInfo_L = icon_serverInfo_R = null;
+		icon_options_L = icon_options_R = null;
+		icon_discord_L = icon_discord_R = null;
+		icon_disconnect_L = icon_disconnect_R = null;
+		icon_background_pause = icon_background_all = null;
+		icon_watermark_pause = icon_watermark_all = null;
+		icon_title_L_aspect = icon_title_R_aspect = 1.0f;
+		icon_backToGame_L_aspect = icon_backToGame_R_aspect = 1.0f;
+		icon_achievements_L_aspect = icon_achievements_R_aspect = 1.0f;
+		icon_statistics_L_aspect = icon_statistics_R_aspect = 1.0f;
+		icon_serverInfo_L_aspect = icon_serverInfo_R_aspect = 1.0f;
+		icon_options_L_aspect = icon_options_R_aspect = 1.0f;
+		icon_discord_L_aspect = icon_discord_R_aspect = 1.0f;
+		icon_disconnect_L_aspect = icon_disconnect_R_aspect = 1.0f;
+		icon_background_pause_aspect = icon_background_all_aspect = 1.0f;
+		icon_watermark_pause_aspect = icon_watermark_all_aspect = 1.0f;
+		serverInfoMode = 0;
+		serverInfoEmbedPerms = SERVER_INFO_EMBED_PERMS_STRICT_CSP;
+		serverInfoButtonText = null;
+		serverInfoURL = null;
+		serverInfoHash = null;
+		serverInfoEmbedTitle = null;
+		discordButtonMode = 0;
+		discordButtonText = null;
+		discordInviteURL = null;
+		if(!toFree.isEmpty()) {
+			TextureManager mgr = Minecraft.getMinecraft().getTextureManager();
+			for(PauseMenuSprite rc : toFree) {
+				mgr.deleteTexture(rc.loc);
+			}
+			toFree.clear();
+		}
+	}
+
+}
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/PointerInputAbstraction.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/PointerInputAbstraction.java
new file mode 100644
index 00000000..c3ed1ca2
--- /dev/null
+++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/PointerInputAbstraction.java
@@ -0,0 +1,227 @@
+package net.lax1dude.eaglercraft.v1_8;
+
+import net.lax1dude.eaglercraft.v1_8.touch_gui.TouchControls;
+import net.minecraft.client.Minecraft;
+
+/**
+ * Copyright (c) 2024 lax1dude, ayunami2000. All Rights Reserved.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ * 
+ */
+public class PointerInputAbstraction {
+
+	protected static Minecraft mc;
+	protected static int oldMX = -1;
+	protected static int oldMY = -1;
+	protected static int oldTX = -1;
+	protected static int oldTY = -1;
+	protected static int dragStartX = -1;
+	protected static int dragStartY = -1;
+	protected static int dragStepStartX = -1;
+	protected static int dragStepStartY = -1;
+	protected static int dragUID = -1;
+
+	protected static int cursorX = -1;
+	protected static int cursorY = -1;
+	protected static int cursorDX = 0;
+	protected static int cursorDY = 0;
+	protected static boolean touchingScreen = false;
+	protected static boolean touchingScreenNotButton = false;
+	protected static boolean draggingNotTouching = false;
+	protected static boolean touchMode = false;
+
+	public static void init(Minecraft mcIn) {
+		mc = mcIn;
+		oldMX = -1;
+		oldMY = -1;
+		oldTX = -1;
+		oldTY = -1;
+		dragStartX = -1;
+		dragStartY = -1;
+		dragStepStartX = -1;
+		dragStepStartY = -1;
+		dragUID = -1;
+		cursorX = -1;
+		cursorY = -1;
+		cursorDX = 0;
+		cursorDY = 0;
+		touchingScreen = false;
+		touchingScreenNotButton = false;
+		draggingNotTouching = false;
+		touchMode = !mcIn.mouseGrabSupported;
+	}
+
+	public static void runGameLoop() {
+		if(touchMode) {
+			runTouchUpdate();
+		}else {
+			oldTX = -1;
+			oldTY = -1;
+			cursorX = oldMX = Mouse.getX();
+			cursorY = oldMY = Mouse.getY();
+			cursorDX += Mouse.getDX();
+			cursorDY += Mouse.getDY();
+		}
+	}
+
+	private static void runTouchUpdate() {
+		int tc = Touch.touchPointCount();
+		if (tc > 0) {
+			TouchControls.update(true);
+			touchingScreen = true;
+			for(int i = 0; i < tc; ++i) {
+				int uid = Touch.touchPointUID(i);
+				if(TouchControls.touchControls.containsKey(uid)) {
+					continue;
+				}
+				int tx = Touch.touchPointX(i);
+				int ty = Touch.touchPointY(i);
+				if(TouchControls.overlappingControl(tx, ty) != null) {
+					continue;
+				}
+				if(mc.currentScreen == null && mc.ingameGUI.isTouchOverlapEagler(uid, tx, ty)) {
+					continue;
+				}
+				cursorX = oldTX = tx;
+				cursorY = oldTY = ty;
+				oldMX = Mouse.getX();
+				oldMY = Mouse.getY();
+				touchingScreenNotButton = true;
+				runTouchDeltaUpdate(uid);
+				return;
+			}
+			touchingScreenNotButton = false;
+		} else {
+			TouchControls.update(false);
+			touchingScreen = false;
+			touchingScreenNotButton = false;
+			dragStepStartX = -1;
+			dragStepStartY = -1;
+			dragStartX = -1;
+			dragStartY = -1;
+			dragUID = -1;
+			final int tmp = Mouse.getX();
+			final int tmp2 = Mouse.getY();
+			if(oldTX == -1 || oldTY == -1) {
+				cursorX = oldMX = tmp;
+				cursorY = oldMY = tmp2;
+				cursorDX += Mouse.getDX();
+				cursorDY += Mouse.getDY();
+				return;
+			}
+			if (oldMX == -1 || oldMY == -1) {
+				oldMX = tmp;
+				oldMY = tmp2;
+			}
+			if (oldMX == tmp && oldMY == tmp2) {
+				cursorX = oldTX;
+				cursorY = oldTY;
+			}else {
+				cursorX = oldMX = tmp;
+				cursorY = oldMY = tmp2;
+				cursorDX += Mouse.getDX();
+				cursorDY += Mouse.getDY();
+			}
+		}
+	}
+
+	private static void runTouchDeltaUpdate(int uid) {
+		if(uid != dragUID) {
+			dragStartX = oldTX;
+			dragStartY = oldTY;
+			dragStepStartX = -1;
+			dragStepStartY = -1;
+			dragUID = uid;
+			draggingNotTouching = false;
+			return;
+		}
+		if(dragStepStartX != -1) {
+			cursorDX += oldTX - dragStepStartX;
+		}
+		dragStepStartX = oldTX;
+		if(dragStepStartY != -1) {
+			cursorDY += oldTY - dragStepStartY;
+		}
+		dragStepStartY = oldTY;
+		if(dragStartX != -1 && dragStartY != -1) {
+			int dx = oldTX - dragStartX;
+			int dy = oldTY - dragStartY;
+			int len = dx * dx + dy * dy;
+			int dm = Math.max((int)(6 * Display.getDPI()), 2);
+			if(len > dm * dm) {
+				draggingNotTouching = true;
+			}
+		}
+	}
+
+	public static boolean isTouchMode() {
+		return touchMode;
+	}
+
+	public static boolean isTouchingScreen() {
+		return touchingScreen;
+	}
+
+	public static boolean isTouchingScreenNotButton() {
+		return touchingScreenNotButton;
+	}
+
+	public static boolean isDraggingNotTouching() {
+		return draggingNotTouching;
+	}
+
+	public static void enterTouchModeHook() {
+		if(!touchMode) {
+			touchMode = true;
+			if(mc.mouseGrabSupported) {
+				mc.mouseHelper.ungrabMouseCursor();
+			}
+		}
+	}
+
+	public static void enterMouseModeHook() {
+		if(touchMode) {
+			touchMode = false;
+			touchingScreen = false;
+			touchingScreenNotButton = false;
+			if(mc.inGameHasFocus && mc.mouseGrabSupported) {
+				mc.mouseHelper.grabMouseCursor();
+			}
+		}
+	}
+
+	public static int getVCursorX() {
+		return cursorX;
+	}
+
+	public static int getVCursorY() {
+		return cursorY;
+	}
+
+	public static int getVCursorDX() {
+		int tmp = cursorDX;
+		cursorDX = 0;
+		return tmp;
+	}
+
+	public static int getVCursorDY() {
+		int tmp = cursorDY;
+		cursorDY = 0;
+		return tmp;
+	}
+
+	public static boolean getVCursorButtonDown(int bt) {
+		return (touchingScreenNotButton && bt == 0) || Mouse.isButtonDown(bt);
+	}
+
+}
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/Touch.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/Touch.java
new file mode 100644
index 00000000..eb27322d
--- /dev/null
+++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/Touch.java
@@ -0,0 +1,134 @@
+package net.lax1dude.eaglercraft.v1_8;
+
+import net.lax1dude.eaglercraft.v1_8.internal.EnumTouchEvent;
+import net.lax1dude.eaglercraft.v1_8.internal.PlatformInput;
+
+/**
+ * Copyright (c) 2024 lax1dude. All Rights Reserved.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ * 
+ */
+public class Touch {
+
+	public static boolean next() {
+		return PlatformInput.touchNext();
+	}
+
+	public static EnumTouchEvent getEventType() {
+		return PlatformInput.touchGetEventType();
+	}
+
+	public static int getEventTouchPointCount() {
+		return PlatformInput.touchGetEventTouchPointCount();
+	}
+
+	public static int getEventTouchX(int pointId) {
+		return PlatformInput.touchGetEventTouchX(pointId);
+	}
+
+	public static int getEventTouchY(int pointId) {
+		return PlatformInput.touchGetEventTouchY(pointId);
+	}
+
+	public static float getEventTouchRadiusX(int pointId) {
+		return PlatformInput.touchGetEventTouchRadiusX(pointId);
+	}
+
+	public static float getEventTouchRadiusY(int pointId) {
+		return PlatformInput.touchGetEventTouchRadiusY(pointId);
+	}
+
+	public static float getEventTouchRadiusMixed(int pointId) {
+		return PlatformInput.touchGetEventTouchRadiusMixed(pointId);
+	}
+
+	public static float getEventTouchForce(int pointId) {
+		return PlatformInput.touchGetEventTouchForce(pointId);
+	}
+
+	public static int getEventTouchPointUID(int pointId) {
+		return PlatformInput.touchGetEventTouchPointUID(pointId);
+	}
+
+	public static int touchPointCount() {
+		return PlatformInput.touchPointCount();
+	}
+
+	public static int touchPointX(int pointId) {
+		return PlatformInput.touchPointX(pointId);
+	}
+
+	public static int touchPointY(int pointId) {
+		return PlatformInput.touchPointY(pointId);
+	}
+
+	public static float touchPointRadiusX(int pointId) {
+		return PlatformInput.touchRadiusX(pointId);
+	}
+
+	public static float touchPointRadiusY(int pointId) {
+		return PlatformInput.touchRadiusY(pointId);
+	}
+
+	public static float touchPointRadiusMixed(int pointId) {
+		return PlatformInput.touchRadiusMixed(pointId);
+	}
+
+	public static float touchPointForce(int pointId) {
+		return PlatformInput.touchForce(pointId);
+	}
+
+	public static int touchPointUID(int pointId) {
+		return PlatformInput.touchPointUID(pointId);
+	}
+
+	public static void touchSetOpenKeyboardZone(int x, int y, int w, int h) {
+		PlatformInput.touchSetOpenKeyboardZone(x, y, w, h);
+	}
+
+	public static void closeDeviceKeyboard() {
+		PlatformInput.touchCloseDeviceKeyboard();
+	}
+
+	public static boolean isDeviceKeyboardOpenMAYBE() {
+		return PlatformInput.touchIsDeviceKeyboardOpenMAYBE();
+	}
+
+	public static String getPastedString() {
+		return PlatformInput.touchGetPastedString();
+	}
+
+	public static boolean checkPointTouching(int uid) {
+		int cnt = PlatformInput.touchPointCount();
+		if(cnt > 0) {
+			for(int i = 0; i < cnt; ++i) {
+				if(PlatformInput.touchPointUID(i) == uid) {
+					return true;
+				}
+			}
+		}
+		return false;
+	}
+
+	public static int fetchPointIdx(int uid) {
+		int cnt = PlatformInput.touchPointCount();
+		if(cnt > 0) {
+			for(int i = 0; i < cnt; ++i) {
+				if(PlatformInput.touchPointUID(i) == uid) {
+					return i;
+				}
+			}
+		}
+		return -1;
+	}
+}
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/boot_menu/GuiScreenEnterBootMenu.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/boot_menu/GuiScreenEnterBootMenu.java
new file mode 100644
index 00000000..e5f5b6c5
--- /dev/null
+++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/boot_menu/GuiScreenEnterBootMenu.java
@@ -0,0 +1,54 @@
+package net.lax1dude.eaglercraft.v1_8.boot_menu;
+
+import net.lax1dude.eaglercraft.v1_8.EagRuntime;
+import net.minecraft.client.gui.GuiButton;
+import net.minecraft.client.gui.GuiScreen;
+import net.minecraft.client.resources.I18n;
+
+/**
+ * Copyright (c) 2024 lax1dude. All Rights Reserved.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ * 
+ */
+public class GuiScreenEnterBootMenu extends GuiScreen {
+
+	private final GuiScreen parent;
+
+	public GuiScreenEnterBootMenu(GuiScreen parent) {
+		this.parent = parent;
+	}
+
+	public void initGui() {
+		EagRuntime.setDisplayBootMenuNextRefresh(true);
+		this.buttonList.clear();
+		this.buttonList.add(new GuiButton(0, this.width / 2 - 100, this.height / 6 + 96, I18n.format("gui.cancel")));
+	}
+
+	public void onGuiClosed() {
+		EagRuntime.setDisplayBootMenuNextRefresh(false);
+	}
+
+	public void drawScreen(int par1, int par2, float par3) {
+		this.drawDefaultBackground();
+		this.drawCenteredString(fontRendererObj, I18n.format("enterBootMenu.title"), this.width / 2, 70, 11184810);
+		this.drawCenteredString(fontRendererObj, I18n.format("enterBootMenu.text0"), this.width / 2, 90, 16777215);
+		super.drawScreen(par1, par2, par3);
+	}
+
+	protected void actionPerformed(GuiButton par1GuiButton) {
+		if(par1GuiButton.id == 0) {
+			this.mc.displayGuiScreen(parent);
+		}
+	}
+
+}
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/cache/EaglerLoadingCache.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/cache/EaglerLoadingCache.java
index a9a7ecc9..54d55a00 100644
--- a/sources/main/java/net/lax1dude/eaglercraft/v1_8/cache/EaglerLoadingCache.java
+++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/cache/EaglerLoadingCache.java
@@ -25,7 +25,7 @@ public class EaglerLoadingCache<K, V> {
 
 	public EaglerLoadingCache(EaglerCacheProvider<K, V> provider) {
 		this.provider = provider;
-		this.cacheMap = new HashMap();
+		this.cacheMap = new HashMap<>();
 	}
 
 	public V get(K key) {
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/cookie/GuiScreenInspectSessionToken.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/cookie/GuiScreenInspectSessionToken.java
new file mode 100644
index 00000000..ea9897cb
--- /dev/null
+++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/cookie/GuiScreenInspectSessionToken.java
@@ -0,0 +1,84 @@
+package net.lax1dude.eaglercraft.v1_8.cookie;
+
+import java.text.SimpleDateFormat;
+import java.util.Date;
+
+import net.lax1dude.eaglercraft.v1_8.cookie.ServerCookieDataStore.ServerCookie;
+import net.minecraft.client.gui.GuiButton;
+import net.minecraft.client.gui.GuiScreen;
+import net.minecraft.client.resources.I18n;
+
+/**
+ * Copyright (c) 2024 lax1dude. All Rights Reserved.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ * 
+ */
+public class GuiScreenInspectSessionToken extends GuiScreen {
+
+	private final GuiScreen parent;
+	private final ServerCookie cookie;
+
+	public GuiScreenInspectSessionToken(GuiScreenRevokeSessionToken parent, ServerCookie cookie) {
+		this.parent = parent;
+		this.cookie = cookie;
+	}
+
+	public void initGui() {
+		this.buttonList.clear();
+		this.buttonList.add(new GuiButton(0, this.width / 2 - 100, this.height / 6 + 106, I18n.format("gui.done")));
+	}
+
+	public void drawScreen(int par1, int par2, float par3) {
+		this.drawDefaultBackground();
+		String[][] toDraw = new String[][] {
+			{
+				I18n.format("inspectSessionToken.details.server"),
+				I18n.format("inspectSessionToken.details.expires"),
+				I18n.format("inspectSessionToken.details.length")
+			},
+			{
+				cookie.server.length() > 32 ? cookie.server.substring(0, 30) + "..." : cookie.server,
+				(new SimpleDateFormat("M/d/yyyy h:mm aa")).format(new Date(cookie.expires)),
+				Integer.toString(cookie.cookie.length)
+			}
+		};
+		int[] maxWidth = new int[2];
+		for(int i = 0; i < 2; ++i) {
+			String[] strs = toDraw[i];
+			int w = 0;
+			for(int j = 0; j < strs.length; ++j) {
+				int k = fontRendererObj.getStringWidth(strs[j]);
+				if(k > w) {
+					w = k;
+				}
+			}
+			maxWidth[i] = w + 10;
+		}
+		int totalWidth = maxWidth[0] + maxWidth[1];
+		this.drawCenteredString(fontRendererObj, I18n.format("inspectSessionToken.title"), this.width / 2, 70, 16777215);
+		this.drawString(fontRendererObj, toDraw[0][0], (this.width - totalWidth) / 2, 90, 11184810);
+		this.drawString(fontRendererObj, toDraw[0][1], (this.width - totalWidth) / 2, 104, 11184810);
+		this.drawString(fontRendererObj, toDraw[0][2], (this.width - totalWidth) / 2, 118, 11184810);
+		this.drawString(fontRendererObj, toDraw[1][0], (this.width - totalWidth) / 2 + maxWidth[0], 90, 11184810);
+		this.drawString(fontRendererObj, toDraw[1][1], (this.width - totalWidth) / 2 + maxWidth[0], 104, 11184810);
+		this.drawString(fontRendererObj, toDraw[1][2], (this.width - totalWidth) / 2 + maxWidth[0], 118, 11184810);
+		super.drawScreen(par1, par2, par3);
+	}
+
+	protected void actionPerformed(GuiButton par1GuiButton) {
+		if(par1GuiButton.id == 0) {
+			this.mc.displayGuiScreen(parent);
+		}
+	}
+
+}
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/cookie/GuiScreenRevokeSessionToken.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/cookie/GuiScreenRevokeSessionToken.java
new file mode 100644
index 00000000..6d42d00c
--- /dev/null
+++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/cookie/GuiScreenRevokeSessionToken.java
@@ -0,0 +1,146 @@
+package net.lax1dude.eaglercraft.v1_8.cookie;
+
+import java.io.IOException;
+import java.util.Collections;
+
+import com.google.common.collect.Lists;
+
+import net.minecraft.client.Minecraft;
+import net.minecraft.client.gui.GuiButton;
+import net.minecraft.client.gui.GuiScreen;
+import net.minecraft.client.gui.GuiSlot;
+import net.minecraft.client.resources.I18n;
+
+/**
+ * Copyright (c) 2024 lax1dude. All Rights Reserved.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ * 
+ */
+public class GuiScreenRevokeSessionToken extends GuiScreen {
+	protected GuiScreen parentScreen;
+	private GuiScreenRevokeSessionToken.List list;
+	private GuiButton inspectButton;
+	private GuiButton revokeButton;
+
+	public GuiScreenRevokeSessionToken(GuiScreen parent) {
+		this.parentScreen = parent;
+	}
+
+	public void initGui() {
+		this.buttonList.clear();
+		this.buttonList.add(this.inspectButton = new GuiButton(10, this.width / 2 - 154, this.height - 38, 100, 20, I18n.format("revokeSessionToken.inspect")));
+		this.buttonList.add(this.revokeButton = new GuiButton(9, this.width / 2 - 50, this.height - 38, 100, 20, I18n.format("revokeSessionToken.revoke")));
+		this.buttonList.add(new GuiButton(6, this.width / 2 + 54, this.height - 38, 100, 20, I18n.format("gui.done")));
+		this.list = new GuiScreenRevokeSessionToken.List(this.mc);
+		this.list.registerScrollButtons(7, 8);
+		updateButtons();
+	}
+
+	public void handleMouseInput() throws IOException {
+		super.handleMouseInput();
+		this.list.handleMouseInput();
+	}
+
+	public void handleTouchInput() throws IOException {
+		super.handleTouchInput();
+		this.list.handleTouchInput();
+	}
+
+	protected void actionPerformed(GuiButton parGuiButton) {
+		if (parGuiButton.enabled) {
+			switch (parGuiButton.id) {
+			case 6:
+				this.mc.displayGuiScreen(this.parentScreen);
+				break;
+			case 9:
+				String s1 = list.getSelectedItem();
+				if(s1 != null) {
+					ServerCookieDataStore.ServerCookie cookie = ServerCookieDataStore.loadCookie(s1);
+					if(cookie != null) {
+						this.mc.displayGuiScreen(new GuiScreenSendRevokeRequest(this, cookie));
+					}else {
+						this.initGui();
+					}
+				}
+				break;
+			case 10:
+				String s2 = list.getSelectedItem();
+				if(s2 != null) {
+					ServerCookieDataStore.ServerCookie cookie = ServerCookieDataStore.loadCookie(s2);
+					if(cookie != null) {
+						this.mc.displayGuiScreen(new GuiScreenInspectSessionToken(this, cookie));
+					}else {
+						this.initGui();
+					}
+				}
+				break;
+			default:
+				this.list.actionPerformed(parGuiButton);
+			}
+
+		}
+	}
+
+	protected void updateButtons() {
+		inspectButton.enabled = revokeButton.enabled = list.getSelectedItem() != null;
+	}
+
+	public void drawScreen(int i, int j, float f) {
+		this.list.drawScreen(i, j, f);
+		this.drawCenteredString(this.fontRendererObj, I18n.format("revokeSessionToken.title"), this.width / 2, 16, 16777215);
+		this.drawCenteredString(this.fontRendererObj, I18n.format("revokeSessionToken.note.0"), this.width / 2, this.height - 66, 8421504);
+		this.drawCenteredString(this.fontRendererObj, I18n.format("revokeSessionToken.note.1"), this.width / 2, this.height - 56, 8421504);
+		super.drawScreen(i, j, f);
+	}
+
+	class List extends GuiSlot {
+		private final java.util.List<String> cookieNames = Lists.newArrayList();
+
+		public List(Minecraft mcIn) {
+			super(mcIn, GuiScreenRevokeSessionToken.this.width, GuiScreenRevokeSessionToken.this.height, 32, GuiScreenRevokeSessionToken.this.height - 75 + 4, 18);
+			ServerCookieDataStore.flush();
+			cookieNames.addAll(ServerCookieDataStore.getRevokableServers());
+			Collections.sort(cookieNames);
+		}
+
+		protected int getSize() {
+			return this.cookieNames.size();
+		}
+
+		protected void elementClicked(int i, boolean var2, int var3, int var4) {
+			selectedElement = i;
+			GuiScreenRevokeSessionToken.this.updateButtons();
+		}
+
+		protected boolean isSelected(int i) {
+			return selectedElement == i;
+		}
+
+		protected String getSelectedItem() {
+			return selectedElement == -1 ? null : cookieNames.get(selectedElement);
+		}
+
+		protected int getContentHeight() {
+			return this.getSize() * 18;
+		}
+
+		protected void drawBackground() {
+			GuiScreenRevokeSessionToken.this.drawDefaultBackground();
+		}
+
+		protected void drawSlot(int i, int var2, int j, int var4, int var5, int var6) {
+			GuiScreenRevokeSessionToken.this.drawCenteredString(GuiScreenRevokeSessionToken.this.fontRendererObj,
+					this.cookieNames.get(i), this.width / 2, j + 1, 16777215);
+		}
+	}
+}
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/cookie/GuiScreenSendRevokeRequest.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/cookie/GuiScreenSendRevokeRequest.java
new file mode 100644
index 00000000..fb3b60d4
--- /dev/null
+++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/cookie/GuiScreenSendRevokeRequest.java
@@ -0,0 +1,177 @@
+package net.lax1dude.eaglercraft.v1_8.cookie;
+
+import org.json.JSONObject;
+
+import net.lax1dude.eaglercraft.v1_8.cookie.ServerCookieDataStore.ServerCookie;
+import net.lax1dude.eaglercraft.v1_8.internal.IServerQuery;
+import net.lax1dude.eaglercraft.v1_8.internal.QueryResponse;
+import net.lax1dude.eaglercraft.v1_8.log4j.LogManager;
+import net.lax1dude.eaglercraft.v1_8.log4j.Logger;
+import net.lax1dude.eaglercraft.v1_8.minecraft.GuiScreenGenericErrorMessage;
+import net.lax1dude.eaglercraft.v1_8.socket.ServerQueryDispatch;
+import net.minecraft.client.gui.GuiButton;
+import net.minecraft.client.gui.GuiScreen;
+import net.minecraft.client.resources.I18n;
+
+/**
+ * Copyright (c) 2024 lax1dude. All Rights Reserved.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ * 
+ */
+public class GuiScreenSendRevokeRequest extends GuiScreen {
+
+	private static final Logger logger = LogManager.getLogger("SessionRevokeRequest");
+
+	private GuiScreen parent;
+	private ServerCookie cookie;
+	private String title;
+	private String message;
+	private int timer = 0;
+	private boolean cancelRequested = false;
+	private IServerQuery query = null;
+	private boolean hasSentPacket = false;
+
+	public GuiScreenSendRevokeRequest(GuiScreen parent, ServerCookie cookie) {
+		this.parent = parent;
+		this.cookie = cookie;
+		this.title = I18n.format("revokeSendingScreen.title");
+		this.message = I18n.format("revokeSendingScreen.message.opening", cookie.server);
+	}
+
+	public void initGui() {
+		this.buttonList.clear();
+		this.buttonList.add(new GuiButton(0, this.width / 2 - 100, this.height / 6 + 96, I18n.format("gui.cancel")));
+	}
+
+	public void drawScreen(int par1, int par2, float par3) {
+		this.drawDefaultBackground();
+		this.drawCenteredString(fontRendererObj, title, this.width / 2, 70, 11184810);
+		this.drawCenteredString(fontRendererObj, message, this.width / 2, 90, 16777215);
+		super.drawScreen(par1, par2, par3);
+	}
+	
+	public void updateScreen() {
+		++timer;
+		if (timer > 1) {
+			if(query == null) {
+				logger.info("Attempting to revoke session tokens for: {}", cookie.server);
+				query = ServerQueryDispatch.sendServerQuery(cookie.server, "revoke_session_token");
+				if(query == null) {
+					this.mc.displayGuiScreen(new GuiScreenGenericErrorMessage("revokeFailure.title", "revokeFailure.desc.connectionError", parent));
+					return;
+				}
+			}else {
+				query.update();
+				QueryResponse resp = query.getResponse();
+				if(resp != null) {
+					if(resp.responseType.equalsIgnoreCase("revoke_session_token") && (hasSentPacket ? resp.isResponseJSON() : resp.isResponseString())) {
+						if(!hasSentPacket) {
+							String str = resp.getResponseString();
+							if("ready".equalsIgnoreCase(str)) {
+								hasSentPacket = true;
+								message = I18n.format("revokeSendingScreen.message.sending");
+								query.send(cookie.cookie);
+								return;
+							}else {
+								this.mc.displayGuiScreen(new GuiScreenGenericErrorMessage("revokeFailure.title", "revokeFailure.desc.clientError", parent));
+								return;
+							}
+						}else {
+							JSONObject json = resp.getResponseJSON();
+							String stat = json.optString("status");
+							if("ok".equalsIgnoreCase(stat)) {
+								if(hasSentPacket) {
+									query.close();
+									this.mc.displayGuiScreen(new GuiScreenGenericErrorMessage("revokeSuccess.title", "revokeSuccess.desc", parent));
+									ServerCookieDataStore.clearCookie(cookie.server);
+									return;
+								}else {
+									query.close();
+									this.mc.displayGuiScreen(new GuiScreenGenericErrorMessage("revokeFailure.title", "revokeFailure.desc.clientError", parent));
+									return;
+								}
+							}else if("error".equalsIgnoreCase(stat)) {
+								int code = json.optInt("code", -1);
+								if(code == -1) {
+									query.close();
+									this.mc.displayGuiScreen(new GuiScreenGenericErrorMessage("revokeFailure.title", "revokeFailure.desc.clientError", parent));
+									return;
+								}else {
+									String key;
+									switch(code) {
+									case 1:
+										key = "revokeFailure.desc.notSupported";
+										break;
+									case 2:
+										key = "revokeFailure.desc.notAllowed";
+										break;
+									case 3:
+										key = "revokeFailure.desc.notFound";
+										break;
+									case 4:
+										key = "revokeFailure.desc.serverError";
+										break;
+									default:
+										key = "revokeFailure.desc.genericCode";
+										break;
+									}
+									logger.error("Recieved error code {}! ({})", code, key);
+									query.close();
+									this.mc.displayGuiScreen(new GuiScreenGenericErrorMessage("revokeFailure.title", key, parent));
+									if(json.optBoolean("delete", false)) {
+										ServerCookieDataStore.clearCookie(cookie.server);
+									}
+									return;
+								}
+							}else {
+								logger.error("Recieved unknown status \"{}\"!", stat);
+								query.close();
+								this.mc.displayGuiScreen(new GuiScreenGenericErrorMessage("revokeFailure.title", "revokeFailure.desc.clientError", parent));
+								return;
+							}
+						}
+					}else {
+						query.close();
+						this.mc.displayGuiScreen(new GuiScreenGenericErrorMessage("revokeFailure.title", "revokeFailure.desc.clientError", parent));
+						return;
+					}
+				}
+				if(query.isClosed()) {
+					if(!hasSentPacket || query.responsesAvailable() == 0) {
+						this.mc.displayGuiScreen(new GuiScreenGenericErrorMessage("revokeFailure.title", "revokeFailure.desc.connectionError", parent));
+						return;
+					}
+				}else {
+					if(timer > 400) {
+						query.close();
+						this.mc.displayGuiScreen(new GuiScreenGenericErrorMessage("revokeFailure.title", "revokeFailure.desc.connectionError", parent));
+						return;
+					}
+				}
+				if(cancelRequested) {
+					query.close();
+					this.mc.displayGuiScreen(new GuiScreenGenericErrorMessage("revokeFailure.title", "revokeFailure.desc.cancelled", parent));
+					return;
+				}
+			}
+		}
+	}
+
+	protected void actionPerformed(GuiButton par1GuiButton) {
+		if(par1GuiButton.id == 0) {
+			cancelRequested = true;
+			par1GuiButton.enabled = false;
+		}
+	}
+
+}
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/cookie/HardwareFingerprint.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/cookie/HardwareFingerprint.java
new file mode 100644
index 00000000..8fd21769
--- /dev/null
+++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/cookie/HardwareFingerprint.java
@@ -0,0 +1,294 @@
+package net.lax1dude.eaglercraft.v1_8.cookie;
+
+import net.lax1dude.eaglercraft.v1_8.internal.IFramebufferGL;
+import net.lax1dude.eaglercraft.v1_8.internal.IProgramGL;
+import net.lax1dude.eaglercraft.v1_8.internal.IShaderGL;
+import net.lax1dude.eaglercraft.v1_8.internal.PlatformAssets;
+import net.lax1dude.eaglercraft.v1_8.internal.buffer.ByteBuffer;
+import net.lax1dude.eaglercraft.v1_8.internal.buffer.FloatBuffer;
+import net.lax1dude.eaglercraft.v1_8.log4j.LogManager;
+import net.lax1dude.eaglercraft.v1_8.log4j.Logger;
+import net.lax1dude.eaglercraft.v1_8.opengl.DrawUtils;
+import net.lax1dude.eaglercraft.v1_8.opengl.EaglercraftGPU;
+import net.lax1dude.eaglercraft.v1_8.opengl.GLSLHeader;
+import net.lax1dude.eaglercraft.v1_8.opengl.GlStateManager;
+import net.lax1dude.eaglercraft.v1_8.opengl.ImageData;
+import net.lax1dude.eaglercraft.v1_8.opengl.VSHInputLayoutParser;
+import net.minecraft.client.renderer.texture.TextureUtil;
+
+import static net.lax1dude.eaglercraft.v1_8.internal.PlatformOpenGL.*;
+import static net.lax1dude.eaglercraft.v1_8.opengl.RealOpenGLEnums.*;
+import static net.lax1dude.eaglercraft.v1_8.opengl.ext.deferred.ExtGLEnums.*;
+
+import java.nio.charset.StandardCharsets;
+import java.util.Collections;
+import java.util.List;
+
+import com.google.common.collect.Lists;
+
+import net.lax1dude.eaglercraft.v1_8.Base64;
+import net.lax1dude.eaglercraft.v1_8.EagRuntime;
+import net.lax1dude.eaglercraft.v1_8.EaglercraftRandom;
+import net.lax1dude.eaglercraft.v1_8.crypto.GeneralDigest;
+import net.lax1dude.eaglercraft.v1_8.crypto.SHA256Digest;
+
+/**
+ * Copyright (c) 2024 lax1dude. All Rights Reserved.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ * 
+ */
+public class HardwareFingerprint {
+	
+	// This is used for generating encryption keys for storing cookies,
+	// its supposed to make session hijacking more difficult for skids
+
+	private static final String fingerprintIMG = "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";
+
+	private static final String shaderPrecision = "precision lowp int;\nprecision mediump float;\nprecision mediump sampler2D;\n";
+
+	private static byte[] fingerprint = null;
+
+	public static final Logger logger = LogManager.getLogger("HardwareFingerprint");
+
+	public static byte[] getFingerprint() {
+		if(fingerprint == null) {
+			try {
+				fingerprint = generateFingerprint();
+			}catch(Throwable t) {
+				fingerprint = new byte[0];
+			}
+			if(fingerprint.length == 0) {
+				logger.error("Failed to calculate hardware fingerprint, server cookies will not be encrypted!");
+			}
+		}
+		return fingerprint;
+	}
+
+	private static byte[] generateFingerprint() {
+		ImageData img = PlatformAssets.loadImageFile(Base64.decodeBase64(fingerprintIMG), "image/jpeg");
+		if(img == null) {
+			logger.error("Input image data is corrupt!");
+			return new byte[0];
+		}
+		
+		int[][] mipmapLevels = TextureUtil.generateMipmapData(7, 128,
+				new int[][] { img.pixels, null, null, null, null, null, null, null });
+		
+		int helperTexture = GlStateManager.generateTexture();
+		GlStateManager.bindTexture(helperTexture);
+		_wglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
+		_wglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
+		_wglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+		TextureUtil.allocateTextureImpl(helperTexture, 7, 128, 128);
+		TextureUtil.uploadTextureMipmap(mipmapLevels, 128, 128, 0, 0, false, false);
+		if(checkAnisotropicFilteringSupport()) {
+			_wglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY, 16.0f);
+		}
+		
+		IShaderGL vert;
+		List<VSHInputLayoutParser.ShaderInput> vertLayout;
+		if(DrawUtils.vshLocal != null) {
+			vert = DrawUtils.vshLocal;
+			vertLayout = DrawUtils.vshLocalLayout;
+		}else {
+			String vshLocalSrc = EagRuntime.getRequiredResourceString("/assets/eagler/glsl/local.vsh");
+			vertLayout = VSHInputLayoutParser.getShaderInputs(vshLocalSrc);
+			vert = _wglCreateShader(GL_VERTEX_SHADER);
+			_wglShaderSource(vert, GLSLHeader.getVertexHeaderCompat(vshLocalSrc, DrawUtils.vertexShaderPrecision));
+			_wglCompileShader(vert);
+			if(_wglGetShaderi(vert, GL_COMPILE_STATUS) != GL_TRUE) {
+				_wglDeleteShader(vert);
+				GlStateManager.deleteTexture(helperTexture);
+				return new byte[0];
+			}
+		}
+		
+		IShaderGL frag = _wglCreateShader(GL_FRAGMENT_SHADER);
+		_wglShaderSource(frag, GLSLHeader.getFragmentHeaderCompat(EagRuntime.getRequiredResourceString("/assets/eagler/glsl/hw_fingerprint.fsh"), shaderPrecision));
+		_wglCompileShader(frag);
+		if(_wglGetShaderi(frag, GL_COMPILE_STATUS) != GL_TRUE) {
+			_wglDeleteShader(vert);
+			_wglDeleteShader(frag);
+			GlStateManager.deleteTexture(helperTexture);
+			return new byte[0];
+		}
+		
+		IProgramGL program = _wglCreateProgram();
+		
+		_wglAttachShader(program, vert);
+		_wglAttachShader(program, frag);
+
+		if(EaglercraftGPU.checkOpenGLESVersion() == 200) {
+			VSHInputLayoutParser.applyLayout(program, vertLayout);
+		}
+
+		_wglLinkProgram(program);
+		_wglDetachShader(program, vert);
+		_wglDetachShader(program, frag);
+		if(DrawUtils.vshLocal == null) {
+			_wglDeleteShader(vert);
+		}
+		_wglDeleteShader(frag);
+		
+		if(_wglGetProgrami(program, GL_LINK_STATUS) != GL_TRUE) {
+			_wglDeleteProgram(program);
+			GlStateManager.deleteTexture(helperTexture);
+			return new byte[0];
+		}
+		
+		EaglercraftGPU.bindGLShaderProgram(program);
+		_wglUniform1i(_wglGetUniformLocation(program, "u_inputTexture"), 0);
+		
+		float fovy = 90.0f;
+		float aspect = 1.0f;
+		float zNear = 0.01f;
+		float zFar = 100.0f;
+		FloatBuffer matrixUploadBuffer = EagRuntime.allocateFloatBuffer(16);
+		float toRad = 0.0174532925f;
+		float cotangent = (float) Math.cos(fovy * toRad * 0.5f) / (float) Math.sin(fovy * toRad * 0.5f);
+		
+		matrixUploadBuffer.put(cotangent / aspect);
+		matrixUploadBuffer.put(0.0f);
+		matrixUploadBuffer.put(0.0f);
+		matrixUploadBuffer.put(0.0f);
+		matrixUploadBuffer.put(0.0f);
+		matrixUploadBuffer.put(cotangent);
+		matrixUploadBuffer.put(0.0f);
+		matrixUploadBuffer.put(0.0f);
+		matrixUploadBuffer.put(0.0f);
+		matrixUploadBuffer.put(0.0f);
+		matrixUploadBuffer.put((zFar + zNear) / (zFar - zNear));
+		matrixUploadBuffer.put(2.0f * zFar * zNear / (zFar - zNear));
+		matrixUploadBuffer.put(0.0f);
+		matrixUploadBuffer.put(0.0f);
+		matrixUploadBuffer.put(-1.0f);
+		matrixUploadBuffer.put(0.0f);
+		
+		matrixUploadBuffer.flip();
+		_wglUniformMatrix4fv(_wglGetUniformLocation(program, "u_textureMatrix"), false, matrixUploadBuffer);
+		EagRuntime.freeFloatBuffer(matrixUploadBuffer);
+		
+		int[] oldViewport = new int[4];
+		EaglercraftGPU.glGetInteger(GL_VIEWPORT, oldViewport);
+		IFramebufferGL framebuffer = _wglCreateFramebuffer();
+		int renderTexture = GlStateManager.generateTexture();
+		GlStateManager.bindTexture(renderTexture);
+		_wglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+		_wglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+		_wglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
+		_wglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
+		
+		int dataLength;
+		int type;
+		if(EaglercraftGPU.checkHDRFramebufferSupport(32)) {
+			dataLength = 256 * 256 * 4 * 4;
+			type = GL_FLOAT;
+			EaglercraftGPU.createFramebufferHDR32FTexture(GL_TEXTURE_2D, 0, 256, 256, GL_RGBA, false);
+		}else if(EaglercraftGPU.checkHDRFramebufferSupport(16)) {
+			dataLength = 256 * 256 * 4 * 2;
+			type = _GL_HALF_FLOAT;
+			EaglercraftGPU.createFramebufferHDR16FTexture(GL_TEXTURE_2D, 0, 256, 256, GL_RGBA, false);
+		}else {
+			dataLength = 256 * 256 * 4;
+			type = GL_UNSIGNED_BYTE;
+			EaglercraftGPU.glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 256, 256, 0, GL_RGBA, GL_UNSIGNED_BYTE, (ByteBuffer)null);
+		}
+		
+		_wglBindFramebuffer(_GL_FRAMEBUFFER, framebuffer);
+		_wglFramebufferTexture2D(_GL_FRAMEBUFFER, _GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, EaglercraftGPU.getNativeTexture(renderTexture), 0);
+		_wglDrawBuffers(_GL_COLOR_ATTACHMENT0);
+		
+		GlStateManager.viewport(0, 0, 256, 256);
+		GlStateManager.disableBlend();
+		GlStateManager.bindTexture(helperTexture);
+		
+		DrawUtils.drawStandardQuad2D();
+		
+		_wglDeleteProgram(program);
+		GlStateManager.deleteTexture(helperTexture);
+		
+		ByteBuffer readBuffer = EagRuntime.allocateByteBuffer(dataLength);
+		EaglercraftGPU.glReadPixels(0, 0, 256, 256, GL_RGBA, type, readBuffer);
+		
+		_wglBindFramebuffer(_GL_FRAMEBUFFER, null);
+		_wglDeleteFramebuffer(framebuffer);
+		GlStateManager.deleteTexture(renderTexture);
+		GlStateManager.viewport(oldViewport[0], oldViewport[1], oldViewport[2], oldViewport[3]);
+		
+		SHA256Digest digest = new SHA256Digest();
+		byte[] copyBuffer = new byte[1024];
+		
+		byte[] b = ("eag" + EaglercraftGPU.glGetString(GL_VENDOR) + "; eag " + EaglercraftGPU.glGetString(GL_RENDERER)).getBytes(StandardCharsets.UTF_8);
+		digest.update(b, 0, b.length);
+		
+		digestInts(digest, _wglGetInteger(0x8869), _wglGetInteger(0x8DFB), _wglGetInteger(0x8B4C), _wglGetInteger(0x8DFC), copyBuffer);
+		digestInts(digest, _wglGetInteger(0x8DFD), _wglGetInteger(0x8872), _wglGetInteger(0x84E8), 69, copyBuffer);
+		digestInts(digest, _wglGetInteger(0x0D33), _wglGetInteger(0x851C), _wglGetInteger(0x8B4D), 69, copyBuffer);
+		
+		if(EaglercraftGPU.checkOpenGLESVersion() >= 300) {
+			digestInts(digest, _wglGetInteger(0x8B4A), _wglGetInteger(0x8A2B), _wglGetInteger(0x9122), _wglGetInteger(0x8B4B), copyBuffer);
+			digestInts(digest, _wglGetInteger(0x8C8A), _wglGetInteger(0x8C8B), _wglGetInteger(0x8C80), _wglGetInteger(0x8B49), copyBuffer);
+			digestInts(digest, _wglGetInteger(0x8A2D), _wglGetInteger(0x9125), _wglGetInteger(0x8904), _wglGetInteger(0x8905), copyBuffer);
+			digestInts(digest, _wglGetInteger(0x8824), _wglGetInteger(0x8073), _wglGetInteger(0x88FF), _wglGetInteger(0x84FD), copyBuffer);
+			digestInts(digest, _wglGetInteger(0x8CDF), _wglGetInteger(0x8A2F), _wglGetInteger(0x8A30), _wglGetInteger(0x8A34), copyBuffer);
+			digestInts(digest, _wglGetInteger(0x8A2E),  _wglGetInteger(0x8A31), _wglGetInteger(0x8A33), _wglGetInteger(0x8D57), copyBuffer);
+		}
+		
+		try {
+			List<String> exts = Lists.newArrayList(getAllExtensions());
+			Collections.sort(exts);
+			EaglercraftRandom rand = new EaglercraftRandom(6942069420l + exts.size() * 69l + b.length);
+			for (int i = exts.size() - 1; i > 0; --i) {
+				int j = rand.nextInt(i + 1);
+				Collections.swap(exts, i, j);
+			}
+			b = String.join(":>", exts).getBytes(StandardCharsets.UTF_8);
+			digest.update(b, 0, b.length);
+		}catch(Throwable t) {
+		}
+		
+		int i;
+		while(readBuffer.hasRemaining()) {
+			i = Math.min(readBuffer.remaining(), copyBuffer.length);
+			readBuffer.get(copyBuffer, 0, i);
+			digest.update(copyBuffer, 0, i);
+		}
+		
+		EagRuntime.freeByteBuffer(readBuffer);
+		
+		byte[] hashOut = new byte[32];
+		digest.doFinal(hashOut, 0);
+		
+		return hashOut;
+	}
+
+	private static void digestInts(GeneralDigest digest, int i1, int i2, int i3, int i4, byte[] tmpBuffer) {
+		tmpBuffer[0] = (byte)(i1 >>> 24);
+		tmpBuffer[1] = (byte)(i1 >>> 16);
+		tmpBuffer[2] = (byte)(i1 >>> 8);
+		tmpBuffer[3] = (byte)(i1 & 0xFF);
+		tmpBuffer[4] = (byte)(i2 >>> 24);
+		tmpBuffer[5] = (byte)(i2 >>> 16);
+		tmpBuffer[6] = (byte)(i2 >>> 8);
+		tmpBuffer[7] = (byte)(i2 & 0xFF);
+		tmpBuffer[8] = (byte)(i3 >>> 24);
+		tmpBuffer[9] = (byte)(i3 >>> 16);
+		tmpBuffer[10] = (byte)(i3 >>> 8);
+		tmpBuffer[11] = (byte)(i3 & 0xFF);
+		tmpBuffer[12] = (byte)(i4 >>> 24);
+		tmpBuffer[13] = (byte)(i4 >>> 16);
+		tmpBuffer[14] = (byte)(i4 >>> 8);
+		tmpBuffer[15] = (byte)(i4 & 0xFF);
+		digest.update(tmpBuffer, 0, 16);
+	}
+}
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/cookie/ServerCookieDataStore.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/cookie/ServerCookieDataStore.java
new file mode 100644
index 00000000..705da432
--- /dev/null
+++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/cookie/ServerCookieDataStore.java
@@ -0,0 +1,396 @@
+package net.lax1dude.eaglercraft.v1_8.cookie;
+
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+
+import net.lax1dude.eaglercraft.v1_8.EagRuntime;
+import net.lax1dude.eaglercraft.v1_8.EaglerInputStream;
+import net.lax1dude.eaglercraft.v1_8.EaglerOutputStream;
+import net.lax1dude.eaglercraft.v1_8.EaglerZLIB;
+import net.lax1dude.eaglercraft.v1_8.crypto.AESLightEngine;
+import net.lax1dude.eaglercraft.v1_8.crypto.SHA1Digest;
+import net.lax1dude.eaglercraft.v1_8.internal.PlatformApplication;
+import net.lax1dude.eaglercraft.v1_8.log4j.LogManager;
+import net.lax1dude.eaglercraft.v1_8.log4j.Logger;
+
+/**
+ * Copyright (c) 2024 lax1dude. All Rights Reserved.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ * 
+ */
+public class ServerCookieDataStore {
+
+	private static final Logger logger = LogManager.getLogger("ServerCookieDataStore");
+
+	private static final Map<String,ServerCookie> dataStore = new HashMap<>();
+
+	public static final String localStorageKey = "c";
+
+	public static class ServerCookie {
+
+		public final String server;
+		public final byte[] cookie;
+		public final long expires;
+		public final boolean revokeQuerySupported;
+		public final boolean saveCookieToDisk;
+
+		public ServerCookie(String server, byte[] cookie, long expires, boolean revokeQuerySupported, boolean saveCookieToDisk) {
+			this.server = server;
+			this.cookie = cookie;
+			this.expires = expires;
+			this.revokeQuerySupported = revokeQuerySupported;
+			this.saveCookieToDisk = saveCookieToDisk;
+		}
+
+	}
+
+	public static void load() {
+		if(EagRuntime.getConfiguration().isEnableServerCookies()) {
+			loadData(HardwareFingerprint.getFingerprint());
+		}
+	}
+
+	public static ServerCookie loadCookie(String server) {
+		if(!EagRuntime.getConfiguration().isEnableServerCookies()) {
+			return null;
+		}
+		server = normalize(server);
+		ServerCookie cookie = dataStore.get(server);
+		if(cookie == null) {
+			return null;
+		}
+		long timestamp = System.currentTimeMillis();
+		if(timestamp > cookie.expires) {
+			dataStore.remove(server);
+			saveData(HardwareFingerprint.getFingerprint());
+			return null;
+		}
+		return cookie;
+	}
+
+	public static void saveCookie(String server, long expires, byte[] data, boolean revokeQuerySupported, boolean saveCookieToDisk) {
+		if(!EagRuntime.getConfiguration().isEnableServerCookies()) {
+			return;
+		}
+		server = normalize(server);
+		if(expires > 604800l) {
+			clearCookie(server);
+			logger.error("Server \"{}\" tried to set a cookie for {} days! (The max is 7 days)", server, (expires / 604800l));
+			return;
+		}
+		if(data.length > 255) {
+			clearCookie(server);
+			logger.error("Server \"{}\" tried to set a {} byte cookie! (The max length is 255 bytes)", server, data.length);
+			return;
+		}
+		if(expires < 0l || data.length == 0) {
+			clearCookie(server);
+			return;
+		}
+		long expiresRelative = System.currentTimeMillis() + expires * 1000l;
+		dataStore.put(server, new ServerCookie(server, data, expiresRelative, revokeQuerySupported, saveCookieToDisk));
+		saveData(HardwareFingerprint.getFingerprint());
+	}
+
+	public static void clearCookie(String server) {
+		if(!EagRuntime.getConfiguration().isEnableServerCookies()) {
+			return;
+		}
+		if(dataStore.remove(normalize(server)) != null) {
+			saveData(HardwareFingerprint.getFingerprint());
+		}
+	}
+
+	public static void clearCookiesLow() {
+		dataStore.clear();
+	}
+
+	private static String normalize(String server) {
+		int j = server.indexOf('/');
+		if(j != -1) {
+			int i = server.indexOf("://");
+			if(i != -1) {
+				j = server.indexOf('/', i + 3);
+				if(j == -1) {
+					return server.toLowerCase();
+				}else {
+					return server.substring(0, j).toLowerCase() + server.substring(j);
+				}
+			}else {
+				return server.substring(0, j).toLowerCase() + server.substring(j);
+			}
+		}else {
+			return server.toLowerCase();
+		}
+	}
+
+	public static Set<String> getAllServers() {
+		return dataStore.keySet();
+	}
+
+	public static List<String> getRevokableServers() {
+		List<String> ret = new ArrayList<>(dataStore.size());
+		for(ServerCookie c : dataStore.values()) {
+			if(c.revokeQuerySupported) {
+				ret.add(c.server);
+			}
+		}
+		return ret;
+	}
+
+	public static int size() {
+		return dataStore.size();
+	}
+
+	public static int numRevokable() {
+		int i = 0;
+		for(ServerCookie c : dataStore.values()) {
+			if(c.revokeQuerySupported) {
+				++i;
+			}
+		}
+		return i;
+	}
+
+	public static void flush() {
+		Iterator<ServerCookie> itr = dataStore.values().iterator();
+		boolean changed = false;
+		while(itr.hasNext()) {
+			long timestamp = System.currentTimeMillis();
+			ServerCookie cookie = itr.next();
+			if(timestamp > cookie.expires) {
+				itr.remove();
+				changed = true;
+			}
+		}
+		if(changed) {
+			saveData(HardwareFingerprint.getFingerprint());
+		}
+	}
+
+	private static void loadData(byte[] key) {
+		dataStore.clear();
+		byte[] cookiesTag = PlatformApplication.getLocalStorage(localStorageKey, false);
+		if(cookiesTag == null) {
+			return;
+		}
+		if(cookiesTag.length <= 25) {
+			PlatformApplication.setLocalStorage(localStorageKey, null, false);
+			return;
+		}
+		try {
+			byte[] decrypted;
+			int decryptedLen;
+			switch(cookiesTag[0]) {
+			case 2:
+				if(key == null || key.length == 0) {
+					throw new IOException("Data is encrypted!");
+				}
+				decrypted = new byte[cookiesTag.length - 5];
+				decryptedLen = (cookiesTag[1] << 24) | (cookiesTag[2] << 16) | (cookiesTag[3] << 8) | (cookiesTag[4] & 0xFF);
+				if(decryptedLen < 25) {
+					throw new IOException("too short!");
+				}
+				AESLightEngine aes = new AESLightEngine();
+				aes.init(false, key);
+				int bs = aes.getBlockSize();
+				if(decrypted.length % bs != 0) {
+					throw new IOException("length not aligned to block size!");
+				}
+				byte[] cbcHelper = new byte[] { (byte) 29, (byte) 163, (byte) 4, (byte) 20, (byte) 207, (byte) 26,
+						(byte) 140, (byte) 55, (byte) 246, (byte) 250, (byte) 141, (byte) 183, (byte) 153, (byte) 154,
+						(byte) 59, (byte) 4 };
+				for(int i = 0; i < decryptedLen; i += bs) {
+					processBlockDecryptHelper(aes, cookiesTag, 5 + i, decrypted, i, bs, Math.min(decryptedLen - i, bs), cbcHelper);
+				}
+				if(decrypted[0] != (byte)0x69) {
+					throw new IOException("Data is corrupt!");
+				}
+				break;
+			case 1:
+				if(key != null && key.length > 0) {
+					throw new IOException("Data isn't encrypted!");
+				}
+				decrypted = cookiesTag;
+				decryptedLen = cookiesTag.length;
+				break;
+			default:
+				throw new IOException("Unknown type!");
+			}
+			SHA1Digest digest = new SHA1Digest();
+			digest.update(decrypted, 25, decryptedLen - 25);
+			byte[] digestOut = new byte[20];
+			digest.doFinal(digestOut, 0);
+			for(int i = 0; i < 20; ++i) {
+				if(digestOut[i] != decrypted[5 + i]) {
+					throw new IOException("Invalid checksum!");
+				}
+			}
+			int decompressedLen = (decrypted[1] << 24) | (decrypted[2] << 16) | (decrypted[3] << 8) | (decrypted[4] & 0xFF);
+			byte[] decompressed = new byte[decompressedLen];
+			try (InputStream zstream = EaglerZLIB.newInflaterInputStream(new EaglerInputStream(decrypted, 25, decryptedLen - 25))) {
+				int i = 0, j;
+				while(i < decompressedLen && (j = zstream.read(decompressed, i, decompressedLen - i)) != -1) {
+					i += j;
+				}
+				if(i != decompressedLen) {
+					throw new IOException("Length does not match!");
+				}
+			}
+			DataInputStream dis = new DataInputStream(new EaglerInputStream(decompressed));
+			int readCount = dis.readInt();
+			long time = System.currentTimeMillis();
+			for(int i = 0; i < readCount; ++i) {
+				byte flags = dis.readByte();
+				long expires = dis.readLong();
+				int len = dis.readUnsignedShort();
+				String server = dis.readUTF();
+				if(len == 0) {
+					continue;
+				}
+				if(expires < time) {
+					dis.skipBytes(len);
+					continue;
+				}
+				byte[] cookieData = new byte[len];
+				dis.readFully(cookieData);
+				server = normalize(server);
+				dataStore.put(server, new ServerCookie(server, cookieData, expires, (flags & 1) != 0, (flags & 2) != 0));
+			}
+			if(dis.available() > 0) {
+				throw new IOException("Extra bytes remaining!");
+			}
+		}catch (IOException e) {
+			dataStore.clear();
+			PlatformApplication.setLocalStorage(localStorageKey, null, false);
+			return;
+		}
+	}
+
+	private static void saveData(byte[] key) {
+		Iterator<ServerCookie> itr = dataStore.values().iterator();
+		List<ServerCookie> toSave = new ArrayList<>(dataStore.size());
+		while(itr.hasNext()) {
+			long timestamp = System.currentTimeMillis();
+			ServerCookie cookie = itr.next();
+			if(timestamp > cookie.expires || cookie.cookie.length > 255 || cookie.cookie.length == 0) {
+				itr.remove();
+			}else if(cookie.saveCookieToDisk) {
+				toSave.add(cookie);
+			}
+		}
+		if(toSave.size() == 0) {
+			PlatformApplication.setLocalStorage(localStorageKey, null, false);
+		}else {
+			EaglerOutputStream bao = new EaglerOutputStream(1024);
+			bao.skipBytes(25);
+			int totalUncompressedLen;
+			try(DataOutputStream zstream = new DataOutputStream(EaglerZLIB.newDeflaterOutputStream(bao))) {
+				zstream.writeInt(dataStore.size());
+				for(Entry<String,ServerCookie> etr : dataStore.entrySet()) {
+					ServerCookie cookie = etr.getValue();
+					zstream.writeByte((cookie.revokeQuerySupported ? 1 : 0) | (cookie.saveCookieToDisk ? 2 : 0));
+					zstream.writeLong(cookie.expires);
+					zstream.writeShort(cookie.cookie.length);
+					zstream.writeUTF(etr.getKey());
+					zstream.write(cookie.cookie);
+				}
+				totalUncompressedLen = zstream.size();
+			} catch (IOException e) {
+				logger.error("Failed to write cookies to local storage!");
+				return;
+			}
+			byte[] toEncrypt = bao.toByteArray();
+			SHA1Digest hash = new SHA1Digest();
+			hash.update(toEncrypt, 25, toEncrypt.length - 25);
+			hash.doFinal(toEncrypt, 5);
+			toEncrypt[1] = (byte)(totalUncompressedLen >>> 24);
+			toEncrypt[2] = (byte)(totalUncompressedLen >>> 16);
+			toEncrypt[3] = (byte)(totalUncompressedLen >>> 8);
+			toEncrypt[4] = (byte)(totalUncompressedLen & 0xFF);
+			if(key != null && key.length > 0) {
+				toEncrypt[0] = (byte)0x69;
+				AESLightEngine aes = new AESLightEngine();
+				aes.init(true, key);
+				int bs = aes.getBlockSize();
+				int blockCount = (toEncrypt.length % bs) != 0 ? (toEncrypt.length / bs + 1) : (toEncrypt.length / bs);
+				byte[] encrypted = new byte[blockCount * bs + 5];
+				encrypted[0] = (byte)2;
+				encrypted[1] = (byte)(toEncrypt.length >>> 24);
+				encrypted[2] = (byte)(toEncrypt.length >>> 16);
+				encrypted[3] = (byte)(toEncrypt.length >>> 8);
+				encrypted[4] = (byte)(toEncrypt.length & 0xFF);
+				byte[] cbcHelper = new byte[] { (byte) 29, (byte) 163, (byte) 4, (byte) 20, (byte) 207, (byte) 26,
+						(byte) 140, (byte) 55, (byte) 246, (byte) 250, (byte) 141, (byte) 183, (byte) 153, (byte) 154,
+						(byte) 59, (byte) 4 };
+				for(int i = 0; i < toEncrypt.length; i += bs) {
+					processBlockEncryptHelper(aes, toEncrypt, i, encrypted, 5 + i, bs, cbcHelper);
+				}
+				PlatformApplication.setLocalStorage(localStorageKey, encrypted, false);
+			}else {
+				toEncrypt[0] = (byte)1;
+				PlatformApplication.setLocalStorage(localStorageKey, toEncrypt, false);
+			}
+		}
+	}
+
+	private static void processBlockEncryptHelper(AESLightEngine aes, byte[] in, int inOff, byte[] out, int outOff,
+			int len, byte[] cbcHelper) {
+		int clampedBlockLength = Math.min(in.length - inOff, len);
+		if(clampedBlockLength == len) {
+			for(int i = 0; i < len; ++i) {
+				in[i + inOff] ^= cbcHelper[i];
+			}
+			aes.processBlock(in, inOff, out, outOff);
+			System.arraycopy(out, outOff, cbcHelper, 0, len);
+		}else {
+			byte[] paddedBlock = new byte[len];
+			System.arraycopy(in, inOff, paddedBlock, 0, clampedBlockLength);
+			byte padValue = (byte)(len - clampedBlockLength);
+			for(byte i = 0; i < padValue; ++i) {
+				paddedBlock[clampedBlockLength + i] = padValue;
+			}
+			for(int i = 0; i < len; ++i) {
+				paddedBlock[i] ^= cbcHelper[i];
+			}
+			aes.processBlock(paddedBlock, 0, out, outOff);
+		}
+	}
+
+	private static void processBlockDecryptHelper(AESLightEngine aes, byte[] in, int inOff, byte[] out, int outOff,
+			int paddedLen, int unpaddedLen, byte[] cbcHelper) throws IOException {
+		aes.processBlock(in, inOff, out, outOff);
+		for(int i = 0; i < paddedLen; ++i) {
+			out[i + outOff] ^= cbcHelper[i];
+		}
+		if(unpaddedLen == paddedLen) {
+			System.arraycopy(in, inOff, cbcHelper, 0, paddedLen);
+		}else {
+			byte padValue = (byte)(paddedLen - unpaddedLen);
+			for(byte i = 0; i < padValue; ++i) {
+				if(out[outOff + unpaddedLen + i] != padValue) {
+					throw new IOException("Invalid padding!");
+				}
+			}
+		}
+	}
+}
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/crypto/AESLightEngine.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/crypto/AESLightEngine.java
new file mode 100644
index 00000000..6938e30f
--- /dev/null
+++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/crypto/AESLightEngine.java
@@ -0,0 +1,527 @@
+/*
+ * Copyright (c) 2000-2021 The Legion of the Bouncy Castle Inc. (https://www.bouncycastle.org)
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software 
+ * and associated documentation files (the "Software"), to deal in the Software without restriction, 
+ * including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, 
+ * and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or substantial
+ * portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
+ * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+ * PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ * 
+ */
+
+package net.lax1dude.eaglercraft.v1_8.crypto;
+
+/**
+ * an implementation of the AES (Rijndael), from FIPS-197.
+ * <p>
+ * For further details see: <a href="https://csrc.nist.gov/encryption/aes/">https://csrc.nist.gov/encryption/aes/</a>.
+ *
+ * This implementation is based on optimizations from Dr. Brian Gladman's paper and C code at
+ * <a href="https://fp.gladman.plus.com/cryptography_technology/rijndael/">https://fp.gladman.plus.com/cryptography_technology/rijndael/</a>
+ *
+ * There are three levels of tradeoff of speed vs memory
+ * Because java has no preprocessor, they are written as three separate classes from which to choose
+ *
+ * The fastest uses 8Kbytes of static tables to precompute round calculations, 4 256 word tables for encryption
+ * and 4 for decryption.
+ *
+ * The middle performance version uses only one 256 word table for each, for a total of 2Kbytes,
+ * adding 12 rotate operations per round to compute the values contained in the other tables from
+ * the contents of the first
+ *
+ * The slowest version uses no static tables at all and computes the values
+ * in each round.
+ * <p>
+ * This file contains the slowest performance version with no static tables
+ * for round precomputation, but it has the smallest foot print.
+ *
+ */
+public class AESLightEngine {
+	// The S box
+	private static final byte[] S = { (byte) 99, (byte) 124, (byte) 119, (byte) 123, (byte) 242, (byte) 107, (byte) 111,
+			(byte) 197, (byte) 48, (byte) 1, (byte) 103, (byte) 43, (byte) 254, (byte) 215, (byte) 171, (byte) 118,
+			(byte) 202, (byte) 130, (byte) 201, (byte) 125, (byte) 250, (byte) 89, (byte) 71, (byte) 240, (byte) 173,
+			(byte) 212, (byte) 162, (byte) 175, (byte) 156, (byte) 164, (byte) 114, (byte) 192, (byte) 183, (byte) 253,
+			(byte) 147, (byte) 38, (byte) 54, (byte) 63, (byte) 247, (byte) 204, (byte) 52, (byte) 165, (byte) 229,
+			(byte) 241, (byte) 113, (byte) 216, (byte) 49, (byte) 21, (byte) 4, (byte) 199, (byte) 35, (byte) 195,
+			(byte) 24, (byte) 150, (byte) 5, (byte) 154, (byte) 7, (byte) 18, (byte) 128, (byte) 226, (byte) 235,
+			(byte) 39, (byte) 178, (byte) 117, (byte) 9, (byte) 131, (byte) 44, (byte) 26, (byte) 27, (byte) 110,
+			(byte) 90, (byte) 160, (byte) 82, (byte) 59, (byte) 214, (byte) 179, (byte) 41, (byte) 227, (byte) 47,
+			(byte) 132, (byte) 83, (byte) 209, (byte) 0, (byte) 237, (byte) 32, (byte) 252, (byte) 177, (byte) 91,
+			(byte) 106, (byte) 203, (byte) 190, (byte) 57, (byte) 74, (byte) 76, (byte) 88, (byte) 207, (byte) 208,
+			(byte) 239, (byte) 170, (byte) 251, (byte) 67, (byte) 77, (byte) 51, (byte) 133, (byte) 69, (byte) 249,
+			(byte) 2, (byte) 127, (byte) 80, (byte) 60, (byte) 159, (byte) 168, (byte) 81, (byte) 163, (byte) 64,
+			(byte) 143, (byte) 146, (byte) 157, (byte) 56, (byte) 245, (byte) 188, (byte) 182, (byte) 218, (byte) 33,
+			(byte) 16, (byte) 255, (byte) 243, (byte) 210, (byte) 205, (byte) 12, (byte) 19, (byte) 236, (byte) 95,
+			(byte) 151, (byte) 68, (byte) 23, (byte) 196, (byte) 167, (byte) 126, (byte) 61, (byte) 100, (byte) 93,
+			(byte) 25, (byte) 115, (byte) 96, (byte) 129, (byte) 79, (byte) 220, (byte) 34, (byte) 42, (byte) 144,
+			(byte) 136, (byte) 70, (byte) 238, (byte) 184, (byte) 20, (byte) 222, (byte) 94, (byte) 11, (byte) 219,
+			(byte) 224, (byte) 50, (byte) 58, (byte) 10, (byte) 73, (byte) 6, (byte) 36, (byte) 92, (byte) 194,
+			(byte) 211, (byte) 172, (byte) 98, (byte) 145, (byte) 149, (byte) 228, (byte) 121, (byte) 231, (byte) 200,
+			(byte) 55, (byte) 109, (byte) 141, (byte) 213, (byte) 78, (byte) 169, (byte) 108, (byte) 86, (byte) 244,
+			(byte) 234, (byte) 101, (byte) 122, (byte) 174, (byte) 8, (byte) 186, (byte) 120, (byte) 37, (byte) 46,
+			(byte) 28, (byte) 166, (byte) 180, (byte) 198, (byte) 232, (byte) 221, (byte) 116, (byte) 31, (byte) 75,
+			(byte) 189, (byte) 139, (byte) 138, (byte) 112, (byte) 62, (byte) 181, (byte) 102, (byte) 72, (byte) 3,
+			(byte) 246, (byte) 14, (byte) 97, (byte) 53, (byte) 87, (byte) 185, (byte) 134, (byte) 193, (byte) 29,
+			(byte) 158, (byte) 225, (byte) 248, (byte) 152, (byte) 17, (byte) 105, (byte) 217, (byte) 142, (byte) 148,
+			(byte) 155, (byte) 30, (byte) 135, (byte) 233, (byte) 206, (byte) 85, (byte) 40, (byte) 223, (byte) 140,
+			(byte) 161, (byte) 137, (byte) 13, (byte) 191, (byte) 230, (byte) 66, (byte) 104, (byte) 65, (byte) 153,
+			(byte) 45, (byte) 15, (byte) 176, (byte) 84, (byte) 187, (byte) 22, };
+
+	// The inverse S-box
+	private static final byte[] Si = { (byte) 82, (byte) 9, (byte) 106, (byte) 213, (byte) 48, (byte) 54, (byte) 165,
+			(byte) 56, (byte) 191, (byte) 64, (byte) 163, (byte) 158, (byte) 129, (byte) 243, (byte) 215, (byte) 251,
+			(byte) 124, (byte) 227, (byte) 57, (byte) 130, (byte) 155, (byte) 47, (byte) 255, (byte) 135, (byte) 52,
+			(byte) 142, (byte) 67, (byte) 68, (byte) 196, (byte) 222, (byte) 233, (byte) 203, (byte) 84, (byte) 123,
+			(byte) 148, (byte) 50, (byte) 166, (byte) 194, (byte) 35, (byte) 61, (byte) 238, (byte) 76, (byte) 149,
+			(byte) 11, (byte) 66, (byte) 250, (byte) 195, (byte) 78, (byte) 8, (byte) 46, (byte) 161, (byte) 102,
+			(byte) 40, (byte) 217, (byte) 36, (byte) 178, (byte) 118, (byte) 91, (byte) 162, (byte) 73, (byte) 109,
+			(byte) 139, (byte) 209, (byte) 37, (byte) 114, (byte) 248, (byte) 246, (byte) 100, (byte) 134, (byte) 104,
+			(byte) 152, (byte) 22, (byte) 212, (byte) 164, (byte) 92, (byte) 204, (byte) 93, (byte) 101, (byte) 182,
+			(byte) 146, (byte) 108, (byte) 112, (byte) 72, (byte) 80, (byte) 253, (byte) 237, (byte) 185, (byte) 218,
+			(byte) 94, (byte) 21, (byte) 70, (byte) 87, (byte) 167, (byte) 141, (byte) 157, (byte) 132, (byte) 144,
+			(byte) 216, (byte) 171, (byte) 0, (byte) 140, (byte) 188, (byte) 211, (byte) 10, (byte) 247, (byte) 228,
+			(byte) 88, (byte) 5, (byte) 184, (byte) 179, (byte) 69, (byte) 6, (byte) 208, (byte) 44, (byte) 30,
+			(byte) 143, (byte) 202, (byte) 63, (byte) 15, (byte) 2, (byte) 193, (byte) 175, (byte) 189, (byte) 3,
+			(byte) 1, (byte) 19, (byte) 138, (byte) 107, (byte) 58, (byte) 145, (byte) 17, (byte) 65, (byte) 79,
+			(byte) 103, (byte) 220, (byte) 234, (byte) 151, (byte) 242, (byte) 207, (byte) 206, (byte) 240, (byte) 180,
+			(byte) 230, (byte) 115, (byte) 150, (byte) 172, (byte) 116, (byte) 34, (byte) 231, (byte) 173, (byte) 53,
+			(byte) 133, (byte) 226, (byte) 249, (byte) 55, (byte) 232, (byte) 28, (byte) 117, (byte) 223, (byte) 110,
+			(byte) 71, (byte) 241, (byte) 26, (byte) 113, (byte) 29, (byte) 41, (byte) 197, (byte) 137, (byte) 111,
+			(byte) 183, (byte) 98, (byte) 14, (byte) 170, (byte) 24, (byte) 190, (byte) 27, (byte) 252, (byte) 86,
+			(byte) 62, (byte) 75, (byte) 198, (byte) 210, (byte) 121, (byte) 32, (byte) 154, (byte) 219, (byte) 192,
+			(byte) 254, (byte) 120, (byte) 205, (byte) 90, (byte) 244, (byte) 31, (byte) 221, (byte) 168, (byte) 51,
+			(byte) 136, (byte) 7, (byte) 199, (byte) 49, (byte) 177, (byte) 18, (byte) 16, (byte) 89, (byte) 39,
+			(byte) 128, (byte) 236, (byte) 95, (byte) 96, (byte) 81, (byte) 127, (byte) 169, (byte) 25, (byte) 181,
+			(byte) 74, (byte) 13, (byte) 45, (byte) 229, (byte) 122, (byte) 159, (byte) 147, (byte) 201, (byte) 156,
+			(byte) 239, (byte) 160, (byte) 224, (byte) 59, (byte) 77, (byte) 174, (byte) 42, (byte) 245, (byte) 176,
+			(byte) 200, (byte) 235, (byte) 187, (byte) 60, (byte) 131, (byte) 83, (byte) 153, (byte) 97, (byte) 23,
+			(byte) 43, (byte) 4, (byte) 126, (byte) 186, (byte) 119, (byte) 214, (byte) 38, (byte) 225, (byte) 105,
+			(byte) 20, (byte) 99, (byte) 85, (byte) 33, (byte) 12, (byte) 125, };
+
+	// vector used in calculating key schedule (powers of x in GF(256))
+	private static final int[] rcon = { 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab,
+			0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91 };
+
+	private static int shift(int r, int shift) {
+		return (r >>> shift) | (r << -shift);
+	}
+
+	/* multiply four bytes in GF(2^8) by 'x' {02} in parallel */
+
+	private static final int m1 = 0x80808080;
+	private static final int m2 = 0x7f7f7f7f;
+	private static final int m3 = 0x0000001b;
+	private static final int m4 = 0xC0C0C0C0;
+	private static final int m5 = 0x3f3f3f3f;
+
+	private static int FFmulX(int x) {
+		return (((x & m2) << 1) ^ (((x & m1) >>> 7) * m3));
+	}
+
+	private static int FFmulX2(int x) {
+		int t0 = (x & m5) << 2;
+		int t1 = (x & m4);
+		t1 ^= (t1 >>> 1);
+		return t0 ^ (t1 >>> 2) ^ (t1 >>> 5);
+	}
+
+	/* 
+		The following defines provide alternative definitions of FFmulX that might
+		give improved performance if a fast 32-bit multiply is not available.
+
+		private int FFmulX(int x) { int u = x & m1; u |= (u >> 1); return ((x & m2) << 1) ^ ((u >>> 3) | (u >>> 6)); } 
+		private static final int  m4 = 0x1b1b1b1b;
+		private int FFmulX(int x) { int u = x & m1; return ((x & m2) << 1) ^ ((u - (u >>> 7)) & m4); } 
+
+	 */
+
+	private static int mcol(int x) {
+		int t0, t1;
+		t0 = shift(x, 8);
+		t1 = x ^ t0;
+		return shift(t1, 16) ^ t0 ^ FFmulX(t1);
+	}
+
+	private static int inv_mcol(int x) {
+		int t0, t1;
+		t0 = x;
+		t1 = t0 ^ shift(t0, 8);
+		t0 ^= FFmulX(t1);
+		t1 ^= FFmulX2(t0);
+		t0 ^= t1 ^ shift(t1, 16);
+		return t0;
+	}
+
+	private static int subWord(int x) {
+		return (S[x & 255] & 255 | ((S[(x >> 8) & 255] & 255) << 8) | ((S[(x >> 16) & 255] & 255) << 16)
+				| S[(x >> 24) & 255] << 24);
+	}
+
+	private static int littleEndianToInt(byte[] bs, int off) {
+		int n = bs[off] & 0xff;
+		n |= (bs[++off] & 0xff) << 8;
+		n |= (bs[++off] & 0xff) << 16;
+		n |= bs[++off] << 24;
+		return n;
+	}
+
+	public static void intToLittleEndian(int n, byte[] bs, int off) {
+		bs[off] = (byte) (n);
+		bs[++off] = (byte) (n >>> 8);
+		bs[++off] = (byte) (n >>> 16);
+		bs[++off] = (byte) (n >>> 24);
+	}
+
+	/**
+	 * Calculate the necessary round keys
+	 * The number of calculations depends on key size and block size
+	 * AES specified a fixed block size of 128 bits and key sizes 128/192/256 bits
+	 * This code is written assuming those are the only possible values
+	 */
+	private int[][] generateWorkingKey(byte[] key, boolean forEncryption) {
+		int keyLen = key.length;
+		if (keyLen < 16 || keyLen > 32 || (keyLen & 7) != 0) {
+			throw new IllegalArgumentException("Key length not 128/192/256 bits.");
+		}
+
+		int KC = keyLen >>> 2;
+		ROUNDS = KC + 6; // This is not always true for the generalized Rijndael that allows larger block
+							// sizes
+		int[][] W = new int[ROUNDS + 1][4]; // 4 words in a block
+
+		switch (KC) {
+		case 4: {
+			int col0 = littleEndianToInt(key, 0);
+			W[0][0] = col0;
+			int col1 = littleEndianToInt(key, 4);
+			W[0][1] = col1;
+			int col2 = littleEndianToInt(key, 8);
+			W[0][2] = col2;
+			int col3 = littleEndianToInt(key, 12);
+			W[0][3] = col3;
+
+			for (int i = 1; i <= 10; ++i) {
+				int colx = subWord(shift(col3, 8)) ^ rcon[i - 1];
+				col0 ^= colx;
+				W[i][0] = col0;
+				col1 ^= col0;
+				W[i][1] = col1;
+				col2 ^= col1;
+				W[i][2] = col2;
+				col3 ^= col2;
+				W[i][3] = col3;
+			}
+
+			break;
+		}
+		case 6: {
+			int col0 = littleEndianToInt(key, 0);
+			W[0][0] = col0;
+			int col1 = littleEndianToInt(key, 4);
+			W[0][1] = col1;
+			int col2 = littleEndianToInt(key, 8);
+			W[0][2] = col2;
+			int col3 = littleEndianToInt(key, 12);
+			W[0][3] = col3;
+
+			int col4 = littleEndianToInt(key, 16);
+			int col5 = littleEndianToInt(key, 20);
+
+			int i = 1, rcon = 1, colx;
+			for (;;) {
+				W[i][0] = col4;
+				W[i][1] = col5;
+				colx = subWord(shift(col5, 8)) ^ rcon;
+				rcon <<= 1;
+				col0 ^= colx;
+				W[i][2] = col0;
+				col1 ^= col0;
+				W[i][3] = col1;
+
+				col2 ^= col1;
+				W[i + 1][0] = col2;
+				col3 ^= col2;
+				W[i + 1][1] = col3;
+				col4 ^= col3;
+				W[i + 1][2] = col4;
+				col5 ^= col4;
+				W[i + 1][3] = col5;
+
+				colx = subWord(shift(col5, 8)) ^ rcon;
+				rcon <<= 1;
+				col0 ^= colx;
+				W[i + 2][0] = col0;
+				col1 ^= col0;
+				W[i + 2][1] = col1;
+				col2 ^= col1;
+				W[i + 2][2] = col2;
+				col3 ^= col2;
+				W[i + 2][3] = col3;
+
+				if ((i += 3) >= 13) {
+					break;
+				}
+
+				col4 ^= col3;
+				col5 ^= col4;
+			}
+
+			break;
+		}
+		case 8: {
+			int col0 = littleEndianToInt(key, 0);
+			W[0][0] = col0;
+			int col1 = littleEndianToInt(key, 4);
+			W[0][1] = col1;
+			int col2 = littleEndianToInt(key, 8);
+			W[0][2] = col2;
+			int col3 = littleEndianToInt(key, 12);
+			W[0][3] = col3;
+
+			int col4 = littleEndianToInt(key, 16);
+			W[1][0] = col4;
+			int col5 = littleEndianToInt(key, 20);
+			W[1][1] = col5;
+			int col6 = littleEndianToInt(key, 24);
+			W[1][2] = col6;
+			int col7 = littleEndianToInt(key, 28);
+			W[1][3] = col7;
+
+			int i = 2, rcon = 1, colx;
+			for (;;) {
+				colx = subWord(shift(col7, 8)) ^ rcon;
+				rcon <<= 1;
+				col0 ^= colx;
+				W[i][0] = col0;
+				col1 ^= col0;
+				W[i][1] = col1;
+				col2 ^= col1;
+				W[i][2] = col2;
+				col3 ^= col2;
+				W[i][3] = col3;
+				++i;
+
+				if (i >= 15) {
+					break;
+				}
+
+				colx = subWord(col3);
+				col4 ^= colx;
+				W[i][0] = col4;
+				col5 ^= col4;
+				W[i][1] = col5;
+				col6 ^= col5;
+				W[i][2] = col6;
+				col7 ^= col6;
+				W[i][3] = col7;
+				++i;
+			}
+
+			break;
+		}
+		default: {
+			throw new IllegalStateException("Should never get here");
+		}
+		}
+
+		if (!forEncryption) {
+			for (int j = 1; j < ROUNDS; j++) {
+				for (int i = 0; i < 4; i++) {
+					W[j][i] = inv_mcol(W[j][i]);
+				}
+			}
+		}
+
+		return W;
+	}
+
+	private int ROUNDS;
+	private int[][] WorkingKey = null;
+	private boolean forEncryption;
+
+	private static final int BLOCK_SIZE = 16;
+
+	/**
+	 * default constructor - 128 bit block size.
+	 */
+	public AESLightEngine() {
+		
+	}
+
+	/**
+	 * initialise an AES cipher.
+	 *
+	 * @param forEncryption whether or not we are for encryption.
+	 * @param params the parameters required to set up the cipher.
+	 * @exception IllegalArgumentException if the params argument is
+	 * inappropriate.
+	 */
+	public void init(boolean forEncryption, byte[] key) {
+		WorkingKey = generateWorkingKey(key, forEncryption);
+		this.forEncryption = forEncryption;
+		return;
+	}
+
+	public String getAlgorithmName() {
+		return "AES";
+	}
+
+	public int getBlockSize() {
+		return BLOCK_SIZE;
+	}
+
+	public int processBlock(byte[] in, int inOff, byte[] out, int outOff) {
+		if (WorkingKey == null) {
+			throw new IllegalStateException("AES engine not initialised");
+		}
+
+		if (inOff > (in.length - BLOCK_SIZE)) {
+			throw new IndexOutOfBoundsException("input buffer too short");
+		}
+
+		if (outOff > (out.length - BLOCK_SIZE)) {
+			throw new IndexOutOfBoundsException("output buffer too short");
+		}
+
+		if (forEncryption) {
+			encryptBlock(in, inOff, out, outOff, WorkingKey);
+		} else {
+			decryptBlock(in, inOff, out, outOff, WorkingKey);
+		}
+
+		return BLOCK_SIZE;
+	}
+
+	public void reset() {
+	}
+
+	private void encryptBlock(byte[] in, int inOff, byte[] out, int outOff, int[][] KW) {
+		int C0 = littleEndianToInt(in, inOff + 0);
+		int C1 = littleEndianToInt(in, inOff + 4);
+		int C2 = littleEndianToInt(in, inOff + 8);
+		int C3 = littleEndianToInt(in, inOff + 12);
+
+		int t0 = C0 ^ KW[0][0];
+		int t1 = C1 ^ KW[0][1];
+		int t2 = C2 ^ KW[0][2];
+
+		int r = 1, r0, r1, r2, r3 = C3 ^ KW[0][3];
+		while (r < ROUNDS - 1) {
+			r0 = mcol((S[t0 & 255] & 255) ^ ((S[(t1 >> 8) & 255] & 255) << 8) ^ ((S[(t2 >> 16) & 255] & 255) << 16)
+					^ (S[(r3 >> 24) & 255] << 24)) ^ KW[r][0];
+			r1 = mcol((S[t1 & 255] & 255) ^ ((S[(t2 >> 8) & 255] & 255) << 8) ^ ((S[(r3 >> 16) & 255] & 255) << 16)
+					^ (S[(t0 >> 24) & 255] << 24)) ^ KW[r][1];
+			r2 = mcol((S[t2 & 255] & 255) ^ ((S[(r3 >> 8) & 255] & 255) << 8) ^ ((S[(t0 >> 16) & 255] & 255) << 16)
+					^ (S[(t1 >> 24) & 255] << 24)) ^ KW[r][2];
+			r3 = mcol((S[r3 & 255] & 255) ^ ((S[(t0 >> 8) & 255] & 255) << 8) ^ ((S[(t1 >> 16) & 255] & 255) << 16)
+					^ (S[(t2 >> 24) & 255] << 24)) ^ KW[r++][3];
+			t0 = mcol((S[r0 & 255] & 255) ^ ((S[(r1 >> 8) & 255] & 255) << 8) ^ ((S[(r2 >> 16) & 255] & 255) << 16)
+					^ (S[(r3 >> 24) & 255] << 24)) ^ KW[r][0];
+			t1 = mcol((S[r1 & 255] & 255) ^ ((S[(r2 >> 8) & 255] & 255) << 8) ^ ((S[(r3 >> 16) & 255] & 255) << 16)
+					^ (S[(r0 >> 24) & 255] << 24)) ^ KW[r][1];
+			t2 = mcol((S[r2 & 255] & 255) ^ ((S[(r3 >> 8) & 255] & 255) << 8) ^ ((S[(r0 >> 16) & 255] & 255) << 16)
+					^ (S[(r1 >> 24) & 255] << 24)) ^ KW[r][2];
+			r3 = mcol((S[r3 & 255] & 255) ^ ((S[(r0 >> 8) & 255] & 255) << 8) ^ ((S[(r1 >> 16) & 255] & 255) << 16)
+					^ (S[(r2 >> 24) & 255] << 24)) ^ KW[r++][3];
+		}
+
+		r0 = mcol((S[t0 & 255] & 255) ^ ((S[(t1 >> 8) & 255] & 255) << 8) ^ ((S[(t2 >> 16) & 255] & 255) << 16)
+				^ (S[(r3 >> 24) & 255] << 24)) ^ KW[r][0];
+		r1 = mcol((S[t1 & 255] & 255) ^ ((S[(t2 >> 8) & 255] & 255) << 8) ^ ((S[(r3 >> 16) & 255] & 255) << 16)
+				^ (S[(t0 >> 24) & 255] << 24)) ^ KW[r][1];
+		r2 = mcol((S[t2 & 255] & 255) ^ ((S[(r3 >> 8) & 255] & 255) << 8) ^ ((S[(t0 >> 16) & 255] & 255) << 16)
+				^ (S[(t1 >> 24) & 255] << 24)) ^ KW[r][2];
+		r3 = mcol((S[r3 & 255] & 255) ^ ((S[(t0 >> 8) & 255] & 255) << 8) ^ ((S[(t1 >> 16) & 255] & 255) << 16)
+				^ (S[(t2 >> 24) & 255] << 24)) ^ KW[r++][3];
+
+		// the final round is a simple function of S
+
+		C0 = (S[r0 & 255] & 255) ^ ((S[(r1 >> 8) & 255] & 255) << 8) ^ ((S[(r2 >> 16) & 255] & 255) << 16)
+				^ (S[(r3 >> 24) & 255] << 24) ^ KW[r][0];
+		C1 = (S[r1 & 255] & 255) ^ ((S[(r2 >> 8) & 255] & 255) << 8) ^ ((S[(r3 >> 16) & 255] & 255) << 16)
+				^ (S[(r0 >> 24) & 255] << 24) ^ KW[r][1];
+		C2 = (S[r2 & 255] & 255) ^ ((S[(r3 >> 8) & 255] & 255) << 8) ^ ((S[(r0 >> 16) & 255] & 255) << 16)
+				^ (S[(r1 >> 24) & 255] << 24) ^ KW[r][2];
+		C3 = (S[r3 & 255] & 255) ^ ((S[(r0 >> 8) & 255] & 255) << 8) ^ ((S[(r1 >> 16) & 255] & 255) << 16)
+				^ (S[(r2 >> 24) & 255] << 24) ^ KW[r][3];
+
+		intToLittleEndian(C0, out, outOff + 0);
+		intToLittleEndian(C1, out, outOff + 4);
+		intToLittleEndian(C2, out, outOff + 8);
+		intToLittleEndian(C3, out, outOff + 12);
+	}
+
+	private void decryptBlock(byte[] in, int inOff, byte[] out, int outOff, int[][] KW) {
+		int C0 = littleEndianToInt(in, inOff + 0);
+		int C1 = littleEndianToInt(in, inOff + 4);
+		int C2 = littleEndianToInt(in, inOff + 8);
+		int C3 = littleEndianToInt(in, inOff + 12);
+
+		int t0 = C0 ^ KW[ROUNDS][0];
+		int t1 = C1 ^ KW[ROUNDS][1];
+		int t2 = C2 ^ KW[ROUNDS][2];
+
+		int r = ROUNDS - 1, r0, r1, r2, r3 = C3 ^ KW[ROUNDS][3];
+		while (r > 1) {
+			r0 = inv_mcol((Si[t0 & 255] & 255) ^ ((Si[(r3 >> 8) & 255] & 255) << 8)
+					^ ((Si[(t2 >> 16) & 255] & 255) << 16) ^ (Si[(t1 >> 24) & 255] << 24)) ^ KW[r][0];
+			r1 = inv_mcol((Si[t1 & 255] & 255) ^ ((Si[(t0 >> 8) & 255] & 255) << 8)
+					^ ((Si[(r3 >> 16) & 255] & 255) << 16) ^ (Si[(t2 >> 24) & 255] << 24)) ^ KW[r][1];
+			r2 = inv_mcol((Si[t2 & 255] & 255) ^ ((Si[(t1 >> 8) & 255] & 255) << 8)
+					^ ((Si[(t0 >> 16) & 255] & 255) << 16) ^ (Si[(r3 >> 24) & 255] << 24)) ^ KW[r][2];
+			r3 = inv_mcol((Si[r3 & 255] & 255) ^ ((Si[(t2 >> 8) & 255] & 255) << 8)
+					^ ((Si[(t1 >> 16) & 255] & 255) << 16) ^ (Si[(t0 >> 24) & 255] << 24)) ^ KW[r--][3];
+			t0 = inv_mcol((Si[r0 & 255] & 255) ^ ((Si[(r3 >> 8) & 255] & 255) << 8)
+					^ ((Si[(r2 >> 16) & 255] & 255) << 16) ^ (Si[(r1 >> 24) & 255] << 24)) ^ KW[r][0];
+			t1 = inv_mcol((Si[r1 & 255] & 255) ^ ((Si[(r0 >> 8) & 255] & 255) << 8)
+					^ ((Si[(r3 >> 16) & 255] & 255) << 16) ^ (Si[(r2 >> 24) & 255] << 24)) ^ KW[r][1];
+			t2 = inv_mcol((Si[r2 & 255] & 255) ^ ((Si[(r1 >> 8) & 255] & 255) << 8)
+					^ ((Si[(r0 >> 16) & 255] & 255) << 16) ^ (Si[(r3 >> 24) & 255] << 24)) ^ KW[r][2];
+			r3 = inv_mcol((Si[r3 & 255] & 255) ^ ((Si[(r2 >> 8) & 255] & 255) << 8)
+					^ ((Si[(r1 >> 16) & 255] & 255) << 16) ^ (Si[(r0 >> 24) & 255] << 24)) ^ KW[r--][3];
+		}
+
+		r0 = inv_mcol((Si[t0 & 255] & 255) ^ ((Si[(r3 >> 8) & 255] & 255) << 8) ^ ((Si[(t2 >> 16) & 255] & 255) << 16)
+				^ (Si[(t1 >> 24) & 255] << 24)) ^ KW[r][0];
+		r1 = inv_mcol((Si[t1 & 255] & 255) ^ ((Si[(t0 >> 8) & 255] & 255) << 8) ^ ((Si[(r3 >> 16) & 255] & 255) << 16)
+				^ (Si[(t2 >> 24) & 255] << 24)) ^ KW[r][1];
+		r2 = inv_mcol((Si[t2 & 255] & 255) ^ ((Si[(t1 >> 8) & 255] & 255) << 8) ^ ((Si[(t0 >> 16) & 255] & 255) << 16)
+				^ (Si[(r3 >> 24) & 255] << 24)) ^ KW[r][2];
+		r3 = inv_mcol((Si[r3 & 255] & 255) ^ ((Si[(t2 >> 8) & 255] & 255) << 8) ^ ((Si[(t1 >> 16) & 255] & 255) << 16)
+				^ (Si[(t0 >> 24) & 255] << 24)) ^ KW[r][3];
+
+		// the final round's table is a simple function of Si
+
+		C0 = (Si[r0 & 255] & 255) ^ ((Si[(r3 >> 8) & 255] & 255) << 8) ^ ((Si[(r2 >> 16) & 255] & 255) << 16)
+				^ (Si[(r1 >> 24) & 255] << 24) ^ KW[0][0];
+		C1 = (Si[r1 & 255] & 255) ^ ((Si[(r0 >> 8) & 255] & 255) << 8) ^ ((Si[(r3 >> 16) & 255] & 255) << 16)
+				^ (Si[(r2 >> 24) & 255] << 24) ^ KW[0][1];
+		C2 = (Si[r2 & 255] & 255) ^ ((Si[(r1 >> 8) & 255] & 255) << 8) ^ ((Si[(r0 >> 16) & 255] & 255) << 16)
+				^ (Si[(r3 >> 24) & 255] << 24) ^ KW[0][2];
+		C3 = (Si[r3 & 255] & 255) ^ ((Si[(r2 >> 8) & 255] & 255) << 8) ^ ((Si[(r1 >> 16) & 255] & 255) << 16)
+				^ (Si[(r0 >> 24) & 255] << 24) ^ KW[0][3];
+
+		intToLittleEndian(C0, out, outOff + 0);
+		intToLittleEndian(C1, out, outOff + 4);
+		intToLittleEndian(C2, out, outOff + 8);
+		intToLittleEndian(C3, out, outOff + 12);
+	}
+
+	private int bitsOfSecurity() {
+		if (WorkingKey == null) {
+			return 256;
+		}
+		return (WorkingKey.length - 7) << 5;
+	}
+}
\ No newline at end of file
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/futures/ListenableFutureTask.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/futures/ListenableFutureTask.java
index bbbb57c2..eb914064 100644
--- a/sources/main/java/net/lax1dude/eaglercraft/v1_8/futures/ListenableFutureTask.java
+++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/futures/ListenableFutureTask.java
@@ -22,7 +22,7 @@ import java.util.concurrent.Executor;
  */
 public class ListenableFutureTask<V> extends FutureTask<V> implements ListenableFuture<V> {
 	
-	private final List<Runnable> listeners = new ArrayList();
+	private final List<Runnable> listeners = new ArrayList<>();
 
 	public ListenableFutureTask(Callable<V> callable) {
 		super(callable);
@@ -54,7 +54,7 @@ public class ListenableFutureTask<V> extends FutureTask<V> implements Listenable
 	}
 
 	public static <V> ListenableFutureTask<V> create(Callable<V> callableToSchedule) {
-		return new ListenableFutureTask(callableToSchedule);
+		return new ListenableFutureTask<>(callableToSchedule);
 	}
 	
 }
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/internal/AbstractWebSocketClient.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/internal/AbstractWebSocketClient.java
new file mode 100644
index 00000000..ff588197
--- /dev/null
+++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/internal/AbstractWebSocketClient.java
@@ -0,0 +1,227 @@
+package net.lax1dude.eaglercraft.v1_8.internal;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+
+/**
+ * Copyright (c) 2024 lax1dude. All Rights Reserved.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ * 
+ */
+public abstract class AbstractWebSocketClient implements IWebSocketClient {
+
+	protected volatile int availableStringFrames = 0;
+	protected volatile int availableBinaryFrames = 0;
+	protected final List<IWebSocketFrame> recievedPacketBuffer = new LinkedList<>();
+	protected String currentURI;
+
+	protected AbstractWebSocketClient(String currentURI) {
+		this.currentURI = currentURI;
+	}
+
+	protected void addRecievedFrame(IWebSocketFrame frame) {
+		boolean str = frame.isString();
+		synchronized(recievedPacketBuffer) {
+			recievedPacketBuffer.add(frame);
+			if(str) {
+				++availableStringFrames;
+			}else {
+				++availableBinaryFrames;
+			}
+		}
+	}
+
+	@Override
+	public int availableFrames() {
+		synchronized(recievedPacketBuffer) {
+			return availableStringFrames + availableBinaryFrames;
+		}
+	}
+
+	@Override
+	public IWebSocketFrame getNextFrame() {
+		synchronized(recievedPacketBuffer) {
+			if(!recievedPacketBuffer.isEmpty()) {
+				IWebSocketFrame frame = recievedPacketBuffer.remove(0);
+				if(frame.isString()) {
+					--availableStringFrames;
+				}else {
+					--availableBinaryFrames;
+				}
+				return frame;
+			}else {
+				return null;
+			}
+		}
+	}
+
+	@Override
+	public List<IWebSocketFrame> getNextFrames() {
+		synchronized(recievedPacketBuffer) {
+			if(!recievedPacketBuffer.isEmpty()) {
+				List<IWebSocketFrame> ret = new ArrayList<>(recievedPacketBuffer);
+				recievedPacketBuffer.clear();
+				availableStringFrames = 0;
+				availableBinaryFrames = 0;
+				return ret;
+			}else {
+				return null;
+			}
+		}
+	}
+
+	@Override
+	public void clearFrames() {
+		synchronized(recievedPacketBuffer) {
+			recievedPacketBuffer.clear();
+		}
+	}
+
+	@Override
+	public int availableStringFrames() {
+		synchronized(recievedPacketBuffer) {
+			return availableStringFrames;
+		}
+	}
+
+	@Override
+	public IWebSocketFrame getNextStringFrame() {
+		synchronized(recievedPacketBuffer) {
+			if(availableStringFrames > 0) {
+				Iterator<IWebSocketFrame> itr = recievedPacketBuffer.iterator();
+				while(itr.hasNext()) {
+					IWebSocketFrame r = itr.next();
+					if(r.isString()) {
+						itr.remove();
+						--availableStringFrames;
+						return r;
+					}
+				}
+				availableStringFrames = 0;
+				return null;
+			}else {
+				return null;
+			}
+		}
+	}
+
+	@Override
+	public List<IWebSocketFrame> getNextStringFrames() {
+		synchronized(recievedPacketBuffer) {
+			if(availableStringFrames > 0) {
+				List<IWebSocketFrame> ret = new ArrayList<>(availableStringFrames);
+				Iterator<IWebSocketFrame> itr = recievedPacketBuffer.iterator();
+				while(itr.hasNext()) {
+					IWebSocketFrame r = itr.next();
+					if(r.isString()) {
+						itr.remove();
+						ret.add(r);
+					}
+				}
+				availableStringFrames = 0;
+				return ret;
+			}else {
+				return null;
+			}
+		}
+	}
+
+	@Override
+	public void clearStringFrames() {
+		synchronized(recievedPacketBuffer) {
+			if(availableStringFrames > 0) {
+				Iterator<IWebSocketFrame> itr = recievedPacketBuffer.iterator();
+				while(itr.hasNext()) {
+					IWebSocketFrame r = itr.next();
+					if(r.isString()) {
+						itr.remove();
+					}
+				}
+				availableStringFrames = 0;
+			}
+		}
+	}
+
+	@Override
+	public int availableBinaryFrames() {
+		synchronized(recievedPacketBuffer) {
+			return availableBinaryFrames;
+		}
+	}
+
+	@Override
+	public IWebSocketFrame getNextBinaryFrame() {
+		synchronized(recievedPacketBuffer) {
+			if(availableBinaryFrames > 0) {
+				Iterator<IWebSocketFrame> itr = recievedPacketBuffer.iterator();
+				while(itr.hasNext()) {
+					IWebSocketFrame r = itr.next();
+					if(!r.isString()) {
+						itr.remove();
+						--availableBinaryFrames;
+						return r;
+					}
+				}
+				availableBinaryFrames = 0;
+				return null;
+			}else {
+				return null;
+			}
+		}
+	}
+
+	@Override
+	public List<IWebSocketFrame> getNextBinaryFrames() {
+		synchronized(recievedPacketBuffer) {
+			if(availableBinaryFrames > 0) {
+				List<IWebSocketFrame> ret = new ArrayList<>(availableBinaryFrames);
+				Iterator<IWebSocketFrame> itr = recievedPacketBuffer.iterator();
+				while(itr.hasNext()) {
+					IWebSocketFrame r = itr.next();
+					if(!r.isString()) {
+						itr.remove();
+						ret.add(r);
+					}
+				}
+				availableBinaryFrames = 0;
+				return ret;
+			}else {
+				return null;
+			}
+		}
+	}
+
+	@Override
+	public void clearBinaryFrames() {
+		synchronized(recievedPacketBuffer) {
+			if(availableBinaryFrames > 0) {
+				Iterator<IWebSocketFrame> itr = recievedPacketBuffer.iterator();
+				while(itr.hasNext()) {
+					IWebSocketFrame r = itr.next();
+					if(!r.isString()) {
+						itr.remove();
+					}
+				}
+				availableBinaryFrames = 0;
+			}
+		}
+	}
+
+	@Override
+	public String getCurrentURI() {
+		return currentURI;
+	}
+
+}
diff --git a/sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/PlatformBufferFunctions.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/internal/EaglerMissingResourceException.java
similarity index 63%
rename from sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/PlatformBufferFunctions.java
rename to sources/main/java/net/lax1dude/eaglercraft/v1_8/internal/EaglerMissingResourceException.java
index c3b65936..a4791d18 100644
--- a/sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/PlatformBufferFunctions.java
+++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/internal/EaglerMissingResourceException.java
@@ -1,10 +1,7 @@
 package net.lax1dude.eaglercraft.v1_8.internal;
 
-import net.lax1dude.eaglercraft.v1_8.internal.buffer.ByteBuffer;
-import net.lax1dude.eaglercraft.v1_8.internal.buffer.IntBuffer;
-
 /**
- * Copyright (c) 2022-2023 lax1dude. All Rights Reserved.
+ * Copyright (c) 2024 lax1dude. All Rights Reserved.
  * 
  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
@@ -18,17 +15,21 @@ import net.lax1dude.eaglercraft.v1_8.internal.buffer.IntBuffer;
  * POSSIBILITY OF SUCH DAMAGE.
  * 
  */
-public class PlatformBufferFunctions {
-	
-	public static void put(ByteBuffer newBuffer, ByteBuffer flip) {
-		newBuffer.put(flip);
+public class EaglerMissingResourceException extends RuntimeException {
+
+	public EaglerMissingResourceException() {
 	}
 
-	public static void put(IntBuffer intBuffer, int index, int[] data) {
-		int p = intBuffer.position();
-		intBuffer.position(index);
-		intBuffer.put(data);
-		intBuffer.position(p);
+	public EaglerMissingResourceException(String message, Throwable cause) {
+		super(message, cause);
 	}
-	
+
+	public EaglerMissingResourceException(String message) {
+		super(message);
+	}
+
+	public EaglerMissingResourceException(Throwable cause) {
+		super(cause);
+	}
+
 }
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/internal/EnumFireKeyboardEvent.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/internal/EnumFireKeyboardEvent.java
new file mode 100644
index 00000000..b74e605e
--- /dev/null
+++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/internal/EnumFireKeyboardEvent.java
@@ -0,0 +1,20 @@
+package net.lax1dude.eaglercraft.v1_8.internal;
+
+/**
+ * Copyright (c) 2024 lax1dude. All Rights Reserved.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ * 
+ */
+public enum EnumFireKeyboardEvent {
+	KEY_DOWN, KEY_UP, KEY_REPEAT;
+}
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/internal/EnumFireMouseEvent.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/internal/EnumFireMouseEvent.java
new file mode 100644
index 00000000..5e29c32e
--- /dev/null
+++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/internal/EnumFireMouseEvent.java
@@ -0,0 +1,20 @@
+package net.lax1dude.eaglercraft.v1_8.internal;
+
+/**
+ * Copyright (c) 2024 lax1dude. All Rights Reserved.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ * 
+ */
+public enum EnumFireMouseEvent {
+	MOUSE_DOWN, MOUSE_UP, MOUSE_MOVE, MOUSE_WHEEL;
+}
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/internal/EnumPlatformANGLE.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/internal/EnumPlatformANGLE.java
index 051b5f53..43fae4df 100644
--- a/sources/main/java/net/lax1dude/eaglercraft/v1_8/internal/EnumPlatformANGLE.java
+++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/internal/EnumPlatformANGLE.java
@@ -18,6 +18,7 @@ package net.lax1dude.eaglercraft.v1_8.internal;
 public enum EnumPlatformANGLE {
 
 	DEFAULT(225281 /* GLFW_ANGLE_PLATFORM_TYPE_NONE */, "default", "Default"),
+	D3D9(225284 /* GLFW_ANGLE_PLATFORM_TYPE_D3D9 */, "d3d9", "Direct3D9"),
 	D3D11(225285 /* GLFW_ANGLE_PLATFORM_TYPE_D3D11 */, "d3d11", "Direct3D11"),
 	OPENGL(225282 /* GLFW_ANGLE_PLATFORM_TYPE_OPENGL */, "opengl", "OpenGL"),
 	OPENGLES(225283 /* GLFW_ANGLE_PLATFORM_TYPE_OPENGLES */, "opengles", "OpenGL ES"),
@@ -41,6 +42,8 @@ public enum EnumPlatformANGLE {
 	public static EnumPlatformANGLE fromId(String id) {
 		if(id.equals("d3d11") || id.equals("d3d") || id.equals("dx11")) {
 			return D3D11;
+		}else if(id.equals("d3d9") || id.equals("dx9")) {
+			return D3D9;
 		}else if(id.equals("opengl")) {
 			return OPENGL;
 		}else if(id.equals("opengles")) {
@@ -58,6 +61,8 @@ public enum EnumPlatformANGLE {
 		str = str.toLowerCase();
 		if(str.contains("direct3d11") || str.contains("d3d11")) {
 			return D3D11;
+		}else if(str.contains("direct3d9") || str.contains("d3d9")) {
+			return D3D9;
 		}else if(str.contains("opengl es")) {
 			return OPENGLES;
 		}else if(str.contains("opengl")) {
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/internal/EnumPlatformAgent.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/internal/EnumPlatformAgent.java
index 1ea4f444..dc0171e3 100644
--- a/sources/main/java/net/lax1dude/eaglercraft/v1_8/internal/EnumPlatformAgent.java
+++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/internal/EnumPlatformAgent.java
@@ -35,12 +35,15 @@ public enum EnumPlatformAgent {
 	}
 	
 	public static EnumPlatformAgent getFromUA(String ua) {
+		if(ua == null) {
+			return UNKNOWN;
+		}
 		ua = " " + ua.toLowerCase();
 		if(ua.contains(" edg/")) {
 			return EDGE;
 		}else if(ua.contains(" opr/")) {
 			return OPERA;
-		}else if(ua.contains(" chrome/")) {
+		}else if(ua.contains(" chrome/") || ua.contains(" chromium/")) {
 			return CHROME;
 		}else if(ua.contains(" firefox/")) {
 			return FIREFOX;
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/internal/EnumPlatformOS.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/internal/EnumPlatformOS.java
index b42f7321..bfa1eff3 100644
--- a/sources/main/java/net/lax1dude/eaglercraft/v1_8/internal/EnumPlatformOS.java
+++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/internal/EnumPlatformOS.java
@@ -42,6 +42,9 @@ public enum EnumPlatformOS {
 	}
 	
 	public static EnumPlatformOS getFromJVM(String osNameProperty) {
+		if(osNameProperty == null) {
+			return OTHER;
+		}
 		osNameProperty = osNameProperty.toLowerCase();
 		if(osNameProperty.contains("chrome")) {
 			return CHROMEBOOK_LINUX;
@@ -57,6 +60,9 @@ public enum EnumPlatformOS {
 	}
 	
 	public static EnumPlatformOS getFromUA(String ua) {
+		if(ua == null) {
+			return OTHER;
+		}
 		ua = " " + ua.toLowerCase();
 		if(ua.contains(" cros")) {
 			return CHROMEBOOK_LINUX;
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/relay/pkt/IPacket05ClientSuccess.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/internal/EnumTouchEvent.java
similarity index 55%
rename from sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/relay/pkt/IPacket05ClientSuccess.java
rename to sources/main/java/net/lax1dude/eaglercraft/v1_8/internal/EnumTouchEvent.java
index 240e9644..a94c6537 100644
--- a/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/relay/pkt/IPacket05ClientSuccess.java
+++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/internal/EnumTouchEvent.java
@@ -1,11 +1,7 @@
-package net.lax1dude.eaglercraft.v1_8.sp.relay.pkt;
-
-import java.io.DataInputStream;
-import java.io.DataOutputStream;
-import java.io.IOException;
+package net.lax1dude.eaglercraft.v1_8.internal;
 
 /**
- * Copyright (c) 2022 lax1dude. All Rights Reserved.
+ * Copyright (c) 2024 lax1dude. All Rights Reserved.
  * 
  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
@@ -19,27 +15,29 @@ import java.io.IOException;
  * POSSIBILITY OF SUCH DAMAGE.
  * 
  */
-public class IPacket05ClientSuccess extends IPacket {
+public enum EnumTouchEvent {
+	TOUCHSTART(0), TOUCHMOVE(1), TOUCHEND(2);
 	
-	public String clientId;
+	public final int id;
 	
-	public IPacket05ClientSuccess() {
+	private EnumTouchEvent(int id) {
+		this.id = id;
 	}
 	
-	public IPacket05ClientSuccess(String clientId) {
-		this.clientId = clientId;
-	}
-
-	public void read(DataInputStream input) throws IOException {
-		clientId = readASCII8(input);
-	}
-
-	public void write(DataOutputStream output) throws IOException {
-		writeASCII8(output, clientId);
+	public static EnumTouchEvent getById(int id) {
+		if(id >= 0 && id < lookup.length) {
+			return lookup[id];
+		}else {
+			return null;
+		}
 	}
 	
-	public int packetLength() {
-		return 1 + clientId.length();
-	}
+	private static final EnumTouchEvent[] lookup = new EnumTouchEvent[3];
 	
+	static {
+		EnumTouchEvent[] v = values();
+		for(int i = 0; i < v.length; ++i) {
+			lookup[v[i].id] = v[i];
+		}
+	}
 }
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/internal/EnumWebViewContentMode.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/internal/EnumWebViewContentMode.java
new file mode 100644
index 00000000..75ef2a4e
--- /dev/null
+++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/internal/EnumWebViewContentMode.java
@@ -0,0 +1,20 @@
+package net.lax1dude.eaglercraft.v1_8.internal;
+
+/**
+ * Copyright (c) 2024 lax1dude. All Rights Reserved.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ * 
+ */
+public enum EnumWebViewContentMode {
+	URL_BASED, BLOB_BASED;
+}
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/internal/GLObjectMap.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/internal/GLObjectMap.java
index 2c5acef2..680c1e09 100644
--- a/sources/main/java/net/lax1dude/eaglercraft/v1_8/internal/GLObjectMap.java
+++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/internal/GLObjectMap.java
@@ -71,4 +71,11 @@ public class GLObjectMap<T> {
 		values = new Object[size];
 		System.arraycopy(oldValues, 0, values, 0, oldSize);
 	}
+
+	public void clear() {
+		if(allocatedObjects == 0) return;
+		values = new Object[size];
+		insertIndex = 0;
+		allocatedObjects = 0;
+	}
 }
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/internal/GamepadConstants.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/internal/GamepadConstants.java
new file mode 100644
index 00000000..fbc04a55
--- /dev/null
+++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/internal/GamepadConstants.java
@@ -0,0 +1,134 @@
+package net.lax1dude.eaglercraft.v1_8.internal;
+
+/**
+ * Copyright (c) 2024 lax1dude. All Rights Reserved.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ * 
+ */
+public class GamepadConstants {
+
+	private static final String[] buttonNames = new String[24];
+	private static final String[] axisNames = new String[4];
+	private static final int[] eaglerButtonsToGLFW = new int[24];
+	private static final int[] glfwButtonsToEagler = new int[24];
+
+	public static final int GAMEPAD_NONE = -1;
+	public static final int GAMEPAD_A = 0;
+	public static final int GAMEPAD_B = 1;
+	public static final int GAMEPAD_X = 2;
+	public static final int GAMEPAD_Y = 3;
+	public static final int GAMEPAD_LEFT_BUTTON = 4;
+	public static final int GAMEPAD_RIGHT_BUTTON = 5;
+	public static final int GAMEPAD_LEFT_TRIGGER = 6;
+	public static final int GAMEPAD_RIGHT_TRIGGER = 7;
+	public static final int GAMEPAD_BACK = 8;
+	public static final int GAMEPAD_START = 9;
+	public static final int GAMEPAD_LEFT_STICK_BUTTON = 10;
+	public static final int GAMEPAD_RIGHT_STICK_BUTTON = 11;
+	public static final int GAMEPAD_DPAD_UP = 12;
+	public static final int GAMEPAD_DPAD_DOWN = 13;
+	public static final int GAMEPAD_DPAD_LEFT = 14;
+	public static final int GAMEPAD_DPAD_RIGHT = 15;
+	public static final int GAMEPAD_GUIDE = 16;
+
+	public static final int GAMEPAD_AXIS_NONE = -1;
+	public static final int GAMEPAD_AXIS_LEFT_STICK_X = 0;
+	public static final int GAMEPAD_AXIS_LEFT_STICK_Y = 1;
+	public static final int GAMEPAD_AXIS_RIGHT_STICK_X = 2;
+	public static final int GAMEPAD_AXIS_RIGHT_STICK_Y = 3;
+
+	private static final int GLFW_GAMEPAD_BUTTON_A = 0, GLFW_GAMEPAD_BUTTON_B = 1, GLFW_GAMEPAD_BUTTON_X = 2,
+			GLFW_GAMEPAD_BUTTON_Y = 3, GLFW_GAMEPAD_BUTTON_LEFT_BUMPER = 4, GLFW_GAMEPAD_BUTTON_RIGHT_BUMPER = 5,
+			GLFW_GAMEPAD_BUTTON_BACK = 6, GLFW_GAMEPAD_BUTTON_START = 7, GLFW_GAMEPAD_BUTTON_GUIDE = 8,
+			GLFW_GAMEPAD_BUTTON_LEFT_THUMB = 9, GLFW_GAMEPAD_BUTTON_RIGHT_THUMB = 10, GLFW_GAMEPAD_BUTTON_DPAD_UP = 11,
+			GLFW_GAMEPAD_BUTTON_DPAD_RIGHT = 12, GLFW_GAMEPAD_BUTTON_DPAD_DOWN = 13, GLFW_GAMEPAD_BUTTON_DPAD_LEFT = 14;
+
+	private static void registerBtn(int eaglerBtn, int glfwBtn, String name) {
+		if(eaglerButtonsToGLFW[eaglerBtn] != 0) throw new IllegalArgumentException("Duplicate eaglerButtonsToGLFW entry: " + eaglerBtn + " -> " + glfwBtn);
+		if(glfwBtn != -1 && glfwButtonsToEagler[glfwBtn] != 0) throw new IllegalArgumentException("Duplicate glfwButtonsToEAGLER entry: " + glfwBtn + " -> " + eaglerBtn);
+		eaglerButtonsToGLFW[eaglerBtn] = glfwBtn;
+		if(glfwBtn != -1) glfwButtonsToEagler[glfwBtn] = eaglerBtn;
+		if(buttonNames[eaglerBtn] != null) throw new IllegalArgumentException("Duplicate buttonNames entry: " + eaglerBtn);
+		buttonNames[eaglerBtn] = name;
+	}
+
+	private static void registerAxis(int eaglerAxis, String name) {
+		if(axisNames[eaglerAxis] != null) throw new IllegalArgumentException("Duplicate axisNames entry: " + eaglerAxis);
+		axisNames[eaglerAxis] = name;
+	}
+
+	static {
+		registerBtn(GAMEPAD_A, GLFW_GAMEPAD_BUTTON_A, "A");
+		registerBtn(GAMEPAD_B, GLFW_GAMEPAD_BUTTON_B, "B");
+		registerBtn(GAMEPAD_X, GLFW_GAMEPAD_BUTTON_X, "X");
+		registerBtn(GAMEPAD_Y, GLFW_GAMEPAD_BUTTON_Y, "Y");
+		registerBtn(GAMEPAD_LEFT_BUTTON, GLFW_GAMEPAD_BUTTON_LEFT_BUMPER, "Left Button");
+		registerBtn(GAMEPAD_LEFT_TRIGGER, -1, "Left Trigger");
+		registerBtn(GAMEPAD_RIGHT_BUTTON, GLFW_GAMEPAD_BUTTON_RIGHT_BUMPER, "Right Button");
+		registerBtn(GAMEPAD_RIGHT_TRIGGER, -1, "Right Trigger");
+		registerBtn(GAMEPAD_BACK, GLFW_GAMEPAD_BUTTON_BACK, "Back");
+		registerBtn(GAMEPAD_START, GLFW_GAMEPAD_BUTTON_START, "Start");
+		registerBtn(GAMEPAD_LEFT_STICK_BUTTON, GLFW_GAMEPAD_BUTTON_LEFT_THUMB, "L. Stick Button");
+		registerBtn(GAMEPAD_RIGHT_STICK_BUTTON, GLFW_GAMEPAD_BUTTON_RIGHT_THUMB, "R. Stick Button");
+		registerBtn(GAMEPAD_DPAD_UP, GLFW_GAMEPAD_BUTTON_DPAD_UP, "D-Pad Up");
+		registerBtn(GAMEPAD_DPAD_DOWN, GLFW_GAMEPAD_BUTTON_DPAD_DOWN, "D-Pad Down");
+		registerBtn(GAMEPAD_DPAD_LEFT, GLFW_GAMEPAD_BUTTON_DPAD_LEFT, "D-Pad Left");
+		registerBtn(GAMEPAD_DPAD_RIGHT, GLFW_GAMEPAD_BUTTON_DPAD_RIGHT, "D-Pad Right");
+		registerBtn(GAMEPAD_GUIDE, GLFW_GAMEPAD_BUTTON_GUIDE, "Guide");
+		registerAxis(GAMEPAD_AXIS_LEFT_STICK_X, "Left Stick X");
+		registerAxis(GAMEPAD_AXIS_LEFT_STICK_Y, "Left Stick Y");
+		registerAxis(GAMEPAD_AXIS_RIGHT_STICK_X, "Right Stick X");
+		registerAxis(GAMEPAD_AXIS_RIGHT_STICK_Y, "Right Stick Y");
+	}
+
+	public static int getEaglerButtonFromBrowser(int button) {
+		return button;
+	}
+
+	public static int getBrowserButtonFromEagler(int button) {
+		return button;
+	}
+
+	public static int getEaglerButtonFromGLFW(int button) {
+		if(button >= 0 && button < glfwButtonsToEagler.length) {
+			return glfwButtonsToEagler[button];
+		}else {
+			return -1;
+		}
+	}
+
+	public static int getGLFWButtonFromEagler(int button) {
+		if(button >= 0 && button < eaglerButtonsToGLFW.length) {
+			return eaglerButtonsToGLFW[button];
+		}else {
+			return -1;
+		}
+	}
+
+	public static String getButtonName(int button) {
+		if(button >= 0 && button < buttonNames.length) {
+			return buttonNames[button];
+		}else {
+			return "Button " + button;
+		}
+	}
+
+	public static String getAxisName(int button) {
+		if(button >= 0 && button < axisNames.length) {
+			return axisNames[button];
+		}else {
+			return "Axis " + button;
+		}
+	}
+
+}
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/internal/IClientConfigAdapter.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/internal/IClientConfigAdapter.java
index f28f78a4..fa6f350e 100644
--- a/sources/main/java/net/lax1dude/eaglercraft/v1_8/internal/IClientConfigAdapter.java
+++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/internal/IClientConfigAdapter.java
@@ -26,10 +26,12 @@ public interface IClientConfigAdapter {
 
 		public final String name;
 		public final String addr;
+		public final boolean hideAddress;
 
-		public DefaultServer(String name, String addr) {
+		public DefaultServer(String name, String addr, boolean hideAddress) {
 			this.name = name;
 			this.addr = addr;
+			this.hideAddress = hideAddress;
 		}
 
 	}
@@ -76,6 +78,24 @@ public interface IClientConfigAdapter {
 
 	boolean isEnableMinceraft();
 
+	boolean isEnableServerCookies();
+
+	boolean isAllowServerRedirects();
+
+	boolean isOpenDebugConsoleOnLaunch();
+
+	boolean isForceWebViewSupport();
+
+	boolean isEnableWebViewCSP();
+
+	boolean isAllowBootMenu();
+
+	boolean isForceProfanityFilter();
+
+	boolean isEaglerNoDelay();
+
+	boolean isRamdiskMode();
+
 	IClientConfigAdapterHooks getHooks();
 
 }
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/internal/IClientConfigAdapterHooks.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/internal/IClientConfigAdapterHooks.java
index e6d0a545..888e36f5 100644
--- a/sources/main/java/net/lax1dude/eaglercraft/v1_8/internal/IClientConfigAdapterHooks.java
+++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/internal/IClientConfigAdapterHooks.java
@@ -25,4 +25,6 @@ public interface IClientConfigAdapterHooks {
 
 	void callCrashReportHook(String crashReport, Consumer<String> customMessageCB);
 
+	void callScreenChangedHook(String screenName, int scaledWidth, int scaledHeight, int realWidth, int realHeight, int scaleFactor);
+
 }
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/internal/IEaglerFilesystem.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/internal/IEaglerFilesystem.java
new file mode 100644
index 00000000..8ec0faf4
--- /dev/null
+++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/internal/IEaglerFilesystem.java
@@ -0,0 +1,46 @@
+package net.lax1dude.eaglercraft.v1_8.internal;
+
+import net.lax1dude.eaglercraft.v1_8.internal.buffer.ByteBuffer;
+
+/**
+ * Copyright (c) 2024 lax1dude. All Rights Reserved.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ * 
+ */
+public interface IEaglerFilesystem {
+
+	String getFilesystemName();
+
+	String getInternalDBName();
+
+	boolean isRamdisk();
+
+	boolean eaglerDelete(String pathName);
+
+	ByteBuffer eaglerRead(String pathName);
+
+	void eaglerWrite(String pathName, ByteBuffer data);
+
+	boolean eaglerExists(String pathName);
+
+	boolean eaglerMove(String pathNameOld, String pathNameNew);
+
+	int eaglerCopy(String pathNameOld, String pathNameNew);
+
+	int eaglerSize(String pathName);
+
+	void eaglerIterate(String pathName, VFSFilenameIterator itr, boolean recursive);
+
+	void closeHandle();
+
+}
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/internal/IServerQuery.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/internal/IServerQuery.java
index ba97b26d..fc331c75 100644
--- a/sources/main/java/net/lax1dude/eaglercraft/v1_8/internal/IServerQuery.java
+++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/internal/IServerQuery.java
@@ -2,6 +2,8 @@ package net.lax1dude.eaglercraft.v1_8.internal;
 
 import org.json.JSONObject;
 
+import net.lax1dude.eaglercraft.v1_8.EagRuntime;
+
 /**
  * Copyright (c) 2022 lax1dude. All Rights Reserved.
  * 
@@ -42,6 +44,8 @@ public interface IServerQuery {
 
 	}
 
+	void update();
+
 	void send(String str);
 
 	default void send(JSONObject json) {
@@ -73,8 +77,8 @@ public interface IServerQuery {
 	EnumServerRateLimit getRateLimit();
 
 	default boolean awaitResponseAvailable(long timeout) {
-		long start = System.currentTimeMillis();
-		while(isOpen() && responsesAvailable() <= 0 && (timeout <= 0l || System.currentTimeMillis() - start < timeout)) {
+		long start = EagRuntime.steadyTimeMillis();
+		while(isOpen() && responsesAvailable() <= 0 && (timeout <= 0l || EagRuntime.steadyTimeMillis() - start < timeout)) {
 			try {
 				Thread.sleep(0l, 250000);
 			} catch (InterruptedException e) {
@@ -88,8 +92,8 @@ public interface IServerQuery {
 	}
 	
 	default boolean awaitResponseBinaryAvailable(long timeout) {
-		long start = System.currentTimeMillis();
-		while(isOpen() && binaryResponsesAvailable() <= 0 && (timeout <= 0l || System.currentTimeMillis() - start < timeout)) {
+		long start = EagRuntime.steadyTimeMillis();
+		while(isOpen() && binaryResponsesAvailable() <= 0 && (timeout <= 0l || EagRuntime.steadyTimeMillis() - start < timeout)) {
 			try {
 				Thread.sleep(0l, 250000);
 			} catch (InterruptedException e) {
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/relay/pkt/IPacket07LocalWorlds.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/internal/IWebSocketClient.java
similarity index 50%
rename from sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/relay/pkt/IPacket07LocalWorlds.java
rename to sources/main/java/net/lax1dude/eaglercraft/v1_8/internal/IWebSocketClient.java
index 923e1798..85aad5aa 100644
--- a/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/relay/pkt/IPacket07LocalWorlds.java
+++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/internal/IWebSocketClient.java
@@ -1,12 +1,9 @@
-package net.lax1dude.eaglercraft.v1_8.sp.relay.pkt;
+package net.lax1dude.eaglercraft.v1_8.internal;
 
-import java.io.DataInputStream;
-import java.io.IOException;
-import java.util.ArrayList;
 import java.util.List;
 
 /**
- * Copyright (c) 2022 lax1dude. All Rights Reserved.
+ * Copyright (c) 2024 lax1dude. All Rights Reserved.
  * 
  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
@@ -20,31 +17,46 @@ import java.util.List;
  * POSSIBILITY OF SUCH DAMAGE.
  * 
  */
-public class IPacket07LocalWorlds extends IPacket {
-	
-	public static class LocalWorld {
-		
-		public final String worldName;
-		public final String worldCode;
-		
-		public LocalWorld(String worldName, String worldCode) {
-			this.worldName = worldName;
-			this.worldCode = worldCode;
-		}
-		
-	}
-	
-	public final List<LocalWorld> worldsList;
-	
-	public IPacket07LocalWorlds() {
-		this.worldsList = new ArrayList();
-	}
+public interface IWebSocketClient {
+
+	EnumEaglerConnectionState getState();
+
+	boolean connectBlocking(int timeoutMS);
+
+	boolean isOpen();
+
+	boolean isClosed();
+
+	void close();
+
+	int availableFrames();
+
+	IWebSocketFrame getNextFrame();
+
+	List<IWebSocketFrame> getNextFrames();
+
+	void clearFrames();
+
+	int availableStringFrames();
+
+	IWebSocketFrame getNextStringFrame();
+
+	List<IWebSocketFrame> getNextStringFrames();
+
+	void clearStringFrames();
+
+	int availableBinaryFrames();
+
+	IWebSocketFrame getNextBinaryFrame();
+
+	List<IWebSocketFrame> getNextBinaryFrames();
+
+	void clearBinaryFrames();
+
+	void send(String str);
+
+	void send(byte[] bytes);
+
+	String getCurrentURI();
 
-	public void read(DataInputStream input) throws IOException {
-		int l = input.read();
-		for(int i = 0; i < l; ++i) {
-			worldsList.add(new LocalWorld(readASCII8(input), readASCII8(input)));
-		}
-	}
-	
 }
diff --git a/sources/lwjgl/java/net/lax1dude/eaglercraft/v1_8/internal/PlatformBufferFunctions.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/internal/IWebSocketFrame.java
similarity index 62%
rename from sources/lwjgl/java/net/lax1dude/eaglercraft/v1_8/internal/PlatformBufferFunctions.java
rename to sources/main/java/net/lax1dude/eaglercraft/v1_8/internal/IWebSocketFrame.java
index 6cab7cc5..7ecec0f1 100644
--- a/sources/lwjgl/java/net/lax1dude/eaglercraft/v1_8/internal/PlatformBufferFunctions.java
+++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/internal/IWebSocketFrame.java
@@ -1,10 +1,9 @@
 package net.lax1dude.eaglercraft.v1_8.internal;
 
-import net.lax1dude.eaglercraft.v1_8.internal.buffer.ByteBuffer;
-import net.lax1dude.eaglercraft.v1_8.internal.buffer.IntBuffer;
+import java.io.InputStream;
 
 /**
- * Copyright (c) 2022-2023 lax1dude, ayunami2000. All Rights Reserved.
+ * Copyright (c) 2024 lax1dude. All Rights Reserved.
  * 
  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
@@ -18,17 +17,18 @@ import net.lax1dude.eaglercraft.v1_8.internal.buffer.IntBuffer;
  * POSSIBILITY OF SUCH DAMAGE.
  * 
  */
-public class PlatformBufferFunctions {
+public interface IWebSocketFrame {
 
-	public static void put(ByteBuffer newBuffer, ByteBuffer flip) {
-		newBuffer.put(flip);
-	}
+	boolean isString();
+
+	String getString();
+
+	byte[] getByteArray();
+
+	InputStream getInputStream();
+
+	int getLength();
+
+	long getTimestamp();
 
-	public static void put(IntBuffer intBuffer, int index, int[] data) {
-		int p = intBuffer.position();
-		intBuffer.position(index);
-		intBuffer.put(data);
-		intBuffer.position(p);
-	}
-	
 }
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/internal/QueryResponse.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/internal/QueryResponse.java
index 3f95a0a6..f069acbe 100644
--- a/sources/main/java/net/lax1dude/eaglercraft/v1_8/internal/QueryResponse.java
+++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/internal/QueryResponse.java
@@ -2,6 +2,8 @@ package net.lax1dude.eaglercraft.v1_8.internal;
 
 import org.json.JSONObject;
 
+import net.lax1dude.eaglercraft.v1_8.EagRuntime;
+
 /**
  * Copyright (c) 2022 lax1dude. All Rights Reserved.
  * 
@@ -37,7 +39,7 @@ public class QueryResponse {
 		this.serverBrand = obj.getString("brand");
 		this.serverName = obj.getString("name");
 		this.serverTime = obj.getLong("time");
-		this.clientTime = System.currentTimeMillis();
+		this.clientTime = EagRuntime.steadyTimeMillis();
 		this.serverCracked = obj.optBoolean("cracked", false);
 	}
 	
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/internal/RamdiskFilesystemImpl.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/internal/RamdiskFilesystemImpl.java
new file mode 100644
index 00000000..9302a899
--- /dev/null
+++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/internal/RamdiskFilesystemImpl.java
@@ -0,0 +1,131 @@
+package net.lax1dude.eaglercraft.v1_8.internal;
+
+import java.util.Map;
+import java.util.TreeMap;
+
+import net.lax1dude.eaglercraft.v1_8.internal.buffer.ByteBuffer;
+
+/**
+ * Copyright (c) 2024 lax1dude. All Rights Reserved.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ * 
+ */
+public class RamdiskFilesystemImpl implements IEaglerFilesystem {
+
+	protected final String filesystemName;
+	protected final Map<String,byte[]> filesystemMap = new TreeMap<>();
+
+	public RamdiskFilesystemImpl(String filesystemName) {
+		this.filesystemName = filesystemName;
+	}
+
+	@Override
+	public String getFilesystemName() {
+		return filesystemName;
+	}
+
+	@Override
+	public String getInternalDBName() {
+		return "ramdisk:" + filesystemName;
+	}
+
+	@Override
+	public boolean isRamdisk() {
+		return true;
+	}
+
+	@Override
+	public boolean eaglerDelete(String pathName) {
+		return filesystemMap.remove(pathName) != null;
+	}
+
+	@Override
+	public ByteBuffer eaglerRead(String pathName) {
+		byte[] data = filesystemMap.get(pathName);
+		if(data != null) {
+			ByteBuffer buf = PlatformRuntime.castPrimitiveByteArray(data);
+			if(buf == null) {
+				buf = PlatformRuntime.allocateByteBuffer(data.length);
+				buf.put(data);
+				buf.flip();
+			}
+			return buf;
+		}else {
+			return null;
+		}
+	}
+
+	@Override
+	public void eaglerWrite(String pathName, ByteBuffer data) {
+		byte[] arr = PlatformRuntime.castNativeByteBuffer(data);
+		if(arr == null) {
+			arr = new byte[data.remaining()];
+			int i = data.position();
+			data.get(arr);
+			data.position(i);
+		}
+		filesystemMap.put(pathName, arr);
+	}
+
+	@Override
+	public boolean eaglerExists(String pathName) {
+		return filesystemMap.containsKey(pathName);
+	}
+
+	@Override
+	public boolean eaglerMove(String pathNameOld, String pathNameNew) {
+		byte[] dat = filesystemMap.remove(pathNameOld);
+		if(dat != null) {
+			filesystemMap.put(pathNameNew, dat);
+			return true;
+		}
+		return false;
+	}
+
+	@Override
+	public int eaglerCopy(String pathNameOld, String pathNameNew) {
+		byte[] dat = filesystemMap.get(pathNameOld);
+		if(dat != null) {
+			filesystemMap.put(pathNameNew, dat);
+			return dat.length;
+		}
+		return -1;
+	}
+
+	@Override
+	public int eaglerSize(String pathName) {
+		byte[] dat = filesystemMap.get(pathName);
+		return dat != null ? dat.length : -1;
+	}
+
+	@Override
+	public void eaglerIterate(String pathName, VFSFilenameIterator itr, boolean recursive) {
+		if(!recursive) {
+			eaglerIterate(pathName, new VFSFilenameIteratorNonRecursive(itr,
+					VFSFilenameIteratorNonRecursive.countSlashes(pathName) + 1), true);
+		}else {
+			boolean b = pathName.length() == 0;
+			for(String key : filesystemMap.keySet()) {
+				if(b || key.startsWith(pathName)) {
+					itr.next(key);
+				}
+			}
+		}
+	}
+
+	@Override
+	public void closeHandle() {
+		filesystemMap.clear();
+	}
+
+}
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/internal/ScreenRecordParameters.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/internal/ScreenRecordParameters.java
new file mode 100644
index 00000000..0c4d25ba
--- /dev/null
+++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/internal/ScreenRecordParameters.java
@@ -0,0 +1,37 @@
+package net.lax1dude.eaglercraft.v1_8.internal;
+
+import net.lax1dude.eaglercraft.v1_8.recording.EnumScreenRecordingCodec;
+
+/**
+ * Copyright (c) 2024 lax1dude. All Rights Reserved.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ * 
+ */
+public class ScreenRecordParameters {
+
+	public final EnumScreenRecordingCodec codec;
+	public final int resolutionDivisior;
+	public final int videoBitsPerSecond;
+	public final int audioBitsPerSecond;
+	public final int captureFrameRate;
+
+	public ScreenRecordParameters(EnumScreenRecordingCodec codec, int resolutionDivisior, int videoBitsPerSecond,
+			int audioBitsPerSecond, int captureFrameRate) {
+		this.codec = codec;
+		this.resolutionDivisior = resolutionDivisior;
+		this.videoBitsPerSecond = videoBitsPerSecond;
+		this.audioBitsPerSecond = audioBitsPerSecond;
+		this.captureFrameRate = captureFrameRate;
+	}
+
+}
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/relay/pkt/IPacket69Pong.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/internal/VFSFilenameIteratorNonRecursive.java
similarity index 53%
rename from sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/relay/pkt/IPacket69Pong.java
rename to sources/main/java/net/lax1dude/eaglercraft/v1_8/internal/VFSFilenameIteratorNonRecursive.java
index 589ca92a..d10a3afb 100644
--- a/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/relay/pkt/IPacket69Pong.java
+++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/internal/VFSFilenameIteratorNonRecursive.java
@@ -1,10 +1,7 @@
-package net.lax1dude.eaglercraft.v1_8.sp.relay.pkt;
-
-import java.io.DataInputStream;
-import java.io.IOException;
+package net.lax1dude.eaglercraft.v1_8.internal;
 
 /**
- * Copyright (c) 2022 lax1dude. All Rights Reserved.
+ * Copyright (c) 2022-2024 lax1dude. All Rights Reserved.
  * 
  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
@@ -18,28 +15,33 @@ import java.io.IOException;
  * POSSIBILITY OF SUCH DAMAGE.
  * 
  */
-public class IPacket69Pong extends IPacket {
+public class VFSFilenameIteratorNonRecursive implements VFSFilenameIterator {
 
-	public int protcolVersion;
-	public String comment;
-	public String brand;
-	
-	public IPacket69Pong(int protcolVersion, String comment, String brand) {
-		if(comment.length() > 255) {
-			comment = comment.substring(0, 256);
+	private final VFSFilenameIterator child;
+	private final int pathCount;
+
+	public VFSFilenameIteratorNonRecursive(VFSFilenameIterator child, int pathCount) {
+		this.child = child;
+		this.pathCount = pathCount;
+	}
+
+	@Override
+	public void next(String entry) {
+		int i = countSlashes(entry);
+		if(i == pathCount) {
+			child.next(entry);
 		}
-		this.protcolVersion = protcolVersion;
-		this.comment = comment;
-		this.brand = brand;
 	}
 
-	public IPacket69Pong() {
+	public static int countSlashes(String str) {
+		if(str.length() == 0) return -1;
+		int j = 0;
+		for(int i = 0, l = str.length(); i < l; ++i) {
+			if(str.charAt(i) == '/') {
+				++j;
+			}
+		}
+		return j;
 	}
-	
-	public void read(DataInputStream output) throws IOException {
-		protcolVersion = output.read();
-		comment = readASCII8(output);
-		brand = readASCII8(output);
-	}
-	
+
 }
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/internal/WebViewOptions.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/internal/WebViewOptions.java
new file mode 100644
index 00000000..6015c73f
--- /dev/null
+++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/internal/WebViewOptions.java
@@ -0,0 +1,67 @@
+package net.lax1dude.eaglercraft.v1_8.internal;
+
+import java.net.URI;
+import java.nio.charset.StandardCharsets;
+
+import net.lax1dude.eaglercraft.v1_8.EaglercraftUUID;
+
+/**
+ * Copyright (c) 2024 lax1dude. All Rights Reserved.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ * 
+ */
+public class WebViewOptions {
+
+	public EnumWebViewContentMode contentMode = EnumWebViewContentMode.BLOB_BASED;
+	public String fallbackTitle = "WebView";
+	public boolean scriptEnabled = false;
+	public boolean strictCSPEnable = true;
+	public boolean serverMessageAPIEnabled = false;
+	public URI url = null;
+	public byte[] blob = null;
+	public EaglercraftUUID permissionsOriginUUID = null;
+
+	public WebViewOptions() {
+	}
+
+	public WebViewOptions(boolean script, boolean serverMessageAPIEnabled, boolean strictCSPEnable, URI url) {
+		this.contentMode = EnumWebViewContentMode.URL_BASED;
+		this.scriptEnabled = script;
+		this.strictCSPEnable = strictCSPEnable;
+		this.serverMessageAPIEnabled = serverMessageAPIEnabled;
+		this.url = url;
+		this.permissionsOriginUUID = getURLOriginUUID(url);
+	}
+
+	public WebViewOptions(boolean script, boolean serverMessageAPIEnabled, boolean strictCSPEnable, byte[] data, EaglercraftUUID permissionsOriginUUID) {
+		this.contentMode = EnumWebViewContentMode.BLOB_BASED;
+		this.scriptEnabled = script;
+		this.strictCSPEnable = strictCSPEnable;
+		this.serverMessageAPIEnabled = serverMessageAPIEnabled;
+		this.blob = data;
+		this.permissionsOriginUUID = permissionsOriginUUID;
+	}
+
+	public static EaglercraftUUID getURLOriginUUID(URI url) {
+		return EaglercraftUUID.nameUUIDFromBytes(("URLOrigin:" + url.toString()).getBytes(StandardCharsets.UTF_8));
+	}
+
+	public static EaglercraftUUID getEmbedOriginUUID(byte[] sha256) {
+		byte[] vigg = "BlobOrigin:".getBytes(StandardCharsets.UTF_8);
+		byte[] eagler = new byte[sha256.length + vigg.length];
+		System.arraycopy(vigg, 0, eagler, 0, vigg.length);
+		System.arraycopy(sha256, 0, eagler, vigg.length, sha256.length);
+		return EaglercraftUUID.nameUUIDFromBytes(eagler);
+	}
+
+}
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/internal/buffer/Buffer.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/internal/buffer/Buffer.java
index 0aff7fc0..ee27b232 100644
--- a/sources/main/java/net/lax1dude/eaglercraft/v1_8/internal/buffer/Buffer.java
+++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/internal/buffer/Buffer.java
@@ -41,14 +41,14 @@ public interface Buffer {
 
 	boolean hasRemaining();
 
-	boolean isReadOnly();
-
 	boolean hasArray();
 
 	Object array();
 
-	int arrayOffset();
-
 	boolean isDirect();
 
+	static IndexOutOfBoundsException makeIOOBE(int idx) {
+		return new IndexOutOfBoundsException("Index out of range: " + idx);
+	}
+
 }
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/internal/buffer/ByteBuffer.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/internal/buffer/ByteBuffer.java
index b301853c..4ec39b18 100644
--- a/sources/main/java/net/lax1dude/eaglercraft/v1_8/internal/buffer/ByteBuffer.java
+++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/internal/buffer/ByteBuffer.java
@@ -18,12 +18,8 @@ package net.lax1dude.eaglercraft.v1_8.internal.buffer;
  */
 public interface ByteBuffer extends Buffer {
 
-	ByteBuffer slice();
-
 	ByteBuffer duplicate();
 
-	ByteBuffer asReadOnlyBuffer();
-
 	byte get();
 
 	ByteBuffer put(byte b);
@@ -42,10 +38,6 @@ public interface ByteBuffer extends Buffer {
 
 	ByteBuffer put(byte[] src);
 
-	int arrayOffset();
-
-	ByteBuffer compact();
-
 	char getChar();
 
 	ByteBuffer putChar(char value);
@@ -54,7 +46,7 @@ public interface ByteBuffer extends Buffer {
 
 	ByteBuffer putChar(int index, char value);
 
-	public abstract short getShort();
+	short getShort();
 
 	ByteBuffer putShort(short value);
 
@@ -106,4 +98,6 @@ public interface ByteBuffer extends Buffer {
 
 	ByteBuffer position(int newPosition);
 
+	byte[] array();
+
 }
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/internal/buffer/EaglerBufferInputStream.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/internal/buffer/EaglerBufferInputStream.java
index 383f83e8..d6fd8ee9 100644
--- a/sources/main/java/net/lax1dude/eaglercraft/v1_8/internal/buffer/EaglerBufferInputStream.java
+++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/internal/buffer/EaglerBufferInputStream.java
@@ -3,7 +3,6 @@ package net.lax1dude.eaglercraft.v1_8.internal.buffer;
 import java.io.IOException;
 import java.io.InputStream;
 
-
 /**
  * Copyright (c) 2022 lax1dude. All Rights Reserved.
  * 
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/internal/buffer/FloatBuffer.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/internal/buffer/FloatBuffer.java
index 73656cb9..ecaf25ff 100644
--- a/sources/main/java/net/lax1dude/eaglercraft/v1_8/internal/buffer/FloatBuffer.java
+++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/internal/buffer/FloatBuffer.java
@@ -17,12 +17,8 @@ package net.lax1dude.eaglercraft.v1_8.internal.buffer;
  */
 public interface FloatBuffer extends Buffer {
 
-	FloatBuffer slice();
-
 	FloatBuffer duplicate();
 
-	FloatBuffer asReadOnlyBuffer();
-
 	float get();
 
 	FloatBuffer put(float b);
@@ -45,10 +41,6 @@ public interface FloatBuffer extends Buffer {
 
 	FloatBuffer put(float[] src);
 
-	int getArrayOffset();
-
-	FloatBuffer compact();
-
 	boolean isDirect();
 
 	FloatBuffer mark();
@@ -64,6 +56,8 @@ public interface FloatBuffer extends Buffer {
 	FloatBuffer limit(int newLimit);
 
 	FloatBuffer position(int newPosition);
-	
+
+	float[] array();
+
 }
 
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/internal/buffer/IntBuffer.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/internal/buffer/IntBuffer.java
index 27b33607..0d96de55 100644
--- a/sources/main/java/net/lax1dude/eaglercraft/v1_8/internal/buffer/IntBuffer.java
+++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/internal/buffer/IntBuffer.java
@@ -17,12 +17,8 @@ package net.lax1dude.eaglercraft.v1_8.internal.buffer;
  */
 public interface IntBuffer extends Buffer {
 
-	IntBuffer slice();
-
 	IntBuffer duplicate();
 
-	IntBuffer asReadOnlyBuffer();
-
 	int get();
 
 	IntBuffer put(int b);
@@ -45,10 +41,6 @@ public interface IntBuffer extends Buffer {
 
 	IntBuffer put(int[] src);
 
-	int getArrayOffset();
-
-	IntBuffer compact();
-
 	boolean isDirect();
 
 	IntBuffer mark();
@@ -64,6 +56,8 @@ public interface IntBuffer extends Buffer {
 	IntBuffer limit(int newLimit);
 
 	IntBuffer position(int newPosition);
-	
+
+	int[] array();
+
 }
 
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/internal/buffer/ShortBuffer.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/internal/buffer/ShortBuffer.java
index b66bad62..56e54a54 100644
--- a/sources/main/java/net/lax1dude/eaglercraft/v1_8/internal/buffer/ShortBuffer.java
+++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/internal/buffer/ShortBuffer.java
@@ -17,12 +17,8 @@ package net.lax1dude.eaglercraft.v1_8.internal.buffer;
  */
 public interface ShortBuffer extends Buffer {
 
-	ShortBuffer slice();
-
 	ShortBuffer duplicate();
 
-	ShortBuffer asReadOnlyBuffer();
-
 	short get();
 
 	ShortBuffer put(short b);
@@ -45,10 +41,6 @@ public interface ShortBuffer extends Buffer {
 
 	ShortBuffer put(short[] src);
 
-	int getArrayOffset();
-
-	ShortBuffer compact();
-
 	boolean isDirect();
 
 	ShortBuffer mark();
@@ -64,5 +56,7 @@ public interface ShortBuffer extends Buffer {
 	ShortBuffer limit(int newLimit);
 
 	ShortBuffer position(int newPosition);
-	
+
+	short[] array();
+
 }
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/internal/vfs2/VFSFilenameIteratorImpl.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/internal/vfs2/VFSFilenameIteratorImpl.java
index 0311f158..6bfec45d 100644
--- a/sources/main/java/net/lax1dude/eaglercraft/v1_8/internal/vfs2/VFSFilenameIteratorImpl.java
+++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/internal/vfs2/VFSFilenameIteratorImpl.java
@@ -1,5 +1,6 @@
 package net.lax1dude.eaglercraft.v1_8.internal.vfs2;
 
+import net.lax1dude.eaglercraft.v1_8.internal.IEaglerFilesystem;
 import net.lax1dude.eaglercraft.v1_8.internal.VFSFilenameIterator;
 
 /**
@@ -19,15 +20,17 @@ import net.lax1dude.eaglercraft.v1_8.internal.VFSFilenameIterator;
  */
 class VFSFilenameIteratorImpl implements VFSFilenameIterator {
 
+	protected IEaglerFilesystem fs;
 	protected VFSIterator2 itr;
 
-	VFSFilenameIteratorImpl(VFSIterator2 itr) {
+	VFSFilenameIteratorImpl(IEaglerFilesystem fs, VFSIterator2 itr) {
+		this.fs = fs;
 		this.itr = itr;
 	}
 
 	@Override
 	public void next(String entry) {
-		itr.next(new VFile2(entry));
+		itr.next(VFile2.create(fs, entry));
 	}
 
 }
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/internal/vfs2/VFSListFilesIteratorImpl.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/internal/vfs2/VFSListFilesIteratorImpl.java
index 81d44766..0e937743 100644
--- a/sources/main/java/net/lax1dude/eaglercraft/v1_8/internal/vfs2/VFSListFilesIteratorImpl.java
+++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/internal/vfs2/VFSListFilesIteratorImpl.java
@@ -2,6 +2,7 @@ package net.lax1dude.eaglercraft.v1_8.internal.vfs2;
 
 import java.util.List;
 
+import net.lax1dude.eaglercraft.v1_8.internal.IEaglerFilesystem;
 import net.lax1dude.eaglercraft.v1_8.internal.VFSFilenameIterator;
 
 /**
@@ -21,15 +22,17 @@ import net.lax1dude.eaglercraft.v1_8.internal.VFSFilenameIterator;
  */
 class VFSListFilesIteratorImpl implements VFSFilenameIterator {
 
+	protected IEaglerFilesystem fs;
 	protected List<VFile2> list;
 
-	VFSListFilesIteratorImpl(List<VFile2> list) {
+	VFSListFilesIteratorImpl(IEaglerFilesystem fs, List<VFile2> list) {
+		this.fs = fs;
 		this.list = list;
 	}
 
 	@Override
 	public void next(String entry) {
-		list.add(new VFile2(entry));
+		list.add(VFile2.create(fs, entry));
 	}
 
 }
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/internal/vfs2/VFile2.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/internal/vfs2/VFile2.java
index 88c0ecf8..f1114238 100644
--- a/sources/main/java/net/lax1dude/eaglercraft/v1_8/internal/vfs2/VFile2.java
+++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/internal/vfs2/VFile2.java
@@ -5,9 +5,10 @@ import java.io.OutputStream;
 import java.nio.charset.StandardCharsets;
 import java.util.ArrayList;
 import java.util.List;
+import java.util.function.Supplier;
 
 import net.lax1dude.eaglercraft.v1_8.EagUtils;
-import net.lax1dude.eaglercraft.v1_8.internal.PlatformFilesystem;
+import net.lax1dude.eaglercraft.v1_8.internal.IEaglerFilesystem;
 import net.lax1dude.eaglercraft.v1_8.internal.PlatformRuntime;
 import net.lax1dude.eaglercraft.v1_8.internal.buffer.ByteBuffer;
 
@@ -31,6 +32,12 @@ public class VFile2 {
 	public static final String pathSeperator = "/";
 	public static final String[] altPathSeperator = new String[] { "\\" };
 	
+	static IEaglerFilesystem primaryFilesystem = null;
+	
+	public static void setPrimaryFilesystem(IEaglerFilesystem fs) {
+		primaryFilesystem = fs;
+	}
+	
 	public static String normalizePath(String p) {
 		for(int i = 0; i < altPathSeperator.length; ++i) {
 			p = p.replace(altPathSeperator[i], pathSeperator);
@@ -53,9 +60,11 @@ public class VFile2 {
 	}
 	
 	protected String path;
+	protected IEaglerFilesystem myFilesystem;
+	protected Supplier<IEaglerFilesystem> myFilesystemProvider;
 	
 	public static String createPath(Object... p) {
-		ArrayList<String> r = new ArrayList();
+		ArrayList<String> r = new ArrayList<>();
 		for(int i = 0; i < p.length; ++i) {
 			if(p[i] == null) {
 				continue;
@@ -94,13 +103,45 @@ public class VFile2 {
 		}
 	}
 	
-	public VFile2(Object... p) {
-		this.path = createPath(p);
+	public static VFile2 create(IEaglerFilesystem fs, Object... path) {
+		return new VFile2(createPath(path), fs);
+	}
+	
+	public static VFile2 create(Supplier<IEaglerFilesystem> fs, Object... path) {
+		return new VFile2(createPath(path), fs);
+	}
+	
+	public VFile2(Object... path) {
+		this(createPath(path), primaryFilesystem);
+	}
+	
+	private VFile2(String path, IEaglerFilesystem fs) {
+		this.path = path;
+		this.myFilesystem = fs;
+	}
+	
+	private VFile2(String path, Supplier<IEaglerFilesystem> fs) {
+		this.path = path;
+		this.myFilesystemProvider = fs;
+	}
+	
+	protected IEaglerFilesystem getFS() {
+		if(myFilesystem == null) {
+			if(myFilesystemProvider != null) {
+				myFilesystem = myFilesystemProvider.get();
+			}else {
+				myFilesystem = primaryFilesystem;
+			}
+			if(myFilesystem == null) {
+				throw new IllegalStateException("The filesystem has not been initialized yet!");
+			}
+		}
+		return myFilesystem;
 	}
 	
 	public InputStream getInputStream() {
 		assertNotRelative();
-		return new VFileInputStream(PlatformFilesystem.eaglerRead(path));
+		return new VFileInputStream(getFS().eaglerRead(path));
 	}
 	
 	public OutputStream getOutputStream() {
@@ -121,7 +162,7 @@ public class VFile2 {
 	}
 	
 	public boolean canRead() {
-		return !isRelative() && PlatformFilesystem.eaglerExists(path);
+		return !isRelative() && getFS().eaglerExists(path);
 	}
 	
 	public String getPath() {
@@ -160,15 +201,15 @@ public class VFile2 {
 	}
 	
 	public boolean exists() {
-		return !isRelative() && PlatformFilesystem.eaglerExists(path);
+		return !isRelative() && getFS().eaglerExists(path);
 	}
 	
 	public boolean delete() {
-		return !isRelative() && PlatformFilesystem.eaglerDelete(path);
+		return !isRelative() && getFS().eaglerDelete(path);
 	}
 	
 	public boolean renameTo(String p) {
-		if(!isRelative() && PlatformFilesystem.eaglerMove(path, p)) {
+		if(!isRelative() && getFS().eaglerMove(path, p)) {
 			return true;
 		}
 		return false;
@@ -179,7 +220,7 @@ public class VFile2 {
 	}
 	
 	public int length() {
-		return isRelative() ? -1 : PlatformFilesystem.eaglerSize(path);
+		return isRelative() ? -1 : getFS().eaglerSize(path);
 	}
 	
 	public byte[] getAllBytes() {
@@ -187,7 +228,7 @@ public class VFile2 {
 		if(!exists()) {
 			return null;
 		}
-		ByteBuffer readBuffer = PlatformFilesystem.eaglerRead(path);
+		ByteBuffer readBuffer = getFS().eaglerRead(path);
 		byte[] copyBuffer = PlatformRuntime.castNativeByteBuffer(readBuffer);
 		if(copyBuffer != null) {
 			return copyBuffer;
@@ -225,14 +266,14 @@ public class VFile2 {
 		assertNotRelative();
 		ByteBuffer copyBuffer = PlatformRuntime.castPrimitiveByteArray(bytes);
 		if(copyBuffer != null) {
-			PlatformFilesystem.eaglerWrite(path, copyBuffer);
+			getFS().eaglerWrite(path, copyBuffer);
 			return;
 		}
 		copyBuffer = PlatformRuntime.allocateByteBuffer(bytes.length);
 		try {
 			copyBuffer.put(bytes);
 			copyBuffer.flip();
-			PlatformFilesystem.eaglerWrite(path, copyBuffer);
+			getFS().eaglerWrite(path, copyBuffer);
 		}finally {
 			PlatformRuntime.freeByteBuffer(copyBuffer);
 		}
@@ -240,24 +281,30 @@ public class VFile2 {
 
 	public void iterateFiles(VFSIterator2 itr, boolean recursive) {
 		assertNotRelative();
-		PlatformFilesystem.eaglerIterate(path, new VFSFilenameIteratorImpl(itr), recursive);
+		IEaglerFilesystem fs = getFS();
+		fs.eaglerIterate(path, new VFSFilenameIteratorImpl(fs, itr), recursive);
 	}
 
 	public List<String> listFilenames(boolean recursive) {
-		List<String> ret = new ArrayList();
-		PlatformFilesystem.eaglerIterate(path, new VFSListFilenamesIteratorImpl(ret), recursive);
+		List<String> ret = new ArrayList<>();
+		getFS().eaglerIterate(path, new VFSListFilenamesIteratorImpl(ret), recursive);
 		return ret;
 	}
 
 	public List<VFile2> listFiles(boolean recursive) {
-		List<VFile2> ret = new ArrayList();
-		PlatformFilesystem.eaglerIterate(path, new VFSListFilesIteratorImpl(ret), recursive);
+		List<VFile2> ret = new ArrayList<>();
+		IEaglerFilesystem fs = getFS();
+		fs.eaglerIterate(path, new VFSListFilesIteratorImpl(fs, ret), recursive);
 		return ret;
 	}
 
 	public static int copyFile(VFile2 src, VFile2 dst) {
 		src.assertNotRelative();
 		dst.assertNotRelative();
-		return PlatformFilesystem.eaglerCopy(src.path, dst.path);
+		IEaglerFilesystem sfs = src.getFS();
+		if(sfs != dst.getFS()) {
+			throw new UnsupportedOperationException("Cannot copy file between filesystems!");
+		}
+		return sfs.eaglerCopy(src.path, dst.path);
 	}
 }
\ No newline at end of file
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/internal/vfs2/VFileOutputStream.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/internal/vfs2/VFileOutputStream.java
index 4333bfd4..8be71750 100644
--- a/sources/main/java/net/lax1dude/eaglercraft/v1_8/internal/vfs2/VFileOutputStream.java
+++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/internal/vfs2/VFileOutputStream.java
@@ -3,7 +3,6 @@ package net.lax1dude.eaglercraft.v1_8.internal.vfs2;
 import java.io.IOException;
 
 import net.lax1dude.eaglercraft.v1_8.EaglerOutputStream;
-import net.lax1dude.eaglercraft.v1_8.internal.PlatformFilesystem;
 import net.lax1dude.eaglercraft.v1_8.internal.PlatformRuntime;
 import net.lax1dude.eaglercraft.v1_8.internal.buffer.ByteBuffer;
 
@@ -41,7 +40,7 @@ class VFileOutputStream extends EaglerOutputStream {
 				copyBuffer.put(buf, 0, count);
 				copyBuffer.flip();
 				try {
-					PlatformFilesystem.eaglerWrite(vfsFile.path, copyBuffer);
+					vfsFile.getFS().eaglerWrite(vfsFile.path, copyBuffer);
 				}catch(Throwable t) {
 					throw new IOException("Could not write stream contents to file!", t);
 				}
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/json/JSONTypeProvider.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/json/JSONTypeProvider.java
index 8549dff0..3d0dd8be 100644
--- a/sources/main/java/net/lax1dude/eaglercraft/v1_8/json/JSONTypeProvider.java
+++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/json/JSONTypeProvider.java
@@ -54,10 +54,10 @@ import net.minecraft.world.gen.ChunkProviderSettings;
  */
 public class JSONTypeProvider {
 
-	private static final Map<Class<?>,JSONTypeSerializer<?,?>> serializers = new HashMap();
-	private static final Map<Class<?>,JSONTypeDeserializer<?,?>> deserializers = new HashMap();
+	private static final Map<Class<?>,JSONTypeSerializer<?,?>> serializers = new HashMap<>();
+	private static final Map<Class<?>,JSONTypeDeserializer<?,?>> deserializers = new HashMap<>();
 	
-	private static final List<JSONDataParserImpl> parsers = new ArrayList();
+	private static final List<JSONDataParserImpl> parsers = new ArrayList<>();
 
 	public static <J> J serialize(Object object) throws JSONException {
 		JSONTypeSerializer<Object,J> ser = (JSONTypeSerializer<Object,J>) serializers.get(object.getClass());
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/json/impl/SoundMapDeserializer.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/json/impl/SoundMapDeserializer.java
index ccbeca47..7e21dec9 100644
--- a/sources/main/java/net/lax1dude/eaglercraft/v1_8/json/impl/SoundMapDeserializer.java
+++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/json/impl/SoundMapDeserializer.java
@@ -30,7 +30,7 @@ public class SoundMapDeserializer implements JSONTypeDeserializer<JSONObject, So
 
 	@Override
 	public SoundMap deserialize(JSONObject json) throws JSONException {
-		Map<String, SoundList> soundsMap = new HashMap();
+		Map<String, SoundList> soundsMap = new HashMap<>();
 		for(String str : json.keySet()) {
 			soundsMap.put(str, JSONTypeProvider.deserialize(json.getJSONObject(str), SoundList.class));
 		}
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/log4j/LogManager.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/log4j/LogManager.java
index 3cc11e12..2d295d36 100644
--- a/sources/main/java/net/lax1dude/eaglercraft/v1_8/log4j/LogManager.java
+++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/log4j/LogManager.java
@@ -20,7 +20,7 @@ import java.util.Map;
  */
 public class LogManager {
 	
-	private static final Map<String,Logger> loggerInstances = new HashMap();
+	private static final Map<String,Logger> loggerInstances = new HashMap<>();
 	
 	public static final Object logLock = new Object();
 	public static Level logLevel = Level.DEBUG;
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/log4j/Logger.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/log4j/Logger.java
index 137ac39e..f734f35f 100644
--- a/sources/main/java/net/lax1dude/eaglercraft/v1_8/log4j/Logger.java
+++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/log4j/Logger.java
@@ -101,7 +101,7 @@ public class Logger {
 		log(Level.FATAL, msg);
 	}
 	
-	private static final SimpleDateFormat fmt = EagRuntime.fixDateFormat(new SimpleDateFormat("hh:mm:ss+SSS"));
+	private static final SimpleDateFormat fmt = new SimpleDateFormat("hh:mm:ss+SSS");
 	private static final Date dateInstance = new Date();
 	
 	public void log(Level level, String msg) {
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/minecraft/ChunkUpdateManager.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/minecraft/ChunkUpdateManager.java
index 7ea085ee..579a29dd 100644
--- a/sources/main/java/net/lax1dude/eaglercraft/v1_8/minecraft/ChunkUpdateManager.java
+++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/minecraft/ChunkUpdateManager.java
@@ -5,6 +5,7 @@ import static net.lax1dude.eaglercraft.v1_8.opengl.RealOpenGLEnums.*;
 import java.util.LinkedList;
 import java.util.List;
 
+import net.lax1dude.eaglercraft.v1_8.EagRuntime;
 import net.lax1dude.eaglercraft.v1_8.log4j.LogManager;
 import net.lax1dude.eaglercraft.v1_8.log4j.Logger;
 import net.lax1dude.eaglercraft.v1_8.opengl.EaglercraftGPU;
@@ -35,7 +36,7 @@ public class ChunkUpdateManager {
 	private int chunkUpdatesQueuedLast = 0;
 	private long chunkUpdatesTotalLastUpdate = 0l;
 	
-	private final List<ChunkCompileTaskGenerator> queue = new LinkedList();
+	private final List<ChunkCompileTaskGenerator> queue = new LinkedList<>();
 
 	public ChunkUpdateManager() {
 		worldVertexUploader = new WorldVertexBufferUploader();
@@ -108,8 +109,8 @@ public class ChunkUpdateManager {
 			return false;
 		}else {
 			boolean flag = false;
-			long millis = System.currentTimeMillis();
-			List<ChunkCompileTaskGenerator> droppedUpdates = new LinkedList();
+			long millis = EagRuntime.steadyTimeMillis();
+			List<ChunkCompileTaskGenerator> droppedUpdates = new LinkedList<>();
 			while(!queue.isEmpty()) {
 				ChunkCompileTaskGenerator generator = queue.remove(0);
 				
@@ -125,7 +126,7 @@ public class ChunkUpdateManager {
 				
 				++chunkUpdatesTotal;
 				
-				if(timeout < System.nanoTime()) {
+				if(timeout < EagRuntime.nanoTime()) {
 					break;
 				}
 			}
@@ -176,7 +177,7 @@ public class ChunkUpdateManager {
 		if (chunkcompiletaskgenerator == null) {
 			return true;
 		}
-		chunkcompiletaskgenerator.goddamnFuckingTimeout = System.currentTimeMillis();
+		chunkcompiletaskgenerator.goddamnFuckingTimeout = EagRuntime.steadyTimeMillis();
 		if(queue.size() < 100) {
 			chunkcompiletaskgenerator.addFinishRunnable(new Runnable() {
 				@Override
@@ -219,7 +220,7 @@ public class ChunkUpdateManager {
 	}
 
 	public String getDebugInfo() {
-		long millis = System.currentTimeMillis();
+		long millis = EagRuntime.steadyTimeMillis();
 		
 		if(millis - chunkUpdatesTotalLastUpdate > 500l) {
 			chunkUpdatesTotalLastUpdate = millis;
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/minecraft/EaglerFolderResourcePack.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/minecraft/EaglerFolderResourcePack.java
index 5a5ab3e0..e8ccb4f1 100644
--- a/sources/main/java/net/lax1dude/eaglercraft/v1_8/minecraft/EaglerFolderResourcePack.java
+++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/minecraft/EaglerFolderResourcePack.java
@@ -105,7 +105,7 @@ public class EaglerFolderResourcePack extends AbstractResourcePack {
 		}
 		try {
 			JSONArray json = (new JSONObject(str)).getJSONArray("resourcePacks");
-			List<EaglerFolderResourcePack> ret = new ArrayList(json.length());
+			List<EaglerFolderResourcePack> ret = new ArrayList<>(json.length());
 			for(int i = 0, l = json.length(); i < l; ++i) {
 				JSONObject jp = json.getJSONObject(i);
 				String folderName = jp.getString("folder");
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/minecraft/EaglerFontRenderer.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/minecraft/EaglerFontRenderer.java
index 61a52490..0e0f561b 100644
--- a/sources/main/java/net/lax1dude/eaglercraft/v1_8/minecraft/EaglerFontRenderer.java
+++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/minecraft/EaglerFontRenderer.java
@@ -30,6 +30,15 @@ public class EaglerFontRenderer extends FontRenderer {
 
 	private final int[] temporaryCodepointArray = new int[6553];
 
+	public static FontRenderer createSupportedFontRenderer(GameSettings gameSettingsIn, ResourceLocation location,
+			TextureManager textureManagerIn, boolean unicode) {
+		if(EaglercraftGPU.checkInstancingCapable()) {
+			return new EaglerFontRenderer(gameSettingsIn, location, textureManagerIn, unicode);
+		}else {
+			return new FontRenderer(gameSettingsIn, location, textureManagerIn, unicode);
+		}
+	}
+
 	public EaglerFontRenderer(GameSettings gameSettingsIn, ResourceLocation location, TextureManager textureManagerIn,
 			boolean unicode) {
 		super(gameSettingsIn, location, textureManagerIn, unicode);
@@ -116,15 +125,16 @@ public class EaglerFontRenderer extends FontRenderer {
 				++i;
 			} else {
 				int j = temporaryCodepointArray[i];
+				if(j > 255) continue;
 				
 				if (this.randomStyle && j != -1) {
 					int k = this.getCharWidth(c0);
-					String chars = "\u00c0\u00c1\u00c2\u00c8\u00ca\u00cb\u00cd\u00d3\u00d4\u00d5\u00da\u00df\u00e3\u00f5\u011f\u0130\u0131\u0152\u0153\u015e\u015f\u0174\u0175\u017e\u0207\u0000\u0000\u0000\u0000\u0000\u0000\u0000 !\"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\u0000\u00c7\u00fc\u00e9\u00e2\u00e4\u00e0\u00e5\u00e7\u00ea\u00eb\u00e8\u00ef\u00ee\u00ec\u00c4\u00c5\u00c9\u00e6\u00c6\u00f4\u00f6\u00f2\u00fb\u00f9\u00ff\u00d6\u00dc\u00f8\u00a3\u00d8\u00d7\u0192\u00e1\u00ed\u00f3\u00fa\u00f1\u00d1\u00aa\u00ba\u00bf\u00ae\u00ac\u00bd\u00bc\u00a1\u00ab\u00bb\u2591\u2592\u2593\u2502\u2524\u2561\u2562\u2556\u2555\u2563\u2551\u2557\u255d\u255c\u255b\u2510\u2514\u2534\u252c\u251c\u2500\u253c\u255e\u255f\u255a\u2554\u2569\u2566\u2560\u2550\u256c\u2567\u2568\u2564\u2565\u2559\u2558\u2552\u2553\u256b\u256a\u2518\u250c\u2588\u2584\u258c\u2590\u2580\u03b1\u03b2\u0393\u03c0\u03a3\u03c3\u03bc\u03c4\u03a6\u0398\u03a9\u03b4\u221e\u2205\u2208\u2229\u2261\u00b1\u2265\u2264\u2320\u2321\u00f7\u2248\u00b0\u2219\u00b7\u221a\u207f\u00b2\u25a0\u0000";
+					char[] chars = FontRenderer.codepointLookup;
 
 					char c1;
 					while (true) {
-						j = this.fontRandom.nextInt(chars.length());
-						c1 = chars.charAt(j);
+						j = this.fontRandom.nextInt(chars.length);
+						c1 = chars[j];
 						if (k == this.getCharWidth(c1)) {
 							break;
 						}
@@ -220,8 +230,7 @@ public class EaglerFontRenderer extends FontRenderer {
 
 	private boolean decodeASCIICodepointsAndValidate(String str) {
 		for(int i = 0, l = str.length(); i < l; ++i) {
-			int j = "\u00c0\u00c1\u00c2\u00c8\u00ca\u00cb\u00cd\u00d3\u00d4\u00d5\u00da\u00df\u00e3\u00f5\u011f\u0130\u0131\u0152\u0153\u015e\u015f\u0174\u0175\u017e\u0207\u0000\u0000\u0000\u0000\u0000\u0000\u0000 !\"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\u0000\u00c7\u00fc\u00e9\u00e2\u00e4\u00e0\u00e5\u00e7\u00ea\u00eb\u00e8\u00ef\u00ee\u00ec\u00c4\u00c5\u00c9\u00e6\u00c6\u00f4\u00f6\u00f2\u00fb\u00f9\u00ff\u00d6\u00dc\u00f8\u00a3\u00d8\u00d7\u0192\u00e1\u00ed\u00f3\u00fa\u00f1\u00d1\u00aa\u00ba\u00bf\u00ae\u00ac\u00bd\u00bc\u00a1\u00ab\u00bb\u2591\u2592\u2593\u2502\u2524\u2561\u2562\u2556\u2555\u2563\u2551\u2557\u255d\u255c\u255b\u2510\u2514\u2534\u252c\u251c\u2500\u253c\u255e\u255f\u255a\u2554\u2569\u2566\u2560\u2550\u256c\u2567\u2568\u2564\u2565\u2559\u2558\u2552\u2553\u256b\u256a\u2518\u250c\u2588\u2584\u258c\u2590\u2580\u03b1\u03b2\u0393\u03c0\u03a3\u03c3\u03bc\u03c4\u03a6\u0398\u03a9\u03b4\u221e\u2205\u2208\u2229\u2261\u00b1\u2265\u2264\u2320\u2321\u00f7\u2248\u00b0\u2219\u00b7\u221a\u207f\u00b2\u25a0\u0000\u00a7"
-				.indexOf(str.charAt(i));
+			int j = FontMappingHelper.lookupChar(str.charAt(i), true);
 			if(j != -1) {
 				temporaryCodepointArray[i] = j;
 			}else {
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/minecraft/EaglerTextureAtlasSprite.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/minecraft/EaglerTextureAtlasSprite.java
index ef9f92ae..125c6b6b 100644
--- a/sources/main/java/net/lax1dude/eaglercraft/v1_8/minecraft/EaglerTextureAtlasSprite.java
+++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/minecraft/EaglerTextureAtlasSprite.java
@@ -1,7 +1,6 @@
 package net.lax1dude.eaglercraft.v1_8.minecraft;
 
 import java.io.IOException;
-import java.util.ArrayList;
 import java.util.Iterator;
 import java.util.List;
 import java.util.concurrent.Callable;
@@ -229,10 +228,10 @@ public class EaglerTextureAtlasSprite {
 			int l = i;
 			this.height = this.width;
 			if (meta.getFrameCount() > 0) {
-				Iterator iterator = meta.getFrameIndexSet().iterator();
+				Iterator<Integer> iterator = meta.getFrameIndexSet().iterator();
 
 				while (iterator.hasNext()) {
-					int i1 = ((Integer) iterator.next()).intValue();
+					int i1 = iterator.next().intValue();
 					if (i1 >= j1) {
 						throw new RuntimeException("invalid frameindex " + i1);
 					}
@@ -243,7 +242,7 @@ public class EaglerTextureAtlasSprite {
 
 				this.animationMetadata = meta;
 			} else {
-				ArrayList arraylist = Lists.newArrayList();
+				List<AnimationFrame> arraylist = Lists.newArrayList();
 
 				for (int l1 = 0; l1 < j1; ++l1) {
 					this.framesTextureData.add(getFrameTextureData(aint, k1, l, l1));
@@ -258,10 +257,10 @@ public class EaglerTextureAtlasSprite {
 	}
 
 	public void generateMipmaps(int level) {
-		ArrayList arraylist = Lists.newArrayList();
+		List<int[][]> arraylist = Lists.newArrayList();
 
 		for (int i = 0; i < this.framesTextureData.size(); ++i) {
-			final int[][] aint = (int[][]) this.framesTextureData.get(i);
+			final int[][] aint = this.framesTextureData.get(i);
 			if (aint != null) {
 				try {
 					arraylist.add(TextureUtil.generateMipmapData(level, this.width, aint));
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/minecraft/EnumInputEvent.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/minecraft/EnumInputEvent.java
new file mode 100644
index 00000000..419e5366
--- /dev/null
+++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/minecraft/EnumInputEvent.java
@@ -0,0 +1,20 @@
+package net.lax1dude.eaglercraft.v1_8.minecraft;
+
+/**
+ * Copyright (c) 2024 lax1dude. All Rights Reserved.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ * 
+ */
+public enum EnumInputEvent {
+	CLIPBOARD_COPY, CLIPBOARD_PASTE;
+}
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/minecraft/FontMappingHelper.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/minecraft/FontMappingHelper.java
new file mode 100644
index 00000000..15e2553a
--- /dev/null
+++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/minecraft/FontMappingHelper.java
@@ -0,0 +1,525 @@
+package net.lax1dude.eaglercraft.v1_8.minecraft;
+
+/**
+ * Copyright (c) 2024 lax1dude. All Rights Reserved.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ * 
+ */
+public class FontMappingHelper {
+
+	public static int lookupChar(char c, boolean incSel) {
+		switch(c) {
+		case 167:
+			return incSel ? 256 : -1;
+		case 192:
+			return 0;
+		case 193:
+			return 1;
+		case 194:
+			return 2;
+		case 200:
+			return 3;
+		case 202:
+			return 4;
+		case 203:
+			return 5;
+		case 205:
+			return 6;
+		case 211:
+			return 7;
+		case 212:
+			return 8;
+		case 213:
+			return 9;
+		case 218:
+			return 10;
+		case 223:
+			return 11;
+		case 227:
+			return 12;
+		case 245:
+			return 13;
+		case 287:
+			return 14;
+		case 304:
+			return 15;
+		case 305:
+			return 16;
+		case 338:
+			return 17;
+		case 339:
+			return 18;
+		case 350:
+			return 19;
+		case 351:
+			return 20;
+		case 372:
+			return 21;
+		case 373:
+			return 22;
+		case 382:
+			return 23;
+		case 519:
+			return 24;
+		case 0:
+			return 25;
+		case 32:
+			return 32;
+		case 33:
+			return 33;
+		case 34:
+			return 34;
+		case 35:
+			return 35;
+		case 36:
+			return 36;
+		case 37:
+			return 37;
+		case 38:
+			return 38;
+		case 39:
+			return 39;
+		case 40:
+			return 40;
+		case 41:
+			return 41;
+		case 42:
+			return 42;
+		case 43:
+			return 43;
+		case 44:
+			return 44;
+		case 45:
+			return 45;
+		case 46:
+			return 46;
+		case 47:
+			return 47;
+		case 48:
+			return 48;
+		case 49:
+			return 49;
+		case 50:
+			return 50;
+		case 51:
+			return 51;
+		case 52:
+			return 52;
+		case 53:
+			return 53;
+		case 54:
+			return 54;
+		case 55:
+			return 55;
+		case 56:
+			return 56;
+		case 57:
+			return 57;
+		case 58:
+			return 58;
+		case 59:
+			return 59;
+		case 60:
+			return 60;
+		case 61:
+			return 61;
+		case 62:
+			return 62;
+		case 63:
+			return 63;
+		case 64:
+			return 64;
+		case 65:
+			return 65;
+		case 66:
+			return 66;
+		case 67:
+			return 67;
+		case 68:
+			return 68;
+		case 69:
+			return 69;
+		case 70:
+			return 70;
+		case 71:
+			return 71;
+		case 72:
+			return 72;
+		case 73:
+			return 73;
+		case 74:
+			return 74;
+		case 75:
+			return 75;
+		case 76:
+			return 76;
+		case 77:
+			return 77;
+		case 78:
+			return 78;
+		case 79:
+			return 79;
+		case 80:
+			return 80;
+		case 81:
+			return 81;
+		case 82:
+			return 82;
+		case 83:
+			return 83;
+		case 84:
+			return 84;
+		case 85:
+			return 85;
+		case 86:
+			return 86;
+		case 87:
+			return 87;
+		case 88:
+			return 88;
+		case 89:
+			return 89;
+		case 90:
+			return 90;
+		case 91:
+			return 91;
+		case 92:
+			return 92;
+		case 93:
+			return 93;
+		case 94:
+			return 94;
+		case 95:
+			return 95;
+		case 96:
+			return 96;
+		case 97:
+			return 97;
+		case 98:
+			return 98;
+		case 99:
+			return 99;
+		case 100:
+			return 100;
+		case 101:
+			return 101;
+		case 102:
+			return 102;
+		case 103:
+			return 103;
+		case 104:
+			return 104;
+		case 105:
+			return 105;
+		case 106:
+			return 106;
+		case 107:
+			return 107;
+		case 108:
+			return 108;
+		case 109:
+			return 109;
+		case 110:
+			return 110;
+		case 111:
+			return 111;
+		case 112:
+			return 112;
+		case 113:
+			return 113;
+		case 114:
+			return 114;
+		case 115:
+			return 115;
+		case 116:
+			return 116;
+		case 117:
+			return 117;
+		case 118:
+			return 118;
+		case 119:
+			return 119;
+		case 120:
+			return 120;
+		case 121:
+			return 121;
+		case 122:
+			return 122;
+		case 123:
+			return 123;
+		case 124:
+			return 124;
+		case 125:
+			return 125;
+		case 126:
+			return 126;
+		case 199:
+			return 128;
+		case 252:
+			return 129;
+		case 233:
+			return 130;
+		case 226:
+			return 131;
+		case 228:
+			return 132;
+		case 224:
+			return 133;
+		case 229:
+			return 134;
+		case 231:
+			return 135;
+		case 234:
+			return 136;
+		case 235:
+			return 137;
+		case 232:
+			return 138;
+		case 239:
+			return 139;
+		case 238:
+			return 140;
+		case 236:
+			return 141;
+		case 196:
+			return 142;
+		case 197:
+			return 143;
+		case 201:
+			return 144;
+		case 230:
+			return 145;
+		case 198:
+			return 146;
+		case 244:
+			return 147;
+		case 246:
+			return 148;
+		case 242:
+			return 149;
+		case 251:
+			return 150;
+		case 249:
+			return 151;
+		case 255:
+			return 152;
+		case 214:
+			return 153;
+		case 220:
+			return 154;
+		case 248:
+			return 155;
+		case 163:
+			return 156;
+		case 216:
+			return 157;
+		case 215:
+			return 158;
+		case 402:
+			return 159;
+		case 225:
+			return 160;
+		case 237:
+			return 161;
+		case 243:
+			return 162;
+		case 250:
+			return 163;
+		case 241:
+			return 164;
+		case 209:
+			return 165;
+		case 170:
+			return 166;
+		case 186:
+			return 167;
+		case 191:
+			return 168;
+		case 174:
+			return 169;
+		case 172:
+			return 170;
+		case 189:
+			return 171;
+		case 188:
+			return 172;
+		case 161:
+			return 173;
+		case 171:
+			return 174;
+		case 187:
+			return 175;
+		case 9617:
+			return 176;
+		case 9618:
+			return 177;
+		case 9619:
+			return 178;
+		case 9474:
+			return 179;
+		case 9508:
+			return 180;
+		case 9569:
+			return 181;
+		case 9570:
+			return 182;
+		case 9558:
+			return 183;
+		case 9557:
+			return 184;
+		case 9571:
+			return 185;
+		case 9553:
+			return 186;
+		case 9559:
+			return 187;
+		case 9565:
+			return 188;
+		case 9564:
+			return 189;
+		case 9563:
+			return 190;
+		case 9488:
+			return 191;
+		case 9492:
+			return 192;
+		case 9524:
+			return 193;
+		case 9516:
+			return 194;
+		case 9500:
+			return 195;
+		case 9472:
+			return 196;
+		case 9532:
+			return 197;
+		case 9566:
+			return 198;
+		case 9567:
+			return 199;
+		case 9562:
+			return 200;
+		case 9556:
+			return 201;
+		case 9577:
+			return 202;
+		case 9574:
+			return 203;
+		case 9568:
+			return 204;
+		case 9552:
+			return 205;
+		case 9580:
+			return 206;
+		case 9575:
+			return 207;
+		case 9576:
+			return 208;
+		case 9572:
+			return 209;
+		case 9573:
+			return 210;
+		case 9561:
+			return 211;
+		case 9560:
+			return 212;
+		case 9554:
+			return 213;
+		case 9555:
+			return 214;
+		case 9579:
+			return 215;
+		case 9578:
+			return 216;
+		case 9496:
+			return 217;
+		case 9484:
+			return 218;
+		case 9608:
+			return 219;
+		case 9604:
+			return 220;
+		case 9612:
+			return 221;
+		case 9616:
+			return 222;
+		case 9600:
+			return 223;
+		case 945:
+			return 224;
+		case 946:
+			return 225;
+		case 915:
+			return 226;
+		case 960:
+			return 227;
+		case 931:
+			return 228;
+		case 963:
+			return 229;
+		case 956:
+			return 230;
+		case 964:
+			return 231;
+		case 934:
+			return 232;
+		case 920:
+			return 233;
+		case 937:
+			return 234;
+		case 948:
+			return 235;
+		case 8734:
+			return 236;
+		case 8709:
+			return 237;
+		case 8712:
+			return 238;
+		case 8745:
+			return 239;
+		case 8801:
+			return 240;
+		case 177:
+			return 241;
+		case 8805:
+			return 242;
+		case 8804:
+			return 243;
+		case 8992:
+			return 244;
+		case 8993:
+			return 245;
+		case 247:
+			return 246;
+		case 8776:
+			return 247;
+		case 176:
+			return 248;
+		case 8729:
+			return 249;
+		case 183:
+			return 250;
+		case 8730:
+			return 251;
+		case 8319:
+			return 252;
+		case 178:
+			return 253;
+		case 9632:
+			return 254;
+		default:
+			return -1;
+		}
+	}
+
+}
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/minecraft/GuiButtonWithStupidIcons.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/minecraft/GuiButtonWithStupidIcons.java
new file mode 100644
index 00000000..80108669
--- /dev/null
+++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/minecraft/GuiButtonWithStupidIcons.java
@@ -0,0 +1,132 @@
+package net.lax1dude.eaglercraft.v1_8.minecraft;
+
+import static net.lax1dude.eaglercraft.v1_8.opengl.RealOpenGLEnums.*;
+
+import net.lax1dude.eaglercraft.v1_8.Mouse;
+import net.lax1dude.eaglercraft.v1_8.internal.EnumCursorType;
+import net.lax1dude.eaglercraft.v1_8.opengl.GlStateManager;
+import net.minecraft.client.Minecraft;
+import net.minecraft.client.gui.FontRenderer;
+import net.minecraft.client.gui.GuiButton;
+import net.minecraft.util.ResourceLocation;
+
+/**
+ * Copyright (c) 2024 lax1dude. All Rights Reserved.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ * 
+ */
+public class GuiButtonWithStupidIcons extends GuiButton {
+
+	protected ResourceLocation leftIcon;
+	protected float leftIconAspect;
+	protected ResourceLocation rightIcon;
+	protected float rightIconAspect;
+
+	public GuiButtonWithStupidIcons(int buttonId, int x, int y, int widthIn, int heightIn, String buttonText) {
+		super(buttonId, x, y, widthIn, heightIn, buttonText);
+	}
+
+	public GuiButtonWithStupidIcons(int buttonId, int x, int y, String buttonText) {
+		super(buttonId, x, y, buttonText);
+	}
+
+	public GuiButtonWithStupidIcons(int buttonId, int x, int y, int widthIn, int heightIn, String buttonText,
+			ResourceLocation leftIcon, float leftIconAspect, ResourceLocation rightIcon, float rightIconAspect) {
+		super(buttonId, x, y, widthIn, heightIn, buttonText);
+		this.leftIcon = leftIcon;
+		this.leftIconAspect = leftIconAspect;
+		this.rightIcon = rightIcon;
+		this.rightIconAspect = rightIconAspect;
+	}
+
+	public GuiButtonWithStupidIcons(int buttonId, int x, int y, String buttonText, ResourceLocation leftIcon,
+			float leftIconAspect, ResourceLocation rightIcon, float rightIconAspect) {
+		super(buttonId, x, y, buttonText);
+		this.leftIcon = leftIcon;
+		this.leftIconAspect = leftIconAspect;
+		this.rightIcon = rightIcon;
+		this.rightIconAspect = rightIconAspect;
+	}
+
+	public ResourceLocation getLeftIcon() {
+		return leftIcon;
+	}
+
+	public ResourceLocation getRightIcon() {
+		return rightIcon;
+	}
+
+	public void setLeftIcon(ResourceLocation leftIcon, float aspectRatio) {
+		this.leftIcon = leftIcon;
+		this.leftIconAspect = aspectRatio;
+	}
+
+	public void setRightIcon(ResourceLocation rightIcon, float aspectRatio) {
+		this.rightIcon = rightIcon;
+		this.rightIconAspect = aspectRatio;
+	}
+
+	public void drawButton(Minecraft mc, int mouseX, int mouseY) {
+		if (this.visible) {
+			FontRenderer fontrenderer = mc.fontRendererObj;
+			mc.getTextureManager().bindTexture(buttonTextures);
+			GlStateManager.color(1.0F, 1.0F, 1.0F, 1.0F);
+			this.hovered = mouseX >= this.xPosition && mouseY >= this.yPosition && mouseX < this.xPosition + this.width
+					&& mouseY < this.yPosition + this.height;
+			if (this.enabled && this.hovered) {
+				Mouse.showCursor(EnumCursorType.HAND);
+			}
+			int i = this.getHoverState(this.hovered);
+			GlStateManager.enableBlend();
+			GlStateManager.tryBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, 1, 0);
+			GlStateManager.blendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+			this.drawTexturedModalRect(this.xPosition, this.yPosition, 0, 46 + i * 20, this.width / 2, this.height);
+			this.drawTexturedModalRect(this.xPosition + this.width / 2, this.yPosition, 200 - this.width / 2,
+					46 + i * 20, this.width / 2, this.height);
+			this.mouseDragged(mc, mouseX, mouseY);
+			int j = 14737632;
+			if (!this.enabled) {
+				j = 10526880;
+			} else if (this.hovered) {
+				j = 16777120;
+			}
+
+			int strWidth = fontrenderer.getStringWidth(displayString);
+			int strWidthAdj = strWidth - (leftIcon != null ? (int) (16 * leftIconAspect) : 0)
+					+ (rightIcon != null ? (int) (16 * rightIconAspect) : 0);
+			this.drawString(fontrenderer, this.displayString, this.xPosition + (this.width - strWidthAdj) / 2,
+					this.yPosition + (this.height - 8) / 2, j);
+			if(leftIcon != null) {
+				GlStateManager.color(1.0f, 1.0f, 1.0f, 1.0f);
+				mc.getTextureManager().bindTexture(leftIcon);
+				GlStateManager.pushMatrix();
+				GlStateManager.translate(this.xPosition + (this.width - strWidthAdj) / 2 - 3 - 16 * leftIconAspect, this.yPosition + 2, 0.0f);
+				float f = 16.0f / 256.0f;
+				GlStateManager.scale(f * leftIconAspect, f, f);
+				this.drawTexturedModalRect(0, 0, 0, 0, 256, 256);
+				GlStateManager.popMatrix();
+			}
+			if(rightIcon != null) {
+				GlStateManager.color(1.0f, 1.0f, 1.0f, 1.0f);
+				mc.getTextureManager().bindTexture(rightIcon);
+				GlStateManager.pushMatrix();
+				GlStateManager.translate(this.xPosition + (this.width - strWidthAdj) / 2 + strWidth + 3, this.yPosition + 2, 0.0f);
+				float f = 16.0f / 256.0f;
+				GlStateManager.scale(f * rightIconAspect, f, f);
+				this.drawTexturedModalRect(0, 0, 0, 0, 256, 256);
+				GlStateManager.popMatrix();
+			}
+		}
+	}
+
+}
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/minecraft/GuiScreenGenericErrorMessage.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/minecraft/GuiScreenGenericErrorMessage.java
index f6fb104c..6e8fa027 100644
--- a/sources/main/java/net/lax1dude/eaglercraft/v1_8/minecraft/GuiScreenGenericErrorMessage.java
+++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/minecraft/GuiScreenGenericErrorMessage.java
@@ -1,5 +1,7 @@
 package net.lax1dude.eaglercraft.v1_8.minecraft;
 
+import org.apache.commons.lang3.StringUtils;
+
 import net.minecraft.client.gui.GuiButton;
 import net.minecraft.client.gui.GuiScreen;
 import net.minecraft.client.resources.I18n;
@@ -26,8 +28,8 @@ public class GuiScreenGenericErrorMessage extends GuiScreen {
 	private GuiScreen cont;
 
 	public GuiScreenGenericErrorMessage(String str1, String str2, GuiScreen cont) {
-		this.str1 = I18n.format(str1);
-		this.str2 = I18n.format(str2);
+		this.str1 = StringUtils.isAllEmpty(str1) ? "" : I18n.format(str1);
+		this.str2 = StringUtils.isAllEmpty(str2) ? "" : I18n.format(str2);
 		this.cont = cont;
 	}
 
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/minecraft/GuiScreenVisualViewport.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/minecraft/GuiScreenVisualViewport.java
new file mode 100644
index 00000000..3a0e5aed
--- /dev/null
+++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/minecraft/GuiScreenVisualViewport.java
@@ -0,0 +1,144 @@
+package net.lax1dude.eaglercraft.v1_8.minecraft;
+
+import net.lax1dude.eaglercraft.v1_8.Display;
+import net.lax1dude.eaglercraft.v1_8.opengl.GlStateManager;
+import net.minecraft.client.Minecraft;
+import net.minecraft.client.gui.GuiScreen;
+
+/**
+ * Copyright (c) 2024 lax1dude. All Rights Reserved.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ * 
+ */
+public class GuiScreenVisualViewport extends GuiScreen {
+
+	protected int offsetX;
+	protected int offsetY;
+
+	@Override
+	public final void setWorldAndResolution(Minecraft mc, int width, int height) {
+		Display.wasVisualViewportResized(); // clear state
+		offsetX = Display.getVisualViewportX() * width / mc.displayWidth;
+		offsetY = Display.getVisualViewportY() * height / mc.displayHeight;
+		setWorldAndResolution0(mc, Display.getVisualViewportW() * width / mc.displayWidth,
+				Display.getVisualViewportH() * height / mc.displayHeight);
+	}
+
+	protected void setWorldAndResolution0(Minecraft mc, int width, int height) {
+		super.setWorldAndResolution(mc, width, height);
+	}
+
+	@Override
+	public final void updateScreen() {
+		if(Display.wasVisualViewportResized()) {
+			setWorldAndResolution(mc, mc.scaledResolution.getScaledWidth(), mc.scaledResolution.getScaledHeight());
+		}
+		updateScreen0();
+	}
+
+	protected void updateScreen0() {
+		super.updateScreen();
+	}
+
+	@Override
+	public final void drawScreen(int i, int j, float var3) {
+		i -= offsetX;
+		j -= offsetY;
+		GlStateManager.pushMatrix();
+		GlStateManager.translate(offsetX, offsetY, 0.0f);
+		drawScreen0(i, j, var3);
+		GlStateManager.popMatrix();
+	}
+
+	protected void drawScreen0(int i, int j, float var3) {
+		super.drawScreen(i, j, var3);
+	}
+
+	@Override
+	protected final void mouseClicked(int parInt1, int parInt2, int parInt3) {
+		parInt1 -= offsetX;
+		parInt2 -= offsetY;
+		mouseClicked0(parInt1, parInt2, parInt3);
+	}
+
+	protected void mouseClicked0(int parInt1, int parInt2, int parInt3) {
+		super.mouseClicked(parInt1, parInt2, parInt3);
+	}
+
+	@Override
+	protected final void mouseReleased(int i, int j, int k) {
+		i -= offsetX;
+		j -= offsetY;
+		mouseReleased0(i, j, k);
+	}
+
+	protected void mouseReleased0(int i, int j, int k) {
+		super.mouseReleased(i, j, k);
+	}
+
+	@Override
+	protected final void mouseClickMove(int var1, int var2, int var3, long var4) {
+		var1 -= offsetX;
+		var2 -= offsetY;
+		mouseClickMove0(var1, var2, var3, var4);
+	}
+
+	protected void mouseClickMove0(int var1, int var2, int var3, long var4) {
+		super.mouseClickMove(var1, var2, var3, var4);
+	}
+
+	@Override
+	protected final void touchEndMove(int parInt1, int parInt2, int parInt3) {
+		parInt1 -= offsetX;
+		parInt2 -= offsetY;
+		touchEndMove0(parInt1, parInt2, parInt3);
+	}
+
+	protected void touchEndMove0(int parInt1, int parInt2, int parInt3) {
+		super.touchEndMove(parInt1, parInt2, parInt3);
+	}
+
+	@Override
+	protected final void touchMoved(int parInt1, int parInt2, int parInt3) {
+		parInt1 -= offsetX;
+		parInt2 -= offsetY;
+		touchMoved0(parInt1, parInt2, parInt3);
+	}
+
+	protected void touchMoved0(int parInt1, int parInt2, int parInt3) {
+		super.touchMoved(parInt1, parInt2, parInt3);
+	}
+
+	@Override
+	protected final void touchStarted(int parInt1, int parInt2, int parInt3) {
+		parInt1 -= offsetX;
+		parInt2 -= offsetY;
+		touchStarted0(parInt1, parInt2, parInt3);
+	}
+
+	protected void touchStarted0(int parInt1, int parInt2, int parInt3) {
+		super.touchStarted(parInt1, parInt2, parInt3);
+	}
+
+	@Override
+	protected void touchTapped(int parInt1, int parInt2, int parInt3) {
+		parInt1 -= offsetX;
+		parInt2 -= offsetY;
+		touchTapped0(parInt1, parInt2, parInt3);
+	}
+
+	protected void touchTapped0(int parInt1, int parInt2, int parInt3) {
+		super.touchTapped(parInt1, parInt2, parInt3);
+	}
+
+}
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/minecraft/TextureAnimationCache.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/minecraft/TextureAnimationCache.java
index fbf84e60..b20d3fc0 100644
--- a/sources/main/java/net/lax1dude/eaglercraft/v1_8/minecraft/TextureAnimationCache.java
+++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/minecraft/TextureAnimationCache.java
@@ -54,8 +54,8 @@ public class TextureAnimationCache {
 			for(int i = 0; i < cacheTextures.length; ++i) {
 				cacheTextures[i] = GlStateManager.generateTexture();
 				GlStateManager.bindTexture(cacheTextures[i]);
-				EaglercraftGPU.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
-				EaglercraftGPU.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
+				EaglercraftGPU.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+				EaglercraftGPU.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
 				EaglercraftGPU.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
 				EaglercraftGPU.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
 			}
@@ -123,6 +123,8 @@ public class TextureAnimationCache {
 		if(cacheTextures == null) {
 			throw new IllegalStateException("Cannot copy from uninitialized TextureAnimationCache");
 		}
+		GlStateManager.disableBlend();
+		GlStateManager.disableAlpha();
 		GlStateManager.bindTexture(cacheTextures[level]);
 		TextureCopyUtil.srcSize(width >> level, (height >> level) * frameCount);
 		TextureCopyUtil.blitTextureUsingViewports(0, h * animationFrame, dx, dy, w, h);
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/notifications/CachedNotifBadgeTexture.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/notifications/CachedNotifBadgeTexture.java
new file mode 100644
index 00000000..904e10ec
--- /dev/null
+++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/notifications/CachedNotifBadgeTexture.java
@@ -0,0 +1,46 @@
+package net.lax1dude.eaglercraft.v1_8.notifications;
+
+import java.util.List;
+
+import net.minecraft.util.IChatComponent;
+
+/**
+ * Copyright (c) 2024 lax1dude. All Rights Reserved.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ * 
+ */
+public class CachedNotifBadgeTexture {
+
+	public final int glTexture;
+	public final int scaleFactor;
+	public final int width;
+	public final int height;
+	public final List<ClickEventZone> cursorEvents;
+	public final IChatComponent rootClickEvent;
+	public final boolean hasClickEvents;
+	public final boolean hasHoverEvents;
+
+	protected CachedNotifBadgeTexture(int glTexture, int scaleFactor, int width, int height,
+			List<ClickEventZone> cursorEvents, IChatComponent rootClickEvent, boolean hasClickEvents,
+			boolean hasHoverEvents) {
+		this.glTexture = glTexture;
+		this.scaleFactor = scaleFactor;
+		this.width = width;
+		this.height = height;
+		this.cursorEvents = cursorEvents;
+		this.rootClickEvent = rootClickEvent;
+		this.hasClickEvents = hasClickEvents;
+		this.hasHoverEvents = hasHoverEvents;
+	}
+
+}
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/notifications/ClickEventZone.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/notifications/ClickEventZone.java
new file mode 100644
index 00000000..939a61f3
--- /dev/null
+++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/notifications/ClickEventZone.java
@@ -0,0 +1,41 @@
+package net.lax1dude.eaglercraft.v1_8.notifications;
+
+import net.minecraft.util.IChatComponent;
+
+/**
+ * Copyright (c) 2024 lax1dude. All Rights Reserved.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ * 
+ */
+public class ClickEventZone {
+
+	public final int posX;
+	public final int posY;
+	public final int width;
+	public final int height;
+	public final IChatComponent chatComponent;
+	public final boolean hasHoverEvent;
+	public final boolean hasClickEvent;
+
+	public ClickEventZone(int posX, int posY, int width, int height, IChatComponent chatComponent,
+			boolean hasHoverEvent, boolean hasClickEvent) {
+		this.posX = posX;
+		this.posY = posY;
+		this.width = width;
+		this.height = height;
+		this.chatComponent = chatComponent;
+		this.hasHoverEvent = hasHoverEvent;
+		this.hasClickEvent = hasClickEvent;
+	}
+
+}
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/notifications/GuiButtonNotifBell.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/notifications/GuiButtonNotifBell.java
new file mode 100644
index 00000000..fc72d217
--- /dev/null
+++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/notifications/GuiButtonNotifBell.java
@@ -0,0 +1,69 @@
+package net.lax1dude.eaglercraft.v1_8.notifications;
+
+import net.lax1dude.eaglercraft.v1_8.Mouse;
+import net.lax1dude.eaglercraft.v1_8.internal.EnumCursorType;
+import net.lax1dude.eaglercraft.v1_8.opengl.GlStateManager;
+import net.minecraft.client.Minecraft;
+import net.minecraft.client.gui.GuiButton;
+import net.minecraft.util.ResourceLocation;
+
+/**
+ * Copyright (c) 2024 lax1dude. All Rights Reserved.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ * 
+ */
+public class GuiButtonNotifBell extends GuiButton {
+
+	private static final ResourceLocation eaglerTextures = new ResourceLocation("eagler:gui/eagler_gui.png");
+
+	private int unread = 0;
+
+	public GuiButtonNotifBell(int buttonID, int xPos, int yPos) {
+		super(buttonID, xPos, yPos, 20, 20, "");
+	}
+
+	public void setUnread(int num) {
+		unread = num;
+	}
+
+	public void drawButton(Minecraft minecraft, int i, int j) {
+		if (this.visible) {
+			minecraft.getTextureManager().bindTexture(eaglerTextures);
+			GlStateManager.color(1.0F, 1.0F, 1.0F, 1.0F);
+			boolean flag = i >= this.xPosition && j >= this.yPosition && i < this.xPosition + this.width
+					&& j < this.yPosition + this.height;
+			int k = 0;
+			int c = 14737632;
+			if (flag) {
+				k += this.height;
+				c = 16777120;
+				Mouse.showCursor(EnumCursorType.HAND);
+			}
+
+			drawTexturedModalRect(xPosition, yPosition, unread > 0 ? 116 : 136, k, width, height);
+			
+			if(unread > 0) {
+				GlStateManager.pushMatrix();
+				GlStateManager.translate(xPosition + 15.5f, yPosition + 11.0f, 0.0f);
+				if(unread >= 10) {
+					GlStateManager.translate(0.0f, 1.0f, 0.0f);
+					GlStateManager.scale(0.5f, 0.5f, 0.5f);
+				}else {
+					GlStateManager.scale(0.75f, 0.75f, 0.75f);
+				}
+				drawCenteredString(minecraft.fontRendererObj, Integer.toString(unread), 0, 0, c);
+				GlStateManager.popMatrix();
+			}
+		}
+	}
+}
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/notifications/GuiScreenNotifications.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/notifications/GuiScreenNotifications.java
new file mode 100644
index 00000000..80876fb4
--- /dev/null
+++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/notifications/GuiScreenNotifications.java
@@ -0,0 +1,172 @@
+package net.lax1dude.eaglercraft.v1_8.notifications;
+
+import java.io.IOException;
+import java.util.List;
+
+import com.google.common.base.Predicate;
+import com.google.common.collect.Collections2;
+
+import net.lax1dude.eaglercraft.v1_8.EaglercraftUUID;
+import net.lax1dude.eaglercraft.v1_8.socket.protocol.pkt.server.SPacketNotifBadgeShowV4EAG.EnumBadgePriority;
+import net.minecraft.client.Minecraft;
+import net.minecraft.client.gui.GuiButton;
+import net.minecraft.client.gui.GuiScreen;
+import net.minecraft.client.resources.I18n;
+
+/**
+ * Copyright (c) 2024 lax1dude. All Rights Reserved.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ * 
+ */
+public class GuiScreenNotifications extends GuiScreen {
+
+	private static final String[] priorityLangKeys = new String[] {
+			"notifications.priority.low",
+			"notifications.priority.normal",
+			"notifications.priority.higher",
+			"notifications.priority.highest"
+	};
+
+	private static final int[] priorityOrder = new int[] {
+			0, 3, 2, 1
+	};
+
+	GuiScreen parent;
+	int selected;
+	GuiSlotNotifications slots;
+	GuiButton clearAllButton;
+	GuiButton priorityButton;
+	int showPriority = 0;
+	EnumBadgePriority selectedMaxPriority = EnumBadgePriority.LOW;
+	int lastUpdate = -1;
+
+	public GuiScreenNotifications(GuiScreen parent) {
+		this.parent = parent;
+	}
+
+	public void initGui() {
+		selected = -1;
+		buttonList.clear();
+		buttonList.add(new GuiButton(0, this.width / 2 + 54, this.height - 32, 100, 20, I18n.format("gui.done")));
+		buttonList.add(clearAllButton = new GuiButton(1, this.width / 2 - 154, this.height - 32, 100, 20,
+				I18n.format("notifications.clearAll")));
+		int i = priorityOrder[showPriority];
+		buttonList.add(priorityButton = new GuiButton(2, this.width / 2 - 50, this.height - 32, 100, 20,
+				I18n.format("notifications.priority", I18n.format(priorityLangKeys[i]))));
+		selectedMaxPriority = EnumBadgePriority.getByID(i);
+		slots = new GuiSlotNotifications(this);
+		lastUpdate = -69420;
+		updateList();
+		updateButtons();
+	}
+
+	void updateButtons() {
+		clearAllButton.enabled = !slots.currentDisplayNotifs.isEmpty();
+	}
+
+	void updateList() {
+		if(mc.thePlayer == null) return;
+		ServerNotificationManager mgr = mc.thePlayer.sendQueue.getNotifManager();
+		int verHash = showPriority | (mgr.getNotifListUpdateCount() << 2);
+		if(verHash != lastUpdate) {
+			lastUpdate = verHash;
+			EaglercraftUUID selectedUUID = null;
+			List<GuiSlotNotifications.NotifBadgeSlot> lst = slots.currentDisplayNotifs;
+			int oldSelectedId = selected;
+			if(oldSelectedId >= 0 && oldSelectedId < lst.size()) {
+				selectedUUID = lst.get(oldSelectedId).badge.badgeUUID;
+			}
+			lst.clear();
+			lst.addAll(Collections2.transform(Collections2.filter(mgr.getNotifLongHistory(), new Predicate<NotificationBadge>() {
+				@Override
+				public boolean apply(NotificationBadge input) {
+					return input.priority.priority >= priorityOrder[showPriority];
+				}
+			}), GuiSlotNotifications.NotifBadgeSlot::new));
+			selected = -1;
+			if(selectedUUID != null) {
+				for(int i = 0, l = lst.size(); i < l; ++i) {
+					if(selectedUUID.equals(lst.get(i).badge.badgeUUID)) {
+						selected = i;
+						break;
+					}
+				}
+			}
+			if(selected != -1) {
+				if(oldSelectedId != selected) {
+					slots.scrollBy((selected - oldSelectedId) * slots.getSlotHeight());
+				}
+			}
+			updateButtons();
+		}
+	}
+
+	public void updateScreen() {
+		if(mc.thePlayer == null) {
+			mc.displayGuiScreen(parent);
+			return;
+		}
+		updateList();
+	}
+
+	static Minecraft getMinecraft(GuiScreenNotifications screen) {
+		return screen.mc;
+	}
+
+	public void actionPerformed(GuiButton btn) {
+		switch(btn.id) {
+		case 0:
+			mc.displayGuiScreen(parent);
+			break;
+		case 1:
+			if(mc.thePlayer != null) {
+				ServerNotificationManager mgr = mc.thePlayer.sendQueue.getNotifManager();
+				mgr.removeAllNotifFromActiveList(mgr.getNotifLongHistory());
+				clearAllButton.enabled = false;
+			}
+			break;
+		case 2:
+			showPriority = (showPriority + 1) & 3;
+			int i = priorityOrder[showPriority];
+			priorityButton.displayString = I18n.format("notifications.priority", I18n.format(priorityLangKeys[i]));
+			selectedMaxPriority = EnumBadgePriority.getByID(i);
+			updateList();
+			break;
+		default:
+			break;
+		}
+	}
+
+	public void drawScreen(int par1, int par2, float par3) {
+		if(mc.thePlayer == null) return;
+		slots.drawScreen(par1, par2, par3);
+		this.drawCenteredString(fontRendererObj, I18n.format("notifications.title"), this.width / 2, 16, 16777215);
+		super.drawScreen(par1, par2, par3);
+	}
+
+	public void handleMouseInput() throws IOException {
+		super.handleMouseInput();
+		slots.handleMouseInput();
+	}
+
+	public void handleTouchInput() throws IOException {
+		super.handleTouchInput();
+		slots.handleTouchInput();
+	}
+
+	public void onGuiClosed() {
+		if(mc.thePlayer != null) {
+			mc.thePlayer.sendQueue.getNotifManager().commitUnreadFlag();
+		}
+	}
+}
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/notifications/GuiSlotNotifications.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/notifications/GuiSlotNotifications.java
new file mode 100644
index 00000000..e7b4ef3c
--- /dev/null
+++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/notifications/GuiSlotNotifications.java
@@ -0,0 +1,338 @@
+package net.lax1dude.eaglercraft.v1_8.notifications;
+
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+
+import net.lax1dude.eaglercraft.v1_8.opengl.GlStateManager;
+import net.lax1dude.eaglercraft.v1_8.socket.protocol.pkt.server.SPacketNotifBadgeShowV4EAG.EnumBadgePriority;
+import net.minecraft.client.audio.PositionedSoundRecord;
+import net.minecraft.client.gui.GuiSlot;
+import net.minecraft.client.gui.GuiUtilRenderComponents;
+import net.minecraft.event.ClickEvent;
+import net.minecraft.event.HoverEvent;
+import net.minecraft.util.ChatComponentText;
+import net.minecraft.util.EnumChatFormatting;
+import net.minecraft.util.IChatComponent;
+import net.minecraft.util.MathHelper;
+import net.minecraft.util.ResourceLocation;
+
+/**
+ * Copyright (c) 2024 lax1dude. All Rights Reserved.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ * 
+ */
+public class GuiSlotNotifications extends GuiSlot {
+
+	private static final ResourceLocation eaglerGui = new ResourceLocation("eagler:gui/eagler_gui.png");
+	private static final ResourceLocation largeNotifBk = new ResourceLocation("eagler:gui/notif_bk_large.png");
+
+	private static final SimpleDateFormat dateFormat = new SimpleDateFormat("hh:mm a");
+
+	final GuiScreenNotifications parent;
+	final List<NotifBadgeSlot> currentDisplayNotifs;
+
+	int mouseX;
+	int mouseY;
+
+	protected static class NotifBadgeSlot {
+		
+		protected final NotificationBadge badge;
+		protected final List<ClickEventZone> cursorEvents = new ArrayList<>();
+		protected int currentScreenX = -69420;
+		protected int currentScreenY = -69420;
+		
+		protected NotifBadgeSlot(NotificationBadge badge) {
+			this.badge = badge;
+		}
+		
+	}
+
+	public GuiSlotNotifications(GuiScreenNotifications parent) {
+		super(GuiScreenNotifications.getMinecraft(parent), parent.width, parent.height, 32, parent.height - 44, 68);
+		this.parent = parent;
+		this.currentDisplayNotifs = new ArrayList<>();
+	}
+
+	@Override
+	protected int getSize() {
+		return currentDisplayNotifs.size();
+	}
+
+	@Override
+	protected void elementClicked(int id, boolean doubleClk, int xx, int yy) {
+		if(selectedElement != id) return; //workaround for vanilla bs
+		if(id < currentDisplayNotifs.size()) {
+			NotifBadgeSlot slot = currentDisplayNotifs.get(id);
+			if(slot.currentScreenY != -69420) {
+				int w = getListWidth();
+				int localX = xx - slot.currentScreenX;
+				int localY = yy - slot.currentScreenY;
+				if(localX >= w - 22 && localX < w - 5 && localY >= 5 && localY < 21) {
+					slot.badge.removeNotif();
+					mc.getSoundHandler().playSound(PositionedSoundRecord.create(new ResourceLocation("gui.button.press"), 1.0F));
+					return;
+				}
+				IChatComponent cmp = slot.badge.bodyComponent;
+				if(cmp != null) {
+					if(doubleClk) {
+						if (cmp.getChatStyle().getChatClickEvent() != null
+								&& cmp.getChatStyle().getChatClickEvent().getAction().shouldAllowInChat()) {
+							if(parent.handleComponentClick(cmp)) {
+								mc.getSoundHandler().playSound(PositionedSoundRecord.create(new ResourceLocation("gui.button.press"), 1.0F));
+								return;
+							}
+						}
+					}else {
+						if(parent.selected != id) {
+							parent.selected = id;
+						}else {
+							List<ClickEventZone> cursorEvents = slot.cursorEvents;
+							if(cursorEvents != null && !cursorEvents.isEmpty()) {
+								for(int j = 0, m = cursorEvents.size(); j < m; ++j) {
+									ClickEventZone evt = cursorEvents.get(j);
+									if(evt.hasClickEvent) {
+										int offsetPosX = slot.currentScreenX + evt.posX;
+										int offsetPosY = slot.currentScreenY + evt.posY;
+										if(xx >= offsetPosX && yy >= offsetPosY && xx < offsetPosX + evt.width && yy < offsetPosY + evt.height) {
+											if(parent.handleComponentClick(evt.chatComponent)) {
+												mc.getSoundHandler().playSound(PositionedSoundRecord.create(new ResourceLocation("gui.button.press"), 1.0F));
+												return;
+											}
+										}
+									}
+								}
+							}
+						}
+					}
+				}
+			}
+		}
+	}
+
+	@Override
+	protected boolean isSelected(int var1) {
+		return var1 == parent.selected;
+	}
+
+	@Override
+	protected void drawBackground() {
+		parent.drawBackground(0);
+	}
+
+	@Override
+	protected void drawSlot(int id, int xx, int yy, int width, int height, int ii) {
+		if(id < currentDisplayNotifs.size()) {
+			NotifBadgeSlot slot = currentDisplayNotifs.get(id);
+			slot.currentScreenX = xx;
+			slot.currentScreenY = yy;
+			NotificationBadge bd = slot.badge;
+			if(yy + 32 > this.top && yy + 32 < this.bottom) {
+				bd.markRead();
+			}
+			GlStateManager.pushMatrix();
+			GlStateManager.translate(xx, yy, 0.0f);
+			mc.getTextureManager().bindTexture(largeNotifBk);
+			int badgeWidth = getListWidth() - 4;
+			int badgeHeight = getSlotHeight() - 4;
+			float r = ((bd.backgroundColor >> 16) & 0xFF) * 0.00392156f;
+			float g = ((bd.backgroundColor >> 8) & 0xFF) * 0.00392156f;
+			float b = (bd.backgroundColor & 0xFF) * 0.00392156f;
+			if(parent.selected != id) {
+				r *= 0.85f;
+				g *= 0.85f;
+				b *= 0.85f;
+			}
+			GlStateManager.color(r, g, b, 1.0f);
+			parent.drawTexturedModalRect(0, 0, 0, bd.unreadFlagRender ? 64 : 0, badgeWidth - 32, 64);
+			parent.drawTexturedModalRect(badgeWidth - 32, 0, 224, bd.unreadFlagRender ? 64 : 0, 32, 64);
+			mc.getTextureManager().bindTexture(eaglerGui);
+			if(bd.priority == EnumBadgePriority.LOW) {
+				parent.drawTexturedModalRect(badgeWidth - 21, badgeHeight - 21, 192, 176, 16, 16);
+			}
+			GlStateManager.color(1.0f, 1.0f, 1.0f, 1.0f);
+			
+			switch(bd.priority) {
+			default:
+				break;
+			case NORMAL:
+				parent.drawTexturedModalRect(badgeWidth - 21, badgeHeight - 21, 208, 176, 16, 16);
+				break;
+			case HIGHER:
+				parent.drawTexturedModalRect(badgeWidth - 21, badgeHeight - 21, 224, 176, 16, 16);
+				break;
+			case HIGHEST:
+				parent.drawTexturedModalRect(badgeWidth - 21, badgeHeight - 21, 240, 176, 16, 16);
+				break;
+			}
+			
+			int bodyYOffset = 16;
+					
+			int leftPadding = 6;
+			int rightPadding = 26;
+			
+			int mainIconSW = 32;
+			boolean mainIconEn = bd.mainIcon != null && bd.mainIcon.isValid();
+			if(mainIconEn) {
+				int iw = bd.mainIcon.texture.getWidth();
+				int ih = bd.mainIcon.texture.getHeight();
+				float iaspect = (float)iw / (float)ih;
+				mainIconSW = (int)(32 * iaspect);
+				leftPadding += Math.min(mainIconSW, 64) + 3;
+			}
+			
+			int textZoneWidth = badgeWidth - leftPadding - rightPadding;
+			
+			if(mainIconEn) {
+				mc.getTextureManager().bindTexture(bd.mainIcon.resource);
+				ServerNotificationRenderer.drawTexturedRect(6, bodyYOffset, mainIconSW, 32);
+			}
+
+			boolean titleIconEn = bd.titleIcon != null && bd.titleIcon.isValid();
+			if(titleIconEn) {
+				mc.getTextureManager().bindTexture(bd.titleIcon.resource);
+				ServerNotificationRenderer.drawTexturedRect(6, 5, 8, 8);
+			}
+			
+			String titleText = "";
+			IChatComponent titleComponent = bd.getTitleProfanityFilter();
+			if(titleComponent != null) {
+				titleText = titleComponent.getFormattedText();
+			}
+			
+			titleText += EnumChatFormatting.GRAY + (titleText.length() > 0 ? " @ " : "@ ")
+					+ (bd.unreadFlagRender ? EnumChatFormatting.YELLOW : EnumChatFormatting.GRAY)
+					+ formatAge(bd.serverTimestamp);
+
+			GlStateManager.pushMatrix();
+			GlStateManager.translate(6 + (titleIconEn ? 10 : 0), 6, 0.0f);
+			GlStateManager.scale(0.75f, 0.75f, 0.75f);
+			mc.fontRendererObj.drawStringWithShadow(titleText, 0, 0, bd.titleTxtColor);
+			GlStateManager.popMatrix();
+			
+			String sourceText = null;
+			IChatComponent sourceComponent = bd.getSourceProfanityFilter();
+			if(sourceComponent != null) {
+				sourceText = sourceComponent.getFormattedText();
+				if(sourceText.length() == 0) {
+					sourceText = null;
+				}
+			}
+			
+			List<IChatComponent> bodyLines = null;
+			float bodyFontSize = (sourceText != null || titleIconEn) ? 0.75f : 1.0f;
+			IChatComponent bodyComponent = bd.getBodyProfanityFilter();
+			if(bodyComponent != null) {
+				bodyLines = GuiUtilRenderComponents.func_178908_a(bodyComponent, (int) (textZoneWidth / bodyFontSize),
+						mc.fontRendererObj, true, true);
+				
+				int maxHeight = badgeHeight - (sourceText != null ? 32 : 22);
+				int maxLines = MathHelper.floor_float(maxHeight / (9 * bodyFontSize));
+				if(bodyLines.size() > maxLines) {
+					bodyLines = bodyLines.subList(0, maxLines);
+					IChatComponent cmp = bodyLines.get(maxLines - 1);
+					List<IChatComponent> siblings = cmp.getSiblings();
+					IChatComponent dots = new ChatComponentText("...");
+					if(siblings != null && siblings.size() > 0) {
+						dots.setChatStyle(siblings.get(siblings.size() - 1).getChatStyle());
+					}
+					cmp.appendSibling(dots);
+				}
+			}
+			
+			slot.cursorEvents.clear();
+			if(bodyLines != null && !bodyLines.isEmpty()) {
+				GlStateManager.pushMatrix();
+				GlStateManager.translate(leftPadding, bodyYOffset, 0.0f);
+				int l = bodyLines.size();
+				GlStateManager.scale(bodyFontSize, bodyFontSize, bodyFontSize);
+				IChatComponent toolTip = null;
+				for(int i = 0; i < l; ++i) {
+					int startXLocal = 0;
+					int startXReal = leftPadding;
+					for(IChatComponent comp : bodyLines.get(i)) {
+						int w = mc.fontRendererObj.drawStringWithShadow(
+								comp.getChatStyle().getFormattingCode() + comp.getUnformattedTextForChat(), startXLocal,
+								i * 9, bd.bodyTxtColor) - startXLocal;
+						ClickEvent clickEvent = comp.getChatStyle().getChatClickEvent();
+						HoverEvent hoverEvent = toolTip == null ? comp.getChatStyle().getChatHoverEvent() : null;
+						if(clickEvent != null && !clickEvent.getAction().shouldAllowInChat()) {
+							clickEvent = null;
+						}
+						if(hoverEvent != null && !hoverEvent.getAction().shouldAllowInChat()) {
+							hoverEvent = null;
+						}
+						if(clickEvent != null) {
+							slot.cursorEvents.add(new ClickEventZone(startXReal + (int) (startXLocal * bodyFontSize),
+									bodyYOffset + (int) (i * 9 * bodyFontSize), (int) (w * bodyFontSize),
+									(int) (9 * bodyFontSize), comp, clickEvent != null, hoverEvent != null));
+						}
+						if(hoverEvent != null) {
+							int px = xx + startXReal + (int) (startXLocal * bodyFontSize);
+							int py = yy + bodyYOffset + (int) (i * 9 * bodyFontSize);
+							if (mouseX >= px && mouseX < px + (int) (w * bodyFontSize) && mouseY >= py
+									&& mouseY < py + (int) (9 * bodyFontSize)) {
+								toolTip = comp;
+							}
+						}
+						startXLocal += w;
+					}
+				}
+				GlStateManager.popMatrix();
+				if(toolTip != null) {
+					parent.handleComponentHover(toolTip, mouseX - xx, mouseY - yy);
+				}
+			}
+			
+			if(sourceText != null) {
+				GlStateManager.pushMatrix();
+				GlStateManager.translate(badgeWidth - 21, badgeHeight - 5, 0.0f);
+				GlStateManager.scale(0.75f, 0.75f, 0.75f);
+				mc.fontRendererObj.drawStringWithShadow(sourceText, -mc.fontRendererObj.getStringWidth(sourceText) - 4, -10, bd.sourceTxtColor);
+				GlStateManager.popMatrix();
+			}
+			
+			GlStateManager.popMatrix();
+		}
+	}
+
+	private String formatAge(long serverTimestamp) {
+		long cur = System.currentTimeMillis();
+		long daysAgo = Math.round((cur - serverTimestamp) / 86400000.0);
+		String ret = dateFormat.format(new Date(serverTimestamp));
+		if(daysAgo > 0l) {
+			ret += " (" + daysAgo + (daysAgo == 1l ? " day" : " days") + " ago)";
+		}else if(daysAgo < 0l) {
+			ret += " (in " + -daysAgo + (daysAgo == -1l ? " day" : " days") + ")";
+		}
+		return ret;
+	}
+
+	@Override
+	public int getListWidth() {
+		return 224;
+	}
+
+	@Override
+	public void drawScreen(int mouseXIn, int mouseYIn, float parFloat1) {
+		mouseX = mouseXIn;
+		mouseY = mouseYIn;
+		for(int i = 0, l = currentDisplayNotifs.size(); i < l; ++i) {
+			NotifBadgeSlot slot = currentDisplayNotifs.get(i);
+			slot.currentScreenX = -69420;
+			slot.currentScreenY = -69420;
+		}
+		super.drawScreen(mouseXIn, mouseYIn, parFloat1);
+	}
+}
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/notifications/NotificationBadge.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/notifications/NotificationBadge.java
new file mode 100644
index 00000000..6f17cb0b
--- /dev/null
+++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/notifications/NotificationBadge.java
@@ -0,0 +1,171 @@
+package net.lax1dude.eaglercraft.v1_8.notifications;
+
+import net.lax1dude.eaglercraft.v1_8.EagRuntime;
+import net.lax1dude.eaglercraft.v1_8.EaglercraftUUID;
+import net.lax1dude.eaglercraft.v1_8.opengl.GlStateManager;
+import net.lax1dude.eaglercraft.v1_8.profanity_filter.ProfanityFilter;
+import net.lax1dude.eaglercraft.v1_8.socket.protocol.pkt.server.SPacketNotifBadgeShowV4EAG.EnumBadgePriority;
+import net.minecraft.client.Minecraft;
+import net.minecraft.util.IChatComponent;
+
+/**
+ * Copyright (c) 2024 lax1dude. All Rights Reserved.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ * 
+ */
+public class NotificationBadge {
+	
+	public final ServerNotificationManager mgr;
+	public final EaglercraftUUID badgeUUID;
+	public final IChatComponent bodyComponent;
+	protected IChatComponent bodyComponentProfanityFilter;
+	public final IChatComponent titleComponent;
+	protected IChatComponent titleComponentProfanityFilter;
+	public final IChatComponent sourceComponent;
+	protected IChatComponent sourceComponentProfanityFilter;
+	public final long clientTimestamp;
+	public final long serverTimestamp;
+	public final boolean silent;
+	public final EnumBadgePriority priority;
+	public final NotificationIcon mainIcon;
+	public final NotificationIcon titleIcon;
+	public final int hideAfterSec;
+	public final int expireAfterSec;
+	public final int backgroundColor;
+	public final int bodyTxtColor;
+	public final int titleTxtColor;
+	public final int sourceTxtColor;
+
+	protected CachedNotifBadgeTexture currentCacheGLTexture = null;
+	protected int currentCacheScaleFac = -1;
+	protected boolean currentCacheXButton = false;
+	protected boolean currentCacheProfanityFilter = false;
+	protected long hideAtMillis = -1l;
+	protected boolean unreadFlag = true;
+	protected boolean unreadFlagRender = true;
+	
+	protected NotificationBadge(ServerNotificationManager mgr, EaglercraftUUID badgeUUID, IChatComponent bodyComponent,
+			IChatComponent titleComponent, IChatComponent sourceComponent, long clientTimestamp, long serverTimestamp,
+			boolean silent, EnumBadgePriority priority, NotificationIcon mainIcon, NotificationIcon titleIcon,
+			int hideAfterSec, int expireAfterSec, int backgroundColor, int bodyTxtColor, int titleTxtColor,
+			int sourceTxtColor) {
+		this.mgr = mgr;
+		this.badgeUUID = badgeUUID;
+		this.bodyComponent = bodyComponent;
+		this.titleComponent = titleComponent;
+		this.sourceComponent = sourceComponent;
+		this.clientTimestamp = clientTimestamp;
+		this.serverTimestamp = serverTimestamp;
+		this.silent = silent;
+		this.priority = priority;
+		this.mainIcon = mainIcon;
+		this.titleIcon = titleIcon;
+		this.hideAfterSec = hideAfterSec;
+		this.expireAfterSec = expireAfterSec;
+		this.backgroundColor = backgroundColor;
+		this.bodyTxtColor = bodyTxtColor;
+		this.titleTxtColor = titleTxtColor;
+		this.sourceTxtColor = sourceTxtColor;
+	}
+	
+	protected void incrIconRefcounts() {
+		if(mainIcon != null) {
+			mainIcon.retain();
+		}
+		if(titleIcon != null) {
+			titleIcon.retain();
+		}
+	}
+	
+	protected void decrIconRefcounts() {
+		deleteGLTexture();
+		if(mainIcon != null) {
+			mainIcon.release();
+		}
+		if(titleIcon != null) {
+			titleIcon.release();
+		}
+	}
+
+	protected CachedNotifBadgeTexture getGLTexture(ServerNotificationRenderer renderer, int scaleFactor, boolean showXButton) {
+		boolean profanityFilter = Minecraft.getMinecraft().isEnableProfanityFilter();
+		if(currentCacheGLTexture == null || currentCacheScaleFac != scaleFactor || currentCacheXButton != showXButton || currentCacheProfanityFilter != profanityFilter) {
+			deleteGLTexture();
+			currentCacheGLTexture = renderer.renderBadge(this, scaleFactor, showXButton);
+			currentCacheScaleFac = scaleFactor;
+			currentCacheXButton = showXButton;
+			currentCacheProfanityFilter = profanityFilter;
+		}
+		return currentCacheGLTexture;
+	}
+
+	protected void deleteGLTexture() {
+		if(currentCacheGLTexture != null) {
+			GlStateManager.deleteTexture(currentCacheGLTexture.glTexture);
+			currentCacheGLTexture = null;
+		}
+	}
+
+	public void hideNotif() {
+		if(hideAtMillis == -1l) {
+			markRead();
+			unreadFlagRender = false;
+			hideAtMillis = EagRuntime.steadyTimeMillis();
+		}
+	}
+
+	public void removeNotif() {
+		mgr.removeNotifFromActiveList(badgeUUID);
+	}
+
+	public void markRead() {
+		if(unreadFlag) {
+			unreadFlag = false;
+			--mgr.unreadCounter;
+		}
+	}
+
+	public IChatComponent getBodyProfanityFilter() {
+		if(Minecraft.getMinecraft().isEnableProfanityFilter()) {
+			if(bodyComponentProfanityFilter == null && bodyComponent != null) {
+				bodyComponentProfanityFilter = ProfanityFilter.getInstance().profanityFilterChatComponent(bodyComponent);
+			}
+			return bodyComponentProfanityFilter;
+		}else {
+			return bodyComponent;
+		}
+	}
+
+	public IChatComponent getTitleProfanityFilter() {
+		if(Minecraft.getMinecraft().isEnableProfanityFilter()) {
+			if(titleComponentProfanityFilter == null && titleComponent != null) {
+				titleComponentProfanityFilter = ProfanityFilter.getInstance().profanityFilterChatComponent(titleComponent);
+			}
+			return titleComponentProfanityFilter;
+		}else {
+			return titleComponent;
+		}
+	}
+
+	public IChatComponent getSourceProfanityFilter() {
+		if(Minecraft.getMinecraft().isEnableProfanityFilter()) {
+			if(sourceComponentProfanityFilter == null && sourceComponent != null) {
+				sourceComponentProfanityFilter = ProfanityFilter.getInstance().profanityFilterChatComponent(sourceComponent);
+			}
+			return sourceComponentProfanityFilter;
+		}else {
+			return sourceComponent;
+		}
+	}
+
+}
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/notifications/NotificationIcon.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/notifications/NotificationIcon.java
new file mode 100644
index 00000000..e67df09c
--- /dev/null
+++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/notifications/NotificationIcon.java
@@ -0,0 +1,51 @@
+package net.lax1dude.eaglercraft.v1_8.notifications;
+
+import net.lax1dude.eaglercraft.v1_8.EaglercraftUUID;
+import net.lax1dude.eaglercraft.v1_8.profile.EaglerSkinTexture;
+import net.minecraft.util.ResourceLocation;
+
+/**
+ * Copyright (c) 2024 lax1dude. All Rights Reserved.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ * 
+ */
+public class NotificationIcon {
+
+	private static int notifIconTmpId = 0;
+
+	protected int refCount = 0;
+	protected boolean serverRegistered = true;
+
+	public final EaglercraftUUID iconUUID;
+	public final EaglerSkinTexture texture;
+	public final ResourceLocation resource;
+
+	protected NotificationIcon(EaglercraftUUID iconUUID, EaglerSkinTexture texture) {
+		this.iconUUID = iconUUID;
+		this.texture = texture;
+		this.resource = new ResourceLocation("eagler:gui/server/notifs/tex_" + notifIconTmpId++);
+	}
+
+	public void retain() {
+		++refCount;
+	}
+
+	public void release() {
+		--refCount;
+	}
+
+	public boolean isValid() {
+		return serverRegistered || refCount > 0;
+	}
+
+}
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/notifications/ServerNotificationManager.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/notifications/ServerNotificationManager.java
new file mode 100644
index 00000000..27b51590
--- /dev/null
+++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/notifications/ServerNotificationManager.java
@@ -0,0 +1,277 @@
+package net.lax1dude.eaglercraft.v1_8.notifications;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.commons.lang3.StringUtils;
+
+import net.lax1dude.eaglercraft.v1_8.EagRuntime;
+import net.lax1dude.eaglercraft.v1_8.EaglercraftUUID;
+import net.lax1dude.eaglercraft.v1_8.log4j.LogManager;
+import net.lax1dude.eaglercraft.v1_8.log4j.Logger;
+import net.lax1dude.eaglercraft.v1_8.opengl.ImageData;
+import net.lax1dude.eaglercraft.v1_8.profile.EaglerSkinTexture;
+import net.lax1dude.eaglercraft.v1_8.socket.protocol.pkt.server.SPacketNotifBadgeHideV4EAG;
+import net.lax1dude.eaglercraft.v1_8.socket.protocol.pkt.server.SPacketNotifBadgeShowV4EAG;
+import net.lax1dude.eaglercraft.v1_8.socket.protocol.pkt.server.SPacketNotifIconsRegisterV4EAG;
+import net.lax1dude.eaglercraft.v1_8.socket.protocol.pkt.server.SPacketNotifIconsReleaseV4EAG;
+import net.lax1dude.eaglercraft.v1_8.socket.protocol.util.PacketImageData;
+import net.minecraft.client.Minecraft;
+import net.minecraft.client.renderer.texture.TextureManager;
+import net.minecraft.util.IChatComponent;
+
+/**
+ * Copyright (c) 2024 lax1dude. All Rights Reserved.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ * 
+ */
+public class ServerNotificationManager {
+
+	private static final Logger logger = LogManager.getLogger("ServerNotificationManager");
+
+	private final Map<EaglercraftUUID,NotificationIcon> activeIcons = new HashMap<>();
+	private final Map<EaglercraftUUID,NotificationBadge> activeNotifications = new HashMap<>();
+	private List<NotificationBadge> sortedNotifList = new ArrayList<>(0);
+	private List<NotificationBadge> sortedDisplayNotifList = new ArrayList<>(0);
+	private int updateCounter = 0;
+	private long lastCleanup = EagRuntime.steadyTimeMillis();
+	private final TextureManager textureMgr;
+	protected int unreadCounter = 0;
+
+	public ServerNotificationManager() {
+		this.textureMgr = Minecraft.getMinecraft().getTextureManager();
+	}
+
+	public void processPacketAddIcons(SPacketNotifIconsRegisterV4EAG packet) {
+		for(SPacketNotifIconsRegisterV4EAG.CreateIcon icn : packet.iconsToCreate) {
+			if(icn.uuidMost == 0 && icn.uuidLeast == 0) {
+				logger.error("Skipping notification icon with UUID 0!");
+				continue;
+			}
+			EaglercraftUUID uuid = new EaglercraftUUID(icn.uuidMost, icn.uuidLeast);
+			PacketImageData imageData = icn.imageData;
+			NotificationIcon existing = activeIcons.get(uuid);
+			if(existing != null) {
+				if (existing.texture.getWidth() != imageData.width
+						|| existing.texture.getHeight() != imageData.height) {
+					logger.error("Error: server tried to change the dimensions of icon {}!", uuid);
+				}else if(!Arrays.equals(existing.texture.getData(), imageData.rgba)) {
+					existing.texture.copyPixelsIn(ImageData.swapRB(imageData.rgba));
+				}
+				existing.serverRegistered = true;
+				continue;
+			}
+			NotificationIcon newIcon = new NotificationIcon(uuid,
+					new EaglerSkinTexture(ImageData.swapRB(imageData.rgba), imageData.width, imageData.height));
+			textureMgr.loadTexture(newIcon.resource, newIcon.texture);
+			activeIcons.put(uuid, newIcon);
+		}
+	}
+
+	public void processPacketRemIcons(SPacketNotifIconsReleaseV4EAG packet) {
+		for(SPacketNotifIconsReleaseV4EAG.DestroyIcon icn : packet.iconsToDestroy) {
+			NotificationIcon existing = activeIcons.get(new EaglercraftUUID(icn.uuidMost, icn.uuidLeast));
+			if(existing != null) {
+				existing.serverRegistered = false;
+			}
+		}
+	}
+
+	public void processPacketShowBadge(SPacketNotifBadgeShowV4EAG packet) {
+		EaglercraftUUID newUuid = new EaglercraftUUID(packet.badgeUUIDMost, packet.badgeUUIDLeast);
+		NotificationBadge existing = activeNotifications.get(newUuid);
+		if(existing != null) {
+			logger.error("Duplicate notification UUID {}, all notifications should have unique UUIDs!", newUuid);
+			return;
+		}
+		NotificationBadge newBadge = new NotificationBadge(this, newUuid,
+				!StringUtils.isAllBlank(packet.bodyComponent) ? IChatComponent.Serializer.jsonToComponent(packet.bodyComponent) : null,
+				!StringUtils.isAllBlank(packet.titleComponent) ? IChatComponent.Serializer.jsonToComponent(packet.titleComponent) : null,
+				!StringUtils.isAllBlank(packet.sourceComponent) ? IChatComponent.Serializer.jsonToComponent(packet.sourceComponent) : null,
+				EagRuntime.steadyTimeMillis(), packet.originalTimestampSec * 1000l, packet.silent, packet.priority,
+				getIcon(packet.mainIconUUIDMost, packet.mainIconUUIDLeast),
+				getIcon(packet.titleIconUUIDMost, packet.titleIconUUIDLeast), packet.hideAfterSec, packet.expireAfterSec,
+				packet.backgroundColor, packet.bodyTxtColor, packet.titleTxtColor, packet.sourceTxtColor);
+		++unreadCounter;
+		addNotifToActiveList(newBadge);
+	}
+
+	private NotificationIcon getIcon(long uuidMost, long uuidLeast) {
+		if(uuidMost == 0l && uuidLeast == 0l) {
+			return null;
+		}
+		return activeIcons.get(new EaglercraftUUID(uuidMost, uuidLeast));
+	}
+
+	public void processPacketHideBadge(SPacketNotifBadgeHideV4EAG packet) {
+		removeNotifFromActiveList(new EaglercraftUUID(packet.badgeUUIDLeast, packet.badgeUUIDMost));
+	}
+
+	public int getNotifListUpdateCount() {
+		return updateCounter;
+	}
+
+	public List<NotificationBadge> getNotifBadgesToDisplay() {
+		return sortedDisplayNotifList;
+	}
+
+	public List<NotificationBadge> getNotifLongHistory() {
+		return sortedNotifList;
+	}
+
+	protected void addNotifToActiveList(NotificationBadge badge) {
+		NotificationBadge exists = activeNotifications.put(badge.badgeUUID, badge);
+		if(exists != null) {
+			exists.decrIconRefcounts();
+		}
+		badge.incrIconRefcounts();
+		resortLists();
+	}
+
+	protected void removeNotifFromActiveList(EaglercraftUUID badge) {
+		NotificationBadge exists = activeNotifications.remove(badge);
+		if(exists != null) {
+			exists.decrIconRefcounts();
+			resortLists();
+		}
+	}
+
+	protected void removeAllNotifFromActiveList(Collection<NotificationBadge> badges) {
+		boolean resort = false;
+		for(NotificationBadge badge : badges) {
+			NotificationBadge exists = activeNotifications.remove(badge.badgeUUID);
+			if(exists != null) {
+				exists.decrIconRefcounts();
+				resort = true;
+			}
+		}
+		if(resort) {
+			resortLists();
+		}
+	}
+
+	protected static final Comparator<NotificationBadge> clientAgeComparator = (a, b) -> {
+		return (int)(b.clientTimestamp - a.clientTimestamp);
+	};
+
+	private void resortLists() {
+		updateCounter++;
+		int ll = activeNotifications.size();
+		if(!sortedNotifList.isEmpty()) sortedNotifList = new ArrayList<>(ll);
+		if(!sortedDisplayNotifList.isEmpty()) sortedDisplayNotifList = new ArrayList<>(Math.min(ll, 4));
+		if(ll > 0) {
+			sortedNotifList.addAll(activeNotifications.values());
+			Collections.sort(sortedNotifList, clientAgeComparator);
+			long millis = EagRuntime.steadyTimeMillis();
+			for(int i = 0, l = sortedNotifList.size(); i < l; ++i) {
+				NotificationBadge bd = sortedNotifList.get(i);
+				if(millis - bd.clientTimestamp < (long)(bd.hideAfterSec * 1000)) {
+					sortedDisplayNotifList.add(bd);
+				}else {
+					bd.deleteGLTexture();
+				}
+			}
+		}
+	}
+
+	public void runTick() {
+		long millis = EagRuntime.steadyTimeMillis();
+		if(millis - lastCleanup > 2500l) {
+			lastCleanup = millis;
+			int len = sortedNotifList.size();
+			if(len > 128) {
+				removeAllNotifFromActiveList(new ArrayList<NotificationBadge>(sortedNotifList.subList(128, len)));
+			}
+			Iterator<NotificationIcon> itr = activeIcons.values().iterator();
+			while(itr.hasNext()) {
+				NotificationIcon icn = itr.next();
+				if(!icn.isValid()) {
+					itr.remove();
+					textureMgr.deleteTexture(icn.resource);
+				}
+			}
+			if(!sortedDisplayNotifList.isEmpty()) {
+				Iterator<NotificationBadge> itr2 = sortedDisplayNotifList.iterator();
+				while(itr2.hasNext()) {
+					NotificationBadge bd = itr2.next();
+					if(bd.hideAtMillis != -1l) {
+						if(millis - bd.hideAtMillis > 500l) {
+							bd.deleteGLTexture();
+							itr2.remove();
+						}
+					}else {
+						long age = millis - bd.clientTimestamp;
+						if(age > (long)(bd.hideAfterSec * 1000) || age > (long)(bd.expireAfterSec * 1000)) {
+							bd.deleteGLTexture();
+							itr2.remove();
+						}
+					}
+				}
+			}
+			if(!activeNotifications.isEmpty()) {
+				Iterator<NotificationBadge> itr3 = activeNotifications.values().iterator();
+				List<NotificationBadge> toDelete = null;
+				while(itr3.hasNext()) {
+					NotificationBadge bd = itr3.next();
+					long age = millis - bd.clientTimestamp;
+					if(age > (long)(bd.expireAfterSec * 1000)) {
+						if(toDelete == null) {
+							toDelete = new ArrayList<>();
+						}
+						toDelete.add(bd);
+					}
+				}
+				if(toDelete != null) {
+					removeAllNotifFromActiveList(toDelete);
+				}
+			}
+		}
+	}
+
+	public int getUnread() {
+		if(unreadCounter < 0) unreadCounter = 0;
+		return unreadCounter;
+	}
+
+	public void commitUnreadFlag() {
+		for(NotificationBadge badge : activeNotifications.values()) {
+			badge.unreadFlagRender = badge.unreadFlag;
+		}
+	}
+
+	public void markRead() {
+		for(NotificationBadge badge : activeNotifications.values()) {
+			badge.unreadFlag = false;
+			badge.unreadFlagRender = false;
+		}
+		unreadCounter = 0;
+	}
+
+	public void destroy() {
+		for(NotificationIcon icn : activeIcons.values()) {
+			textureMgr.deleteTexture(icn.resource);
+		}
+		activeIcons.clear();
+		activeNotifications.clear();
+		sortedNotifList = null;
+		sortedDisplayNotifList = null;
+	}
+
+}
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/notifications/ServerNotificationRenderer.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/notifications/ServerNotificationRenderer.java
new file mode 100644
index 00000000..b61b5434
--- /dev/null
+++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/notifications/ServerNotificationRenderer.java
@@ -0,0 +1,539 @@
+package net.lax1dude.eaglercraft.v1_8.notifications;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import net.lax1dude.eaglercraft.v1_8.EagRuntime;
+import net.lax1dude.eaglercraft.v1_8.internal.IFramebufferGL;
+import net.lax1dude.eaglercraft.v1_8.internal.buffer.ByteBuffer;
+import net.lax1dude.eaglercraft.v1_8.log4j.LogManager;
+import net.lax1dude.eaglercraft.v1_8.log4j.Logger;
+import net.lax1dude.eaglercraft.v1_8.opengl.EaglercraftGPU;
+import net.lax1dude.eaglercraft.v1_8.opengl.GlStateManager;
+import net.lax1dude.eaglercraft.v1_8.opengl.VertexFormat;
+import net.lax1dude.eaglercraft.v1_8.opengl.WorldRenderer;
+import net.minecraft.client.Minecraft;
+import net.minecraft.client.audio.PositionedSoundRecord;
+import net.minecraft.client.gui.GuiChat;
+import net.minecraft.client.gui.GuiScreen;
+import net.minecraft.client.gui.GuiUtilRenderComponents;
+import net.minecraft.client.renderer.Tessellator;
+import net.minecraft.event.ClickEvent;
+import net.minecraft.event.HoverEvent;
+import net.minecraft.util.ChatComponentText;
+import net.minecraft.util.IChatComponent;
+import net.minecraft.util.MathHelper;
+import net.minecraft.util.ResourceLocation;
+
+import static net.lax1dude.eaglercraft.v1_8.internal.PlatformOpenGL.*;
+import static net.lax1dude.eaglercraft.v1_8.opengl.RealOpenGLEnums.*;
+import static net.lax1dude.eaglercraft.v1_8.opengl.ext.deferred.ExtGLEnums.*;
+
+/**
+ * Copyright (c) 2024 lax1dude. All Rights Reserved.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ * 
+ */
+public class ServerNotificationRenderer {
+
+	protected static final Logger logger = LogManager.getLogger("ServerNotificationRenderer");
+
+	protected Minecraft mc;
+	protected int width;
+	protected int height;
+	protected int scaleFactor;
+
+	protected IFramebufferGL rendererFramebuffer;
+
+	protected static final int BADGE_WIDTH = 160;
+	protected static final int BADGE_HEIGHT = 64;
+
+	private static final ResourceLocation eaglerGui = new ResourceLocation("eagler:gui/eagler_gui.png");
+
+	public ServerNotificationRenderer() {
+		
+	}
+
+	public void init() {
+		destroy();
+		rendererFramebuffer = _wglCreateFramebuffer();
+	}
+
+	public void setResolution(Minecraft mc, int w, int h, int scaleFactor) {
+		this.mc = mc;
+		this.width = w;
+		this.height = h;
+		this.scaleFactor = scaleFactor;
+	}
+
+	public boolean handleClicked(GuiScreen currentScreen, int posX, int posY) {
+		if(mc.thePlayer == null) return false;
+		ServerNotificationManager mgr = mc.thePlayer.sendQueue.getNotifManager();
+		List<NotificationBadge> lst = mgr.getNotifBadgesToDisplay();
+		if(!lst.isEmpty()) {
+			int baseOffset = mc.guiAchievement.getHeight();
+			boolean showX = (currentScreen instanceof GuiChat);
+			if(showX) {
+				baseOffset += 25; // exit button in chat screen;
+			}
+			long millis = EagRuntime.steadyTimeMillis();
+			for(int i = 0, l = lst.size(); i < l; ++i) {
+				NotificationBadge badge = lst.get(i);
+				CachedNotifBadgeTexture tex = badge.currentCacheGLTexture;
+				if(tex != null) {
+					int baseX = width - tex.width;
+					float texHeight = tex.height;
+					float timeRemainingSec;
+					long age = millis - badge.clientTimestamp;
+					if(badge.hideAtMillis != -1l) {
+						timeRemainingSec = (float)((double)(500l - (millis - badge.hideAtMillis)) * 0.001);
+					}else {
+						timeRemainingSec = (float)((double)((long)badge.hideAfterSec * 1000l - age) * 0.001);
+					}
+					timeRemainingSec = Math.min((float)(age * 0.001) + 0.001f, timeRemainingSec);
+					float f = MathHelper.clamp_float(timeRemainingSec * 3.0F, 0.0F, 1.0F);
+					f *= f;
+					texHeight *= f;
+					if(badge.hideAtMillis == -1l) {
+						if(posX >= baseX && posX < width && posY >= baseOffset && posY < baseOffset + texHeight) {
+							if(showX) {
+								int xposX = baseX + tex.width - 21;
+								int xposY = baseOffset + 5;
+								if(posX >= xposX && posY >= xposY && posX < xposX + 16 && posY < xposY + 16) {
+									badge.hideNotif();
+									mc.getSoundHandler().playSound(PositionedSoundRecord.create(new ResourceLocation("gui.button.press"), 1.0F));
+									return true;
+								}
+							}
+							if(tex.rootClickEvent != null) {
+								if(currentScreen.handleComponentClick(tex.rootClickEvent)) {
+									mc.getSoundHandler().playSound(PositionedSoundRecord.create(new ResourceLocation("gui.button.press"), 1.0F));
+									return true;
+								}
+							}
+							List<ClickEventZone> cursorEvents = tex.cursorEvents;
+							if(tex.hasClickEvents && cursorEvents != null) {
+								for(int j = 0, m = cursorEvents.size(); j < m; ++j) {
+									ClickEventZone evt = cursorEvents.get(j);
+									if(evt.hasClickEvent) {
+										int offsetPosX = baseX + evt.posX;
+										int offsetPosY = baseOffset + evt.posY;
+										if(posX >= offsetPosX && posY >= offsetPosY && posX < offsetPosX + evt.width && posY < offsetPosY + evt.height) {
+											if(currentScreen.handleComponentClick(evt.chatComponent)) {
+												mc.getSoundHandler().playSound(PositionedSoundRecord.create(new ResourceLocation("gui.button.press"), 1.0F));
+												return true;
+											}
+										}
+									}
+								}
+							}
+						}
+					}
+					baseOffset += texHeight;
+				}
+			}
+		}
+		return false;
+	}
+
+	public void renderOverlay(int mouseX, int mouseY) {
+		if(mc.thePlayer == null) return;
+		ServerNotificationManager mgr = mc.thePlayer.sendQueue.getNotifManager();
+		List<NotificationBadge> lst = mgr.getNotifBadgesToDisplay();
+		if(!lst.isEmpty()) {
+			GlStateManager.clear(GL_DEPTH_BUFFER_BIT);
+			boolean showXButtons = false;
+			int baseOffset = mc.guiAchievement.getHeight();
+			if(mc.currentScreen != null) {
+				if(mc.currentScreen instanceof GuiChat) {
+					baseOffset += 25; // exit button in chat screen;
+					showXButtons = true;
+				}else if(mc.currentScreen instanceof GuiScreenNotifications) {
+					return;
+				}
+			}
+			long millis = EagRuntime.steadyTimeMillis();
+			boolean isBlend = false;
+			for(int i = 0, l = lst.size(); i < l; ++i) {
+				NotificationBadge badge = lst.get(i);
+				boolean isHiding = false;
+				if(badge.hideAtMillis != -1l) {
+					isHiding = true;
+					if(millis - badge.hideAtMillis > 500l) {
+						continue;
+					}
+				}
+				CachedNotifBadgeTexture tex = badge.getGLTexture(this, scaleFactor, showXButtons);
+				if(tex != null) {
+					GlStateManager.bindTexture(tex.glTexture);
+					float alphaTop = 1.0f;
+					float alphaBottom = 1.0f;
+					float timeRemainingSec;
+					long age = millis - badge.clientTimestamp;
+					if(isHiding) {
+						timeRemainingSec = (float)((double)(500l - (millis - badge.hideAtMillis)) * 0.001);
+					}else {
+						timeRemainingSec = (float)((double)((long)badge.hideAfterSec * 1000l - age) * 0.001);
+					}
+					timeRemainingSec = Math.min((float)(age * 0.001) + 0.001f, timeRemainingSec);
+					alphaTop *= MathHelper.clamp_float(timeRemainingSec * 3.0F, 0.0F, 1.0F);
+					alphaTop *= alphaTop;
+					alphaBottom *= MathHelper.clamp_float(timeRemainingSec * 2.0F, 0.0F, 1.0F);
+					alphaBottom *= alphaBottom;
+					if(alphaTop == 0.0F && alphaBottom == 0.0F) {
+						continue;
+					}
+					boolean blend = alphaTop < 1.0f || alphaBottom < 1.0f;
+					if(blend != isBlend) {
+						if(blend) {
+							GlStateManager.enableBlend();
+							GlStateManager.tryBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, 1, 0);
+						}else {
+							GlStateManager.disableBlend();
+						}
+						isBlend = blend;
+					}
+					int px = width - tex.width;
+					drawTexturedGradientFBRect(px, baseOffset, tex.width, tex.height,
+							((int) (alphaTop * 255.0f) << 24) | 0xFFFFFF,
+							((int) (alphaBottom * 255.0f) << 24) | 0xFFFFFF, 200.0f);
+					if(showXButtons && tex.hasHoverEvents) {
+						if(mouseX >= px && mouseY >= baseOffset && mouseX < px + tex.width && mouseY < baseOffset + tex.height) {
+							List<ClickEventZone> cursorEvents = tex.cursorEvents;
+							if(cursorEvents != null) {
+								for(int j = 0, m = cursorEvents.size(); j < m; ++j) {
+									ClickEventZone evt = cursorEvents.get(j);
+									if(evt.hasHoverEvent) {
+										int offsetPosX = px + evt.posX;
+										int offsetPosY = baseOffset + evt.posY;
+										if(mouseX >= offsetPosX && mouseY >= offsetPosY && mouseX < offsetPosX + evt.width
+												&& mouseY < offsetPosY + evt.height) {
+											if(isBlend) {
+												GlStateManager.disableBlend();
+												isBlend = false;
+											}
+											mc.currentScreen.handleComponentHover(evt.chatComponent, mouseX, mouseY);
+										}
+									}
+								}
+							}
+						}
+					}
+					baseOffset += tex.height * alphaTop;
+				}
+			}
+			if(isBlend) {
+				GlStateManager.disableBlend();
+			}
+		}
+	}
+
+	protected CachedNotifBadgeTexture renderBadge(NotificationBadge badge, int scaleFactor, boolean showXButton) {
+		int badgeWidth = BADGE_WIDTH;
+		int badgeHeight = 10;
+		
+		int leftPadding = 6;
+		int rightPadding = 26;
+		
+		int mainIconSW = 32;
+		if(badge.mainIcon != null) {
+			int iw = badge.mainIcon.texture.getWidth();
+			int ih = badge.mainIcon.texture.getHeight();
+			float iaspect = (float)iw / (float)ih;
+			mainIconSW = (int)(32 * iaspect);
+			leftPadding += Math.min(mainIconSW, 64) + 3;
+		}
+		
+		int textZoneWidth = badgeWidth - leftPadding - rightPadding;
+		int bodyYOffset = 5;
+		
+		String titleText = null;
+		IChatComponent titleComponent = badge.getTitleProfanityFilter();
+		if(titleComponent != null) {
+			titleText = titleComponent.getFormattedText();
+			if(titleText.length() > 0) {
+				badgeHeight += 12;
+				bodyYOffset += 12;
+			}else {
+				titleText = null;
+			}
+		}
+		
+		if(badge.titleIcon != null && titleText == null) {
+			badgeHeight += 12;
+			bodyYOffset += 12;
+		}
+		
+		float bodyFontSize = 0.75f;
+		List<IChatComponent> bodyLines = null;
+		List<ClickEventZone> clickEvents = null;
+		IChatComponent rootClickEvt = null;
+		boolean hasClickEvents = false;
+		boolean hasHoverEvents = false;
+		
+		int bodyHeight = 0;
+		
+		IChatComponent bodyComponent = badge.getBodyProfanityFilter();
+		if(bodyComponent != null) {
+			if (bodyComponent.getChatStyle().getChatClickEvent() != null
+					&& bodyComponent.getChatStyle().getChatClickEvent().getAction().shouldAllowInChat()) {
+				rootClickEvt = bodyComponent;
+			}
+			bodyLines = GuiUtilRenderComponents.func_178908_a(bodyComponent, (int) (textZoneWidth / bodyFontSize),
+					mc.fontRendererObj, true, true);
+			
+			int maxHeight = BADGE_HEIGHT - 32;
+			int maxLines = MathHelper.floor_float(maxHeight / (9 * bodyFontSize));
+			if(bodyLines.size() > maxLines) {
+				bodyLines = bodyLines.subList(0, maxLines);
+				bodyComponent = bodyLines.get(maxLines - 1);
+				List<IChatComponent> siblings = bodyComponent.getSiblings();
+				IChatComponent dots = new ChatComponentText("...");
+				if(siblings != null && siblings.size() > 0) {
+					dots.setChatStyle(siblings.get(siblings.size() - 1).getChatStyle());
+				}
+				bodyComponent.appendSibling(dots);
+			}
+			bodyHeight = MathHelper.floor_float(bodyLines.size() * (9 * bodyFontSize));
+		}
+
+		String sourceText = null;
+		IChatComponent sourceComponent = badge.getSourceProfanityFilter();
+		if(sourceComponent != null) {
+			sourceText = sourceComponent.getFormattedText();
+			if(sourceText.length() == 0) {
+				sourceText = null;
+			}
+		}
+		
+		if(badge.mainIcon != null) {
+			bodyHeight = Math.max(sourceText != null ? 30 : 32, bodyHeight);
+		}
+		
+		if(sourceText != null) {
+			badgeHeight += 6;
+		}
+		
+		badgeHeight += bodyHeight;
+		
+		badgeHeight = Math.max(badgeHeight, showXButton ? 42 : 26);
+		
+		if(badgeHeight > BADGE_HEIGHT) {
+			logger.info("Warning: Badge {} was {} pixels too high!", badge.badgeUUID, BADGE_HEIGHT - badgeHeight);
+			badgeHeight = BADGE_HEIGHT;
+		}
+		
+		int glTex = GlStateManager.generateTexture();
+		GlStateManager.bindTexture(glTex);
+		EaglercraftGPU.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+		EaglercraftGPU.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+		EaglercraftGPU.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+		EaglercraftGPU.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+		EaglercraftGPU.glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, badgeWidth * scaleFactor, badgeHeight * scaleFactor, 0, GL_RGBA,
+				GL_UNSIGNED_BYTE, (ByteBuffer) null);
+		_wglBindFramebuffer(_GL_FRAMEBUFFER, rendererFramebuffer);
+		_wglFramebufferTexture2D(_GL_FRAMEBUFFER, _GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, EaglercraftGPU.getNativeTexture(glTex), 0);
+		_wglDrawBuffers(_GL_COLOR_ATTACHMENT0);
+		
+		int[] oldViewport = new int[4];
+		EaglercraftGPU.glGetInteger(GL_VIEWPORT, oldViewport);
+		
+		GlStateManager.viewport(0, 0, badgeWidth * scaleFactor, badgeHeight * scaleFactor);
+		
+		GlStateManager.disableDepth();
+		GlStateManager.depthMask(false);
+		GlStateManager.enableTexture2D();
+		GlStateManager.disableLighting();
+		GlStateManager.color(1.0f, 1.0f, 1.0f, 1.0f);
+		
+		GlStateManager.matrixMode(GL_PROJECTION);
+		GlStateManager.pushMatrix();
+		GlStateManager.loadIdentity();
+		GlStateManager.ortho(0.0D, badgeWidth, badgeHeight, 0.0D, 1000.0D, 3000.0D);
+		GlStateManager.matrixMode(GL_MODELVIEW);
+		GlStateManager.pushMatrix();
+		GlStateManager.loadIdentity();
+		GlStateManager.translate(0.0F, 0.0F, -2000.0F);
+
+		Tessellator tess = Tessellator.getInstance();
+		WorldRenderer worldRenderer = tess.getWorldRenderer();
+
+		worldRenderer.begin(GL_QUADS, VertexFormat.POSITION_TEX_COLOR);
+		
+		mc.getTextureManager().bindTexture(eaglerGui);
+
+		drawTexturedColoredRect(worldRenderer, 0, 0, 96, 192, 160, 8, (badge.backgroundColor >>> 16) & 0xFF,
+				(badge.backgroundColor >>> 8) & 0xFF, badge.backgroundColor & 0xFF, 0xFF);
+		
+		drawTexturedColoredRect(worldRenderer, 0, 8, 96, 192 + (BADGE_HEIGHT - badgeHeight + 8), 160, (badgeHeight - 8),
+				(badge.backgroundColor >>> 16) & 0xFF, (badge.backgroundColor >>> 8) & 0xFF,
+				badge.backgroundColor & 0xFF, 0xFF);
+		
+		switch(badge.priority) {
+		case LOW:
+		default:
+			drawTexturedColoredRect(worldRenderer, badgeWidth - 21, badgeHeight - 21, 192, 176, 16, 16, (badge.backgroundColor >>> 16) & 0xFF,
+					(badge.backgroundColor >>> 8) & 0xFF, badge.backgroundColor & 0xFF, 0xFF);
+			break;
+		case NORMAL:
+			drawTexturedColoredRect(worldRenderer, badgeWidth - 21, badgeHeight - 21, 208, 176, 16, 16, 0xFF, 0xFF, 0xFF, 0xFF);
+			break;
+		case HIGHER:
+			drawTexturedColoredRect(worldRenderer, badgeWidth - 21, badgeHeight - 21, 224, 176, 16, 16, 0xFF, 0xFF, 0xFF, 0xFF);
+			break;
+		case HIGHEST:
+			drawTexturedColoredRect(worldRenderer, badgeWidth - 21, badgeHeight - 21, 240, 176, 16, 16, 0xFF, 0xFF, 0xFF, 0xFF);
+			break;
+		}
+		
+		if(showXButton) {
+			drawTexturedColoredRect(worldRenderer, badgeWidth - 21, 5, 80, 208, 16, 16, 0xFF, 0xFF, 0xFF, 0xFF);
+		}
+		
+		tess.draw();
+
+		if(badge.mainIcon != null) {
+			mc.getTextureManager().bindTexture(badge.mainIcon.resource);
+			drawTexturedRect(6, bodyYOffset, mainIconSW, 32);
+		}
+
+		if(badge.titleIcon != null) {
+			mc.getTextureManager().bindTexture(badge.titleIcon.resource);
+			drawTexturedRect(6, 5, 8, 8);
+		}
+		
+		if(titleText != null) {
+			GlStateManager.pushMatrix();
+			GlStateManager.translate(6 + (badge.titleIcon != null ? 10 : 0), 6, 0.0f);
+			GlStateManager.scale(0.75f, 0.75f, 0.75f);
+			mc.fontRendererObj.drawStringWithShadow(titleText, 0, 0, badge.titleTxtColor);
+			GlStateManager.popMatrix();
+		}
+		
+		if(bodyLines != null && !bodyLines.isEmpty()) {
+			GlStateManager.pushMatrix();
+			if(!showXButton && badge.mainIcon == null && titleText != null) {
+				bodyYOffset -= 2;
+			}
+			GlStateManager.translate(leftPadding, bodyYOffset, 0.0f);
+			int l = bodyLines.size();
+			GlStateManager.scale(bodyFontSize, bodyFontSize, bodyFontSize);
+			for(int i = 0; i < l; ++i) {
+				int startXLocal = 0;
+				int startXReal = leftPadding;
+				for(IChatComponent comp : bodyLines.get(i)) {
+					int w = mc.fontRendererObj.drawStringWithShadow(
+							comp.getChatStyle().getFormattingCode() + comp.getUnformattedTextForChat(), startXLocal,
+							i * 9, badge.bodyTxtColor) - startXLocal;
+					ClickEvent clickEvent = comp.getChatStyle().getChatClickEvent();
+					HoverEvent hoverEvent = comp.getChatStyle().getChatHoverEvent();
+					if(clickEvent != null && !clickEvent.getAction().shouldAllowInChat()) {
+						clickEvent = null;
+					}
+					if(hoverEvent != null && !hoverEvent.getAction().shouldAllowInChat()) {
+						hoverEvent = null;
+					}
+					if(clickEvent != null || hoverEvent != null) {
+						hasClickEvents |= clickEvent != null;
+						hasHoverEvents |= hoverEvent != null;
+						if(clickEvents == null) {
+							clickEvents = new ArrayList<>();
+						}
+						clickEvents.add(new ClickEventZone(startXReal + (int) (startXLocal * bodyFontSize),
+								bodyYOffset + (int) (i * 9 * bodyFontSize), (int) (w * bodyFontSize),
+								(int) (9 * bodyFontSize), comp, clickEvent != null, hoverEvent != null));
+					}
+					startXLocal += w;
+				}
+			}
+			GlStateManager.popMatrix();
+		}
+		
+		if(sourceText != null) {
+			GlStateManager.pushMatrix();
+			GlStateManager.translate(badgeWidth - 21, badgeHeight - 5, 0.0f);
+			GlStateManager.scale(0.5f, 0.5f, 0.5f);
+			mc.fontRendererObj.drawStringWithShadow(sourceText, -mc.fontRendererObj.getStringWidth(sourceText) - 4, -10, badge.sourceTxtColor);
+			GlStateManager.popMatrix();
+		}
+		
+		GlStateManager.matrixMode(GL_PROJECTION);
+		GlStateManager.popMatrix();
+		GlStateManager.matrixMode(GL_MODELVIEW);
+		GlStateManager.popMatrix();
+
+		GlStateManager.depthMask(true);
+		GlStateManager.enableDepth();
+
+		_wglBindFramebuffer(_GL_FRAMEBUFFER, null);
+		GlStateManager.viewport(oldViewport[0], oldViewport[1], oldViewport[2], oldViewport[3]);
+		
+		return new CachedNotifBadgeTexture(glTex, scaleFactor, badgeWidth, badgeHeight, clickEvents, rootClickEvt, hasClickEvents, hasHoverEvents);
+	}
+
+	static void drawTexturedColoredRect(WorldRenderer worldRenderer, float xCoord, float yCoord, int minU,
+			int minV, int width, int height, int r, int g, int b, int a) {
+		float f = 0.00390625F;
+		float f1 = 0.00390625F;
+		worldRenderer.pos((double) (xCoord + 0.0F), (double) (yCoord + (float) height), 0.0).color(r, g, b, a)
+				.tex((double) ((float) (minU + 0) * f), (double) ((float) (minV + height) * f1)).endVertex();
+		worldRenderer.pos((double) (xCoord + (float) width), (double) (yCoord + (float) height), 0.0).color(r, g, b, a)
+				.tex((double) ((float) (minU + width) * f), (double) ((float) (minV + height) * f1)).endVertex();
+		worldRenderer.pos((double) (xCoord + (float) width), (double) (yCoord + 0.0F), 0.0).color(r, g, b, a)
+				.tex((double) ((float) (minU + width) * f), (double) ((float) (minV + 0) * f1)).endVertex();
+		worldRenderer.pos((double) (xCoord + 0.0F), (double) (yCoord + 0.0F), 0.0).color(r, g, b, a)
+				.tex((double) ((float) (minU + 0) * f), (double) ((float) (minV + 0) * f1)).endVertex();
+	}
+
+	static void drawTexturedGradientFBRect(float xCoord, float yCoord, int width, int height, int rgbaTop, int rgbaBottom, float zIndex) {
+		int topR = (rgbaTop >>> 16) & 0xFF;
+		int topG = (rgbaTop >>> 8) & 0xFF;
+		int topB = rgbaTop & 0xFF;
+		int topA = (rgbaTop >>> 24) & 0xFF;
+		int bottomR = (rgbaBottom >>> 16) & 0xFF;
+		int bottomG = (rgbaBottom >>> 8) & 0xFF;
+		int bottomB = rgbaBottom & 0xFF;
+		int bottomA = (rgbaBottom >>> 24) & 0xFF;
+		Tessellator tess = Tessellator.getInstance();
+		WorldRenderer worldRenderer = tess.getWorldRenderer();
+		worldRenderer.begin(GL_QUADS, VertexFormat.POSITION_TEX_COLOR);
+		worldRenderer.pos((double) (xCoord + 0.0F), (double) (yCoord + (float) height), zIndex)
+				.color(bottomR, bottomG, bottomB, bottomA).tex(0.0, 0.0).endVertex();
+		worldRenderer.pos((double) (xCoord + (float) width), (double) (yCoord + (float) height), zIndex)
+				.color(bottomR, bottomG, bottomB, bottomA).tex(1.0, 0.0).endVertex();
+		worldRenderer.pos((double) (xCoord + (float) width), (double) (yCoord + 0.0F), zIndex)
+				.color(topR, topG, topB, topA).tex(1.0, 1.0).endVertex();
+		worldRenderer.pos((double) (xCoord + 0.0F), (double) (yCoord + 0.0F), zIndex).color(topR, topG, topB, topA)
+				.tex(0.0, 1.0).endVertex();
+		tess.draw();
+	}
+
+	static void drawTexturedRect(float xCoord, float yCoord, int width, int height) {
+		Tessellator tess = Tessellator.getInstance();
+		WorldRenderer worldRenderer = tess.getWorldRenderer();
+		worldRenderer.begin(GL_QUADS, VertexFormat.POSITION_TEX);
+		worldRenderer.pos((double) (xCoord + 0.0F), (double) (yCoord + (float) height), 0.0).tex(0.0, 1.0).endVertex();
+		worldRenderer.pos((double) (xCoord + (float) width), (double) (yCoord + (float) height), 0.0).tex(1.0, 1.0).endVertex();
+		worldRenderer.pos((double) (xCoord + (float) width), (double) (yCoord + 0.0F), 0.0).tex(1.0, 0.0).endVertex();
+		worldRenderer.pos((double) (xCoord + 0.0F), (double) (yCoord + 0.0F), 0.0).tex(0.0, 0.0).endVertex();
+		tess.draw();
+	}
+
+	public void destroy() {
+		if(rendererFramebuffer != null) {
+			_wglDeleteFramebuffer(rendererFramebuffer);
+			rendererFramebuffer = null;
+		}
+	}
+
+}
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/DrawUtils.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/DrawUtils.java
index a3adccae..58872a1e 100644
--- a/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/DrawUtils.java
+++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/DrawUtils.java
@@ -3,15 +3,16 @@ package net.lax1dude.eaglercraft.v1_8.opengl;
 import static net.lax1dude.eaglercraft.v1_8.internal.PlatformOpenGL.*;
 import static net.lax1dude.eaglercraft.v1_8.opengl.RealOpenGLEnums.*;
 
+import java.util.List;
+
 import net.lax1dude.eaglercraft.v1_8.EagRuntime;
 import net.lax1dude.eaglercraft.v1_8.internal.IBufferArrayGL;
 import net.lax1dude.eaglercraft.v1_8.internal.IBufferGL;
 import net.lax1dude.eaglercraft.v1_8.internal.IShaderGL;
 import net.lax1dude.eaglercraft.v1_8.internal.buffer.FloatBuffer;
-import net.lax1dude.eaglercraft.v1_8.opengl.FixedFunctionShader.FixedFunctionConstants;
 
 /**
- * Copyright (c) 2022-2023 lax1dude. All Rights Reserved.
+ * Copyright (c) 2022-2024 lax1dude. All Rights Reserved.
  * 
  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
@@ -28,17 +29,19 @@ import net.lax1dude.eaglercraft.v1_8.opengl.FixedFunctionShader.FixedFunctionCon
 public class DrawUtils {
 
 	public static final String vertexShaderPath = "/assets/eagler/glsl/local.vsh";
+	public static final String vertexShaderPrecision = "precision highp float;\n";
 
 	public static IBufferArrayGL standardQuad2DVAO = null;
 	public static IBufferArrayGL standardQuad3DVAO = null;
 	public static IBufferGL standardQuadVBO = null;
 
 	public static IShaderGL vshLocal = null;
+	public static List<VSHInputLayoutParser.ShaderInput> vshLocalLayout = null;
 
 	static void init() {
 		if(standardQuad2DVAO == null) {
-			standardQuad2DVAO = _wglGenVertexArrays();
-			standardQuad3DVAO = _wglGenVertexArrays();
+			standardQuad2DVAO = EaglercraftGPU.createGLBufferArray();
+			standardQuad3DVAO = EaglercraftGPU.createGLBufferArray();
 			standardQuadVBO = _wglGenBuffers();
 
 			FloatBuffer verts = EagRuntime.allocateFloatBuffer(18);
@@ -48,30 +51,29 @@ public class DrawUtils {
 			});
 			verts.flip();
 
-			EaglercraftGPU.bindGLArrayBuffer(standardQuadVBO);
+			EaglercraftGPU.bindVAOGLArrayBufferNow(standardQuadVBO);
 			_wglBufferData(GL_ARRAY_BUFFER, verts, GL_STATIC_DRAW);
 			EagRuntime.freeFloatBuffer(verts);
 
 			EaglercraftGPU.bindGLBufferArray(standardQuad2DVAO);
 
-			_wglEnableVertexAttribArray(0);
-			_wglVertexAttribPointer(0, 2, GL_FLOAT, false, 12, 0);
+			EaglercraftGPU.enableVertexAttribArray(0);
+			EaglercraftGPU.vertexAttribPointer(0, 2, GL_FLOAT, false, 12, 0);
 
 			EaglercraftGPU.bindGLBufferArray(standardQuad3DVAO);
 
-			_wglEnableVertexAttribArray(0);
-			_wglVertexAttribPointer(0, 3, GL_FLOAT, false, 12, 0);
+			EaglercraftGPU.enableVertexAttribArray(0);
+			EaglercraftGPU.vertexAttribPointer(0, 3, GL_FLOAT, false, 12, 0);
 		}
 
 		if(vshLocal == null) {
-			String vertexSource = EagRuntime.getResourceString(vertexShaderPath);
-			if(vertexSource == null) {
-				throw new RuntimeException("vertex shader \"" + vertexShaderPath + "\" is missing!");
-			}
-	
+			String vertexSource = EagRuntime.getRequiredResourceString(vertexShaderPath);
+
+			vshLocalLayout = VSHInputLayoutParser.getShaderInputs(vertexSource);
+
 			vshLocal = _wglCreateShader(GL_VERTEX_SHADER);
-	
-			_wglShaderSource(vshLocal, FixedFunctionConstants.VERSION + "\n" + vertexSource);
+
+			_wglShaderSource(vshLocal, GLSLHeader.getVertexHeaderCompat(vertexSource, vertexShaderPrecision));
 			_wglCompileShader(vshLocal);
 	
 			if(_wglGetShaderi(vshLocal, GL_COMPILE_STATUS) != GL_TRUE) {
@@ -90,12 +92,32 @@ public class DrawUtils {
 
 	public static void drawStandardQuad2D() {
 		EaglercraftGPU.bindGLBufferArray(standardQuad2DVAO);
-		_wglDrawArrays(GL_TRIANGLES, 0, 6);
+		EaglercraftGPU.doDrawArrays(GL_TRIANGLES, 0, 6);
 	}
 
 	public static void drawStandardQuad3D() {
 		EaglercraftGPU.bindGLBufferArray(standardQuad3DVAO);
-		_wglDrawArrays(GL_TRIANGLES, 0, 6);
+		EaglercraftGPU.doDrawArrays(GL_TRIANGLES, 0, 6);
+	}
+
+	public static void destroy() {
+		if(standardQuad2DVAO != null) {
+			EaglercraftGPU.destroyGLBufferArray(standardQuad2DVAO);
+			standardQuad2DVAO = null;
+		}
+		if(standardQuad3DVAO != null) {
+			EaglercraftGPU.destroyGLBufferArray(standardQuad3DVAO);
+			standardQuad3DVAO = null;
+		}
+		if(standardQuadVBO != null) {
+			_wglDeleteBuffers(standardQuadVBO);
+			standardQuadVBO = null;
+		}
+		if(vshLocal != null) {
+			vshLocal.free();
+			vshLocal = null;
+			vshLocalLayout = null;
+		}
 	}
 
 }
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/EaglerMeshLoader.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/EaglerMeshLoader.java
index e4c6f11b..cb1c7b60 100644
--- a/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/EaglerMeshLoader.java
+++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/EaglerMeshLoader.java
@@ -39,7 +39,7 @@ public class EaglerMeshLoader implements IResourceManagerReloadListener {
 
 	private static final Logger logger = LogManager.getLogger("EaglerMeshLoader");
 
-	private static final Map<ResourceLocation, HighPolyMesh> meshCache = new HashMap();
+	private static final Map<ResourceLocation, HighPolyMesh> meshCache = new HashMap<>();
 
 	public static HighPolyMesh getEaglerMesh(ResourceLocation meshLoc) {
 		if(meshLoc.cachedPointerType == ResourceLocation.CACHED_POINTER_EAGLER_MESH) {
@@ -104,7 +104,7 @@ public class EaglerMeshLoader implements IResourceManagerReloadListener {
 			}
 
 			if(meshStruct.vertexArray == null) {
-				meshStruct.vertexArray = _wglGenVertexArrays();
+				meshStruct.vertexArray = EaglercraftGPU.createGLBufferArray();
 			}
 			if(meshStruct.vertexBuffer == null) {
 				meshStruct.vertexBuffer = _wglGenBuffers();
@@ -115,29 +115,29 @@ public class EaglerMeshLoader implements IResourceManagerReloadListener {
 			
 			up1.position(0).limit(intsOfVertex);
 			
-			EaglercraftGPU.bindGLArrayBuffer(meshStruct.vertexBuffer);
+			EaglercraftGPU.bindVAOGLArrayBufferNow(meshStruct.vertexBuffer);
 			_wglBufferData(GL_ARRAY_BUFFER, up1, GL_STATIC_DRAW);
 			
 			EaglercraftGPU.bindGLBufferArray(meshStruct.vertexArray);
 			
 			up1.position(intsOfVertex).limit(intsTotal);
 			
-			_wglBindBuffer(GL_ELEMENT_ARRAY_BUFFER, meshStruct.indexBuffer);
+			EaglercraftGPU.bindVAOGLElementArrayBufferNow(meshStruct.indexBuffer);
 			_wglBufferData(GL_ELEMENT_ARRAY_BUFFER, up1, GL_STATIC_DRAW);
 			
-			_wglEnableVertexAttribArray(0);
-			_wglVertexAttribPointer(0, 3, GL_FLOAT, false, stride, 0);
+			EaglercraftGPU.enableVertexAttribArray(0);
+			EaglercraftGPU.vertexAttribPointer(0, 3, GL_FLOAT, false, stride, 0);
 			
 			if(meshStruct.hasTexture) {
-				_wglEnableVertexAttribArray(1);
-				_wglVertexAttribPointer(1, 2, GL_FLOAT, false, stride, 16);
+				EaglercraftGPU.enableVertexAttribArray(1);
+				EaglercraftGPU.vertexAttribPointer(1, 2, GL_FLOAT, false, stride, 16);
 			}
 			
-			_wglEnableVertexAttribArray(meshStruct.hasTexture ? 2 : 1);
-			_wglVertexAttribPointer(meshStruct.hasTexture ? 2 : 1, 4, GL_BYTE, true, stride, 12);
+			EaglercraftGPU.enableVertexAttribArray(meshStruct.hasTexture ? 2 : 1);
+			EaglercraftGPU.vertexAttribPointer(meshStruct.hasTexture ? 2 : 1, 4, GL_BYTE, true, stride, 12);
 		}catch(Throwable ex) {
 			if(meshStruct.vertexArray != null) {
-				_wglDeleteVertexArrays(meshStruct.vertexArray);
+				EaglercraftGPU.destroyGLBufferArray(meshStruct.vertexArray);
 				meshStruct.vertexArray = null;
 			}
 			if(meshStruct.vertexBuffer != null) {
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/EaglercraftGPU.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/EaglercraftGPU.java
index a5b60b2f..87ac654d 100644
--- a/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/EaglercraftGPU.java
+++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/EaglercraftGPU.java
@@ -5,6 +5,7 @@ import net.lax1dude.eaglercraft.v1_8.internal.buffer.FloatBuffer;
 import net.lax1dude.eaglercraft.v1_8.internal.buffer.IntBuffer;
 import net.lax1dude.eaglercraft.v1_8.log4j.LogManager;
 import net.lax1dude.eaglercraft.v1_8.log4j.Logger;
+import net.minecraft.util.MathHelper;
 
 import java.util.HashMap;
 import java.util.Map;
@@ -16,7 +17,6 @@ import net.lax1dude.eaglercraft.v1_8.internal.IBufferGL;
 import net.lax1dude.eaglercraft.v1_8.internal.IProgramGL;
 import net.lax1dude.eaglercraft.v1_8.internal.IQueryGL;
 import net.lax1dude.eaglercraft.v1_8.internal.ITextureGL;
-import net.lax1dude.eaglercraft.v1_8.internal.PlatformBufferFunctions;
 import net.lax1dude.eaglercraft.v1_8.internal.PlatformOpenGL;
 
 import static net.lax1dude.eaglercraft.v1_8.opengl.RealOpenGLEnums.*;
@@ -39,12 +39,15 @@ import static net.lax1dude.eaglercraft.v1_8.internal.PlatformOpenGL.*;
  */
 public class EaglercraftGPU {
 
-	static final GLObjectMap<ITextureGL> mapTexturesGL = new GLObjectMap(32767);
-	static final GLObjectMap<IQueryGL> mapQueriesGL = new GLObjectMap(32767);
-	static final GLObjectMap<DisplayList> mapDisplayListsGL = new GLObjectMap(32767);
+	static final GLObjectMap<ITextureGL> mapTexturesGL = new GLObjectMap<>(8192);
+	static final GLObjectMap<IQueryGL> mapQueriesGL = new GLObjectMap<>(8192);
+	static final GLObjectMap<DisplayList> mapDisplayListsGL = new GLObjectMap<>(8192);
 
 	static final Logger logger = LogManager.getLogger("EaglercraftGPU");
 
+	static boolean emulatedVAOs = false;
+	static SoftGLBufferState emulatedVAOState = new SoftGLBufferState();
+
 	public static final String gluErrorString(int i) {
 		switch(i) {
 		case GL_INVALID_ENUM: return "GL_INVALID_ENUM";
@@ -87,16 +90,16 @@ public class EaglercraftGPU {
 			EaglercraftGPU.bindGLBufferArray(dp.vertexArray);
 			int c = 0;
 			if((dp.attribs & ATTRIB_TEXTURE) == ATTRIB_TEXTURE) {
-				_wglDisableVertexAttribArray(++c);
+				EaglercraftGPU.disableVertexAttribArray(++c);
 			}
 			if((dp.attribs & ATTRIB_COLOR) == ATTRIB_COLOR) {
-				_wglDisableVertexAttribArray(++c);
+				EaglercraftGPU.disableVertexAttribArray(++c);
 			}
 			if((dp.attribs & ATTRIB_NORMAL) == ATTRIB_NORMAL) {
-				_wglDisableVertexAttribArray(++c);
+				EaglercraftGPU.disableVertexAttribArray(++c);
 			}
 			if((dp.attribs & ATTRIB_LIGHTMAP) == ATTRIB_LIGHTMAP) {
-				_wglDisableVertexAttribArray(++c);
+				EaglercraftGPU.disableVertexAttribArray(++c);
 			}
 		}
 		dp.attribs = -1;
@@ -109,7 +112,7 @@ public class EaglercraftGPU {
 		if(displayListBuffer.capacity() < wantSize) {
 			int newSize = (wantSize & 0xFFFE0000) + 0x40000;
 			ByteBuffer newBuffer = EagRuntime.allocateByteBuffer(newSize);
-			PlatformBufferFunctions.put(newBuffer, (ByteBuffer)displayListBuffer.flip());
+			newBuffer.put((ByteBuffer)displayListBuffer.flip());
 			EagRuntime.freeByteBuffer(displayListBuffer);
 			displayListBuffer = newBuffer;
 		}
@@ -123,7 +126,7 @@ public class EaglercraftGPU {
 		
 		if(dp.attribs == -1) {
 			if(dp.vertexArray != null) {
-				_wglDeleteVertexArrays(dp.vertexArray);
+				EaglercraftGPU.destroyGLBufferArray(dp.vertexArray);
 				dp.vertexArray = null;
 			}
 			if(dp.vertexBuffer != null) {
@@ -135,7 +138,7 @@ public class EaglercraftGPU {
 		}
 		
 		if(dp.vertexArray == null) {
-			dp.vertexArray = _wglGenVertexArrays();
+			dp.vertexArray = createGLBufferArray();
 			dp.bindQuad16 = false;
 			dp.bindQuad32 = false;
 		}
@@ -143,7 +146,7 @@ public class EaglercraftGPU {
 			dp.vertexBuffer = _wglGenBuffers();
 		}
 		
-		bindGLArrayBuffer(dp.vertexBuffer);
+		bindVAOGLArrayBufferNow(dp.vertexBuffer);
 		displayListBuffer.flip();
 		_wglBufferData(GL_ARRAY_BUFFER, displayListBuffer, GL_STATIC_DRAW);
 		displayListBuffer.clear();
@@ -194,7 +197,7 @@ public class EaglercraftGPU {
 		}
 		dp.attribs = -1;
 		if(dp.vertexArray != null) {
-			_wglDeleteVertexArrays(dp.vertexArray);
+			EaglercraftGPU.destroyGLBufferArray(dp.vertexArray);
 			dp.vertexArray = null;
 		}
 		if(dp.vertexBuffer != null) {
@@ -210,7 +213,7 @@ public class EaglercraftGPU {
 		++GlStateManager.stateNormalSerial;
 	}
 	
-	private static final Map<Integer,String> stringCache = new HashMap();
+	private static final Map<Integer,String> stringCache = new HashMap<>();
 
 	public static final String glGetString(int param) {
 		String str = stringCache.get(param);
@@ -238,9 +241,24 @@ public class EaglercraftGPU {
 		return _wglGetInteger(param);
 	}
 
+	public static final void glTexImage2D(int target, int level, int internalFormat, int w, int h, int unused,
+			int format, int type, ByteBuffer pixels) {
+		if(glesVers >= 300) {
+			_wglTexImage2D(target, level, internalFormat, w, h, unused, format, type, pixels);
+		}else {
+			int tv = TextureFormatHelper.trivializeInternalFormatToGLES20(internalFormat);
+			_wglTexImage2D(target, level, tv, w, h, unused, tv, type, pixels);
+		}
+	}
+
 	public static final void glTexImage2D(int target, int level, int internalFormat, int w, int h, int unused,
 			int format, int type, IntBuffer pixels) {
-		_wglTexImage2D(target, level, internalFormat, w, h, unused, format, type, pixels);
+		if(glesVers >= 300) {
+			_wglTexImage2D(target, level, internalFormat, w, h, unused, format, type, pixels);
+		}else {
+			int tv = TextureFormatHelper.trivializeInternalFormatToGLES20(internalFormat);
+			_wglTexImage2D(target, level, tv, w, h, unused, tv, type, pixels);
+		}
 	}
 
 	public static final void glTexSubImage2D(int target, int level, int x, int y, int w, int h, int format,
@@ -249,9 +267,32 @@ public class EaglercraftGPU {
 	}
 
 	public static final void glTexStorage2D(int target, int levels, int internalFormat, int w, int h) {
-		_wglTexStorage2D(target, levels, internalFormat, w, h);
+		if(texStorageCapable && (glesVers >= 300 || levels == 1 || (MathHelper.calculateLogBaseTwo(Math.max(w, h)) + 1) == levels)) {
+			_wglTexStorage2D(target, levels, internalFormat, w, h);
+		}else {
+			int tv = TextureFormatHelper.trivializeInternalFormatToGLES20(internalFormat);
+			int type = TextureFormatHelper.getTypeFromInternal(internalFormat);
+			for(int i = 0; i < levels; ++i) {
+				_wglTexImage2D(target, i, tv, Math.max(w >> i, 1), Math.max(h >> i, 1), 0, tv, type, (ByteBuffer)null);
+			}
+		}
 	}
-	
+
+	public static final void glReadPixels(int x, int y, int width, int height, int format, int type, ByteBuffer buffer) {
+		switch(type) {
+		case GL_FLOAT:
+			_wglReadPixels(x, y, width, height, format, GL_FLOAT, buffer.asFloatBuffer());
+			break;
+		case 0x140B: // GL_HALF_FLOAT
+			_wglReadPixels_u16(x, y, width, height, format, glesVers == 200 ? 0x8D61 : 0x140B, buffer);
+			break;
+		case GL_UNSIGNED_BYTE:
+		default:
+			_wglReadPixels(x, y, width, height, format, type, buffer);
+			break;
+		}
+	}
+
 	public static final void glLineWidth(float f) {
 		_wglLineWidth(f);
 	}
@@ -284,7 +325,7 @@ public class EaglercraftGPU {
 		DisplayList d = mapDisplayListsGL.free(id);
 		if(d != null) {
 			if(d.vertexArray != null) {
-				_wglDeleteVertexArrays(d.vertexArray);
+				EaglercraftGPU.destroyGLBufferArray(d.vertexArray);
 			}
 			if(d.vertexBuffer != null) {
 				_wglDeleteBuffers(d.vertexBuffer);
@@ -302,18 +343,197 @@ public class EaglercraftGPU {
 			GlStateManager.stateBlendEquation = equation;
 		}
 	}
-	
-	private static IBufferArrayGL currentBufferArray = null;
-	
-	public static final void bindGLBufferArray(IBufferArrayGL buffer) {
-		if(currentBufferArray != buffer) {
-			_wglBindVertexArray(buffer);
-			currentBufferArray = buffer;
+
+	public static final boolean areVAOsEmulated() {
+		return emulatedVAOs;
+	}
+
+	public static final IBufferArrayGL createGLBufferArray() {
+		if(emulatedVAOs) {
+			return new SoftGLBufferArray();
+		}else {
+			return _wglGenVertexArrays();
 		}
 	}
+
+	public static final void destroyGLBufferArray(IBufferArrayGL buffer) {
+		if(!emulatedVAOs) {
+			_wglDeleteVertexArrays(buffer);
+		}
+	}
+
+	public static final void enableVertexAttribArray(int index) {
+		if(emulatedVAOs) {
+			if(currentBufferArray == null) {
+				logger.warn("Skipping enable attrib with emulated VAO because no known VAO is bound!");
+				return;
+			}
+			((SoftGLBufferArray)currentBufferArray).enableAttrib(index, true);
+		}else {
+			_wglEnableVertexAttribArray(index);
+		}
+	}
+
+	public static final void disableVertexAttribArray(int index) {
+		if(emulatedVAOs) {
+			if(currentBufferArray == null) {
+				logger.warn("Skipping disable attrib with emulated VAO because no known VAO is bound!");
+				return;
+			}
+			((SoftGLBufferArray)currentBufferArray).enableAttrib(index, false);
+		}else {
+			_wglDisableVertexAttribArray(index);
+		}
+	}
+
+	public static final void vertexAttribPointer(int index, int size, int format, boolean normalized, int stride, int offset) {
+		if(emulatedVAOs) {
+			if(currentBufferArray == null) {
+				logger.warn("Skipping vertexAttribPointer with emulated VAO because no known VAO is bound!");
+				return;
+			}
+			if(currentVAOArrayBuffer == null) {
+				logger.warn("Skipping vertexAttribPointer with emulated VAO because no VAO array buffer is bound!");
+				return;
+			}
+			((SoftGLBufferArray)currentBufferArray).setAttrib(currentVAOArrayBuffer, index, size, format, normalized, stride, offset);
+		}else {
+			_wglVertexAttribPointer(index, size, format, normalized, stride, offset);
+		}
+	}
+
+	public static final void vertexAttribDivisor(int index, int divisor) {
+		if(emulatedVAOs) {
+			if(currentBufferArray == null) {
+				logger.warn("Skipping vertexAttribPointer with emulated VAO because no known VAO is bound!");
+				return;
+			}
+			((SoftGLBufferArray)currentBufferArray).setAttribDivisor(index, divisor);
+		}else {
+			_wglVertexAttribDivisor(index, divisor);
+		}
+	}
+
+	public static final void doDrawArrays(int mode, int first, int count) {
+		if(emulatedVAOs) {
+			if(currentBufferArray == null) {
+				logger.warn("Skipping draw call with emulated VAO because no known VAO is bound!");
+				return;
+			}
+			((SoftGLBufferArray)currentBufferArray).transitionToState(emulatedVAOState, false);
+		}
+		_wglDrawArrays(mode, first, count);
+	}
+
+	public static final void doDrawElements(int mode, int count, int type, int offset) {
+		if(emulatedVAOs) {
+			if(currentBufferArray == null) {
+				logger.warn("Skipping draw call with emulated VAO because no known VAO is bound!");
+				return;
+			}
+			((SoftGLBufferArray)currentBufferArray).transitionToState(emulatedVAOState, true);
+		}
+		_wglDrawElements(mode, count, type, offset);
+	}
+
+	public static final void doDrawArraysInstanced(int mode, int first, int count, int instances) {
+		if(emulatedVAOs) {
+			if(currentBufferArray == null) {
+				logger.warn("Skipping instanced draw call with emulated VAO because no known VAO is bound!");
+				return;
+			}
+			((SoftGLBufferArray)currentBufferArray).transitionToState(emulatedVAOState, false);
+		}
+		_wglDrawArraysInstanced(mode, first, count, instances);
+	}
+
+	public static final void doDrawElementsInstanced(int mode, int count, int type, int offset, int instances) {
+		if(emulatedVAOs) {
+			if(currentBufferArray == null) {
+				logger.warn("Skipping instanced draw call with emulated VAO because no known VAO is bound!");
+				return;
+			}
+			((SoftGLBufferArray)currentBufferArray).transitionToState(emulatedVAOState, true);
+		}
+		_wglDrawElementsInstanced(mode, count, type, offset, instances);
+	}
+
+	static IBufferArrayGL currentBufferArray = null;
 	
-	private static IBufferGL currentArrayBuffer = null;
-	
+	public static final void bindGLBufferArray(IBufferArrayGL buffer) {
+		if(emulatedVAOs) {
+			currentBufferArray = buffer;
+		}else {
+			if(currentBufferArray != buffer) {
+				_wglBindVertexArray(buffer);
+				currentBufferArray = buffer;
+			}
+		}
+	}
+
+	static IBufferGL currentArrayBuffer = null;
+
+	// only used when VAOs are emulated
+	static IBufferGL currentVAOArrayBuffer = null;
+
+	public static final void bindVAOGLArrayBuffer(IBufferGL buffer) {
+		if(emulatedVAOs) {
+			currentVAOArrayBuffer = buffer;
+		}else {
+			if(currentArrayBuffer != buffer) {
+				_wglBindBuffer(GL_ARRAY_BUFFER, buffer);
+				currentArrayBuffer = buffer;
+			}
+		}
+	}
+
+	public static final void bindVAOGLArrayBufferNow(IBufferGL buffer) {
+		if(emulatedVAOs) {
+			currentVAOArrayBuffer = buffer;
+		}
+		if(currentArrayBuffer != buffer) {
+			_wglBindBuffer(GL_ARRAY_BUFFER, buffer);
+			currentArrayBuffer = buffer;
+		}
+	}
+
+	public static final void bindVAOGLElementArrayBuffer(IBufferGL buffer) {
+		if(emulatedVAOs) {
+			if(currentBufferArray == null) {
+				logger.warn("Skipping set element array buffer with emulated VAO because no known VAO is bound!");
+				return;
+			}
+			((SoftGLBufferArray)currentBufferArray).setIndexBuffer(buffer);
+		}else {
+			_wglBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffer);
+		}
+	}
+
+	static final void bindVAOGLElementArrayBufferNow(IBufferGL buffer) {
+		if(emulatedVAOs) {
+			if(currentBufferArray == null) {
+				logger.warn("Skipping set element array buffer with emulated VAO because no known VAO is bound!");
+				return;
+			}
+			((SoftGLBufferArray)currentBufferArray).setIndexBuffer(buffer);
+			if(currentEmulatedVAOIndexBuffer != buffer) {
+				_wglBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffer);
+				currentEmulatedVAOIndexBuffer = buffer;
+			}
+		}else {
+			_wglBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffer);
+		}
+	}
+
+	static IBufferGL currentEmulatedVAOIndexBuffer = null;
+
+	static final void bindEmulatedVAOIndexBuffer(IBufferGL buffer) {
+		if(currentEmulatedVAOIndexBuffer != buffer) {
+			_wglBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffer);
+			currentEmulatedVAOIndexBuffer = buffer;
+		}
+	}
+
 	public static final void bindGLArrayBuffer(IBufferGL buffer) {
 		if(currentArrayBuffer != buffer) {
 			_wglBindBuffer(GL_ARRAY_BUFFER, buffer);
@@ -321,7 +541,7 @@ public class EaglercraftGPU {
 		}
 	}
 	
-	private static IBufferGL currentUniformBuffer = null;
+	static IBufferGL currentUniformBuffer = null;
 	
 	public static final void bindGLUniformBuffer(IBufferGL buffer) {
 		if(currentUniformBuffer != buffer) {
@@ -330,7 +550,7 @@ public class EaglercraftGPU {
 		}
 	}
 	
-	private static IProgramGL currentShaderProgram = null;
+	static IProgramGL currentShaderProgram = null;
 	
 	public static final void bindGLShaderProgram(IProgramGL prog) {
 		if(currentShaderProgram != prog) {
@@ -352,6 +572,38 @@ public class EaglercraftGPU {
 			currentUniformBlockBindingSize[index] = size;
 		}
 	}
+
+	public static final int CLEAR_BINDING_TEXTURE = 1;
+	public static final int CLEAR_BINDING_TEXTURE0 = 2;
+	public static final int CLEAR_BINDING_ACTIVE_TEXTURE = 4;
+	public static final int CLEAR_BINDING_BUFFER_ARRAY = 8;
+	public static final int CLEAR_BINDING_ARRAY_BUFFER = 16;
+	public static final int CLEAR_BINDING_SHADER_PROGRAM = 32;
+	
+	public static final void clearCurrentBinding(int mask) {
+		if((mask & CLEAR_BINDING_TEXTURE) != 0) {
+			int[] i = GlStateManager.boundTexture;
+			for(int j = 0; j < i.length; ++j) {
+				i[j] = -1;
+			}
+		}
+		if((mask & CLEAR_BINDING_TEXTURE0) != 0) {
+			GlStateManager.boundTexture[0] = -1;
+		}
+		if((mask & CLEAR_BINDING_ACTIVE_TEXTURE) != 0) {
+			GlStateManager.activeTexture = 0;
+			_wglActiveTexture(GL_TEXTURE0);
+		}
+		if((mask & CLEAR_BINDING_BUFFER_ARRAY) != 0) {
+			currentBufferArray = null;
+		}
+		if((mask & CLEAR_BINDING_ARRAY_BUFFER) != 0) {
+			currentArrayBuffer = currentVAOArrayBuffer = null;
+		}
+		if((mask & CLEAR_BINDING_SHADER_PROGRAM) != 0) {
+			currentShaderProgram = null;
+		}
+	}
 	
 	public static final int ATTRIB_TEXTURE = 1;
 	public static final int ATTRIB_COLOR = 2;
@@ -414,7 +666,7 @@ public class EaglercraftGPU {
 			if(newSize > 0xFFFF) {
 				newSize = 0xFFFF;
 			}
-			_wglBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buf);
+			EaglercraftGPU.bindVAOGLElementArrayBufferNow(buf);
 			resizeQuad16EmulationBuffer(newSize >> 2);
 		}else {
 			int cnt = quad16EmulationBufferSize;
@@ -423,10 +675,10 @@ public class EaglercraftGPU {
 				if(newSize > 0xFFFF) {
 					newSize = 0xFFFF;
 				}
-				_wglBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buf);
+				EaglercraftGPU.bindVAOGLElementArrayBufferNow(buf);
 				resizeQuad16EmulationBuffer(newSize >> 2);
 			}else if(bind) {
-				_wglBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buf);
+				EaglercraftGPU.bindVAOGLElementArrayBuffer(buf);
 			}
 		}
 	}
@@ -436,16 +688,16 @@ public class EaglercraftGPU {
 		if(buf == null) {
 			quad32EmulationBuffer = buf = _wglGenBuffers();
 			int newSize = quad32EmulationBufferSize = (vertexCount & 0xFFFFC000) + 0x8000;
-			_wglBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buf);
+			EaglercraftGPU.bindVAOGLElementArrayBufferNow(buf);
 			resizeQuad32EmulationBuffer(newSize >> 2);
 		}else {
 			int cnt = quad32EmulationBufferSize;
 			if(cnt < vertexCount) {
 				int newSize = quad32EmulationBufferSize = (vertexCount & 0xFFFFC000) + 0x8000;
-				_wglBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buf);
+				EaglercraftGPU.bindVAOGLElementArrayBufferNow(buf);
 				resizeQuad32EmulationBuffer(newSize >> 2);
 			}else if(bind) {
-				_wglBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buf);
+				EaglercraftGPU.bindVAOGLElementArrayBuffer(buf);
 			}
 		}
 	}
@@ -508,9 +760,19 @@ public class EaglercraftGPU {
 		p.drawElements(GL_TRIANGLES, mesh.indexCount, GL_UNSIGNED_SHORT, 0);
 	}
 
+	static int glesVers = -1;
 	static boolean hasFramebufferHDR16FSupport = false;
 	static boolean hasFramebufferHDR32FSupport = false;
+	static boolean hasLinearHDR16FSupport = false;
 	static boolean hasLinearHDR32FSupport = false;
+	static boolean fboRenderMipmapCapable = false;
+	static boolean vertexArrayCapable = false;
+	static boolean instancingCapable = false;
+	static boolean texStorageCapable = false;
+	static boolean textureLODCapable = false;
+	static boolean shader5Capable = false;
+	static boolean npotCapable = false;
+	static int uniformBufferOffsetAlignment = -1;
 
 	public static final void createFramebufferHDR16FTexture(int target, int level, int w, int h, int format, boolean allow32bitFallback) {
 		createFramebufferHDR16FTexture(target, level, w, h, format, allow32bitFallback, null);
@@ -525,19 +787,24 @@ public class EaglercraftGPU {
 			int internalFormat;
 			switch(format) {
 			case GL_RED:
-				internalFormat = 0x822D; // GL_R16F
+				if(glesVers == 200) {
+					format = GL_LUMINANCE;
+					internalFormat = GL_LUMINANCE;
+				}else {
+					internalFormat = glesVers == 200 ? GL_LUMINANCE : 0x822D; // GL_R16F
+				}
 				break;
 			case 0x8227: // GL_RG
-				internalFormat = 0x822F; // GL_RG16F
+				internalFormat = glesVers == 200 ? 0x8227 : 0x822F; // GL_RG16F
 			case GL_RGB:
 				throw new UnsupportedOperationException("GL_RGB16F isn't supported specifically in WebGL 2.0 for some goddamn reason");
 			case GL_RGBA:
-				internalFormat = 0x881A; // GL_RGBA16F
+				internalFormat = glesVers == 200 ? GL_RGBA : 0x881A; // GL_RGBA16F
 				break;
 			default:
 				throw new UnsupportedOperationException("Unknown format: " + format);
 			}
-			_wglTexImage2Du16(target, level, internalFormat, w, h, 0, format, 0x140B, pixelData);
+			_wglTexImage2Du16(target, level, internalFormat, w, h, 0, format, glesVers == 200 ? 0x8D61 : 0x140B, pixelData);
 		}else {
 			if(allow32bitFallback) {
 				if(hasFramebufferHDR32FSupport) {
@@ -567,7 +834,7 @@ public class EaglercraftGPU {
 				internalFormat = 0x822E; // GL_R32F
 				break;
 			case 0x8227: // GL_RG
-				internalFormat = 0x822F; // GL_RG32F
+				internalFormat = 0x8230; // GL_RG32F
 			case GL_RGB:
 				throw new UnsupportedOperationException("GL_RGB32F isn't supported specifically in WebGL 2.0 for some goddamn reason");
 			case GL_RGBA:
@@ -594,19 +861,38 @@ public class EaglercraftGPU {
 		EaglercraftGPU.glGetString(7936);
 		EaglercraftGPU.glGetString(7937);
 		EaglercraftGPU.glGetString(7938);
+		glesVers = PlatformOpenGL.checkOpenGLESVersion();
+		vertexArrayCapable = PlatformOpenGL.checkVAOCapable();
+		emulatedVAOs = !vertexArrayCapable;
+		fboRenderMipmapCapable = PlatformOpenGL.checkFBORenderMipmapCapable();
+		instancingCapable = PlatformOpenGL.checkInstancingCapable();
+		texStorageCapable = PlatformOpenGL.checkTexStorageCapable();
+		textureLODCapable = PlatformOpenGL.checkTextureLODCapable();
+		shader5Capable = PlatformOpenGL.checkOESGPUShader5Capable() || PlatformOpenGL.checkEXTGPUShader5Capable();
+		npotCapable = PlatformOpenGL.checkNPOTCapable();
+		uniformBufferOffsetAlignment = glesVers >= 300 ? _wglGetInteger(0x8A34) : -1;
+		if(!npotCapable) {
+			logger.warn("NPOT texture support detected as false, texture wrapping must be set to GL_CLAMP_TO_EDGE if the texture's width or height is not a power of 2");
+		}
 		hasFramebufferHDR16FSupport = PlatformOpenGL.checkHDRFramebufferSupport(16);
 		if(hasFramebufferHDR16FSupport) {
 			logger.info("16-bit HDR render target support: true");
 		}else {
 			logger.error("16-bit HDR render target support: false");
 		}
+		hasLinearHDR16FSupport = PlatformOpenGL.checkLinearHDRFilteringSupport(16);
+		if(hasLinearHDR16FSupport) {
+			logger.info("16-bit HDR linear filter support: true");
+		}else {
+			logger.error("16-bit HDR linear filter support: false");
+		}
 		hasFramebufferHDR32FSupport = PlatformOpenGL.checkHDRFramebufferSupport(32);
 		if(hasFramebufferHDR32FSupport) {
 			logger.info("32-bit HDR render target support: true");
 		}else {
 			logger.error("32-bit HDR render target support: false");
 		}
-		hasLinearHDR32FSupport = PlatformOpenGL.checkLinearHDR32FSupport();
+		hasLinearHDR32FSupport = PlatformOpenGL.checkLinearHDRFilteringSupport(32);
 		if(hasLinearHDR32FSupport) {
 			logger.info("32-bit HDR linear filter support: true");
 		}else {
@@ -615,16 +901,86 @@ public class EaglercraftGPU {
 		if(!checkHasHDRFramebufferSupportWithFilter()) {
 			logger.error("No HDR render target support was detected! Shaders will be disabled.");
 		}
+		if(emulatedVAOs) {
+			logger.info("Note: Could not unlock VAOs via OpenGL extensions, emulating them instead");
+		}
+		if(!instancingCapable) {
+			logger.info("Note: Could not unlock instancing via OpenGL extensions, using slow vanilla font and particle rendering");
+		}
+		emulatedVAOState = emulatedVAOs ? new SoftGLBufferState() : null;
+		PlatformOpenGL.enterVAOEmulationHook();
+		GLSLHeader.init();
 		DrawUtils.init();
 		SpriteLevelMixer.initialize();
-		InstancedFontRenderer.initialize();
-		InstancedParticleRenderer.initialize();
+		if(instancingCapable) {
+			InstancedFontRenderer.initialize();
+			InstancedParticleRenderer.initialize();
+		}
 		EffectPipelineFXAA.initialize();
 		TextureCopyUtil.initialize();
 		DrawUtils.vshLocal.free();
 		DrawUtils.vshLocal = null;
 	}
 
+	public static final void destroyCache() {
+		stringCache.clear();
+		mapTexturesGL.clear();
+		mapQueriesGL.clear();
+		mapDisplayListsGL.clear();
+		emulatedVAOs = false;
+		emulatedVAOState = null;
+		glesVers = -1;
+		fboRenderMipmapCapable = false;
+		vertexArrayCapable = false;
+		instancingCapable = false;
+		hasFramebufferHDR16FSupport = false;
+		hasFramebufferHDR32FSupport = false;
+		hasLinearHDR32FSupport = false;
+		GLSLHeader.destroy();
+		DrawUtils.destroy();
+		SpriteLevelMixer.destroy();
+		InstancedFontRenderer.destroy();
+		InstancedParticleRenderer.destroy();
+		EffectPipelineFXAA.destroy();
+		TextureCopyUtil.destroy();
+	}
+
+	public static final int checkOpenGLESVersion() {
+		return glesVers;
+	}
+
+	public static final boolean checkFBORenderMipmapCapable() {
+		return fboRenderMipmapCapable;
+	}
+
+	public static final boolean checkVAOCapable() {
+		return vertexArrayCapable;
+	}
+
+	public static final boolean checkInstancingCapable() {
+		return instancingCapable;
+	}
+
+	public static final boolean checkTexStorageCapable() {
+		return texStorageCapable;
+	}
+
+	public static final boolean checkTextureLODCapable() {
+		return textureLODCapable;
+	}
+
+	public static final boolean checkShader5Capable() {
+		return shader5Capable;
+	}
+
+	public static final boolean checkNPOTCapable() {
+		return npotCapable;
+	}
+
+	public static final int getUniformBufferOffsetAlignment() {
+		return uniformBufferOffsetAlignment;
+	}
+
 	public static final boolean checkHDRFramebufferSupport(int bits) {
 		switch(bits) {
 		case 16:
@@ -636,15 +992,28 @@ public class EaglercraftGPU {
 		}
 	}
 
+	public static final boolean checkLinearHDRFilteringSupport(int bits) {
+		switch(bits) {
+		case 16:
+			return hasLinearHDR16FSupport;
+		case 32:
+			return hasLinearHDR32FSupport;
+		default:
+			return false;
+		}
+	}
+
 	public static final boolean checkHasHDRFramebufferSupport() {
 		return hasFramebufferHDR16FSupport || hasFramebufferHDR32FSupport;
 	}
 
 	public static final boolean checkHasHDRFramebufferSupportWithFilter() {
-		return hasFramebufferHDR16FSupport || (hasFramebufferHDR32FSupport && hasLinearHDR32FSupport);
+		return (hasFramebufferHDR16FSupport && hasLinearHDR16FSupport) || (hasFramebufferHDR32FSupport && hasLinearHDR32FSupport);
 	}
 
+	//legacy
 	public static final boolean checkLinearHDR32FSupport() {
 		return hasLinearHDR32FSupport;
 	}
+
 }
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/EffectPipelineFXAA.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/EffectPipelineFXAA.java
index f61fe144..9166ec7f 100644
--- a/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/EffectPipelineFXAA.java
+++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/EffectPipelineFXAA.java
@@ -8,7 +8,6 @@ import net.lax1dude.eaglercraft.v1_8.internal.IUniformGL;
 import net.lax1dude.eaglercraft.v1_8.internal.buffer.ByteBuffer;
 import net.lax1dude.eaglercraft.v1_8.log4j.LogManager;
 import net.lax1dude.eaglercraft.v1_8.log4j.Logger;
-import net.lax1dude.eaglercraft.v1_8.opengl.FixedFunctionShader.FixedFunctionConstants;
 
 import static net.lax1dude.eaglercraft.v1_8.opengl.RealOpenGLEnums.*;
 import static net.lax1dude.eaglercraft.v1_8.internal.PlatformOpenGL.*;
@@ -35,11 +34,13 @@ public class EffectPipelineFXAA {
 	private static final Logger logger = LogManager.getLogger("EffectPipelineFXAA");
 
 	public static final String fragmentShaderPath = "/assets/eagler/glsl/post_fxaa.fsh";
+	public static final String fragmentShaderPrecision = "precision lowp int;\nprecision mediump float;\nprecision mediump sampler2D;\n";
 
 	private static final int _GL_FRAMEBUFFER = 0x8D40;
 	private static final int _GL_RENDERBUFFER = 0x8D41;
 	private static final int _GL_COLOR_ATTACHMENT0 = 0x8CE0;
 	private static final int _GL_DEPTH_ATTACHMENT = 0x8D00;
+	private static final int _GL_DEPTH_COMPONENT16 = 0x81A5;
 	private static final int _GL_DEPTH_COMPONENT32F = 0x8CAC;
 
 	private static IProgramGL shaderProgram = null;
@@ -53,14 +54,11 @@ public class EffectPipelineFXAA {
 	private static int currentHeight = -1;
 
 	static void initialize() {
-		String fragmentSource = EagRuntime.getResourceString(fragmentShaderPath);
-		if(fragmentSource == null) {
-			throw new RuntimeException("EffectPipelineFXAA shader \"" + fragmentShaderPath + "\" is missing!");
-		}
+		String fragmentSource = EagRuntime.getRequiredResourceString(fragmentShaderPath);
 
 		IShaderGL frag = _wglCreateShader(GL_FRAGMENT_SHADER);
 
-		_wglShaderSource(frag, FixedFunctionConstants.VERSION + "\n" + fragmentSource);
+		_wglShaderSource(frag, GLSLHeader.getFragmentHeaderCompat(fragmentSource, fragmentShaderPrecision));
 		_wglCompileShader(frag);
 
 		if(_wglGetShaderi(frag, GL_COMPILE_STATUS) != GL_TRUE) {
@@ -80,6 +78,10 @@ public class EffectPipelineFXAA {
 		_wglAttachShader(shaderProgram, DrawUtils.vshLocal);
 		_wglAttachShader(shaderProgram, frag);
 
+		if(EaglercraftGPU.checkOpenGLESVersion() == 200) {
+			VSHInputLayoutParser.applyLayout(shaderProgram, DrawUtils.vshLocalLayout);
+		}
+
 		_wglLinkProgram(shaderProgram);
 
 		_wglDetachShader(shaderProgram, DrawUtils.vshLocal);
@@ -130,10 +132,10 @@ public class EffectPipelineFXAA {
 			currentHeight = height;
 
 			GlStateManager.bindTexture(framebufferColor);
-			_wglTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, (ByteBuffer)null);
+			EaglercraftGPU.glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, (ByteBuffer)null);
 
 			_wglBindRenderbuffer(_GL_RENDERBUFFER, framebufferDepth);
-			_wglRenderbufferStorage(_GL_RENDERBUFFER, _GL_DEPTH_COMPONENT32F, width, height);
+			_wglRenderbufferStorage(_GL_RENDERBUFFER, EaglercraftGPU.checkOpenGLESVersion() == 200 ? _GL_DEPTH_COMPONENT16 : _GL_DEPTH_COMPONENT32F, width, height);
 		}
 
 		_wglBindFramebuffer(_GL_FRAMEBUFFER, framebuffer);
@@ -155,4 +157,24 @@ public class EffectPipelineFXAA {
 		DrawUtils.drawStandardQuad2D();
 	}
 
+	public static void destroy() {
+		if(shaderProgram != null) {
+			_wglDeleteProgram(shaderProgram);
+			shaderProgram = null;
+		}
+		u_screenSize2f = null;
+		if(framebuffer != null) {
+			_wglDeleteFramebuffer(framebuffer);
+			framebuffer = null;
+		}
+		if(framebufferColor != -1) {
+			GlStateManager.deleteTexture(framebufferColor);
+			framebufferColor = -2;
+		}
+		if(framebufferDepth != null) {
+			_wglDeleteRenderbuffer(framebufferDepth);
+			framebufferDepth = null;
+		}
+	}
+
 }
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/FixedFunctionPipeline.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/FixedFunctionPipeline.java
index 1b714c0f..8b65c2e5 100644
--- a/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/FixedFunctionPipeline.java
+++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/FixedFunctionPipeline.java
@@ -98,33 +98,33 @@ public class FixedFunctionPipeline {
 		}
 		
 		EaglercraftGPU.bindGLBufferArray(list.vertexArray);
-		EaglercraftGPU.bindGLArrayBuffer(list.vertexBuffer);
+		EaglercraftGPU.bindVAOGLArrayBuffer(list.vertexBuffer);
 		
-		_wglEnableVertexAttribArray(0);
-		_wglVertexAttribPointer(0, VertexFormat.COMPONENT_POSITION_SIZE,
+		EaglercraftGPU.enableVertexAttribArray(0);
+		EaglercraftGPU.vertexAttribPointer(0, VertexFormat.COMPONENT_POSITION_SIZE,
 				VertexFormat.COMPONENT_POSITION_FORMAT, false, self.attribStride, 0);
 
 		if(self.attribTextureIndex != -1) {
-			_wglEnableVertexAttribArray(self.attribTextureIndex);
-			_wglVertexAttribPointer(self.attribTextureIndex, VertexFormat.COMPONENT_TEX_SIZE,
+			EaglercraftGPU.enableVertexAttribArray(self.attribTextureIndex);
+			EaglercraftGPU.vertexAttribPointer(self.attribTextureIndex, VertexFormat.COMPONENT_TEX_SIZE,
 					VertexFormat.COMPONENT_TEX_FORMAT, false, self.attribStride, self.attribTextureOffset);
 		}
 		
 		if(self.attribColorIndex != -1) {
-			_wglEnableVertexAttribArray(self.attribColorIndex);
-			_wglVertexAttribPointer(self.attribColorIndex, VertexFormat.COMPONENT_COLOR_SIZE,
+			EaglercraftGPU.enableVertexAttribArray(self.attribColorIndex);
+			EaglercraftGPU.vertexAttribPointer(self.attribColorIndex, VertexFormat.COMPONENT_COLOR_SIZE,
 					VertexFormat.COMPONENT_COLOR_FORMAT, true, self.attribStride, self.attribColorOffset);
 		}
 		
 		if(self.attribNormalIndex != -1) {
-			_wglEnableVertexAttribArray(self.attribNormalIndex);
-			_wglVertexAttribPointer(self.attribNormalIndex, VertexFormat.COMPONENT_NORMAL_SIZE,
+			EaglercraftGPU.enableVertexAttribArray(self.attribNormalIndex);
+			EaglercraftGPU.vertexAttribPointer(self.attribNormalIndex, VertexFormat.COMPONENT_NORMAL_SIZE,
 					VertexFormat.COMPONENT_NORMAL_FORMAT, true, self.attribStride, self.attribNormalOffset);
 		}
 		
 		if(self.attribLightmapIndex != -1) {
-			_wglEnableVertexAttribArray(self.attribLightmapIndex);
-			_wglVertexAttribPointer(self.attribLightmapIndex, VertexFormat.COMPONENT_LIGHTMAP_SIZE,
+			EaglercraftGPU.enableVertexAttribArray(self.attribLightmapIndex);
+			EaglercraftGPU.vertexAttribPointer(self.attribLightmapIndex, VertexFormat.COMPONENT_LIGHTMAP_SIZE,
 					VertexFormat.COMPONENT_LIGHTMAP_FORMAT, false, self.attribStride, self.attribLightmapOffset);
 		}
 		
@@ -145,7 +145,7 @@ public class FixedFunctionPipeline {
 	
 	void drawArrays(int mode, int offset, int count) {
 		EaglercraftGPU.bindGLShaderProgram(shaderProgram);
-		PlatformOpenGL._wglDrawArrays(mode, offset, count);
+		EaglercraftGPU.doDrawArrays(mode, offset, count);
 	}
 	
 	void drawDirectArrays(int mode, int offset, int count) {
@@ -160,7 +160,7 @@ public class FixedFunctionPipeline {
 				}else {
 					EaglercraftGPU.attachQuad32EmulationBuffer(count, false);
 				}
-				PlatformOpenGL._wglDrawElements(GL_TRIANGLES, count + (count >> 1),
+				EaglercraftGPU.doDrawElements(GL_TRIANGLES, count + (count >> 1),
 						GL_UNSIGNED_INT, 0);
 			}else {
 				if(!sb.bindQuad16) {
@@ -170,17 +170,17 @@ public class FixedFunctionPipeline {
 				}else {
 					EaglercraftGPU.attachQuad16EmulationBuffer(count, false);
 				}
-				PlatformOpenGL._wglDrawElements(GL_TRIANGLES, count + (count >> 1),
+				EaglercraftGPU.doDrawElements(GL_TRIANGLES, count + (count >> 1),
 						GL_UNSIGNED_SHORT, 0);
 			}
 		}else {
-			PlatformOpenGL._wglDrawArrays(mode, offset, count);
+			EaglercraftGPU.doDrawArrays(mode, offset, count);
 		}
 	}
 	
 	void drawElements(int mode, int count, int type, int offset) {
 		EaglercraftGPU.bindGLShaderProgram(shaderProgram);
-		PlatformOpenGL._wglDrawElements(mode, count, type, offset);
+		EaglercraftGPU.doDrawElements(mode, count, type, offset);
 	}
 	
 	private static IExtPipelineCompiler extensionProvider;
@@ -192,7 +192,7 @@ public class FixedFunctionPipeline {
 
 	private static final FixedFunctionPipeline[] pipelineStateCache = new FixedFunctionPipeline[fixedFunctionStatesBits + 1];
 	private static final FixedFunctionPipeline[][] pipelineExtStateCache = new FixedFunctionPipeline[fixedFunctionStatesBits + 1][];
-	private static final List<FixedFunctionPipeline> pipelineListTracker = new ArrayList(1024);
+	private static final List<FixedFunctionPipeline> pipelineListTracker = new ArrayList<>(1024);
 
 	private static String shaderSourceCacheVSH = null;
 	private static String shaderSourceCacheFSH = null;
@@ -232,22 +232,16 @@ public class FixedFunctionPipeline {
 			fshSource = extSource[1];
 		}else {
 			if(shaderSourceCacheVSH == null) {
-				shaderSourceCacheVSH = EagRuntime.getResourceString(FILENAME_VSH);
-				if(shaderSourceCacheVSH == null) {
-					throw new RuntimeException("Could not load: " + FILENAME_VSH);
-				}
+				shaderSourceCacheVSH = EagRuntime.getRequiredResourceString(FILENAME_VSH);
 			}
 			vshSource = shaderSourceCacheVSH;
 			if(shaderSourceCacheFSH == null) {
-				shaderSourceCacheFSH = EagRuntime.getResourceString(FILENAME_FSH);
-				if(shaderSourceCacheFSH == null) {
-					throw new RuntimeException("Could not load: " + FILENAME_FSH);
-				}
+				shaderSourceCacheFSH = EagRuntime.getRequiredResourceString(FILENAME_FSH);
 			}
 			fshSource = shaderSourceCacheFSH;
 		}
 		
-		StringBuilder macros = new StringBuilder(VERSION + "\n");
+		StringBuilder macros = new StringBuilder();
 		if((coreBits & STATE_HAS_ATTRIB_TEXTURE) != 0) {
 			macros.append("#define " + MACRO_ATTRIB_TEXTURE + "\n");
 		}
@@ -291,7 +285,8 @@ public class FixedFunctionPipeline {
 		
 		IShaderGL vsh = _wglCreateShader(GL_VERTEX_SHADER);
 		
-		_wglShaderSource(vsh, macros.toString() + vshSource);
+		String macrosStr = macros.toString();
+		_wglShaderSource(vsh, GLSLHeader.getVertexHeaderCompat(vshSource, macrosStr));
 		_wglCompileShader(vsh);
 		
 		if(_wglGetShaderi(vsh, GL_COMPILE_STATUS) != GL_TRUE) {
@@ -309,7 +304,7 @@ public class FixedFunctionPipeline {
 		
 		IShaderGL fsh = _wglCreateShader(GL_FRAGMENT_SHADER);
 		
-		_wglShaderSource(fsh, macros.toString() + fshSource);
+		_wglShaderSource(fsh, GLSLHeader.getFragmentHeaderCompat(fshSource, macrosStr));
 		_wglCompileShader(fsh);
 		
 		if(_wglGetShaderi(fsh, GL_COMPILE_STATUS) != GL_TRUE) {
@@ -581,45 +576,45 @@ public class FixedFunctionPipeline {
 		streamBuffer = new StreamBuffer(FixedFunctionShader.initialSize, FixedFunctionShader.initialCount,
 				FixedFunctionShader.maxCount, (vertexArray, vertexBuffer) -> {
 					EaglercraftGPU.bindGLBufferArray(vertexArray);
-					EaglercraftGPU.bindGLArrayBuffer(vertexBuffer);
+					EaglercraftGPU.bindVAOGLArrayBuffer(vertexBuffer);
 
-					_wglEnableVertexAttribArray(0);
-					_wglVertexAttribPointer(0, VertexFormat.COMPONENT_POSITION_SIZE,
+					EaglercraftGPU.enableVertexAttribArray(0);
+					EaglercraftGPU.vertexAttribPointer(0, VertexFormat.COMPONENT_POSITION_SIZE,
 							VertexFormat.COMPONENT_POSITION_FORMAT, false, attribStride, 0);
 
 					if(attribTextureIndex != -1) {
-						_wglEnableVertexAttribArray(attribTextureIndex);
-						_wglVertexAttribPointer(attribTextureIndex, VertexFormat.COMPONENT_TEX_SIZE,
+						EaglercraftGPU.enableVertexAttribArray(attribTextureIndex);
+						EaglercraftGPU.vertexAttribPointer(attribTextureIndex, VertexFormat.COMPONENT_TEX_SIZE,
 								VertexFormat.COMPONENT_TEX_FORMAT, false, attribStride, attribTextureOffset);
 					}
 					
 					if(attribColorIndex != -1) {
-						_wglEnableVertexAttribArray(attribColorIndex);
-						_wglVertexAttribPointer(attribColorIndex, VertexFormat.COMPONENT_COLOR_SIZE,
+						EaglercraftGPU.enableVertexAttribArray(attribColorIndex);
+						EaglercraftGPU.vertexAttribPointer(attribColorIndex, VertexFormat.COMPONENT_COLOR_SIZE,
 								VertexFormat.COMPONENT_COLOR_FORMAT, true, attribStride, attribColorOffset);
 					}
 					
 					if(attribNormalIndex != -1) {
-						_wglEnableVertexAttribArray(attribNormalIndex);
-						_wglVertexAttribPointer(attribNormalIndex, VertexFormat.COMPONENT_NORMAL_SIZE,
+						EaglercraftGPU.enableVertexAttribArray(attribNormalIndex);
+						EaglercraftGPU.vertexAttribPointer(attribNormalIndex, VertexFormat.COMPONENT_NORMAL_SIZE,
 								VertexFormat.COMPONENT_NORMAL_FORMAT, true, attribStride, attribNormalOffset);
 					}
 					
 					if(attribLightmapIndex != -1) {
-						_wglEnableVertexAttribArray(attribLightmapIndex);
-						_wglVertexAttribPointer(attribLightmapIndex, VertexFormat.COMPONENT_LIGHTMAP_SIZE,
+						EaglercraftGPU.enableVertexAttribArray(attribLightmapIndex);
+						EaglercraftGPU.vertexAttribPointer(attribLightmapIndex, VertexFormat.COMPONENT_LIGHTMAP_SIZE,
 								VertexFormat.COMPONENT_LIGHTMAP_FORMAT, false, attribStride, attribLightmapOffset);
 					}
 				});
 
-		stateEnableTexture2D = (bits & STATE_ENABLE_TEXTURE2D) == STATE_ENABLE_TEXTURE2D;
-		stateEnableLightmap = (bits & STATE_ENABLE_LIGHTMAP) == STATE_ENABLE_LIGHTMAP;
-		stateEnableAlphaTest = (bits & STATE_ENABLE_ALPHA_TEST) == STATE_ENABLE_ALPHA_TEST;
-		stateEnableMCLighting = (bits & STATE_ENABLE_MC_LIGHTING) == STATE_ENABLE_MC_LIGHTING;
-		stateEnableEndPortal = (bits & STATE_ENABLE_END_PORTAL) == STATE_ENABLE_END_PORTAL;
-		stateEnableAnisotropicFix = (bits & STATE_ENABLE_ANISOTROPIC_FIX) == STATE_ENABLE_ANISOTROPIC_FIX;
-		stateEnableFog = (bits & STATE_ENABLE_FOG) == STATE_ENABLE_FOG;
-		stateEnableBlendAdd = (bits & STATE_ENABLE_BLEND_ADD) == STATE_ENABLE_BLEND_ADD;
+		stateEnableTexture2D = (bits & STATE_ENABLE_TEXTURE2D) != 0;
+		stateEnableLightmap = (bits & STATE_ENABLE_LIGHTMAP) != 0;
+		stateEnableAlphaTest = (bits & STATE_ENABLE_ALPHA_TEST) != 0;
+		stateEnableMCLighting = (bits & STATE_ENABLE_MC_LIGHTING) != 0;
+		stateEnableEndPortal = (bits & STATE_ENABLE_END_PORTAL) != 0;
+		stateEnableAnisotropicFix = (bits & STATE_ENABLE_ANISOTROPIC_FIX) != 0;
+		stateEnableFog = (bits & STATE_ENABLE_FOG) != 0;
+		stateEnableBlendAdd = (bits & STATE_ENABLE_BLEND_ADD) != 0;
 		
 		for(int i = 0; i < stateLightsVectors.length; ++i) { 
 			stateLightsVectors[i] = new Vector4f(-999.0f, -999.0f, -999.0f, 0.0f);
@@ -1068,7 +1063,6 @@ public class FixedFunctionPipeline {
 	}
 
 	static void optimize() {
-		FixedFunctionPipeline pp;
 		for(int i = 0, l = pipelineListTracker.size(); i < l; ++i) {
 			pipelineListTracker.get(i).streamBuffer.optimize();
 		}
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/FixedFunctionShader.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/FixedFunctionShader.java
index 3ca87543..392ad203 100644
--- a/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/FixedFunctionShader.java
+++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/FixedFunctionShader.java
@@ -44,7 +44,6 @@ public class FixedFunctionShader {
 
 	public class FixedFunctionConstants {
 
-		public static final String VERSION = "#version 300 es";
 		public static final String FILENAME_VSH = "/assets/eagler/glsl/core.vsh";
 		public static final String FILENAME_FSH = "/assets/eagler/glsl/core.fsh";
 
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/GLSLHeader.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/GLSLHeader.java
new file mode 100644
index 00000000..5e93f199
--- /dev/null
+++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/GLSLHeader.java
@@ -0,0 +1,99 @@
+package net.lax1dude.eaglercraft.v1_8.opengl;
+
+import net.lax1dude.eaglercraft.v1_8.EagRuntime;
+import net.lax1dude.eaglercraft.v1_8.internal.PlatformOpenGL;
+
+/**
+ * Copyright (c) 2024 lax1dude. All Rights Reserved.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ * 
+ */
+public class GLSLHeader {
+
+	public static final String GLES2_COMPAT_FILE_NAME = "/assets/eagler/glsl/gles2_compat.glsl";
+
+	private static String header = null;
+	private static String gles2CompatFile = null;
+
+	static void init() {
+		gles2CompatFile = EagRuntime.getRequiredResourceString(GLES2_COMPAT_FILE_NAME);
+		int glesVersion = EaglercraftGPU.checkOpenGLESVersion();
+		StringBuilder headerBuilder;
+		if(glesVersion >= 310) {
+			headerBuilder = new StringBuilder("#version 310 es");
+			boolean oes5 = PlatformOpenGL.checkOESGPUShader5Capable();
+			boolean ext5 = !oes5 && PlatformOpenGL.checkEXTGPUShader5Capable();
+			if(oes5) {
+				headerBuilder.append("\n#extension GL_OES_gpu_shader5 : enable");
+			}else if(ext5) {
+				headerBuilder.append("\n#extension GL_EXT_gpu_shader5 : enable");
+			}
+			headerBuilder.append("\n#define EAGLER_IS_GLES_310");
+			headerBuilder.append("\n#define EAGLER_HAS_GLES_310");
+			headerBuilder.append("\n#define EAGLER_HAS_GLES_300");
+			headerBuilder.append("\n#define EAGLER_HAS_GLES_200");
+			if(oes5 || ext5) {
+				headerBuilder.append("\n#define EAGLER_HAS_GLES_310_SHADER_5");
+			}
+		}else if(glesVersion == 300) {
+			headerBuilder = new StringBuilder("#version 300 es");
+			headerBuilder.append("\n#define EAGLER_IS_GLES_300");
+			headerBuilder.append("\n#define EAGLER_HAS_GLES_300");
+			headerBuilder.append("\n#define EAGLER_HAS_GLES_200");
+		}else if(glesVersion == 200) {
+			boolean texLOD = PlatformOpenGL.checkTextureLODCapable();
+			headerBuilder = new StringBuilder("#version 100");
+			if(texLOD) {
+				headerBuilder.append("\n#extension GL_EXT_shader_texture_lod : enable");
+			}
+			headerBuilder.append("\n#define EAGLER_HAS_GLES_200");
+			headerBuilder.append("\n#define EAGLER_IS_GLES_200");
+			if(texLOD) {
+				headerBuilder.append("\n#define EAGLER_HAS_GLES_200_SHADER_TEXTURE_LOD");
+			}
+		}else {
+			throw new IllegalStateException("Unsupported OpenGL ES version: " + glesVersion);
+		}
+		header = headerBuilder.append('\n').toString();
+	}
+
+	static void destroy() {
+		header = null;
+	}
+
+	public static String getHeader() {
+		if(header == null) throw new IllegalStateException();
+		return header;
+	}
+
+	public static String getVertexHeader(String shaderSrc) {
+		if(header == null) throw new IllegalStateException();
+		return header + "#define EAGLER_IS_VERTEX_SHADER\n" + shaderSrc;
+	}
+
+	public static String getFragmentHeader(String shaderSrc) {
+		if(header == null) throw new IllegalStateException();
+		return header + "#define EAGLER_IS_FRAGMENT_SHADER\n" + shaderSrc;
+	}
+
+	public static String getVertexHeaderCompat(String shaderSrc, String precisions) {
+		if(header == null || gles2CompatFile == null) throw new IllegalStateException();
+		return header + "#define EAGLER_IS_VERTEX_SHADER\n" + (precisions == null ? "" : precisions + "\n") + gles2CompatFile + "\n" + shaderSrc;
+	}
+
+	public static String getFragmentHeaderCompat(String shaderSrc, String precisions) {
+		if(header == null || gles2CompatFile == null) throw new IllegalStateException();
+		return header + "#define EAGLER_IS_FRAGMENT_SHADER\n"+ (precisions == null ? "" : precisions + "\n") + gles2CompatFile + "\n" + shaderSrc;
+	}
+
+}
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/GameOverlayFramebuffer.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/GameOverlayFramebuffer.java
index 94a54027..9aec1e65 100644
--- a/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/GameOverlayFramebuffer.java
+++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/GameOverlayFramebuffer.java
@@ -5,10 +5,13 @@ import net.lax1dude.eaglercraft.v1_8.internal.IRenderbufferGL;
 import net.lax1dude.eaglercraft.v1_8.internal.buffer.ByteBuffer;
 
 import static net.lax1dude.eaglercraft.v1_8.opengl.RealOpenGLEnums.*;
+
+import net.lax1dude.eaglercraft.v1_8.EagRuntime;
+
 import static net.lax1dude.eaglercraft.v1_8.internal.PlatformOpenGL.*;
 
 /**
- * Copyright (c) 2022-2023 lax1dude. All Rights Reserved.
+ * Copyright (c) 2022-2024 lax1dude. All Rights Reserved.
  * 
  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
@@ -40,10 +43,20 @@ public class GameOverlayFramebuffer {
 
 	private int framebufferColor = -1;
 
-	public void beginRender(int width, int height) {
+	private final boolean enableDepth;
+
+	public GameOverlayFramebuffer() {
+		this(true);
+	}
+
+	public GameOverlayFramebuffer(boolean enableDepth) {
+		this.enableDepth = enableDepth;
+	}
+
+	public boolean beginRender(int width, int height) {
 		if(framebuffer == null) {
 			framebuffer = _wglCreateFramebuffer();
-			depthBuffer = _wglCreateRenderbuffer();
+			depthBuffer = enableDepth ? _wglCreateRenderbuffer() : null;
 			framebufferColor = GlStateManager.generateTexture();
 			_wglBindFramebuffer(_GL_FRAMEBUFFER, framebuffer);
 			GlStateManager.bindTexture(framebufferColor);
@@ -52,29 +65,35 @@ public class GameOverlayFramebuffer {
 			_wglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
 			_wglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
 			_wglFramebufferTexture2D(_GL_FRAMEBUFFER, _GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, EaglercraftGPU.getNativeTexture(framebufferColor), 0);
-			_wglBindRenderbuffer(_GL_RENDERBUFFER, depthBuffer);
-			_wglFramebufferRenderbuffer(_GL_FRAMEBUFFER, _GL_DEPTH_ATTACHMENT, _GL_RENDERBUFFER, depthBuffer);
+			if(enableDepth) {
+				_wglBindRenderbuffer(_GL_RENDERBUFFER, depthBuffer);
+				_wglFramebufferRenderbuffer(_GL_FRAMEBUFFER, _GL_DEPTH_ATTACHMENT, _GL_RENDERBUFFER, depthBuffer);
+			}
 		}
 
-		if(currentWidth != width || currentHeight != height) {
+		boolean resized = currentWidth != width || currentHeight != height;
+		if(resized) {
 			currentWidth = width;
 			currentHeight = height;
 			GlStateManager.bindTexture(framebufferColor);
-			_wglTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, (ByteBuffer)null);
-			_wglBindRenderbuffer(_GL_RENDERBUFFER, depthBuffer);
-			_wglRenderbufferStorage(_GL_RENDERBUFFER, _GL_DEPTH_COMPONENT16, width, height);
+			EaglercraftGPU.glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, (ByteBuffer)null);
+			if(enableDepth) {
+				_wglBindRenderbuffer(_GL_RENDERBUFFER, depthBuffer);
+				_wglRenderbufferStorage(_GL_RENDERBUFFER, _GL_DEPTH_COMPONENT16, width, height);
+			}
 		}
 
 		_wglBindFramebuffer(_GL_FRAMEBUFFER, framebuffer);
+		return resized;
 	}
 
 	public void endRender() {
 		_wglBindFramebuffer(_GL_FRAMEBUFFER, null);
-		age = System.currentTimeMillis();
+		age = EagRuntime.steadyTimeMillis();
 	}
 
 	public long getAge() {
-		return age == -1l ? -1l : (System.currentTimeMillis() - age);
+		return age == -1l ? -1l : (EagRuntime.steadyTimeMillis() - age);
 	}
 
 	public int getTexture() {
@@ -84,7 +103,9 @@ public class GameOverlayFramebuffer {
 	public void destroy() {
 		if(framebuffer != null) {
 			_wglDeleteFramebuffer(framebuffer);
-			_wglDeleteRenderbuffer(depthBuffer);
+			if(enableDepth) {
+				_wglDeleteRenderbuffer(depthBuffer);
+			}
 			GlStateManager.deleteTexture(framebufferColor);
 			framebuffer = null;
 			depthBuffer = null;
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/GlStateManager.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/GlStateManager.java
index 37819b91..537dfb50 100644
--- a/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/GlStateManager.java
+++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/GlStateManager.java
@@ -30,10 +30,12 @@ public class GlStateManager {
 	static final Logger logger = LogManager.getLogger("GlStateManager");
 
 	static boolean stateDepthTest = false;
+	static boolean stateDepthTestStash = false;
 	static int stateDepthFunc = -1;
 	static boolean stateDepthMask = true;
 
 	static boolean stateCull = false;
+	static boolean stateCullStash = false;
 	static int stateCullFace = GL_BACK;
 
 	static boolean statePolygonOffset = false;
@@ -58,6 +60,7 @@ public class GlStateManager {
 	static boolean stateEnableShaderBlendColor = false;
 
 	static boolean stateBlend = false;
+	static boolean stateBlendStash = false;
 	static boolean stateGlobalBlend = true;
 	static int stateBlendEquation = -1;
 	static int stateBlendSRC = -1;
@@ -312,6 +315,30 @@ public class GlStateManager {
 		}
 	}
 
+	public static final void eagPushStateForGLES2BlitHack() {
+		stateDepthTestStash = stateDepthTest;
+		stateCullStash = stateCull;
+		stateBlendStash = stateBlend;
+	}
+
+	public static final void eagPopStateForGLES2BlitHack() {
+		if(stateDepthTestStash) {
+			enableDepth();
+		}else {
+			disableDepth();
+		}
+		if(stateCullStash) {
+			enableCull();
+		}else {
+			disableCull();
+		}
+		if(stateBlendStash) {
+			enableBlend();
+		}else {
+			disableBlend();
+		}
+	}
+
 	public static final void depthFunc(int depthFunc) {
 		int rev = depthFunc;
 		switch(depthFunc) {
@@ -603,7 +630,9 @@ public class GlStateManager {
 					f2 = f1;
 				}
 				_wglBindTexture(GL_TEXTURE_2D, null);
-				_wglBindTexture(GL_TEXTURE_3D, null);
+				if(EaglercraftGPU.checkOpenGLESVersion() >= 300) {
+					_wglBindTexture(GL_TEXTURE_3D, null);
+				}
 				boundTexture[i] = -1;
 			}
 		}
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/ImageData.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/ImageData.java
index ca5a5b19..ec8cbb21 100644
--- a/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/ImageData.java
+++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/ImageData.java
@@ -56,6 +56,22 @@ public class ImageData {
 		return new ImageData(pw, ph, img, alpha);
 	}
 
+	public static String getMimeFromType(String nameOrPath) {
+		if(nameOrPath == null) return "image/png";
+		nameOrPath = nameOrPath.toLowerCase();
+		if(nameOrPath.endsWith(".png")) {
+			return "image/png";
+		}else if(nameOrPath.endsWith(".jpg") || nameOrPath.endsWith(".jpeg")) {
+			return "image/jpeg";
+		}else if(nameOrPath.endsWith(".gif")) {
+			return "image/gif";
+		}else if(nameOrPath.endsWith(".bmp")) {
+			return "image/bmp";
+		}else {
+			return "image/png"; // rip
+		}
+	}
+
 	public static final ImageData loadImageFile(String path) {
 		byte[] fileData = EagRuntime.getResourceBytes(path);
 		if(fileData != null) {
@@ -73,6 +89,23 @@ public class ImageData {
 		return PlatformAssets.loadImageFile(data);
 	}
 
+	public static final ImageData loadImageFile(String path, String mime) {
+		byte[] fileData = EagRuntime.getResourceBytes(path);
+		if(fileData != null) {
+			return loadImageFile(fileData, mime);
+		}else {
+			return null;
+		}
+	}
+
+	public static final ImageData loadImageFile(InputStream data, String mime) {
+		return PlatformAssets.loadImageFile(data, mime);
+	}
+
+	public static final ImageData loadImageFile(byte[] data, String mime) {
+		return PlatformAssets.loadImageFile(data, mime);
+	}
+
 	public void getRGB(int startX, int startY, int w, int h,
             int[] rgbArray, int offset, int scansize) {
 		for(int y = 0; y < h; ++y) {
@@ -147,5 +180,22 @@ public class ImageData {
 	public static int swapRB(int c) {
 		return (c & 0xFF00FF00) | ((c & 0x00FF0000) >>> 16) | ((c & 0x000000FF) << 16);
 	}
+	
+	public static int[] swapRB(int[] arr) {
+		for(int i = 0; i < arr.length; ++i) {
+			int j = arr[i];
+			arr[i] = (j & 0xFF00FF00) | ((j & 0x00FF0000) >>> 16) |
+					((j & 0x000000FF) << 16);
+		}
+		return arr;
+	}
+
+	public boolean isNPOT() {
+		return (width & (width - 1)) != 0 || (height & (height - 1)) != 0;
+	}
+
+	public static boolean isNPOTStatic(int w, int h) {
+		return (w & (w - 1)) != 0 || (h & (h - 1)) != 0;
+	}
 
 }
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/InstancedFontRenderer.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/InstancedFontRenderer.java
index 0a36fd0b..6c2839ab 100644
--- a/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/InstancedFontRenderer.java
+++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/InstancedFontRenderer.java
@@ -13,13 +13,12 @@ import net.lax1dude.eaglercraft.v1_8.internal.buffer.ByteBuffer;
 import net.lax1dude.eaglercraft.v1_8.internal.buffer.FloatBuffer;
 import net.lax1dude.eaglercraft.v1_8.log4j.LogManager;
 import net.lax1dude.eaglercraft.v1_8.log4j.Logger;
-import net.lax1dude.eaglercraft.v1_8.opengl.FixedFunctionShader.FixedFunctionConstants;
 import net.lax1dude.eaglercraft.v1_8.opengl.ext.deferred.DeferredStateManager;
 import net.lax1dude.eaglercraft.v1_8.vector.Matrix4f;
 import net.lax1dude.eaglercraft.v1_8.vector.Vector4f;
 
 /**
- * Copyright (c) 2022 lax1dude. All Rights Reserved.
+ * Copyright (c) 2022-2024 lax1dude. All Rights Reserved.
  * 
  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
@@ -38,7 +37,10 @@ public class InstancedFontRenderer {
 	private static final Logger logger = LogManager.getLogger("InstancedFontRenderer");
 
 	public static final String vertexShaderPath = "/assets/eagler/glsl/accel_font.vsh";
+	public static final String vertexShaderPrecision = "precision lowp int;\nprecision highp float;\nprecision mediump sampler2D;\n";
+
 	public static final String fragmentShaderPath = "/assets/eagler/glsl/accel_font.fsh";
+	public static final String fragmentShaderPrecision = "precision lowp int;\nprecision highp float;\nprecision mediump sampler2D;\n";
 
 	private static final int BYTES_PER_CHARACTER = 10;
 	private static final int CHARACTER_LIMIT = 6553;
@@ -78,21 +80,13 @@ public class InstancedFontRenderer {
 	private static float charCoordHeightValue = -1.0f;
 	
 	static void initialize() {
-		
-		String vertexSource = EagRuntime.getResourceString(vertexShaderPath);
-		if(vertexSource == null) {
-			throw new RuntimeException("InstancedFontRenderer shader \"" + vertexShaderPath + "\" is missing!");
-		}
-
-		String fragmentSource = EagRuntime.getResourceString(fragmentShaderPath);
-		if(fragmentSource == null) {
-			throw new RuntimeException("InstancedFontRenderer shader \"" + fragmentShaderPath + "\" is missing!");
-		}
+		String vertexSource = EagRuntime.getRequiredResourceString(vertexShaderPath);
+		String fragmentSource = EagRuntime.getRequiredResourceString(fragmentShaderPath);
 
 		IShaderGL vert = _wglCreateShader(GL_VERTEX_SHADER);
 		IShaderGL frag = _wglCreateShader(GL_FRAGMENT_SHADER);
 
-		_wglShaderSource(vert, FixedFunctionConstants.VERSION + "\n" + vertexSource);
+		_wglShaderSource(vert, GLSLHeader.getVertexHeaderCompat(vertexSource, vertexShaderPrecision));
 		_wglCompileShader(vert);
 
 		if(_wglGetShaderi(vert, GL_COMPILE_STATUS) != GL_TRUE) {
@@ -107,7 +101,7 @@ public class InstancedFontRenderer {
 			throw new IllegalStateException("Vertex shader \"" + vertexShaderPath + "\" could not be compiled!");
 		}
 
-		_wglShaderSource(frag, FixedFunctionConstants.VERSION + "\n" + fragmentSource);
+		_wglShaderSource(frag, GLSLHeader.getFragmentHeaderCompat(fragmentSource, fragmentShaderPrecision));
 		_wglCompileShader(frag);
 
 		if(_wglGetShaderi(frag, GL_COMPILE_STATUS) != GL_TRUE) {
@@ -127,6 +121,10 @@ public class InstancedFontRenderer {
 		_wglAttachShader(shaderProgram, vert);
 		_wglAttachShader(shaderProgram, frag);
 
+		if(EaglercraftGPU.checkOpenGLESVersion() == 200) {
+			VSHInputLayoutParser.applyLayout(shaderProgram, VSHInputLayoutParser.getShaderInputs(vertexSource));
+		}
+
 		_wglLinkProgram(shaderProgram);
 
 		_wglDetachShader(shaderProgram, vert);
@@ -161,60 +159,62 @@ public class InstancedFontRenderer {
 
 		_wglUniform1i(_wglGetUniformLocation(shaderProgram, "u_inputTexture"), 0);
 
-		vertexArray = _wglGenVertexArrays();
+		vertexArray = EaglercraftGPU.createGLBufferArray();
 		vertexBuffer = _wglGenBuffers();
 		instancesBuffer = _wglGenBuffers();
 
 		FloatBuffer verts = EagRuntime.allocateFloatBuffer(108);
+		float paddingA = 0.005f;
+		float paddingB = 1.0f - paddingA;
 		verts.put(new float[] {
 				
 				// (0 - 6 - 12) regular:
 				
-				0.0f, 0.0f, 0.25f,  0.0f, 1.0f, 0.25f,  1.0f, 0.0f, 0.25f,
-				1.0f, 0.0f, 0.25f,  0.0f, 1.0f, 0.25f,  1.0f, 1.0f, 0.25f,
-				0.0f, 0.0f, 0.0f,  0.0f, 1.0f, 0.0f,  1.0f, 0.0f, 0.0f,
-				1.0f, 0.0f, 0.0f,  0.0f, 1.0f, 0.0f,  1.0f, 1.0f, 0.0f,
+				paddingA, paddingA, 0.25f,  paddingA, paddingB, 0.25f,  paddingB, paddingA, 0.25f,
+				paddingB, paddingA, 0.25f,  paddingA, paddingB, 0.25f,  paddingB, paddingB, 0.25f,
+				paddingA, paddingA, 0.0f,  paddingA, paddingB, 0.0f,  paddingB, paddingA, 0.0f,
+				paddingB, paddingA, 0.0f,  paddingA, paddingB, 0.0f,  paddingB, paddingB, 0.0f,
 
 				// (12 - 24 - 36) bold shadow:
 
-				0.0f, 0.0f, 0.25f,  0.0f, 1.0f, 0.25f,  1.0f, 0.0f, 0.25f,
-				1.0f, 0.0f, 0.25f,  0.0f, 1.0f, 0.25f,  1.0f, 1.0f, 0.25f,
-				0.0f, 0.0f, 0.75f,  0.0f, 1.0f, 0.75f,  1.0f, 0.0f, 0.75f,
-				1.0f, 0.0f, 0.75f,  0.0f, 1.0f, 0.75f,  1.0f, 1.0f, 0.75f,
+				paddingA, paddingA, 0.25f,  paddingA, paddingB, 0.25f,  paddingB, paddingA, 0.25f,
+				paddingB, paddingA, 0.25f,  paddingA, paddingB, 0.25f,  paddingB, paddingB, 0.25f,
+				paddingA, paddingA, 0.75f,  paddingA, paddingB, 0.75f,  paddingB, paddingA, 0.75f,
+				paddingB, paddingA, 0.75f,  paddingA, paddingB, 0.75f,  paddingB, paddingB, 0.75f,
 
-				0.0f, 0.0f, 0.0f,  0.0f, 1.0f, 0.0f,  1.0f, 0.0f, 0.0f,
-				1.0f, 0.0f, 0.0f,  0.0f, 1.0f, 0.0f,  1.0f, 1.0f, 0.0f,
-				0.0f, 0.0f, 0.5f,  0.0f, 1.0f, 0.5f,  1.0f, 0.0f, 0.5f,
-				1.0f, 0.0f, 0.5f,  0.0f, 1.0f, 0.5f,  1.0f, 1.0f, 0.5f
+				paddingA, paddingA, 0.0f,  paddingA, paddingB, 0.0f,  paddingB, paddingA, 0.0f,
+				paddingB, paddingA, 0.0f,  paddingA, paddingB, 0.0f,  paddingB, paddingB, 0.0f,
+				paddingA, paddingA, 0.5f,  paddingA, paddingB, 0.5f,  paddingB, paddingA, 0.5f,
+				paddingB, paddingA, 0.5f,  paddingA, paddingB, 0.5f,  paddingB, paddingB, 0.5f
 
 		});
 		verts.flip();
 
 		EaglercraftGPU.bindGLBufferArray(vertexArray);
 
-		EaglercraftGPU.bindGLArrayBuffer(vertexBuffer);
+		EaglercraftGPU.bindVAOGLArrayBufferNow(vertexBuffer);
 		_wglBufferData(GL_ARRAY_BUFFER, verts, GL_STATIC_DRAW);
 
 		EagRuntime.freeFloatBuffer(verts);
 
-		_wglEnableVertexAttribArray(0);
-		_wglVertexAttribPointer(0, 3, GL_FLOAT, false, 12, 0);
-		_wglVertexAttribDivisor(0, 0);
+		EaglercraftGPU.enableVertexAttribArray(0);
+		EaglercraftGPU.vertexAttribPointer(0, 3, GL_FLOAT, false, 12, 0);
+		EaglercraftGPU.vertexAttribDivisor(0, 0);
 
-		EaglercraftGPU.bindGLArrayBuffer(instancesBuffer);
+		EaglercraftGPU.bindVAOGLArrayBufferNow(instancesBuffer);
 		_wglBufferData(GL_ARRAY_BUFFER, fontDataBuffer.remaining(), GL_STREAM_DRAW);
 
-		_wglEnableVertexAttribArray(1);
-		_wglVertexAttribPointer(1, 2, GL_SHORT, false, 10, 0);
-		_wglVertexAttribDivisor(1, 1);
+		EaglercraftGPU.enableVertexAttribArray(1);
+		EaglercraftGPU.vertexAttribPointer(1, 2, GL_SHORT, false, 10, 0);
+		EaglercraftGPU.vertexAttribDivisor(1, 1);
 
-		_wglEnableVertexAttribArray(2);
-		_wglVertexAttribPointer(2, 2, GL_UNSIGNED_BYTE, false, 10, 4);
-		_wglVertexAttribDivisor(2, 1);
+		EaglercraftGPU.enableVertexAttribArray(2);
+		EaglercraftGPU.vertexAttribPointer(2, 2, GL_UNSIGNED_BYTE, false, 10, 4);
+		EaglercraftGPU.vertexAttribDivisor(2, 1);
 
-		_wglEnableVertexAttribArray(3);
-		_wglVertexAttribPointer(3, 4, GL_UNSIGNED_BYTE, true, 10, 6);
-		_wglVertexAttribDivisor(3, 1);
+		EaglercraftGPU.enableVertexAttribArray(3);
+		EaglercraftGPU.vertexAttribPointer(3, 4, GL_UNSIGNED_BYTE, true, 10, 6);
+		EaglercraftGPU.vertexAttribDivisor(3, 1);
 		
 	}
 
@@ -381,7 +381,7 @@ public class InstancedFontRenderer {
 			fontDataBuffer.position(p);
 			fontDataBuffer.limit(l);
 
-			_wglDrawArraysInstanced(GL_TRIANGLES, shadow ? 0 : 6, shadow ? 12 : 6, charactersDrawn);
+			EaglercraftGPU.doDrawArraysInstanced(GL_TRIANGLES, shadow ? 0 : 6, shadow ? 12 : 6, charactersDrawn);
 		}
 
 		if(boldCharactersDrawn > 0) {
@@ -394,7 +394,7 @@ public class InstancedFontRenderer {
 			fontBoldDataBuffer.position(p);
 			fontBoldDataBuffer.limit(l);
 
-			_wglDrawArraysInstanced(GL_TRIANGLES, shadow ? 12 : 24, shadow ? 24 : 12, boldCharactersDrawn);
+			EaglercraftGPU.doDrawArraysInstanced(GL_TRIANGLES, shadow ? 12 : 24, shadow ? 24 : 12, boldCharactersDrawn);
 		}
 	}
 
@@ -455,4 +455,40 @@ public class InstancedFontRenderer {
 		if(y > heightCalcMost || heightCalcMost == Integer.MAX_VALUE) heightCalcMost = y;
 	}
 
+	public static void destroy() {
+		if(fontDataBuffer != null) {
+			EagRuntime.freeByteBuffer(fontDataBuffer);
+			fontDataBuffer = null;
+		}
+		if(fontBoldDataBuffer != null) {
+			EagRuntime.freeByteBuffer(fontBoldDataBuffer);
+			fontBoldDataBuffer = null;
+		}
+		if(shaderProgram != null) {
+			_wglDeleteProgram(shaderProgram);
+			shaderProgram = null;
+		}
+		if(matrixCopyBuffer != null) {
+			EagRuntime.freeFloatBuffer(matrixCopyBuffer);
+			matrixCopyBuffer = null;
+		}
+		u_matrixTransform = null;
+		u_charSize2f = null;
+		u_charCoordSize2f = null;
+		u_color4f = null;
+		u_colorBias4f = null;
+		if(vertexArray != null) {
+			EaglercraftGPU.destroyGLBufferArray(vertexArray);
+			vertexArray = null;
+		}
+		if(vertexBuffer != null) {
+			_wglDeleteBuffers(vertexBuffer);
+			vertexBuffer = null;
+		}
+		if(instancesBuffer != null) {
+			_wglDeleteBuffers(instancesBuffer);
+			instancesBuffer = null;
+		}
+	}
+
 }
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/InstancedParticleRenderer.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/InstancedParticleRenderer.java
index 32b4b8cd..3ac10ab7 100644
--- a/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/InstancedParticleRenderer.java
+++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/InstancedParticleRenderer.java
@@ -13,11 +13,10 @@ import net.lax1dude.eaglercraft.v1_8.internal.buffer.ByteBuffer;
 import net.lax1dude.eaglercraft.v1_8.internal.buffer.FloatBuffer;
 import net.lax1dude.eaglercraft.v1_8.log4j.LogManager;
 import net.lax1dude.eaglercraft.v1_8.log4j.Logger;
-import net.lax1dude.eaglercraft.v1_8.opengl.FixedFunctionShader.FixedFunctionConstants;
 import net.lax1dude.eaglercraft.v1_8.vector.Matrix4f;
 
 /**
- * Copyright (c) 2022 lax1dude. All Rights Reserved.
+ * Copyright (c) 2022-2024 lax1dude. All Rights Reserved.
  * 
  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
@@ -36,7 +35,10 @@ public class InstancedParticleRenderer {
 	private static final Logger logger = LogManager.getLogger("InstancedParticleRenderer");
 
 	public static final String vertexShaderPath = "/assets/eagler/glsl/accel_particle.vsh";
+	public static final String vertexShaderPrecision = "precision lowp int;\nprecision highp float;\nprecision mediump sampler2D;\n";
+
 	public static final String fragmentShaderPath = "/assets/eagler/glsl/accel_particle.fsh";
+	public static final String fragmentShaderPrecision = "precision lowp int;\nprecision mediump float;\nprecision mediump sampler2D;\n";
 
 	private static ByteBuffer particleBuffer = null;
 	private static int particleCount = 0;
@@ -79,20 +81,13 @@ public class InstancedParticleRenderer {
 	private static float stateTransformParam5 = -999.0f;
 
 	static void initialize() {
-		String vertexSource = EagRuntime.getResourceString(vertexShaderPath);
-		if(vertexSource == null) {
-			throw new RuntimeException("InstancedParticleRenderer shader \"" + vertexShaderPath + "\" is missing!");
-		}
-
-		String fragmentSource = EagRuntime.getResourceString(fragmentShaderPath);
-		if(fragmentSource == null) {
-			throw new RuntimeException("InstancedParticleRenderer shader \"" + fragmentShaderPath + "\" is missing!");
-		}
+		String vertexSource = EagRuntime.getRequiredResourceString(vertexShaderPath);
+		String fragmentSource = EagRuntime.getRequiredResourceString(fragmentShaderPath);
 
 		IShaderGL vert = _wglCreateShader(GL_VERTEX_SHADER);
 		IShaderGL frag = _wglCreateShader(GL_FRAGMENT_SHADER);
 
-		_wglShaderSource(vert, FixedFunctionConstants.VERSION + "\n" + vertexSource);
+		_wglShaderSource(vert, GLSLHeader.getVertexHeaderCompat(vertexSource, vertexShaderPrecision));
 		_wglCompileShader(vert);
 
 		if(_wglGetShaderi(vert, GL_COMPILE_STATUS) != GL_TRUE) {
@@ -107,7 +102,7 @@ public class InstancedParticleRenderer {
 			throw new IllegalStateException("Vertex shader \"" + vertexShaderPath + "\" could not be compiled!");
 		}
 
-		_wglShaderSource(frag, FixedFunctionConstants.VERSION + "\n" + fragmentSource);
+		_wglShaderSource(frag, GLSLHeader.getFragmentHeaderCompat(fragmentSource, fragmentShaderPrecision));
 		_wglCompileShader(frag);
 
 		if(_wglGetShaderi(frag, GL_COMPILE_STATUS) != GL_TRUE) {
@@ -127,6 +122,10 @@ public class InstancedParticleRenderer {
 		_wglAttachShader(shaderProgram, vert);
 		_wglAttachShader(shaderProgram, frag);
 
+		if(EaglercraftGPU.checkOpenGLESVersion() == 200) {
+			VSHInputLayoutParser.applyLayout(shaderProgram, VSHInputLayoutParser.getShaderInputs(vertexSource));
+		}
+
 		_wglLinkProgram(shaderProgram);
 
 		_wglDetachShader(shaderProgram, vert);
@@ -161,7 +160,7 @@ public class InstancedParticleRenderer {
 		_wglUniform1i(_wglGetUniformLocation(shaderProgram, "u_inputTexture"), 0);
 		_wglUniform1i(_wglGetUniformLocation(shaderProgram, "u_lightmapTexture"), 1);
 
-		vertexArray = _wglGenVertexArrays();
+		vertexArray = EaglercraftGPU.createGLBufferArray();
 		vertexBuffer = _wglGenBuffers();
 		instancesBuffer = _wglGenBuffers();
 
@@ -174,37 +173,37 @@ public class InstancedParticleRenderer {
 
 		EaglercraftGPU.bindGLBufferArray(vertexArray);
 
-		EaglercraftGPU.bindGLArrayBuffer(vertexBuffer);
+		EaglercraftGPU.bindVAOGLArrayBufferNow(vertexBuffer);
 		_wglBufferData(GL_ARRAY_BUFFER, verts, GL_STATIC_DRAW);
 
 		EagRuntime.freeFloatBuffer(verts);
 
-		_wglEnableVertexAttribArray(0);
-		_wglVertexAttribPointer(0, 2, GL_FLOAT, false, 8, 0);
-		_wglVertexAttribDivisor(0, 0);
+		EaglercraftGPU.enableVertexAttribArray(0);
+		EaglercraftGPU.vertexAttribPointer(0, 2, GL_FLOAT, false, 8, 0);
+		EaglercraftGPU.vertexAttribDivisor(0, 0);
 
-		EaglercraftGPU.bindGLArrayBuffer(instancesBuffer);
+		EaglercraftGPU.bindVAOGLArrayBufferNow(instancesBuffer);
 		_wglBufferData(GL_ARRAY_BUFFER, particleBuffer.remaining(), GL_STREAM_DRAW);
 
-		_wglEnableVertexAttribArray(1);
-		_wglVertexAttribPointer(1, 3, GL_FLOAT, false, 24, 0);
-		_wglVertexAttribDivisor(1, 1);
+		EaglercraftGPU.enableVertexAttribArray(1);
+		EaglercraftGPU.vertexAttribPointer(1, 3, GL_FLOAT, false, 24, 0);
+		EaglercraftGPU.vertexAttribDivisor(1, 1);
 
-		_wglEnableVertexAttribArray(2);
-		_wglVertexAttribPointer(2, 2, GL_UNSIGNED_SHORT, false, 24, 12);
-		_wglVertexAttribDivisor(2, 1);
+		EaglercraftGPU.enableVertexAttribArray(2);
+		EaglercraftGPU.vertexAttribPointer(2, 2, GL_UNSIGNED_SHORT, false, 24, 12);
+		EaglercraftGPU.vertexAttribDivisor(2, 1);
 
-		_wglEnableVertexAttribArray(3);
-		_wglVertexAttribPointer(3, 2, GL_UNSIGNED_BYTE, true, 24, 16);
-		_wglVertexAttribDivisor(3, 1);
+		EaglercraftGPU.enableVertexAttribArray(3);
+		EaglercraftGPU.vertexAttribPointer(3, 2, GL_UNSIGNED_BYTE, true, 24, 16);
+		EaglercraftGPU.vertexAttribDivisor(3, 1);
 
-		_wglEnableVertexAttribArray(4);
-		_wglVertexAttribPointer(4, 2, GL_UNSIGNED_BYTE, false, 24, 18);
-		_wglVertexAttribDivisor(4, 1);
+		EaglercraftGPU.enableVertexAttribArray(4);
+		EaglercraftGPU.vertexAttribPointer(4, 2, GL_UNSIGNED_BYTE, false, 24, 18);
+		EaglercraftGPU.vertexAttribDivisor(4, 1);
 
-		_wglEnableVertexAttribArray(5);
-		_wglVertexAttribPointer(5, 4, GL_UNSIGNED_BYTE, true, 24, 20);
-		_wglVertexAttribDivisor(5, 1);
+		EaglercraftGPU.enableVertexAttribArray(5);
+		EaglercraftGPU.vertexAttribPointer(5, 4, GL_UNSIGNED_BYTE, true, 24, 20);
+		EaglercraftGPU.vertexAttribDivisor(5, 1);
 
 	}
 
@@ -316,11 +315,43 @@ public class InstancedParticleRenderer {
 		particleBuffer.position(p);
 		particleBuffer.limit(l);
 
-		_wglDrawArraysInstanced(GL_TRIANGLES, 0, 6, particleCount);
+		EaglercraftGPU.doDrawArraysInstanced(GL_TRIANGLES, 0, 6, particleCount);
 	}
 
 	public static void stupidColorSetHack(IUniformGL color4f) {
 		_wglUniform4f(color4f, GlStateManager.stateColorR, GlStateManager.stateColorG, GlStateManager.stateColorB, GlStateManager.stateColorA);
 	}
 
+	public static void destroy() {
+		if(particleBuffer != null) {
+			EagRuntime.freeByteBuffer(particleBuffer);
+			particleBuffer = null;
+		}
+		if(shaderProgram != null) {
+			_wglDeleteProgram(shaderProgram);
+			shaderProgram = null;
+		}
+		if(matrixCopyBuffer != null) {
+			EagRuntime.freeFloatBuffer(matrixCopyBuffer);
+			matrixCopyBuffer = null;
+		}
+		u_matrixTransform = null;
+		u_texCoordSize2f_particleSize1f = null;
+		u_transformParam_1_2_5_f = null;
+		u_transformParam_3_4_f = null;
+		u_color4f = null;
+		if(vertexArray != null) {
+			EaglercraftGPU.destroyGLBufferArray(vertexArray);
+			vertexArray = null;
+		}
+		if(vertexBuffer != null) {
+			_wglDeleteBuffers(vertexBuffer);
+			vertexBuffer = null;
+		}
+		if(instancesBuffer != null) {
+			_wglDeleteBuffers(instancesBuffer);
+			instancesBuffer = null;
+		}
+	}
+
 }
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/RealOpenGLEnums.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/RealOpenGLEnums.java
index f3064644..a37d0b56 100644
--- a/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/RealOpenGLEnums.java
+++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/RealOpenGLEnums.java
@@ -1,7 +1,7 @@
 package net.lax1dude.eaglercraft.v1_8.opengl;
 
 /**
- * Copyright (c) 2022-2023 lax1dude, ayunami2000. All Rights Reserved.
+ * Copyright (c) 2022-2023 lax1dude. All Rights Reserved.
  * 
  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/SoftGLBufferArray.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/SoftGLBufferArray.java
new file mode 100644
index 00000000..1a111a80
--- /dev/null
+++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/SoftGLBufferArray.java
@@ -0,0 +1,225 @@
+package net.lax1dude.eaglercraft.v1_8.opengl;
+
+import net.lax1dude.eaglercraft.v1_8.internal.IBufferArrayGL;
+import net.lax1dude.eaglercraft.v1_8.internal.IBufferGL;
+
+import static net.lax1dude.eaglercraft.v1_8.internal.PlatformOpenGL.*;
+
+/**
+ * Copyright (c) 2024 lax1dude. All Rights Reserved.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ * 
+ */
+class SoftGLBufferArray implements IBufferArrayGL {
+
+	Attrib[] attribs = new Attrib[4];
+	int[] attribDivisors = null;
+	int hasAttribDivisorMask = 0;
+	int enabled = 0;
+	int enabledCnt = -1;
+	IBufferGL indexBuffer = null;
+
+	SoftGLBufferArray() {
+	}
+
+	void setAttrib(IBufferGL buffer, int index, int size, int format, boolean normalized, int stride, int offset) {
+		if(index >= attribs.length) {
+			int newLen = attribs.length << 1;
+			while(newLen <= index) {
+				newLen <<= 1;
+			}
+			Attrib[] newAttrib = new Attrib[newLen];
+			System.arraycopy(attribs, 0, newAttrib, 0, attribs.length);
+			attribs = newAttrib;
+		}
+		attribs[index] = new Attrib(buffer, size, format, normalized, stride, offset);
+	}
+
+	void setAttribDivisor(int index, int divisor) {
+		if(attribDivisors == null) {
+			if(divisor != 0) {
+				int newLen = 8;
+				while(newLen <= index) {
+					newLen <<= 1;
+				}
+				attribDivisors = new int[newLen];
+			}
+		}else if(index >= attribDivisors.length) {
+			int newLen = attribDivisors.length << 1;
+			while(newLen <= index) {
+				newLen <<= 1;
+			}
+			int[] newDivisor = new int[newLen];
+			System.arraycopy(attribDivisors, 0, newDivisor, 0, attribDivisors.length);
+			attribDivisors = newDivisor;
+		}
+		if(attribDivisors != null) {
+			attribDivisors[index] = divisor;
+			if(divisor != 0) {
+				hasAttribDivisorMask |= (1 << index);
+			}else {
+				hasAttribDivisorMask &= ~(1 << index);
+			}
+		}
+	}
+
+	void enableAttrib(int index, boolean en) {
+		if(en) {
+			enabled |= (1 << index);
+		}else {
+			enabled &= ~(1 << index);
+		}
+		enabledCnt = 32 - Integer.numberOfLeadingZeros(enabled);
+	}
+
+	void setIndexBuffer(IBufferGL buffer) {
+		indexBuffer = buffer;
+	}
+
+	void transitionToState(SoftGLBufferState previousState, boolean elements) {
+		int oldEnabled = previousState.oldEnabled;
+		int oldEnabledCnt = previousState.oldEnabledCnt;
+		int[] oldAttribDivisors = previousState.attribDivisors;
+		int oldHasAttribDivisorMask = previousState.hasAttribDivisorMask;
+		Attrib[] oldAttrs = previousState.attribs;
+		boolean instancingCapable = EaglercraftGPU.checkInstancingCapable();
+		int enCnt = enabledCnt;
+		int en = enabled;
+		Attrib[] attrs = attribs;
+		int[] divs = attribDivisors;
+		int hasDivs = hasAttribDivisorMask;
+		if(oldEnabledCnt >= 0) {
+			int enMax = Math.max(enCnt, oldEnabledCnt);
+			for(int i = 0, ii; i < enMax; ++i) {
+				ii = (1 << i);
+				boolean old = i < oldEnabledCnt && (oldEnabled & ii) != 0;
+				boolean _new = i < enCnt && (en & ii) != 0;
+				if(_new) {
+					if(!old) {
+						_wglEnableVertexAttribArray(i);
+					}
+					Attrib attr = i < attrs.length ? attrs[i] : null;
+					if(attr != null) {
+						Attrib oldAttr = oldAttrs[i];
+						if(oldAttr == null || !oldAttr.equalsExplicit(attr)) {
+							EaglercraftGPU.bindGLArrayBuffer(attr.buffer);
+							_wglVertexAttribPointer(i, attr.size, attr.format, attr.normalized, attr.stride, attr.offset);
+							oldAttrs[i] = attr;
+						}
+					}else {
+						oldAttrs[i] = null;
+					}
+					if(instancingCapable) {
+						// instancing is uncommon
+						if((hasDivs & ii) != 0) {
+							int newDivisor = divs[i];
+							if((oldHasAttribDivisorMask & ii) == 0 || newDivisor != oldAttribDivisors[i]) {
+								_wglVertexAttribDivisor(i, newDivisor);
+								oldAttribDivisors[i] = newDivisor;
+								previousState.hasAttribDivisorMask |= ii;
+							}
+						}else {
+							if((oldHasAttribDivisorMask & ii) != 0) {
+								_wglVertexAttribDivisor(i, 0);
+								oldAttribDivisors[i] = 0;
+								previousState.hasAttribDivisorMask &= ~ii;
+							}
+						}
+					}
+				}else if(old) {
+					_wglDisableVertexAttribArray(i);
+				}
+			}
+		}else {
+			// Bootstrap code for the emulator's first draw
+			for(int i = 0; i < enCnt; ++i) {
+				int ii = (1 << i);
+				if((en & ii) != 0) {
+					_wglEnableVertexAttribArray(i);
+					Attrib attr = attrs[i];
+					if(attr != null) {
+						EaglercraftGPU.bindGLArrayBuffer(attr.buffer);
+						_wglVertexAttribPointer(i, attr.size, attr.format, attr.normalized, attr.stride, attr.offset);
+						oldAttrs[i] = attr;
+					}else {
+						oldAttrs[i] = null;
+					}
+					if(instancingCapable) {
+						if((hasDivs & ii) != 0) {
+							int newDivisor = divs[i];
+							_wglVertexAttribDivisor(i, newDivisor);
+							oldAttribDivisors[i] = newDivisor;
+							previousState.hasAttribDivisorMask |= ii;
+						}else {
+							_wglVertexAttribDivisor(i, 0);
+							oldAttribDivisors[i] = 0;
+						}
+					}
+				}
+			}
+		}
+		if(elements) {
+			IBufferGL indexBufferL = indexBuffer;
+			if(indexBufferL != null) {
+				EaglercraftGPU.bindEmulatedVAOIndexBuffer(indexBufferL);
+			}
+		}
+		previousState.oldEnabled = en & ((1 << enCnt) - 1);
+		previousState.oldEnabledCnt = enCnt;
+	}
+
+	@Override
+	public void free() {
+	}
+
+	static class Attrib {
+
+		final IBufferGL buffer;
+		final int size;
+		final int format;
+		final boolean normalized;
+		final int stride;
+		final int offset;
+		final int hash;
+		final int checkVal;
+
+		Attrib(IBufferGL buffer, int size, int format, boolean normalized, int stride, int offset) {
+			this.buffer = buffer;
+			this.size = size;
+			this.format = format;
+			this.normalized = normalized;
+			this.stride = stride;
+			this.offset = offset;
+			this.checkVal = ((size - 1) & 3) | (normalized ? 4 : 0) | (format << 4);
+			this.hash = (((((31 + buffer.hashCode()) * 31 + size) * 31 + format) * 31 + (normalized ? 1 : 0)) * 31
+					+ stride) * 31 + offset;
+		}
+
+		public int hashCode() {
+			return hash;
+		}
+
+		public boolean equals(Object obj) {
+			if(obj == this) return true;
+			if(!(obj instanceof Attrib)) return false;
+			Attrib o2 = (Attrib)obj;
+			return o2.hash == hash && o2.buffer == buffer && o2.checkVal == checkVal && o2.stride == stride && o2.offset == offset;
+		}
+
+		public boolean equalsExplicit(Attrib o2) {
+			return o2 == this || (o2.hash == hash && o2.buffer == buffer && o2.checkVal == checkVal && o2.stride == stride && o2.offset == offset);
+		}
+
+	}
+
+}
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/SoftGLBufferState.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/SoftGLBufferState.java
new file mode 100644
index 00000000..611f4352
--- /dev/null
+++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/SoftGLBufferState.java
@@ -0,0 +1,31 @@
+package net.lax1dude.eaglercraft.v1_8.opengl;
+
+import net.lax1dude.eaglercraft.v1_8.opengl.SoftGLBufferArray.Attrib;
+
+/**
+ * Copyright (c) 2024 lax1dude. All Rights Reserved.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ * 
+ */
+class SoftGLBufferState {
+
+	final Attrib[] attribs = new Attrib[24];
+	int[] attribDivisors = new int[24];
+	int hasAttribDivisorMask = 0;
+	int oldEnabled = 0;
+	int oldEnabledCnt = -1;
+
+	SoftGLBufferState() {
+	}
+
+}
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/SpriteLevelMixer.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/SpriteLevelMixer.java
index 439b314f..e01dbd39 100644
--- a/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/SpriteLevelMixer.java
+++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/SpriteLevelMixer.java
@@ -10,7 +10,6 @@ import net.lax1dude.eaglercraft.v1_8.internal.IUniformGL;
 import net.lax1dude.eaglercraft.v1_8.internal.buffer.FloatBuffer;
 import net.lax1dude.eaglercraft.v1_8.log4j.LogManager;
 import net.lax1dude.eaglercraft.v1_8.log4j.Logger;
-import net.lax1dude.eaglercraft.v1_8.opengl.FixedFunctionShader.FixedFunctionConstants;
 import net.lax1dude.eaglercraft.v1_8.vector.Matrix3f;
 
 /**
@@ -33,6 +32,7 @@ public class SpriteLevelMixer {
 	private static final Logger LOGGER = LogManager.getLogger("SpriteLevelMixer");
 
 	public static final String fragmentShaderPath = "/assets/eagler/glsl/texture_mix.fsh";
+	public static final String fragmentShaderPrecision = "precision lowp int;\nprecision highp float;\nprecision highp sampler2D;\n";
 
 	private static IProgramGL shaderProgram = null;
 
@@ -61,15 +61,11 @@ public class SpriteLevelMixer {
 	private static final Matrix3f identityMatrix = new Matrix3f();
 
 	static void initialize() {
-
-		String fragmentSource = EagRuntime.getResourceString(fragmentShaderPath);
-		if(fragmentSource == null) {
-			throw new RuntimeException("SpriteLevelMixer shader \"" + fragmentShaderPath + "\" is missing!");
-		}
+		String fragmentSource = EagRuntime.getRequiredResourceString(fragmentShaderPath);
 
 		IShaderGL frag = _wglCreateShader(GL_FRAGMENT_SHADER);
 
-		_wglShaderSource(frag, FixedFunctionConstants.VERSION + "\n" + fragmentSource);
+		_wglShaderSource(frag, GLSLHeader.getFragmentHeaderCompat(fragmentSource, fragmentShaderPrecision));
 		_wglCompileShader(frag);
 
 		if(_wglGetShaderi(frag, GL_COMPILE_STATUS) != GL_TRUE) {
@@ -89,6 +85,10 @@ public class SpriteLevelMixer {
 		_wglAttachShader(shaderProgram, DrawUtils.vshLocal);
 		_wglAttachShader(shaderProgram, frag);
 
+		if(EaglercraftGPU.checkOpenGLESVersion() == 200) {
+			VSHInputLayoutParser.applyLayout(shaderProgram, DrawUtils.vshLocalLayout);
+		}
+
 		_wglLinkProgram(shaderProgram);
 
 		_wglDetachShader(shaderProgram, DrawUtils.vshLocal);
@@ -155,7 +155,14 @@ public class SpriteLevelMixer {
 	public static void drawSprite(float level) {
 		EaglercraftGPU.bindGLShaderProgram(shaderProgram);
 		
-		_wglUniform1f(u_textureLod1f, level);
+		if(EaglercraftGPU.checkTextureLODCapable()) {
+			_wglUniform1f(u_textureLod1f, level);
+		}else {
+			if(level != 0.0f) {
+				LOGGER.error("Tried to copy from mipmap level {}, but this GPU does not support textureLod!", level);
+			}
+			_wglUniform1f(u_textureLod1f, 0.0f);
+		}
 		
 		if(blendColorChanged) {
 			_wglUniform4f(u_blendFactor4f, blendColorR, blendColorG, blendColorB, blendColorA);
@@ -178,4 +185,19 @@ public class SpriteLevelMixer {
 		DrawUtils.drawStandardQuad2D();
 	}
 
+	public static void destroy() {
+		if(matrixCopyBuffer != null) {
+			EagRuntime.freeFloatBuffer(matrixCopyBuffer);
+			matrixCopyBuffer = null;
+		}
+		if(shaderProgram != null) {
+			_wglDeleteProgram(shaderProgram);
+			shaderProgram = null;
+		}
+		u_textureLod1f = null;
+		u_blendFactor4f = null;
+		u_blendBias4f = null;
+		u_matrixTransform = null;
+	}
+
 }
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/StreamBuffer.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/StreamBuffer.java
index d6a44616..252830eb 100644
--- a/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/StreamBuffer.java
+++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/StreamBuffer.java
@@ -74,7 +74,7 @@ public class StreamBuffer {
 			next.vertexBuffer = _wglGenBuffers();
 		}
 		if(next.vertexArray == null) {
-			next.vertexArray = _wglGenVertexArrays();
+			next.vertexArray = EaglercraftGPU.createGLBufferArray();
 			initializer.initialize(next.vertexArray, next.vertexBuffer);
 		}
 		if(next.vertexBufferSize < requiredMemory) {
@@ -100,7 +100,7 @@ public class StreamBuffer {
 						newArray[i] = buffers[i];
 					}else {
 						if(buffers[i].vertexArray != null) {
-							_wglDeleteVertexArrays(buffers[i].vertexArray);
+							EaglercraftGPU.destroyGLBufferArray(buffers[i].vertexArray);
 						}
 						if(buffers[i].vertexBuffer != null) {
 							_wglDeleteBuffers(buffers[i].vertexBuffer);
@@ -135,7 +135,7 @@ public class StreamBuffer {
 		for(int i = 0; i < buffers.length; ++i) {
 			StreamBufferInstance next = buffers[i];
 			if(next.vertexArray != null) {
-				_wglDeleteVertexArrays(next.vertexArray);
+				EaglercraftGPU.destroyGLBufferArray(next.vertexArray);
 			}
 			if(next.vertexBuffer != null) {
 				_wglDeleteBuffers(next.vertexBuffer);
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/TextureCopyUtil.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/TextureCopyUtil.java
index 32fb3cec..b5f6f9f4 100644
--- a/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/TextureCopyUtil.java
+++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/TextureCopyUtil.java
@@ -3,16 +3,17 @@ package net.lax1dude.eaglercraft.v1_8.opengl;
 import static net.lax1dude.eaglercraft.v1_8.internal.PlatformOpenGL.*;
 import static net.lax1dude.eaglercraft.v1_8.opengl.RealOpenGLEnums.*;
 
+import java.util.List;
+
 import net.lax1dude.eaglercraft.v1_8.EagRuntime;
 import net.lax1dude.eaglercraft.v1_8.internal.IProgramGL;
 import net.lax1dude.eaglercraft.v1_8.internal.IShaderGL;
 import net.lax1dude.eaglercraft.v1_8.internal.IUniformGL;
 import net.lax1dude.eaglercraft.v1_8.log4j.LogManager;
 import net.lax1dude.eaglercraft.v1_8.log4j.Logger;
-import net.lax1dude.eaglercraft.v1_8.opengl.FixedFunctionShader.FixedFunctionConstants;
 
 /**
- * Copyright (c) 2023 lax1dude. All Rights Reserved.
+ * Copyright (c) 2023-2024 lax1dude. All Rights Reserved.
  * 
  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
@@ -31,9 +32,13 @@ public class TextureCopyUtil {
 	private static final Logger LOGGER = LogManager.getLogger("TextureCopyUtil");
 
 	public static final String vertexShaderPath = "/assets/eagler/glsl/texture_blit.vsh";
+	public static final String vertexShaderPrecision = "precision lowp int;\nprecision highp float;\nprecision highp sampler2D;\n";
+
 	public static final String fragmentShaderPath = "/assets/eagler/glsl/texture_blit.fsh";
+	public static final String fragmentShaderPrecision = "precision lowp int;\nprecision highp float;\nprecision highp sampler2D;\n";
 
 	private static String vshSource = null;
+	private static List<VSHInputLayoutParser.ShaderInput> vshSourceLayout = null;
 	private static String fshSource = null;
 
 	private static IShaderGL vshShader = null;
@@ -54,6 +59,17 @@ public class TextureCopyUtil {
 			this.u_pixelAlignmentSizes4f = _wglGetUniformLocation(shaderProgram, "u_pixelAlignmentSizes4f");
 			this.u_pixelAlignmentOffset2f = _wglGetUniformLocation(shaderProgram, "u_pixelAlignmentOffset2f");
 		}
+		private void destroy() {
+			if(shaderProgram != null) {
+				_wglDeleteProgram(shaderProgram);
+				shaderProgram = null;
+			}
+			u_srcCoords4f = null;
+			u_dstCoords4f = null;
+			u_textureLod1f = null;
+			u_pixelAlignmentSizes4f = null;
+			u_pixelAlignmentOffset2f = null;
+		}
 	}
 
 	private static TextureCopyShader textureBlit = null;
@@ -74,19 +90,12 @@ public class TextureCopyUtil {
 	private static float alignOffsetY = 0.0f;
 
 	static void initialize() {
-		vshSource = EagRuntime.getResourceString(vertexShaderPath);
-		if(vshSource == null) {
-			throw new RuntimeException("TextureCopyUtil shader \"" + vertexShaderPath + "\" is missing!");
-		}
-
-		fshSource = EagRuntime.getResourceString(fragmentShaderPath);
-		if(fshSource == null) {
-			throw new RuntimeException("TextureCopyUtil shader \"" + fragmentShaderPath + "\" is missing!");
-		}
+		vshSource = EagRuntime.getRequiredResourceString(vertexShaderPath);
+		fshSource = EagRuntime.getRequiredResourceString(fragmentShaderPath);
 
 		vshShader = _wglCreateShader(GL_VERTEX_SHADER);
 
-		_wglShaderSource(vshShader, FixedFunctionConstants.VERSION + "\n" + vshSource);
+		_wglShaderSource(vshShader, GLSLHeader.getVertexHeaderCompat(vshSource, vertexShaderPrecision));
 		_wglCompileShader(vshShader);
 
 		if(_wglGetShaderi(vshShader, GL_COMPILE_STATUS) != GL_TRUE) {
@@ -100,14 +109,17 @@ public class TextureCopyUtil {
 			}
 			throw new IllegalStateException("Vertex shader \"" + vertexShaderPath + "\" could not be compiled!");
 		}
+		
+		if(EaglercraftGPU.checkOpenGLESVersion() == 200) {
+			vshSourceLayout = VSHInputLayoutParser.getShaderInputs(vshSource);
+		}
 	}
 
 	private static TextureCopyShader compileShader(boolean align, boolean depth) {
 		IShaderGL frag = _wglCreateShader(GL_FRAGMENT_SHADER);
 
-		_wglShaderSource(frag,
-				FixedFunctionConstants.VERSION + "\n" + (align ? "#define COMPILE_PIXEL_ALIGNMENT\n" : "")
-						+ (depth ? "#define COMPILE_BLIT_DEPTH\n" : "") + fshSource);
+		_wglShaderSource(frag, GLSLHeader.getFragmentHeaderCompat(fshSource, fragmentShaderPrecision
+				+ (align ? "#define COMPILE_PIXEL_ALIGNMENT\n" : "") + (depth ? "#define COMPILE_BLIT_DEPTH\n" : "")));
 		_wglCompileShader(frag);
 
 		if(_wglGetShaderi(frag, GL_COMPILE_STATUS) != GL_TRUE) {
@@ -127,6 +139,10 @@ public class TextureCopyUtil {
 		_wglAttachShader(shaderProgram, vshShader);
 		_wglAttachShader(shaderProgram, frag);
 
+		if(EaglercraftGPU.checkOpenGLESVersion() == 200) {
+			VSHInputLayoutParser.applyLayout(shaderProgram, vshSourceLayout);
+		}
+
 		_wglLinkProgram(shaderProgram);
 
 		_wglDetachShader(shaderProgram, vshShader);
@@ -226,7 +242,14 @@ public class TextureCopyUtil {
 		_wglUniform4f(shaderObj.u_srcCoords4f, (float)srcX / srcViewW, (float)srcY / srcViewH, (float)srcW / srcViewW, (float)srcH / srcViewH);
 		_wglUniform4f(shaderObj.u_dstCoords4f, (float) dstX / dstViewW - 1.0f, (float) dstY / dstViewH - 1.0f,
 				(float) dstW / dstViewW, (float) dstH / dstViewH);
-		_wglUniform1f(shaderObj.u_textureLod1f, lvl);
+		if(EaglercraftGPU.checkTextureLODCapable()) {
+			_wglUniform1f(shaderObj.u_textureLod1f, lvl);
+		}else {
+			if(lvl != 0.0f) {
+				LOGGER.error("Tried to copy from mipmap level {}, but this GPU does not support textureLod!", lvl);
+			}
+			_wglUniform1f(shaderObj.u_textureLod1f, 0.0f);
+		}
 		if(isAligned) {
 			_wglUniform4f(shaderObj.u_pixelAlignmentSizes4f, alignW, alignH, 1.0f / alignW, 1.0f / alignH);
 			_wglUniform2f(shaderObj.u_pixelAlignmentOffset2f, alignOffsetX, alignOffsetY);
@@ -244,7 +267,14 @@ public class TextureCopyUtil {
 		EaglercraftGPU.bindGLShaderProgram(shaderObj.shaderProgram);
 		_wglUniform4f(shaderObj.u_srcCoords4f, 0.0f, 0.0f, 1.0f, 1.0f);
 		_wglUniform4f(shaderObj.u_dstCoords4f, -1.0f, -1.0f, 2.0f, 2.0f);
-		_wglUniform1f(shaderObj.u_textureLod1f, lvl);
+		if(EaglercraftGPU.checkTextureLODCapable()) {
+			_wglUniform1f(shaderObj.u_textureLod1f, lvl);
+		}else {
+			if(lvl != 0.0f) {
+				LOGGER.error("Tried to copy from mipmap level {}, but this GPU does not support textureLod!", lvl);
+			}
+			_wglUniform1f(shaderObj.u_textureLod1f, 0.0f);
+		}
 		if(isAligned) {
 			_wglUniform4f(shaderObj.u_pixelAlignmentSizes4f, alignW, alignH, 1.0f / alignW, 1.0f / alignH);
 			_wglUniform2f(shaderObj.u_pixelAlignmentOffset2f, alignOffsetX, alignOffsetY);
@@ -271,7 +301,14 @@ public class TextureCopyUtil {
 		GlStateManager.viewport(dstX, dstY, dstW, dstH);
 		_wglUniform4f(shaderObj.u_srcCoords4f, (float)srcX / srcViewW, (float)srcY / srcViewH, (float)srcW / srcViewW, (float)srcH / srcViewH);
 		_wglUniform4f(shaderObj.u_dstCoords4f, -1.0f, -1.0f, 2.0f, 2.0f);
-		_wglUniform1f(shaderObj.u_textureLod1f, lvl);
+		if(EaglercraftGPU.checkTextureLODCapable()) {
+			_wglUniform1f(shaderObj.u_textureLod1f, lvl);
+		}else {
+			if(lvl != 0.0f) {
+				LOGGER.error("Tried to copy from mipmap level {}, but this GPU does not support textureLod!", lvl);
+			}
+			_wglUniform1f(shaderObj.u_textureLod1f, 0.0f);
+		}
 		if(isAligned) {
 			_wglUniform4f(shaderObj.u_pixelAlignmentSizes4f, alignW, alignH, 1.0f / alignW, 1.0f / alignH);
 			_wglUniform2f(shaderObj.u_pixelAlignmentOffset2f, alignOffsetX, alignOffsetY);
@@ -298,7 +335,14 @@ public class TextureCopyUtil {
 		_wglUniform4f(shaderObj.u_srcCoords4f, (float)srcX / srcViewW, (float)srcY / srcViewH, (float)srcW / srcViewW, (float)srcH / srcViewH);
 		_wglUniform4f(shaderObj.u_dstCoords4f, (float) dstX / dstViewW - 1.0f, (float) dstY / dstViewH - 1.0f,
 				(float) dstW / dstViewW, (float) dstH / dstViewH);
-		_wglUniform1f(shaderObj.u_textureLod1f, lvl);
+		if(EaglercraftGPU.checkTextureLODCapable()) {
+			_wglUniform1f(shaderObj.u_textureLod1f, lvl);
+		}else {
+			if(lvl != 0.0f) {
+				LOGGER.error("Tried to copy from mipmap level {}, but this GPU does not support textureLod!", lvl);
+			}
+			_wglUniform1f(shaderObj.u_textureLod1f, 0.0f);
+		}
 		if(isAligned) {
 			_wglUniform4f(shaderObj.u_pixelAlignmentSizes4f, alignW, alignH, 1.0f / alignW, 1.0f / alignH);
 			_wglUniform2f(shaderObj.u_pixelAlignmentOffset2f, alignOffsetX, alignOffsetY);
@@ -316,7 +360,14 @@ public class TextureCopyUtil {
 		EaglercraftGPU.bindGLShaderProgram(shaderObj.shaderProgram);
 		_wglUniform4f(shaderObj.u_srcCoords4f, 0.0f, 0.0f, 1.0f, 1.0f);
 		_wglUniform4f(shaderObj.u_dstCoords4f, -1.0f, -1.0f, 2.0f, 2.0f);
-		_wglUniform1f(shaderObj.u_textureLod1f, lvl);
+		if(EaglercraftGPU.checkTextureLODCapable()) {
+			_wglUniform1f(shaderObj.u_textureLod1f, lvl);
+		}else {
+			if(lvl != 0.0f) {
+				LOGGER.error("Tried to copy from mipmap level {}, but this GPU does not support textureLod!", lvl);
+			}
+			_wglUniform1f(shaderObj.u_textureLod1f, 0.0f);
+		}
 		if(isAligned) {
 			_wglUniform4f(shaderObj.u_pixelAlignmentSizes4f, alignW, alignH, 1.0f / alignW, 1.0f / alignH);
 			_wglUniform2f(shaderObj.u_pixelAlignmentOffset2f, alignOffsetX, alignOffsetY);
@@ -343,7 +394,14 @@ public class TextureCopyUtil {
 		GlStateManager.viewport(dstX, dstY, dstW, dstH);
 		_wglUniform4f(shaderObj.u_srcCoords4f, (float)srcX / srcViewW, (float)srcY / srcViewH, (float)srcW / srcViewW, (float)srcH / srcViewH);
 		_wglUniform4f(shaderObj.u_dstCoords4f, -1.0f, -1.0f, 2.0f, 2.0f);
-		_wglUniform1f(shaderObj.u_textureLod1f, lvl);
+		if(EaglercraftGPU.checkTextureLODCapable()) {
+			_wglUniform1f(shaderObj.u_textureLod1f, lvl);
+		}else {
+			if(lvl != 0.0f) {
+				LOGGER.error("Tried to copy from mipmap level {}, but this GPU does not support textureLod!", lvl);
+			}
+			_wglUniform1f(shaderObj.u_textureLod1f, 0.0f);
+		}
 		if(isAligned) {
 			_wglUniform4f(shaderObj.u_pixelAlignmentSizes4f, alignW, alignH, 1.0f / alignW, 1.0f / alignH);
 			_wglUniform2f(shaderObj.u_pixelAlignmentOffset2f, alignOffsetX, alignOffsetY);
@@ -351,4 +409,27 @@ public class TextureCopyUtil {
 		}
 		DrawUtils.drawStandardQuad2D();
 	}
+
+	public static void destroy() {
+		if(vshShader != null) {
+			_wglDeleteShader(vshShader);
+			vshShader = null;
+		}
+		if(textureBlit != null) {
+			textureBlit.destroy();
+			textureBlit = null;
+		}
+		if(textureBlitAligned != null) {
+			textureBlitAligned.destroy();
+			textureBlitAligned = null;
+		}
+		if(textureBlitDepth != null) {
+			textureBlitDepth.destroy();
+			textureBlitDepth = null;
+		}
+		if(textureBlitDepthAligned != null) {
+			textureBlitDepthAligned.destroy();
+			textureBlitDepthAligned = null;
+		}
+	}
 }
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/TextureFormatHelper.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/TextureFormatHelper.java
new file mode 100644
index 00000000..6049022f
--- /dev/null
+++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/TextureFormatHelper.java
@@ -0,0 +1,81 @@
+package net.lax1dude.eaglercraft.v1_8.opengl;
+
+import static net.lax1dude.eaglercraft.v1_8.opengl.RealOpenGLEnums.*;
+import static net.lax1dude.eaglercraft.v1_8.opengl.ext.deferred.ExtGLEnums.*;
+
+/**
+ * Copyright (c) 2024 lax1dude. All Rights Reserved.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ * 
+ */
+public class TextureFormatHelper {
+
+	public static int getFormatFromInternal(int internalFormat) {
+		switch(internalFormat) {
+		case _GL_R8:
+		case 0x822D: // GL_R16F
+		case 0x822E: // GL_R32F
+			return GL_RED;
+		case _GL_RG8:
+		case 0x822F: // GL_RG16F
+		case 0x8230: // GL_RG32F
+			return _GL_RG;
+		case GL_RGB8:
+		case _GL_RGB16F:
+		case 0x8815: // GL_RGB32F
+			return GL_RGB;
+		case GL_RGBA8:
+		case 0x881A: // GL_RGBA16F
+		case 0x8814: // GL_RGBA32F
+			return GL_RGBA;
+		default:
+			throw new UnsupportedOperationException();
+		}
+	}
+
+	public static int getTypeFromInternal(int internalFormat) {
+		switch(internalFormat) {
+		case _GL_R8:
+		case _GL_RG8:
+		case GL_RGB8:
+		case GL_RGBA8:
+			return GL_UNSIGNED_BYTE;
+		case 0x822D: // GL_R16F
+		case 0x822F: // GL_RG16F
+		case _GL_RGB16F:
+		case 0x881A: // GL_RGBA16F
+			return _GL_HALF_FLOAT;
+		case 0x822E: // GL_R32F
+		case 0x8230: // GL_RG32F
+		case 0x8815: // GL_RGB32F
+		case 0x8814: // GL_RGBA32F
+			return GL_FLOAT;
+		default:
+			throw new UnsupportedOperationException();
+		}
+	}
+
+	public static int trivializeInternalFormatToGLES20(int internalFormat) {
+		switch(internalFormat) {
+		case _GL_R8:
+			return GL_LUMINANCE;
+		case GL_RGB8:
+			return GL_RGB;
+		case GL_RGBA8:
+			return GL_RGBA;
+		default:
+			throw new UnsupportedOperationException();
+		}
+	}
+
+}
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/VSHInputLayoutParser.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/VSHInputLayoutParser.java
new file mode 100644
index 00000000..0eaf2e9a
--- /dev/null
+++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/VSHInputLayoutParser.java
@@ -0,0 +1,91 @@
+package net.lax1dude.eaglercraft.v1_8.opengl;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import net.lax1dude.eaglercraft.v1_8.EagUtils;
+import net.lax1dude.eaglercraft.v1_8.internal.IProgramGL;
+
+import static net.lax1dude.eaglercraft.v1_8.internal.PlatformOpenGL.*;
+
+/**
+ * Copyright (c) 2024 lax1dude. All Rights Reserved.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ * 
+ */
+public class VSHInputLayoutParser {
+
+	public static class ShaderInput {
+
+		public final int index;
+		public final String type;
+		public final String name;
+
+		public ShaderInput(int index, String type, String name) {
+			this.index = index;
+			this.type = type;
+			this.name = name;
+		}
+
+	}
+
+	public static class ShaderLayoutParseException extends RuntimeException {
+
+		public ShaderLayoutParseException(String message, Throwable cause) {
+			super(message, cause);
+		}
+
+		public ShaderLayoutParseException(String message) {
+			super(message);
+		}
+
+	}
+
+	public static List<ShaderInput> getShaderInputs(String vshSource) {
+		int idx1 = vshSource.indexOf("EAGLER_VSH_LAYOUT_BEGIN()");
+		if(idx1 == -1) {
+			throw new ShaderLayoutParseException("Could not find \"EAGLER_VSH_LAYOUT_BEGIN()\" delimiter!");
+		}
+		int idx2 = vshSource.indexOf("EAGLER_VSH_LAYOUT_END()", idx1 + 25);
+		if(idx2 == -1) {
+			throw new ShaderLayoutParseException("Could not find \"EAGLER_VSH_LAYOUT_END()\" delimiter!");
+		}
+		List<String> lines = EagUtils.linesList(vshSource.substring(idx1 + 25, idx2));
+		List<ShaderInput> ret = new ArrayList<>();
+		for(int i = 0, l = lines.size(); i < l; ++i) {
+			String ln = lines.get(i);
+			ln = ln.trim();
+			if(ln.startsWith("EAGLER_IN(") && ln.endsWith(")")) {
+				String[] tokens = ln.substring(10, ln.length() - 1).split(",", 3);
+				if(tokens.length == 3) {
+					int idx;
+					try {
+						idx = Integer.parseInt(tokens[0].trim());
+					}catch(NumberFormatException ex) {
+						continue;
+					}
+					ret.add(new ShaderInput(idx, tokens[1].trim(), tokens[2].trim()));
+				}
+			}
+		}
+		return ret;
+	}
+
+	public static void applyLayout(IProgramGL program, List<ShaderInput> layout) {
+		for(int i = 0, l = layout.size(); i < l; ++i) {
+			ShaderInput itm = layout.get(i);
+			_wglBindAttribLocation(program, itm.index, itm.name);
+		}
+	}
+
+}
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/WorldRenderer.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/WorldRenderer.java
index a9555f5f..30056597 100644
--- a/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/WorldRenderer.java
+++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/WorldRenderer.java
@@ -8,7 +8,6 @@ import java.util.BitSet;
 import java.util.Comparator;
 
 import net.lax1dude.eaglercraft.v1_8.EagRuntime;
-import net.lax1dude.eaglercraft.v1_8.internal.PlatformBufferFunctions;
 import net.lax1dude.eaglercraft.v1_8.log4j.LogManager;
 import net.lax1dude.eaglercraft.v1_8.vector.Vector3f;
 import net.minecraft.client.renderer.GLAllocation;
@@ -121,7 +120,7 @@ public class WorldRenderer {
 				for (int k1 = ainteger[i1].intValue(); j1 != l1; k1 = ainteger[k1].intValue()) {
 					this.intBuffer.limit(k1 * l + l);
 					this.intBuffer.position(k1 * l);
-					IntBuffer intbuffer = this.intBuffer.slice();
+					IntBuffer intbuffer = this.intBuffer.duplicate();
 					this.intBuffer.limit(j1 * l + l);
 					this.intBuffer.position(j1 * l);
 					this.intBuffer.put(intbuffer);
@@ -178,7 +177,10 @@ public class WorldRenderer {
 	 */
 	public void setVertexState(WorldRenderer.State state) {
 		this.grow(state.getRawBuffer().length);
-		PlatformBufferFunctions.put(this.intBuffer, 0, state.getRawBuffer());
+		int p = intBuffer.position();
+		this.intBuffer.position(0);
+		this.intBuffer.put(state.getRawBuffer());
+		this.intBuffer.position(p);
 		this.vertexCount = state.getVertexCount();
 		this.vertexFormat = state.getVertexFormat();
 	}
@@ -339,7 +341,10 @@ public class WorldRenderer {
 	 */
 	public void addVertexData(int[] vertexData) {
 		this.grow(vertexData.length);
-		PlatformBufferFunctions.put(this.intBuffer, (this.vertexCount * this.vertexFormat.attribStride) >> 2, vertexData);
+		int p = this.intBuffer.position();
+		this.intBuffer.position((this.vertexCount * this.vertexFormat.attribStride) >> 2);
+		this.intBuffer.put(vertexData);
+		this.intBuffer.position(p);
 		this.vertexCount += vertexData.length / (this.vertexFormat.attribStride >> 2); 
 	}
 
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/ext/deferred/BlockVertexIDs.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/ext/deferred/BlockVertexIDs.java
index 2a00144a..2b5a2730 100644
--- a/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/ext/deferred/BlockVertexIDs.java
+++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/ext/deferred/BlockVertexIDs.java
@@ -32,7 +32,7 @@ public class BlockVertexIDs implements IResourceManagerReloadListener {
 
 	private static final Logger logger = LogManager.getLogger("BlockVertexIDsCSV");
 
-	public static final Map<String,Integer> modelToID = new HashMap();
+	public static final Map<String,Integer> modelToID = new HashMap<>();
 
 	public static int builtin_water_still_vertex_id = 0;
 	public static int builtin_water_flow_vertex_id = 0;
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/ext/deferred/CloudRenderWorker.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/ext/deferred/CloudRenderWorker.java
index 789e7fe9..05698c41 100644
--- a/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/ext/deferred/CloudRenderWorker.java
+++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/ext/deferred/CloudRenderWorker.java
@@ -103,7 +103,7 @@ public class CloudRenderWorker {
 	static void initialize() {
 		destroy();
 
-		cloudStartTimer = System.currentTimeMillis();
+		cloudStartTimer = EagRuntime.steadyTimeMillis();
 		cloudRenderProgress = 0;
 		cloudRenderPeriod = 500;
 		cloudRenderPhase = 0;
@@ -168,7 +168,7 @@ public class CloudRenderWorker {
 		_wglTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
 		_wglTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
 		_wglTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
-		byte[] cloudShapeTexture = EagRuntime.getResourceBytes("/assets/eagler/glsl/deferred/clouds_shapes.bmp");
+		byte[] cloudShapeTexture = EagRuntime.getRequiredResourceBytes("/assets/eagler/glsl/deferred/clouds_shapes.bmp");
 		cloudNoiseDatBuffer = EagRuntime.allocateByteBuffer(cloudShapeTexture.length);
 		cloudNoiseDatBuffer.put(cloudShapeTexture);
 		cloudNoiseDatBuffer.flip();
@@ -207,7 +207,7 @@ public class CloudRenderWorker {
 	}
 
 	static void update() {
-		long millis = System.currentTimeMillis();
+		long millis = EagRuntime.steadyTimeMillis();
 		int cloudProgress = (int)(millis - cloudStartTimer);
 		int totalCloudSteps = 32 + 32 - 1;
 		int currentCloudStep = cloudProgress * totalCloudSteps / cloudRenderPeriod;
@@ -268,7 +268,7 @@ public class CloudRenderWorker {
 			cloudColorB += (currentSunAngle.z - cloudColorB) * 0.1f;
 			_wglUniform3f(shader_clouds_sample.uniforms.u_sunColor3f, cloudColorR, cloudColorG, cloudColorB);
 			
-			float cloudDensityTimer = (float)((System.currentTimeMillis() % 10000000l) * 0.001);
+			float cloudDensityTimer = (float)((EagRuntime.steadyTimeMillis() % 10000000l) * 0.001);
 			cloudDensityTimer += MathHelper.sin(cloudDensityTimer * 1.5f) * 1.5f;
 			float x = cloudDensityTimer * 0.004f;
 			float f1 = MathHelper.sin(x + 0.322f) * 0.544f + MathHelper.sin(x * 4.5f + 1.843f) * 0.69f + MathHelper.sin(x * 3.4f + 0.8f) * 0.6f + MathHelper.sin(x * 6.1f + 1.72f) * 0.7f;
@@ -404,7 +404,7 @@ public class CloudRenderWorker {
 		
 		if(b) {
 			cloudRenderProgress = 0;
-			cloudStartTimer = System.currentTimeMillis();
+			cloudStartTimer = EagRuntime.steadyTimeMillis();
 			cloudProgress = 0;
 			cloudRenderPhase = (cloudRenderPhase + 1) % 3;
 		}else {
@@ -539,7 +539,7 @@ public class CloudRenderWorker {
 	}
 
 	private static void updateShape() {
-		long millis = System.currentTimeMillis();
+		long millis = EagRuntime.steadyTimeMillis();
 		float dt = (float)((millis - shapeUpdateTimer) * 0.001);
 		shapeUpdateTimer = millis;
 		if(millis > nextShapeAppearance) {
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/ext/deferred/DebugFramebufferView.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/ext/deferred/DebugFramebufferView.java
index dc19044d..1a0913b7 100644
--- a/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/ext/deferred/DebugFramebufferView.java
+++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/ext/deferred/DebugFramebufferView.java
@@ -4,12 +4,12 @@ import java.util.Arrays;
 import java.util.List;
 import java.util.function.Consumer;
 
+import net.lax1dude.eaglercraft.v1_8.EagRuntime;
 import net.lax1dude.eaglercraft.v1_8.opengl.DrawUtils;
 import net.lax1dude.eaglercraft.v1_8.opengl.GlStateManager;
 import net.lax1dude.eaglercraft.v1_8.opengl.ext.deferred.program.PipelineShaderGBufferDebugView;
 import net.minecraft.client.Minecraft;
 import net.minecraft.client.gui.Gui;
-import net.minecraft.client.gui.ScaledResolution;
 
 import static net.lax1dude.eaglercraft.v1_8.internal.PlatformOpenGL.*;
 import static net.lax1dude.eaglercraft.v1_8.opengl.RealOpenGLEnums.*;
@@ -249,7 +249,7 @@ public class DebugFramebufferView {
 				PipelineShaderGBufferDebugView dbg = pipeline.useDebugViewShader(18);
 				GlStateManager.setActiveTexture(GL_TEXTURE0);
 				GlStateManager.bindTexture3D(CloudRenderWorker.cloud3DSamplesTexture);
-				_wglUniform1f(_wglGetUniformLocation(dbg.program, "u_fuckU1f"), (float)((System.currentTimeMillis() % 5000l) / 5000.0));
+				_wglUniform1f(_wglGetUniformLocation(dbg.program, "u_fuckU1f"), (float)((EagRuntime.steadyTimeMillis() % 5000l) / 5000.0));
 				DrawUtils.drawStandardQuad2D();
 			})),
 			(new DebugFramebufferView("Clouds Back Buffer", (pipeline) -> {
@@ -449,19 +449,18 @@ public class DebugFramebufferView {
 			GlStateManager.clear(GL_COLOR_BUFFER_BIT);
 			noData = true;
 		}
-		long millis = System.currentTimeMillis();
+		long millis = EagRuntime.steadyTimeMillis();
 		long elapsed = millis - debugViewNameTimer;
 		if(elapsed < 2000l || noData) {
 			GlStateManager.matrixMode(GL_PROJECTION);
 			GlStateManager.pushMatrix();
 			GlStateManager.matrixMode(GL_MODELVIEW);
 			GlStateManager.pushMatrix();
-			ScaledResolution scaledresolution = new ScaledResolution(mc);
-			int w = scaledresolution.getScaledWidth();
+			int w = mc.scaledResolution.getScaledWidth();
 			mc.entityRenderer.setupOverlayRendering();
 			GlStateManager.enableBlend();
 			GlStateManager.blendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
-			int h = scaledresolution.getScaledHeight() / 2;
+			int h = mc.scaledResolution.getScaledHeight() / 2;
 			
 			if(noData) {
 				String noDataTxt = "No Data";
@@ -507,13 +506,13 @@ public class DebugFramebufferView {
 	public static void toggleDebugView() {
 		debugViewShown = !debugViewShown;
 		if(debugViewShown) {
-			debugViewNameTimer = System.currentTimeMillis();
+			debugViewNameTimer = EagRuntime.steadyTimeMillis();
 		}
 	}
 
 	public static void switchView(int dir) {
 		if(!debugViewShown) return;
-		debugViewNameTimer = System.currentTimeMillis();
+		debugViewNameTimer = EagRuntime.steadyTimeMillis();
 		currentDebugView += dir;
 		if(currentDebugView < 0) currentDebugView = views.size() - 1;
 		if(currentDebugView >= views.size()) currentDebugView = 0;
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/ext/deferred/DeferredStateManager.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/ext/deferred/DeferredStateManager.java
index 68d5d0a7..e55faddd 100644
--- a/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/ext/deferred/DeferredStateManager.java
+++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/ext/deferred/DeferredStateManager.java
@@ -148,7 +148,7 @@ public class DeferredStateManager {
 			if(!cfg.is_rendering_dynamicLights || !cfg.shaderPackInfo.DYNAMIC_LIGHTS) {
 				return;
 			}
-			instance.loadLightSourceBucket(centerX, centerY, centerZ);
+			instance.bindLightSourceBucket(centerX, centerY, centerZ, 1);
 		}
 	}
 
@@ -162,7 +162,7 @@ public class DeferredStateManager {
 			float posX = (float)((x + TileEntityRendererDispatcher.staticPlayerX) - (MathHelper.floor_double(TileEntityRendererDispatcher.staticPlayerX / 16.0) << 4));
 			float posY = (float)((y + TileEntityRendererDispatcher.staticPlayerY) - (MathHelper.floor_double(TileEntityRendererDispatcher.staticPlayerY / 16.0) << 4));
 			float posZ = (float)((z + TileEntityRendererDispatcher.staticPlayerZ) - (MathHelper.floor_double(TileEntityRendererDispatcher.staticPlayerZ / 16.0) << 4));
-			instance.loadLightSourceBucket((int)posX, (int)posY, (int)posZ);
+			instance.bindLightSourceBucket((int)posX, (int)posY, (int)posZ, 1);
 		}
 	}
 
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/ext/deferred/DynamicLightInstance.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/ext/deferred/DynamicLightInstance.java
index e0c45ca7..a846bae8 100644
--- a/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/ext/deferred/DynamicLightInstance.java
+++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/ext/deferred/DynamicLightInstance.java
@@ -1,5 +1,7 @@
 package net.lax1dude.eaglercraft.v1_8.opengl.ext.deferred;
 
+import net.lax1dude.eaglercraft.v1_8.EagRuntime;
+
 /**
  * Copyright (c) 2023 lax1dude. All Rights Reserved.
  * 
@@ -35,7 +37,7 @@ class DynamicLightInstance {
 	}
 
 	public void updateLight(double posX, double posY, double posZ, float red, float green, float blue) {
-		this.lastCacheHit = System.currentTimeMillis();
+		this.lastCacheHit = EagRuntime.steadyTimeMillis();
 		this.posX = posX;
 		this.posY = posY;
 		this.posZ = posZ;
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/ext/deferred/DynamicLightManager.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/ext/deferred/DynamicLightManager.java
index 1315b344..5b91886f 100644
--- a/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/ext/deferred/DynamicLightManager.java
+++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/ext/deferred/DynamicLightManager.java
@@ -6,6 +6,8 @@ import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
 
+import net.lax1dude.eaglercraft.v1_8.EagRuntime;
+
 /**
  * Copyright (c) 2023 lax1dude. All Rights Reserved.
  * 
@@ -23,8 +25,8 @@ import java.util.Map;
  */
 public class DynamicLightManager {
 
-	static final Map<String, DynamicLightInstance> lightRenderers = new HashMap();
-	static final List<DynamicLightInstance> lightRenderList = new LinkedList();
+	static final Map<String, DynamicLightInstance> lightRenderers = new HashMap<>();
+	static final List<DynamicLightInstance> lightRenderList = new LinkedList<>();
 	static long renderTimeout = 5000l;
 	static boolean isRenderLightsPass = false;
 
@@ -51,7 +53,7 @@ public class DynamicLightManager {
 	}
 
 	static void updateTimers() {
-		long millis = System.currentTimeMillis();
+		long millis = EagRuntime.steadyTimeMillis();
 		if(millis - lastTick > 1000l) {
 			lastTick = millis;
 			Iterator<DynamicLightInstance> itr = lightRenderers.values().iterator();
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/ext/deferred/EaglerDeferredPipeline.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/ext/deferred/EaglerDeferredPipeline.java
index 6e0fa7e7..4e9b63f5 100644
--- a/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/ext/deferred/EaglerDeferredPipeline.java
+++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/ext/deferred/EaglerDeferredPipeline.java
@@ -71,7 +71,7 @@ import java.util.Iterator;
 import java.util.List;
 
 /**
- * Copyright (c) 2023 lax1dude. All Rights Reserved.
+ * Copyright (c) 2023-2024 lax1dude. All Rights Reserved.
  * 
  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
@@ -112,6 +112,7 @@ public class EaglerDeferredPipeline {
 	public double currentRenderX = 0.0;
 	public double currentRenderY = 0.0;
 	public double currentRenderZ = 0.0;
+	public int currentRenderPosSerial = 0;
 
 	public IFramebufferGL gBufferFramebuffer = null;
 
@@ -307,6 +308,7 @@ public class EaglerDeferredPipeline {
 	private ByteBuffer worldLightingDataCopyBuffer;
 
 	public IBufferGL buffer_chunkLightingData;
+	public IBufferGL buffer_chunkLightingDataZero;
 	private ByteBuffer chunkLightingDataCopyBuffer;
 	private boolean isChunkLightingEnabled = false;
 	public ListSerial<DynamicLightInstance> currentBoundLightSourceBucket;
@@ -336,9 +338,20 @@ public class EaglerDeferredPipeline {
 	public static final Vector3f tmpVector4 = new Vector3f();
 
 	public final ListSerial<DynamicLightInstance>[] lightSourceBuckets;
+	private final int[] lightSourceBucketSerials;
+	private final int[] lightSourceRenderPosSerials;
 	public ListSerial<DynamicLightInstance> currentLightSourceBucket;
+	private int currentLightSourceBucketId = -1;
+	private int lightingBufferSliceLength = -1;
 
 	public static final int MAX_LIGHTS_PER_CHUNK = 12;
+	public static final int LIGHTING_BUFFER_LENGTH = 32 * MAX_LIGHTS_PER_CHUNK + 16;
+
+	private int uniformBufferOffsetAlignment = -1;
+
+	private int uboAlign(int offset) {
+		return MathHelper.ceiling_float_int((float)offset / (float)uniformBufferOffsetAlignment) * uniformBufferOffsetAlignment;
+	}
 
 	private final int lightSourceBucketsWidth;
 	private final int lightSourceBucketsHeight;
@@ -372,13 +385,18 @@ public class EaglerDeferredPipeline {
 		this.lightSourceBucketsHeight = 3;
 		int cnt = 5 * 3 * 5;
 		this.lightSourceBuckets = new ListSerial[cnt];
+		this.lightSourceBucketSerials = new int[cnt];
+		this.lightSourceRenderPosSerials = new int[cnt];
 		for(int i = 0; i < cnt; ++i) {
-			this.lightSourceBuckets[i] = new ArrayListSerial(16);
+			this.lightSourceBuckets[i] = new ArrayListSerial<>(16);
+			this.lightSourceBucketSerials[i] = -1;
+			this.lightSourceRenderPosSerials[i] = -1;
 		}
 	}
 
 	public void rebuild(EaglerDeferredConfig config) {
 		destroy();
+		uniformBufferOffsetAlignment = EaglercraftGPU.getUniformBufferOffsetAlignment();
 		DeferredStateManager.doCheckErrors = EagRuntime.getConfiguration().isCheckShaderGLErrors();
 		DeferredStateManager.checkGLError("Pre: rebuild pipeline");
 		this.config = config;
@@ -544,7 +562,7 @@ public class EaglerDeferredPipeline {
 			GlStateManager.bindTexture(ssaoNoiseTexture);
 			setNearest();
 			int noiseTexSize = 64, noiseTexLen = 16384;
-			byte[] noiseTexDat = EagRuntime.getResourceBytes("assets/eagler/glsl/deferred/ssao_noise.bmp");
+			byte[] noiseTexDat = EagRuntime.getRequiredResourceBytes("assets/eagler/glsl/deferred/ssao_noise.bmp");
 			if(noiseTexDat == null || noiseTexDat.length != noiseTexLen) {
 				noiseTexDat = new byte[noiseTexLen];
 				for(int i = 0; i < 4096; ++i) {
@@ -592,7 +610,7 @@ public class EaglerDeferredPipeline {
 		GlStateManager.bindTexture(brdfTexture);
 		setLinear();
 		int brdfLutW = 64, brdfLutH = 64, brdfLutLen = 8192;
-		byte[] brdfLutDat = EagRuntime.getResourceBytes("assets/eagler/glsl/deferred/brdf_lut.bmp");
+		byte[] brdfLutDat = EagRuntime.getRequiredResourceBytes("assets/eagler/glsl/deferred/brdf_lut.bmp");
 		if(brdfLutDat == null || brdfLutDat.length != brdfLutLen) {
 			brdfLutDat = new byte[brdfLutLen];
 			for(int i = 0; i < 4096; ++i) {
@@ -748,7 +766,9 @@ public class EaglerDeferredPipeline {
 		_wglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
 		ByteBuffer copyBuffer = EagRuntime.allocateByteBuffer(262144);
 		int mip = 0;
-		try(DataInputStream dis = new DataInputStream(EagRuntime.getResourceStream("/assets/eagler/glsl/deferred/eagler_moon.bmp"))) {
+		
+		try (DataInputStream dis = new DataInputStream(mc.getResourceManager()
+				.getResource(new ResourceLocation("eagler:glsl/deferred/eagler_moon.bmp")).getInputStream())) {
 			while(dis.read() == 'E') {
 				int w = dis.readShort();
 				int h = dis.readShort();
@@ -873,7 +893,7 @@ public class EaglerDeferredPipeline {
 			_wglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
 			_wglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
 			String realistic_water_noise_filename = "assets/eagler/glsl/deferred/realistic_water_noise.bmp";
-			byte[] bitmapBytes = EagRuntime.getResourceBytes(realistic_water_noise_filename);
+			byte[] bitmapBytes = EagRuntime.getRequiredResourceBytes(realistic_water_noise_filename);
 			try {
 				if(bitmapBytes.length != 32768) {
 					throw new IOException("File is length " + bitmapBytes.length + ", expected " + 32768);
@@ -1008,15 +1028,22 @@ public class EaglerDeferredPipeline {
 			shader_lighting_point = PipelineShaderLightingPoint.compile(false);
 			shader_lighting_point.loadUniforms();
 
-			buffer_chunkLightingData = _wglGenBuffers();
-			EaglercraftGPU.bindGLUniformBuffer(buffer_chunkLightingData);
-			int lightingDataLength = 8 * MAX_LIGHTS_PER_CHUNK + 4;
-			chunkLightingDataCopyBuffer = EagRuntime.allocateByteBuffer(lightingDataLength << 2);
-			for(int i = 0; i < lightingDataLength; ++i) {
+			lightingBufferSliceLength = uboAlign(LIGHTING_BUFFER_LENGTH);
+
+			chunkLightingDataCopyBuffer = EagRuntime.allocateByteBuffer(LIGHTING_BUFFER_LENGTH);
+			for(int i = 0; i < LIGHTING_BUFFER_LENGTH; i += 4) {
 				chunkLightingDataCopyBuffer.putInt(0);
 			}
 			chunkLightingDataCopyBuffer.flip();
-			_wglBufferData(_GL_UNIFORM_BUFFER, chunkLightingDataCopyBuffer, GL_DYNAMIC_DRAW);
+			
+			buffer_chunkLightingData = _wglGenBuffers();
+			EaglercraftGPU.bindGLUniformBuffer(buffer_chunkLightingData);
+			int cnt = lightSourceBucketsWidth * lightSourceBucketsHeight * lightSourceBucketsWidth;
+			_wglBufferData(_GL_UNIFORM_BUFFER, cnt * lightingBufferSliceLength, GL_DYNAMIC_DRAW);
+			
+			buffer_chunkLightingDataZero = _wglGenBuffers();
+			EaglercraftGPU.bindGLUniformBuffer(buffer_chunkLightingDataZero);
+			_wglBufferData(_GL_UNIFORM_BUFFER, chunkLightingDataCopyBuffer, GL_STATIC_DRAW);
 
 			DeferredStateManager.checkGLError("Post: rebuild pipeline: dynamic lights");
 		}
@@ -1042,6 +1069,16 @@ public class EaglerDeferredPipeline {
 		DeferredStateManager.checkGLError("Post: rebuild pipeline");
 	}
 
+	public void setRenderPosGlobal(double renderPosX, double renderPosY, double renderPosZ) {
+		if (renderPosX != currentRenderX || renderPosY != currentRenderY || renderPosZ != currentRenderZ
+				|| currentRenderPosSerial == 0) {
+			currentRenderX = renderPosX;
+			currentRenderY = renderPosY;
+			currentRenderZ = renderPosZ;
+			++currentRenderPosSerial;
+		}
+	}
+
 	public void updateReprojectionCoordinates(double worldX, double worldY, double worldZ) {
 		double distX = worldX - reprojectionOriginCoordinateX;
 		double distY = worldY - reprojectionOriginCoordinateY;
@@ -1467,7 +1504,7 @@ public class EaglerDeferredPipeline {
 		float sunKelvin = 1500.0f + (2500.0f * Math.max(-currentSunAngle.y, 0.0f));
 		float fff = mc.theWorld.getRainStrength(partialTicks);
 		float ff2 = mc.theWorld.getThunderStrength(partialTicks);
-		long millis = System.currentTimeMillis();
+		long millis = EagRuntime.steadyTimeMillis();
 		int dim = Minecraft.getMinecraft().theWorld.provider.getDimensionId();
 
 		// ==================== UPDATE CLOUD RENDERER ===================== //
@@ -2172,7 +2209,7 @@ public class EaglerDeferredPipeline {
 		GlStateManager.disableBlend();
 	}
 
-	public void loadLightSourceBucket(int relativeBlockX, int relativeBlockY, int relativeBlockZ) {
+	public void bindLightSourceBucket(int relativeBlockX, int relativeBlockY, int relativeBlockZ, int uboIndex) {
 		int hw = lightSourceBucketsWidth / 2;
 		int hh = lightSourceBucketsHeight / 2;
 		int bucketX = (relativeBlockX >> 4) + hw;
@@ -2180,12 +2217,51 @@ public class EaglerDeferredPipeline {
 		int bucketZ = (relativeBlockZ >> 4) + hw;
 		if(bucketX >= 0 && bucketY >= 0 && bucketZ >= 0 && bucketX < lightSourceBucketsWidth
 				&& bucketY < lightSourceBucketsHeight && bucketZ < lightSourceBucketsWidth) {
-			currentLightSourceBucket = lightSourceBuckets[bucketY * lightSourceBucketsWidth * lightSourceBucketsWidth
-					+ bucketZ * lightSourceBucketsWidth + bucketX];
+			currentLightSourceBucketId = bucketY * lightSourceBucketsWidth * lightSourceBucketsWidth
+					+ bucketZ * lightSourceBucketsWidth + bucketX;
+			currentLightSourceBucket = lightSourceBuckets[currentLightSourceBucketId];
+			int ser = currentLightSourceBucket.getEaglerSerial();
+			int max = currentLightSourceBucket.size();
+			if(max > 0) {
+				EaglercraftGPU.bindGLUniformBuffer(buffer_chunkLightingData);
+				int offset = currentLightSourceBucketId * lightingBufferSliceLength;
+				if (lightSourceBucketSerials[currentLightSourceBucketId] != ser
+						|| lightSourceRenderPosSerials[currentLightSourceBucketId] != currentRenderPosSerial) {
+					lightSourceBucketSerials[currentLightSourceBucketId] = ser;
+					lightSourceRenderPosSerials[currentLightSourceBucketId] = currentRenderPosSerial;
+					if(max > MAX_LIGHTS_PER_CHUNK) {
+						max = MAX_LIGHTS_PER_CHUNK;
+					}
+					chunkLightingDataCopyBuffer.clear();
+					chunkLightingDataCopyBuffer.putInt(max);
+					chunkLightingDataCopyBuffer.putInt(0); //padding
+					chunkLightingDataCopyBuffer.putInt(0); //padding
+					chunkLightingDataCopyBuffer.putInt(0); //padding
+					for(int i = 0; i < max; ++i) {
+						DynamicLightInstance dl = currentLightSourceBucket.get(i);
+						chunkLightingDataCopyBuffer.putFloat((float)(dl.posX - currentRenderX));
+						chunkLightingDataCopyBuffer.putFloat((float)(dl.posY - currentRenderY));
+						chunkLightingDataCopyBuffer.putFloat((float)(dl.posZ - currentRenderZ));
+						chunkLightingDataCopyBuffer.putInt(0); //padding
+						chunkLightingDataCopyBuffer.putFloat(dl.red);
+						chunkLightingDataCopyBuffer.putFloat(dl.green);
+						chunkLightingDataCopyBuffer.putFloat(dl.blue);
+						chunkLightingDataCopyBuffer.putInt(0); //padding
+					}
+					chunkLightingDataCopyBuffer.flip();
+					_wglBufferSubData(_GL_UNIFORM_BUFFER, offset, chunkLightingDataCopyBuffer);
+				}
+				EaglercraftGPU.bindUniformBufferRange(uboIndex, buffer_chunkLightingData, offset, LIGHTING_BUFFER_LENGTH);
+			}else {
+				EaglercraftGPU.bindGLUniformBuffer(buffer_chunkLightingDataZero);
+				EaglercraftGPU.bindUniformBufferRange(uboIndex, buffer_chunkLightingDataZero, 0, LIGHTING_BUFFER_LENGTH);
+			}
 		}else {
+			currentLightSourceBucketId = -1;
 			currentLightSourceBucket = null;
+			EaglercraftGPU.bindGLUniformBuffer(buffer_chunkLightingDataZero);
+			EaglercraftGPU.bindUniformBufferRange(uboIndex, buffer_chunkLightingDataZero, 0, LIGHTING_BUFFER_LENGTH);
 		}
-		updateLightSourceUBO();
 	}
 
 	public ListSerial<DynamicLightInstance> getLightSourceBucketRelativeChunkCoords(int cx, int cy, int cz) {
@@ -2319,65 +2395,10 @@ public class EaglerDeferredPipeline {
 		}
 	}
 
-	public void updateLightSourceUBO() {
-		if(currentLightSourceBucket == null) {
-			currentBoundLightSourceBucket = null;
-			if(isChunkLightingEnabled) {
-				isChunkLightingEnabled = false;
-				EaglercraftGPU.bindGLUniformBuffer(buffer_chunkLightingData);
-				chunkLightingDataCopyBuffer.clear();
-				chunkLightingDataCopyBuffer.putInt(0);
-				chunkLightingDataCopyBuffer.flip();
-				_wglBufferSubData(_GL_UNIFORM_BUFFER, 0, chunkLightingDataCopyBuffer);
-			}
-		}else {
-			boolean isNew;
-			if(!isChunkLightingEnabled) {
-				isChunkLightingEnabled = true;
-				isNew = true;
-			}else {
-				isNew = currentLightSourceBucket != currentBoundLightSourceBucket;
-			}
-			currentBoundLightSourceBucket = currentLightSourceBucket;
-			if(isNew || currentBoundLightSourceBucket.eaglerCheck()) {
-				populateLightSourceUBOFromBucket(currentBoundLightSourceBucket);
-				currentBoundLightSourceBucket.eaglerResetCheck();
-			}
-		}
-	}
-
 	private static final Comparator<DynamicLightInstance> comparatorLightRadius = (l1, l2) -> {
 		return l1.radius < l2.radius ? 1 : -1;
 	};
 
-	private void populateLightSourceUBOFromBucket(List<DynamicLightInstance> lights) {
-		int max = lights.size();
-		if(max > MAX_LIGHTS_PER_CHUNK) {
-			max = MAX_LIGHTS_PER_CHUNK;
-		}
-		chunkLightingDataCopyBuffer.clear();
-		chunkLightingDataCopyBuffer.putInt(max);
-		if(max > 0) {
-			chunkLightingDataCopyBuffer.putInt(0); //padding
-			chunkLightingDataCopyBuffer.putInt(0); //padding
-			chunkLightingDataCopyBuffer.putInt(0); //padding
-			for(int i = 0; i < max; ++i) {
-				DynamicLightInstance dl = lights.get(i);
-				chunkLightingDataCopyBuffer.putFloat((float)(dl.posX - currentRenderX));
-				chunkLightingDataCopyBuffer.putFloat((float)(dl.posY - currentRenderY));
-				chunkLightingDataCopyBuffer.putFloat((float)(dl.posZ - currentRenderZ));
-				chunkLightingDataCopyBuffer.putInt(0); //padding
-				chunkLightingDataCopyBuffer.putFloat(dl.red);
-				chunkLightingDataCopyBuffer.putFloat(dl.green);
-				chunkLightingDataCopyBuffer.putFloat(dl.blue);
-				chunkLightingDataCopyBuffer.putInt(0); //padding
-			}
-		}
-		chunkLightingDataCopyBuffer.flip();
-		EaglercraftGPU.bindGLUniformBuffer(buffer_chunkLightingData);
-		_wglBufferSubData(_GL_UNIFORM_BUFFER, 0, chunkLightingDataCopyBuffer);
-	}
-
 	public void beginDrawEnvMap() {
 		DeferredStateManager.checkGLError("Pre: beginDrawEnvMap()");
 		GlStateManager.enableDepth();
@@ -2797,7 +2818,7 @@ public class EaglerDeferredPipeline {
 		GlStateManager.bindTexture(realisticWaterNoiseMap);
 
 		shader_realistic_water_noise.useProgram();
-		float waveTimer = (float)((System.currentTimeMillis() % 600000l) * 0.001);
+		float waveTimer = (float)((EagRuntime.steadyTimeMillis() % 600000l) * 0.001);
 		_wglUniform4f(shader_realistic_water_noise.uniforms.u_waveTimer4f, waveTimer, 0.0f, 0.0f, 0.0f);
 
 		DrawUtils.drawStandardQuad2D();
@@ -3147,7 +3168,7 @@ public class EaglerDeferredPipeline {
 
 		// ================ DOWNSCALE AND AVERAGE LUMA =============== //
 
-		long millis = System.currentTimeMillis();
+		long millis = EagRuntime.steadyTimeMillis();
 		if(millis - lastExposureUpdate > 33l) {
 			if(lumaAvgDownscaleFramebuffers.length == 0) {
 				_wglBindFramebuffer(_GL_FRAMEBUFFER, exposureBlendFramebuffer);
@@ -3925,6 +3946,10 @@ public class EaglerDeferredPipeline {
 			_wglDeleteBuffers(buffer_chunkLightingData);
 			buffer_chunkLightingData = null;
 		}
+		if(buffer_chunkLightingDataZero != null) {
+			_wglDeleteBuffers(buffer_chunkLightingDataZero);
+			buffer_chunkLightingDataZero = null;
+		}
 		if(buffer_worldLightingData != null) {
 			_wglDeleteBuffers(buffer_worldLightingData);
 			buffer_worldLightingData = null;
@@ -3939,8 +3964,11 @@ public class EaglerDeferredPipeline {
 		}
 		for(int i = 0; i < lightSourceBuckets.length; ++i) {
 			lightSourceBuckets[i].clear();
+			lightSourceBucketSerials[i] = -1;
+			lightSourceRenderPosSerials[i] = -1;
 		}
 		currentLightSourceBucket = null;
+		currentLightSourceBucketId = -1;
 		currentBoundLightSourceBucket = null;
 		isChunkLightingEnabled = false;
 		for(int i = 0; i < shader_gbuffer_debug_view.length; ++i) {
@@ -3993,11 +4021,13 @@ public class EaglerDeferredPipeline {
 	}
 
 	public static final boolean isSupported() {
-		return EaglercraftGPU.checkHasHDRFramebufferSupportWithFilter();
+		return EaglercraftGPU.checkOpenGLESVersion() >= 300 && EaglercraftGPU.checkHasHDRFramebufferSupportWithFilter();
 	}
 
 	public static final String getReasonUnsupported() {
-		if(!EaglercraftGPU.checkHasHDRFramebufferSupportWithFilter()) {
+		if(EaglercraftGPU.checkOpenGLESVersion() < 300) {
+			return I18n.format("shaders.gui.unsupported.reason.oldOpenGLVersion");
+		}else if(!EaglercraftGPU.checkHasHDRFramebufferSupportWithFilter()) {
 			return I18n.format("shaders.gui.unsupported.reason.hdrFramebuffer");
 		}else {
 			return null;
@@ -4015,7 +4045,7 @@ public class EaglerDeferredPipeline {
 		GlStateManager.pushMatrix();
 		GlStateManager.matrixMode(GL_MODELVIEW);
 		GlStateManager.pushMatrix();
-		ScaledResolution scaledresolution = new ScaledResolution(mc);
+		ScaledResolution scaledresolution = mc.scaledResolution;
 		int w = scaledresolution.getScaledWidth();
 		mc.entityRenderer.setupOverlayRendering();
 		GlStateManager.enableAlpha();
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/ext/deferred/ForwardRenderCallbackHandler.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/ext/deferred/ForwardRenderCallbackHandler.java
index 699e7474..7dd380c0 100644
--- a/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/ext/deferred/ForwardRenderCallbackHandler.java
+++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/ext/deferred/ForwardRenderCallbackHandler.java
@@ -22,7 +22,7 @@ import java.util.List;
  */
 public class ForwardRenderCallbackHandler {
 
-	public final List<ShadersRenderPassFuture> renderPassList = new ArrayList(1024);
+	public final List<ShadersRenderPassFuture> renderPassList = new ArrayList<>(1024);
 
 	public void push(ShadersRenderPassFuture f) {
 		renderPassList.add(f);
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/ext/deferred/LensFlareMeshRenderer.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/ext/deferred/LensFlareMeshRenderer.java
index d258636d..a49c1a8d 100644
--- a/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/ext/deferred/LensFlareMeshRenderer.java
+++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/ext/deferred/LensFlareMeshRenderer.java
@@ -8,7 +8,6 @@ import java.io.DataInputStream;
 import java.io.IOException;
 
 import net.lax1dude.eaglercraft.v1_8.EagRuntime;
-import net.lax1dude.eaglercraft.v1_8.EaglerInputStream;
 import net.lax1dude.eaglercraft.v1_8.internal.IBufferArrayGL;
 import net.lax1dude.eaglercraft.v1_8.internal.IBufferGL;
 import net.lax1dude.eaglercraft.v1_8.internal.buffer.ByteBuffer;
@@ -20,6 +19,7 @@ import net.lax1dude.eaglercraft.v1_8.vector.Matrix3f;
 import net.lax1dude.eaglercraft.v1_8.vector.Vector3f;
 import net.minecraft.client.Minecraft;
 import net.minecraft.util.MathHelper;
+import net.minecraft.util.ResourceLocation;
 
 /**
  * Copyright (c) 2023 lax1dude. All Rights Reserved.
@@ -38,8 +38,8 @@ import net.minecraft.util.MathHelper;
  */
 public class LensFlareMeshRenderer {
 
-	public static final String streaksTextureLocation ="assets/eagler/glsl/deferred/lens_streaks.bmp";
-	public static final String ghostsTextureLocation = "assets/eagler/glsl/deferred/lens_ghosts.bmp";
+	public static final ResourceLocation streaksTextureLocation = new ResourceLocation("eagler:glsl/deferred/lens_streaks.bmp");
+	public static final ResourceLocation ghostsTextureLocation = new ResourceLocation("eagler:glsl/deferred/lens_ghosts.bmp");
 	public static final int ghostsSpriteCount = 4;
 
 	static IBufferArrayGL streaksVertexArray = null;
@@ -157,11 +157,8 @@ public class LensFlareMeshRenderer {
 
 		streaksTexture = GlStateManager.generateTexture();
 		GlStateManager.bindTexture(streaksTexture);
-		byte[] flareTex = EagRuntime.getResourceBytes(streaksTextureLocation);
-		if(flareTex == null) {
-			throw new RuntimeException("Could not locate: " + streaksTextureLocation);
-		}
-		try(DataInputStream dis = new DataInputStream(new EaglerInputStream(flareTex))) {
+		try (DataInputStream dis = new DataInputStream(
+				Minecraft.getMinecraft().getResourceManager().getResource(streaksTextureLocation).getInputStream())) {
 			loadFlareTexture(copyBuffer, dis);
 		}catch(IOException ex) {
 			EagRuntime.freeByteBuffer(copyBuffer);
@@ -170,11 +167,8 @@ public class LensFlareMeshRenderer {
 
 		ghostsTexture = GlStateManager.generateTexture();
 		GlStateManager.bindTexture(ghostsTexture);
-		flareTex = EagRuntime.getResourceBytes(ghostsTextureLocation);
-		if(flareTex == null) {
-			throw new RuntimeException("Could not locate: " + ghostsTextureLocation);
-		}
-		try(DataInputStream dis = new DataInputStream(new EaglerInputStream(flareTex))) {
+		try (DataInputStream dis = new DataInputStream(
+				Minecraft.getMinecraft().getResourceManager().getResource(ghostsTextureLocation).getInputStream())) {
 			loadFlareTexture(copyBuffer, dis);
 		}catch(IOException ex) {
 			EagRuntime.freeByteBuffer(copyBuffer);
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/ext/deferred/ShaderPackInfo.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/ext/deferred/ShaderPackInfo.java
index df2e38de..4837b044 100644
--- a/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/ext/deferred/ShaderPackInfo.java
+++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/ext/deferred/ShaderPackInfo.java
@@ -52,7 +52,7 @@ public class ShaderPackInfo {
 		vers = json.optString("vers", "Unknown");
 		author = json.optString("author", "Unknown");
 		apiVers = json.optInt("api_vers", -1);
-		supportedFeatures = new HashSet();
+		supportedFeatures = new HashSet<>();
 		JSONArray features = json.getJSONArray("features");
 		if(features.length() == 0) {
 			throw new JSONException("No supported features list has been defined for this shader pack!");
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/ext/deferred/gui/GuiShaderConfig.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/ext/deferred/gui/GuiShaderConfig.java
index 7b29066b..6451750f 100644
--- a/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/ext/deferred/gui/GuiShaderConfig.java
+++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/ext/deferred/gui/GuiShaderConfig.java
@@ -103,6 +103,11 @@ public class GuiShaderConfig extends GuiScreen {
 		listView.handleMouseInput();
 	}
 
+	public void handleTouchInput() throws IOException {
+		super.handleTouchInput();
+		listView.handleTouchInput();
+	}
+
 	protected void mouseClicked(int parInt1, int parInt2, int parInt3) {
 		super.mouseClicked(parInt1, parInt2, parInt3);
 		listView.mouseClicked(parInt1, parInt2, parInt3);
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/ext/deferred/gui/GuiShaderConfigList.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/ext/deferred/gui/GuiShaderConfigList.java
index 680297d1..9d62b7f0 100644
--- a/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/ext/deferred/gui/GuiShaderConfigList.java
+++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/ext/deferred/gui/GuiShaderConfigList.java
@@ -35,7 +35,7 @@ public class GuiShaderConfigList extends GuiListExtended {
 
 	private final GuiShaderConfig screen;
 
-	private final List<IGuiListEntry> list = new ArrayList();
+	private final List<IGuiListEntry> list = new ArrayList<>();
 
 	private static abstract class ShaderOption {
 
@@ -56,7 +56,7 @@ public class GuiShaderConfigList extends GuiListExtended {
 	}
 
 	private static List<String> loadDescription(String key) {
-		List<String> ret = new ArrayList();
+		List<String> ret = new ArrayList<>();
 		String msg;
 		int i = 0;
 		while(true) {
@@ -112,7 +112,7 @@ public class GuiShaderConfigList extends GuiListExtended {
 		this.list.add(new ListEntrySpacing());
 		this.list.add(new ListEntrySpacing());
 		this.list.add(new ListEntryHeader(I18n.format("shaders.gui.headerTier1")));
-		List<ShaderOption> opts = new ArrayList();
+		List<ShaderOption> opts = new ArrayList<>();
 		EaglerDeferredConfig conf = mcIn.gameSettings.deferredShaderConf;
 		if(conf.shaderPackInfo.WAVING_BLOCKS) {
 			opts.add(new ShaderOption(loadShaderLbl("WAVING_BLOCKS"), loadShaderDesc("WAVING_BLOCKS")) {
@@ -550,6 +550,7 @@ public class GuiShaderConfigList extends GuiListExtended {
 
 		@Override
 		public boolean mousePressed(int var1, int var2, int var3, int var4, int var5, int var6) {
+			if(var4 != 0) return false;
 			if(this.button1 != null) {
 				if(this.button1.yPosition + 15 < bottom && this.button1.yPosition + 5 > top) {
 					if(this.button1.mousePressed(mc, var2, var3)) {
@@ -610,7 +611,7 @@ public class GuiShaderConfigList extends GuiListExtended {
 	}
 
 	private void renderTooltip(int x, int y, int width, List<String> msg) {
-		ArrayList tooltipList = new ArrayList(msg.size() * 2);
+		List<String> tooltipList = new ArrayList<>(msg.size() * 2);
 		for(int i = 0, l = msg.size(); i < l; ++i) {
 			String s = msg.get(i);
 			if(s.length() > 0) {
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/ext/deferred/program/PipelineShaderAccelParticleForward.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/ext/deferred/program/PipelineShaderAccelParticleForward.java
index a9f18bcf..53933529 100644
--- a/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/ext/deferred/program/PipelineShaderAccelParticleForward.java
+++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/ext/deferred/program/PipelineShaderAccelParticleForward.java
@@ -32,7 +32,7 @@ public class PipelineShaderAccelParticleForward extends ShaderProgram<PipelineSh
 				ShaderSource.accel_particle_vsh, "COMPILE_FORWARD_VSH");
 		IShaderGL accelParticleFSH = null;
 		try {
-			List<String> lst = new ArrayList(2);
+			List<String> lst = new ArrayList<>(2);
 			if(dynamicLights) {
 				lst.add("COMPILE_DYNAMIC_LIGHTS");
 			}
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/ext/deferred/program/PipelineShaderGBufferCombine.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/ext/deferred/program/PipelineShaderGBufferCombine.java
index 497b4900..db4925de 100644
--- a/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/ext/deferred/program/PipelineShaderGBufferCombine.java
+++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/ext/deferred/program/PipelineShaderGBufferCombine.java
@@ -30,7 +30,7 @@ public class PipelineShaderGBufferCombine extends ShaderProgram<PipelineShaderGB
 
 	public static PipelineShaderGBufferCombine compile(boolean ssao, boolean env, boolean ssr) throws ShaderException {
 		IShaderGL coreGBuffer = null;
-		List<String> compileFlags = new ArrayList(2);
+		List<String> compileFlags = new ArrayList<>(2);
 		if(ssao) {
 			compileFlags.add("COMPILE_GLOBAL_AMBIENT_OCCLUSION");
 		}
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/ext/deferred/program/PipelineShaderGBufferFog.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/ext/deferred/program/PipelineShaderGBufferFog.java
index a158c5d8..0827606b 100644
--- a/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/ext/deferred/program/PipelineShaderGBufferFog.java
+++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/ext/deferred/program/PipelineShaderGBufferFog.java
@@ -28,7 +28,7 @@ import net.lax1dude.eaglercraft.v1_8.internal.IUniformGL;
 public class PipelineShaderGBufferFog extends ShaderProgram<PipelineShaderGBufferFog.Uniforms> {
 
 	public static PipelineShaderGBufferFog compile(boolean linear, boolean atmosphere, boolean lightShafts) {
-		List<String> macros = new ArrayList(3);
+		List<String> macros = new ArrayList<>(3);
 		if(linear) {
 			macros.add("COMPILE_FOG_LINEAR");
 		}
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/ext/deferred/program/PipelineShaderLightingPoint.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/ext/deferred/program/PipelineShaderLightingPoint.java
index 73f58745..8fc6aa10 100644
--- a/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/ext/deferred/program/PipelineShaderLightingPoint.java
+++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/ext/deferred/program/PipelineShaderLightingPoint.java
@@ -29,7 +29,7 @@ public class PipelineShaderLightingPoint extends ShaderProgram<PipelineShaderLig
 
 	public static PipelineShaderLightingPoint compile(boolean shadows)
 			throws ShaderException {
-		List<String> compileFlags = new ArrayList(2);
+		List<String> compileFlags = new ArrayList<>(2);
 		if(shadows) {
 			compileFlags.add("COMPILE_PARABOLOID_SHADOW");
 		}
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/ext/deferred/program/PipelineShaderLightingSun.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/ext/deferred/program/PipelineShaderLightingSun.java
index 0932c5ac..9e725375 100644
--- a/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/ext/deferred/program/PipelineShaderLightingSun.java
+++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/ext/deferred/program/PipelineShaderLightingSun.java
@@ -29,7 +29,7 @@ public class PipelineShaderLightingSun extends ShaderProgram<PipelineShaderLight
 
 	public static PipelineShaderLightingSun compile(int shadowsSun, boolean coloredShadows) throws ShaderException {
 		IShaderGL sunShader = null;
-		List<String> compileFlags = new ArrayList(1);
+		List<String> compileFlags = new ArrayList<>(1);
 		if(shadowsSun > 0) {
 			compileFlags.add("COMPILE_SUN_SHADOW");
 		}
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/ext/deferred/program/PipelineShaderPostExposureAvg.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/ext/deferred/program/PipelineShaderPostExposureAvg.java
index e4a092c0..6a267c9a 100644
--- a/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/ext/deferred/program/PipelineShaderPostExposureAvg.java
+++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/ext/deferred/program/PipelineShaderPostExposureAvg.java
@@ -28,7 +28,7 @@ import net.lax1dude.eaglercraft.v1_8.internal.IUniformGL;
 public class PipelineShaderPostExposureAvg extends ShaderProgram<PipelineShaderPostExposureAvg.Uniforms> {
 
 	public static PipelineShaderPostExposureAvg compile(boolean luma) throws ShaderException {
-		List<String> compileFlags = new ArrayList(1);
+		List<String> compileFlags = new ArrayList<>(1);
 		if(luma) {
 			compileFlags.add("CALCULATE_LUMINANCE");
 		}
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/ext/deferred/program/PipelineShaderReprojControl.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/ext/deferred/program/PipelineShaderReprojControl.java
index ac9f6c94..36be41ef 100644
--- a/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/ext/deferred/program/PipelineShaderReprojControl.java
+++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/ext/deferred/program/PipelineShaderReprojControl.java
@@ -28,7 +28,7 @@ import net.lax1dude.eaglercraft.v1_8.internal.IUniformGL;
 public class PipelineShaderReprojControl extends ShaderProgram<PipelineShaderReprojControl.Uniforms> {
 
 	public static PipelineShaderReprojControl compile(boolean ssao, boolean ssr) throws ShaderException {
-		List<String> compileFlags = new ArrayList(2);
+		List<String> compileFlags = new ArrayList<>(2);
 		if(ssao) {
 			compileFlags.add("COMPILE_REPROJECT_SSAO");
 		}
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/ext/deferred/program/PipelineShaderShadowsSun.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/ext/deferred/program/PipelineShaderShadowsSun.java
index bd318ab1..2164b71d 100644
--- a/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/ext/deferred/program/PipelineShaderShadowsSun.java
+++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/ext/deferred/program/PipelineShaderShadowsSun.java
@@ -30,7 +30,7 @@ public class PipelineShaderShadowsSun extends ShaderProgram<PipelineShaderShadow
 	public static PipelineShaderShadowsSun compile(int shadowsSun, boolean shadowsSunSmooth, boolean coloredShadows)
 			throws ShaderException {
 		IShaderGL shadowShader = null;
-		List<String> compileFlags = new ArrayList(2);
+		List<String> compileFlags = new ArrayList<>(2);
 		if(shadowsSun == 0) {
 			throw new IllegalStateException("Enable shadows to compile this shader");
 		}
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/ext/deferred/program/PipelineShaderSkyboxRender.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/ext/deferred/program/PipelineShaderSkyboxRender.java
index df798ac8..14e4f458 100644
--- a/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/ext/deferred/program/PipelineShaderSkyboxRender.java
+++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/ext/deferred/program/PipelineShaderSkyboxRender.java
@@ -28,7 +28,7 @@ import java.util.List;
 public class PipelineShaderSkyboxRender extends ShaderProgram<PipelineShaderSkyboxRender.Uniforms> {
 
 	public static PipelineShaderSkyboxRender compile(boolean paraboloid, boolean clouds) throws ShaderException {
-		List<String> compileFlags = new ArrayList();
+		List<String> compileFlags = new ArrayList<>();
 		if(paraboloid) {
 			compileFlags.add("COMPILE_PARABOLOID_SKY");
 		}
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/ext/deferred/program/ShaderCompiler.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/ext/deferred/program/ShaderCompiler.java
index ae431957..83b3f572 100644
--- a/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/ext/deferred/program/ShaderCompiler.java
+++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/ext/deferred/program/ShaderCompiler.java
@@ -10,7 +10,7 @@ import net.lax1dude.eaglercraft.v1_8.internal.IProgramGL;
 import net.lax1dude.eaglercraft.v1_8.internal.IShaderGL;
 import net.lax1dude.eaglercraft.v1_8.log4j.LogManager;
 import net.lax1dude.eaglercraft.v1_8.log4j.Logger;
-import net.lax1dude.eaglercraft.v1_8.opengl.FixedFunctionShader;
+import net.lax1dude.eaglercraft.v1_8.opengl.GLSLHeader;
 import net.minecraft.util.ResourceLocation;
 
 /**
@@ -47,7 +47,7 @@ public class ShaderCompiler {
 	public static IShaderGL compileShader(String name, int stage, String filename, String source, List<String> compileFlags) throws ShaderCompileException {
 		logger.info("Compiling Shader: " + filename);
 		StringBuilder srcCat = new StringBuilder();
-		srcCat.append(FixedFunctionShader.FixedFunctionConstants.VERSION).append('\n');
+		srcCat.append(GLSLHeader.getHeader()).append('\n');
 		
 		if(compileFlags != null && compileFlags.size() > 0) {
 			for(int i = 0, l = compileFlags.size(); i < l; ++i) {
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/ext/deferred/program/ShaderSource.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/ext/deferred/program/ShaderSource.java
index d28f8170..17b21299 100644
--- a/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/ext/deferred/program/ShaderSource.java
+++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/ext/deferred/program/ShaderSource.java
@@ -97,7 +97,7 @@ public class ShaderSource {
 	public static final ResourceLocation accel_particle_dynamiclights_vsh = new ResourceLocation("eagler:glsl/dynamiclights/accel_particle_dynamiclights.vsh");
 	public static final ResourceLocation accel_particle_dynamiclights_fsh = new ResourceLocation("eagler:glsl/dynamiclights/accel_particle_dynamiclights.fsh");
 
-	private static final Map<ResourceLocation, String> sourceCache = new HashMap();
+	private static final Map<ResourceLocation, String> sourceCache = new HashMap<>();
 
 	private static boolean isHighP = false;
 
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/ext/deferred/texture/EaglerTextureAtlasSpritePBR.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/ext/deferred/texture/EaglerTextureAtlasSpritePBR.java
index b095929e..a2074e2d 100644
--- a/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/ext/deferred/texture/EaglerTextureAtlasSpritePBR.java
+++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/ext/deferred/texture/EaglerTextureAtlasSpritePBR.java
@@ -1,7 +1,6 @@
 package net.lax1dude.eaglercraft.v1_8.opengl.ext.deferred.texture;
 
 import java.io.IOException;
-import java.util.ArrayList;
 import java.util.Iterator;
 import java.util.List;
 import java.util.concurrent.Callable;
@@ -121,7 +120,7 @@ public class EaglerTextureAtlasSpritePBR extends EaglerTextureAtlasSprite {
 
 				this.animationMetadata = meta;
 			} else {
-				ArrayList arraylist = Lists.newArrayList();
+				List<AnimationFrame> arraylist = Lists.newArrayList();
 
 				for (int l1 = 0; l1 < j1; ++l1) {
 					this.frameTextureDataPBR[0].add(getFrameTextureData(aint[0], k1, l, l1));
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/ext/deferred/texture/EmissiveItems.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/ext/deferred/texture/EmissiveItems.java
index ef2fdb4b..8e9eb1e6 100644
--- a/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/ext/deferred/texture/EmissiveItems.java
+++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/ext/deferred/texture/EmissiveItems.java
@@ -34,7 +34,7 @@ public class EmissiveItems implements IResourceManagerReloadListener {
 
 	private static final Logger logger = LogManager.getLogger("EmissiveItemsCSV");
 
-	private static final Map<String,float[]> entries = new HashMap();
+	private static final Map<String,float[]> entries = new HashMap<>();
 
 	public static float[] getItemEmission(ItemStack itemStack) {
 		return getItemEmission(itemStack.getItem(), itemStack.getItemDamage());
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/ext/deferred/texture/PBRMaterialConstants.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/ext/deferred/texture/PBRMaterialConstants.java
index 4bd425c8..88fc72e6 100644
--- a/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/ext/deferred/texture/PBRMaterialConstants.java
+++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/ext/deferred/texture/PBRMaterialConstants.java
@@ -34,7 +34,7 @@ public class PBRMaterialConstants implements IResourceManagerReloadListener {
 	public static final Logger logger = LogManager.getLogger("PBRMaterialConstants");
 
 	public final ResourceLocation resourceLocation;
-	public final Map<String,Integer> spriteNameToMaterialConstants = new HashMap();
+	public final Map<String,Integer> spriteNameToMaterialConstants = new HashMap<>();
 
 	public int defaultMaterial = 0x00000A77;
 
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/ext/dynamiclights/DynamicLightBucketLoader.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/ext/dynamiclights/DynamicLightBucketLoader.java
index 8f062140..5a17d1f8 100644
--- a/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/ext/dynamiclights/DynamicLightBucketLoader.java
+++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/ext/dynamiclights/DynamicLightBucketLoader.java
@@ -34,14 +34,19 @@ import net.minecraft.util.MathHelper;
 public class DynamicLightBucketLoader {
 
 	public IBufferGL buffer_chunkLightingData;
+	public IBufferGL buffer_chunkLightingDataZero;
 	private ByteBuffer chunkLightingDataCopyBuffer;
-	private boolean isChunkLightingEnabled = false;
 	public ListSerial<DynamicLightInstance> currentBoundLightSourceBucket;
 
 	public final ListSerial<DynamicLightInstance>[] lightSourceBuckets;
+	private final int[] lightSourceBucketsSerials;
+	private final int[] lightSourceRenderPosSerials;
 	public ListSerial<DynamicLightInstance> currentLightSourceBucket;
+	private int currentLightSourceBucketId = -1;
+	private int lightingBufferSliceLength = -1;
 
 	public static final int MAX_LIGHTS_PER_CHUNK = 12;
+	public static final int LIGHTING_BUFFER_LENGTH = 16 * MAX_LIGHTS_PER_CHUNK + 16;
 
 	private final int lightSourceBucketsWidth;
 	private final int lightSourceBucketsHeight;
@@ -49,29 +54,42 @@ public class DynamicLightBucketLoader {
 	private double currentRenderX = 0.0;
 	private double currentRenderY = 0.0;
 	private double currentRenderZ = 0.0;
+	private int currentRenderPosSerial = 0;
 
 	public DynamicLightBucketLoader() {
 		this.lightSourceBucketsWidth = 5;
 		this.lightSourceBucketsHeight = 3;
 		int cnt = 5 * 3 * 5;
 		this.lightSourceBuckets = new ListSerial[cnt];
+		this.lightSourceBucketsSerials = new int[cnt];
+		this.lightSourceRenderPosSerials = new int[cnt];
 	}
 
 	public void initialize() {
 		destroy();
 		
-		buffer_chunkLightingData = _wglGenBuffers();
-		EaglercraftGPU.bindGLUniformBuffer(buffer_chunkLightingData);
-		int lightingDataLength = 4 * MAX_LIGHTS_PER_CHUNK + 4;
-		chunkLightingDataCopyBuffer = EagRuntime.allocateByteBuffer(lightingDataLength << 2);
-		for(int i = 0; i < lightingDataLength; ++i) {
+		int alignment = EaglercraftGPU.getUniformBufferOffsetAlignment();
+		lightingBufferSliceLength = MathHelper.ceiling_float_int((float)LIGHTING_BUFFER_LENGTH / (float)alignment) * alignment;
+		
+		chunkLightingDataCopyBuffer = EagRuntime.allocateByteBuffer(LIGHTING_BUFFER_LENGTH);
+		for(int i = 0; i < LIGHTING_BUFFER_LENGTH; i += 4) {
 			chunkLightingDataCopyBuffer.putInt(0);
 		}
 		chunkLightingDataCopyBuffer.flip();
-		_wglBufferData(_GL_UNIFORM_BUFFER, chunkLightingDataCopyBuffer, GL_DYNAMIC_DRAW);
+		
+		buffer_chunkLightingData = _wglGenBuffers();
+		EaglercraftGPU.bindGLUniformBuffer(buffer_chunkLightingData);
+		int cnt = lightSourceBucketsWidth * lightSourceBucketsHeight * lightSourceBucketsWidth;
+		_wglBufferData(_GL_UNIFORM_BUFFER, cnt * lightingBufferSliceLength, GL_DYNAMIC_DRAW);
+		
+		buffer_chunkLightingDataZero = _wglGenBuffers();
+		EaglercraftGPU.bindGLUniformBuffer(buffer_chunkLightingDataZero);
+		_wglBufferData(_GL_UNIFORM_BUFFER, chunkLightingDataCopyBuffer, GL_STATIC_DRAW);
 		
 		for(int i = 0; i < this.lightSourceBuckets.length; ++i) {
-			this.lightSourceBuckets[i] = new ArrayListSerial(16);
+			this.lightSourceBuckets[i] = new ArrayListSerial<>(16);
+			this.lightSourceBucketsSerials[i] = -1;
+			this.lightSourceRenderPosSerials[i] = -1;
 		}
 	}
 
@@ -81,7 +99,7 @@ public class DynamicLightBucketLoader {
 		}
 	}
 
-	public void loadLightSourceBucket(int relativeBlockX, int relativeBlockY, int relativeBlockZ) {
+	public void bindLightSourceBucket(int relativeBlockX, int relativeBlockY, int relativeBlockZ, int uboIndex) {
 		int hw = lightSourceBucketsWidth / 2;
 		int hh = lightSourceBucketsHeight / 2;
 		int bucketX = (relativeBlockX >> 4) + hw;
@@ -89,12 +107,47 @@ public class DynamicLightBucketLoader {
 		int bucketZ = (relativeBlockZ >> 4) + hw;
 		if(bucketX >= 0 && bucketY >= 0 && bucketZ >= 0 && bucketX < lightSourceBucketsWidth
 				&& bucketY < lightSourceBucketsHeight && bucketZ < lightSourceBucketsWidth) {
-			currentLightSourceBucket = lightSourceBuckets[bucketY * lightSourceBucketsWidth * lightSourceBucketsWidth
-					+ bucketZ * lightSourceBucketsWidth + bucketX];
+			currentLightSourceBucketId = bucketY * lightSourceBucketsWidth * lightSourceBucketsWidth
+					+ bucketZ * lightSourceBucketsWidth + bucketX;
+			currentLightSourceBucket = lightSourceBuckets[currentLightSourceBucketId];
+			int ser = currentLightSourceBucket.getEaglerSerial();
+			int max = currentLightSourceBucket.size();
+			if(max > 0) {
+				EaglercraftGPU.bindGLUniformBuffer(buffer_chunkLightingData);
+				int offset = currentLightSourceBucketId * lightingBufferSliceLength;
+				if (lightSourceBucketsSerials[currentLightSourceBucketId] != ser
+						|| lightSourceRenderPosSerials[currentLightSourceBucketId] != currentRenderPosSerial) {
+					lightSourceBucketsSerials[currentLightSourceBucketId] = ser;
+					lightSourceRenderPosSerials[currentLightSourceBucketId] = currentRenderPosSerial;
+					if(max > MAX_LIGHTS_PER_CHUNK) {
+						max = MAX_LIGHTS_PER_CHUNK;
+					}
+					chunkLightingDataCopyBuffer.clear();
+					chunkLightingDataCopyBuffer.putInt(max);
+					chunkLightingDataCopyBuffer.putInt(0); //padding
+					chunkLightingDataCopyBuffer.putInt(0); //padding
+					chunkLightingDataCopyBuffer.putInt(0); //padding
+					for(int i = 0; i < max; ++i) {
+						DynamicLightInstance dl = currentLightSourceBucket.get(i);
+						chunkLightingDataCopyBuffer.putFloat((float)(dl.posX - currentRenderX));
+						chunkLightingDataCopyBuffer.putFloat((float)(dl.posY - currentRenderY));
+						chunkLightingDataCopyBuffer.putFloat((float)(dl.posZ - currentRenderZ));
+						chunkLightingDataCopyBuffer.putFloat(dl.radius);
+					}
+					chunkLightingDataCopyBuffer.flip();
+					_wglBufferSubData(_GL_UNIFORM_BUFFER, offset, chunkLightingDataCopyBuffer);
+				}
+				EaglercraftGPU.bindUniformBufferRange(uboIndex, buffer_chunkLightingData, offset, LIGHTING_BUFFER_LENGTH);
+			}else {
+				EaglercraftGPU.bindGLUniformBuffer(buffer_chunkLightingDataZero);
+				EaglercraftGPU.bindUniformBufferRange(uboIndex, buffer_chunkLightingDataZero, 0, LIGHTING_BUFFER_LENGTH);
+			}
 		}else {
+			currentLightSourceBucketId = -1;
 			currentLightSourceBucket = null;
+			EaglercraftGPU.bindGLUniformBuffer(buffer_chunkLightingDataZero);
+			EaglercraftGPU.bindUniformBufferRange(uboIndex, buffer_chunkLightingDataZero, 0, LIGHTING_BUFFER_LENGTH);
 		}
-		updateLightSourceUBO();
 	}
 
 	public ListSerial<DynamicLightInstance> getLightSourceBucketRelativeChunkCoords(int cx, int cy, int cz) {
@@ -188,8 +241,8 @@ public class DynamicLightBucketLoader {
 	}
 
 	public void truncateOverflowingBuffers() {
-		for(int i = 0; i < this.lightSourceBuckets.length; ++i) {
-			List<DynamicLightInstance> lst = this.lightSourceBuckets[i];
+		for(int i = 0; i < lightSourceBuckets.length; ++i) {
+			List<DynamicLightInstance> lst = lightSourceBuckets[i];
 			int k = lst.size();
 			if(k > MAX_LIGHTS_PER_CHUNK) {
 				lst.sort(comparatorLightRadius);
@@ -200,74 +253,18 @@ public class DynamicLightBucketLoader {
 		}
 	}
 
-	public void updateLightSourceUBO() {
-		if(currentLightSourceBucket == null) {
-			currentBoundLightSourceBucket = null;
-			if(isChunkLightingEnabled) {
-				isChunkLightingEnabled = false;
-				EaglercraftGPU.bindGLUniformBuffer(buffer_chunkLightingData);
-				chunkLightingDataCopyBuffer.clear();
-				chunkLightingDataCopyBuffer.putInt(0);
-				chunkLightingDataCopyBuffer.flip();
-				_wglBufferSubData(_GL_UNIFORM_BUFFER, 0, chunkLightingDataCopyBuffer);
-			}
-		}else {
-			boolean isNew;
-			if(!isChunkLightingEnabled) {
-				isChunkLightingEnabled = true;
-				isNew = true;
-			}else {
-				isNew = currentLightSourceBucket != currentBoundLightSourceBucket;
-			}
-			currentBoundLightSourceBucket = currentLightSourceBucket;
-			if(isNew || currentBoundLightSourceBucket.eaglerCheck()) {
-				populateLightSourceUBOFromBucket(currentBoundLightSourceBucket);
-				currentBoundLightSourceBucket.eaglerResetCheck();
-			}
-		}
-	}
-
 	private static final Comparator<DynamicLightInstance> comparatorLightRadius = (l1, l2) -> {
 		return l1.radius < l2.radius ? 1 : -1;
 	};
 
-	private void populateLightSourceUBOFromBucket(List<DynamicLightInstance> lights) {
-		int max = lights.size();
-		if(max > MAX_LIGHTS_PER_CHUNK) {
-			//tmpListLights.clear();
-			//tmpListLights.addAll(lights);
-			//lights = tmpListLights;
-			//lights.sort(comparatorLightRadius);
-			max = MAX_LIGHTS_PER_CHUNK;
-		}
-		chunkLightingDataCopyBuffer.clear();
-		chunkLightingDataCopyBuffer.putInt(max);
-		if(max > 0) {
-			chunkLightingDataCopyBuffer.putInt(0); //padding
-			chunkLightingDataCopyBuffer.putInt(0); //padding
-			chunkLightingDataCopyBuffer.putInt(0); //padding
-			for(int i = 0; i < max; ++i) {
-				DynamicLightInstance dl = lights.get(i);
-				chunkLightingDataCopyBuffer.putFloat((float)(dl.posX - currentRenderX));
-				chunkLightingDataCopyBuffer.putFloat((float)(dl.posY - currentRenderY));
-				chunkLightingDataCopyBuffer.putFloat((float)(dl.posZ - currentRenderZ));
-				chunkLightingDataCopyBuffer.putFloat(dl.radius);
-			}
-		}
-		chunkLightingDataCopyBuffer.flip();
-		EaglercraftGPU.bindGLUniformBuffer(buffer_chunkLightingData);
-		_wglBufferSubData(_GL_UNIFORM_BUFFER, 0, chunkLightingDataCopyBuffer);
-	}
-
 	public void setRenderPos(double currentRenderX, double currentRenderY, double currentRenderZ) {
-		this.currentRenderX = currentRenderX;
-		this.currentRenderY = currentRenderY;
-		this.currentRenderZ = currentRenderZ;
-	}
-
-	public void bindUniformBuffer(int index) {
-		EaglercraftGPU.bindGLUniformBuffer(buffer_chunkLightingData);
-		EaglercraftGPU.bindUniformBufferRange(index, buffer_chunkLightingData, 0, chunkLightingDataCopyBuffer.capacity());
+		if (this.currentRenderX != currentRenderX || this.currentRenderY != currentRenderY
+				|| this.currentRenderZ != currentRenderZ || this.currentRenderPosSerial == 0) {
+			this.currentRenderX = currentRenderX;
+			this.currentRenderY = currentRenderY;
+			this.currentRenderZ = currentRenderZ;
+			++this.currentRenderPosSerial;
+		}
 	}
 
 	public void destroy() {
@@ -279,8 +276,16 @@ public class DynamicLightBucketLoader {
 			_wglDeleteBuffers(buffer_chunkLightingData);
 			buffer_chunkLightingData = null;
 		}
-		for(int i = 0; i < this.lightSourceBuckets.length; ++i) {
-			this.lightSourceBuckets[i] = null;
+		if(buffer_chunkLightingDataZero != null) {
+			_wglDeleteBuffers(buffer_chunkLightingDataZero);
+			buffer_chunkLightingDataZero = null;
 		}
+		for(int i = 0; i < lightSourceBuckets.length; ++i) {
+			lightSourceBuckets[i] = null;
+			lightSourceBucketsSerials[i] = -1;
+			lightSourceRenderPosSerials[i] = -1;
+		}
+		currentLightSourceBucket = null;
+		currentLightSourceBucketId = -1;
 	}
 }
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/ext/dynamiclights/DynamicLightsStateManager.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/ext/dynamiclights/DynamicLightsStateManager.java
index 0495c299..bf47ed13 100644
--- a/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/ext/dynamiclights/DynamicLightsStateManager.java
+++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/opengl/ext/dynamiclights/DynamicLightsStateManager.java
@@ -5,6 +5,8 @@ import java.util.Iterator;
 import java.util.LinkedList;
 import java.util.List;
 
+import net.lax1dude.eaglercraft.v1_8.EagRuntime;
+import net.lax1dude.eaglercraft.v1_8.opengl.EaglercraftGPU;
 import net.lax1dude.eaglercraft.v1_8.opengl.FixedFunctionPipeline;
 import net.lax1dude.eaglercraft.v1_8.opengl.GlStateManager;
 import net.lax1dude.eaglercraft.v1_8.vector.Matrix4f;
@@ -30,10 +32,10 @@ import net.minecraft.util.MathHelper;
 public class DynamicLightsStateManager {
 
 	static final DynamicLightsPipelineCompiler deferredExtPipeline = new DynamicLightsPipelineCompiler();
-	private static List<DynamicLightInstance> lightInstancePool = new ArrayList();
+	private static List<DynamicLightInstance> lightInstancePool = new ArrayList<>();
 	private static int instancePoolIndex = 0;
 	private static int maxListLengthTracker = 0;
-	static final List<DynamicLightInstance> lightRenderList = new LinkedList();
+	static final List<DynamicLightInstance> lightRenderList = new LinkedList<>();
 	static final Matrix4f inverseViewMatrix = new Matrix4f();
 	static int inverseViewMatrixSerial = 0;
 	static DynamicLightBucketLoader bucketLoader = null;
@@ -45,7 +47,7 @@ public class DynamicLightsStateManager {
 		if(bucketLoader == null) {
 			bucketLoader = new DynamicLightBucketLoader();
 			bucketLoader.initialize();
-			bucketLoader.bindUniformBuffer(0);
+			bucketLoader.bindLightSourceBucket(-999, -999, -999, 0);
 			FixedFunctionPipeline.loadExtensionPipeline(deferredExtPipeline);
 		}
 		if(accelParticleRenderer == null) {
@@ -89,7 +91,7 @@ public class DynamicLightsStateManager {
 
 	public static final void reportForwardRenderObjectPosition(int centerX, int centerY, int centerZ) {
 		if(bucketLoader != null) {
-			bucketLoader.loadLightSourceBucket(centerX, centerY, centerZ);
+			bucketLoader.bindLightSourceBucket(centerX, centerY, centerZ, 0);
 		}
 	}
 
@@ -98,7 +100,7 @@ public class DynamicLightsStateManager {
 			float posX = (float)((x + TileEntityRendererDispatcher.staticPlayerX) - (MathHelper.floor_double(TileEntityRendererDispatcher.staticPlayerX / 16.0) << 4));
 			float posY = (float)((y + TileEntityRendererDispatcher.staticPlayerY) - (MathHelper.floor_double(TileEntityRendererDispatcher.staticPlayerY / 16.0) << 4));
 			float posZ = (float)((z + TileEntityRendererDispatcher.staticPlayerZ) - (MathHelper.floor_double(TileEntityRendererDispatcher.staticPlayerZ / 16.0) << 4));
-			bucketLoader.loadLightSourceBucket((int)posX, (int)posY, (int)posZ);
+			bucketLoader.bindLightSourceBucket((int)posX, (int)posY, (int)posZ, 0);
 		}
 	}
 
@@ -152,11 +154,11 @@ public class DynamicLightsStateManager {
 	}
 
 	private static final void updateTimers() {
-		long millis = System.currentTimeMillis();
+		long millis = EagRuntime.steadyTimeMillis();
 		if(millis - lastTick > 5000l) {
 			lastTick = millis;
 			if(maxListLengthTracker < (lightInstancePool.size() >> 1)) {
-				List<DynamicLightInstance> newPool = new ArrayList(Math.max(maxListLengthTracker, 16));
+				List<DynamicLightInstance> newPool = new ArrayList<>(Math.max(maxListLengthTracker, 16));
 				for(int i = 0; i < maxListLengthTracker; ++i) {
 					newPool.add(lightInstancePool.get(i));
 				}
@@ -167,11 +169,15 @@ public class DynamicLightsStateManager {
 	}
 
 	public static final void destroyAll() {
-		lightInstancePool = new ArrayList();
+		lightInstancePool = new ArrayList<>();
 	}
 
 	public static String getF3String() {
 		return "DynamicLightsTotal: " + lastTotal;
 	}
 
+	public static boolean isSupported() {
+		return EaglercraftGPU.checkOpenGLESVersion() >= 300;
+	}
+
 }
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/profanity_filter/GuiScreenContentWarning.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/profanity_filter/GuiScreenContentWarning.java
new file mode 100644
index 00000000..2a339996
--- /dev/null
+++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/profanity_filter/GuiScreenContentWarning.java
@@ -0,0 +1,63 @@
+package net.lax1dude.eaglercraft.v1_8.profanity_filter;
+
+import net.minecraft.client.gui.GuiButton;
+import net.minecraft.client.gui.GuiScreen;
+import net.minecraft.client.resources.I18n;
+import net.minecraft.util.EnumChatFormatting;
+
+/**
+ * Copyright (c) 2024 lax1dude. All Rights Reserved.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ * 
+ */
+public class GuiScreenContentWarning extends GuiScreen {
+
+	private final GuiScreen cont;
+	private boolean enableState;
+	private GuiButton optButton;
+
+	public GuiScreenContentWarning(GuiScreen cont) {
+		this.cont = cont;
+	}
+
+	public void initGui() {
+		this.buttonList.clear();
+		enableState = mc.gameSettings.enableProfanityFilter;
+		this.buttonList.add(optButton = new GuiButton(1, this.width / 2 - 100, this.height / 6 + 108, I18n.format("options.profanityFilterButton") + ": " + I18n.format(enableState ? "gui.yes" : "gui.no")));
+		this.buttonList.add(new GuiButton(0, this.width / 2 - 100, this.height / 6 + 138, I18n.format("gui.done")));
+	}
+
+	@Override
+	protected void actionPerformed(GuiButton parGuiButton) {
+		if(parGuiButton.id == 0) {
+			mc.gameSettings.enableProfanityFilter = enableState;
+			mc.gameSettings.hasShownProfanityFilter = true;
+			mc.gameSettings.saveOptions();
+			mc.displayGuiScreen(cont);
+		}else if(parGuiButton.id == 1) {
+			enableState = !enableState;
+			optButton.displayString = I18n.format("options.profanityFilterButton") + ": " + I18n.format(enableState ? "gui.yes" : "gui.no");
+		}
+	}
+
+	public void drawScreen(int mx, int my, float pt) {
+		this.drawDefaultBackground();
+		this.drawCenteredString(fontRendererObj, EnumChatFormatting.BOLD + I18n.format("profanityFilterWarning.title"), this.width / 2, 50, 0xFF4444);
+		this.drawCenteredString(fontRendererObj, I18n.format("profanityFilterWarning.text0"), this.width / 2, 70, 16777215);
+		this.drawCenteredString(fontRendererObj, I18n.format("profanityFilterWarning.text1"), this.width / 2, 82, 16777215);
+		this.drawCenteredString(fontRendererObj, I18n.format("profanityFilterWarning.text2"), this.width / 2, 94, 16777215);
+		this.drawCenteredString(fontRendererObj, I18n.format("profanityFilterWarning.text4"), this.width / 2, 116, 0xCCCCCC);
+		super.drawScreen(mx, my, pt);
+	}
+
+}
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/profanity_filter/LookAlikeUnicodeConv.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/profanity_filter/LookAlikeUnicodeConv.java
new file mode 100644
index 00000000..5756218b
--- /dev/null
+++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/profanity_filter/LookAlikeUnicodeConv.java
@@ -0,0 +1,1028 @@
+package net.lax1dude.eaglercraft.v1_8.profanity_filter;
+
+/**
+ * Copyright (c) 2024 lax1dude. All Rights Reserved.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ * 
+ */
+public class LookAlikeUnicodeConv {
+
+	public static String convertString(String stringIn) {
+		char[] ret = null;
+		char c1, c2;
+		for(int i = 0, l = stringIn.length(); i < l; ++i) {
+			c1 = stringIn.charAt(i);
+			c2 = convertChar(c1);
+			if(c2 != 0) {
+				if(ret == null) {
+					ret = stringIn.toCharArray();
+				}
+				ret[i] = c2;
+			}
+		}
+		return ret != null ? new String(ret) : stringIn;
+	}
+
+	public static char convertChar(char charIn) {
+		switch (charIn) {
+		case 9313:
+		case 9333:
+		case 65298:
+			return '2';
+		case 9315:
+		case 9335:
+		case 65300:
+			return '4';
+		case 9316:
+		case 9336:
+		case 65301:
+			return '5';
+		case 9317:
+		case 9337:
+		case 65302:
+			return '6';
+		case 9319:
+		case 9339:
+		case 65304:
+			return '8';
+		case 9320:
+		case 9340:
+		case 65305:
+			return '9';
+		case 192:
+		case 193:
+		case 194:
+		case 195:
+		case 196:
+		case 197:
+		case 256:
+		case 258:
+		case 260:
+		case 461:
+		case 478:
+		case 480:
+		case 506:
+		case 512:
+		case 514:
+		case 550:
+		case 570:
+		case 913:
+		case 1040:
+		case 1232:
+		case 1234:
+		case 7680:
+		case 7840:
+		case 7842:
+		case 7844:
+		case 7846:
+		case 7848:
+		case 7850:
+		case 7852:
+		case 7854:
+		case 7856:
+		case 7858:
+		case 7860:
+		case 7862:
+		case 7944:
+		case 7945:
+		case 7946:
+		case 7947:
+		case 7948:
+		case 7949:
+		case 7950:
+		case 7951:
+		case 8072:
+		case 8073:
+		case 8074:
+		case 8075:
+		case 8076:
+		case 8077:
+		case 8078:
+		case 8079:
+		case 8120:
+		case 8121:
+		case 8122:
+		case 8123:
+		case 8124:
+		case 9424:
+		case 65313:
+			return 'A';
+		case 385:
+		case 386:
+		case 579:
+		case 914:
+		case 1042:
+		case 7682:
+		case 7684:
+		case 7686:
+		case 9425:
+		case 65314:
+			return 'B';
+		case 199:
+		case 262:
+		case 264:
+		case 266:
+		case 268:
+		case 391:
+		case 571:
+		case 1057:
+		case 1194:
+		case 7688:
+		case 9426:
+		case 65315:
+			return 'C';
+		case 270:
+		case 272:
+		case 393:
+		case 394:
+		case 7690:
+		case 7692:
+		case 7694:
+		case 7696:
+		case 7698:
+		case 9427:
+		case 65316:
+			return 'D';
+		case 200:
+		case 201:
+		case 202:
+		case 203:
+		case 274:
+		case 276:
+		case 278:
+		case 280:
+		case 282:
+		case 516:
+		case 518:
+		case 552:
+		case 582:
+		case 904:
+		case 917:
+		case 7700:
+		case 7702:
+		case 7704:
+		case 7706:
+		case 7708:
+		case 7864:
+		case 7866:
+		case 7868:
+		case 7870:
+		case 7872:
+		case 7874:
+		case 7876:
+		case 7878:
+		case 7960:
+		case 7961:
+		case 7962:
+		case 7963:
+		case 7964:
+		case 7965:
+		case 8136:
+		case 8137:
+		case 9428:
+		case 65317:
+			return 'E';
+		case 401:
+		case 7710:
+		case 9429:
+		case 65318:
+			return 'F';
+		case 284:
+		case 286:
+		case 288:
+		case 290:
+		case 403:
+		case 484:
+		case 486:
+		case 500:
+		case 7712:
+		case 9430:
+		case 65319:
+			return 'G';
+		case 292:
+		case 294:
+		case 542:
+		case 7714:
+		case 7716:
+		case 7718:
+		case 7720:
+		case 7722:
+		case 7976:
+		case 7977:
+		case 7978:
+		case 7979:
+		case 7980:
+		case 7981:
+		case 7982:
+		case 7983:
+		case 9431:
+		case 65320:
+			return 'H';
+		case 204:
+		case 205:
+		case 206:
+		case 207:
+		case 296:
+		case 298:
+		case 300:
+		case 302:
+		case 304:
+		case 406:
+		case 407:
+		case 463:
+		case 520:
+		case 522:
+		case 906:
+		case 921:
+		case 938:
+		case 1030:
+		case 7724:
+		case 7726:
+		case 7880:
+		case 7882:
+		case 7992:
+		case 7993:
+		case 7994:
+		case 7995:
+		case 7996:
+		case 7997:
+		case 7998:
+		case 7999:
+		case 9432:
+		case 65321:
+			return 'I';
+		case 308:
+		case 584:
+		case 1032:
+		case 9433:
+		case 65322:
+			return 'J';
+		case 310:
+		case 408:
+		case 488:
+		case 922:
+		case 1036:
+		case 1050:
+		case 1178:
+		case 1180:
+		case 1182:
+		case 7728:
+		case 7730:
+		case 7732:
+		case 9434:
+		case 65323:
+			return 'K';
+		case 313:
+		case 315:
+		case 317:
+		case 319:
+		case 321:
+		case 573:
+		case 7734:
+		case 7736:
+		case 7738:
+		case 7740:
+		case 9435:
+		case 65324:
+			return 'L';
+		case 924:
+		case 7742:
+		case 7744:
+		case 7746:
+		case 9436:
+		case 65325:
+			return 'M';
+		case 209:
+		case 323:
+		case 325:
+		case 327:
+		case 413:
+		case 504:
+		case 544:
+		case 925:
+		case 7748:
+		case 7750:
+		case 7752:
+		case 7754:
+		case 9437:
+		case 65326:
+			return 'N';
+		case 48:
+		case 210:
+		case 211:
+		case 212:
+		case 213:
+		case 214:
+		case 332:
+		case 334:
+		case 336:
+		case 416:
+		case 465:
+		case 490:
+		case 492:
+		case 510:
+		case 524:
+		case 526:
+		case 554:
+		case 556:
+		case 558:
+		case 560:
+		case 908:
+		case 927:
+		case 1054:
+		case 1254:
+		case 7756:
+		case 7758:
+		case 7760:
+		case 7762:
+		case 7884:
+		case 7886:
+		case 7888:
+		case 7890:
+		case 7892:
+		case 7894:
+		case 7896:
+		case 7898:
+		case 7900:
+		case 7902:
+		case 7904:
+		case 7906:
+		case 8008:
+		case 8009:
+		case 8010:
+		case 8011:
+		case 8012:
+		case 8013:
+		case 8184:
+		case 8185:
+		case 9438:
+		case 65296:
+		case 65327:
+			return 'O';
+		case 420:
+		case 929:
+		case 7764:
+		case 7766:
+		case 8172:
+		case 9439:
+		case 65328:
+			return 'P';
+		case 9440:
+		case 65329:
+			return 'Q';
+		case 340:
+		case 342:
+		case 344:
+		case 528:
+		case 530:
+		case 588:
+		case 7768:
+		case 7770:
+		case 7772:
+		case 7774:
+		case 9441:
+		case 65330:
+			return 'R';
+		case 36:
+		case 346:
+		case 348:
+		case 350:
+		case 352:
+		case 536:
+		case 1029:
+		case 7776:
+		case 7778:
+		case 7780:
+		case 7782:
+		case 7784:
+		case 9442:
+		case 65331:
+			return 'S';
+		case 354:
+		case 356:
+		case 358:
+		case 428:
+		case 430:
+		case 538:
+		case 574:
+		case 932:
+		case 7786:
+		case 7788:
+		case 7790:
+		case 7792:
+		case 9443:
+		case 65332:
+			return 'T';
+		case 217:
+		case 218:
+		case 219:
+		case 220:
+		case 360:
+		case 362:
+		case 364:
+		case 366:
+		case 368:
+		case 370:
+		case 431:
+		case 467:
+		case 469:
+		case 471:
+		case 473:
+		case 475:
+		case 532:
+		case 534:
+		case 580:
+		case 1329:
+		case 1357:
+		case 7794:
+		case 7796:
+		case 7798:
+		case 7800:
+		case 7802:
+		case 7908:
+		case 7910:
+		case 7912:
+		case 7914:
+		case 7916:
+		case 7918:
+		case 7920:
+		case 9444:
+		case 65333:
+			return 'U';
+		case 1140:
+		case 1142:
+		case 7804:
+		case 7806:
+		case 9445:
+		case 65334:
+			return 'V';
+		case 372:
+		case 7808:
+		case 7810:
+		case 7812:
+		case 7814:
+		case 7816:
+		case 9446:
+		case 65335:
+			return 'W';
+		case 935:
+		case 1061:
+		case 1202:
+		case 1276:
+		case 1278:
+		case 7818:
+		case 7820:
+		case 9447:
+		case 65336:
+			return 'X';
+		case 221:
+		case 374:
+		case 376:
+		case 435:
+		case 562:
+		case 590:
+		case 933:
+		case 939:
+		case 7822:
+		case 7922:
+		case 7924:
+		case 7926:
+		case 7928:
+		case 8025:
+		case 8027:
+		case 8029:
+		case 8031:
+		case 8168:
+		case 8169:
+		case 8170:
+		case 8171:
+		case 9448:
+		case 65337:
+			return 'Y';
+		case 377:
+		case 379:
+		case 381:
+		case 437:
+		case 548:
+		case 918:
+		case 7824:
+		case 7826:
+		case 7828:
+		case 9449:
+		case 65338:
+			return 'Z';
+		case 64:
+		case 224:
+		case 225:
+		case 226:
+		case 227:
+		case 228:
+		case 229:
+		case 257:
+		case 259:
+		case 261:
+		case 462:
+		case 479:
+		case 481:
+		case 507:
+		case 513:
+		case 515:
+		case 551:
+		case 940:
+		case 945:
+		case 1072:
+		case 1233:
+		case 1235:
+		case 7681:
+		case 7834:
+		case 7841:
+		case 7843:
+		case 7845:
+		case 7847:
+		case 7849:
+		case 7851:
+		case 7853:
+		case 7855:
+		case 7857:
+		case 7859:
+		case 7861:
+		case 7863:
+		case 7936:
+		case 7937:
+		case 7938:
+		case 7939:
+		case 7940:
+		case 7941:
+		case 7942:
+		case 7943:
+		case 8048:
+		case 8049:
+		case 8064:
+		case 8065:
+		case 8066:
+		case 8067:
+		case 8068:
+		case 8069:
+		case 8070:
+		case 8071:
+		case 8112:
+		case 8113:
+		case 8114:
+		case 8115:
+		case 8116:
+		case 8118:
+		case 8119:
+		case 9372:
+		case 9398:
+		case 65345:
+			return 'a';
+		case 384:
+		case 387:
+		case 388:
+		case 389:
+		case 595:
+		case 946:
+		case 7683:
+		case 7685:
+		case 7687:
+		case 9373:
+		case 9399:
+		case 65346:
+			return 'b';
+		case 231:
+		case 263:
+		case 265:
+		case 267:
+		case 269:
+		case 392:
+		case 572:
+		case 1089:
+		case 7689:
+		case 9374:
+		case 9400:
+		case 65347:
+			return 'c';
+		case 271:
+		case 273:
+		case 396:
+		case 598:
+		case 599:
+		case 7691:
+		case 7693:
+		case 7695:
+		case 7697:
+		case 7699:
+		case 9375:
+		case 9401:
+		case 65348:
+			return 'd';
+		case 51:
+		case 232:
+		case 233:
+		case 234:
+		case 235:
+		case 275:
+		case 277:
+		case 279:
+		case 281:
+		case 283:
+		case 517:
+		case 519:
+		case 553:
+		case 583:
+		case 1239:
+		case 7701:
+		case 7703:
+		case 7705:
+		case 7707:
+		case 7709:
+		case 7865:
+		case 7867:
+		case 7869:
+		case 7871:
+		case 7873:
+		case 7875:
+		case 7877:
+		case 7879:
+		case 9314:
+		case 9334:
+		case 9376:
+		case 9402:
+		case 65299:
+		case 65349:
+			return 'e';
+		case 402:
+		case 7711:
+		case 9377:
+		case 9403:
+		case 65350:
+			return 'f';
+		case 285:
+		case 287:
+		case 289:
+		case 291:
+		case 485:
+		case 487:
+		case 7713:
+		case 9378:
+		case 9404:
+		case 65351:
+			return 'g';
+		case 293:
+		case 295:
+		case 543:
+		case 614:
+		case 7715:
+		case 7717:
+		case 7719:
+		case 7721:
+		case 7723:
+		case 7830:
+		case 9379:
+		case 9405:
+		case 65352:
+			return 'h';
+		case 33:
+		case 49:
+		case 236:
+		case 237:
+		case 238:
+		case 239:
+		case 297:
+		case 299:
+		case 301:
+		case 303:
+		case 464:
+		case 521:
+		case 523:
+		case 616:
+		case 617:
+		case 943:
+		case 953:
+		case 970:
+		case 1110:
+		case 7725:
+		case 7727:
+		case 7881:
+		case 7883:
+		case 9312:
+		case 9332:
+		case 9380:
+		case 9406:
+		case 65297:
+		case 65353:
+			return 'i';
+		case 309:
+		case 496:
+		case 585:
+		case 669:
+		case 1112:
+		case 9381:
+		case 9407:
+		case 65354:
+			return 'j';
+		case 311:
+		case 312:
+		case 409:
+		case 489:
+		case 954:
+		case 1116:
+		case 1179:
+		case 1181:
+		case 1183:
+		case 7729:
+		case 7731:
+		case 7733:
+		case 9382:
+		case 9408:
+		case 65355:
+			return 'k';
+		case 314:
+		case 316:
+		case 318:
+		case 320:
+		case 322:
+		case 410:
+		case 619:
+		case 620:
+		case 621:
+		case 7735:
+		case 7737:
+		case 7739:
+		case 7741:
+		case 9383:
+		case 9409:
+		case 65356:
+			return 'l';
+		case 625:
+		case 7743:
+		case 7745:
+		case 7747:
+		case 9384:
+		case 9410:
+		case 65357:
+			return 'm';
+		case 241:
+		case 324:
+		case 326:
+		case 328:
+		case 329:
+		case 414:
+		case 505:
+		case 565:
+		case 626:
+		case 627:
+		case 7749:
+		case 7751:
+		case 7753:
+		case 7755:
+		case 9385:
+		case 9411:
+		case 65358:
+			return 'n';
+		case 242:
+		case 243:
+		case 244:
+		case 245:
+		case 246:
+		case 248:
+		case 333:
+		case 335:
+		case 337:
+		case 417:
+		case 466:
+		case 491:
+		case 493:
+		case 511:
+		case 525:
+		case 527:
+		case 555:
+		case 557:
+		case 559:
+		case 561:
+		case 959:
+		case 972:
+		case 1086:
+		case 1255:
+		case 7757:
+		case 7759:
+		case 7761:
+		case 7763:
+		case 7885:
+		case 7887:
+		case 7889:
+		case 7891:
+		case 7893:
+		case 7895:
+		case 7897:
+		case 7899:
+		case 7901:
+		case 7903:
+		case 7905:
+		case 7907:
+		case 8000:
+		case 8001:
+		case 8002:
+		case 8003:
+		case 8004:
+		case 8005:
+		case 9386:
+		case 9412:
+		case 65359:
+			return 'o';
+		case 421:
+		case 961:
+		case 7765:
+		case 7767:
+		case 9387:
+		case 9413:
+		case 65360:
+			return 'p';
+		case 587:
+		case 672:
+		case 9388:
+		case 9414:
+		case 65361:
+			return 'q';
+		case 341:
+		case 343:
+		case 345:
+		case 529:
+		case 531:
+		case 589:
+		case 7769:
+		case 7771:
+		case 7773:
+		case 7775:
+		case 9389:
+		case 9415:
+		case 65362:
+			return 'r';
+		case 347:
+		case 349:
+		case 351:
+		case 353:
+		case 537:
+		case 575:
+		case 1109:
+		case 7777:
+		case 7779:
+		case 7781:
+		case 7783:
+		case 7785:
+		case 9390:
+		case 9416:
+		case 65363:
+			return 's';
+		case 55:
+		case 355:
+		case 357:
+		case 359:
+		case 427:
+		case 429:
+		case 539:
+		case 566:
+		case 964:
+		case 1090:
+		case 1197:
+		case 7787:
+		case 7789:
+		case 7791:
+		case 7793:
+		case 7831:
+		case 9318:
+		case 9338:
+		case 9391:
+		case 9417:
+		case 65303:
+		case 65364:
+			return 't';
+		case 249:
+		case 250:
+		case 251:
+		case 252:
+		case 361:
+		case 363:
+		case 365:
+		case 367:
+		case 369:
+		case 371:
+		case 432:
+		case 468:
+		case 470:
+		case 472:
+		case 474:
+		case 476:
+		case 533:
+		case 535:
+		case 649:
+		case 965:
+		case 973:
+		case 7795:
+		case 7797:
+		case 7799:
+		case 7801:
+		case 7803:
+		case 7909:
+		case 7911:
+		case 7913:
+		case 7915:
+		case 7917:
+		case 7919:
+		case 7921:
+		case 8016:
+		case 8017:
+		case 8018:
+		case 8019:
+		case 8020:
+		case 8021:
+		case 8022:
+		case 8023:
+		case 8160:
+		case 8161:
+		case 8162:
+		case 8163:
+		case 9392:
+		case 9418:
+		case 65365:
+			return 'u';
+		case 1141:
+		case 1143:
+		case 7805:
+		case 7807:
+		case 9393:
+		case 9419:
+		case 65366:
+			return 'v';
+		case 373:
+		case 7809:
+		case 7811:
+		case 7813:
+		case 7815:
+		case 7817:
+		case 7832:
+		case 9394:
+		case 9420:
+		case 65367:
+			return 'w';
+		case 215:
+		case 967:
+		case 1093:
+		case 1203:
+		case 1277:
+		case 1279:
+		case 7819:
+		case 7821:
+		case 9395:
+		case 9421:
+		case 65368:
+			return 'x';
+		case 253:
+		case 255:
+		case 375:
+		case 436:
+		case 563:
+		case 591:
+		case 947:
+		case 1118:
+		case 7823:
+		case 7833:
+		case 7923:
+		case 7925:
+		case 7927:
+		case 7929:
+		case 7935:
+		case 9396:
+		case 9422:
+		case 65369:
+			return 'y';
+		case 378:
+		case 380:
+		case 382:
+		case 438:
+		case 549:
+		case 576:
+		case 656:
+		case 657:
+		case 7825:
+		case 7827:
+		case 7829:
+		case 9397:
+		case 9423:
+		case 65370:
+			return 'z';
+		}
+		return 0;
+	}
+
+}
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/profanity_filter/ProfanityFilter.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/profanity_filter/ProfanityFilter.java
new file mode 100644
index 00000000..94e35832
--- /dev/null
+++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/profanity_filter/ProfanityFilter.java
@@ -0,0 +1,534 @@
+package net.lax1dude.eaglercraft.v1_8.profanity_filter;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import org.apache.commons.lang3.StringUtils;
+
+import net.lax1dude.eaglercraft.v1_8.EagRuntime;
+import net.lax1dude.eaglercraft.v1_8.log4j.LogManager;
+import net.lax1dude.eaglercraft.v1_8.log4j.Logger;
+import net.minecraft.event.HoverEvent;
+import net.minecraft.util.ChatComponentScore;
+import net.minecraft.util.ChatComponentSelector;
+import net.minecraft.util.ChatComponentStyle;
+import net.minecraft.util.ChatComponentText;
+import net.minecraft.util.ChatComponentTranslation;
+import net.minecraft.util.ChatStyle;
+import net.minecraft.util.IChatComponent;
+import net.minecraft.util.MathHelper;
+
+/**
+ * Copyright (c) 2024 lax1dude. All Rights Reserved.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ * 
+ */
+public class ProfanityFilter {
+
+	private static final Logger logger = LogManager.getLogger("ProfanityFilter");
+
+	protected final Set<String>[] bannedWords;
+
+	private static ProfanityFilter instance = null;
+
+	public static ProfanityFilter getInstance() {
+		if(instance == null) {
+			instance = new ProfanityFilter();
+		}
+		return instance;
+	}
+
+	private ProfanityFilter() {
+		logger.info("Loading profanity filter hash set...");
+		List<String> strs = EagRuntime.getResourceLines("profanity_filter.wlist");
+		if(strs == null) {
+			throw new RuntimeException("File is missing: profanity_filter.wlist");
+		}
+		long start = EagRuntime.steadyTimeMillis();
+		Set<String>[] sets = new Set[0];
+		int j = 0;
+		for(String str : strs) {
+			if(nextDelimiter(str, 0) != -1) continue;
+			str = LookAlikeUnicodeConv.convertString(str);
+			int l = str.length();
+			if(l == 0) continue;
+			if(sets.length < l) {
+				Set<String>[] setsNew = new Set[l];
+				System.arraycopy(sets, 0, setsNew, 0, sets.length);
+				sets = setsNew;
+			}
+			--l;
+			if(sets[l] == null) {
+				sets[l] = new HashSet();
+			}
+			if(sets[l].add(str)) {
+				++j;
+			}
+		}
+		bannedWords = sets;
+		logger.info("Processed {} entries after {}ms", j, (EagRuntime.steadyTimeMillis() - start));
+	}
+
+	public IChatComponent profanityFilterChatComponent(IChatComponent componentIn) {
+		if(componentIn == null) return null;
+		IChatComponent cmp = null;
+		//long start = System.nanoTime();
+		try {
+			cmp = profanityFilterChatComponent0(componentIn);
+		}catch(Throwable t) {
+			logger.error("Profanity filter raised an exception on chat component!");
+			logger.error(t);
+		}
+		//logger.info("Took: {}", ((System.nanoTime() - start) / 1000000.0));
+		return cmp != null ? cmp : componentIn;
+	}
+
+	protected IChatComponent profanityFilterChatComponent0(IChatComponent componentIn) {
+		if(componentIn instanceof ChatComponentStyle) {
+			boolean flag = false;
+			if(componentIn instanceof ChatComponentText) {
+				ChatComponentText comp = (ChatComponentText)componentIn;
+				String str = comp.getChatComponentText_TextValue();
+				if(StringUtils.isEmpty(str) && componentIn.getSiblings().isEmpty()) {
+					return componentIn;
+				}
+				str = profanityFilterString0(str);
+				if(str != null) {
+					IChatComponent replacedComponent = new ChatComponentText(str);
+					replacedComponent.setChatStyle(comp.getChatStyleIfPresent());
+					replacedComponent.getSiblings().addAll(componentIn.getSiblings());
+					componentIn = replacedComponent;
+					flag = true;
+				}
+			}else if(componentIn instanceof ChatComponentTranslation) {
+				ChatComponentTranslation comp = (ChatComponentTranslation)componentIn;
+				IChatComponent replacedComponent = new ChatComponentTranslation(comp.getKey(), profanityFilterFormatArgs(comp.getFormatArgs()));
+				replacedComponent.setChatStyle(comp.getChatStyleIfPresent());
+				replacedComponent.getSiblings().addAll(componentIn.getSiblings());
+				componentIn = replacedComponent;
+				flag = true;
+			}
+			List<IChatComponent> siblings = componentIn.getSiblings();
+			for(int i = 0, l = siblings.size(); i < l; ++i) {
+				IChatComponent cmp = profanityFilterChatComponent0(siblings.get(i));
+				if(cmp != null) {
+					if(!flag) {
+						componentIn = shallowCopy(componentIn);
+						siblings = componentIn.getSiblings();
+						flag = true;
+					}
+					siblings.set(i, cmp);
+				}
+			}
+			ChatStyle styleOpt = ((ChatComponentStyle)componentIn).getChatStyleIfPresent();
+			if(styleOpt != null) {
+				HoverEvent hoverEvent = styleOpt.getChatHoverEvent();
+				if(hoverEvent != null) {
+					HoverEvent filteredHoverEvent = profanityFilterHoverEvent(hoverEvent);
+					if(filteredHoverEvent != null) {
+						if(!flag) {
+							componentIn = shallowCopy(componentIn);
+							flag = true;
+						}
+						ChatStyle newStyle = styleOpt.createShallowCopy();
+						newStyle.setChatHoverEvent(filteredHoverEvent);
+						componentIn.setChatStyle(newStyle);
+					}
+				}
+			}
+			return flag ? componentIn : null;
+		}else {
+			return null;
+		}
+	}
+
+	private Object[] profanityFilterFormatArgs(Object[] formatArgs) {
+		Object[] ret = profanityFilterFormatArgs0(formatArgs);
+		return ret != null ? ret : formatArgs;
+	}
+
+	private Object[] profanityFilterFormatArgs0(Object[] formatArgs) {
+		Object[] ret = null;
+		for(int i = 0; i < formatArgs.length; ++i) {
+			if(formatArgs[i] != null) {
+				String arg = formatArgs[i].toString();
+				arg = profanityFilterString0(arg);
+				if(arg != null) {
+					if(ret == null) {
+						ret = new Object[formatArgs.length];
+						System.arraycopy(formatArgs, 0, ret, 0, ret.length);
+					}
+					ret[i] = arg;
+				}
+			}
+			
+		}
+		return ret;
+	}
+
+	protected HoverEvent profanityFilterHoverEvent(HoverEvent evtIn) {
+		if(evtIn.getAction() == HoverEvent.Action.SHOW_TEXT) {
+			IChatComponent filtered = evtIn.getValue();
+			if(filtered != null) {
+				filtered = profanityFilterChatComponent0(filtered);
+				if(filtered != null) {
+					return new HoverEvent(evtIn.getAction(), filtered);
+				}
+			}
+		}
+		return null;
+	}
+
+	private static IChatComponent shallowCopy(IChatComponent comp) {
+		if(comp instanceof ChatComponentStyle) {
+			if(comp instanceof ChatComponentText) {
+				ChatComponentText old = (ChatComponentText)comp;
+				IChatComponent ret = new ChatComponentText(old.getChatComponentText_TextValue());
+				ret.setChatStyle(old.getChatStyleIfPresent());
+				ret.getSiblings().addAll(comp.getSiblings());
+				return ret;
+			}else if(comp instanceof ChatComponentTranslation) {
+				ChatComponentTranslation old = (ChatComponentTranslation)comp;
+				IChatComponent ret = new ChatComponentTranslation(old.getKey(), old.getFormatArgs());
+				ret.setChatStyle(old.getChatStyleIfPresent());
+				ret.getSiblings().addAll(comp.getSiblings());
+				return ret;
+			}else if(comp instanceof ChatComponentScore) {
+				ChatComponentScore old = (ChatComponentScore)comp;
+				IChatComponent ret = new ChatComponentScore(old.getName(), old.getObjective());
+				ret.setChatStyle(old.getChatStyleIfPresent());
+				ret.getSiblings().addAll(comp.getSiblings());
+				return ret;
+			}else if(comp instanceof ChatComponentSelector) {
+				ChatComponentSelector old = (ChatComponentSelector)comp;
+				IChatComponent ret = new ChatComponentSelector(old.getSelector());
+				ret.setChatStyle(old.getChatStyleIfPresent());
+				ret.getSiblings().addAll(comp.getSiblings());
+				return ret;
+			}
+		}
+		return comp.createCopy();
+	}
+
+	private static final char[] stars = new char[] { '*', '*', '*', '*', '*', '*', '*', '*', '*', '*', '*', '*', '*',
+			'*', '*', '*', '*', '*', '*', '*', '*', '*', '*', '*', '*', '*', '*', '*', '*', '*', '*', '*', '*', '*',
+			'*', '*', '*', '*', '*', '*', '*', '*', '*', '*', '*', '*', '*', '*', '*', '*', '*', '*', '*', '*', '*',
+			'*', '*', '*', '*', '*', '*', '*', '*', '*', '*', '*', '*', '*' };
+
+	public String profanityFilterString(String stringIn) {
+		if(stringIn == null) return null;
+		String str = null;
+		//long start = System.nanoTime();
+		try {
+			str = profanityFilterString0(stringIn);
+		}catch(Throwable t) {
+			logger.error("Profanity filter raised an exception on string!");
+			logger.error(t);
+		}
+		//logger.info("Took: {}", ((System.nanoTime() - start) / 1000000.0));
+		return str != null ? str : stringIn;
+	}
+
+	protected String profanityFilterString0(String stringIn) {
+		if(StringUtils.isAllBlank(stringIn)) {
+			return null;
+		}
+		int inLen = stringIn.length();
+		boolean flag = false;
+		int i = 0, j;
+		int k = -1;
+		StringBuilder b = null;
+		String str;
+		List<int[]> rangeList = new ArrayList(4);
+		int minCoverage = 40;
+		int pieceLen;
+		while((j = nextDelimiter(stringIn, i)) != -1) {
+			if(j - i > 2) {
+				if(b != null) {
+					str = LookAlikeUnicodeConv.convertString(stripColorCodes(b.toString())).toLowerCase();
+					pieceLen = str.length();
+					b = null;
+					//System.out.println("\"" + str + "\"");
+					rangeList.clear();
+					if(isBanned(str, rangeList) && evaluateCoverage(pieceLen, rangeList) > (pieceLen * minCoverage / 100)) {
+						flag = true;
+						for(int m = 0, n = rangeList.size(); m < n; ++m) {
+							stringIn = doStar(stringIn, k, i - 1, rangeList.get(m));
+						}
+					}
+					k = -1;
+				}
+				str = LookAlikeUnicodeConv.convertString(stripColorCodes(stringIn.substring(i, j))).toLowerCase();
+				pieceLen = str.length();
+				//System.out.println("\"" + str + "\"");
+				rangeList.clear();
+				if(isBanned(str, rangeList) && evaluateCoverage(pieceLen, rangeList) > (pieceLen * minCoverage / 100)) {
+					flag = true;
+					for(int m = 0, n = rangeList.size(); m < n; ++m) {
+						stringIn = doStar(stringIn, i, j, rangeList.get(m));
+					}
+				}
+			}else if(j - i > 0) {
+				if(b == null) {
+					k = i;
+					b = new StringBuilder(stringIn.substring(i, j));
+				}else {
+					b.append(stringIn.substring(i, j));
+				}
+			}
+			i = j + 1;
+		}
+		j = inLen;
+		if(j - i > 2) {
+			if(b != null) {
+				str = LookAlikeUnicodeConv.convertString(stripColorCodes(b.toString())).toLowerCase();
+				pieceLen = str.length();
+				b = null;
+				//System.out.println("\"" + str + "\"");
+				rangeList.clear();
+				if(isBanned(str, rangeList) && evaluateCoverage(pieceLen, rangeList) > (pieceLen * minCoverage / 100)) {
+					flag = true;
+					for(int m = 0, n = rangeList.size(); m < n; ++m) {
+						stringIn = doStar(stringIn, k, i - 1, rangeList.get(m));
+					}
+				}
+				k = -1;
+			}
+			str = LookAlikeUnicodeConv.convertString(stripColorCodes(stringIn.substring(i, j))).toLowerCase();
+			pieceLen = str.length();
+			//System.out.println("\"" + str + "\"");
+			rangeList.clear();
+			if(isBanned(str, rangeList) && evaluateCoverage(pieceLen, rangeList) > (pieceLen * minCoverage / 100)) {
+				flag = true;
+				for(int m = 0, n = rangeList.size(); m < n; ++m) {
+					stringIn = doStar(stringIn, i, j, rangeList.get(m));
+				}
+			}
+		}else if(j - i > 0) {
+			if(b == null) {
+				k = i;
+				b = new StringBuilder(stringIn.substring(i, j));
+			}else {
+				b.append(stringIn.substring(i, j));
+			}
+		}
+		if(b != null) {
+			str = LookAlikeUnicodeConv.convertString(stripColorCodes(b.toString())).toLowerCase();
+			pieceLen = str.length();
+			b = null;
+			//System.out.println("\"" + str + "\"");
+			rangeList.clear();
+			if(isBanned(str, rangeList) && evaluateCoverage(pieceLen, rangeList) > (pieceLen * minCoverage / 100)) {
+				flag = true;
+				for(int m = 0, n = rangeList.size(); m < n; ++m) {
+					stringIn = doStar(stringIn, k, stringIn.length(), rangeList.get(m));
+				}
+			}
+		}
+		return flag ? stringIn : null;
+	}
+
+	protected String doStar(String stringIn, int start, int end, int[] rangeReturn) {
+		int strlen = stringIn.length();
+		start += rangeReturn[0];
+		end -= rangeReturn[1];
+		int len = end - start;
+		if(len <= 0 || start < 0 || end > strlen) {
+			logger.warn("Profanity filter attempted out of bounds substring @ strlen: {}, start: {}, end: {}, len: {}", strlen, start, end, len);
+			return stringIn;
+		}
+		StringBuilder fixed = new StringBuilder(stringIn.substring(0, start));
+		fixed.append(stars, 0, MathHelper.clamp_int(len, 1, stars.length));
+		fixed.append(stringIn, end, stringIn.length());
+		return fixed.toString();
+	}
+
+	protected static final int[] zeroZero = new int[2];
+
+	protected boolean isBanned(String word, List<int[]> rangeReturn) {
+		int l = word.length();
+		if(l == 0) return false;
+		int i = bannedWords.length;
+		int k;
+		boolean flag = false;
+		for(int j = Math.min(l, i); j >= 3; --j) {
+			if(j == l) {
+				Set<String> set = bannedWords[j - 1];
+				//System.out.println(" - \"" + word + "\"");
+				if(set != null && set.contains(word)) {
+					rangeReturn.add(zeroZero);
+					return true;
+				}
+			}else {
+				Set<String> set = bannedWords[j - 1];
+				if(set != null) {
+					int m = l - j;
+					for(int n = 0; n <= m; ++n) {
+						if(overlaps(n, n + j, l, rangeReturn)) {
+							//System.out.println("Skipping overlap: " + n + " -> " + (n + j));
+							continue;
+						}
+						String ss = word.substring(n, n + j);
+						//System.out.println(" - \"" + ss + "\"");
+						if(set.contains(ss)) {
+							rangeReturn.add(new int[] { n, m - n });
+							flag = true;
+						}
+					}
+				}
+			}
+		}
+		return flag;
+	}
+
+	protected static boolean overlaps(int min, int max, int fullLen, List<int[]> rangeReturn) {
+		int[] ii;
+		int j, k;
+		for(int i = 0, l = rangeReturn.size(); i < l; ++i) {
+			ii = rangeReturn.get(i);
+			j = ii[0];
+			k = fullLen - ii[1];
+			if(min < k && j < max) {
+				return true;
+			}
+		}
+		return false;
+	}
+
+	protected static int evaluateCoverage(int fullLen, List<int[]> rangeReturn) {
+		int coverage = 0;
+		int[] ii;
+		for(int i = 0, l = rangeReturn.size(); i < l; ++i) {
+			ii = rangeReturn.get(i);
+			coverage += fullLen - ii[0] - ii[1] - 1;
+		}
+		return coverage;
+	}
+
+	protected static String stripColorCodes(String stringIn) {
+		int i = stringIn.indexOf('\u00a7');
+		if(i != -1) {
+			int j = 0;
+			int l = stringIn.length();
+			StringBuilder ret = new StringBuilder(l);
+			do {
+				if(i - j > 0) {
+					ret.append(stringIn, j, i);
+				}
+				j = i + 2;
+			}while(j < l && (i = stringIn.indexOf('\u00a7', j)) != -1);
+			if(l - j > 0) {
+				ret.append(stringIn, j, l);
+			}
+			return ret.toString();
+		}else {
+			return stringIn;
+		}
+	}
+
+	private static int nextDelimiter(String stringIn, int startIndex) {
+		int len = stringIn.length();
+		while(startIndex < len) {
+			char c = stringIn.charAt(startIndex);
+			switch(c) {
+			case ' ':
+			case '.':
+			case ',':
+			case '_':
+			case '+':
+			case '-':
+			case '=':
+			case '|':
+			case '?':
+			case '<':
+			case '>':
+			case '/':
+			case '\\':
+			case '\'':
+			case '\"':
+			case '@':
+			case '#':
+			case '%':
+			case '^':
+			case '&':
+			case '*':
+			case '(':
+			case ')':
+			case '{':
+			case '}':
+			case ':':
+			case ';':
+			case '`':
+			case '~':
+			case '\n':
+			case '\r':
+			case '\t':
+			case '\u00a0':
+				return startIndex;
+			case '!':
+				if (!(startIndex > 0 && !isDelimiter(stringIn.charAt(startIndex - 1)))
+						|| !(startIndex + 1 < len && !isDelimiter(stringIn.charAt(startIndex + 1)))) {
+					return startIndex;
+				}
+			default:
+				break;
+			}
+			++startIndex;
+		}
+		return -1;
+	}
+
+	private static boolean isDelimiter(char c) {
+		switch(c) {
+		case ' ':
+		case '.':
+		case ',':
+		case '_':
+		case '+':
+		case '-':
+		case '=':
+		case '|':
+		case '?':
+		case '!':
+		case '<':
+		case '>':
+		case '/':
+		case '\\':
+		case '\'':
+		case '\"':
+		case '@':
+		case '#':
+		case '%':
+		case '^':
+		case '&':
+		case '*':
+		case '(':
+		case ')':
+		case '{':
+		case '}':
+		case ':':
+		case ';':
+		case '`':
+		case '~':
+		case '\n':
+		case '\r':
+		case '\t':
+		case '\u00a0':
+			return true;
+		}
+		return false;
+	}
+
+}
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/profile/CapePackets.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/profile/CapePackets.java
index b8df6591..af6327a8 100644
--- a/sources/main/java/net/lax1dude/eaglercraft/v1_8/profile/CapePackets.java
+++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/profile/CapePackets.java
@@ -1,11 +1,5 @@
 package net.lax1dude.eaglercraft.v1_8.profile;
 
-import java.io.IOException;
-
-import net.lax1dude.eaglercraft.v1_8.EaglercraftUUID;
-import net.lax1dude.eaglercraft.v1_8.netty.Unpooled;
-import net.minecraft.network.PacketBuffer;
-
 /**
  * Copyright (c) 2024 lax1dude. All Rights Reserved.
  * 
@@ -25,42 +19,6 @@ public class CapePackets {
 
 	public static final int PACKET_MY_CAPE_PRESET = 0x01;
 	public static final int PACKET_MY_CAPE_CUSTOM = 0x02;
-	public static final int PACKET_GET_OTHER_CAPE = 0x03;
-	public static final int PACKET_OTHER_CAPE_PRESET = 0x04;
-	public static final int PACKET_OTHER_CAPE_CUSTOM = 0x05;
-
-	public static void readPluginMessage(PacketBuffer buffer, ServerCapeCache capeCache) throws IOException {
-		try {
-			int type = (int)buffer.readByte() & 0xFF;
-			switch(type) {
-			case PACKET_OTHER_CAPE_PRESET: {
-				EaglercraftUUID responseUUID = buffer.readUuid();
-				int responsePreset = buffer.readInt();
-				if(buffer.isReadable()) {
-					throw new IOException("PACKET_OTHER_CAPE_PRESET had " + buffer.readableBytes() + " remaining bytes!");
-				}
-				capeCache.cacheCapePreset(responseUUID, responsePreset);
-				break;
-			}
-			case PACKET_OTHER_CAPE_CUSTOM: {
-				EaglercraftUUID responseUUID = buffer.readUuid();
-				byte[] readCape = new byte[1173];
-				buffer.readBytes(readCape);
-				if(buffer.isReadable()) {
-					throw new IOException("PACKET_OTHER_CAPE_CUSTOM had " + buffer.readableBytes() + " remaining bytes!");
-				}
-				capeCache.cacheCapeCustom(responseUUID, readCape);
-				break;
-			}
-			default:
-				throw new IOException("Unknown skin packet type: " + type);
-			}
-		}catch(IOException ex) {
-			throw ex;
-		}catch(Throwable t) {
-			throw new IOException("Failed to parse cape packet!", t);
-		}
-	}
 
 	public static byte[] writeMyCapePreset(int capeId) {
 		return new byte[] { (byte) PACKET_MY_CAPE_PRESET, (byte) (capeId >>> 24), (byte) (capeId >>> 16),
@@ -74,10 +32,4 @@ public class CapePackets {
 		return packet;
 	}
 
-	public static PacketBuffer writeGetOtherCape(EaglercraftUUID playerId) throws IOException {
-		PacketBuffer ret = new PacketBuffer(Unpooled.buffer(17, 17));
-		ret.writeByte(PACKET_GET_OTHER_CAPE);
-		ret.writeUuid(playerId);
-		return ret;
-	}
 }
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/profile/EaglerProfile.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/profile/EaglerProfile.java
index 13bd51d4..d5edfaa0 100644
--- a/sources/main/java/net/lax1dude/eaglercraft/v1_8/profile/EaglerProfile.java
+++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/profile/EaglerProfile.java
@@ -40,12 +40,34 @@ public class EaglerProfile {
 	public static int presetCapeId;
 	public static int customCapeId;
 
-	public static final List<CustomSkin> customSkins = new ArrayList();
-	public static final List<CustomCape> customCapes = new ArrayList();
+	public static boolean isServerSkinOverride = false;
+	public static int overridePresetSkinId = -1;
+	public static final ResourceLocation overrideCustomSkinTexture = new ResourceLocation("eagler:skins/custom/tex_server_override");
+	public static EaglerSkinTexture overrideCustomSkin = null;
+	public static SkinModel overrideCustomSkinModel = SkinModel.STEVE;
+
+	public static boolean isServerCapeOverride = false;
+	public static int overridePresetCapeId = -1;
+	public static final ResourceLocation overrideCustomCapeTexture = new ResourceLocation("eagler:capes/custom/tex_server_override");
+	public static EaglerSkinTexture overrideCustomCape = null;
+
+	public static final List<CustomSkin> customSkins = new ArrayList<>();
+	public static final List<CustomCape> customCapes = new ArrayList<>();
 	
 	public static final EaglercraftRandom rand;
 	
 	public static ResourceLocation getActiveSkinResourceLocation() {
+		if(isServerSkinOverride) {
+			if(overridePresetSkinId == -1) {
+				return overrideCustomSkinTexture;
+			}else {
+				if(overridePresetSkinId >= 0 && overridePresetSkinId < DefaultSkins.defaultSkinsMap.length) {
+					return DefaultSkins.defaultSkinsMap[overridePresetSkinId].location;
+				}else {
+					return DefaultSkins.defaultSkinsMap[0].location;
+				}
+			}
+		}
 		if(presetSkinId == -1) {
 			if(customSkinId >= 0 && customSkinId < customSkins.size()) {
 				return customSkins.get(customSkinId).getResource();
@@ -65,6 +87,17 @@ public class EaglerProfile {
 	}
 	
 	public static SkinModel getActiveSkinModel() {
+		if(isServerSkinOverride) {
+			if(overridePresetSkinId == -1) {
+				return overrideCustomSkinModel;
+			}else {
+				if(overridePresetSkinId >= 0 && overridePresetSkinId < DefaultSkins.defaultSkinsMap.length) {
+					return DefaultSkins.defaultSkinsMap[overridePresetSkinId].model;
+				}else {
+					return DefaultSkins.defaultSkinsMap[0].model;
+				}
+			}
+		}
 		if(presetSkinId == -1) {
 			if(customSkinId >= 0 && customSkinId < customSkins.size()) {
 				return customSkins.get(customSkinId).model;
@@ -84,6 +117,17 @@ public class EaglerProfile {
 	}
 	
 	public static ResourceLocation getActiveCapeResourceLocation() {
+		if(isServerCapeOverride) {
+			if(overridePresetCapeId == -1) {
+				return overrideCustomCapeTexture;
+			}else {
+				if(overridePresetCapeId >= 0 && overridePresetCapeId < DefaultCapes.defaultCapesMap.length) {
+					return DefaultCapes.defaultCapesMap[overridePresetCapeId].location;
+				}else {
+					return DefaultCapes.defaultCapesMap[0].location;
+				}
+			}
+		}
 		if(presetCapeId == -1) {
 			if(customCapeId >= 0 && customCapeId < customCapes.size()) {
 				return customCapes.get(customCapeId).getResource();
@@ -118,10 +162,15 @@ public class EaglerProfile {
 		}
 	}
 
-	public static byte[] getSkinPacket() {
+	public static byte[] getSkinPacket(int vers) {
 		if(presetSkinId == -1) {
 			if(customSkinId >= 0 && customSkinId < customSkins.size()) {
-				return SkinPackets.writeMySkinCustom(customSkins.get(customSkinId));
+				CustomSkin toSend = customSkins.get(customSkinId);
+				if(vers <= 3) {
+					return SkinPackets.writeMySkinCustomV3(toSend);
+				}else {
+					return SkinPackets.writeMySkinCustomV4(toSend);
+				}
 			}else {
 				customSkinId = -1;
 				presetSkinId = 0;
@@ -156,6 +205,59 @@ public class EaglerProfile {
 		}
 	}
 
+	public static void handleForceSkinPreset(int preset) {
+		isServerSkinOverride = true;
+		overridePresetSkinId = preset;
+		ServerSkinCache.needReloadClientSkin = true;
+	}
+
+	public static void handleForceSkinCustom(int modelID, byte[] datav3) {
+		if(datav3.length != 16384) {
+			return;
+		}
+		isServerSkinOverride = true;
+		overridePresetSkinId = -1;
+		overrideCustomSkinModel = SkinModel.getModelFromId(modelID);
+		if(overrideCustomSkinModel.highPoly != null) {
+			overrideCustomSkinModel = SkinModel.STEVE;
+		}
+		if(overrideCustomSkin == null) {
+			overrideCustomSkin = new EaglerSkinTexture(datav3, 64, 64);
+			Minecraft.getMinecraft().getTextureManager().loadTexture(overrideCustomSkinTexture, overrideCustomSkin);
+		}else {
+			overrideCustomSkin.copyPixelsIn(datav3);
+		}
+		ServerSkinCache.needReloadClientSkin = true;
+	}
+
+	public static void handleForceCapePreset(int preset) {
+		isServerCapeOverride = true;
+		overridePresetCapeId = preset;
+		ServerCapeCache.needReloadClientCape = true;
+	}
+
+	public static void handleForceCapeCustom(byte[] custom) {
+		if(custom.length != 1173) {
+			return;
+		}
+		byte[] pixels32x32 = new byte[4096];
+		SkinConverter.convertCape23x17RGBto32x32RGBA(custom, pixels32x32);
+		isServerCapeOverride = true;
+		overridePresetCapeId = -1;
+		if(overrideCustomCape == null) {
+			overrideCustomCape = new EaglerSkinTexture(pixels32x32, 32, 32);
+			Minecraft.getMinecraft().getTextureManager().loadTexture(overrideCustomCapeTexture, overrideCustomCape);
+		}else {
+			overrideCustomCape.copyPixelsIn(pixels32x32);
+		}
+		ServerCapeCache.needReloadClientCape = true;
+	}
+
+	public static void clearServerSkinOverride() {
+		isServerSkinOverride = false;
+		isServerCapeOverride = false;
+	}
+
 	private static boolean doesSkinExist(String name) {
 		for(int i = 0, l = customSkins.size(); i < l; ++i) {
 			if(customSkins.get(i).name.equalsIgnoreCase(name)) {
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/profile/EaglerSkinTexture.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/profile/EaglerSkinTexture.java
index bea6cf60..025a0149 100644
--- a/sources/main/java/net/lax1dude/eaglercraft/v1_8/profile/EaglerSkinTexture.java
+++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/profile/EaglerSkinTexture.java
@@ -44,15 +44,23 @@ public class EaglerSkinTexture implements ITextureObject {
 		if(pixels.length != width * height * 4) {
 			throw new IllegalArgumentException("Wrong data length " + pixels.length + "  for " + width + "x" + height + " texture");
 		}
+		this.pixels = convertToInt(pixels);
+		this.width = width;
+		this.height = height;
+	}
+
+	public static int[] convertToInt(byte[] pixels) {
 		int[] p = new int[pixels.length >> 2];
 		for(int i = 0, j; i < p.length; ++i) {
 			j = i << 2;
 			p[i] = (((int) pixels[j] & 0xFF) << 24) | (((int) pixels[j + 1] & 0xFF) << 16)
 					| (((int) pixels[j + 2] & 0xFF) << 8) | ((int) pixels[j + 3] & 0xFF);
 		}
-		this.pixels = p;
-		this.width = width;
-		this.height = height;
+		return p;
+	}
+
+	public void copyPixelsIn(byte[] pixels) {
+		copyPixelsIn(convertToInt(pixels));
 	}
 
 	public void copyPixelsIn(int[] pixels) {
@@ -93,4 +101,16 @@ public class EaglerSkinTexture implements ITextureObject {
 		textureId = -1;
 	}
 
+	public int getWidth() {
+		return width;
+	}
+
+	public int getHeight() {
+		return height;
+	}
+
+	public int[] getData() {
+		return pixels;
+	}
+
 }
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/profile/GuiAuthenticationScreen.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/profile/GuiAuthenticationScreen.java
index 3dc82f46..bec4f424 100644
--- a/sources/main/java/net/lax1dude/eaglercraft/v1_8/profile/GuiAuthenticationScreen.java
+++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/profile/GuiAuthenticationScreen.java
@@ -2,7 +2,7 @@ package net.lax1dude.eaglercraft.v1_8.profile;
 
 import net.lax1dude.eaglercraft.v1_8.Keyboard;
 import net.lax1dude.eaglercraft.v1_8.internal.KeyboardConstants;
-import net.lax1dude.eaglercraft.v1_8.internal.PlatformNetworking;
+import net.lax1dude.eaglercraft.v1_8.minecraft.EnumInputEvent;
 import net.lax1dude.eaglercraft.v1_8.socket.ConnectionHandshake;
 import net.lax1dude.eaglercraft.v1_8.socket.HandshakePacketTypes;
 import net.minecraft.client.gui.GuiButton;
@@ -92,9 +92,6 @@ public class GuiAuthenticationScreen extends GuiScreen {
 			this.mc.displayGuiScreen(new GuiConnecting(retAfterAuthScreen, password.getText()));
 		}else {
 			this.mc.displayGuiScreen(parent);
-			if (!PlatformNetworking.playConnectionState().isClosed()) {
-				PlatformNetworking.playDisconnect();
-			}
 		}
 	}
 
@@ -122,4 +119,14 @@ public class GuiAuthenticationScreen extends GuiScreen {
 		this.password.mouseClicked(parInt1, parInt2, parInt3);
 	}
 
+	@Override
+	public boolean showCopyPasteButtons() {
+		return password.isFocused();
+	}
+
+	@Override
+	public void fireInputEvent(EnumInputEvent event, String param) {
+		password.fireInputEvent(event, param);
+	}
+
 }
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/profile/GuiScreenEditCape.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/profile/GuiScreenEditCape.java
index 6e50f1ab..e4cee9f7 100644
--- a/sources/main/java/net/lax1dude/eaglercraft/v1_8/profile/GuiScreenEditCape.java
+++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/profile/GuiScreenEditCape.java
@@ -3,6 +3,7 @@ package net.lax1dude.eaglercraft.v1_8.profile;
 import net.lax1dude.eaglercraft.v1_8.EagRuntime;
 import net.lax1dude.eaglercraft.v1_8.Keyboard;
 import net.lax1dude.eaglercraft.v1_8.Mouse;
+import net.lax1dude.eaglercraft.v1_8.PointerInputAbstraction;
 import net.lax1dude.eaglercraft.v1_8.internal.EnumCursorType;
 import net.lax1dude.eaglercraft.v1_8.internal.FileChooserResult;
 import net.lax1dude.eaglercraft.v1_8.opengl.GlStateManager;
@@ -51,7 +52,6 @@ public class GuiScreenEditCape extends GuiScreen {
 
 	public GuiScreenEditCape(GuiScreenEditProfile parent) {
 		this.parent = parent;
-		updateOptions();
 	}
 
 	public void initGui() {
@@ -61,6 +61,7 @@ public class GuiScreenEditCape extends GuiScreen {
 		buttonList.add(new GuiButton(0, width / 2 - 100, height / 6 + 168, I18n.format("gui.done")));
 		buttonList.add(new GuiButton(1, width / 2 - 21, height / 6 + 80, 71, 20, I18n.format("editCape.addCape")));
 		buttonList.add(new GuiButton(2, width / 2 - 21 + 71, height / 6 + 80, 72, 20, I18n.format("editCape.clearCape")));
+		updateOptions();
 	}
 
 	private void updateOptions() {
@@ -243,7 +244,7 @@ public class GuiScreenEditCape extends GuiScreen {
 		if(EagRuntime.fileChooserHasResult()) {
 			FileChooserResult result = EagRuntime.getFileChooserResult();
 			if(result != null) {
-				ImageData loadedCape = ImageData.loadImageFile(result.fileData);
+				ImageData loadedCape = ImageData.loadImageFile(result.fileData, ImageData.getMimeFromType(result.fileName));
 				if(loadedCape != null) {
 					if((loadedCape.width == 32 || loadedCape.width == 64) && loadedCape.height == 32) {
 						byte[] resized = new byte[1173];
@@ -258,12 +259,12 @@ public class GuiScreenEditCape extends GuiScreen {
 						EagRuntime.showPopup("The selected image '" + result.fileName + "' is not the right size!\nEaglercraft only supports 32x32 or 64x32 capes");
 					}
 				}else {
-					EagRuntime.showPopup("The selected file '" + result.fileName + "' is not a PNG file!");
+					EagRuntime.showPopup("The selected file '" + result.fileName + "' is not a supported format!");
 				}
 			}
 		}
 		if(dropDownOpen) {
-			if(Mouse.isButtonDown(0)) {
+			if(PointerInputAbstraction.getVCursorButtonDown(0)) {
 				int skinX = width / 2 - 20;
 				int skinY = height / 6 + 73;
 				int skinWidth = 140;
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/profile/GuiScreenEditProfile.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/profile/GuiScreenEditProfile.java
index 8ed345bf..4910f395 100644
--- a/sources/main/java/net/lax1dude/eaglercraft/v1_8/profile/GuiScreenEditProfile.java
+++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/profile/GuiScreenEditProfile.java
@@ -3,8 +3,10 @@ package net.lax1dude.eaglercraft.v1_8.profile;
 import net.lax1dude.eaglercraft.v1_8.EagRuntime;
 import net.lax1dude.eaglercraft.v1_8.Keyboard;
 import net.lax1dude.eaglercraft.v1_8.Mouse;
+import net.lax1dude.eaglercraft.v1_8.PointerInputAbstraction;
 import net.lax1dude.eaglercraft.v1_8.internal.EnumCursorType;
 import net.lax1dude.eaglercraft.v1_8.internal.FileChooserResult;
+import net.lax1dude.eaglercraft.v1_8.minecraft.EnumInputEvent;
 import net.lax1dude.eaglercraft.v1_8.opengl.GlStateManager;
 import net.lax1dude.eaglercraft.v1_8.opengl.ImageData;
 import net.minecraft.client.audio.PositionedSoundRecord;
@@ -57,7 +59,6 @@ public class GuiScreenEditProfile extends GuiScreen {
 
 	public GuiScreenEditProfile(GuiScreen parent) {
 		this.parent = parent;
-		updateOptions();
 	}
 
 	public void initGui() {
@@ -66,10 +67,12 @@ public class GuiScreenEditProfile extends GuiScreen {
 		usernameField = new GuiTextField(0, fontRendererObj, width / 2 - 20 + 1, height / 6 + 24 + 1, 138, 20);
 		usernameField.setFocused(true);
 		usernameField.setText(EaglerProfile.getName());
+		usernameField.setMaxStringLength(16);
 		selectedSlot = EaglerProfile.presetSkinId == -1 ? EaglerProfile.customSkinId : (EaglerProfile.presetSkinId + EaglerProfile.customSkins.size());
 		buttonList.add(new GuiButton(0, width / 2 - 100, height / 6 + 168, I18n.format("gui.done")));
 		buttonList.add(new GuiButton(1, width / 2 - 21, height / 6 + 110, 71, 20, I18n.format("editProfile.addSkin")));
 		buttonList.add(new GuiButton(2, width / 2 - 21 + 71, height / 6 + 110, 72, 20, I18n.format("editProfile.clearSkin")));
+		updateOptions();
 	}
 
 	private void updateOptions() {
@@ -330,7 +333,7 @@ public class GuiScreenEditProfile extends GuiScreen {
 		if(EagRuntime.fileChooserHasResult()) {
 			FileChooserResult result = EagRuntime.getFileChooserResult();
 			if(result != null) {
-				ImageData loadedSkin = ImageData.loadImageFile(result.fileData);
+				ImageData loadedSkin = ImageData.loadImageFile(result.fileData, ImageData.getMimeFromType(result.fileName));
 				if(loadedSkin != null) {
 					boolean isLegacy = loadedSkin.width == 64 && loadedSkin.height == 32;
 					boolean isModern = loadedSkin.width == 64 && loadedSkin.height == 64;
@@ -367,12 +370,12 @@ public class GuiScreenEditProfile extends GuiScreen {
 						EagRuntime.showPopup("The selected image '" + result.fileName + "' is not the right size!\nEaglercraft only supports 64x32 or 64x64 skins");
 					}
 				}else {
-					EagRuntime.showPopup("The selected file '" + result.fileName + "' is not a PNG file!");
+					EagRuntime.showPopup("The selected file '" + result.fileName + "' is not a supported format!");
 				}
 			}
 		}
 		if(dropDownOpen) {
-			if(Mouse.isButtonDown(0)) {
+			if(PointerInputAbstraction.getVCursorButtonDown(0)) {
 				int skinX = width / 2 - 20;
 				int skinY = height / 6 + 103;
 				int skinWidth = 140;
@@ -532,4 +535,14 @@ public class GuiScreenEditProfile extends GuiScreen {
 		EaglerProfile.setName(name);
 	}
 
+	@Override
+	public boolean showCopyPasteButtons() {
+		return usernameField.isFocused();
+	}
+
+	@Override
+	public void fireInputEvent(EnumInputEvent event, String param) {
+		usernameField.fireInputEvent(event, param);
+	}
+
 }
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/profile/GuiScreenImportProfile.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/profile/GuiScreenImportProfile.java
index 825974a9..a08dc915 100644
--- a/sources/main/java/net/lax1dude/eaglercraft/v1_8/profile/GuiScreenImportProfile.java
+++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/profile/GuiScreenImportProfile.java
@@ -77,8 +77,8 @@ public class GuiScreenImportProfile extends GuiScreen {
 			}else {
 				mc.loadingScreen.eaglerShow(I18n.format("settingsBackup.importing.1"), I18n.format("settingsBackup.importing.2"));
 				try {
-					List<String> list1 = new ArrayList(mc.gameSettings.resourcePacks); 
-					List<String> list2 = new ArrayList(mc.gameSettings.field_183018_l);
+					List<String> list1 = new ArrayList<>(mc.gameSettings.resourcePacks); 
+					List<String> list2 = new ArrayList<>(mc.gameSettings.field_183018_l);
 					importer.importProfileAndSettings(doImportProfile, doImportSettings, doImportServers, doImportResourcePacks);
 					boolean resourcePacksChanged = !mc.gameSettings.resourcePacks.equals(list1) || !mc.gameSettings.field_183018_l.equals(list2);
 					if(resourcePacksChanged || (doImportResourcePacks && (list1.size() > 0 || list2.size() > 0))) {
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/profile/RenderHighPoly.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/profile/RenderHighPoly.java
index 515b1ea6..176c9907 100644
--- a/sources/main/java/net/lax1dude/eaglercraft/v1_8/profile/RenderHighPoly.java
+++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/profile/RenderHighPoly.java
@@ -2,6 +2,7 @@ package net.lax1dude.eaglercraft.v1_8.profile;
 
 import static net.lax1dude.eaglercraft.v1_8.opengl.RealOpenGLEnums.*;
 
+import net.lax1dude.eaglercraft.v1_8.EagRuntime;
 import net.lax1dude.eaglercraft.v1_8.log4j.LogManager;
 import net.lax1dude.eaglercraft.v1_8.log4j.Logger;
 import net.lax1dude.eaglercraft.v1_8.opengl.EaglerMeshLoader;
@@ -158,7 +159,7 @@ public class RenderHighPoly extends RenderPlayer {
 				
 				if(highPolySkin.headModel != null) {
 					if(highPolySkin == HighPolySkin.BABY_CHARLES) {
-						long millis = System.currentTimeMillis();
+						long millis = EagRuntime.steadyTimeMillis();
 						float partialTicks = (float) ((millis - abstractclientplayer.eaglerHighPolyAnimationTick) * 0.02);
 						//long l50 = millis / 50l * 50l;
 						//boolean runTick = par1EntityPlayer.eaglerHighPolyAnimationTick < l50 && millis >= l50;
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/profile/ServerCapeCache.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/profile/ServerCapeCache.java
index 77fb2766..ffad6327 100644
--- a/sources/main/java/net/lax1dude/eaglercraft/v1_8/profile/ServerCapeCache.java
+++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/profile/ServerCapeCache.java
@@ -1,17 +1,16 @@
 package net.lax1dude.eaglercraft.v1_8.profile;
 
-import java.io.IOException;
 import java.util.HashMap;
 import java.util.Iterator;
 import java.util.Map;
 
+import net.lax1dude.eaglercraft.v1_8.EagRuntime;
 import net.lax1dude.eaglercraft.v1_8.EaglercraftUUID;
 import net.lax1dude.eaglercraft.v1_8.log4j.LogManager;
 import net.lax1dude.eaglercraft.v1_8.log4j.Logger;
-import net.lax1dude.eaglercraft.v1_8.socket.EaglercraftNetworkManager;
+import net.lax1dude.eaglercraft.v1_8.socket.protocol.pkt.client.CPacketGetOtherCapeEAG;
+import net.minecraft.client.network.NetHandlerPlayClient;
 import net.minecraft.client.renderer.texture.TextureManager;
-import net.minecraft.network.PacketBuffer;
-import net.minecraft.network.play.client.C17PacketCustomPayload;
 import net.minecraft.util.ResourceLocation;
 
 /**
@@ -39,7 +38,7 @@ public class ServerCapeCache {
 		protected final int presetCapeId;
 		protected final CacheCustomCape customCape;
 		
-		protected long lastCacheHit = System.currentTimeMillis();
+		protected long lastCacheHit = EagRuntime.steadyTimeMillis();
 		
 		protected CapeCacheEntry(EaglerSkinTexture textureInstance, ResourceLocation resourceLocation) {
 			this.isPresetCape = false;
@@ -96,26 +95,32 @@ public class ServerCapeCache {
 	}
 
 	private final CapeCacheEntry defaultCacheEntry = new CapeCacheEntry(0);
-	private final Map<EaglercraftUUID, CapeCacheEntry> capesCache = new HashMap();
-	private final Map<EaglercraftUUID, Long> waitingCapes = new HashMap();
-	private final Map<EaglercraftUUID, Long> evictedCapes = new HashMap();
+	private final Map<EaglercraftUUID, CapeCacheEntry> capesCache = new HashMap<>();
+	private final Map<EaglercraftUUID, Long> waitingCapes = new HashMap<>();
+	private final Map<EaglercraftUUID, Long> evictedCapes = new HashMap<>();
 
-	private final EaglercraftNetworkManager networkManager;
+	private final NetHandlerPlayClient netHandler;
 	protected final TextureManager textureManager;
 	
 	private final EaglercraftUUID clientPlayerId;
-	private final CapeCacheEntry clientPlayerCacheEntry;
+	private CapeCacheEntry clientPlayerCacheEntry;
 
-	private long lastFlush = System.currentTimeMillis();
-	private long lastFlushReq = System.currentTimeMillis();
-	private long lastFlushEvict = System.currentTimeMillis();
+	private long lastFlush = EagRuntime.steadyTimeMillis();
+	private long lastFlushReq = EagRuntime.steadyTimeMillis();
+	private long lastFlushEvict = EagRuntime.steadyTimeMillis();
 
 	private static int texId = 0;
+	public static boolean needReloadClientCape = false;
 
-	public ServerCapeCache(EaglercraftNetworkManager networkManager, TextureManager textureManager) {
-		this.networkManager = networkManager;
+	public ServerCapeCache(NetHandlerPlayClient netHandler, TextureManager textureManager) {
+		this.netHandler = netHandler;
 		this.textureManager = textureManager;
 		this.clientPlayerId = EaglerProfile.getPlayerUUID();
+		reloadClientPlayerCape();
+	}
+	
+	public void reloadClientPlayerCape() {
+		needReloadClientCape = false;
 		this.clientPlayerCacheEntry = new CapeCacheEntry(EaglerProfile.getActiveCapeResourceLocation());
 	}
 
@@ -130,20 +135,12 @@ public class ServerCapeCache {
 		CapeCacheEntry etr = capesCache.get(player);
 		if(etr == null) {
 			if(!waitingCapes.containsKey(player) && !evictedCapes.containsKey(player)) {
-				waitingCapes.put(player, System.currentTimeMillis());
-				PacketBuffer buffer;
-				try {
-					buffer = CapePackets.writeGetOtherCape(player);
-				}catch(IOException ex) {
-					logger.error("Could not write cape request packet!");
-					logger.error(ex);
-					return defaultCacheEntry;
-				}
-				networkManager.sendPacket(new C17PacketCustomPayload("EAG|Capes-1.8", buffer));
+				waitingCapes.put(player, EagRuntime.steadyTimeMillis());
+				netHandler.sendEaglerMessage(new CPacketGetOtherCapeEAG(player.msb, player.lsb));
 			}
 			return defaultCacheEntry;
 		}else {
-			etr.lastCacheHit = System.currentTimeMillis();
+			etr.lastCacheHit = EagRuntime.steadyTimeMillis();
 			return etr;
 		}
 	}
@@ -183,7 +180,7 @@ public class ServerCapeCache {
 	}
 
 	public void flush() {
-		long millis = System.currentTimeMillis();
+		long millis = EagRuntime.steadyTimeMillis();
 		if(millis - lastFlushReq > 5000l) {
 			lastFlushReq = millis;
 			if(!waitingCapes.isEmpty()) {
@@ -219,6 +216,9 @@ public class ServerCapeCache {
 				}
 			}
 		}
+		if(needReloadClientCape) {
+			reloadClientPlayerCape();
+		}
 	}
 
 	public void destroy() {
@@ -232,7 +232,14 @@ public class ServerCapeCache {
 	}
 
 	public void evictCape(EaglercraftUUID uuid) {
-		evictedCapes.put(uuid, Long.valueOf(System.currentTimeMillis()));
+		evictedCapes.put(uuid, Long.valueOf(EagRuntime.steadyTimeMillis()));
+		CapeCacheEntry etr = capesCache.remove(uuid);
+		if(etr != null) {
+			etr.free();
+		}
+	}
+
+	public void handleInvalidate(EaglercraftUUID uuid) {
 		CapeCacheEntry etr = capesCache.remove(uuid);
 		if(etr != null) {
 			etr.free();
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/profile/ServerSkinCache.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/profile/ServerSkinCache.java
index 5a88c280..f11cf4ba 100644
--- a/sources/main/java/net/lax1dude/eaglercraft/v1_8/profile/ServerSkinCache.java
+++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/profile/ServerSkinCache.java
@@ -1,19 +1,19 @@
 package net.lax1dude.eaglercraft.v1_8.profile;
 
-import java.io.IOException;
 import java.util.HashMap;
 import java.util.Iterator;
 import java.util.Map;
 
+import net.lax1dude.eaglercraft.v1_8.EagRuntime;
 import net.lax1dude.eaglercraft.v1_8.EaglercraftUUID;
 import net.lax1dude.eaglercraft.v1_8.log4j.LogManager;
 import net.lax1dude.eaglercraft.v1_8.log4j.Logger;
 import net.lax1dude.eaglercraft.v1_8.mojang.authlib.GameProfile;
 import net.lax1dude.eaglercraft.v1_8.mojang.authlib.TexturesProperty;
-import net.lax1dude.eaglercraft.v1_8.socket.EaglercraftNetworkManager;
+import net.lax1dude.eaglercraft.v1_8.socket.protocol.pkt.client.CPacketGetOtherSkinEAG;
+import net.lax1dude.eaglercraft.v1_8.socket.protocol.pkt.client.CPacketGetSkinByURLEAG;
+import net.minecraft.client.network.NetHandlerPlayClient;
 import net.minecraft.client.renderer.texture.TextureManager;
-import net.minecraft.network.PacketBuffer;
-import net.minecraft.network.play.client.C17PacketCustomPayload;
 import net.minecraft.util.ResourceLocation;
 
 /**
@@ -41,7 +41,7 @@ public class ServerSkinCache {
 		protected final int presetSkinId;
 		protected final CacheCustomSkin customSkin;
 		
-		protected long lastCacheHit = System.currentTimeMillis();
+		protected long lastCacheHit = EagRuntime.steadyTimeMillis();
 		
 		protected SkinCacheEntry(EaglerSkinTexture textureInstance, ResourceLocation resourceLocation, SkinModel model) {
 			this.isPresetSkin = false;
@@ -125,26 +125,32 @@ public class ServerSkinCache {
 
 	private final SkinCacheEntry defaultCacheEntry = new SkinCacheEntry(0);
 	private final SkinCacheEntry defaultSlimCacheEntry = new SkinCacheEntry(1);
-	private final Map<EaglercraftUUID, SkinCacheEntry> skinsCache = new HashMap();
-	private final Map<EaglercraftUUID, WaitingSkin> waitingSkins = new HashMap();
-	private final Map<EaglercraftUUID, Long> evictedSkins = new HashMap();
+	private final Map<EaglercraftUUID, SkinCacheEntry> skinsCache = new HashMap<>();
+	private final Map<EaglercraftUUID, WaitingSkin> waitingSkins = new HashMap<>();
+	private final Map<EaglercraftUUID, Long> evictedSkins = new HashMap<>();
 
-	private final EaglercraftNetworkManager networkManager;
+	private final NetHandlerPlayClient netHandler;
 	protected final TextureManager textureManager;
 	
 	private final EaglercraftUUID clientPlayerId;
-	private final SkinCacheEntry clientPlayerCacheEntry;
+	private SkinCacheEntry clientPlayerCacheEntry;
 
-	private long lastFlush = System.currentTimeMillis();
-	private long lastFlushReq = System.currentTimeMillis();
-	private long lastFlushEvict = System.currentTimeMillis();
+	private long lastFlush = EagRuntime.steadyTimeMillis();
+	private long lastFlushReq = EagRuntime.steadyTimeMillis();
+	private long lastFlushEvict = EagRuntime.steadyTimeMillis();
 
 	private static int texId = 0;
+	public static boolean needReloadClientSkin = false;
 
-	public ServerSkinCache(EaglercraftNetworkManager networkManager, TextureManager textureManager) {
-		this.networkManager = networkManager;
+	public ServerSkinCache(NetHandlerPlayClient netHandler, TextureManager textureManager) {
+		this.netHandler = netHandler;
 		this.textureManager = textureManager;
 		this.clientPlayerId = EaglerProfile.getPlayerUUID();
+		reloadClientPlayerSkin();
+	}
+
+	public void reloadClientPlayerSkin() {
+		needReloadClientSkin = false;
 		this.clientPlayerCacheEntry = new SkinCacheEntry(EaglerProfile.getActiveSkinResourceLocation(), EaglerProfile.getActiveSkinModel());
 	}
 
@@ -184,20 +190,12 @@ public class ServerSkinCache {
 		SkinCacheEntry etr = skinsCache.get(player);
 		if(etr == null) {
 			if(!waitingSkins.containsKey(player) && !evictedSkins.containsKey(player)) {
-				waitingSkins.put(player, new WaitingSkin(System.currentTimeMillis(), null));
-				PacketBuffer buffer;
-				try {
-					buffer = SkinPackets.writeGetOtherSkin(player);
-				}catch(IOException ex) {
-					logger.error("Could not write skin request packet!");
-					logger.error(ex);
-					return defaultCacheEntry;
-				}
-				networkManager.sendPacket(new C17PacketCustomPayload("EAG|Skins-1.8", buffer));
+				waitingSkins.put(player, new WaitingSkin(EagRuntime.steadyTimeMillis(), null));
+				netHandler.sendEaglerMessage(new CPacketGetOtherSkinEAG(player.msb, player.lsb));
 			}
 			return defaultCacheEntry;
 		}else {
-			etr.lastCacheHit = System.currentTimeMillis();
+			etr.lastCacheHit = EagRuntime.steadyTimeMillis();
 			return etr;
 		}
 	}
@@ -209,20 +207,12 @@ public class ServerSkinCache {
 		EaglercraftUUID generatedUUID = SkinPackets.createEaglerURLSkinUUID(url);
 		SkinCacheEntry etr = skinsCache.get(generatedUUID);
 		if(etr != null) {
-			etr.lastCacheHit = System.currentTimeMillis();
+			etr.lastCacheHit = EagRuntime.steadyTimeMillis();
 			return etr;
 		}else {
 			if(!waitingSkins.containsKey(generatedUUID) && !evictedSkins.containsKey(generatedUUID)) {
-				waitingSkins.put(generatedUUID, new WaitingSkin(System.currentTimeMillis(), skinModelResponse));
-				PacketBuffer buffer;
-				try {
-					buffer = SkinPackets.writeGetSkinByURL(generatedUUID, url);
-				}catch(IOException ex) {
-					logger.error("Could not write skin request packet!");
-					logger.error(ex);
-					return skinModelResponse == SkinModel.ALEX ? defaultSlimCacheEntry : defaultCacheEntry;
-				}
-				networkManager.sendPacket(new C17PacketCustomPayload("EAG|Skins-1.8", buffer));
+				waitingSkins.put(generatedUUID, new WaitingSkin(EagRuntime.steadyTimeMillis(), skinModelResponse));
+				netHandler.sendEaglerMessage(new CPacketGetSkinByURLEAG(generatedUUID.msb, generatedUUID.lsb, url));
 			}
 		}
 		return skinModelResponse == SkinModel.ALEX ? defaultSlimCacheEntry : defaultCacheEntry;
@@ -276,13 +266,13 @@ public class ServerSkinCache {
 	}
 	
 	public void flush() {
-		long millis = System.currentTimeMillis();
+		long millis = EagRuntime.steadyTimeMillis();
 		if(millis - lastFlushReq > 5000l) {
 			lastFlushReq = millis;
 			if(!waitingSkins.isEmpty()) {
 				Iterator<WaitingSkin> waitingItr = waitingSkins.values().iterator();
 				while(waitingItr.hasNext()) {
-					if(millis - waitingItr.next().timeout > 30000l) {
+					if(millis - waitingItr.next().timeout > 20000l) {
 						waitingItr.remove();
 					}
 				}
@@ -312,6 +302,9 @@ public class ServerSkinCache {
 				}
 			}
 		}
+		if(needReloadClientSkin) {
+			reloadClientPlayerSkin();
+		}
 	}
 	
 	public void destroy() {
@@ -325,7 +318,14 @@ public class ServerSkinCache {
 	}
 	
 	public void evictSkin(EaglercraftUUID uuid) {
-		evictedSkins.put(uuid, Long.valueOf(System.currentTimeMillis()));
+		evictedSkins.put(uuid, Long.valueOf(EagRuntime.steadyTimeMillis()));
+		SkinCacheEntry etr = skinsCache.remove(uuid);
+		if(etr != null) {
+			etr.free();
+		}
+	}
+
+	public void handleInvalidate(EaglercraftUUID uuid) {
 		SkinCacheEntry etr = skinsCache.remove(uuid);
 		if(etr != null) {
 			etr.free();
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/profile/SkinModel.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/profile/SkinModel.java
index 735deea5..541c51e9 100644
--- a/sources/main/java/net/lax1dude/eaglercraft/v1_8/profile/SkinModel.java
+++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/profile/SkinModel.java
@@ -32,7 +32,7 @@ public enum SkinModel {
 	public final HighPolySkin highPoly;
 	
 	public static final SkinModel[] skinModels = new SkinModel[8];
-	private static final Map<String, SkinModel> skinModelsByName = new HashMap();
+	private static final Map<String, SkinModel> skinModelsByName = new HashMap<>();
 	
 	private SkinModel(int id, int w, int h, String profileSkinType, boolean sanitize) {
 		this.id = id;
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/profile/SkinPackets.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/profile/SkinPackets.java
index 7616c6b0..b91d7013 100644
--- a/sources/main/java/net/lax1dude/eaglercraft/v1_8/profile/SkinPackets.java
+++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/profile/SkinPackets.java
@@ -1,12 +1,8 @@
 package net.lax1dude.eaglercraft.v1_8.profile;
 
-import java.io.IOException;
-
 import net.lax1dude.eaglercraft.v1_8.ArrayUtils;
 import net.lax1dude.eaglercraft.v1_8.EaglercraftUUID;
 import net.lax1dude.eaglercraft.v1_8.crypto.MD5Digest;
-import net.lax1dude.eaglercraft.v1_8.netty.Unpooled;
-import net.minecraft.network.PacketBuffer;
 
 /**
  * Copyright (c) 2022-2023 lax1dude, ayunami2000. All Rights Reserved.
@@ -27,97 +23,33 @@ public class SkinPackets {
 
 	public static final int PACKET_MY_SKIN_PRESET = 0x01;
 	public static final int PACKET_MY_SKIN_CUSTOM = 0x02;
-	public static final int PACKET_GET_OTHER_SKIN = 0x03;
-	public static final int PACKET_OTHER_SKIN_PRESET = 0x04;
-	public static final int PACKET_OTHER_SKIN_CUSTOM = 0x05;
-	public static final int PACKET_GET_SKIN_BY_URL = 0x06;
-	public static final int PACKET_INSTALL_NEW_SKIN = 0x07;
-
-	public static void readPluginMessage(PacketBuffer buffer, ServerSkinCache skinCache) throws IOException {
-		try {
-			int type = (int)buffer.readByte() & 0xFF;
-			switch(type) {
-			case PACKET_OTHER_SKIN_PRESET: {
-				EaglercraftUUID responseUUID = buffer.readUuid();
-				int responsePreset = buffer.readInt();
-				if(buffer.isReadable()) {
-					throw new IOException("PACKET_OTHER_SKIN_PRESET had " + buffer.readableBytes() + " remaining bytes!");
-				}
-				skinCache.cacheSkinPreset(responseUUID, responsePreset);
-				break;
-			}
-			case PACKET_OTHER_SKIN_CUSTOM: {
-				EaglercraftUUID responseUUID = buffer.readUuid();
-				int model = (int)buffer.readByte() & 0xFF;
-				SkinModel modelId;
-				if(model == (byte)0xFF) {
-					modelId = skinCache.getRequestedSkinType(responseUUID);
-				}else {
-					modelId = SkinModel.getModelFromId(model & 0x7F);
-					if((model & 0x80) != 0 && modelId.sanitize) {
-						modelId = SkinModel.STEVE;
-					}
-				}
-				if(modelId.highPoly != null) {
-					modelId = SkinModel.STEVE;
-				}
-				int bytesToRead = modelId.width * modelId.height * 4;
-				byte[] readSkin = new byte[bytesToRead];
-				buffer.readBytes(readSkin);
-				if(buffer.isReadable()) {
-					throw new IOException("PACKET_MY_SKIN_CUSTOM had " + buffer.readableBytes() + " remaining bytes!");
-				}
-				skinCache.cacheSkinCustom(responseUUID, readSkin, modelId);
-				break;
-			}
-			default:
-				throw new IOException("Unknown skin packet type: " + type);
-			}
-		}catch(IOException ex) {
-			throw ex;
-		}catch(Throwable t) {
-			throw new IOException("Failed to parse skin packet!", t);
-		}
-	}
 
 	public static byte[] writeMySkinPreset(int skinId) {
 		return new byte[] { (byte) PACKET_MY_SKIN_PRESET, (byte) (skinId >>> 24), (byte) (skinId >>> 16),
 				(byte) (skinId >>> 8), (byte) (skinId & 0xFF) };
 	}
 
-	public static byte[] writeMySkinCustom(CustomSkin customSkin) {
-		byte[] packet = new byte[2 + customSkin.texture.length];
+	public static byte[] writeMySkinCustomV3(CustomSkin customSkin) {
+		byte[] packet = new byte[2 + 16384];
 		packet[0] = (byte) PACKET_MY_SKIN_CUSTOM;
 		packet[1] = (byte) customSkin.model.id;
-		System.arraycopy(customSkin.texture, 0, packet, 2, customSkin.texture.length);
+		System.arraycopy(customSkin.texture, 0, packet, 2, 16384);
 		return packet;
 	}
 
-	public static PacketBuffer writeCreateCustomSkull(byte[] customSkin) {
-		int len = 3 + customSkin.length;
-		PacketBuffer ret = new PacketBuffer(Unpooled.buffer(len, len));
-		ret.writeByte(PACKET_INSTALL_NEW_SKIN);
-		ret.writeShort(customSkin.length);
-		ret.writeBytes(customSkin);
-		return ret;
-	}
-
-	public static PacketBuffer writeGetOtherSkin(EaglercraftUUID skinId) throws IOException {
-		PacketBuffer ret = new PacketBuffer(Unpooled.buffer(17, 17));
-		ret.writeByte(PACKET_GET_OTHER_SKIN);
-		ret.writeUuid(skinId);
-		return ret;
-	}
-
-	public static PacketBuffer writeGetSkinByURL(EaglercraftUUID skinId, String skinUrl) throws IOException {
-		int len = 19 + skinUrl.length();
-		PacketBuffer ret = new PacketBuffer(Unpooled.buffer(len, len));
-		ret.writeByte(PACKET_GET_SKIN_BY_URL);
-		ret.writeUuid(skinId);
-		byte[] url = ArrayUtils.asciiString(skinUrl);
-		ret.writeShort((int)url.length);
-		ret.writeBytes(url);
-		return ret;
+	public static byte[] writeMySkinCustomV4(CustomSkin customSkin) {
+		byte[] packet = new byte[2 + 12288];
+		packet[0] = (byte) PACKET_MY_SKIN_CUSTOM;
+		packet[1] = (byte) customSkin.model.id;
+		byte[] v3data = customSkin.texture;
+		for(int i = 0, j, k; i < 4096; ++i) {
+			j = i << 2;
+			k = i * 3 + 2;
+			packet[k] = v3data[j + 1];
+			packet[k + 1] = v3data[j + 2];
+			packet[k + 2] = (byte)((v3data[j + 3] >>> 1) | (v3data[j] & 0x80));
+		}
+		return packet;
 	}
 
 	public static EaglercraftUUID createEaglerURLSkinUUID(String skinUrl){
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/profile/SkinPreviewRenderer.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/profile/SkinPreviewRenderer.java
index 36a20895..999c396a 100644
--- a/sources/main/java/net/lax1dude/eaglercraft/v1_8/profile/SkinPreviewRenderer.java
+++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/profile/SkinPreviewRenderer.java
@@ -1,5 +1,6 @@
 package net.lax1dude.eaglercraft.v1_8.profile;
 
+import net.lax1dude.eaglercraft.v1_8.EagRuntime;
 import net.lax1dude.eaglercraft.v1_8.opengl.EaglerMeshLoader;
 import net.lax1dude.eaglercraft.v1_8.opengl.EaglercraftGPU;
 import net.lax1dude.eaglercraft.v1_8.opengl.GlStateManager;
@@ -98,7 +99,7 @@ public class SkinPreviewRenderer {
 			Minecraft.getMinecraft().getTextureManager().bindTexture(skinTexture);
 		}
 		
-		model.render(null, 0.0f, 0.0f, (float)(System.currentTimeMillis() % 2000000) / 50f, ((x - mx) * 0.06f), ((y - my) * -0.1f), 0.0625f);
+		model.render(null, 0.0f, 0.0f, (float)(EagRuntime.steadyTimeMillis() % 2000000) / 50f, ((x - mx) * 0.06f), ((y - my) * -0.1f), 0.0625f);
 		
 		if(capeTexture != null && model instanceof ModelPlayer) {
 			Minecraft.getMinecraft().getTextureManager().bindTexture(capeTexture);
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/recording/EnumScreenRecordingCodec.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/recording/EnumScreenRecordingCodec.java
new file mode 100644
index 00000000..3c1b4d95
--- /dev/null
+++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/recording/EnumScreenRecordingCodec.java
@@ -0,0 +1,152 @@
+package net.lax1dude.eaglercraft.v1_8.recording;
+
+/**
+ * Copyright (c) 2024 lax1dude. All Rights Reserved.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ * 
+ */
+public enum EnumScreenRecordingCodec {
+
+	CODEC_MP4_H264_GENERIC_AAC("MP4 (video: H.264 Default, audio: AAC LC)", "mp4", "video/mp4", "avc1", "mp4a.40.2", false),
+	CODEC_MP4_H264_GENERIC_OPUS("MP4 (video: H.264 Default, audio: Opus)", "mp4", "video/mp4", "avc1", "opus", false),
+	CODEC_MP4_H264_L40_AAC("MP4 (video: H.264 CBP L4.0, audio: AAC LC)", "mp4", "video/mp4", "avc1.424028", "mp4a.40.2", true),
+	CODEC_MP4_H264_L40_OPUS("MP4 (video: H.264 CBP L4.0, audio: Opus)", "mp4", "video/mp4", "avc1.424028", "opus", true),
+	CODEC_MP4_H264_L42_AAC("MP4 (video: H.264 CBP L4.2, audio: AAC LC)", "mp4", "video/mp4", "avc1.42402A", "mp4a.40.2", true),
+	CODEC_MP4_H264_L42_OPUS("MP4 (video: H.264 CBP L4.2, audio: Opus)", "mp4", "video/mp4", "avc1.42402A", "opus", true),
+	CODEC_MP4_H264_L50_AAC("MP4 (video: H.264 CBP L5.0, audio: AAC LC)", "mp4", "video/mp4", "avc1.424032", "mp4a.40.2", true),
+	CODEC_MP4_H264_L50_OPUS("MP4 (video: H.264 CBP L5.0, audio: Opus)", "mp4", "video/mp4", "avc1.424032", "opus", true),
+	CODEC_MP4_H264_L52_AAC("MP4 (video: H.264 CBP L5.2, audio: AAC LC)", "mp4", "video/mp4", "avc1.424034", "mp4a.40.2", true),
+	CODEC_MP4_H264_L52_OPUS("MP4 (video: H.264 CBP L5.2, audio: Opus)", "mp4", "video/mp4", "avc1.424034", "opus", true),
+
+	CODEC_MP4_VP9_GENERIC_AAC("MP4 (video: VP9 Default, audio: AAC LC)", "mp4", "video/mp4", "vp9", "mp4a.40.2", false),
+	CODEC_MP4_VP9_GENERIC_OPUS("MP4 (video: VP9 Default, audio: Opus)", "mp4", "video/mp4", "vp9", "opus", false),
+	CODEC_MP4_VP9_L40_AAC("MP4 (video: VP9 8-bit L4.0, audio: AAC LC)", "mp4", "video/mp4", "vp9.00.40.08", "mp4a.40.2", true),
+	CODEC_MP4_VP9_L40_OPUS("MP4 (video: VP9 8-bit L4.0, audio: Opus)", "mp4", "video/mp4", "vp9.00.40.08", "opus", true),
+	CODEC_MP4_VP9_L41_AAC("MP4 (video: VP9 8-bit L4.1, audio: AAC LC)", "mp4", "video/mp4", "vp9.00.41.08", "mp4a.40.2", true),
+	CODEC_MP4_VP9_L41_OPUS("MP4 (video: VP9 8-bit L4.1, audio: Opus)", "mp4", "video/mp4", "vp9.00.41.08", "opus", true),
+	CODEC_MP4_VP9_L50_AAC("MP4 (video: VP9 8-bit L5.0, audio: AAC LC)", "mp4", "video/mp4", "vp9.00.50.08", "mp4a.40.2", true),
+	CODEC_MP4_VP9_L50_OPUS("MP4 (video: VP9 8-bit L5.0, audio: Opus)", "mp4", "video/mp4", "vp9.00.50.08", "opus", true),
+	CODEC_MP4_VP9_L51_AAC("MP4 (video: VP9 8-bit L5.1, audio: AAC LC)", "mp4", "video/mp4", "vp9.00.51.08", "mp4a.40.2", true),
+	CODEC_MP4_VP9_L51_OPUS("MP4 (video: VP9 8-bit L5.1, audio: Opus)", "mp4", "video/mp4", "vp9.00.51.08", "opus", true),
+
+	CODEC_MP4_GENERIC("MP4 (Default Codecs)", "mp4", "video/mp4", null, null, false),
+
+	CODEC_WEBM_H264_GENERIC_OPUS("WEBM (video: H.264 Default, audio: Opus)", "webm", "video/webm", "avc1", "opus", false),
+	CODEC_WEBM_H264_GENERIC_VORBIS("WEBM (video: H.264 Default, audio: Vorbis)", "webm", "video/webm", "avc1", "vorbis", false),
+	CODEC_WEBM_H264_L40_OPUS("WEBM (video: H.264 CBP L4.0, audio: Opus)", "webm", "video/webm", "avc1.424028", "opus", true),
+	CODEC_WEBM_H264_L40_VORBIS("WEBM (video: H.264 CBP L4.0, audio: Vorbis)", "webm", "video/webm", "avc1.424028", "vorbis", true),
+	CODEC_WEBM_H264_L42_OPUS("WEBM (video: H.264 CBP L4.2, audio: Opus)", "webm", "video/webm", "avc1.42402A", "opus", true),
+	CODEC_WEBM_H264_L42_VORBIS("WEBM (video: H.264 CBP L4.2, audio: Vorbis)", "webm", "video/webm", "avc1.42402A", "vorbis", true),
+	CODEC_WEBM_H264_L50_OPUS("WEBM (video: H.264 CBP L5.0, audio: Opus)", "webm", "video/webm", "avc1.424032", "opus", true),
+	CODEC_WEBM_H264_L50_VORBIS("WEBM (video: H.264 CBP L5.0, audio: Vorbis)", "webm", "video/webm", "avc1.424032", "vorbis", true),
+	CODEC_WEBM_H264_L52_OPUS("WEBM (video: H.264 CBP L5.2, audio: Opus)", "webm", "video/webm", "avc1.424034", "opus", true),
+	CODEC_WEBM_H264_L52_VORBIS("WEBM (video: H.264 CBP L5.2, audio: Vorbis)", "webm", "video/webm", "avc1.424034", "vorbis", true),
+
+	CODEC_WEBM_VP9_GENERIC_OPUS("WEBM (video: VP9 Default, audio: Opus)", "webm", "video/webm", "vp9", "opus", false),
+	CODEC_WEBM_VP9_GENERIC_VORBIS("WEBM (video: VP9 Default, audio: Vorbis)", "webm", "video/webm", "vp9", "vorbis", false),
+	CODEC_WEBM_VP9_L40_OPUS("WEBM (video: VP9 8-bit L4.0, audio: Opus)", "webm", "video/webm", "vp9.00.40.08", "opus", true),
+	CODEC_WEBM_VP9_L40_VORBIS("WEBM (video: VP9 8-bit L4.0, audio: Vorbis)", "webm", "video/webm", "vp9.00.40.08", "vorbis", true),
+	CODEC_WEBM_VP9_L41_OPUS("WEBM (video: VP9 8-bit L4.1, audio: Opus)", "webm", "video/webm", "vp9.00.41.08", "opus", true),
+	CODEC_WEBM_VP9_L41_VORBIS("WEBM (video: VP9 8-bit L4.1, audio: Vorbis)", "webm", "video/webm", "vp9.00.41.08", "vorbis", true),
+	CODEC_WEBM_VP9_L50_OPUS("WEBM (video: VP9 8-bit L5.0, audio: Opus)", "webm", "video/webm", "vp9.00.50.08", "opus", true),
+	CODEC_WEBM_VP9_L50_VORBIS("WEBM (video: VP9 8-bit L5.0, audio: Vorbis)", "webm", "video/webm", "vp9.00.50.08", "vorbis", true),
+	CODEC_WEBM_VP9_L51_OPUS("WEBM (video: VP9 8-bit L5.1, audio: Opus)", "webm", "video/webm", "vp9.00.51.08", "opus", true),
+	CODEC_WEBM_VP9_L51_VORBIS("WEBM (video: VP9 8-bit L5.1, audio: Vorbis)", "webm", "video/webm", "vp9.00.51.08", "vorbis", true),
+
+	CODEC_WEBM_VP8_GENERIC_OPUS("WEBM (video: VP8 Default, audio: Opus)", "webm", "video/webm", "vp8", "opus", false),
+	CODEC_WEBM_VP8_GENERIC_VORBIS("WEBM (video: VP8 Default, audio: Vorbis)", "webm", "video/webm", "vp8", "vorbis", false),
+
+	CODEC_WEBM_GENERIC("WEBM (Default Codecs)", "webm", "video/webm", null, null, false);
+
+	public static final EnumScreenRecordingCodec[] preferred_codec_order = new EnumScreenRecordingCodec[] {
+			CODEC_MP4_H264_GENERIC_AAC,
+			CODEC_MP4_H264_L52_AAC,
+			CODEC_MP4_H264_L50_AAC,
+			CODEC_MP4_H264_L42_AAC,
+			CODEC_MP4_H264_L40_AAC,
+			CODEC_MP4_H264_GENERIC_OPUS,
+			CODEC_MP4_H264_L40_OPUS,
+			CODEC_MP4_H264_L42_OPUS,
+			CODEC_MP4_H264_L50_OPUS,
+			CODEC_MP4_H264_L52_OPUS,
+			CODEC_WEBM_H264_GENERIC_OPUS,
+			CODEC_WEBM_H264_L52_OPUS,
+			CODEC_WEBM_H264_L50_OPUS,
+			CODEC_WEBM_H264_L42_OPUS,
+			CODEC_WEBM_H264_L40_OPUS,
+			CODEC_WEBM_H264_GENERIC_VORBIS,
+			CODEC_WEBM_H264_L52_VORBIS,
+			CODEC_WEBM_H264_L50_VORBIS,
+			CODEC_WEBM_H264_L42_VORBIS,
+			CODEC_WEBM_H264_L40_VORBIS,
+			CODEC_MP4_VP9_GENERIC_AAC,
+			CODEC_MP4_VP9_L51_AAC,
+			CODEC_MP4_VP9_L50_AAC,
+			CODEC_MP4_VP9_L41_AAC,
+			CODEC_MP4_VP9_L40_AAC,
+			CODEC_MP4_VP9_GENERIC_OPUS,
+			CODEC_MP4_VP9_L51_OPUS,
+			CODEC_MP4_VP9_L50_OPUS,
+			CODEC_MP4_VP9_L41_OPUS,
+			CODEC_MP4_VP9_L40_OPUS,
+			CODEC_WEBM_VP9_GENERIC_OPUS,
+			CODEC_WEBM_VP9_L51_OPUS,
+			CODEC_WEBM_VP9_L50_OPUS,
+			CODEC_WEBM_VP9_L41_OPUS,
+			CODEC_WEBM_VP9_L40_OPUS,
+			CODEC_WEBM_VP9_GENERIC_VORBIS,
+			CODEC_WEBM_VP9_L51_VORBIS,
+			CODEC_WEBM_VP9_L50_VORBIS,
+			CODEC_WEBM_VP9_L41_VORBIS,
+			CODEC_WEBM_VP9_L40_VORBIS,
+			CODEC_WEBM_VP8_GENERIC_OPUS,
+			CODEC_WEBM_VP8_GENERIC_VORBIS,
+			CODEC_MP4_GENERIC,
+			CODEC_WEBM_GENERIC
+	};
+
+	public final String name;
+	public final String fileExt;
+	public final String container;
+	public final String videoCodec;
+	public final String audioCodec;
+	public final boolean advanced;
+	public final String mimeType;
+	
+	private EnumScreenRecordingCodec(String name, String fileExt, String container, String videoCodec, String audioCodec, boolean advanced) {
+		this.name = name;
+		this.fileExt = fileExt;
+		this.container = container;
+		this.videoCodec = videoCodec;
+		this.audioCodec = audioCodec;
+		this.advanced = advanced;
+		if(videoCodec != null || audioCodec != null) {
+			StringBuilder mimeBuilder = new StringBuilder(container);
+			mimeBuilder.append(";codecs=\"");
+			if(videoCodec != null) {
+				mimeBuilder.append(videoCodec);
+				if(audioCodec != null) {
+					mimeBuilder.append(',');
+				}
+			}
+			if(audioCodec != null) {
+				mimeBuilder.append(audioCodec);
+			}
+			mimeBuilder.append("\"");
+			this.mimeType = mimeBuilder.toString();
+		}else {
+			this.mimeType = container;
+		}
+	}
+
+}
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/recording/GuiScreenRecordingNote.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/recording/GuiScreenRecordingNote.java
new file mode 100644
index 00000000..1dc251a5
--- /dev/null
+++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/recording/GuiScreenRecordingNote.java
@@ -0,0 +1,52 @@
+package net.lax1dude.eaglercraft.v1_8.recording;
+
+import net.minecraft.client.gui.GuiButton;
+import net.minecraft.client.gui.GuiScreen;
+import net.minecraft.client.resources.I18n;
+
+/**
+ * Copyright (c) 2024 lax1dude. All Rights Reserved.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ * 
+ */
+public class GuiScreenRecordingNote extends GuiScreen {
+
+	private GuiScreen cont;
+
+	public static boolean hasShown = false;
+
+	public GuiScreenRecordingNote(GuiScreen cont) {
+		this.cont = cont;
+	}
+
+	public void initGui() {
+		this.buttonList.clear();
+		this.buttonList.add(new GuiButton(0, this.width / 2 - 100, this.height / 6 + 108, I18n.format("gui.done")));
+	}
+
+	public void drawScreen(int par1, int par2, float par3) {
+		this.drawDefaultBackground();
+		this.drawCenteredString(fontRendererObj, I18n.format("options.recordingNote.title"), this.width / 2, 70, 11184810);
+		this.drawCenteredString(fontRendererObj, I18n.format("options.recordingNote.text0"), this.width / 2, 90, 16777215);
+		this.drawCenteredString(fontRendererObj, I18n.format("options.recordingNote.text1"), this.width / 2, 102, 16777215);
+		super.drawScreen(par1, par2, par3);
+	}
+
+	protected void actionPerformed(GuiButton par1GuiButton) {
+		if(par1GuiButton.id == 0) {
+			hasShown = true;
+			this.mc.displayGuiScreen(cont);
+		}
+	}
+
+}
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/recording/GuiScreenRecordingSettings.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/recording/GuiScreenRecordingSettings.java
new file mode 100644
index 00000000..096a2de0
--- /dev/null
+++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/recording/GuiScreenRecordingSettings.java
@@ -0,0 +1,201 @@
+package net.lax1dude.eaglercraft.v1_8.recording;
+
+import net.lax1dude.eaglercraft.v1_8.HString;
+import net.lax1dude.eaglercraft.v1_8.internal.ScreenRecordParameters;
+import net.lax1dude.eaglercraft.v1_8.log4j.LogManager;
+import net.lax1dude.eaglercraft.v1_8.log4j.Logger;
+import net.lax1dude.eaglercraft.v1_8.minecraft.GuiScreenGenericErrorMessage;
+import net.lax1dude.eaglercraft.v1_8.sp.gui.GuiSlider2;
+import net.minecraft.client.gui.GuiButton;
+import net.minecraft.client.gui.GuiScreen;
+import net.minecraft.client.resources.I18n;
+import net.minecraft.util.EnumChatFormatting;
+import net.minecraft.util.MathHelper;
+
+/**
+ * Copyright (c) 2024 lax1dude. All Rights Reserved.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ * 
+ */
+public class GuiScreenRecordingSettings extends GuiScreen {
+
+	private static final Logger logger = LogManager.getLogger("GuiScreenRecordingSettings");
+
+	protected final GuiScreen parent;
+
+	protected GuiButton recordButton;
+	protected GuiButton codecButton;
+	protected GuiSlider2 videoResolutionSlider;
+	protected GuiSlider2 videoFrameRateSlider;
+	protected GuiSlider2 audioBitrateSlider;
+	protected GuiSlider2 videoBitrateSlider;
+	protected GuiSlider2 microphoneVolumeSlider;
+	protected GuiSlider2 gameVolumeSlider;
+	protected boolean dirty = false;
+
+	public GuiScreenRecordingSettings(GuiScreen parent) {
+		this.parent = parent;
+	}
+
+	public void initGui() {
+		buttonList.clear();
+		buttonList.add(new GuiButton(0, this.width / 2 - 100, this.height / 6 + 168, I18n.format("gui.done")));
+		buttonList.add(codecButton = new GuiButton(1, this.width / 2 + 65, this.height / 6 - 2, 75, 20, I18n.format("options.screenRecording.codecButton")));
+		boolean isRecording = ScreenRecordingController.isRecording();
+		buttonList.add(recordButton = new GuiButton(2, this.width / 2 + 15, this.height / 6 + 28, 125, 20,
+				I18n.format(isRecording ? "options.screenRecording.stop" : "options.screenRecording.start")));
+		buttonList.add(videoResolutionSlider = new GuiSlider2(3, this.width / 2 - 155, this.height / 6 + 64, 150, 20, (mc.gameSettings.screenRecordResolution - 1) / 3.999f, 1.0f) {
+			@Override
+			protected String updateDisplayString() {
+				int i = (int)(sliderValue * 3.999f);
+				return I18n.format("options.screenRecording.videoResolution") + ": x" + HString.format("%.2f", 1.0f / (int)Math.pow(2.0, i));
+			}
+			@Override
+			protected void onChange() {
+				mc.gameSettings.screenRecordResolution = 1 + (int)(sliderValue * 3.999f);
+				dirty = true;
+			}
+		});
+		buttonList.add(videoFrameRateSlider = new GuiSlider2(4, this.width / 2 + 5, this.height / 6 + 64, 150, 20, (Math.max(mc.gameSettings.screenRecordFPS, 9) - 9) / 51.999f, 1.0f) {
+			@Override
+			protected String updateDisplayString() {
+				int i = (int)(sliderValue * 51.999f);
+				return I18n.format("options.screenRecording.videoFPS") + ": " + (i <= 0 ? I18n.format("options.screenRecording.onVSync") : 9 + i);
+			}
+			@Override
+			protected void onChange() {
+				int i = (int)(sliderValue * 51.999f);
+				mc.gameSettings.screenRecordFPS = i <= 0 ? -1 : 9 + i;
+				dirty = true;
+			}
+		});
+		buttonList.add(videoBitrateSlider = new GuiSlider2(5, this.width / 2 - 155, this.height / 6 + 98, 150, 20, MathHelper.sqrt_float(MathHelper.clamp_float((mc.gameSettings.screenRecordVideoBitrate - 250) / 19750.999f, 0.0f, 1.0f)), 1.0f) {
+			@Override
+			protected String updateDisplayString() {
+				return I18n.format("options.screenRecording.videoBitrate") + ": " + (250 + (int)(sliderValue * sliderValue * 19750.999f)) + "kbps";
+			}
+			@Override
+			protected void onChange() {
+				mc.gameSettings.screenRecordVideoBitrate = 250 + (int)(sliderValue * sliderValue * 19750.999f);
+				dirty = true;
+			}
+		});
+		buttonList.add(audioBitrateSlider = new GuiSlider2(6, this.width / 2 + 5, this.height / 6 + 98, 150, 20, MathHelper.sqrt_float(MathHelper.clamp_float((mc.gameSettings.screenRecordAudioBitrate - 24) / 232.999f, 0.0f, 1.0f)), 1.0f) {
+			@Override
+			protected String updateDisplayString() {
+				return I18n.format("options.screenRecording.audioBitrate") + ": " + (24 + (int)(sliderValue * sliderValue * 232.999f)) + "kbps";
+			}
+			@Override
+			protected void onChange() {
+				mc.gameSettings.screenRecordAudioBitrate = 24 + (int)(sliderValue * sliderValue * 232.999f);
+				dirty = true;
+			}
+		});
+		buttonList.add(gameVolumeSlider = new GuiSlider2(7, this.width / 2 - 155, this.height / 6 + 130, 150, 20, mc.gameSettings.screenRecordGameVolume, 1.0f) {
+			@Override
+			protected String updateDisplayString() {
+				return I18n.format("options.screenRecording.gameVolume") + ": " + (int)(sliderValue * 100.999f) + "%";
+			}
+			@Override
+			protected void onChange() {
+				mc.gameSettings.screenRecordGameVolume = sliderValue;
+				ScreenRecordingController.setGameVolume(sliderValue);
+				dirty = true;
+			}
+		});
+		buttonList.add(microphoneVolumeSlider = new GuiSlider2(8, this.width / 2 + 5, this.height / 6 + 130, 150, 20, mc.gameSettings.screenRecordMicVolume, 1.0f) {
+			@Override
+			protected String updateDisplayString() {
+				return I18n.format("options.screenRecording.microphoneVolume") + ": " + (int)(sliderValue * 100.999f) + "%";
+			}
+			@Override
+			protected void onChange() {
+				mc.gameSettings.screenRecordMicVolume = sliderValue;
+				ScreenRecordingController.setMicrophoneVolume(sliderValue);
+				dirty = true;
+			}
+		});
+		codecButton.enabled = !isRecording;
+		videoResolutionSlider.enabled = !isRecording;
+		videoFrameRateSlider.enabled = !isRecording;
+		audioBitrateSlider.enabled = !isRecording;
+		videoBitrateSlider.enabled = !isRecording;
+		microphoneVolumeSlider.enabled = !ScreenRecordingController.isMicVolumeLocked();
+	}
+
+	protected void actionPerformed(GuiButton parGuiButton) {
+		if(parGuiButton.id == 0) {
+			if(dirty) {
+				mc.gameSettings.saveOptions();
+				dirty = false;
+			}
+			mc.displayGuiScreen(parent);
+		}else if(parGuiButton.id == 1) {
+			mc.displayGuiScreen(new GuiScreenSelectCodec(this, mc.gameSettings.screenRecordCodec));
+		}else if(parGuiButton.id == 2) {
+			if(!ScreenRecordingController.isRecording()) {
+				try {
+					ScreenRecordingController.startRecording(new ScreenRecordParameters(mc.gameSettings.screenRecordCodec,
+							mc.gameSettings.screenRecordResolution, mc.gameSettings.screenRecordVideoBitrate,
+							mc.gameSettings.screenRecordAudioBitrate, mc.gameSettings.screenRecordFPS));
+				}catch(Throwable t) {
+					logger.error("Failed to begin screen recording!");
+					logger.error(t);
+					mc.displayGuiScreen(new GuiScreenGenericErrorMessage("options.screenRecording.failed", t.toString(), parent));
+				}
+			}else {
+				ScreenRecordingController.endRecording();
+			}
+		}
+	}
+
+	public void drawScreen(int i, int j, float var3) {
+		drawDefaultBackground();
+		drawCenteredString(fontRendererObj, I18n.format("options.screenRecording.title"), this.width / 2, 15, 16777215);
+		if(mc.gameSettings.screenRecordCodec == null) {
+			mc.gameSettings.screenRecordCodec = ScreenRecordingController.getDefaultCodec();
+		}
+		
+		String codecString = mc.gameSettings.screenRecordCodec.name;
+		int codecStringWidth = fontRendererObj.getStringWidth(codecString);
+		drawString(fontRendererObj, codecString, this.width / 2 + 60 - codecStringWidth, this.height / 6 + 4, 0xFFFFFF);
+		
+		boolean isRecording = ScreenRecordingController.isRecording();
+		codecButton.enabled = !isRecording;
+		videoResolutionSlider.enabled = !isRecording;
+		videoFrameRateSlider.enabled = !isRecording;
+		audioBitrateSlider.enabled = !isRecording;
+		videoBitrateSlider.enabled = !isRecording;
+		microphoneVolumeSlider.enabled = !ScreenRecordingController.isMicVolumeLocked();
+		recordButton.displayString = I18n.format(isRecording ? "options.screenRecording.stop" : "options.screenRecording.start");
+		String statusString = I18n.format("options.screenRecording.status",
+				(isRecording ? EnumChatFormatting.GREEN : EnumChatFormatting.RED) + I18n.format(isRecording ? "options.screenRecording.status.1" : "options.screenRecording.status.0"));
+		int statusStringWidth = fontRendererObj.getStringWidth(statusString);
+		drawString(fontRendererObj, statusString, this.width / 2 + 10 - statusStringWidth, this.height / 6 + 34, 0xFFFFFF);
+		
+		super.drawScreen(i, j, var3);
+	}
+
+	protected void handleCodecCallback(EnumScreenRecordingCodec codec) {
+		EnumScreenRecordingCodec oldCodec = mc.gameSettings.screenRecordCodec;
+		if(ScreenRecordingController.codecs.contains(codec)) {
+			mc.gameSettings.screenRecordCodec = codec;
+		}else {
+			mc.gameSettings.screenRecordCodec = ScreenRecordingController.getDefaultCodec();
+		}
+		if(oldCodec != mc.gameSettings.screenRecordCodec) {
+			dirty = true;
+		}
+	}
+
+}
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/recording/GuiScreenSelectCodec.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/recording/GuiScreenSelectCodec.java
new file mode 100644
index 00000000..3b6cfaa8
--- /dev/null
+++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/recording/GuiScreenSelectCodec.java
@@ -0,0 +1,92 @@
+package net.lax1dude.eaglercraft.v1_8.recording;
+
+import java.io.IOException;
+import java.util.List;
+
+import net.minecraft.client.Minecraft;
+import net.minecraft.client.gui.GuiButton;
+import net.minecraft.client.gui.GuiScreen;
+import net.minecraft.client.resources.I18n;
+
+/**
+ * Copyright (c) 2024 lax1dude. All Rights Reserved.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ * 
+ */
+public class GuiScreenSelectCodec extends GuiScreen {
+
+	protected final GuiScreenRecordingSettings parent;
+	protected List<EnumScreenRecordingCodec> codecs;
+	protected int selectedCodec;
+	protected GuiSlotSelectCodec slots;
+	protected GuiButton showAllButton;
+	protected boolean showAll;
+	protected EnumScreenRecordingCodec codec;
+
+	public GuiScreenSelectCodec(GuiScreenRecordingSettings parent, EnumScreenRecordingCodec codec) {
+		this.parent = parent;
+		this.codec = codec;
+	}
+
+	public void initGui() {
+		showAll = codec.advanced;
+		codecs = showAll ? ScreenRecordingController.advancedCodecsOrdered : ScreenRecordingController.simpleCodecsOrdered;
+		selectedCodec = codecs.indexOf(codec);
+		buttonList.clear();
+		buttonList.add(showAllButton = new GuiButton(0, this.width / 2 - 154, this.height - 38, 150, 20,
+				I18n.format("options.recordingCodec.showAdvancedCodecs", I18n.format(showAll ? "gui.yes" : "gui.no"))));
+		buttonList.add(new GuiButton(1, this.width / 2 + 4, this.height - 38, 150, 20, I18n.format("gui.done")));
+		slots = new GuiSlotSelectCodec(this, 32, height - 45);
+	}
+
+	protected void actionPerformed(GuiButton parGuiButton) {
+		if(parGuiButton.id == 0) {
+			changeStateShowAll(!showAll);
+			showAllButton.displayString = I18n.format("options.recordingCodec.showAdvancedCodecs", I18n.format(showAll ? "gui.yes" : "gui.no"));
+		}else if(parGuiButton.id == 1) {
+			if(selectedCodec >= 0 && selectedCodec < codecs.size()) {
+				parent.handleCodecCallback(codecs.get(selectedCodec));
+			}
+			mc.displayGuiScreen(parent);
+		}
+	}
+
+	protected void changeStateShowAll(boolean newShowAll) {
+		if(newShowAll == showAll) return;
+		EnumScreenRecordingCodec oldCodec = codecs.get(selectedCodec >= 0 && selectedCodec < codecs.size() ? selectedCodec : 0);
+		codecs = newShowAll ? ScreenRecordingController.advancedCodecsOrdered : ScreenRecordingController.simpleCodecsOrdered;
+		showAll = newShowAll;
+		selectedCodec = codecs.indexOf(oldCodec);
+	}
+
+	public void drawScreen(int i, int j, float var3) {
+		slots.drawScreen(i, j, var3);
+		this.drawCenteredString(this.fontRendererObj, I18n.format("options.recordingCodec.title"), this.width / 2, 16, 16777215);
+		super.drawScreen(i, j, var3);
+	}
+
+	public void handleMouseInput() throws IOException {
+		super.handleMouseInput();
+		slots.handleMouseInput();
+	}
+
+	public void handleTouchInput() throws IOException {
+		super.handleTouchInput();
+		slots.handleTouchInput();
+	}
+
+	static Minecraft getMC(GuiScreenSelectCodec screen) {
+		return screen.mc;
+	}
+
+}
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/recording/GuiSlotSelectCodec.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/recording/GuiSlotSelectCodec.java
new file mode 100644
index 00000000..4521968d
--- /dev/null
+++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/recording/GuiSlotSelectCodec.java
@@ -0,0 +1,58 @@
+package net.lax1dude.eaglercraft.v1_8.recording;
+
+import net.minecraft.client.gui.GuiSlot;
+
+/**
+ * Copyright (c) 2024 lax1dude. All Rights Reserved.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ * 
+ */
+public class GuiSlotSelectCodec extends GuiSlot {
+
+	protected final GuiScreenSelectCodec screen;
+
+	public GuiSlotSelectCodec(GuiScreenSelectCodec screen, int topIn, int bottomIn) {
+		super(GuiScreenSelectCodec.getMC(screen), screen.width, screen.height, topIn, bottomIn, 18);
+		this.screen = screen;
+	}
+
+	@Override
+	protected int getSize() {
+		return screen.codecs.size();
+	}
+
+	@Override
+	protected void elementClicked(int var1, boolean var2, int var3, int var4) {
+		if(var1 < screen.codecs.size()) {
+			screen.selectedCodec = var1;
+		}
+	}
+
+	@Override
+	protected boolean isSelected(int var1) {
+		return screen.selectedCodec == var1;
+	}
+
+	@Override
+	protected void drawBackground() {
+		screen.drawDefaultBackground();
+	}
+
+	@Override
+	protected void drawSlot(int id, int xx, int yy, int width, int height, int ii) {
+		if(id < screen.codecs.size()) {
+			this.screen.drawString(mc.fontRendererObj, screen.codecs.get(id).name, xx + 4, yy + 3, 0xFFFFFF);
+		}
+	}
+
+}
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/recording/ScreenRecordingController.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/recording/ScreenRecordingController.java
new file mode 100644
index 00000000..869b7dea
--- /dev/null
+++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/recording/ScreenRecordingController.java
@@ -0,0 +1,99 @@
+package net.lax1dude.eaglercraft.v1_8.recording;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import net.lax1dude.eaglercraft.v1_8.internal.PlatformScreenRecord;
+import net.lax1dude.eaglercraft.v1_8.internal.ScreenRecordParameters;
+
+/**
+ * Copyright (c) 2024 lax1dude. All Rights Reserved.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ * 
+ */
+public class ScreenRecordingController {
+
+	public static final int DEFAULT_FPS = 30;
+	public static final int DEFAULT_RESOLUTION = 1;
+	public static final int DEFAULT_AUDIO_BITRATE = 120;
+	public static final int DEFAULT_VIDEO_BITRATE = 2500;
+	public static final float DEFAULT_GAME_VOLUME = 1.0f;
+	public static final float DEFAULT_MIC_VOLUME = 0.0f;
+
+	public static final List<EnumScreenRecordingCodec> simpleCodecsOrdered = new ArrayList<>();
+	public static final List<EnumScreenRecordingCodec> advancedCodecsOrdered = new ArrayList<>();
+	public static final Set<EnumScreenRecordingCodec> codecs = new HashSet<>();
+	private static boolean supported = false;
+
+	public static void initialize() {
+		simpleCodecsOrdered.clear();
+		advancedCodecsOrdered.clear();
+		codecs.clear();
+		supported = PlatformScreenRecord.isSupported();
+		if(supported) {
+			EnumScreenRecordingCodec[] codecsOrdered = EnumScreenRecordingCodec.preferred_codec_order;
+			for(int i = 0; i < codecsOrdered.length; ++i) {
+				EnumScreenRecordingCodec codec = codecsOrdered[i];
+				if(PlatformScreenRecord.isCodecSupported(codec)) {
+					if(!codec.advanced) {
+						simpleCodecsOrdered.add(codec);
+					}
+					advancedCodecsOrdered.add(codec);
+					codecs.add(codec);
+				}
+			}
+		}
+		if(codecs.isEmpty()) {
+			supported = false;
+		}
+	}
+
+	public static boolean isSupported() {
+		return supported;
+	}
+
+	public static void setGameVolume(float volume) {
+		PlatformScreenRecord.setGameVolume(volume);
+	}
+
+	public static void setMicrophoneVolume(float volume) {
+		PlatformScreenRecord.setMicrophoneVolume(volume);
+	}
+
+	public static void startRecording(ScreenRecordParameters params) {
+		PlatformScreenRecord.startRecording(params);
+	}
+
+	public static void endRecording() {
+		PlatformScreenRecord.endRecording();
+	}
+
+	public static boolean isRecording() {
+		return PlatformScreenRecord.isRecording();
+	}
+
+	public static boolean isMicVolumeLocked() {
+		return PlatformScreenRecord.isMicVolumeLocked();
+	}
+
+	public static boolean isVSyncLocked() {
+		return PlatformScreenRecord.isVSyncLocked();
+	}
+
+	public static EnumScreenRecordingCodec getDefaultCodec() {
+		return simpleCodecsOrdered.isEmpty() ? (advancedCodecsOrdered.isEmpty() ? null : advancedCodecsOrdered.get(0)) : simpleCodecsOrdered.get(0);
+	}
+
+}
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/socket/ConnectionHandshake.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/socket/ConnectionHandshake.java
index c262ee94..d1ca8978 100644
--- a/sources/main/java/net/lax1dude/eaglercraft/v1_8/socket/ConnectionHandshake.java
+++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/socket/ConnectionHandshake.java
@@ -4,14 +4,22 @@ import java.io.DataInputStream;
 import java.io.DataOutputStream;
 import java.io.IOException;
 import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
 
 import net.lax1dude.eaglercraft.v1_8.ArrayUtils;
+import net.lax1dude.eaglercraft.v1_8.EagRuntime;
 import net.lax1dude.eaglercraft.v1_8.EaglerInputStream;
 import net.lax1dude.eaglercraft.v1_8.EaglerOutputStream;
 import net.lax1dude.eaglercraft.v1_8.EaglercraftUUID;
 import net.lax1dude.eaglercraft.v1_8.EaglercraftVersion;
+import net.lax1dude.eaglercraft.v1_8.PauseMenuCustomizeState;
 import net.lax1dude.eaglercraft.v1_8.crypto.SHA256Digest;
-import net.lax1dude.eaglercraft.v1_8.internal.PlatformNetworking;
+import net.lax1dude.eaglercraft.v1_8.internal.IWebSocketClient;
+import net.lax1dude.eaglercraft.v1_8.internal.IWebSocketFrame;
 import net.lax1dude.eaglercraft.v1_8.log4j.LogManager;
 import net.lax1dude.eaglercraft.v1_8.log4j.Logger;
 import net.lax1dude.eaglercraft.v1_8.profile.EaglerProfile;
@@ -42,20 +50,40 @@ import net.minecraft.util.IChatComponent;
  */
 public class ConnectionHandshake {
 
-	private static final long baseTimeout = 15000l;
+	private static final long baseTimeout = 10000l;
 
 	private static final int protocolV2 = 2;
 	private static final int protocolV3 = 3;
+	private static final int protocolV4 = 4;
 	
 	private static final Logger logger = LogManager.getLogger();
 
 	public static String pluginVersion = null;
 	public static String pluginBrand = null;
+	public static int protocolVersion = -1;
 	
-	public static boolean attemptHandshake(Minecraft mc, GuiConnecting connecting, GuiScreen ret, String password, boolean allowPlaintext) {
+	public static byte[] getSPHandshakeProtocolData() {
 		try {
+			EaglerOutputStream bao = new EaglerOutputStream();
+			DataOutputStream d = new DataOutputStream(bao);
+			d.writeShort(3); // supported eagler protocols count
+			d.writeShort(protocolV2); // client supports v2
+			d.writeShort(protocolV3); // client supports v3
+			d.writeShort(protocolV4); // client supports v4
+			return bao.toByteArray();
+		}catch(IOException ex) {
+			throw new RuntimeException(ex);
+		}
+	}
+	
+	public static boolean attemptHandshake(Minecraft mc, IWebSocketClient client, GuiConnecting connecting,
+			GuiScreen ret, String password, boolean allowPlaintext, boolean enableCookies, byte[] cookieData) {
+		try {
+			EaglerProfile.clearServerSkinOverride();
+			PauseMenuCustomizeState.reset();
 			pluginVersion = null;
 			pluginBrand = null;
+			protocolVersion = -1;
 			EaglerOutputStream bao = new EaglerOutputStream();
 			DataOutputStream d = new DataOutputStream(bao);
 			
@@ -63,9 +91,7 @@ public class ConnectionHandshake {
 			
 			d.writeByte(2); // legacy protocol version
 			
-			d.writeShort(2); // supported eagler protocols count
-			d.writeShort(protocolV2); // client supports v2
-			d.writeShort(protocolV3); // client supports v3
+			d.write(getSPHandshakeProtocolData()); // write supported eagler protocol versions
 
 			d.writeShort(1); // supported game protocols count
 			d.writeShort(47); // client supports 1.8 protocol
@@ -84,9 +110,9 @@ public class ConnectionHandshake {
 			d.writeByte(username.length());
 			d.writeBytes(username);
 			
-			PlatformNetworking.writePlayPacket(bao.toByteArray());
+			client.send(bao.toByteArray());
 			
-			byte[] read = awaitNextPacket(baseTimeout);
+			byte[] read = awaitNextPacket(client, baseTimeout);
 			if(read == null) {
 				logger.error("Read timed out while waiting for server protocol response!");
 				return false;
@@ -115,7 +141,7 @@ public class ConnectionHandshake {
 					games.append("mc").append(di.readShort());
 				}
 				
-				logger.info("Incompatible client: v2 & mc47");
+				logger.info("Incompatible client: v2/v3/v4 & mc47");
 				logger.info("Server supports: {}", protocols);
 				logger.info("Server supports: {}", games);
 				
@@ -128,11 +154,11 @@ public class ConnectionHandshake {
 				
 				return false;
 			}else if(type == HandshakePacketTypes.PROTOCOL_SERVER_VERSION) {
-				int serverVers = di.readShort();
+				protocolVersion = di.readShort();
 				
-				if(serverVers != protocolV2 && serverVers != protocolV3) {
-					logger.info("Incompatible server version: {}", serverVers);
-					mc.displayGuiScreen(new GuiDisconnected(ret, "connect.failed", new ChatComponentText(serverVers < protocolV2 ? "Outdated Server" : "Outdated Client")));
+				if(protocolVersion != protocolV2 && protocolVersion != protocolV3 && protocolVersion != protocolV4) {
+					logger.info("Incompatible server version: {}", protocolVersion);
+					mc.displayGuiScreen(new GuiDisconnected(ret, "connect.failed", new ChatComponentText(protocolVersion < protocolV2 ? "Outdated Server" : "Outdated Client")));
 					return false;
 				}
 				
@@ -143,7 +169,7 @@ public class ConnectionHandshake {
 					return false;
 				}
 				
-				logger.info("Server protocol: {}", serverVers);
+				logger.info("Server protocol: {}", protocolVersion);
 				
 				int msgLen = di.read();
 				byte[] dat = new byte[msgLen];
@@ -260,10 +286,19 @@ public class ConnectionHandshake {
 				}else {
 					d.writeByte(0);
 				}
+				if(protocolVersion >= protocolV4) {
+					d.writeBoolean(enableCookies);
+					if(enableCookies && cookieData != null) {
+						d.writeByte(cookieData.length);
+						d.write(cookieData);
+					}else {
+						d.writeByte(0);
+					}
+				}
 				
-				PlatformNetworking.writePlayPacket(bao.toByteArray());
+				client.send(bao.toByteArray());
 				
-				read = awaitNextPacket(baseTimeout);
+				read = awaitNextPacket(client, baseTimeout);
 				if(read == null) {
 					logger.error("Read timed out while waiting for login negotiation response!");
 					return false;
@@ -280,52 +315,79 @@ public class ConnectionHandshake {
 					
 					Minecraft.getMinecraft().getSession().update(serverUsername, new EaglercraftUUID(di.readLong(), di.readLong()));
 					
-					bao.reset();
-					d.writeByte(HandshakePacketTypes.PROTOCOL_CLIENT_PROFILE_DATA);
-					String profileDataType = "skin_v1";
-					d.writeByte(profileDataType.length());
-					d.writeBytes(profileDataType);
-					byte[] packetSkin = EaglerProfile.getSkinPacket();
+					Map<String,byte[]> profileDataToSend = new HashMap<>();
+					
+					if(protocolVersion >= 4) {
+						bao.reset();
+						d.writeLong(EaglercraftVersion.clientBrandUUID.msb);
+						d.writeLong(EaglercraftVersion.clientBrandUUID.lsb);
+						profileDataToSend.put("brand_uuid_v1", bao.toByteArray());
+					}
+					
+					byte[] packetSkin = EaglerProfile.getSkinPacket(protocolVersion);
 					if(packetSkin.length > 0xFFFF) {
 						throw new IOException("Skin packet is too long: " + packetSkin.length);
 					}
-					d.writeShort(packetSkin.length);
-					d.write(packetSkin);
-					PlatformNetworking.writePlayPacket(bao.toByteArray());
+					profileDataToSend.put(protocolVersion >= 4 ? "skin_v2" : "skin_v1", packetSkin);
 					
-					bao.reset();
-					d.writeByte(HandshakePacketTypes.PROTOCOL_CLIENT_PROFILE_DATA);
-					profileDataType = "cape_v1";
-					d.writeByte(profileDataType.length());
-					d.writeBytes(profileDataType);
 					byte[] packetCape = EaglerProfile.getCapePacket();
 					if(packetCape.length > 0xFFFF) {
 						throw new IOException("Cape packet is too long: " + packetCape.length);
 					}
-					d.writeShort(packetCape.length);
-					d.write(packetCape);
-					PlatformNetworking.writePlayPacket(bao.toByteArray());
+					profileDataToSend.put("cape_v1", packetCape);
 					
 					byte[] packetSignatureData = UpdateService.getClientSignatureData();
 					if(packetSignatureData != null) {
-						bao.reset();
-						d.writeByte(HandshakePacketTypes.PROTOCOL_CLIENT_PROFILE_DATA);
-						profileDataType = "update_cert_v1";
-						d.writeByte(profileDataType.length());
-						d.writeBytes(profileDataType);
-						if(packetSignatureData.length > 0xFFFF) {
-							throw new IOException("Update certificate login packet is too long: " + packetSignatureData.length);
+						profileDataToSend.put("update_cert_v1", packetSignatureData);
+					}
+					
+					if(protocolVersion >= 4) {
+						List<Entry<String,byte[]>> toSend = new ArrayList<>(profileDataToSend.entrySet());
+						while(!toSend.isEmpty()) {
+							int sendLen = 2;
+							bao.reset();
+							d.writeByte(HandshakePacketTypes.PROTOCOL_CLIENT_PROFILE_DATA);
+							d.writeByte(0); // will be replaced
+							int packetCount = 0;
+							while(!toSend.isEmpty() && packetCount < 255) {
+								Entry<String,byte[]> etr = toSend.get(toSend.size() - 1);
+								int i = 3 + etr.getKey().length() + etr.getValue().length;
+								if(sendLen + i < 0xFF00) {
+									String profileDataType = etr.getKey();
+									d.writeByte(profileDataType.length());
+									d.writeBytes(profileDataType);
+									byte[] data = etr.getValue();
+									d.writeShort(data.length);
+									d.write(data);
+									toSend.remove(toSend.size() - 1);
+									++packetCount;
+								}else {
+									break;
+								}
+							}
+							byte[] send = bao.toByteArray();
+							send[1] = (byte)packetCount;
+							client.send(send);
+						}
+					}else {
+						for(Entry<String,byte[]> etr : profileDataToSend.entrySet()) {
+							bao.reset();
+							d.writeByte(HandshakePacketTypes.PROTOCOL_CLIENT_PROFILE_DATA);
+							String profileDataType = etr.getKey();
+							d.writeByte(profileDataType.length());
+							d.writeBytes(profileDataType);
+							byte[] data = etr.getValue();
+							d.writeShort(data.length);
+							d.write(data);
+							client.send(bao.toByteArray());
 						}
-						d.writeShort(packetSignatureData.length);
-						d.write(packetSignatureData);
-						PlatformNetworking.writePlayPacket(bao.toByteArray());
 					}
 					
 					bao.reset();
 					d.writeByte(HandshakePacketTypes.PROTOCOL_CLIENT_FINISH_LOGIN);
-					PlatformNetworking.writePlayPacket(bao.toByteArray());
+					client.send(bao.toByteArray());
 					
-					read = awaitNextPacket(baseTimeout);
+					read = awaitNextPacket(client, baseTimeout);
 					if(read == null) {
 						logger.error("Read timed out while waiting for login confirmation response!");
 						return false;
@@ -336,13 +398,13 @@ public class ConnectionHandshake {
 					if(type == HandshakePacketTypes.PROTOCOL_SERVER_FINISH_LOGIN) {
 						return true;
 					}else if(type == HandshakePacketTypes.PROTOCOL_SERVER_ERROR) {
-						showError(mc, connecting, ret, di, serverVers == protocolV2);
+						showError(mc, client, connecting, ret, di, protocolVersion == protocolV2);
 						return false;
 					}else {
 						return false;
 					}
 				}else if(type == HandshakePacketTypes.PROTOCOL_SERVER_DENY_LOGIN) {
-					if(serverVers == protocolV2) {
+					if(protocolVersion == protocolV2) {
 						msgLen = di.read();
 					}else {
 						msgLen = di.readUnsignedShort();
@@ -353,13 +415,13 @@ public class ConnectionHandshake {
 					mc.displayGuiScreen(new GuiDisconnected(ret, "connect.failed", IChatComponent.Serializer.jsonToComponent(errStr)));
 					return false;
 				}else if(type == HandshakePacketTypes.PROTOCOL_SERVER_ERROR) {
-					showError(mc, connecting, ret, di, serverVers == protocolV2);
+					showError(mc, client, connecting, ret, di, protocolVersion == protocolV2);
 					return false;
 				}else {
 					return false;
 				}
 			}else if(type == HandshakePacketTypes.PROTOCOL_SERVER_ERROR) {
-				showError(mc, connecting, ret, di, true);
+				showError(mc, client, connecting, ret, di, true);
 				return false;
 			}else {
 				return false;
@@ -372,37 +434,51 @@ public class ConnectionHandshake {
 		
 	}
 	
-	private static byte[] awaitNextPacket(long timeout) {
-		long millis = System.currentTimeMillis();
-		byte[] b;
-		while((b = PlatformNetworking.readPlayPacket()) == null) {
-			if(PlatformNetworking.playConnectionState().isClosed()) {
+	private static byte[] awaitNextPacket(IWebSocketClient client, long timeout) {
+		long millis = EagRuntime.steadyTimeMillis();
+		IWebSocketFrame b;
+		while((b = client.getNextBinaryFrame()) == null) {
+			if(client.getState().isClosed()) {
 				return null;
 			}
 			try {
 				Thread.sleep(50l);
 			} catch (InterruptedException e) {
 			}
-			if(System.currentTimeMillis() - millis > timeout) {
-				PlatformNetworking.playDisconnect();
+			if(EagRuntime.steadyTimeMillis() - millis > timeout) {
+				client.close();
 				return null;
 			}
 		}
-		return b;
+		return b.getByteArray();
 	}
 	
-	private static void showError(Minecraft mc, GuiConnecting connecting, GuiScreen scr, DataInputStream err, boolean v2) throws IOException {
+	private static void showError(Minecraft mc, IWebSocketClient client, GuiConnecting connecting, GuiScreen scr, DataInputStream err, boolean v2) throws IOException {
 		int errorCode = err.read();
 		int msgLen = v2 ? err.read() : err.readUnsignedShort();
+		
+		// workaround for bug in EaglerXBungee 1.2.7 and below
+		if(msgLen == 0) {
+			if(v2) {
+				if(err.available() == 256) {
+					msgLen = 256;
+				}
+			}else {
+				if(err.available() == 65536) {
+					msgLen = 65536;
+				}
+			}
+		}
+		
 		byte[] dat = new byte[msgLen];
 		err.read(dat);
 		String errStr = new String(dat, StandardCharsets.UTF_8);
 		logger.info("Server Error Code {}: {}", errorCode, errStr);
 		if(errorCode == HandshakePacketTypes.SERVER_ERROR_RATELIMIT_BLOCKED) {
-			RateLimitTracker.registerBlock(PlatformNetworking.getCurrentURI());
+			RateLimitTracker.registerBlock(client.getCurrentURI());
 			mc.displayGuiScreen(GuiDisconnected.createRateLimitKick(scr));
 		}else if(errorCode == HandshakePacketTypes.SERVER_ERROR_RATELIMIT_LOCKED) {
-			RateLimitTracker.registerLockOut(PlatformNetworking.getCurrentURI());
+			RateLimitTracker.registerLockOut(client.getCurrentURI());
 			mc.displayGuiScreen(GuiDisconnected.createRateLimitKick(scr));
 		}else if(errorCode == HandshakePacketTypes.SERVER_ERROR_CUSTOM_MESSAGE) {
 			mc.displayGuiScreen(new GuiDisconnected(scr, "connect.failed", IChatComponent.Serializer.jsonToComponent(errStr)));
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/socket/EaglercraftNetworkManager.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/socket/EaglercraftNetworkManager.java
index 1fe7e649..86959d94 100644
--- a/sources/main/java/net/lax1dude/eaglercraft/v1_8/socket/EaglercraftNetworkManager.java
+++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/socket/EaglercraftNetworkManager.java
@@ -1,24 +1,19 @@
 package net.lax1dude.eaglercraft.v1_8.socket;
 
 import java.io.IOException;
-import java.util.List;
 
 import net.lax1dude.eaglercraft.v1_8.internal.EnumEaglerConnectionState;
-import net.lax1dude.eaglercraft.v1_8.internal.PlatformNetworking;
 import net.lax1dude.eaglercraft.v1_8.log4j.LogManager;
 import net.lax1dude.eaglercraft.v1_8.log4j.Logger;
-import net.lax1dude.eaglercraft.v1_8.netty.ByteBuf;
 import net.lax1dude.eaglercraft.v1_8.netty.Unpooled;
 import net.minecraft.network.EnumConnectionState;
-import net.minecraft.network.EnumPacketDirection;
 import net.minecraft.network.INetHandler;
 import net.minecraft.network.Packet;
 import net.minecraft.network.PacketBuffer;
-import net.minecraft.util.ChatComponentTranslation;
 import net.minecraft.util.IChatComponent;
 
 /**
- * Copyright (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved.
+ * Copyright (c) 2022-2024 lax1dude. All Rights Reserved.
  * 
  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
@@ -32,7 +27,7 @@ import net.minecraft.util.IChatComponent;
  * POSSIBILITY OF SUCH DAMAGE.
  * 
  */
-public class EaglercraftNetworkManager {
+public abstract class EaglercraftNetworkManager {
 	
 	protected final String address;
 	protected INetHandler nethandler = null;
@@ -63,103 +58,23 @@ public class EaglercraftNetworkManager {
 		return pluginVersion;
 	}
 	
-	public void connect() {
-		PlatformNetworking.startPlayConnection(address);
+	public abstract void connect();
+	
+	public abstract EnumEaglerConnectionState getConnectStatus();
+	
+	public String getAddress() {
+		return address;
 	}
 	
-	public EnumEaglerConnectionState getConnectStatus() {
-		return PlatformNetworking.playConnectionState();
-	}
-	
-	public void closeChannel(IChatComponent reason) {
-		PlatformNetworking.playDisconnect();
-		if(nethandler != null) {
-			nethandler.onDisconnect(reason);
-		}
-		clientDisconnected = true;
-	}
+	public abstract void closeChannel(IChatComponent reason);
 	
 	public void setConnectionState(EnumConnectionState state) {
 		packetState = state;
 	}
 	
-	public void processReceivedPackets() throws IOException {
-		if(nethandler == null) return;
-		List<byte[]> pkts = PlatformNetworking.readAllPacket();
+	public abstract void processReceivedPackets() throws IOException;
 
-		if(pkts == null) {
-			return;
-		}
-
-		for(int i = 0, l = pkts.size(); i < l; ++i) {
-			byte[] next = pkts.get(i);
-			++debugPacketCounter;
-			try {
-				ByteBuf nettyBuffer = Unpooled.buffer(next, next.length);
-				nettyBuffer.writerIndex(next.length);
-				PacketBuffer input = new PacketBuffer(nettyBuffer);
-				int pktId = input.readVarIntFromBuffer();
-				
-				Packet pkt;
-				try {
-					pkt = packetState.getPacket(EnumPacketDirection.CLIENTBOUND, pktId);
-				}catch(IllegalAccessException | InstantiationException ex) {
-					throw new IOException("Recieved a packet with type " + pktId + " which is invalid!");
-				}
-				
-				if(pkt == null) {
-					throw new IOException("Recieved packet type " + pktId + " which is undefined in state " + packetState);
-				}
-				
-				try {
-					pkt.readPacketData(input);
-				}catch(Throwable t) {
-					throw new IOException("Failed to read packet type '" + pkt.getClass().getSimpleName() + "'", t);
-				}
-				
-				try {
-					pkt.processPacket(nethandler);
-				}catch(Throwable t) {
-					logger.error("Failed to process {}! It'll be skipped for debug purposes.", pkt.getClass().getSimpleName());
-					logger.error(t);
-				}
-				
-			}catch(Throwable t) {
-				logger.error("Failed to process websocket frame {}! It'll be skipped for debug purposes.", debugPacketCounter);
-				logger.error(t);
-			}
-		}
-	}
-
-	public void sendPacket(Packet pkt) {
-		if(!isChannelOpen()) {
-			logger.error("Packet was sent on a closed connection: {}", pkt.getClass().getSimpleName());
-			return;
-		}
-		
-		int i;
-		try {
-			i = packetState.getPacketId(EnumPacketDirection.SERVERBOUND, pkt);
-		}catch(Throwable t) {
-			logger.error("Incorrect packet for state: {}", pkt.getClass().getSimpleName());
-			return;
-		}
-		
-		temporaryBuffer.clear();
-		temporaryBuffer.writeVarIntToBuffer(i);
-		try {
-			pkt.writePacketData(temporaryBuffer);
-		}catch(IOException ex) {
-			logger.error("Failed to write packet {}!", pkt.getClass().getSimpleName());
-			return;
-		}
-		
-		int len = temporaryBuffer.writerIndex();
-		byte[] bytes = new byte[len];
-		temporaryBuffer.getBytes(0, bytes);
-		
-		PlatformNetworking.writePlayPacket(bytes);
-	}
+	public abstract void sendPacket(Packet pkt);
 	
 	public void setNetHandler(INetHandler nethandler) {
 		this.nethandler = nethandler;
@@ -181,18 +96,7 @@ public class EaglercraftNetworkManager {
 		throw new CompressionNotSupportedException();
 	}
 
-	public boolean checkDisconnected() {
-		if(PlatformNetworking.playConnectionState().isClosed()) {
-			try {
-				processReceivedPackets(); // catch kick message
-			} catch (IOException e) {
-			}
-			doClientDisconnect(new ChatComponentTranslation("disconnect.endOfStream"));
-			return true;
-		}else {
-			return false;
-		}
-	}
+	public abstract boolean checkDisconnected();
 	
 	protected boolean clientDisconnected = false;
 	
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/socket/GuiHandshakeApprove.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/socket/GuiHandshakeApprove.java
index 1783f85e..19882b92 100644
--- a/sources/main/java/net/lax1dude/eaglercraft/v1_8/socket/GuiHandshakeApprove.java
+++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/socket/GuiHandshakeApprove.java
@@ -46,7 +46,7 @@ public class GuiHandshakeApprove extends GuiScreen {
 	public void initGui() {
 		this.buttonList.clear();
 		titleString = I18n.format("handshakeApprove." + message + ".title");
-		bodyLines = new ArrayList();
+		bodyLines = new ArrayList<>();
 		int i = 0;
 		boolean wasNull = true;
 		while(true) {
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/socket/RateLimitTracker.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/socket/RateLimitTracker.java
index 659809b1..97786ca3 100644
--- a/sources/main/java/net/lax1dude/eaglercraft/v1_8/socket/RateLimitTracker.java
+++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/socket/RateLimitTracker.java
@@ -4,6 +4,8 @@ import java.util.HashMap;
 import java.util.Iterator;
 import java.util.Map;
 
+import net.lax1dude.eaglercraft.v1_8.EagRuntime;
+
 /**
  * Copyright (c) 2022-2023 lax1dude, ayunami2000. All Rights Reserved.
  * 
@@ -23,12 +25,12 @@ public class RateLimitTracker {
 
 	private static long lastTickUpdate = 0l;
 
-	private static final Map<String, Long> blocks = new HashMap();
-	private static final Map<String, Long> lockout = new HashMap();
+	private static final Map<String, Long> blocks = new HashMap<>();
+	private static final Map<String, Long> lockout = new HashMap<>();
 
 	public static boolean isLockedOut(String addr) {
 		Long lockoutStatus = lockout.get(addr);
-		return lockoutStatus != null && System.currentTimeMillis() - lockoutStatus.longValue() < 300000l;
+		return lockoutStatus != null && EagRuntime.steadyTimeMillis() - lockoutStatus.longValue() < 300000l;
 	}
 
 	public static boolean isProbablyLockedOut(String addr) {
@@ -36,17 +38,17 @@ public class RateLimitTracker {
 	}
 
 	public static void registerBlock(String addr) {
-		blocks.put(addr, System.currentTimeMillis());
+		blocks.put(addr, EagRuntime.steadyTimeMillis());
 	}
 
 	public static void registerLockOut(String addr) {
-		long millis = System.currentTimeMillis();
+		long millis = EagRuntime.steadyTimeMillis();
 		blocks.put(addr, millis);
 		lockout.put(addr, millis);
 	}
 
 	public static void tick() {
-		long millis = System.currentTimeMillis();
+		long millis = EagRuntime.steadyTimeMillis();
 		if(millis - lastTickUpdate > 5000l) {
 			lastTickUpdate = millis;
 			Iterator<Long> blocksItr = blocks.values().iterator();
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/socket/ServerQueryDispatch.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/socket/ServerQueryDispatch.java
index dceedc1a..bfff0c4b 100644
--- a/sources/main/java/net/lax1dude/eaglercraft/v1_8/socket/ServerQueryDispatch.java
+++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/socket/ServerQueryDispatch.java
@@ -1,6 +1,7 @@
 package net.lax1dude.eaglercraft.v1_8.socket;
 
 import net.lax1dude.eaglercraft.v1_8.internal.IServerQuery;
+import net.lax1dude.eaglercraft.v1_8.internal.IWebSocketClient;
 import net.lax1dude.eaglercraft.v1_8.internal.PlatformNetworking;
 import net.lax1dude.eaglercraft.v1_8.log4j.LogManager;
 import net.lax1dude.eaglercraft.v1_8.log4j.Logger;
@@ -26,7 +27,8 @@ public class ServerQueryDispatch {
 
 	public static IServerQuery sendServerQuery(String uri, String accept) {
 		logger.info("Sending {} query to: \"{}\"", accept, uri);
-		return PlatformNetworking.sendServerQuery(uri, accept);
+		IWebSocketClient sockClient = PlatformNetworking.openWebSocket(uri);
+		return sockClient != null ? new ServerQueryImpl(sockClient, accept) : null;
 	}
 
 }
diff --git a/sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/teavm/TeaVMServerQuery.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/socket/ServerQueryImpl.java
similarity index 64%
rename from sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/teavm/TeaVMServerQuery.java
rename to sources/main/java/net/lax1dude/eaglercraft/v1_8/socket/ServerQueryImpl.java
index 550078cb..19c37156 100644
--- a/sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/teavm/TeaVMServerQuery.java
+++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/socket/ServerQueryImpl.java
@@ -1,25 +1,22 @@
-package net.lax1dude.eaglercraft.v1_8.internal.teavm;
+package net.lax1dude.eaglercraft.v1_8.socket;
 
 import java.util.LinkedList;
 import java.util.List;
 
 import org.json.JSONObject;
-import org.teavm.jso.JSBody;
-import org.teavm.jso.JSObject;
-import org.teavm.jso.dom.events.Event;
-import org.teavm.jso.dom.events.EventListener;
-import org.teavm.jso.dom.events.MessageEvent;
-import org.teavm.jso.typedarrays.ArrayBuffer;
-import org.teavm.jso.websocket.WebSocket;
 
+import net.lax1dude.eaglercraft.v1_8.internal.EnumEaglerConnectionState;
 import net.lax1dude.eaglercraft.v1_8.internal.EnumServerRateLimit;
 import net.lax1dude.eaglercraft.v1_8.internal.IServerQuery;
+import net.lax1dude.eaglercraft.v1_8.internal.IWebSocketClient;
+import net.lax1dude.eaglercraft.v1_8.internal.IWebSocketFrame;
+import net.lax1dude.eaglercraft.v1_8.internal.PlatformRuntime;
 import net.lax1dude.eaglercraft.v1_8.internal.QueryResponse;
 import net.lax1dude.eaglercraft.v1_8.log4j.LogManager;
 import net.lax1dude.eaglercraft.v1_8.log4j.Logger;
 
 /**
- * Copyright (c) 2022 lax1dude. All Rights Reserved.
+ * Copyright (c) 2022-2024 lax1dude. All Rights Reserved.
  * 
  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
@@ -33,58 +30,48 @@ import net.lax1dude.eaglercraft.v1_8.log4j.Logger;
  * POSSIBILITY OF SUCH DAMAGE.
  * 
  */
-public class TeaVMServerQuery implements IServerQuery {
+class ServerQueryImpl implements IServerQuery {
 
 	public static final Logger logger = LogManager.getLogger("WebSocketQuery");
 
-	private final List<QueryResponse> queryResponses = new LinkedList();
-	private final List<byte[]> queryResponsesBytes = new LinkedList();
+	private final List<QueryResponse> queryResponses = new LinkedList<>();
+	private final List<byte[]> queryResponsesBytes = new LinkedList<>();
 
+	protected final IWebSocketClient websocketClient;
 	protected final String uri;
 	protected final String accept;
-	protected final WebSocket sock;
+	protected boolean hasSentAccept = false;
 	protected boolean open = true;
 	protected boolean alive = false;
 	protected long pingStart = -1l;
 	protected long pingTimer = -1l;
 	private EnumServerRateLimit rateLimit = EnumServerRateLimit.OK;
 
-	public TeaVMServerQuery(String uri, String accept) {
-		this.uri = uri;
+	ServerQueryImpl(IWebSocketClient websocketClient, String accept) {
+		this.websocketClient = websocketClient;
+		this.uri = websocketClient.getCurrentURI();
 		this.accept = accept;
-		this.sock = WebSocket.create(uri);
-		initHandlers();
 	}
 
-	@JSBody(params = { "obj" }, script = "return typeof obj === \"string\";")
-	private static native boolean isString(JSObject obj);
-
-	protected void initHandlers() {
-		sock.setBinaryType("arraybuffer");
-		TeaVMUtils.addEventListener(sock, "open", new EventListener<Event>() {
-			@Override
-			public void handleEvent(Event evt) {
-				sock.send("Accept: " + accept);
-			}
-		});
-		TeaVMUtils.addEventListener(sock, "close", new EventListener<Event>() {
-			@Override
-			public void handleEvent(Event evt) {
-				open = false;
-			}
-		});
-		TeaVMUtils.addEventListener(sock, "message", new EventListener<MessageEvent>() {
-			@Override
-			public void handleEvent(MessageEvent evt) {
+	@Override
+	public void update() {
+		if(!hasSentAccept && websocketClient.getState() == EnumEaglerConnectionState.CONNECTED) {
+			hasSentAccept = true;
+			websocketClient.send("Accept: " + accept);
+		}
+		List<IWebSocketFrame> lst = websocketClient.getNextFrames();
+		if(lst != null) {
+			for(int i = 0, l = lst.size(); i < l; ++i) {
+				IWebSocketFrame frame = lst.get(i);
 				alive = true;
 				if(pingTimer == -1) {
-					pingTimer = System.currentTimeMillis() - pingStart;
+					pingTimer = PlatformRuntime.steadyTimeMillis() - pingStart;
 					if(pingTimer < 1) {
 						pingTimer = 1;
 					}
 				}
-				if(isString(evt.getData())) {
-					String str = evt.getDataAsString();
+				if(frame.isString()) {
+					String str = frame.getString();
 					if(str.equalsIgnoreCase("BLOCKED")) {
 						logger.error("Reached full IP ratelimit for {}!", uri);
 						rateLimit = EnumServerRateLimit.BLOCKED;
@@ -104,45 +91,33 @@ public class TeaVMServerQuery implements IServerQuery {
 							logger.error("Reached query ratelimit lockout for {}!", uri);
 							rateLimit = EnumServerRateLimit.LOCKED_OUT;
 						}else {
-							QueryResponse response = new QueryResponse(obj, pingTimer);
-							synchronized(queryResponses) {
-								queryResponses.add(response);
-							}
+							queryResponses.add(new QueryResponse(obj, pingTimer));
 						}
 					}catch(Throwable t) {
 						logger.error("Exception thrown parsing websocket query response from \"" + uri + "\"!");
 						logger.error(t);
 					}
 				}else {
-					synchronized(queryResponsesBytes) {
-						queryResponsesBytes.add(TeaVMUtils.wrapByteArrayBuffer(evt.getDataAsArray()));
-					}
+					queryResponsesBytes.add(frame.getByteArray());
 				}
 			}
-		});
-		TeaVMUtils.addEventListener(sock, "error", new EventListener<Event>() {
-			@Override
-			public void handleEvent(Event evt) {
-				sock.close();
-				open = false;
-			}
-		});
+		}
+		if(websocketClient.isClosed()) {
+			open = false;
+		}
 	}
 
 	@Override
 	public void send(String str) {
-		if(open) {
-			sock.send(str);
+		if(websocketClient.getState() == EnumEaglerConnectionState.CONNECTED) {
+			websocketClient.send(str);
 		}
 	}
 
-	@JSBody(params = { "sock", "buffer" }, script = "sock.send(buffer);")
-	private static native void nativeBinarySend(WebSocket sock, ArrayBuffer buffer);
-
 	@Override
 	public void send(byte[] bytes) {
-		if(open) {
-			nativeBinarySend(sock, TeaVMUtils.unwrapArrayBuffer(bytes));
+		if(websocketClient.getState() == EnumEaglerConnectionState.CONNECTED) {
+			websocketClient.send(bytes);
 		}
 	}
 
@@ -192,7 +167,7 @@ public class TeaVMServerQuery implements IServerQuery {
 	public void close() {
 		if(open) {
 			open = false;
-			sock.close();
+			websocketClient.close();
 		}
 	}
 
@@ -200,4 +175,5 @@ public class TeaVMServerQuery implements IServerQuery {
 	public EnumServerRateLimit getRateLimit() {
 		return rateLimit;
 	}
+
 }
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/socket/WebSocketNetworkManager.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/socket/WebSocketNetworkManager.java
new file mode 100644
index 00000000..fb251f6f
--- /dev/null
+++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/socket/WebSocketNetworkManager.java
@@ -0,0 +1,152 @@
+package net.lax1dude.eaglercraft.v1_8.socket;
+
+import java.io.IOException;
+import java.util.List;
+
+import net.lax1dude.eaglercraft.v1_8.internal.EnumEaglerConnectionState;
+import net.lax1dude.eaglercraft.v1_8.internal.IWebSocketClient;
+import net.lax1dude.eaglercraft.v1_8.internal.IWebSocketFrame;
+import net.lax1dude.eaglercraft.v1_8.netty.ByteBuf;
+import net.lax1dude.eaglercraft.v1_8.netty.Unpooled;
+import net.minecraft.network.EnumPacketDirection;
+import net.minecraft.network.Packet;
+import net.minecraft.network.PacketBuffer;
+import net.minecraft.util.ChatComponentTranslation;
+import net.minecraft.util.IChatComponent;
+
+/**
+ * Copyright (c) 2022-2024 lax1dude. All Rights Reserved.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ * 
+ */
+public class WebSocketNetworkManager extends EaglercraftNetworkManager {
+
+	protected final IWebSocketClient webSocketClient;
+
+	public WebSocketNetworkManager(IWebSocketClient webSocketClient) {
+		super(webSocketClient.getCurrentURI());
+		this.webSocketClient = webSocketClient;
+	}
+
+	public void connect() {
+	}
+
+	public EnumEaglerConnectionState getConnectStatus() {
+		return webSocketClient.getState();
+	}
+
+	public void closeChannel(IChatComponent reason) {
+		webSocketClient.close();
+		if(nethandler != null) {
+			nethandler.onDisconnect(reason);
+		}
+		clientDisconnected = true;
+	}
+
+	public void processReceivedPackets() throws IOException {
+		if(nethandler == null) return;
+		if(webSocketClient.availableStringFrames() > 0) {
+			logger.warn("discarding {} string frames recieved on a binary connection", webSocketClient.availableStringFrames());
+			webSocketClient.clearStringFrames();
+		}
+		List<IWebSocketFrame> pkts = webSocketClient.getNextBinaryFrames();
+
+		if(pkts == null) {
+			return;
+		}
+
+		for(int i = 0, l = pkts.size(); i < l; ++i) {
+			IWebSocketFrame next = pkts.get(i);
+			++debugPacketCounter;
+			try {
+				byte[] asByteArray = next.getByteArray();
+				ByteBuf nettyBuffer = Unpooled.buffer(asByteArray, asByteArray.length);
+				nettyBuffer.writerIndex(asByteArray.length);
+				PacketBuffer input = new PacketBuffer(nettyBuffer);
+				int pktId = input.readVarIntFromBuffer();
+				
+				Packet pkt;
+				try {
+					pkt = packetState.getPacket(EnumPacketDirection.CLIENTBOUND, pktId);
+				}catch(IllegalAccessException | InstantiationException ex) {
+					throw new IOException("Recieved a packet with type " + pktId + " which is invalid!");
+				}
+				
+				if(pkt == null) {
+					throw new IOException("Recieved packet type " + pktId + " which is undefined in state " + packetState);
+				}
+				
+				try {
+					pkt.readPacketData(input);
+				}catch(Throwable t) {
+					throw new IOException("Failed to read packet type '" + pkt.getClass().getSimpleName() + "'", t);
+				}
+				
+				try {
+					pkt.processPacket(nethandler);
+				}catch(Throwable t) {
+					logger.error("Failed to process {}! It'll be skipped for debug purposes.", pkt.getClass().getSimpleName());
+					logger.error(t);
+				}
+				
+			}catch(Throwable t) {
+				logger.error("Failed to process websocket frame {}! It'll be skipped for debug purposes.", debugPacketCounter);
+				logger.error(t);
+			}
+		}
+	}
+
+	public void sendPacket(Packet pkt) {
+		if(!isChannelOpen()) {
+			logger.error("Packet was sent on a closed connection: {}", pkt.getClass().getSimpleName());
+			return;
+		}
+		
+		int i;
+		try {
+			i = packetState.getPacketId(EnumPacketDirection.SERVERBOUND, pkt);
+		}catch(Throwable t) {
+			logger.error("Incorrect packet for state: {}", pkt.getClass().getSimpleName());
+			return;
+		}
+		
+		temporaryBuffer.clear();
+		temporaryBuffer.writeVarIntToBuffer(i);
+		try {
+			pkt.writePacketData(temporaryBuffer);
+		}catch(IOException ex) {
+			logger.error("Failed to write packet {}!", pkt.getClass().getSimpleName());
+			return;
+		}
+		
+		int len = temporaryBuffer.writerIndex();
+		byte[] bytes = new byte[len];
+		temporaryBuffer.getBytes(0, bytes);
+		
+		webSocketClient.send(bytes);
+	}
+
+	public boolean checkDisconnected() {
+		if(webSocketClient.isClosed()) {
+			try {
+				processReceivedPackets(); // catch kick message
+			} catch (IOException e) {
+			}
+			doClientDisconnect(new ChatComponentTranslation("disconnect.endOfStream"));
+			return true;
+		}else {
+			return false;
+		}
+	}
+
+}
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/socket/protocol/client/ClientV3MessageHandler.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/socket/protocol/client/ClientV3MessageHandler.java
new file mode 100644
index 00000000..039c8646
--- /dev/null
+++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/socket/protocol/client/ClientV3MessageHandler.java
@@ -0,0 +1,130 @@
+package net.lax1dude.eaglercraft.v1_8.socket.protocol.client;
+
+import java.nio.charset.StandardCharsets;
+
+import net.lax1dude.eaglercraft.v1_8.EagRuntime;
+import net.lax1dude.eaglercraft.v1_8.EaglercraftUUID;
+import net.lax1dude.eaglercraft.v1_8.profile.SkinModel;
+import net.lax1dude.eaglercraft.v1_8.socket.protocol.pkt.GameMessageHandler;
+import net.lax1dude.eaglercraft.v1_8.socket.protocol.pkt.server.*;
+import net.lax1dude.eaglercraft.v1_8.update.UpdateService;
+import net.lax1dude.eaglercraft.v1_8.voice.VoiceClientController;
+import net.minecraft.client.Minecraft;
+import net.minecraft.client.network.NetHandlerPlayClient;
+
+/**
+ * Copyright (c) 2024 lax1dude. All Rights Reserved.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ * 
+ */
+public class ClientV3MessageHandler implements GameMessageHandler {
+
+	private final NetHandlerPlayClient netHandler;
+
+	public ClientV3MessageHandler(NetHandlerPlayClient netHandler) {
+		this.netHandler = netHandler;
+	}
+
+	public void handleServer(SPacketEnableFNAWSkinsEAG packet) {
+		netHandler.currentFNAWSkinAllowedState = packet.enableSkins;
+		netHandler.currentFNAWSkinForcedState = packet.enableSkins;
+		Minecraft.getMinecraft().getRenderManager().setEnableFNAWSkins(netHandler.currentFNAWSkinForcedState
+				|| (netHandler.currentFNAWSkinAllowedState && Minecraft.getMinecraft().gameSettings.enableFNAWSkins));
+	}
+
+	public void handleServer(SPacketOtherCapeCustomEAG packet) {
+		netHandler.getCapeCache().cacheCapeCustom(new EaglercraftUUID(packet.uuidMost, packet.uuidLeast),
+				packet.customCape);
+	}
+
+	public void handleServer(SPacketOtherCapePresetEAG packet) {
+		netHandler.getCapeCache().cacheCapePreset(new EaglercraftUUID(packet.uuidMost, packet.uuidLeast),
+				packet.presetCape);
+	}
+
+	public void handleServer(SPacketOtherSkinCustomV3EAG packet) {
+		EaglercraftUUID responseUUID = new EaglercraftUUID(packet.uuidMost, packet.uuidLeast);
+		SkinModel modelId;
+		if(packet.modelID == (byte)0xFF) {
+			modelId = this.netHandler.getSkinCache().getRequestedSkinType(responseUUID);
+		}else {
+			modelId = SkinModel.getModelFromId(packet.modelID & 0x7F);
+			if((packet.modelID & 0x80) != 0 && modelId.sanitize) {
+				modelId = SkinModel.STEVE;
+			}
+		}
+		if(modelId.highPoly != null) {
+			modelId = SkinModel.STEVE;
+		}
+		this.netHandler.getSkinCache().cacheSkinCustom(responseUUID, packet.customSkin, modelId);
+	}
+
+	public void handleServer(SPacketOtherSkinPresetEAG packet) {
+		this.netHandler.getSkinCache().cacheSkinPreset(new EaglercraftUUID(packet.uuidMost, packet.uuidLeast),
+				packet.presetSkin);
+	}
+
+	public void handleServer(SPacketUpdateCertEAG packet) {
+		if (EagRuntime.getConfiguration().allowUpdateSvc()) {
+			UpdateService.addCertificateToSet(packet.updateCert);
+		}
+	}
+
+	public void handleServer(SPacketVoiceSignalAllowedEAG packet) {
+		if (VoiceClientController.isClientSupported()) {
+			VoiceClientController.handleVoiceSignalPacketTypeAllowed(packet.allowed, packet.iceServers);
+		}
+	}
+
+	public void handleServer(SPacketVoiceSignalConnectV3EAG packet) {
+		if (VoiceClientController.isClientSupported()) {
+			if (packet.isAnnounceType) {
+				VoiceClientController.handleVoiceSignalPacketTypeConnectAnnounce(
+						new EaglercraftUUID(packet.uuidMost, packet.uuidLeast));
+			} else {
+				VoiceClientController.handleVoiceSignalPacketTypeConnect(
+						new EaglercraftUUID(packet.uuidMost, packet.uuidLeast), packet.offer);
+			}
+		}
+	}
+
+	public void handleServer(SPacketVoiceSignalDescEAG packet) {
+		if (VoiceClientController.isClientSupported()) {
+			VoiceClientController.handleVoiceSignalPacketTypeDescription(
+					new EaglercraftUUID(packet.uuidMost, packet.uuidLeast),
+					new String(packet.desc, StandardCharsets.UTF_8));
+		}
+	}
+
+	public void handleServer(SPacketVoiceSignalDisconnectPeerEAG packet) {
+		if (VoiceClientController.isClientSupported()) {
+			VoiceClientController.handleVoiceSignalPacketTypeDisconnect(
+					new EaglercraftUUID(packet.uuidMost, packet.uuidLeast));
+		}
+	}
+
+	public void handleServer(SPacketVoiceSignalGlobalEAG packet) {
+		if (VoiceClientController.isClientSupported()) {
+			VoiceClientController.handleVoiceSignalPacketTypeGlobalNew(packet.users);
+		}
+	}
+
+	public void handleServer(SPacketVoiceSignalICEEAG packet) {
+		if (VoiceClientController.isClientSupported()) {
+			VoiceClientController.handleVoiceSignalPacketTypeICECandidate(
+					new EaglercraftUUID(packet.uuidMost, packet.uuidLeast),
+					new String(packet.ice, StandardCharsets.UTF_8));
+		}
+	}
+
+}
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/socket/protocol/client/ClientV4MessageHandler.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/socket/protocol/client/ClientV4MessageHandler.java
new file mode 100644
index 00000000..eb52fbe8
--- /dev/null
+++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/socket/protocol/client/ClientV4MessageHandler.java
@@ -0,0 +1,222 @@
+package net.lax1dude.eaglercraft.v1_8.socket.protocol.client;
+
+import java.nio.charset.StandardCharsets;
+
+import net.lax1dude.eaglercraft.v1_8.ClientUUIDLoadingCache;
+import net.lax1dude.eaglercraft.v1_8.EagRuntime;
+import net.lax1dude.eaglercraft.v1_8.EaglercraftUUID;
+import net.lax1dude.eaglercraft.v1_8.PauseMenuCustomizeState;
+import net.lax1dude.eaglercraft.v1_8.cookie.ServerCookieDataStore;
+import net.lax1dude.eaglercraft.v1_8.profile.EaglerProfile;
+import net.lax1dude.eaglercraft.v1_8.profile.SkinModel;
+import net.lax1dude.eaglercraft.v1_8.socket.protocol.pkt.GameMessageHandler;
+import net.lax1dude.eaglercraft.v1_8.socket.protocol.pkt.server.*;
+import net.lax1dude.eaglercraft.v1_8.socket.protocol.util.SkinPacketVersionCache;
+import net.lax1dude.eaglercraft.v1_8.update.UpdateService;
+import net.lax1dude.eaglercraft.v1_8.voice.VoiceClientController;
+import net.lax1dude.eaglercraft.v1_8.webview.ServerInfoCache;
+import net.lax1dude.eaglercraft.v1_8.webview.WebViewOverlayController;
+import net.minecraft.client.Minecraft;
+import net.minecraft.client.network.NetHandlerPlayClient;
+
+/**
+ * Copyright (c) 2024 lax1dude. All Rights Reserved.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ * 
+ */
+public class ClientV4MessageHandler implements GameMessageHandler {
+
+	private final NetHandlerPlayClient netHandler;
+
+	public ClientV4MessageHandler(NetHandlerPlayClient netHandler) {
+		this.netHandler = netHandler;
+	}
+
+	public void handleServer(SPacketEnableFNAWSkinsEAG packet) {
+		netHandler.currentFNAWSkinAllowedState = packet.enableSkins;
+		netHandler.currentFNAWSkinForcedState = packet.force;
+		Minecraft.getMinecraft().getRenderManager().setEnableFNAWSkins(netHandler.currentFNAWSkinForcedState
+				|| (netHandler.currentFNAWSkinAllowedState && Minecraft.getMinecraft().gameSettings.enableFNAWSkins));
+	}
+
+	public void handleServer(SPacketOtherCapeCustomEAG packet) {
+		netHandler.getCapeCache().cacheCapeCustom(new EaglercraftUUID(packet.uuidMost, packet.uuidLeast),
+				packet.customCape);
+	}
+
+	public void handleServer(SPacketOtherCapePresetEAG packet) {
+		netHandler.getCapeCache().cacheCapePreset(new EaglercraftUUID(packet.uuidMost, packet.uuidLeast),
+				packet.presetCape);
+	}
+
+	public void handleServer(SPacketOtherSkinCustomV4EAG packet) {
+		EaglercraftUUID responseUUID = new EaglercraftUUID(packet.uuidMost, packet.uuidLeast);
+		SkinModel modelId;
+		if(packet.modelID == (byte)0xFF) {
+			modelId = this.netHandler.getSkinCache().getRequestedSkinType(responseUUID);
+		}else {
+			modelId = SkinModel.getModelFromId(packet.modelID & 0x7F);
+			if((packet.modelID & 0x80) != 0 && modelId.sanitize) {
+				modelId = SkinModel.STEVE;
+			}
+		}
+		if(modelId.highPoly != null) {
+			modelId = SkinModel.STEVE;
+		}
+		this.netHandler.getSkinCache().cacheSkinCustom(responseUUID, SkinPacketVersionCache.convertToV3Raw(packet.customSkin), modelId);
+	}
+
+	public void handleServer(SPacketOtherSkinPresetEAG packet) {
+		this.netHandler.getSkinCache().cacheSkinPreset(new EaglercraftUUID(packet.uuidMost, packet.uuidLeast), packet.presetSkin);
+	}
+
+	public void handleServer(SPacketUpdateCertEAG packet) {
+		if (EagRuntime.getConfiguration().allowUpdateSvc()) {
+			UpdateService.addCertificateToSet(packet.updateCert);
+		}
+	}
+
+	public void handleServer(SPacketVoiceSignalAllowedEAG packet) {
+		if (VoiceClientController.isClientSupported()) {
+			VoiceClientController.handleVoiceSignalPacketTypeAllowed(packet.allowed, packet.iceServers);
+		}
+	}
+
+	public void handleServer(SPacketVoiceSignalConnectV4EAG packet) {
+		if (VoiceClientController.isClientSupported()) {
+			VoiceClientController.handleVoiceSignalPacketTypeConnect(new EaglercraftUUID(packet.uuidMost, packet.uuidLeast), packet.offer);
+		}
+	}
+
+	public void handleServer(SPacketVoiceSignalConnectAnnounceV4EAG packet) {
+		if (VoiceClientController.isClientSupported()) {
+			VoiceClientController.handleVoiceSignalPacketTypeConnectAnnounce(new EaglercraftUUID(packet.uuidMost, packet.uuidLeast));
+		}
+	}
+
+	public void handleServer(SPacketVoiceSignalDescEAG packet) {
+		if (VoiceClientController.isClientSupported()) {
+			VoiceClientController.handleVoiceSignalPacketTypeDescription(
+					new EaglercraftUUID(packet.uuidMost, packet.uuidLeast),
+					new String(packet.desc, StandardCharsets.UTF_8));
+		}
+	}
+
+	public void handleServer(SPacketVoiceSignalDisconnectPeerEAG packet) {
+		if (VoiceClientController.isClientSupported()) {
+			VoiceClientController.handleVoiceSignalPacketTypeDisconnect(new EaglercraftUUID(packet.uuidMost, packet.uuidLeast));
+		}
+	}
+
+	public void handleServer(SPacketVoiceSignalGlobalEAG packet) {
+		if (VoiceClientController.isClientSupported()) {
+			VoiceClientController.handleVoiceSignalPacketTypeGlobalNew(packet.users);
+		}
+	}
+
+	public void handleServer(SPacketVoiceSignalICEEAG packet) {
+		if (VoiceClientController.isClientSupported()) {
+			VoiceClientController.handleVoiceSignalPacketTypeICECandidate(
+					new EaglercraftUUID(packet.uuidMost, packet.uuidLeast),
+					new String(packet.ice, StandardCharsets.UTF_8));
+		}
+	}
+
+	public void handleServer(SPacketForceClientSkinPresetV4EAG packet) {
+		EaglerProfile.handleForceSkinPreset(packet.presetSkin);
+	}
+
+	public void handleServer(SPacketForceClientSkinCustomV4EAG packet) {
+		EaglerProfile.handleForceSkinCustom(packet.modelID, SkinPacketVersionCache.convertToV3Raw(packet.customSkin));
+	}
+
+	public void handleServer(SPacketSetServerCookieV4EAG packet) {
+		if(!netHandler.isClientInEaglerSingleplayerOrLAN() && Minecraft.getMinecraft().getCurrentServerData().enableCookies) {
+			ServerCookieDataStore.saveCookie(netHandler.getNetworkManager().getAddress(), packet.expires, packet.data,
+					packet.revokeQuerySupported, packet.saveCookieToDisk);
+		}
+	}
+
+	public void handleServer(SPacketRedirectClientV4EAG packet) {
+		Minecraft.getMinecraft().handleReconnectPacket(packet.redirectURI);
+	}
+
+	public void handleServer(SPacketOtherPlayerClientUUIDV4EAG packet) {
+		ClientUUIDLoadingCache.handleResponse(packet.requestId, new EaglercraftUUID(packet.clientUUIDMost, packet.clientUUIDLeast));
+	}
+
+	public void handleServer(SPacketForceClientCapePresetV4EAG packet) {
+		EaglerProfile.handleForceCapePreset(packet.presetCape);
+	}
+
+	public void handleServer(SPacketForceClientCapeCustomV4EAG packet) {
+		EaglerProfile.handleForceCapeCustom(packet.customCape);
+	}
+
+	public void handleServer(SPacketInvalidatePlayerCacheV4EAG packet) {
+		if(packet.players != null && packet.players.size() > 0) {
+			for(SPacketInvalidatePlayerCacheV4EAG.InvalidateRequest req : packet.players) {
+				EaglercraftUUID uuid = new EaglercraftUUID(req.uuidMost, req.uuidLeast);
+				if(req.invalidateSkin) {
+					this.netHandler.getSkinCache().handleInvalidate(uuid);
+				}
+				if(req.invalidateCape) {
+					this.netHandler.getCapeCache().handleInvalidate(uuid);
+				}
+			}
+		}
+	}
+
+	public void handleServer(SPacketUnforceClientV4EAG packet) {
+		if(packet.resetSkin) {
+			EaglerProfile.isServerSkinOverride = false;
+		}
+		if(packet.resetCape) {
+			EaglerProfile.isServerCapeOverride = false;
+		}
+		if(packet.resetFNAW) {
+			netHandler.currentFNAWSkinForcedState = false;
+			Minecraft.getMinecraft().getRenderManager().setEnableFNAWSkins(
+					netHandler.currentFNAWSkinAllowedState && Minecraft.getMinecraft().gameSettings.enableFNAWSkins);
+		}
+	}
+
+	public void handleServer(SPacketCustomizePauseMenuV4EAG packet) {
+		PauseMenuCustomizeState.loadPacket(packet);
+	}
+
+	public void handleServer(SPacketServerInfoDataChunkV4EAG packet) {
+		ServerInfoCache.handleChunk(packet);
+	}
+
+	public void handleServer(SPacketWebViewMessageV4EAG packet) {
+		WebViewOverlayController.handleMessagePacket(packet);
+	}
+
+	public void handleServer(SPacketNotifIconsRegisterV4EAG packet) {
+		netHandler.getNotifManager().processPacketAddIcons(packet);
+	}
+
+	public void handleServer(SPacketNotifIconsReleaseV4EAG packet) {
+		netHandler.getNotifManager().processPacketRemIcons(packet);
+	}
+
+	public void handleServer(SPacketNotifBadgeShowV4EAG packet) {
+		netHandler.getNotifManager().processPacketShowBadge(packet);
+	}
+
+	public void handleServer(SPacketNotifBadgeHideV4EAG packet) {
+		netHandler.getNotifManager().processPacketHideBadge(packet);
+	}
+
+}
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/socket/protocol/client/GameProtocolMessageController.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/socket/protocol/client/GameProtocolMessageController.java
new file mode 100644
index 00000000..dc4176ea
--- /dev/null
+++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/socket/protocol/client/GameProtocolMessageController.java
@@ -0,0 +1,199 @@
+package net.lax1dude.eaglercraft.v1_8.socket.protocol.client;
+
+import java.io.IOException;
+import java.util.LinkedList;
+import java.util.List;
+
+import net.lax1dude.eaglercraft.v1_8.EagRuntime;
+import net.lax1dude.eaglercraft.v1_8.log4j.LogManager;
+import net.lax1dude.eaglercraft.v1_8.log4j.Logger;
+import net.lax1dude.eaglercraft.v1_8.netty.Unpooled;
+import net.lax1dude.eaglercraft.v1_8.socket.protocol.GamePacketOutputBuffer;
+import net.lax1dude.eaglercraft.v1_8.socket.protocol.GamePluginMessageConstants;
+import net.lax1dude.eaglercraft.v1_8.socket.protocol.GamePluginMessageProtocol;
+import net.lax1dude.eaglercraft.v1_8.socket.protocol.pkt.GameMessageHandler;
+import net.lax1dude.eaglercraft.v1_8.socket.protocol.pkt.GameMessagePacket;
+import net.lax1dude.eaglercraft.v1_8.sp.server.socket.protocol.ServerV3MessageHandler;
+import net.lax1dude.eaglercraft.v1_8.sp.server.socket.protocol.ServerV4MessageHandler;
+import net.minecraft.client.network.NetHandlerPlayClient;
+import net.minecraft.network.NetHandlerPlayServer;
+import net.minecraft.network.PacketBuffer;
+
+/**
+ * Copyright (c) 2024 lax1dude. All Rights Reserved.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ * 
+ */
+public class GameProtocolMessageController {
+
+	private static final Logger logger = LogManager.getLogger("GameProtocolMessageController");
+
+	public final GamePluginMessageProtocol protocol;
+	public final int sendDirection;
+	public final int receiveDirection;
+	private final PacketBufferInputWrapper inputStream = new PacketBufferInputWrapper(null);
+	private final PacketBufferOutputWrapper outputStream = new PacketBufferOutputWrapper(null);
+	private final GameMessageHandler handler;
+	private final IPluginMessageSendFunction sendFunction;
+	private final List<PacketBuffer> sendQueueV4;
+	private final boolean noDelay;
+
+	public GameProtocolMessageController(GamePluginMessageProtocol protocol, int sendDirection, GameMessageHandler handler,
+			IPluginMessageSendFunction sendCallback) {
+		this.protocol = protocol;
+		this.sendDirection = sendDirection;
+		this.receiveDirection = GamePluginMessageConstants.oppositeDirection(sendDirection);
+		this.handler = handler;
+		this.sendFunction = sendCallback;
+		this.noDelay = protocol.ver < 4 || EagRuntime.getConfiguration().isEaglerNoDelay();
+		this.sendQueueV4 = !noDelay ? new LinkedList<>() : null;
+	}
+
+	public boolean handlePacket(String channel, PacketBuffer data) throws IOException {
+		GameMessagePacket pkt;
+		if(protocol.ver >= 4 && data.readableBytes() > 0 && data.getByte(data.readerIndex()) == (byte) 0xFF
+				&& channel.equals(GamePluginMessageConstants.V4_CHANNEL)) {
+			data.readByte();
+			inputStream.buffer = data;
+			int count = inputStream.readVarInt();
+			for(int i = 0, j, k; i < count; ++i) {
+				j = data.readVarIntFromBuffer();
+				k = data.readerIndex() + j;
+				if(j > data.readableBytes()) {
+					throw new IOException("Packet fragment is too long: " + j + " > " + data.readableBytes());
+				}
+				pkt = protocol.readPacket(channel, receiveDirection, inputStream);
+				if(pkt != null) {
+					try {
+						pkt.handlePacket(handler);
+					}catch(Throwable t) {
+						logger.error("Failed to handle packet {} in direction {} using handler {}!", pkt.getClass().getSimpleName(),
+								GamePluginMessageConstants.getDirectionString(receiveDirection), handler);
+						logger.error(t);
+					}
+				}else {
+					logger.warn("Could not read packet fragment {} of {}, unknown packet", count, i);
+				}
+				if(data.readerIndex() != k) {
+					logger.warn("Packet fragment {} was the wrong length: {} != {}",
+							(pkt != null ? pkt.getClass().getSimpleName() : "unknown"), j + data.readerIndex() - k, j);
+					data.readerIndex(k);
+				}
+			}
+			if(data.readableBytes() > 0) {
+				logger.warn("Leftover data after reading multi-packet! ({} bytes)", data.readableBytes());
+			}
+			inputStream.buffer = null;
+			return true;
+		}
+		inputStream.buffer = data;
+		pkt = protocol.readPacket(channel, receiveDirection, inputStream);
+		if(pkt != null && inputStream.available() > 0) {
+			logger.warn("Leftover data after reading packet {}! ({} bytes)", pkt.getClass().getSimpleName(), inputStream.available());
+		}
+		inputStream.buffer = null;
+		if(pkt != null) {
+			try {
+				pkt.handlePacket(handler);
+			}catch(Throwable t) {
+				logger.error("Failed to handle packet {} in direction {} using handler {}!", pkt.getClass().getSimpleName(),
+						GamePluginMessageConstants.getDirectionString(receiveDirection), handler);
+				logger.error(t);
+			}
+			return true;
+		}else {
+			return false;
+		}
+	}
+
+	public void sendPacket(GameMessagePacket packet) throws IOException {
+		int len = packet.length() + 1;
+		PacketBuffer buf = new PacketBuffer(len != 0 ? Unpooled.buffer(len) : Unpooled.buffer(64));
+		outputStream.buffer = buf;
+		String chan = protocol.writePacket(sendDirection, outputStream, packet);
+		outputStream.buffer = null;
+		int j = buf.writerIndex();
+		if(len != 0 && j != len && j + 1 != len) {
+			logger.warn("Packet {} was expected to be {} bytes but was serialized to {} bytes!",
+					packet.getClass().getSimpleName(), len, j);
+		}
+		if(sendQueueV4 != null && chan.equals(GamePluginMessageConstants.V4_CHANNEL)) {
+			sendQueueV4.add(buf);
+		}else {
+			sendFunction.sendPluginMessage(chan, buf);
+		}
+	}
+
+	public void flush() {
+		if(sendQueueV4 != null) {
+			int queueLen = sendQueueV4.size();
+			PacketBuffer pkt;
+			if(queueLen == 0) {
+				return;
+			}else if(queueLen == 1) {
+				pkt = sendQueueV4.remove(0);
+				sendFunction.sendPluginMessage(GamePluginMessageConstants.V4_CHANNEL, pkt);
+			}else {
+				int i, j, sendCount = 0, totalLen = 0;
+				PacketBuffer sendBuffer;
+				while(sendQueueV4.size() > 0) {
+					do {
+						i = sendQueueV4.get(sendCount++).readableBytes();
+						totalLen += GamePacketOutputBuffer.getVarIntSize(i) + i;
+					}while(totalLen < 32760 && sendCount < sendQueueV4.size());
+					if(totalLen >= 32760) {
+						--sendCount;
+					}
+					if(sendCount <= 1) {
+						pkt = sendQueueV4.remove(0);
+						sendFunction.sendPluginMessage(GamePluginMessageConstants.V4_CHANNEL, pkt);
+						continue;
+					}
+					sendBuffer = new PacketBuffer(Unpooled.buffer(1 + totalLen + GamePacketOutputBuffer.getVarIntSize(sendCount))); 
+					sendBuffer.writeByte(0xFF);
+					sendBuffer.writeVarIntToBuffer(sendCount);
+					for(j = 0; j < sendCount; ++j) {
+						pkt = sendQueueV4.remove(0);
+						sendBuffer.writeVarIntToBuffer(pkt.readableBytes());
+						sendBuffer.writeBytes(pkt);
+					}
+					sendFunction.sendPluginMessage(GamePluginMessageConstants.V4_CHANNEL, sendBuffer);
+				}
+			}
+		}
+	}
+
+	public static GameMessageHandler createClientHandler(int protocolVersion, NetHandlerPlayClient netHandler) {
+		switch(protocolVersion) {
+		case 2:
+		case 3:
+			return new ClientV3MessageHandler(netHandler);
+		case 4:
+			return new ClientV4MessageHandler(netHandler);
+		default:
+			throw new IllegalArgumentException("Unknown protocol verison: " + protocolVersion);
+		}
+	}
+
+	public static GameMessageHandler createServerHandler(int protocolVersion, NetHandlerPlayServer netHandler) {
+		switch(protocolVersion) {
+		case 2:
+		case 3:
+			return new ServerV3MessageHandler(netHandler);
+		case 4:
+			return new ServerV4MessageHandler(netHandler);
+		default:
+			throw new IllegalArgumentException("Unknown protocol verison: " + protocolVersion);
+		}
+	}
+}
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/socket/protocol/client/IPluginMessageSendFunction.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/socket/protocol/client/IPluginMessageSendFunction.java
new file mode 100644
index 00000000..e4fbbf7b
--- /dev/null
+++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/socket/protocol/client/IPluginMessageSendFunction.java
@@ -0,0 +1,24 @@
+package net.lax1dude.eaglercraft.v1_8.socket.protocol.client;
+
+import net.minecraft.network.PacketBuffer;
+
+/**
+ * Copyright (c) 2024 lax1dude. All Rights Reserved.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ * 
+ */
+public interface IPluginMessageSendFunction {
+
+	void sendPluginMessage(String channel, PacketBuffer contents);
+
+}
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/socket/protocol/client/PacketBufferInputWrapper.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/socket/protocol/client/PacketBufferInputWrapper.java
new file mode 100644
index 00000000..1566bb7e
--- /dev/null
+++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/socket/protocol/client/PacketBufferInputWrapper.java
@@ -0,0 +1,303 @@
+package net.lax1dude.eaglercraft.v1_8.socket.protocol.client;
+
+import java.io.DataInputStream;
+import java.io.EOFException;
+import java.io.IOException;
+import java.io.InputStream;
+
+import net.lax1dude.eaglercraft.v1_8.DecoderException;
+import net.lax1dude.eaglercraft.v1_8.socket.protocol.GamePacketInputBuffer;
+import net.minecraft.network.PacketBuffer;
+
+/**
+ * Copyright (c) 2024 lax1dude. All Rights Reserved.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ * 
+ */
+public class PacketBufferInputWrapper implements GamePacketInputBuffer {
+
+	protected PacketBuffer buffer;
+
+	public PacketBufferInputWrapper(PacketBuffer buffer) {
+		this.buffer = buffer;
+	}
+
+	public PacketBuffer getBuffer() {
+		return buffer;
+	}
+
+	public void setBuffer(PacketBuffer buffer) {
+		this.buffer = buffer;
+	}
+
+	@Override
+	public void readFully(byte[] b) throws IOException {
+		try {
+			buffer.readBytes(b);
+		}catch(IndexOutOfBoundsException ex) {
+			throw new EOFException();
+		}
+	}
+
+	@Override
+	public void readFully(byte[] b, int off, int len) throws IOException {
+		try {
+			buffer.readBytes(b, off, len);
+		}catch(IndexOutOfBoundsException ex) {
+			throw new EOFException();
+		}
+	}
+
+	@Override
+	public int skipBytes(int n) throws IOException {
+		int r = buffer.readableBytes();
+		if(n > r) {
+			n = r;
+		}
+		buffer.readerIndex(buffer.readerIndex() + n);
+		return n;
+	}
+
+	@Override
+	public boolean readBoolean() throws IOException {
+		try {
+			return buffer.readBoolean();
+		}catch(IndexOutOfBoundsException ex) {
+			throw new EOFException();
+		}
+	}
+
+	@Override
+	public byte readByte() throws IOException {
+		try {
+			return buffer.readByte();
+		}catch(IndexOutOfBoundsException ex) {
+			throw new EOFException();
+		}
+	}
+
+	@Override
+	public int readUnsignedByte() throws IOException {
+		try {
+			return buffer.readUnsignedByte();
+		}catch(IndexOutOfBoundsException ex) {
+			throw new EOFException();
+		}
+	}
+
+	@Override
+	public short readShort() throws IOException {
+		try {
+			return buffer.readShort();
+		}catch(IndexOutOfBoundsException ex) {
+			throw new EOFException();
+		}
+	}
+
+	@Override
+	public int readUnsignedShort() throws IOException {
+		try {
+			return buffer.readUnsignedShort();
+		}catch(IndexOutOfBoundsException ex) {
+			throw new EOFException();
+		}
+	}
+
+	@Override
+	public char readChar() throws IOException {
+		try {
+			return buffer.readChar();
+		}catch(IndexOutOfBoundsException ex) {
+			throw new EOFException();
+		}
+	}
+
+	@Override
+	public int readInt() throws IOException {
+		try {
+			return buffer.readInt();
+		}catch(IndexOutOfBoundsException ex) {
+			throw new EOFException();
+		}
+	}
+
+	@Override
+	public long readLong() throws IOException {
+		try {
+			return buffer.readLong();
+		}catch(IndexOutOfBoundsException ex) {
+			throw new EOFException();
+		}
+	}
+
+	@Override
+	public float readFloat() throws IOException {
+		try {
+			return buffer.readFloat();
+		}catch(IndexOutOfBoundsException ex) {
+			throw new EOFException();
+		}
+	}
+
+	@Override
+	public double readDouble() throws IOException {
+		try {
+			return buffer.readDouble();
+		}catch(IndexOutOfBoundsException ex) {
+			throw new EOFException();
+		}
+	}
+
+	@Override
+	public String readLine() throws IOException {
+		throw new UnsupportedOperationException();
+	}
+
+	@Override
+	public String readUTF() throws IOException {
+		return DataInputStream.readUTF(this);
+	}
+
+	@Override
+	public void skipAllBytes(int n) throws IOException {
+		if(buffer.readableBytes() < n) {
+			throw new EOFException();
+		}
+		buffer.readerIndex(buffer.readerIndex() + n);
+	}
+
+	@Override
+	public int readVarInt() throws IOException {
+		try {
+			return buffer.readVarIntFromBuffer();
+		}catch(IndexOutOfBoundsException ex) {
+			throw new EOFException();
+		}
+	}
+
+	@Override
+	public long readVarLong() throws IOException {
+		try {
+			return buffer.readVarLong();
+		}catch(IndexOutOfBoundsException ex) {
+			throw new EOFException();
+		}
+	}
+
+	@Override
+	public String readStringMC(int maxLen) throws IOException {
+		try {
+			return buffer.readStringFromBuffer(maxLen);
+		}catch(DecoderException ex) {
+			throw new IOException(ex.getMessage());
+		}catch(IndexOutOfBoundsException ex) {
+			throw new EOFException();
+		}
+	}
+
+	@Override
+	public String readStringEaglerASCII8() throws IOException {
+		int len = readUnsignedByte();
+		char[] ret = new char[len];
+		for(int i = 0; i < len; ++i) {
+			ret[i] = (char)readByte();
+		}
+		return new String(ret);
+	}
+
+	@Override
+	public String readStringEaglerASCII16() throws IOException {
+		int len = readUnsignedShort();
+		char[] ret = new char[len];
+		for(int i = 0; i < len; ++i) {
+			ret[i] = (char)readByte();
+		}
+		return new String(ret);
+	}
+
+	@Override
+	public byte[] readByteArrayMC() throws IOException {
+		try {
+			return buffer.readByteArray();
+		}catch(IndexOutOfBoundsException ex) {
+			throw new EOFException();
+		}
+	}
+
+	@Override
+	public int available() throws IOException {
+		return buffer.readableBytes();
+	}
+
+	@Override
+	public InputStream stream() {
+		return new InputStream() {
+
+			@Override
+			public int read() throws IOException {
+				if(buffer.readableBytes() > 0) {
+					return buffer.readUnsignedShort();
+				}else {
+					return -1;
+				}
+			}
+
+			@Override
+			public int read(byte b[], int off, int len) throws IOException {
+				int avail = buffer.readableBytes();
+				if(avail == 0) return -1;
+				len = avail > len ? avail : len;
+				buffer.readBytes(b, off, len);
+				return len;
+			}
+
+			@Override
+			public long skip(long n) throws IOException {
+				return PacketBufferInputWrapper.this.skipBytes((int)n);
+			}
+
+			@Override
+			public int available() throws IOException {
+				return buffer.readableBytes();
+			}
+
+			@Override
+		    public boolean markSupported() {
+		        return true;
+		    }
+
+			@Override
+			public synchronized void mark(int readlimit) {
+				buffer.markReaderIndex();
+			}
+
+			@Override
+		    public synchronized void reset() throws IOException {
+				try {
+					buffer.resetReaderIndex();
+				}catch(IndexOutOfBoundsException ex) {
+					throw new EOFException();
+				}
+			}
+
+		};
+	}
+
+	@Override
+	public byte[] toByteArray() throws IOException {
+		byte[] ret = new byte[buffer.readableBytes()];
+		buffer.readBytes(ret);
+		return ret;
+	}
+
+}
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/socket/protocol/client/PacketBufferOutputWrapper.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/socket/protocol/client/PacketBufferOutputWrapper.java
new file mode 100644
index 00000000..67e17cc0
--- /dev/null
+++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/socket/protocol/client/PacketBufferOutputWrapper.java
@@ -0,0 +1,316 @@
+package net.lax1dude.eaglercraft.v1_8.socket.protocol.client;
+
+import java.io.IOException;
+import java.io.OutputStream;
+
+import net.lax1dude.eaglercraft.v1_8.socket.protocol.GamePacketOutputBuffer;
+import net.minecraft.network.PacketBuffer;
+
+/**
+ * Copyright (c) 2024 lax1dude. All Rights Reserved.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ * 
+ */
+public class PacketBufferOutputWrapper implements GamePacketOutputBuffer {
+
+	protected PacketBuffer buffer;
+
+	public PacketBufferOutputWrapper(PacketBuffer buffer) {
+		this.buffer = buffer;
+	}
+
+	public PacketBuffer getBuffer() {
+		return buffer;
+	}
+
+	public void setBuffer(PacketBuffer buffer) {
+		this.buffer = buffer;
+	}
+
+	@Override
+	public void write(int b) throws IOException {
+		try {
+			buffer.writeByte(b);
+		}catch(IndexOutOfBoundsException ex) {
+			throw new IOException("Packet buffer overflowed!");
+		}
+	}
+
+	@Override
+	public void write(byte[] b) throws IOException {
+		try {
+			buffer.writeBytes(b);
+		}catch(IndexOutOfBoundsException ex) {
+			throw new IOException("Packet buffer overflowed!");
+		}
+	}
+
+	@Override
+	public void write(byte[] b, int off, int len) throws IOException {
+		try {
+			buffer.writeBytes(b, off, len);
+		}catch(IndexOutOfBoundsException ex) {
+			throw new IOException("Packet buffer overflowed!");
+		}
+	}
+
+	@Override
+	public void writeBoolean(boolean v) throws IOException {
+		try {
+			buffer.writeBoolean(v);
+		}catch(IndexOutOfBoundsException ex) {
+			throw new IOException("Packet buffer overflowed!");
+		}
+	}
+
+	@Override
+	public void writeByte(int v) throws IOException {
+		try {
+			buffer.writeByte(v);
+		}catch(IndexOutOfBoundsException ex) {
+			throw new IOException("Packet buffer overflowed!");
+		}
+	}
+
+	@Override
+	public void writeShort(int v) throws IOException {
+		try {
+			buffer.writeShort(v);
+		}catch(IndexOutOfBoundsException ex) {
+			throw new IOException("Packet buffer overflowed!");
+		}
+	}
+
+	@Override
+	public void writeChar(int v) throws IOException {
+		try {
+			buffer.writeChar(v);
+		}catch(IndexOutOfBoundsException ex) {
+			throw new IOException("Packet buffer overflowed!");
+		}
+	}
+
+	@Override
+	public void writeInt(int v) throws IOException {
+		try {
+			buffer.writeInt(v);
+		}catch(IndexOutOfBoundsException ex) {
+			throw new IOException("Packet buffer overflowed!");
+		}
+	}
+
+	@Override
+	public void writeLong(long v) throws IOException {
+		try {
+			buffer.writeLong(v);
+		}catch(IndexOutOfBoundsException ex) {
+			throw new IOException("Packet buffer overflowed!");
+		}
+	}
+
+	@Override
+	public void writeFloat(float v) throws IOException {
+		try {
+			buffer.writeFloat(v);
+		}catch(IndexOutOfBoundsException ex) {
+			throw new IOException("Packet buffer overflowed!");
+		}
+	}
+
+	@Override
+	public void writeDouble(double v) throws IOException {
+		try {
+			buffer.writeDouble(v);
+		}catch(IndexOutOfBoundsException ex) {
+			throw new IOException("Packet buffer overflowed!");
+		}
+	}
+
+	@Override
+	public void writeBytes(String s) throws IOException {
+		try {
+			int l = s.length();
+			for(int i = 0; i < l; ++i) {
+				buffer.writeByte((int)s.charAt(i));
+			}
+		}catch(IndexOutOfBoundsException ex) {
+			throw new IOException("Packet buffer overflowed!");
+		}
+	}
+
+	@Override
+	public void writeChars(String s) throws IOException {
+		try {
+			int l = s.length();
+			for(int i = 0; i < l; ++i) {
+				buffer.writeChar(s.charAt(i));
+			}
+		}catch(IndexOutOfBoundsException ex) {
+			throw new IOException("Packet buffer overflowed!");
+		}
+	}
+
+	@Override
+	public final void writeUTF(String str) throws IOException {
+		long utfCount = countUTFBytes(str);
+		if (utfCount > 65535) {
+			throw new IOException("String is longer than 65535 bytes when encoded as UTF8!");
+		}
+		byte[] arr = new byte[(int) utfCount + 2];
+		int offset = 2;
+		arr[0] = (byte)(((int)utfCount >>> 8) & 0xFF);
+		arr[1] = (byte)((int)utfCount & 0xFF);
+		offset = writeUTFBytesToBuffer(str, arr, offset);
+		try {
+			buffer.writeBytes(arr, 0, offset);
+		}catch(IndexOutOfBoundsException ex) {
+			throw new IOException("Packet buffer overflowed!");
+		}
+	}
+
+	private static long countUTFBytes(String str) {
+		int utfCount = 0;
+		int length = str.length();
+		for (int i = 0; i < length; i++) {
+			int charValue = str.charAt(i);
+			if (charValue > 0 && charValue <= 127) {
+				utfCount++;
+			} else if (charValue <= 2047) {
+				utfCount += 2;
+			} else {
+				utfCount += 3;
+			}
+		}
+		return utfCount;
+	}
+
+	private static int writeUTFBytesToBuffer(String str, byte[] buffer, int offset) throws IOException {
+		int length = str.length();
+		for (int i = 0; i < length; i++) {
+			int charValue = str.charAt(i);
+			if (charValue > 0 && charValue <= 127) {
+				buffer[offset++] = (byte) charValue;
+			} else if (charValue <= 2047) {
+				buffer[offset++] = (byte) (0xc0 | (0x1f & (charValue >> 6)));
+				buffer[offset++] = (byte) (0x80 | (0x3f & charValue));
+			} else {
+				buffer[offset++] = (byte) (0xe0 | (0x0f & (charValue >> 12)));
+				buffer[offset++] = (byte) (0x80 | (0x3f & (charValue >> 6)));
+				buffer[offset++] = (byte) (0x80 | (0x3f & charValue));
+			}
+		}
+		return offset;
+	}
+
+	@Override
+	public void writeVarInt(int i) throws IOException {
+		try {
+			buffer.writeVarIntToBuffer(i);
+		}catch(IndexOutOfBoundsException ex) {
+			throw new IOException("Packet buffer overflowed!");
+		}
+	}
+
+	@Override
+	public void writeVarLong(long i) throws IOException {
+		try {
+			buffer.writeVarLong(i);
+		}catch(IndexOutOfBoundsException ex) {
+			throw new IOException("Packet buffer overflowed!");
+		}
+	}
+
+	@Override
+	public void writeStringMC(String str) throws IOException {
+		try {
+			buffer.writeString(str);
+		}catch(IndexOutOfBoundsException ex) {
+			throw new IOException("Packet buffer overflowed!");
+		}
+	}
+
+	@Override
+	public void writeStringEaglerASCII8(String str) throws IOException {
+		int len = str.length();
+		if(len > 255) {
+			throw new IOException("String is longer than 255 chars! (" + len + ")");
+		}
+		try {
+			buffer.writeByte(len);
+			for(int i = 0, j; i < len; ++i) {
+				j = (int)str.charAt(i);
+				if(j > 255) {
+					j = (int)'?';
+				}
+				buffer.writeByte(j);
+			}
+		}catch(IndexOutOfBoundsException ex) {
+			throw new IOException("Packet buffer overflowed!");
+		}
+	}
+
+	@Override
+	public void writeStringEaglerASCII16(String str) throws IOException {
+		int len = str.length();
+		if(len > 65535) {
+			throw new IOException("String is longer than 65535 chars! (" + len + ")");
+		}
+		try {
+			buffer.writeShort(len);
+			for(int i = 0, j; i < len; ++i) {
+				j = (int)str.charAt(i);
+				if(j > 255) {
+					j = (int)'?';
+				}
+				buffer.writeByte(j);
+			}
+		}catch(IndexOutOfBoundsException ex) {
+			throw new IOException("Packet buffer overflowed!");
+		}
+	}
+
+	@Override
+	public void writeByteArrayMC(byte[] bytes) throws IOException {
+		try {
+			buffer.writeByteArray(bytes);
+		}catch(IndexOutOfBoundsException ex) {
+			throw new IOException("Packet buffer overflowed!");
+		}
+	}
+
+	@Override
+	public OutputStream stream() {
+		return new OutputStream() {
+
+			@Override
+			public void write(int b) throws IOException {
+				try {
+					buffer.writeByte(b);
+				}catch(IndexOutOfBoundsException ex) {
+					throw new IOException("Packet buffer overflowed!");
+				}
+			}
+
+			@Override
+			public void write(byte b[], int off, int len) throws IOException {
+				try {
+					buffer.writeBytes(b, off, len);
+				}catch(IndexOutOfBoundsException ex) {
+					throw new IOException("Packet buffer overflowed!");
+				}
+			}
+
+		};
+	}
+
+}
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/SingleplayerServerController.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/SingleplayerServerController.java
index 1479e012..4f8c30a1 100644
--- a/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/SingleplayerServerController.java
+++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/SingleplayerServerController.java
@@ -3,9 +3,11 @@ package net.lax1dude.eaglercraft.v1_8.sp;
 import java.io.IOException;
 import java.util.ArrayList;
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
 
 import net.lax1dude.eaglercraft.v1_8.internal.PlatformWebRTC;
 
@@ -56,34 +58,59 @@ public class SingleplayerServerController implements ISaveFormat {
 	private static boolean loggingState = true;
 	private static String worldStatusString = "";
 	private static float worldStatusProgress = 0.0f;
-	private static final LinkedList<IPCPacket15Crashed> exceptions = new LinkedList();
+	private static final LinkedList<IPCPacket15Crashed> exceptions = new LinkedList<>();
+	private static final Set<Integer> issuesDetected = new HashSet<>();
 
 	public static final SingleplayerServerController instance = new SingleplayerServerController();
 	public static final Logger logger = LogManager.getLogger("SingleplayerServerController");
-	public static final List<SaveFormatComparator> saveListCache = new ArrayList();
-	public static final Map<String, WorldInfo> saveListMap = new HashMap();
-	public static final List<NBTTagCompound> saveListNBT = new ArrayList();
+	public static final List<SaveFormatComparator> saveListCache = new ArrayList<>();
+	public static final Map<String, WorldInfo> saveListMap = new HashMap<>();
+	public static final List<NBTTagCompound> saveListNBT = new ArrayList<>();
 
 	private static boolean isPaused = false;
-	private static List<String> integratedServerTPS = new ArrayList();
+	private static List<String> integratedServerTPS = new ArrayList<>();
 	private static long integratedServerLastTPSUpdate = 0;
 	public static final ClientIntegratedServerNetworkManager localPlayerNetworkManager = new ClientIntegratedServerNetworkManager(PLAYER_CHANNEL);
-	private static final List<String> openLANChannels = new ArrayList();
+	private static final List<String> openLANChannels = new ArrayList<>();
 
 	private static final IPCPacketManager packetManagerInstance = new IPCPacketManager();
 
 	private SingleplayerServerController() {
 	}
 
-	public static void startIntegratedServerWorker() {
+	public static void startIntegratedServerWorker(boolean forceSingleThread) {
 		if(statusState == IntegratedServerState.WORLD_WORKER_NOT_RUNNING) {
 			exceptions.clear();
+			issuesDetected.clear();
 			statusState = IntegratedServerState.WORLD_WORKER_BOOTING;
 			loggingState = true;
-			ClientPlatformSingleplayer.startIntegratedServer();
+			boolean singleThreadSupport = ClientPlatformSingleplayer.isSingleThreadModeSupported();
+			if(!singleThreadSupport && forceSingleThread) {
+				throw new UnsupportedOperationException("Single thread mode is not supported!");
+			}
+			if(forceSingleThread || !singleThreadSupport) {
+				ClientPlatformSingleplayer.startIntegratedServer(forceSingleThread);
+			}else {
+				try {
+					ClientPlatformSingleplayer.startIntegratedServer(forceSingleThread);
+				}catch(Throwable t) {
+					logger.error("Failed to start integrated server worker");
+					logger.error(t);
+					logger.error("Attempting to use single thread mode");
+					exceptions.clear();
+					issuesDetected.clear();
+					statusState = IntegratedServerState.WORLD_WORKER_BOOTING;
+					loggingState = true;
+					ClientPlatformSingleplayer.startIntegratedServer(true);
+				}
+			}
 		}
 	}
 
+	public static boolean isIssueDetected(int issue) {
+		return issuesDetected.contains(issue);
+	}
+
 	public static boolean isIntegratedServerWorkerStarted() {
 		return statusState != IntegratedServerState.WORLD_WORKER_NOT_RUNNING && statusState != IntegratedServerState.WORLD_WORKER_BOOTING;
 	}
@@ -196,7 +223,7 @@ public class SingleplayerServerController implements ISaveFormat {
 	}
 
 	public static long getTPSAge() {
-		return System.currentTimeMillis() - integratedServerLastTPSUpdate;
+		return EagRuntime.steadyTimeMillis() - integratedServerLastTPSUpdate;
 	}
 
 	public static boolean hangupEaglercraftServer() {
@@ -269,7 +296,11 @@ public class SingleplayerServerController implements ISaveFormat {
 		boolean logWindowState = PlatformApplication.isShowingDebugConsole();
 		if(loggingState != logWindowState) {
 			loggingState = logWindowState;
-			sendIPCPacket(new IPCPacket21EnableLogging(logWindowState));
+			sendIPCPacket(new IPCPacket1BEnableLogging(logWindowState));
+		}
+
+		if(ClientPlatformSingleplayer.isRunningSingleThreadMode()) {
+			ClientPlatformSingleplayer.updateSingleThreadMode();
 		}
 
 		LANServerController.updateLANServer();
@@ -385,17 +416,22 @@ public class SingleplayerServerController implements ISaveFormat {
 			if(pkt.opCode == IPCPacket14StringList.SERVER_TPS) {
 				integratedServerTPS.clear();
 				integratedServerTPS.addAll(pkt.stringList);
-				integratedServerLastTPSUpdate = System.currentTimeMillis();
+				integratedServerLastTPSUpdate = EagRuntime.steadyTimeMillis();
 			}else {
 				logger.warn("Strange string list type {} recieved!", pkt.opCode);
 			}
 			break;
 		}
-		case IPCPacket20LoggerMessage.ID: {
-			IPCPacket20LoggerMessage pkt = (IPCPacket20LoggerMessage)ipc;
+		case IPCPacket1ALoggerMessage.ID: {
+			IPCPacket1ALoggerMessage pkt = (IPCPacket1ALoggerMessage)ipc;
 			PlatformApplication.addLogMessage(pkt.logMessage, pkt.isError);
 			break;
 		}
+		case IPCPacket1CIssueDetected.ID: {
+			IPCPacket1CIssueDetected pkt = (IPCPacket1CIssueDetected)ipc;
+			issuesDetected.add(pkt.issueID);
+			break;
+		}
 		default:
 			throw new RuntimeException("Unexpected IPC packet type recieved on client: " + ipc.id());
 		}
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/SkullCommand.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/SkullCommand.java
index 5d2bf322..1d2aa1d0 100644
--- a/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/SkullCommand.java
+++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/SkullCommand.java
@@ -3,9 +3,8 @@ package net.lax1dude.eaglercraft.v1_8.sp;
 import net.lax1dude.eaglercraft.v1_8.EagRuntime;
 import net.lax1dude.eaglercraft.v1_8.internal.FileChooserResult;
 import net.lax1dude.eaglercraft.v1_8.opengl.ImageData;
-import net.lax1dude.eaglercraft.v1_8.profile.SkinPackets;
+import net.lax1dude.eaglercraft.v1_8.socket.protocol.pkt.client.CPacketInstallSkinSPEAG;
 import net.minecraft.client.Minecraft;
-import net.minecraft.network.play.client.C17PacketCustomPayload;
 import net.minecraft.util.ChatComponentTranslation;
 
 /**
@@ -44,9 +43,9 @@ public class SkullCommand {
 			if(fr == null || mc.thePlayer == null || mc.thePlayer.sendQueue == null) {
 				return;
 			}
-			ImageData loaded = ImageData.loadImageFile(fr.fileData);
+			ImageData loaded = ImageData.loadImageFile(fr.fileData, ImageData.getMimeFromType(fr.fileName));
 			if(loaded == null) {
-				mc.ingameGUI.getChatGUI().printChatMessage(new ChatComponentTranslation("command.skull.error.invalid.png"));
+				mc.ingameGUI.getChatGUI().printChatMessage(new ChatComponentTranslation("command.skull.error.invalid.format"));
 				return;
 			}
 			if(loaded.width != 64 || loaded.height > 64) {
@@ -62,7 +61,7 @@ public class SkullCommand {
 				rawSkin[j + 2] = (byte)(k >>> 8);
 				rawSkin[j + 3] = (byte)(k & 0xFF);
 			}
-			mc.thePlayer.sendQueue.addToSendQueue(new C17PacketCustomPayload("EAG|Skins-1.8", SkinPackets.writeCreateCustomSkull(rawSkin)));
+			mc.thePlayer.sendQueue.sendEaglerMessage(new CPacketInstallSkinSPEAG(rawSkin));
 		}
 	}
 
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/gui/GuiIntegratedServerStartup.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/gui/GuiIntegratedServerStartup.java
deleted file mode 100644
index 9e5349d1..00000000
--- a/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/gui/GuiIntegratedServerStartup.java
+++ /dev/null
@@ -1,58 +0,0 @@
-package net.lax1dude.eaglercraft.v1_8.sp.gui;
-
-import net.lax1dude.eaglercraft.v1_8.sp.SingleplayerServerController;
-import net.minecraft.client.gui.GuiScreen;
-import net.minecraft.client.gui.GuiSelectWorld;
-import net.minecraft.client.resources.I18n;
-
-/**
- * Copyright (c) 2023-2024 lax1dude. All Rights Reserved.
- * 
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
- * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- * 
- */
-public class GuiIntegratedServerStartup extends GuiScreen {
-
-	private final GuiScreen backScreen;
-	private static final String[] dotDotDot = new String[] { "", ".", "..", "..." };
-
-	private int counter = 0;
-
-	public GuiIntegratedServerStartup(GuiScreen backScreen) {
-		this.backScreen = backScreen;
-	}
-
-	protected void keyTyped(char parChar1, int parInt1) {
-	}
-
-	public void initGui() {
-		this.buttonList.clear();
-	}
-
-	public void updateScreen() {
-		++counter;
-		if(counter > 1 && SingleplayerServerController.isIntegratedServerWorkerStarted()) {
-			mc.displayGuiScreen(new GuiSelectWorld(backScreen));
-		}else if(counter == 2) {
-			SingleplayerServerController.startIntegratedServerWorker();
-		}
-	}
-
-	public void drawScreen(int i, int j, float f) {
-		this.drawBackground(0);
-		String txt = I18n.format("singleplayer.integratedStartup");
-		int w = this.fontRendererObj.getStringWidth(txt);
-		this.drawString(this.fontRendererObj, txt + dotDotDot[(int)((System.currentTimeMillis() / 300L) % 4L)], (this.width - w) / 2, this.height / 2 - 50, 16777215);
-		super.drawScreen(i, j, f);
-	}
-
-}
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/gui/GuiScreenAddRelay.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/gui/GuiScreenAddRelay.java
index 7032d616..8bba2619 100644
--- a/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/gui/GuiScreenAddRelay.java
+++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/gui/GuiScreenAddRelay.java
@@ -2,6 +2,7 @@ package net.lax1dude.eaglercraft.v1_8.sp.gui;
 
 import net.lax1dude.eaglercraft.v1_8.EagRuntime;
 import net.lax1dude.eaglercraft.v1_8.Keyboard;
+import net.lax1dude.eaglercraft.v1_8.minecraft.EnumInputEvent;
 import net.lax1dude.eaglercraft.v1_8.sp.relay.RelayManager;
 import net.minecraft.client.gui.GuiButton;
 import net.minecraft.client.gui.GuiScreen;
@@ -143,4 +144,16 @@ public class GuiScreenAddRelay extends GuiScreen {
 	public boolean blockPTTKey() {
 		return this.serverName.isFocused() || this.serverAddress.isFocused();
 	}
+
+	@Override
+	public boolean showCopyPasteButtons() {
+		return this.serverName.isFocused() || this.serverAddress.isFocused();
+	}
+
+	@Override
+	public void fireInputEvent(EnumInputEvent event, String param) {
+		this.serverName.fireInputEvent(event, param);
+		this.serverAddress.fireInputEvent(event, param);
+	}
+
 }
\ No newline at end of file
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/gui/GuiScreenDemoIntegratedServerStartup.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/gui/GuiScreenDemoIntegratedServerStartup.java
index 4a351d56..f5418127 100644
--- a/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/gui/GuiScreenDemoIntegratedServerStartup.java
+++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/gui/GuiScreenDemoIntegratedServerStartup.java
@@ -1,9 +1,14 @@
 package net.lax1dude.eaglercraft.v1_8.sp.gui;
 
+import net.lax1dude.eaglercraft.v1_8.EagRuntime;
 import net.lax1dude.eaglercraft.v1_8.sp.SingleplayerServerController;
 import net.lax1dude.eaglercraft.v1_8.sp.WorkerStartupFailedException;
 import net.lax1dude.eaglercraft.v1_8.sp.ipc.IPCPacket15Crashed;
+import net.lax1dude.eaglercraft.v1_8.sp.ipc.IPCPacket1CIssueDetected;
+import net.minecraft.client.gui.GuiButton;
+import net.minecraft.client.gui.GuiMainMenu;
 import net.minecraft.client.gui.GuiScreen;
+import net.minecraft.client.gui.GuiSelectWorld;
 import net.minecraft.client.resources.I18n;
 
 /**
@@ -24,46 +29,76 @@ import net.minecraft.client.resources.I18n;
 public class GuiScreenDemoIntegratedServerStartup extends GuiScreen {
 
 	private final GuiScreen contScreen;
+	private final boolean singleThread;
 	private static final String[] dotDotDot = new String[] { "", ".", "..", "..." };
 
 	private int counter = 0;
 
+	private GuiButton cancelButton;
+
 	public GuiScreenDemoIntegratedServerStartup(GuiScreen contScreen) {
 		this.contScreen = contScreen;
+		this.singleThread = false;
 	}
 
-	protected void keyTyped(char parChar1, int parInt1) {
+	public GuiScreenDemoIntegratedServerStartup(GuiScreen contScreen, boolean singleThread) {
+		this.contScreen = contScreen;
+		this.singleThread = singleThread;
 	}
 
 	public void initGui() {
 		this.buttonList.clear();
+		this.buttonList.add(cancelButton = new GuiButton(0, this.width / 2 - 100, this.height / 3 + 50, I18n.format("singleplayer.busy.killTask")));
+		cancelButton.visible = false;
 	}
 
 	public void updateScreen() {
 		++counter;
 		if(counter == 2) {
 			try {
-				SingleplayerServerController.startIntegratedServerWorker();
+				SingleplayerServerController.startIntegratedServerWorker(singleThread);
 			}catch(WorkerStartupFailedException ex) {
 				mc.displayGuiScreen(new GuiScreenIntegratedServerFailed(ex.getMessage(), new GuiScreenDemoIntegratedServerFailed()));
 				return;
 			}
 		}else if(counter > 2) {
+			if(counter > 100 && SingleplayerServerController.canKillWorker() && !singleThread) {
+				cancelButton.visible = true;
+			}
 			IPCPacket15Crashed[] crashReport = SingleplayerServerController.worldStatusErrors();
 			if(crashReport != null) {
 				mc.displayGuiScreen(GuiScreenIntegratedServerBusy.createException(new GuiScreenDemoIntegratedServerFailed(), "singleplayer.failed.notStarted", crashReport));
 			}else if(SingleplayerServerController.isIntegratedServerWorkerStarted()) {
-				mc.displayGuiScreen(contScreen);
+				GuiScreen cont = contScreen;
+				if(SingleplayerServerController.isRunningSingleThreadMode()) {
+					cont = new GuiScreenIntegratedServerFailed("singleplayer.failed.singleThreadWarning.1", "singleplayer.failed.singleThreadWarning.2", cont);
+				} else if (!EagRuntime.getConfiguration().isRamdiskMode()
+						&& SingleplayerServerController.isIssueDetected(IPCPacket1CIssueDetected.ISSUE_RAMDISK_MODE)
+						&& SingleplayerServerController.canKillWorker()) {
+					cont = new GuiScreenRAMDiskModeDetected(cont);
+				}
+				mc.displayGuiScreen(cont);
 			}
 		}
 	}
 
+	protected void actionPerformed(GuiButton parGuiButton) {
+		if(parGuiButton.id == 0) {
+			SingleplayerServerController.killWorker();
+			mc.displayGuiScreen(new GuiScreenDemoIntegratedServerStartup(contScreen, true));
+		}
+	}
+
 	public void drawScreen(int i, int j, float f) {
 		this.drawBackground(0);
 		String txt = I18n.format("singleplayer.integratedStartup");
 		int w = this.fontRendererObj.getStringWidth(txt);
-		this.drawString(this.fontRendererObj, txt + dotDotDot[(int)((System.currentTimeMillis() / 300L) % 4L)], (this.width - w) / 2, this.height / 2 - 50, 16777215);
+		this.drawString(this.fontRendererObj, txt + dotDotDot[(int)((EagRuntime.steadyTimeMillis() / 300L) % 4L)], (this.width - w) / 2, this.height / 2 - 50, 16777215);
 		super.drawScreen(i, j, f);
 	}
 
+	public boolean canCloseGui() {
+		return false;
+	}
+
 }
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/gui/GuiScreenIntegratedServerBusy.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/gui/GuiScreenIntegratedServerBusy.java
index 53b82876..effd5153 100644
--- a/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/gui/GuiScreenIntegratedServerBusy.java
+++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/gui/GuiScreenIntegratedServerBusy.java
@@ -88,7 +88,7 @@ public class GuiScreenIntegratedServerBusy extends GuiScreen {
 	}
 	
 	public void initGui() {
-		if(startStartTime == 0) this.startStartTime = System.currentTimeMillis();
+		if(startStartTime == 0) this.startStartTime = EagRuntime.steadyTimeMillis();
 		areYouSure = 0;
 		this.buttonList.add(killTask = new GuiButton(0, this.width / 2 - 100, this.height / 3 + 50, I18n.format("singleplayer.busy.killTask")));
 		killTask.enabled = false;
@@ -102,7 +102,7 @@ public class GuiScreenIntegratedServerBusy extends GuiScreen {
 		this.drawDefaultBackground();
 		int top = this.height / 3;
 		
-		long millis = System.currentTimeMillis();
+		long millis = EagRuntime.steadyTimeMillis();
 		
 		String str = I18n.format(currentStatus);
 		
@@ -128,7 +128,7 @@ public class GuiScreenIntegratedServerBusy extends GuiScreen {
 	}
 	
 	public void updateScreen() {
-		long millis = System.currentTimeMillis();
+		long millis = EagRuntime.steadyTimeMillis();
 		if(millis - startStartTime > 6000l && SingleplayerServerController.canKillWorker()) {
 			killTask.enabled = true;
 		}
@@ -164,4 +164,8 @@ public class GuiScreenIntegratedServerBusy extends GuiScreen {
 		return false;
 	}
 
+	public boolean canCloseGui() {
+		return false;
+	}
+
 }
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/gui/GuiScreenIntegratedServerCrashed.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/gui/GuiScreenIntegratedServerCrashed.java
index fb97ea4f..aba74974 100644
--- a/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/gui/GuiScreenIntegratedServerCrashed.java
+++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/gui/GuiScreenIntegratedServerCrashed.java
@@ -2,7 +2,6 @@ package net.lax1dude.eaglercraft.v1_8.sp.gui;
 
 import net.minecraft.client.gui.GuiButton;
 import net.minecraft.client.gui.GuiScreen;
-import net.minecraft.client.gui.ScaledResolution;
 import net.minecraft.client.resources.I18n;
 
 /**
@@ -33,8 +32,7 @@ public class GuiScreenIntegratedServerCrashed extends GuiScreen {
 	public void initGui() {
 		this.buttonList.clear();
 		this.buttonList.add(new GuiButton(0, this.width / 2 - 100, this.height - 50, I18n.format("singleplayer.crashed.continue")));
-		ScaledResolution res = new ScaledResolution(mc);
-		int i = res.getScaleFactor();
+		int i = mc.scaledResolution.getScaleFactor();
 		CrashScreen.showCrashReportOverlay(crashReport, 90 * i, 60 * i, (width - 180) * i, (height - 130) * i);
 	}
 	
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/gui/GuiScreenIntegratedServerFailed.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/gui/GuiScreenIntegratedServerFailed.java
index 2e6a88b6..aba653c0 100644
--- a/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/gui/GuiScreenIntegratedServerFailed.java
+++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/gui/GuiScreenIntegratedServerFailed.java
@@ -1,6 +1,9 @@
 package net.lax1dude.eaglercraft.v1_8.sp.gui;
 
+import net.lax1dude.eaglercraft.v1_8.sp.SingleplayerServerController;
+import net.lax1dude.eaglercraft.v1_8.sp.internal.ClientPlatformSingleplayer;
 import net.minecraft.client.gui.GuiButton;
+import net.minecraft.client.gui.GuiMainMenu;
 import net.minecraft.client.gui.GuiScreen;
 import net.minecraft.client.resources.I18n;
 
@@ -40,6 +43,9 @@ public class GuiScreenIntegratedServerFailed extends GuiScreen {
 	public void initGui() {
 		this.buttonList.clear();
 		this.buttonList.add(new GuiButton(0, this.width / 2 - 100, this.height / 6 + 96, I18n.format("singleplayer.crashed.continue")));
+		if(!ClientPlatformSingleplayer.isRunningSingleThreadMode() && ClientPlatformSingleplayer.isSingleThreadModeSupported()) {
+			this.buttonList.add(new GuiButton(1, this.width / 2 - 100, this.height / 6 + 126, I18n.format("singleplayer.crashed.singleThreadCont")));
+		}
 	}
 
 	public void drawScreen(int par1, int par2, float par3) {
@@ -52,6 +58,12 @@ public class GuiScreenIntegratedServerFailed extends GuiScreen {
 	protected void actionPerformed(GuiButton par1GuiButton) {
 		if(par1GuiButton.id == 0) {
 			this.mc.displayGuiScreen(cont);
+		}else if(par1GuiButton.id == 1) {
+			if(SingleplayerServerController.canKillWorker()) {
+				SingleplayerServerController.killWorker();
+			}
+			this.mc.displayGuiScreen(new GuiScreenIntegratedServerStartup(new GuiMainMenu(), true));
 		}
 	}
+
 }
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/gui/GuiScreenIntegratedServerStartup.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/gui/GuiScreenIntegratedServerStartup.java
index 5b8e5c6f..13ddcf05 100644
--- a/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/gui/GuiScreenIntegratedServerStartup.java
+++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/gui/GuiScreenIntegratedServerStartup.java
@@ -1,8 +1,11 @@
 package net.lax1dude.eaglercraft.v1_8.sp.gui;
 
+import net.lax1dude.eaglercraft.v1_8.EagRuntime;
 import net.lax1dude.eaglercraft.v1_8.sp.SingleplayerServerController;
 import net.lax1dude.eaglercraft.v1_8.sp.WorkerStartupFailedException;
 import net.lax1dude.eaglercraft.v1_8.sp.ipc.IPCPacket15Crashed;
+import net.lax1dude.eaglercraft.v1_8.sp.ipc.IPCPacket1CIssueDetected;
+import net.minecraft.client.gui.GuiButton;
 import net.minecraft.client.gui.GuiMainMenu;
 import net.minecraft.client.gui.GuiScreen;
 import net.minecraft.client.gui.GuiSelectWorld;
@@ -26,31 +29,42 @@ import net.minecraft.client.resources.I18n;
 public class GuiScreenIntegratedServerStartup extends GuiScreen {
 
 	private final GuiScreen backScreen;
+	private final boolean singleThread;
 	private static final String[] dotDotDot = new String[] { "", ".", "..", "..." };
 
 	private int counter = 0;
 
+	private GuiButton cancelButton;
+
 	public GuiScreenIntegratedServerStartup(GuiScreen backScreen) {
 		this.backScreen = backScreen;
+		this.singleThread = false;
 	}
 
-	protected void keyTyped(char parChar1, int parInt1) {
+	public GuiScreenIntegratedServerStartup(GuiScreen backScreen, boolean singleThread) {
+		this.backScreen = backScreen;
+		this.singleThread = singleThread;
 	}
 
 	public void initGui() {
 		this.buttonList.clear();
+		this.buttonList.add(cancelButton = new GuiButton(0, this.width / 2 - 100, this.height / 3 + 50, I18n.format("singleplayer.busy.killTask")));
+		cancelButton.visible = false;
 	}
 
 	public void updateScreen() {
 		++counter;
 		if(counter == 2) {
 			try {
-				SingleplayerServerController.startIntegratedServerWorker();
+				SingleplayerServerController.startIntegratedServerWorker(singleThread);
 			}catch(WorkerStartupFailedException ex) {
 				mc.displayGuiScreen(new GuiScreenIntegratedServerFailed(ex.getMessage(), new GuiMainMenu()));
 				return;
 			}
 		}else if(counter > 2) {
+			if(counter > 100 && SingleplayerServerController.canKillWorker() && !singleThread) {
+				cancelButton.visible = true;
+			}
 			IPCPacket15Crashed[] crashReport = SingleplayerServerController.worldStatusErrors();
 			if(crashReport != null) {
 				mc.displayGuiScreen(GuiScreenIntegratedServerBusy.createException(new GuiMainMenu(), "singleplayer.failed.notStarted", crashReport));
@@ -58,18 +72,33 @@ public class GuiScreenIntegratedServerStartup extends GuiScreen {
 				GuiScreen cont = new GuiSelectWorld(backScreen);
 				if(SingleplayerServerController.isRunningSingleThreadMode()) {
 					cont = new GuiScreenIntegratedServerFailed("singleplayer.failed.singleThreadWarning.1", "singleplayer.failed.singleThreadWarning.2", cont);
+				} else if (!EagRuntime.getConfiguration().isRamdiskMode()
+						&& SingleplayerServerController.isIssueDetected(IPCPacket1CIssueDetected.ISSUE_RAMDISK_MODE)
+						&& SingleplayerServerController.canKillWorker()) {
+					cont = new GuiScreenRAMDiskModeDetected(cont);
 				}
 				mc.displayGuiScreen(cont);
 			}
 		}
 	}
 
+	protected void actionPerformed(GuiButton parGuiButton) {
+		if(parGuiButton.id == 0) {
+			SingleplayerServerController.killWorker();
+			mc.displayGuiScreen(new GuiScreenIntegratedServerStartup(new GuiMainMenu(), true));
+		}
+	}
+
 	public void drawScreen(int i, int j, float f) {
 		this.drawBackground(0);
 		String txt = I18n.format("singleplayer.integratedStartup");
 		int w = this.fontRendererObj.getStringWidth(txt);
-		this.drawString(this.fontRendererObj, txt + dotDotDot[(int)((System.currentTimeMillis() / 300L) % 4L)], (this.width - w) / 2, this.height / 2 - 50, 16777215);
+		this.drawString(this.fontRendererObj, txt + dotDotDot[(int)((EagRuntime.steadyTimeMillis() / 300L) % 4L)], (this.width - w) / 2, this.height / 2 - 50, 16777215);
 		super.drawScreen(i, j, f);
 	}
 
+	public boolean canCloseGui() {
+		return false;
+	}
+
 }
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/gui/GuiScreenLANConnect.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/gui/GuiScreenLANConnect.java
index c6b0aba1..7853f459 100644
--- a/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/gui/GuiScreenLANConnect.java
+++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/gui/GuiScreenLANConnect.java
@@ -1,6 +1,7 @@
 package net.lax1dude.eaglercraft.v1_8.sp.gui;
 
 import net.lax1dude.eaglercraft.v1_8.Keyboard;
+import net.lax1dude.eaglercraft.v1_8.minecraft.EnumInputEvent;
 import net.minecraft.client.gui.GuiButton;
 import net.minecraft.client.gui.GuiScreen;
 import net.minecraft.client.gui.GuiTextField;
@@ -88,4 +89,14 @@ public class GuiScreenLANConnect extends GuiScreen {
 		}
 	}
 
+	@Override
+	public boolean showCopyPasteButtons() {
+		return codeTextField.isFocused();
+	}
+
+	@Override
+	public void fireInputEvent(EnumInputEvent event, String param) {
+		codeTextField.fireInputEvent(event, param);
+	}
+
 }
\ No newline at end of file
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/gui/GuiScreenLANConnecting.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/gui/GuiScreenLANConnecting.java
index d433bfd9..26e4cba1 100644
--- a/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/gui/GuiScreenLANConnecting.java
+++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/gui/GuiScreenLANConnecting.java
@@ -1,7 +1,9 @@
 package net.lax1dude.eaglercraft.v1_8.sp.gui;
 
+import net.lax1dude.eaglercraft.v1_8.EaglercraftVersion;
 import net.lax1dude.eaglercraft.v1_8.internal.PlatformWebRTC;
 import net.lax1dude.eaglercraft.v1_8.profile.EaglerProfile;
+import net.lax1dude.eaglercraft.v1_8.socket.ConnectionHandshake;
 import net.lax1dude.eaglercraft.v1_8.sp.lan.LANClientNetworkManager;
 import net.lax1dude.eaglercraft.v1_8.sp.relay.RelayManager;
 import net.lax1dude.eaglercraft.v1_8.sp.relay.RelayServer;
@@ -120,9 +122,15 @@ public class GuiScreenLANConnecting extends GuiScreen {
 				this.mc.clearTitles();
 				networkManager.setConnectionState(EnumConnectionState.LOGIN);
 				networkManager.setNetHandler(new NetHandlerSingleplayerLogin(networkManager, mc, parent));
-				networkManager.sendPacket(new C00PacketLoginStart(this.mc.getSession().getProfile(), EaglerProfile.getSkinPacket(), EaglerProfile.getCapePacket()));
+				networkManager.sendPacket(new C00PacketLoginStart(this.mc.getSession().getProfile(),
+						EaglerProfile.getSkinPacket(3), EaglerProfile.getCapePacket(),
+						ConnectionHandshake.getSPHandshakeProtocolData(), EaglercraftVersion.clientBrandUUID));
 			}
 		}
 	}
 
+	public boolean canCloseGui() {
+		return false;
+	}
+
 }
\ No newline at end of file
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/gui/GuiScreenNameWorldImport.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/gui/GuiScreenNameWorldImport.java
index eded7662..ff8c54d6 100644
--- a/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/gui/GuiScreenNameWorldImport.java
+++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/gui/GuiScreenNameWorldImport.java
@@ -3,6 +3,7 @@ package net.lax1dude.eaglercraft.v1_8.sp.gui;
 import net.lax1dude.eaglercraft.v1_8.EagRuntime;
 import net.lax1dude.eaglercraft.v1_8.Keyboard;
 import net.lax1dude.eaglercraft.v1_8.internal.FileChooserResult;
+import net.lax1dude.eaglercraft.v1_8.minecraft.EnumInputEvent;
 import net.lax1dude.eaglercraft.v1_8.sp.SingleplayerServerController;
 import net.minecraft.client.gui.GuiButton;
 import net.minecraft.client.gui.GuiCreateWorld;
@@ -144,10 +145,21 @@ public class GuiScreenNameWorldImport extends GuiScreen {
 			this.theGuiTextField.drawTextBox();
 		}else {
 			definetlyTimeToImport = true;
-			long dots = (System.currentTimeMillis() / 500l) % 4l;
+			long dots = (EagRuntime.steadyTimeMillis() / 500l) % 4l;
 			String str = I18n.format("singleplayer.import.reading", world.fileName);
 			this.drawString(fontRendererObj, str + (dots > 0 ? "." : "") + (dots > 1 ? "." : "") + (dots > 2 ? "." : ""), (this.width - this.fontRendererObj.getStringWidth(str)) / 2, this.height / 3 + 10, 0xFFFFFF);
 		}
 		super.drawScreen(par1, par2, par3);
 	}
+
+	@Override
+	public boolean showCopyPasteButtons() {
+		return theGuiTextField.isFocused();
+	}
+
+	@Override
+	public void fireInputEvent(EnumInputEvent event, String param) {
+		theGuiTextField.fireInputEvent(event, param);
+	}
+
 }
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/gui/GuiScreenRAMDiskModeDetected.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/gui/GuiScreenRAMDiskModeDetected.java
new file mode 100644
index 00000000..732f88d6
--- /dev/null
+++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/gui/GuiScreenRAMDiskModeDetected.java
@@ -0,0 +1,55 @@
+package net.lax1dude.eaglercraft.v1_8.sp.gui;
+
+import net.lax1dude.eaglercraft.v1_8.sp.SingleplayerServerController;
+import net.minecraft.client.gui.GuiButton;
+import net.minecraft.client.gui.GuiMainMenu;
+import net.minecraft.client.gui.GuiScreen;
+import net.minecraft.client.resources.I18n;
+
+/**
+ * Copyright (c) 2024 lax1dude. All Rights Reserved.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ * 
+ */
+public class GuiScreenRAMDiskModeDetected extends GuiScreen {
+
+	private GuiScreen cont;
+
+	public GuiScreenRAMDiskModeDetected(GuiScreen cont) {
+		this.cont = cont;
+	}
+
+	public void initGui() {
+		this.buttonList.clear();
+		this.buttonList.add(new GuiButton(0, this.width / 2 - 100, this.height / 6 + 106, I18n.format("singleplayer.ramdiskdetected.continue")));
+		this.buttonList.add(new GuiButton(1, this.width / 2 - 100, this.height / 6 + 136, I18n.format("singleplayer.ramdiskdetected.singleThreadCont")));
+	}
+
+	public void drawScreen(int par1, int par2, float par3) {
+		this.drawDefaultBackground();
+		this.drawCenteredString(fontRendererObj, I18n.format("singleplayer.ramdiskdetected.title"), this.width / 2, 70, 11184810);
+		this.drawCenteredString(fontRendererObj, I18n.format("singleplayer.ramdiskdetected.text0"), this.width / 2, 90, 16777215);
+		this.drawCenteredString(fontRendererObj, I18n.format("singleplayer.ramdiskdetected.text1"), this.width / 2, 105, 16777215);
+		super.drawScreen(par1, par2, par3);
+	}
+
+	protected void actionPerformed(GuiButton par1GuiButton) {
+		if(par1GuiButton.id == 0) {
+			this.mc.displayGuiScreen(cont);
+		}else if(par1GuiButton.id == 1) {
+			SingleplayerServerController.killWorker();
+			mc.displayGuiScreen(new GuiScreenIntegratedServerStartup(new GuiMainMenu(), true));
+		}
+	}
+
+}
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/gui/GuiScreenRelay.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/gui/GuiScreenRelay.java
index da4a48cc..8f10ec17 100644
--- a/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/gui/GuiScreenRelay.java
+++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/gui/GuiScreenRelay.java
@@ -98,7 +98,7 @@ public class GuiScreenRelay extends GuiScreen implements GuiYesNoCallback {
 				selected = 0;
 			}
 		} else if(btn.id == 4) {
-			long millis = System.currentTimeMillis();
+			long millis = EagRuntime.steadyTimeMillis();
 			if(millis - lastRefresh > 700l) {
 				lastRefresh = millis;
 				slots.relayManager.ping();
@@ -106,14 +106,14 @@ public class GuiScreenRelay extends GuiScreen implements GuiYesNoCallback {
 			lastRefresh += 60l;
 		} else if(btn.id == 5) {
 			slots.relayManager.loadDefaults();
-			long millis = System.currentTimeMillis();
+			long millis = EagRuntime.steadyTimeMillis();
 			if(millis - lastRefresh > 700l) {
 				lastRefresh = millis;
 				slots.relayManager.ping();
 			}
 			lastRefresh += 60l;
 		} else if(btn.id == 6) {
-			EagRuntime.downloadFileWithName("EaglerSPRelay.zip", EagRuntime.getResourceBytes("relay_download.zip"));
+			EagRuntime.downloadFileWithName("EaglerSPRelay.zip", EagRuntime.getRequiredResourceBytes("relay_download.zip"));
 		}
 	}
 
@@ -215,4 +215,10 @@ public class GuiScreenRelay extends GuiScreen implements GuiYesNoCallback {
 		this.slots.handleMouseInput();
 	}
 
+	@Override
+	public void handleTouchInput() throws IOException {
+		super.handleTouchInput();
+		this.slots.handleTouchInput();
+	}
+
 }
\ No newline at end of file
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/gui/GuiScreenSingleplayerConnecting.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/gui/GuiScreenSingleplayerConnecting.java
index fb38a61c..89f8d6f4 100644
--- a/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/gui/GuiScreenSingleplayerConnecting.java
+++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/gui/GuiScreenSingleplayerConnecting.java
@@ -2,7 +2,10 @@ package net.lax1dude.eaglercraft.v1_8.sp.gui;
 
 import java.io.IOException;
 
+import net.lax1dude.eaglercraft.v1_8.EagRuntime;
+import net.lax1dude.eaglercraft.v1_8.EaglercraftVersion;
 import net.lax1dude.eaglercraft.v1_8.profile.EaglerProfile;
+import net.lax1dude.eaglercraft.v1_8.socket.ConnectionHandshake;
 import net.lax1dude.eaglercraft.v1_8.sp.SingleplayerServerController;
 import net.lax1dude.eaglercraft.v1_8.sp.socket.ClientIntegratedServerNetworkManager;
 import net.lax1dude.eaglercraft.v1_8.sp.socket.NetHandlerSingleplayerLogin;
@@ -47,7 +50,7 @@ public class GuiScreenSingleplayerConnecting extends GuiScreen {
 	}
 	
 	public void initGui() {
-		if(startStartTime == 0) this.startStartTime = System.currentTimeMillis();
+		if(startStartTime == 0) this.startStartTime = EagRuntime.steadyTimeMillis();
 		this.buttonList.add(killTask = new GuiButton(0, this.width / 2 - 100, this.height / 3 + 50, I18n.format("singleplayer.busy.killTask")));
 		killTask.enabled = false;
 	}
@@ -57,7 +60,7 @@ public class GuiScreenSingleplayerConnecting extends GuiScreen {
 		float f = 2.0f;
 		int top = this.height / 3;
 		
-		long millis = System.currentTimeMillis();
+		long millis = EagRuntime.steadyTimeMillis();
 		
 		long dots = (millis / 500l) % 4l;
 		this.drawString(fontRendererObj, message + (dots > 0 ? "." : "") + (dots > 1 ? "." : "") + (dots > 2 ? "." : ""), (this.width - this.fontRendererObj.getStringWidth(message)) / 2, top + 10, 0xFFFFFF);
@@ -88,7 +91,9 @@ public class GuiScreenSingleplayerConnecting extends GuiScreen {
 						this.mc.clearTitles();
 						this.networkManager.setConnectionState(EnumConnectionState.LOGIN);
 						this.networkManager.setNetHandler(new NetHandlerSingleplayerLogin(this.networkManager, this.mc, this.menu));
-						this.networkManager.sendPacket(new C00PacketLoginStart(this.mc.getSession().getProfile(), EaglerProfile.getSkinPacket(), EaglerProfile.getCapePacket()));
+						this.networkManager.sendPacket(new C00PacketLoginStart(this.mc.getSession().getProfile(),
+								EaglerProfile.getSkinPacket(3), EaglerProfile.getCapePacket(),
+								ConnectionHandshake.getSPHandshakeProtocolData(), EaglercraftVersion.clientBrandUUID));
 					}
 					try {
 						this.networkManager.processReceivedPackets();
@@ -106,7 +111,7 @@ public class GuiScreenSingleplayerConnecting extends GuiScreen {
 			}
 		}
 		
-		long millis = System.currentTimeMillis();
+		long millis = EagRuntime.steadyTimeMillis();
 		if(millis - startStartTime > 6000l && SingleplayerServerController.canKillWorker()) {
 			killTask.enabled = true;
 		}
@@ -124,4 +129,9 @@ public class GuiScreenSingleplayerConnecting extends GuiScreen {
 	public boolean shouldHangupIntegratedServer() {
 		return false;
 	}
+
+	public boolean canCloseGui() {
+		return false;
+	}
+
 }
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/gui/GuiShareToLan.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/gui/GuiShareToLan.java
index cbf896f9..107013f4 100644
--- a/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/gui/GuiShareToLan.java
+++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/gui/GuiShareToLan.java
@@ -1,6 +1,7 @@
 package net.lax1dude.eaglercraft.v1_8.sp.gui;
 
 import net.lax1dude.eaglercraft.v1_8.internal.PlatformWebRTC;
+import net.lax1dude.eaglercraft.v1_8.minecraft.EnumInputEvent;
 import net.lax1dude.eaglercraft.v1_8.sp.SingleplayerServerController;
 import net.lax1dude.eaglercraft.v1_8.sp.lan.LANServerController;
 import net.minecraft.client.LoadingScreenRenderer;
@@ -198,4 +199,15 @@ public class GuiShareToLan extends GuiScreen {
 	public boolean blockPTTKey() {
 		return this.codeTextField.isFocused();
 	}
+
+	@Override
+	public boolean showCopyPasteButtons() {
+		return this.codeTextField.isFocused();
+	}
+
+	@Override
+	public void fireInputEvent(EnumInputEvent event, String param) {
+		this.codeTextField.fireInputEvent(event, param);
+	}
+
 }
\ No newline at end of file
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/gui/GuiSlider2.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/gui/GuiSlider2.java
index 12dc29c5..cba3519f 100644
--- a/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/gui/GuiSlider2.java
+++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/gui/GuiSlider2.java
@@ -27,10 +27,11 @@ public class GuiSlider2 extends GuiButton {
 	/** Is this slider control being dragged. */
 	public boolean dragging = false;
 
-	public GuiSlider2(int par1, int par2, int par3, int par4, int par5, float par6, float par7) {
-		super(par1, par2, par3, par4, par5, (int)(par6 * par7 * 100.0F) + "%");
-		this.sliderValue = par6;
-		this.sliderMax = par7;
+	public GuiSlider2(int buttonId, int x, int y, int widthIn, int heightIn, float sliderValue, float sliderMax) {
+		super(buttonId, x, y, widthIn, heightIn, null);
+		this.sliderValue = sliderValue;
+		this.sliderMax = sliderMax;
+		this.displayString = updateDisplayString();
 	}
 
 	/**
@@ -48,6 +49,7 @@ public class GuiSlider2 extends GuiButton {
 	protected void mouseDragged(Minecraft par1Minecraft, int par2, int par3) {
 		if (this.visible) {
 			if (this.dragging) {
+				float oldValue = sliderValue;
 				this.sliderValue = (float) (par2 - (this.xPosition + 4)) / (float) (this.width - 8);
 
 				if (this.sliderValue < 0.0F) {
@@ -58,7 +60,11 @@ public class GuiSlider2 extends GuiButton {
 					this.sliderValue = 1.0F;
 				}
 
-				this.displayString = (int)(this.sliderValue * this.sliderMax * 100.0F) + "%";
+				if(oldValue != sliderValue) {
+					onChange();
+				}
+
+				this.displayString = updateDisplayString();
 			}
 
 			if(this.enabled) {
@@ -75,6 +81,7 @@ public class GuiSlider2 extends GuiButton {
 	 */
 	public boolean mousePressed(Minecraft par1Minecraft, int par2, int par3) {
 		if (super.mousePressed(par1Minecraft, par2, par3)) {
+			float oldValue = sliderValue;
 			this.sliderValue = (float) (par2 - (this.xPosition + 4)) / (float) (this.width - 8);
 
 			if (this.sliderValue < 0.0F) {
@@ -85,7 +92,11 @@ public class GuiSlider2 extends GuiButton {
 				this.sliderValue = 1.0F;
 			}
 
-			this.displayString = (int)(this.sliderValue * this.sliderMax * 100.0F) + "%";
+			if(oldValue != sliderValue) {
+				onChange();
+			}
+
+			this.displayString = updateDisplayString();
 			this.dragging = true;
 			return true;
 		} else {
@@ -100,4 +111,17 @@ public class GuiSlider2 extends GuiButton {
 	public void mouseReleased(int par1, int par2) {
 		this.dragging = false;
 	}
+
+	protected String updateDisplayString() {
+		return (int)(this.sliderValue * this.sliderMax * 100.0F) + "%";
+	}
+
+	protected void onChange() {
+		
+	}
+
+	public boolean isSliderTouchEvents() {
+		return true;
+	}
+
 }
\ No newline at end of file
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/ipc/IPCPacket14StringList.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/ipc/IPCPacket14StringList.java
index 62c56440..90d3df6c 100644
--- a/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/ipc/IPCPacket14StringList.java
+++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/ipc/IPCPacket14StringList.java
@@ -34,11 +34,11 @@ public class IPCPacket14StringList implements IPCPacketBase {
 	public final List<String> stringList;
 	
 	public IPCPacket14StringList() {
-		stringList = new ArrayList();
+		stringList = new ArrayList<>();
 	}
 	
 	public IPCPacket14StringList(int opcode, String[] list) {
-		stringList = new ArrayList();
+		stringList = new ArrayList<>(list.length);
 		for(int i = 0; i < list.length; ++i) {
 			String s = list[i].trim();
 			if(s.length() > 0) {
@@ -49,7 +49,7 @@ public class IPCPacket14StringList implements IPCPacketBase {
 	}
 	
 	public IPCPacket14StringList(int opcode, List<String> list) {
-		stringList = new ArrayList();
+		stringList = new ArrayList<>(list.size());
 		for(int i = 0, l = list.size(); i < l; ++i) {
 			String s = list.get(i).trim();
 			if(s.length() > 0) {
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/ipc/IPCPacket16NBTList.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/ipc/IPCPacket16NBTList.java
index bb9d464f..d065a082 100644
--- a/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/ipc/IPCPacket16NBTList.java
+++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/ipc/IPCPacket16NBTList.java
@@ -40,8 +40,8 @@ public class IPCPacket16NBTList implements IPCPacketBase {
 	public final List<NBTTagCompound> nbtTagList;
 	
 	public IPCPacket16NBTList() {
-		tagList = new LinkedList();
-		nbtTagList = new LinkedList();
+		tagList = new LinkedList<>();
+		nbtTagList = new LinkedList<>();
 	}
 	
 	public IPCPacket16NBTList(int opcode, NBTTagCompound[] list) {
@@ -49,7 +49,7 @@ public class IPCPacket16NBTList implements IPCPacketBase {
 	}
 	
 	public IPCPacket16NBTList(int opcode, List<NBTTagCompound> list) {
-		tagList = new LinkedList();
+		tagList = new LinkedList<>();
 		nbtTagList = list;
 		for(int i = 0, size = list.size(); i < size; ++i) {
 			NBTTagCompound tag = list.get(i);
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/ipc/IPCPacket17ConfigureLAN.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/ipc/IPCPacket17ConfigureLAN.java
index 272dbc21..21167e54 100644
--- a/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/ipc/IPCPacket17ConfigureLAN.java
+++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/ipc/IPCPacket17ConfigureLAN.java
@@ -30,7 +30,7 @@ public class IPCPacket17ConfigureLAN implements IPCPacketBase {
 	public final List<String> iceServers;
 	
 	public IPCPacket17ConfigureLAN() {
-		iceServers = new ArrayList();
+		iceServers = new ArrayList<>();
 	}
 	
 	public IPCPacket17ConfigureLAN(int gamemode, boolean cheats, List<String> iceServers) {
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/ipc/IPCPacket20LoggerMessage.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/ipc/IPCPacket1ALoggerMessage.java
similarity index 86%
rename from sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/ipc/IPCPacket20LoggerMessage.java
rename to sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/ipc/IPCPacket1ALoggerMessage.java
index 9babf0b6..7404478f 100644
--- a/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/ipc/IPCPacket20LoggerMessage.java
+++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/ipc/IPCPacket1ALoggerMessage.java
@@ -19,22 +19,22 @@ import java.io.IOException;
  * POSSIBILITY OF SUCH DAMAGE.
  * 
  */
-public class IPCPacket20LoggerMessage implements IPCPacketBase {
+public class IPCPacket1ALoggerMessage implements IPCPacketBase {
 	
-	public static final int ID = 0x20;
+	public static final int ID = 0x1A;
 
 	public String logMessage;
 	public boolean isError;
 	
-	public IPCPacket20LoggerMessage() {
+	public IPCPacket1ALoggerMessage() {
 	}
 	
-	public IPCPacket20LoggerMessage(String logMessage, boolean isError) {
+	public IPCPacket1ALoggerMessage(String logMessage, boolean isError) {
 		this.logMessage = logMessage;
 		this.isError = isError;
 	}
 	
-	public IPCPacket20LoggerMessage(String logMessage) {
+	public IPCPacket1ALoggerMessage(String logMessage) {
 		this.logMessage = logMessage;
 		this.isError = false;
 	}
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/ipc/IPCPacket21EnableLogging.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/ipc/IPCPacket1BEnableLogging.java
similarity index 87%
rename from sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/ipc/IPCPacket21EnableLogging.java
rename to sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/ipc/IPCPacket1BEnableLogging.java
index 7c9423d2..a3e5afd1 100644
--- a/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/ipc/IPCPacket21EnableLogging.java
+++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/ipc/IPCPacket1BEnableLogging.java
@@ -19,16 +19,16 @@ import java.io.IOException;
  * POSSIBILITY OF SUCH DAMAGE.
  * 
  */
-public class IPCPacket21EnableLogging implements IPCPacketBase {
+public class IPCPacket1BEnableLogging implements IPCPacketBase {
 	
-	public static final int ID = 0x21;
+	public static final int ID = 0x1B;
 
 	public boolean enable;
 	
-	public IPCPacket21EnableLogging() {
+	public IPCPacket1BEnableLogging() {
 	}
 	
-	public IPCPacket21EnableLogging(boolean enable) {
+	public IPCPacket1BEnableLogging(boolean enable) {
 		this.enable = enable;
 	}
 
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/ipc/IPCPacket1CIssueDetected.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/ipc/IPCPacket1CIssueDetected.java
new file mode 100644
index 00000000..51a5e962
--- /dev/null
+++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/ipc/IPCPacket1CIssueDetected.java
@@ -0,0 +1,57 @@
+package net.lax1dude.eaglercraft.v1_8.sp.ipc;
+
+import java.io.DataInput;
+import java.io.DataOutput;
+import java.io.IOException;
+
+/**
+ * Copyright (c) 2024 lax1dude. All Rights Reserved.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ * 
+ */
+public class IPCPacket1CIssueDetected implements IPCPacketBase {
+
+	public static final int ID = 0x1C;
+
+	public static final int ISSUE_RAMDISK_MODE = 0x01;
+
+	public int issueID;
+
+	public IPCPacket1CIssueDetected() {
+	}
+
+	public IPCPacket1CIssueDetected(int issueID) {
+		this.issueID = issueID;
+	}
+
+	@Override
+	public void deserialize(DataInput bin) throws IOException {
+		issueID = bin.readUnsignedByte();
+	}
+
+	@Override
+	public void serialize(DataOutput bin) throws IOException {
+		bin.writeByte(issueID);
+	}
+
+	@Override
+	public int id() {
+		return ID;
+	}
+
+	@Override
+	public int size() {
+		return 1;
+	}
+
+}
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/ipc/IPCPacketManager.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/ipc/IPCPacketManager.java
index f501c67d..6363efa2 100644
--- a/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/ipc/IPCPacketManager.java
+++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/ipc/IPCPacketManager.java
@@ -23,7 +23,7 @@ import java.util.function.Supplier;
  */
 public class IPCPacketManager {
 	
-	public static final HashMap<Integer, Supplier<IPCPacketBase>> mappings = new HashMap();
+	public static final HashMap<Integer, Supplier<IPCPacketBase>> mappings = new HashMap<>();
 
 	public final IPCInputStream IPC_INPUT_STREAM = new IPCInputStream();
 	public final IPCOutputStream IPC_OUTPUT_STREAM = new IPCOutputStream();
@@ -55,8 +55,9 @@ public class IPCPacketManager {
 		mappings.put(IPCPacket17ConfigureLAN.ID, IPCPacket17ConfigureLAN::new);
 		mappings.put(IPCPacket18ClearPlayers.ID, IPCPacket18ClearPlayers::new);
 		mappings.put(IPCPacket19Autosave.ID, IPCPacket19Autosave::new);
-		mappings.put(IPCPacket20LoggerMessage.ID, IPCPacket20LoggerMessage::new);
-		mappings.put(IPCPacket21EnableLogging.ID, IPCPacket21EnableLogging::new);
+		mappings.put(IPCPacket1ALoggerMessage.ID, IPCPacket1ALoggerMessage::new);
+		mappings.put(IPCPacket1BEnableLogging.ID, IPCPacket1BEnableLogging::new);
+		mappings.put(IPCPacket1CIssueDetected.ID, IPCPacket1CIssueDetected::new);
 		mappings.put(IPCPacketFFProcessKeepAlive.ID, IPCPacketFFProcessKeepAlive::new);
 	}
 	
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/lan/LANClientNetworkManager.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/lan/LANClientNetworkManager.java
index d442f9fb..15a1054b 100644
--- a/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/lan/LANClientNetworkManager.java
+++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/lan/LANClientNetworkManager.java
@@ -1,5 +1,6 @@
 package net.lax1dude.eaglercraft.v1_8.sp.lan;
 
+import net.lax1dude.eaglercraft.v1_8.EagRuntime;
 import net.lax1dude.eaglercraft.v1_8.EagUtils;
 import net.lax1dude.eaglercraft.v1_8.EaglerInputStream;
 import net.lax1dude.eaglercraft.v1_8.EaglerZLIB;
@@ -75,15 +76,17 @@ public class LANClientNetworkManager extends EaglercraftNetworkManager {
 	public static LANClientNetworkManager connectToWorld(RelayServerSocket sock, String displayCode, String displayRelay) {
 		PlatformWebRTC.clearLANClientState();
 		int connectState = PRE;
-		IPacket pkt;
+		RelayPacket pkt;
 		mainLoop: while(!sock.isClosed()) {
+			PlatformWebRTC.runScheduledTasks();
+			sock.update();
 			if((pkt = sock.readPacket()) != null) {
-				if(pkt instanceof IPacket00Handshake) {
+				if(pkt instanceof RelayPacket00Handshake) {
 					if(connectState == PRE) {
 
 						// %%%%%%  Process IPacket00Handshake  %%%%%%
 
-						logger.info("Relay [{}|{}] recieved handshake, client id: {}", displayRelay, displayCode, ((IPacket00Handshake)pkt).connectionCode);
+						logger.info("Relay [{}|{}] recieved handshake, client id: {}", displayRelay, displayCode, ((RelayPacket00Handshake)pkt).connectionCode);
 						connectState = INIT;
 
 					}else {
@@ -91,17 +94,17 @@ public class LANClientNetworkManager extends EaglercraftNetworkManager {
 						logger.error("Relay [{}|{}] unexpected packet: IPacket00Handshake in state {}", displayRelay, displayCode, initStateNames[connectState]);
 						return null;
 					}
-				}else if(pkt instanceof IPacket01ICEServers) {
+				}else if(pkt instanceof RelayPacket01ICEServers) {
 					if(connectState == INIT) {
 
 						// %%%%%%  Process IPacket01ICEServers  %%%%%%
 
-						IPacket01ICEServers ipkt = (IPacket01ICEServers) pkt;
+						RelayPacket01ICEServers ipkt = (RelayPacket01ICEServers) pkt;
 
 						// print servers
 						logger.info("Relay [{}|{}] provided ICE servers:", displayRelay, displayCode);
-						List<String> servers = new ArrayList();
-						for(ICEServerSet.RelayServer srv : ipkt.servers) {
+						List<String> servers = new ArrayList<>();
+						for(RelayPacket01ICEServers.RelayServer srv : ipkt.servers) {
 							logger.info("Relay [{}|{}]     {}: {}", displayRelay, displayCode, srv.type.name(), srv.address);
 							servers.add(srv.getICEString());
 						}
@@ -110,20 +113,21 @@ public class LANClientNetworkManager extends EaglercraftNetworkManager {
 						PlatformWebRTC.clientLANSetICEServersAndConnect(servers.toArray(new String[servers.size()]));
 
 						// await result
-						long lm = System.currentTimeMillis();
+						long lm = EagRuntime.steadyTimeMillis();
 						do {
+							PlatformWebRTC.runScheduledTasks();
 							String c = PlatformWebRTC.clientLANAwaitDescription();
 							if(c != null) {
 								logger.info("Relay [{}|{}] client sent description", displayRelay, displayCode);
 
 								// 'this.descriptionHandler' was called, send result:
-								sock.writePacket(new IPacket04Description("", c));
+								sock.writePacket(new RelayPacket04Description("", c));
 
 								connectState = SENT_DESCRIPTION;
 								continue mainLoop;
 							}
 							EagUtils.sleep(20l);
-						}while(System.currentTimeMillis() - lm < 5000l);
+						}while(EagRuntime.steadyTimeMillis() - lm < 5000l);
 
 						// no description was sent
 						sock.close();
@@ -135,34 +139,35 @@ public class LANClientNetworkManager extends EaglercraftNetworkManager {
 						logger.error("Relay [{}|{}] unexpected packet: IPacket01ICEServers in state {}", displayRelay, displayCode, initStateNames[connectState]);
 						return null;
 					}
-				}else if(pkt instanceof IPacket03ICECandidate) {
+				}else if(pkt instanceof RelayPacket03ICECandidate) {
 					if(connectState == SENT_ICE_CANDIDATE) {
 
 						// %%%%%%  Process IPacket03ICECandidate  %%%%%%
 
-						IPacket03ICECandidate ipkt = (IPacket03ICECandidate) pkt;
+						RelayPacket03ICECandidate ipkt = (RelayPacket03ICECandidate) pkt;
 
 						// process
 						logger.info("Relay [{}|{}] recieved server ICE candidate", displayRelay, displayCode);
-						PlatformWebRTC.clientLANSetICECandidate(ipkt.candidate);
+						PlatformWebRTC.clientLANSetICECandidate(ipkt.getCandidateString());
 
 						// await result
-						long lm = System.currentTimeMillis();
+						long lm = EagRuntime.steadyTimeMillis();
 						do {
+							PlatformWebRTC.runScheduledTasks();
 							if(PlatformWebRTC.clientLANAwaitChannel()) {
 								logger.info("Relay [{}|{}] client opened data channel", displayRelay, displayCode);
 
 								// 'this.remoteDataChannelHandler' was called, success
-								sock.writePacket(new IPacket05ClientSuccess(ipkt.peerId));
+								sock.writePacket(new RelayPacket05ClientSuccess(ipkt.peerId));
 								sock.close();
 								return new LANClientNetworkManager(displayCode, displayRelay);
 
 							}
 							EagUtils.sleep(20l);
-						}while(System.currentTimeMillis() - lm < 5000l);
+						}while(EagRuntime.steadyTimeMillis() - lm < 5000l);
 
 						// no channel was opened
-						sock.writePacket(new IPacket06ClientFailure(ipkt.peerId));
+						sock.writePacket(new RelayPacket06ClientFailure(ipkt.peerId));
 						sock.close();
 						logger.error("Relay [{}|{}] client open data channel timeout", displayRelay, displayCode);
 						return null;
@@ -172,32 +177,33 @@ public class LANClientNetworkManager extends EaglercraftNetworkManager {
 						logger.error("Relay [{}|{}] unexpected packet: IPacket03ICECandidate in state {}", displayRelay, displayCode, initStateNames[connectState]);
 						return null;
 					}
-				}else if(pkt instanceof IPacket04Description) {
+				}else if(pkt instanceof RelayPacket04Description) {
 					if(connectState == SENT_DESCRIPTION) {
 
 						// %%%%%%  Process IPacket04Description  %%%%%%
 
-						IPacket04Description ipkt = (IPacket04Description) pkt;
+						RelayPacket04Description ipkt = (RelayPacket04Description) pkt;
 
 						// process
 						logger.info("Relay [{}|{}] recieved server description", displayRelay, displayCode);
-						PlatformWebRTC.clientLANSetDescription(ipkt.description);
+						PlatformWebRTC.clientLANSetDescription(ipkt.getDescriptionString());
 
 						// await result
-						long lm = System.currentTimeMillis();
+						long lm = EagRuntime.steadyTimeMillis();
 						do {
+							PlatformWebRTC.runScheduledTasks();
 							String c = PlatformWebRTC.clientLANAwaitICECandidate();
 							if(c != null) {
 								logger.info("Relay [{}|{}] client sent ICE candidate", displayRelay, displayCode);
 
 								// 'this.iceCandidateHandler' was called, send result:
-								sock.writePacket(new IPacket03ICECandidate("", c));
+								sock.writePacket(new RelayPacket03ICECandidate("", c));
 
 								connectState = SENT_ICE_CANDIDATE;
 								continue mainLoop;
 							}
 							EagUtils.sleep(20l);
-						}while(System.currentTimeMillis() - lm < 5000l);
+						}while(EagRuntime.steadyTimeMillis() - lm < 5000l);
 
 						// no ice candidates were sent
 						sock.close();
@@ -209,12 +215,12 @@ public class LANClientNetworkManager extends EaglercraftNetworkManager {
 						logger.error("Relay [{}|{}] unexpected packet: IPacket04Description in state {}", displayRelay, displayCode, initStateNames[connectState]);
 						return null;
 					}
-				}else if(pkt instanceof IPacketFFErrorCode) {
+				}else if(pkt instanceof RelayPacketFFErrorCode) {
 
 					// %%%%%%  Process IPacketFFErrorCode  %%%%%%
 
-					IPacketFFErrorCode ipkt = (IPacketFFErrorCode) pkt;
-					logger.error("Relay [{}|{}] connection failed: {}({}): {}", displayRelay, displayCode, IPacketFFErrorCode.code2string(ipkt.code), ipkt.code, ipkt.desc);
+					RelayPacketFFErrorCode ipkt = (RelayPacketFFErrorCode) pkt;
+					logger.error("Relay [{}|{}] connection failed: {}({}): {}", displayRelay, displayCode, RelayPacketFFErrorCode.code2string(ipkt.code), ipkt.code, ipkt.desc);
 					Throwable t;
 					while((t = sock.getException()) != null) {
 						logger.error(t);
@@ -291,7 +297,7 @@ public class LANClientNetworkManager extends EaglercraftNetworkManager {
 		return !clientDisconnected;
 	}
 
-	private List<byte[]> fragmentedPacket = new ArrayList();
+	private List<byte[]> fragmentedPacket = new ArrayList<>();
 
 	@Override
 	public void processReceivedPackets() throws IOException {
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/lan/LANClientPeer.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/lan/LANClientPeer.java
index 425f34b1..817bc4cf 100644
--- a/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/lan/LANClientPeer.java
+++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/lan/LANClientPeer.java
@@ -3,6 +3,7 @@ package net.lax1dude.eaglercraft.v1_8.sp.lan;
 import java.util.Iterator;
 import java.util.List;
 
+import net.lax1dude.eaglercraft.v1_8.EagRuntime;
 import net.lax1dude.eaglercraft.v1_8.EagUtils;
 import net.lax1dude.eaglercraft.v1_8.internal.IPCPacketData;
 import net.lax1dude.eaglercraft.v1_8.internal.PlatformWebRTC;
@@ -10,8 +11,8 @@ import net.lax1dude.eaglercraft.v1_8.log4j.LogManager;
 import net.lax1dude.eaglercraft.v1_8.log4j.Logger;
 import net.lax1dude.eaglercraft.v1_8.sp.SingleplayerServerController;
 import net.lax1dude.eaglercraft.v1_8.sp.internal.ClientPlatformSingleplayer;
-import net.lax1dude.eaglercraft.v1_8.sp.relay.pkt.IPacket03ICECandidate;
-import net.lax1dude.eaglercraft.v1_8.sp.relay.pkt.IPacket04Description;
+import net.lax1dude.eaglercraft.v1_8.sp.relay.pkt.RelayPacket03ICECandidate;
+import net.lax1dude.eaglercraft.v1_8.sp.relay.pkt.RelayPacket04Description;
 
 /**
  * Copyright (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved.
@@ -47,12 +48,12 @@ class LANClientPeer {
 	protected void handleICECandidates(String candidates) {
 		if(state == SENT_DESCRIPTION) {
 			PlatformWebRTC.serverLANPeerICECandidates(clientId, candidates);
-			long millis = System.currentTimeMillis();
+			long millis = EagRuntime.steadyTimeMillis();
 			do {
 				LANPeerEvent evt;
 				if((evt = PlatformWebRTC.serverLANGetEvent(clientId)) != null) {
 					if(evt instanceof LANPeerEvent.LANPeerICECandidateEvent) {
-						LANServerController.lanRelaySocket.writePacket(new IPacket03ICECandidate(clientId, ((LANPeerEvent.LANPeerICECandidateEvent)evt).candidates));
+						LANServerController.lanRelaySocket.writePacket(new RelayPacket03ICECandidate(clientId, ((LANPeerEvent.LANPeerICECandidateEvent)evt).candidates));
 						state = SENT_ICE_CANDIDATE;
 						return;
 					}else if(evt instanceof LANPeerEvent.LANPeerDisconnectEvent) {
@@ -64,7 +65,7 @@ class LANClientPeer {
 					return;
 				}
 				EagUtils.sleep(20l);
-			}while(System.currentTimeMillis() - millis < 5000l);
+			}while(EagRuntime.steadyTimeMillis() - millis < 5000l);
 			logger.error("Getting server ICE candidates for '{}' timed out!", clientId);
 			disconnect();
 		}else {
@@ -75,12 +76,12 @@ class LANClientPeer {
 	protected void handleDescription(String description) {
 		if(state == PRE) {
 			PlatformWebRTC.serverLANPeerDescription(clientId, description);
-			long millis = System.currentTimeMillis();
+			long millis = EagRuntime.steadyTimeMillis();
 			do {
 				LANPeerEvent evt;
 				if((evt = PlatformWebRTC.serverLANGetEvent(clientId)) != null) {
 					if(evt instanceof LANPeerEvent.LANPeerDescriptionEvent) {
-						LANServerController.lanRelaySocket.writePacket(new IPacket04Description(clientId, ((LANPeerEvent.LANPeerDescriptionEvent)evt).description));
+						LANServerController.lanRelaySocket.writePacket(new RelayPacket04Description(clientId, ((LANPeerEvent.LANPeerDescriptionEvent)evt).description));
 						state = SENT_DESCRIPTION;
 						return;
 					}else if(evt instanceof LANPeerEvent.LANPeerDisconnectEvent) {
@@ -92,7 +93,7 @@ class LANClientPeer {
 					return;
 				}
 				EagUtils.sleep(20l);
-			}while(System.currentTimeMillis() - millis < 5000l);
+			}while(EagRuntime.steadyTimeMillis() - millis < 5000l);
 			logger.error("Getting server description for '{}' timed out!", clientId);
 			disconnect();
 		}else {
@@ -102,7 +103,7 @@ class LANClientPeer {
 
 	protected void handleSuccess() {
 		if(state == SENT_ICE_CANDIDATE) {
-			long millis = System.currentTimeMillis();
+			long millis = EagRuntime.steadyTimeMillis();
 			do {
 				LANPeerEvent evt;
 				while((evt = PlatformWebRTC.serverLANGetEvent(clientId)) != null && evt instanceof LANPeerEvent.LANPeerICECandidateEvent) {
@@ -122,7 +123,7 @@ class LANClientPeer {
 					return;
 				}
 				EagUtils.sleep(20l);
-			}while(System.currentTimeMillis() - millis < 5000l);
+			}while(EagRuntime.steadyTimeMillis() - millis < 5000l);
 			logger.error("Getting server description for '{}' timed out!", clientId);
 			disconnect();
 		}else {
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/lan/LANServerController.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/lan/LANServerController.java
index 401b1988..c743baf0 100644
--- a/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/lan/LANServerController.java
+++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/lan/LANServerController.java
@@ -7,6 +7,7 @@ import java.util.List;
 import java.util.Map;
 import java.util.function.Consumer;
 
+import net.lax1dude.eaglercraft.v1_8.EagRuntime;
 import net.lax1dude.eaglercraft.v1_8.EagUtils;
 import net.lax1dude.eaglercraft.v1_8.internal.PlatformWebRTC;
 import net.lax1dude.eaglercraft.v1_8.log4j.LogManager;
@@ -34,7 +35,7 @@ public class LANServerController {
 
 	public static final Logger logger = LogManager.getLogger("LANServerController");
 
-	public static final List<String> currentICEServers = new ArrayList();
+	public static final List<String> currentICEServers = new ArrayList<>();
 
 	static RelayServerSocket lanRelaySocket = null;
 
@@ -49,25 +50,26 @@ public class LANServerController {
 			return null;
 		}else {
 			progressCallback.accept("Opening: " + sock.getURI());
-			IPacket00Handshake hs = (IPacket00Handshake)sock.readPacket();
+			RelayPacket00Handshake hs = (RelayPacket00Handshake)sock.readPacket();
 			lanRelaySocket = sock;
 			String code = hs.connectionCode;
 			logger.info("Relay [{}] connected as 'server', code: {}", sock.getURI(), code);
 			progressCallback.accept("Opened '" + code + "' on " + sock.getURI());
-			long millis = System.currentTimeMillis();
+			long millis = EagRuntime.steadyTimeMillis();
 			do {
+				sock.update();
 				if(sock.isClosed()) {
 					logger.info("Relay [{}] connection lost", sock.getURI());
 					lanRelaySocket = null;
 					return null;
 				}
-				IPacket pkt = sock.readPacket();
+				RelayPacket pkt = sock.readPacket();
 				if(pkt != null) {
-					if(pkt instanceof IPacket01ICEServers) {
-						IPacket01ICEServers ipkt = (IPacket01ICEServers)pkt;
+					if(pkt instanceof RelayPacket01ICEServers) {
+						RelayPacket01ICEServers ipkt = (RelayPacket01ICEServers)pkt;
 						logger.info("Relay [{}] provided ICE servers:", sock.getURI());
 						currentICEServers.clear();
-						for(net.lax1dude.eaglercraft.v1_8.sp.relay.pkt.ICEServerSet.RelayServer srv : ipkt.servers) {
+						for(net.lax1dude.eaglercraft.v1_8.sp.relay.pkt.RelayPacket01ICEServers.RelayServer srv : ipkt.servers) {
 							logger.info("Relay [{}]     {}: {}", sock.getURI(), srv.type.name(), srv.address);
 							currentICEServers.add(srv.getICEString());
 						}
@@ -80,7 +82,7 @@ public class LANServerController {
 					}
 				}
 				EagUtils.sleep(50l);
-			}while(System.currentTimeMillis() - millis < 1000l);
+			}while(EagRuntime.steadyTimeMillis() - millis < 1000l);
 			logger.info("Relay [{}] relay provide ICE servers timeout", sock.getURI());
 			closeLAN();
 			return null;
@@ -131,54 +133,55 @@ public class LANServerController {
 		return lanRelaySocket != null;
 	}
 
-	private static final Map<String, LANClientPeer> clients = new HashMap();
+	private static final Map<String, LANClientPeer> clients = new HashMap<>();
 
 	public static void updateLANServer() {
 		if(lanRelaySocket != null) {
-			IPacket pkt;
+			lanRelaySocket.update();
+			RelayPacket pkt;
 			while((pkt = lanRelaySocket.readPacket()) != null) {
-				if(pkt instanceof IPacket02NewClient) {
-					IPacket02NewClient ipkt = (IPacket02NewClient) pkt;
+				if(pkt instanceof RelayPacket02NewClient) {
+					RelayPacket02NewClient ipkt = (RelayPacket02NewClient) pkt;
 					if(clients.containsKey(ipkt.clientId)) {
 						logger.error("Relay [{}] relay provided duplicate client '{}'", lanRelaySocket.getURI(), ipkt.clientId);
 					}else {
 						clients.put(ipkt.clientId, new LANClientPeer(ipkt.clientId));
 					}
-				}else if(pkt instanceof IPacket03ICECandidate) {
-					IPacket03ICECandidate ipkt = (IPacket03ICECandidate) pkt;
+				}else if(pkt instanceof RelayPacket03ICECandidate) {
+					RelayPacket03ICECandidate ipkt = (RelayPacket03ICECandidate) pkt;
 					LANClientPeer c = clients.get(ipkt.peerId);
 					if(c != null) {
-						c.handleICECandidates(ipkt.candidate);
+						c.handleICECandidates(ipkt.getCandidateString());
 					}else {
 						logger.error("Relay [{}] relay sent IPacket03ICECandidate for unknown client '{}'", lanRelaySocket.getURI(), ipkt.peerId);
 					}
-				}else if(pkt instanceof IPacket04Description) {
-					IPacket04Description ipkt = (IPacket04Description) pkt;
+				}else if(pkt instanceof RelayPacket04Description) {
+					RelayPacket04Description ipkt = (RelayPacket04Description) pkt;
 					LANClientPeer c = clients.get(ipkt.peerId);
 					if(c != null) {
-						c.handleDescription(ipkt.description);
+						c.handleDescription(ipkt.getDescriptionString());
 					}else {
 						logger.error("Relay [{}] relay sent IPacket04Description for unknown client '{}'", lanRelaySocket.getURI(), ipkt.peerId);
 					}
-				}else if(pkt instanceof IPacket05ClientSuccess) {
-					IPacket05ClientSuccess ipkt = (IPacket05ClientSuccess) pkt;
+				}else if(pkt instanceof RelayPacket05ClientSuccess) {
+					RelayPacket05ClientSuccess ipkt = (RelayPacket05ClientSuccess) pkt;
 					LANClientPeer c = clients.get(ipkt.clientId);
 					if(c != null) {
 						c.handleSuccess();
 					}else {
 						logger.error("Relay [{}] relay sent IPacket05ClientSuccess for unknown client '{}'", lanRelaySocket.getURI(), ipkt.clientId);
 					}
-				}else if(pkt instanceof IPacket06ClientFailure) {
-					IPacket06ClientFailure ipkt = (IPacket06ClientFailure) pkt;
+				}else if(pkt instanceof RelayPacket06ClientFailure) {
+					RelayPacket06ClientFailure ipkt = (RelayPacket06ClientFailure) pkt;
 					LANClientPeer c = clients.get(ipkt.clientId);
 					if(c != null) {
 						c.handleFailure();
 					}else {
 						logger.error("Relay [{}] relay sent IPacket06ClientFailure for unknown client '{}'", lanRelaySocket.getURI(), ipkt.clientId);
 					}
-				}else if(pkt instanceof IPacketFFErrorCode) {
-					IPacketFFErrorCode ipkt = (IPacketFFErrorCode) pkt;
-					logger.error("Relay [{}] error code thrown: {}({}): {}", lanRelaySocket.getURI(), IPacketFFErrorCode.code2string(ipkt.code), ipkt.code, ipkt.desc);
+				}else if(pkt instanceof RelayPacketFFErrorCode) {
+					RelayPacketFFErrorCode ipkt = (RelayPacketFFErrorCode) pkt;
+					logger.error("Relay [{}] error code thrown: {}({}): {}", lanRelaySocket.getURI(), RelayPacketFFErrorCode.code2string(ipkt.code), ipkt.code, ipkt.desc);
 					Throwable t;
 					while((t = lanRelaySocket.getException()) != null) {
 						logger.error(t);
@@ -186,6 +189,7 @@ public class LANServerController {
 				}else {
 					logger.error("Relay [{}] unexpected packet: {}", lanRelaySocket.getURI(), pkt.getClass().getSimpleName());
 				}
+				lanRelaySocket.update();
 			}
 			if(lanRelaySocket.isClosed()) {
 				lanRelaySocket = null;
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/lan/LANServerList.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/lan/LANServerList.java
index a9bd0025..d396f6ee 100644
--- a/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/lan/LANServerList.java
+++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/lan/LANServerList.java
@@ -9,11 +9,12 @@ import java.util.Map;
 import java.util.Map.Entry;
 import java.util.Set;
 
+import net.lax1dude.eaglercraft.v1_8.EagRuntime;
 import net.lax1dude.eaglercraft.v1_8.internal.PlatformWebRTC;
 import net.lax1dude.eaglercraft.v1_8.sp.relay.RelayManager;
 import net.lax1dude.eaglercraft.v1_8.sp.relay.RelayServer;
 import net.lax1dude.eaglercraft.v1_8.sp.relay.RelayWorldsQuery;
-import net.lax1dude.eaglercraft.v1_8.sp.relay.pkt.IPacket07LocalWorlds;
+import net.lax1dude.eaglercraft.v1_8.sp.relay.pkt.RelayPacket07LocalWorlds;
 
 /**
  * Copyright (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved.
@@ -32,15 +33,15 @@ import net.lax1dude.eaglercraft.v1_8.sp.relay.pkt.IPacket07LocalWorlds;
  */
 public class LANServerList {
 	
-	private final List<LanServer> lanServersList = new LinkedList();
-	private final Map<String, RelayWorldsQuery> lanServersQueryList = new LinkedHashMap();
-	private final Set<String> deadURIs = new HashSet();
+	private final List<LanServer> lanServersList = new LinkedList<>();
+	private final Map<String, RelayWorldsQuery> lanServersQueryList = new LinkedHashMap<>();
+	private final Set<String> deadURIs = new HashSet<>();
 	
 	private long lastRefresh = 0l;
 	private int refreshCounter = 0;
 	
 	public boolean update() {
-		long millis = System.currentTimeMillis();
+		long millis = EagRuntime.steadyTimeMillis();
 		if(millis - lastRefresh > 20000l) {
 			if(++refreshCounter < 10) {
 				refresh();
@@ -54,6 +55,7 @@ public class LANServerList {
 				Entry<String,RelayWorldsQuery> etr = itr.next();
 				String uri = etr.getKey();
 				RelayWorldsQuery q = etr.getValue();
+				q.update();
 				if(!q.isQueryOpen()) {
 					itr.remove();
 					if(q.isQueryFailed()) {
@@ -75,9 +77,9 @@ public class LANServerList {
 							}
 						}
 						if(rl != null) {
-							Iterator<IPacket07LocalWorlds.LocalWorld> itr3 = q.getWorlds().iterator();
+							Iterator<RelayPacket07LocalWorlds.LocalWorld> itr3 = q.getWorlds().iterator();
 							yee: while(itr3.hasNext()) {
-								IPacket07LocalWorlds.LocalWorld l = itr3.next();
+								RelayPacket07LocalWorlds.LocalWorld l = itr3.next();
 								itr2 = lanServersList.iterator();
 								while(itr2.hasNext()) {
 									LanServer l2 = itr2.next();
@@ -116,7 +118,7 @@ public class LANServerList {
 	}
 
 	private void refresh() {
-		lastRefresh = System.currentTimeMillis();
+		lastRefresh = EagRuntime.steadyTimeMillis();
 		if(PlatformWebRTC.supported()) {
 			for(int i = 0, l = RelayManager.relayManager.count(); i < l; ++i) {
 				RelayServer srv = RelayManager.relayManager.get(i);
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/relay/RelayLoggerImpl.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/relay/RelayLoggerImpl.java
new file mode 100644
index 00000000..c9344cc5
--- /dev/null
+++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/relay/RelayLoggerImpl.java
@@ -0,0 +1,54 @@
+package net.lax1dude.eaglercraft.v1_8.sp.relay;
+
+import net.lax1dude.eaglercraft.v1_8.log4j.Logger;
+import net.lax1dude.eaglercraft.v1_8.sp.relay.pkt.IRelayLogger;
+
+/**
+ * Copyright (c) 2024 lax1dude. All Rights Reserved.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ * 
+ */
+public class RelayLoggerImpl implements IRelayLogger {
+
+	private final Logger impl;
+
+	public RelayLoggerImpl(Logger impl) {
+		this.impl = impl;
+	}
+
+	@Override
+	public void debug(String msg, Object... args) {
+		impl.debug(msg, args);
+	}
+
+	@Override
+	public void info(String msg, Object... args) {
+		impl.debug(msg, args);
+	}
+
+	@Override
+	public void warn(String msg, Object... args) {
+		impl.warn(msg, args);
+	}
+
+	@Override
+	public void error(String msg, Object... args) {
+		impl.error(msg, args);
+	}
+
+	@Override
+	public void error(Throwable th) {
+		impl.error(th);
+	}
+
+}
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/relay/RelayManager.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/relay/RelayManager.java
index 6c9f3a86..937d5803 100644
--- a/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/relay/RelayManager.java
+++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/relay/RelayManager.java
@@ -14,9 +14,9 @@ import net.lax1dude.eaglercraft.v1_8.EaglerOutputStream;
 import net.lax1dude.eaglercraft.v1_8.ThreadLocalRandom;
 import net.lax1dude.eaglercraft.v1_8.log4j.LogManager;
 import net.lax1dude.eaglercraft.v1_8.log4j.Logger;
-import net.lax1dude.eaglercraft.v1_8.sp.relay.pkt.IPacket;
-import net.lax1dude.eaglercraft.v1_8.sp.relay.pkt.IPacket00Handshake;
-import net.lax1dude.eaglercraft.v1_8.sp.relay.pkt.IPacketFFErrorCode;
+import net.lax1dude.eaglercraft.v1_8.sp.relay.pkt.RelayPacket;
+import net.lax1dude.eaglercraft.v1_8.sp.relay.pkt.RelayPacket00Handshake;
+import net.lax1dude.eaglercraft.v1_8.sp.relay.pkt.RelayPacketFFErrorCode;
 import net.minecraft.nbt.CompressedStreamTools;
 import net.minecraft.nbt.NBTTagCompound;
 import net.minecraft.nbt.NBTTagList;
@@ -43,7 +43,7 @@ public class RelayManager {
 	public static final RelayManager relayManager = new RelayManager();
 	public static final int preferredRelayVersion = 1;
 	
-	private final List<RelayServer> relays = new ArrayList();
+	private final List<RelayServer> relays = new ArrayList<>();
 	private long lastPingThrough = 0l;
 
 	public void load(byte[] relayConfig) {
@@ -180,7 +180,7 @@ public class RelayManager {
 	}
 	
 	public void ping() {
-		lastPingThrough = System.currentTimeMillis();
+		lastPingThrough = EagRuntime.steadyTimeMillis();
 		for(int i = 0, l = relays.size(); i < l; ++i) {
 			relays.get(i).ping();
 		}
@@ -274,16 +274,18 @@ public class RelayManager {
 	public RelayServerSocket connectHandshake(RelayServer relay, int type, String code) {
 		RelayServerSocket sock = relay.openSocket();
 		while(!sock.isClosed()) {
+			sock.update();
 			if(sock.isOpen()) {
-				sock.writePacket(new IPacket00Handshake(type, preferredRelayVersion, code));
+				sock.writePacket(new RelayPacket00Handshake(type, preferredRelayVersion, code));
 				while(!sock.isClosed()) {
-					IPacket pkt = sock.nextPacket();
+					sock.update();
+					RelayPacket pkt = sock.nextPacket();
 					if(pkt != null) {
-						if(pkt instanceof IPacket00Handshake) {
+						if(pkt instanceof RelayPacket00Handshake) {
 							return sock;
-						}else if(pkt instanceof IPacketFFErrorCode) {
-							IPacketFFErrorCode ipkt = (IPacketFFErrorCode) pkt;
-							logger.error("Relay [{}] failed: {}({}): {}", relay.address, IPacketFFErrorCode.code2string(ipkt.code), ipkt.code, ipkt.desc);
+						}else if(pkt instanceof RelayPacketFFErrorCode) {
+							RelayPacketFFErrorCode ipkt = (RelayPacketFFErrorCode) pkt;
+							logger.error("Relay [{}] failed: {}({}): {}", relay.address, RelayPacketFFErrorCode.code2string(ipkt.code), ipkt.code, ipkt.desc);
 							Throwable t;
 							while((t = sock.getException()) != null) {
 								logger.error(t);
@@ -309,12 +311,12 @@ public class RelayManager {
 		return null;
 	}
 	
-	private final List<RelayServer> brokenServers = new LinkedList();
+	private final List<RelayServer> brokenServers = new LinkedList<>();
 
 	public RelayServerSocket getWorkingRelay(Consumer<String> progressCallback, int type, String code) {
 		brokenServers.clear();
 		if(!relays.isEmpty()) {
-			long millis = System.currentTimeMillis();
+			long millis = EagRuntime.steadyTimeMillis();
 			if(millis - lastPingThrough < 10000l) {
 				RelayServer relay = getPrimary();
 				if(relay.getPing() > 0l && relay.getPingCompatible().isCompatible()) {
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/relay/RelayQuery.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/relay/RelayQuery.java
index 455fef82..05e24a2f 100644
--- a/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/relay/RelayQuery.java
+++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/relay/RelayQuery.java
@@ -28,6 +28,7 @@ public interface RelayQuery {
 		}
 	}
 
+	void update();
 	boolean isQueryOpen();
 	boolean isQueryFailed();
 	RateLimit isQueryRateLimit();
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/relay/RelayQueryImpl.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/relay/RelayQueryImpl.java
new file mode 100644
index 00000000..09c28da5
--- /dev/null
+++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/relay/RelayQueryImpl.java
@@ -0,0 +1,225 @@
+package net.lax1dude.eaglercraft.v1_8.sp.relay;
+
+import java.io.DataInputStream;
+import java.io.IOException;
+import java.util.List;
+
+import net.lax1dude.eaglercraft.v1_8.EagRuntime;
+import net.lax1dude.eaglercraft.v1_8.EaglerInputStream;
+import net.lax1dude.eaglercraft.v1_8.internal.EnumEaglerConnectionState;
+import net.lax1dude.eaglercraft.v1_8.internal.IWebSocketClient;
+import net.lax1dude.eaglercraft.v1_8.internal.IWebSocketFrame;
+import net.lax1dude.eaglercraft.v1_8.internal.PlatformNetworking;
+import net.lax1dude.eaglercraft.v1_8.log4j.LogManager;
+import net.lax1dude.eaglercraft.v1_8.log4j.Logger;
+import net.lax1dude.eaglercraft.v1_8.sp.relay.pkt.RelayPacket;
+import net.lax1dude.eaglercraft.v1_8.sp.relay.pkt.RelayPacket00Handshake;
+import net.lax1dude.eaglercraft.v1_8.sp.relay.pkt.RelayPacket69Pong;
+import net.lax1dude.eaglercraft.v1_8.sp.relay.pkt.RelayPacket70SpecialUpdate;
+import net.lax1dude.eaglercraft.v1_8.sp.relay.pkt.RelayPacketFFErrorCode;
+import net.lax1dude.eaglercraft.v1_8.update.UpdateService;
+
+/**
+ * Copyright (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ * 
+ */
+public class RelayQueryImpl implements RelayQuery {
+
+	private static final Logger logger = LogManager.getLogger("RelayQuery");
+	private static final RelayLoggerImpl loggerImpl = new RelayLoggerImpl(LogManager.getLogger("RelayPacket"));
+
+	private final IWebSocketClient sock;
+	private final String uri;
+
+	private boolean failed;
+
+	private boolean hasSentHandshake = false;
+	private boolean hasRecievedAnyData = false;
+
+	private int vers = -1;
+	private String comment = "<no comment>";
+	private String brand = "<no brand>";
+
+	private long connectionOpenedAt;
+	private long connectionPingStart = -1;
+	private long connectionPingTimer = -1;
+
+	private RateLimit rateLimitStatus = RateLimit.NONE;
+
+	private VersionMismatch versError = VersionMismatch.UNKNOWN;
+
+	public RelayQueryImpl(String uri) {
+		this.uri = uri;
+		IWebSocketClient s;
+		try {
+			connectionOpenedAt = EagRuntime.steadyTimeMillis();
+			s = PlatformNetworking.openWebSocketUnsafe(uri);
+		}catch(Throwable t) {
+			connectionOpenedAt = 0l;
+			sock = null;
+			failed = true;
+			return;
+		}
+		sock = s;
+		
+	}
+
+	@Override
+	public void update() {
+		if(sock == null) return;
+		if(sock.availableStringFrames() > 0) {
+			logger.warn("[{}] discarding {} string frames recieved on a binary connection", uri, sock.availableStringFrames());
+			sock.clearStringFrames();
+		}
+		List<IWebSocketFrame> frames = sock.getNextBinaryFrames();
+		if(frames != null) {
+			for(int i = 0, l = frames.size(); i < l; ++i) {
+				hasRecievedAnyData = true;
+				byte[] arr = frames.get(i).getByteArray();
+				if(arr.length == 2 && arr[0] == (byte)0xFC) {
+					if(arr[1] == (byte)0x00 || arr[1] == (byte)0x01) {
+						rateLimitStatus = RateLimit.BLOCKED;
+						RelayServerRateLimitTracker.setLimited(RelayQueryImpl.this.uri);
+					}else if(arr[1] == (byte)0x02) {
+						rateLimitStatus = RateLimit.NOW_LOCKED;
+						RelayServerRateLimitTracker.setLimitedLocked(RelayQueryImpl.this.uri);
+					}else {
+						rateLimitStatus = RateLimit.LOCKED;
+						RelayServerRateLimitTracker.setLocked(RelayQueryImpl.this.uri);
+					}
+					failed = true;
+					sock.close();
+				}else {
+					try {
+						RelayPacket pkt = RelayPacket.readPacket(new DataInputStream(new EaglerInputStream(arr)), loggerImpl);
+						if(pkt instanceof RelayPacket69Pong) {
+							RelayPacket69Pong ipkt = (RelayPacket69Pong)pkt;
+							versError = VersionMismatch.COMPATIBLE;
+							if(connectionPingTimer == -1) {
+								connectionPingTimer = frames.get(i).getTimestamp() - connectionPingStart;
+							}
+							vers = ipkt.protcolVersion;
+							comment = ipkt.comment;
+							brand = ipkt.brand;
+							failed = false;
+							sock.close();
+							return;
+						}else if(pkt instanceof RelayPacket70SpecialUpdate) {
+							RelayPacket70SpecialUpdate ipkt = (RelayPacket70SpecialUpdate)pkt;
+							if(ipkt.operation == RelayPacket70SpecialUpdate.OPERATION_UPDATE_CERTIFICATE) {
+								UpdateService.addCertificateToSet(ipkt.updatePacket);
+							}
+						}else if(pkt instanceof RelayPacketFFErrorCode) {
+							RelayPacketFFErrorCode ipkt = (RelayPacketFFErrorCode)pkt;
+							if(ipkt.code == RelayPacketFFErrorCode.TYPE_PROTOCOL_VERSION) {
+								String s1 = ipkt.desc.toLowerCase();
+								if(s1.contains("outdated client") || s1.contains("client outdated")) {
+									versError = VersionMismatch.CLIENT_OUTDATED;
+								}else if(s1.contains("outdated server") || s1.contains("server outdated") ||
+										s1.contains("outdated relay") || s1.contains("server relay")) {
+									versError = VersionMismatch.RELAY_OUTDATED;
+								}else {
+									versError = VersionMismatch.UNKNOWN;
+								}
+							}
+							logger.error("[{}] Recieved query error code {}: {}", uri, ipkt.code, ipkt.desc);
+							failed = true;
+							sock.close();
+							return;
+						}else {
+							throw new IOException("Unexpected packet '" + pkt.getClass().getSimpleName() + "'");
+						}
+					} catch (IOException e) {
+						logger.error("Relay query error: {}", e.toString());
+						logger.error(e);
+						failed = true;
+						sock.close();
+						return;
+					}
+				}
+			}
+		}
+		if(sock.isOpen() && !hasSentHandshake) {
+			hasSentHandshake = true;
+			try {
+				connectionPingStart = EagRuntime.steadyTimeMillis();
+				sock.send(RelayPacket.writePacket(new RelayPacket00Handshake(0x03, RelayManager.preferredRelayVersion, ""), loggerImpl));
+			} catch (IOException e) {
+				logger.error("Failed to write handshake: {}", e.toString());
+				logger.error(e);
+				sock.close();
+				failed = true;
+			}
+		}
+		if(sock.isClosed()) {
+			if(!hasRecievedAnyData) {
+				failed = true;
+				rateLimitStatus = RelayServerRateLimitTracker.isLimitedLong(uri);
+			}
+		}
+		if(EagRuntime.steadyTimeMillis() - connectionOpenedAt > 10000l) {
+			logger.error("Terminating connection that was open for too long: {}", uri);
+			sock.close();
+			failed = true;
+		}
+	}
+
+	@Override
+	public boolean isQueryOpen() {
+		return sock != null && !sock.isClosed();
+	}
+
+	@Override
+	public boolean isQueryFailed() {
+		return failed || sock == null || sock.getState() == EnumEaglerConnectionState.FAILED;
+	}
+
+	@Override
+	public RateLimit isQueryRateLimit() {
+		return rateLimitStatus;
+	}
+
+	@Override
+	public void close() {
+		if(sock != null) {
+			sock.close();
+		}
+	}
+
+	@Override
+	public int getVersion() {
+		return vers;
+	}
+
+	@Override
+	public String getComment() {
+		return comment;
+	}
+
+	@Override
+	public String getBrand() {
+		return brand;
+	}
+
+	@Override
+	public long getPing() {
+		return connectionPingTimer < 1 ? 1 : connectionPingTimer;
+	}
+
+	@Override
+	public VersionMismatch getCompatible() {
+		return versError;
+	}
+
+}
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/relay/RelayQueryRateLimitDummy.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/relay/RelayQueryRateLimitDummy.java
new file mode 100644
index 00000000..059d0837
--- /dev/null
+++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/relay/RelayQueryRateLimitDummy.java
@@ -0,0 +1,75 @@
+package net.lax1dude.eaglercraft.v1_8.sp.relay;
+
+/**
+ * Copyright (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ * 
+ */
+public class RelayQueryRateLimitDummy implements RelayQuery {
+
+	private final RateLimit type;
+
+	public RelayQueryRateLimitDummy(RateLimit type) {
+		this.type = type;
+	}
+
+	@Override
+	public void update() {
+		
+	}
+
+	@Override
+	public boolean isQueryOpen() {
+		return false;
+	}
+
+	@Override
+	public boolean isQueryFailed() {
+		return true;
+	}
+
+	@Override
+	public RateLimit isQueryRateLimit() {
+		return type;
+	}
+
+	@Override
+	public void close() {
+	}
+
+	@Override
+	public int getVersion() {
+		return RelayManager.preferredRelayVersion;
+	}
+
+	@Override
+	public String getComment() {
+		return "this query was rate limited";
+	}
+
+	@Override
+	public String getBrand() {
+		return "lax1dude";
+	}
+
+	@Override
+	public long getPing() {
+		return 0l;
+	}
+
+	@Override
+	public VersionMismatch getCompatible() {
+		return VersionMismatch.COMPATIBLE;
+	}
+
+}
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/relay/RelayServer.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/relay/RelayServer.java
index 9d464325..4ccf839a 100644
--- a/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/relay/RelayServer.java
+++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/relay/RelayServer.java
@@ -1,5 +1,6 @@
 package net.lax1dude.eaglercraft.v1_8.sp.relay;
 
+import net.lax1dude.eaglercraft.v1_8.EagRuntime;
 import net.lax1dude.eaglercraft.v1_8.EagUtils;
 import net.lax1dude.eaglercraft.v1_8.internal.PlatformWebRTC;
 import net.lax1dude.eaglercraft.v1_8.sp.relay.RelayQuery.VersionMismatch;
@@ -105,23 +106,26 @@ public class RelayServer {
 	}
 	
 	public void update() {
-		if(query != null && !query.isQueryOpen()) {
-			if(query.isQueryFailed()) {
-				queriedVersion = -1;
-				queriedComment = null;
-				queriedVendor = null;
-				queriedCompatible = VersionMismatch.UNKNOWN;
-				ping = 0l;
-			}else {
-				queriedVersion = query.getVersion();
-				queriedComment = query.getComment();
-				queriedVendor = query.getBrand();
-				ping = query.getPing();
-				queriedCompatible = query.getCompatible();
-				workingPing = ping;
+		if(query != null) {
+			query.update();
+			if(!query.isQueryOpen()) {
+				if(query.isQueryFailed()) {
+					queriedVersion = -1;
+					queriedComment = null;
+					queriedVendor = null;
+					queriedCompatible = VersionMismatch.UNKNOWN;
+					ping = 0l;
+				}else {
+					queriedVersion = query.getVersion();
+					queriedComment = query.getComment();
+					queriedVendor = query.getBrand();
+					ping = query.getPing();
+					queriedCompatible = query.getCompatible();
+					workingPing = ping;
+				}
+				lastPing = EagRuntime.steadyTimeMillis();
+				query = null;
 			}
-			lastPing = System.currentTimeMillis();
-			query = null;
 		}
 	}
 	
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/relay/RelayServerRateLimitTracker.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/relay/RelayServerRateLimitTracker.java
new file mode 100644
index 00000000..e7b34d65
--- /dev/null
+++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/relay/RelayServerRateLimitTracker.java
@@ -0,0 +1,98 @@
+package net.lax1dude.eaglercraft.v1_8.sp.relay;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import net.lax1dude.eaglercraft.v1_8.EagRuntime;
+
+/**
+ * Copyright (c) 2024 lax1dude. All Rights Reserved.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ * 
+ */
+public class RelayServerRateLimitTracker {
+
+	private static final Map<String,Long> relayQueryLimited = new HashMap<>();
+	private static final Map<String,Long> relayQueryLocked = new HashMap<>();
+
+	public static void setLimited(String str) {
+		synchronized(relayQueryLimited) {
+			relayQueryLimited.put(str, EagRuntime.steadyTimeMillis());
+		}
+	}
+
+	public static void setLocked(String str) {
+		synchronized(relayQueryLocked) {
+			relayQueryLocked.put(str, EagRuntime.steadyTimeMillis());
+		}
+	}
+
+	public static void setLimitedLocked(String str) {
+		long now = EagRuntime.steadyTimeMillis();
+		synchronized(relayQueryLimited) {
+			relayQueryLimited.put(str, now);
+		}
+		synchronized(relayQueryLocked) {
+			relayQueryLocked.put(str, now);
+		}
+	}
+
+	public static RelayQuery.RateLimit isLimited(String str) {
+		long now = EagRuntime.steadyTimeMillis();
+		synchronized(relayQueryLocked) {
+			Long l = relayQueryLocked.get(str);
+			if(l != null && now - l.longValue() < 60000l) {
+				return RelayQuery.RateLimit.LOCKED;
+			}
+		}
+		synchronized(relayQueryLimited) {
+			Long l = relayQueryLimited.get(str);
+			if(l != null && now - l.longValue() < 10000l) {
+				return RelayQuery.RateLimit.BLOCKED;
+			}
+		}
+		return RelayQuery.RateLimit.NONE;	
+	}
+
+	public static RelayQuery.RateLimit isLimitedLong(String str) {
+		long now = EagRuntime.steadyTimeMillis();
+		synchronized(relayQueryLocked) {
+			Long l = relayQueryLocked.get(str);
+			if(l != null && now - l.longValue() < 400000l) {
+				return RelayQuery.RateLimit.LOCKED;
+			}
+		}
+		synchronized(relayQueryLimited) {
+			Long l = relayQueryLimited.get(str);
+			if(l != null && now - l.longValue() < 900000l) {
+				return RelayQuery.RateLimit.BLOCKED;
+			}
+		}
+		return RelayQuery.RateLimit.NONE;	
+	}
+
+	public static RelayQuery.RateLimit isLimitedEver(String str) {
+		synchronized(relayQueryLocked) {
+			if(relayQueryLocked.containsKey(str)) {
+				return RelayQuery.RateLimit.LOCKED;
+			}
+		}
+		synchronized(relayQueryLimited) {
+			if(relayQueryLimited.containsKey(str)) {
+				return RelayQuery.RateLimit.BLOCKED;
+			}
+		}
+		return RelayQuery.RateLimit.NONE;	
+	}
+
+}
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/relay/RelayServerSocket.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/relay/RelayServerSocket.java
index e21cb850..e5fdbf02 100644
--- a/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/relay/RelayServerSocket.java
+++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/relay/RelayServerSocket.java
@@ -1,6 +1,6 @@
 package net.lax1dude.eaglercraft.v1_8.sp.relay;
 
-import net.lax1dude.eaglercraft.v1_8.sp.relay.pkt.IPacket;
+import net.lax1dude.eaglercraft.v1_8.sp.relay.pkt.RelayPacket;
 
 /**
  * Copyright (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved.
@@ -19,6 +19,7 @@ import net.lax1dude.eaglercraft.v1_8.sp.relay.pkt.IPacket;
  */
 public interface RelayServerSocket {
 
+	void update();
 	boolean isOpen();
 	boolean isClosed();
 	void close();
@@ -26,10 +27,10 @@ public interface RelayServerSocket {
 	boolean isFailed();
 	Throwable getException();
 	
-	void writePacket(IPacket pkt);
+	void writePacket(RelayPacket pkt);
 	
-	IPacket readPacket();
-	IPacket nextPacket();
+	RelayPacket readPacket();
+	RelayPacket nextPacket();
 	
 	RelayQuery.RateLimit getRatelimitHistory();
 	
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/relay/RelayServerSocketImpl.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/relay/RelayServerSocketImpl.java
new file mode 100644
index 00000000..05885f48
--- /dev/null
+++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/relay/RelayServerSocketImpl.java
@@ -0,0 +1,173 @@
+package net.lax1dude.eaglercraft.v1_8.sp.relay;
+
+import java.io.DataInputStream;
+import java.io.IOException;
+import java.util.LinkedList;
+import java.util.List;
+
+import net.lax1dude.eaglercraft.v1_8.EagRuntime;
+import net.lax1dude.eaglercraft.v1_8.internal.EnumEaglerConnectionState;
+import net.lax1dude.eaglercraft.v1_8.internal.IWebSocketClient;
+import net.lax1dude.eaglercraft.v1_8.internal.IWebSocketFrame;
+import net.lax1dude.eaglercraft.v1_8.internal.PlatformNetworking;
+import net.lax1dude.eaglercraft.v1_8.log4j.LogManager;
+import net.lax1dude.eaglercraft.v1_8.log4j.Logger;
+import net.lax1dude.eaglercraft.v1_8.sp.relay.pkt.RelayPacket;
+import net.lax1dude.eaglercraft.v1_8.sp.relay.pkt.RelayPacket70SpecialUpdate;
+import net.lax1dude.eaglercraft.v1_8.update.UpdateService;
+
+/**
+ * Copyright (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ * 
+ */
+public class RelayServerSocketImpl implements RelayServerSocket {
+
+	private static final Logger logger = LogManager.getLogger("RelayServerSocket");
+	private static final RelayLoggerImpl loggerImpl = new RelayLoggerImpl(LogManager.getLogger("RelayPacket"));
+
+	private final IWebSocketClient sock;
+	private final String uri;
+
+	private boolean hasRecievedAnyData = false;
+	private boolean failed = false;
+
+	private final List<Throwable> exceptions = new LinkedList<>();
+	private final List<RelayPacket> packets = new LinkedList<>();
+
+	public RelayServerSocketImpl(String uri, int timeout) {
+		this.uri = uri;
+		IWebSocketClient s;
+		try {
+			s = PlatformNetworking.openWebSocketUnsafe(uri);
+		}catch(Throwable t) {
+			exceptions.add(t);
+			sock = null;
+			failed = true;
+			return;
+		}
+		sock = s;
+	}
+
+	@Override
+	public void update() {
+		if(sock == null) return;
+		if(sock.availableStringFrames() > 0) {
+			logger.warn("[{}] discarding {} string frames recieved on a binary connection", uri, sock.availableStringFrames());
+			sock.clearStringFrames();
+		}
+		List<IWebSocketFrame> frames = sock.getNextBinaryFrames();
+		if(frames != null) {
+			for(int i = 0, l = frames.size(); i < l; ++i) {
+				hasRecievedAnyData = true;
+				try {
+					RelayPacket pkt = RelayPacket.readPacket(new DataInputStream(frames.get(i).getInputStream()), loggerImpl);
+					if(pkt instanceof RelayPacket70SpecialUpdate) {
+						RelayPacket70SpecialUpdate ipkt = (RelayPacket70SpecialUpdate)pkt;
+						if(ipkt.operation == RelayPacket70SpecialUpdate.OPERATION_UPDATE_CERTIFICATE) {
+							UpdateService.addCertificateToSet(ipkt.updatePacket);
+						}
+					}else {
+						packets.add(pkt);
+					}
+				} catch (IOException e) {
+					exceptions.add(e);
+					logger.error("[{}] Relay Socket Error: {}", uri, e.toString());
+					EagRuntime.debugPrintStackTrace(e);
+					failed = true;
+					sock.close();
+					return;
+				}
+			}
+		}
+		if(sock.isClosed()) {
+			if (!hasRecievedAnyData) {
+				failed = true;
+			}
+		}
+	}
+
+	@Override
+	public boolean isOpen() {
+		return sock != null && sock.isOpen();
+	}
+
+	@Override
+	public boolean isClosed() {
+		return sock == null || sock.isClosed();
+	}
+
+	@Override
+	public void close() {
+		if(sock != null) {
+			sock.close();
+		}
+	}
+
+	@Override
+	public boolean isFailed() {
+		return failed || sock == null || sock.getState() == EnumEaglerConnectionState.FAILED;
+	}
+
+	@Override
+	public Throwable getException() {
+		if(!exceptions.isEmpty()) {
+			return exceptions.remove(0);
+		}else {
+			return null;
+		}
+	}
+
+	@Override
+	public void writePacket(RelayPacket pkt) {
+		if(sock != null) {
+			try {
+				sock.send(RelayPacket.writePacket(pkt, loggerImpl));
+			} catch (Throwable e) {
+				logger.error("Relay connection error: {}", e.toString());
+				EagRuntime.debugPrintStackTrace(e);
+				exceptions.add(e);
+				sock.close();
+			}
+		}
+	}
+
+	@Override
+	public RelayPacket readPacket() {
+		if(!packets.isEmpty()) {
+			return packets.remove(0);
+		}else {
+			return null;
+		}
+	}
+
+	@Override
+	public RelayPacket nextPacket() {
+		if(!packets.isEmpty()) {
+			return packets.get(0);
+		}else {
+			return null;
+		}
+	}
+
+	@Override
+	public RelayQuery.RateLimit getRatelimitHistory() {
+		return RelayServerRateLimitTracker.isLimitedEver(uri);
+	}
+
+	@Override
+	public String getURI() {
+		return uri;
+	}
+
+}
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/relay/RelayServerSocketRateLimitDummy.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/relay/RelayServerSocketRateLimitDummy.java
new file mode 100644
index 00000000..e00aa10e
--- /dev/null
+++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/relay/RelayServerSocketRateLimitDummy.java
@@ -0,0 +1,80 @@
+package net.lax1dude.eaglercraft.v1_8.sp.relay;
+
+import net.lax1dude.eaglercraft.v1_8.sp.relay.pkt.RelayPacket;
+
+/**
+ * Copyright (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ * 
+ */
+public class RelayServerSocketRateLimitDummy implements RelayServerSocket {
+
+	private final RelayQuery.RateLimit limit;
+
+	public RelayServerSocketRateLimitDummy(RelayQuery.RateLimit limit) {
+		this.limit = limit;
+	}
+
+	@Override
+	public void update() {
+	}
+
+	@Override
+	public boolean isOpen() {
+		return false;
+	}
+
+	@Override
+	public boolean isClosed() {
+		return true;
+	}
+
+	@Override
+	public void close() {
+	}
+
+	@Override
+	public boolean isFailed() {
+		return true;
+	}
+
+	@Override
+	public Throwable getException() {
+		return null;
+	}
+
+	@Override
+	public void writePacket(RelayPacket pkt) {
+	}
+
+	@Override
+	public RelayPacket readPacket() {
+		return null;
+	}
+
+	@Override
+	public RelayPacket nextPacket() {
+		return null;
+	}
+
+	@Override
+	public RelayQuery.RateLimit getRatelimitHistory() {
+		return limit;
+	}
+
+	@Override
+	public String getURI() {
+		return "<disconnected>";
+	}
+
+}
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/relay/RelayWorldsQuery.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/relay/RelayWorldsQuery.java
index 787b8a80..ae461fc8 100644
--- a/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/relay/RelayWorldsQuery.java
+++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/relay/RelayWorldsQuery.java
@@ -3,7 +3,7 @@ package net.lax1dude.eaglercraft.v1_8.sp.relay;
 import java.util.List;
 
 import net.lax1dude.eaglercraft.v1_8.sp.relay.RelayQuery.VersionMismatch;
-import net.lax1dude.eaglercraft.v1_8.sp.relay.pkt.IPacket07LocalWorlds;
+import net.lax1dude.eaglercraft.v1_8.sp.relay.pkt.RelayPacket07LocalWorlds;
 
 /**
  * Copyright (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved.
@@ -22,12 +22,13 @@ import net.lax1dude.eaglercraft.v1_8.sp.relay.pkt.IPacket07LocalWorlds;
  */
 public interface RelayWorldsQuery {
 
+	void update();
 	boolean isQueryOpen();
 	boolean isQueryFailed();
 	RelayQuery.RateLimit isQueryRateLimit();
 	void close();
 	
-	List<IPacket07LocalWorlds.LocalWorld> getWorlds();
+	List<RelayPacket07LocalWorlds.LocalWorld> getWorlds();
 	
 	VersionMismatch getCompatible();
 	
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/relay/RelayWorldsQueryImpl.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/relay/RelayWorldsQueryImpl.java
new file mode 100644
index 00000000..d8a68cb4
--- /dev/null
+++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/relay/RelayWorldsQueryImpl.java
@@ -0,0 +1,197 @@
+package net.lax1dude.eaglercraft.v1_8.sp.relay;
+
+import java.io.DataInputStream;
+import java.io.IOException;
+import java.util.List;
+
+import net.lax1dude.eaglercraft.v1_8.EagRuntime;
+import net.lax1dude.eaglercraft.v1_8.EaglerInputStream;
+import net.lax1dude.eaglercraft.v1_8.internal.EnumEaglerConnectionState;
+import net.lax1dude.eaglercraft.v1_8.internal.IWebSocketClient;
+import net.lax1dude.eaglercraft.v1_8.internal.IWebSocketFrame;
+import net.lax1dude.eaglercraft.v1_8.internal.PlatformNetworking;
+import net.lax1dude.eaglercraft.v1_8.log4j.LogManager;
+import net.lax1dude.eaglercraft.v1_8.log4j.Logger;
+import net.lax1dude.eaglercraft.v1_8.sp.relay.RelayQuery.RateLimit;
+import net.lax1dude.eaglercraft.v1_8.sp.relay.pkt.RelayPacket;
+import net.lax1dude.eaglercraft.v1_8.sp.relay.pkt.RelayPacket00Handshake;
+import net.lax1dude.eaglercraft.v1_8.sp.relay.pkt.RelayPacket07LocalWorlds;
+import net.lax1dude.eaglercraft.v1_8.sp.relay.pkt.RelayPacket70SpecialUpdate;
+import net.lax1dude.eaglercraft.v1_8.sp.relay.pkt.RelayPacketFFErrorCode;
+import net.lax1dude.eaglercraft.v1_8.update.UpdateService;
+
+/**
+ * Copyright (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ * 
+ */
+public class RelayWorldsQueryImpl implements RelayWorldsQuery {
+
+	private static final Logger logger = LogManager.getLogger("RelayWorldsQuery");
+	private static final RelayLoggerImpl loggerImpl = new RelayLoggerImpl(LogManager.getLogger("RelayPacket"));
+
+	private final IWebSocketClient sock;
+	private final String uri;
+
+	private boolean failed;
+
+	private long openedAt;
+
+	private boolean hasSentHandshake = false;
+	private boolean hasRecievedAnyData = false;
+	private RelayQuery.RateLimit rateLimitStatus = RelayQuery.RateLimit.NONE;
+
+	private RelayQuery.VersionMismatch versError = RelayQuery.VersionMismatch.UNKNOWN;
+
+	private List<RelayPacket07LocalWorlds.LocalWorld> worlds = null;
+
+	public RelayWorldsQueryImpl(String uri) {
+		this.uri = uri;
+		IWebSocketClient s;
+		try {
+			openedAt = EagRuntime.steadyTimeMillis();
+			s = PlatformNetworking.openWebSocketUnsafe(uri);
+		}catch(Throwable t) {
+			sock = null;
+			failed = true;
+			return;
+		}
+		sock = s;
+	}
+
+	@Override
+	public void update() {
+		if(sock == null) return;
+		if(sock.availableStringFrames() > 0) {
+			logger.warn("[{}] discarding {} string frames recieved on a binary connection", uri, sock.availableStringFrames());
+			sock.clearStringFrames();
+		}
+		List<IWebSocketFrame> frames = sock.getNextBinaryFrames();
+		if(frames != null) {
+			for(int i = 0, l = frames.size(); i < l; ++i) {
+				hasRecievedAnyData = true;
+				byte[] arr = frames.get(i).getByteArray();
+				if(arr.length == 2 && arr[0] == (byte)0xFC) {
+					if(arr[1] == (byte)0x00 || arr[1] == (byte)0x01) {
+						rateLimitStatus = RateLimit.BLOCKED;
+						RelayServerRateLimitTracker.setLimited(RelayWorldsQueryImpl.this.uri);
+					}else if(arr[1] == (byte)0x02) {
+						rateLimitStatus = RateLimit.NOW_LOCKED;
+						RelayServerRateLimitTracker.setLimitedLocked(RelayWorldsQueryImpl.this.uri);
+					}else {
+						rateLimitStatus = RateLimit.LOCKED;
+						RelayServerRateLimitTracker.setLocked(RelayWorldsQueryImpl.this.uri);
+					}
+					failed = true;
+					sock.close();
+				}else {
+					try {
+						RelayPacket pkt = RelayPacket.readPacket(new DataInputStream(new EaglerInputStream(arr)), loggerImpl);
+						if(pkt instanceof RelayPacket07LocalWorlds) {
+							worlds = ((RelayPacket07LocalWorlds)pkt).worldsList;
+							sock.close();
+							failed = false;
+							return;
+						}else if(pkt instanceof RelayPacket70SpecialUpdate) {
+							RelayPacket70SpecialUpdate ipkt = (RelayPacket70SpecialUpdate)pkt;
+							if(ipkt.operation == RelayPacket70SpecialUpdate.OPERATION_UPDATE_CERTIFICATE) {
+								UpdateService.addCertificateToSet(ipkt.updatePacket);
+							}
+						}else if(pkt instanceof RelayPacketFFErrorCode) {
+							RelayPacketFFErrorCode ipkt = (RelayPacketFFErrorCode)pkt;
+							if(ipkt.code == RelayPacketFFErrorCode.TYPE_PROTOCOL_VERSION) {
+								String s1 = ipkt.desc.toLowerCase();
+								if(s1.contains("outdated client") || s1.contains("client outdated")) {
+									versError = RelayQuery.VersionMismatch.CLIENT_OUTDATED;
+								}else if(s1.contains("outdated server") || s1.contains("server outdated") ||
+										s1.contains("outdated relay") || s1.contains("server relay")) {
+									versError = RelayQuery.VersionMismatch.RELAY_OUTDATED;
+								}else {
+									versError = RelayQuery.VersionMismatch.UNKNOWN;
+								}
+							}
+							logger.error("[{}] Recieved query error code {}: {}", uri, ipkt.code, ipkt.desc);
+							failed = true;
+							sock.close();
+							return;
+						}else {
+							throw new IOException("Unexpected packet '" + pkt.getClass().getSimpleName() + "'");
+						}
+					} catch (IOException e) {
+						logger.error("Relay World Query Error: {}", e.toString());
+						EagRuntime.debugPrintStackTrace(e);
+						failed = true;
+						sock.close();
+						return;
+					}
+				}
+			}
+		}
+		if(sock.isOpen() && !hasSentHandshake) {
+			hasSentHandshake = true;
+			try {
+				sock.send(RelayPacket.writePacket(new RelayPacket00Handshake(0x04, RelayManager.preferredRelayVersion, ""), loggerImpl));
+			} catch (IOException e) {
+				logger.error("Failed to write handshake: {}", e.toString());
+				logger.error(e);
+				sock.close();
+				failed = true;
+			}
+		}
+		if(sock.isClosed()) {
+			if(!hasRecievedAnyData) {
+				failed = true;
+				rateLimitStatus = RelayServerRateLimitTracker.isLimitedLong(uri);
+			}
+		}else {
+			if(EagRuntime.steadyTimeMillis() - openedAt > 10000l) {
+				logger.error("Terminating connection that was open for too long: {}", uri);
+				sock.close();
+				failed = true;
+			}
+		}
+	}
+
+	@Override
+	public boolean isQueryOpen() {
+		return sock != null && !sock.isClosed();
+	}
+
+	@Override
+	public boolean isQueryFailed() {
+		return failed || sock == null || sock.getState() == EnumEaglerConnectionState.FAILED;
+	}
+
+	@Override
+	public RelayQuery.RateLimit isQueryRateLimit() {
+		return rateLimitStatus;
+	}
+
+	@Override
+	public void close() {
+		if(sock != null) {
+			sock.close();
+		}
+	}
+
+	@Override
+	public List<RelayPacket07LocalWorlds.LocalWorld> getWorlds() {
+		return worlds;
+	}
+
+	@Override
+	public RelayQuery.VersionMismatch getCompatible() {
+		return versError;
+	}
+
+}
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/relay/RelayWorldsQueryRateLimitDummy.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/relay/RelayWorldsQueryRateLimitDummy.java
new file mode 100644
index 00000000..2915c825
--- /dev/null
+++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/relay/RelayWorldsQueryRateLimitDummy.java
@@ -0,0 +1,64 @@
+package net.lax1dude.eaglercraft.v1_8.sp.relay;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import net.lax1dude.eaglercraft.v1_8.sp.relay.pkt.RelayPacket07LocalWorlds;
+
+/**
+ * Copyright (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ * 
+ */
+public class RelayWorldsQueryRateLimitDummy implements RelayWorldsQuery {
+
+	private final RelayQuery.RateLimit rateLimit;
+
+	public RelayWorldsQueryRateLimitDummy(RelayQuery.RateLimit rateLimit) {
+		this.rateLimit = rateLimit;
+	}
+
+	@Override
+	public void update() {
+	}
+
+	@Override
+	public boolean isQueryOpen() {
+		return false;
+	}
+
+	@Override
+	public boolean isQueryFailed() {
+		return true;
+	}
+
+	@Override
+	public RelayQuery.RateLimit isQueryRateLimit() {
+		return rateLimit;
+	}
+
+	@Override
+	public void close() {
+	}
+
+	@Override
+	public List<RelayPacket07LocalWorlds.LocalWorld> getWorlds() {
+		return new ArrayList<>(0);
+	}
+
+	@Override
+	public RelayQuery.VersionMismatch getCompatible() {
+		return RelayQuery.VersionMismatch.COMPATIBLE;
+	}
+
+}
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/relay/pkt/ICEServerSet.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/relay/pkt/ICEServerSet.java
deleted file mode 100644
index 2ac4b9d0..00000000
--- a/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/relay/pkt/ICEServerSet.java
+++ /dev/null
@@ -1,55 +0,0 @@
-package net.lax1dude.eaglercraft.v1_8.sp.relay.pkt;
-
-/**
- * Copyright (c) 2022 lax1dude. All Rights Reserved.
- * 
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
- * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- * 
- */
-public class ICEServerSet {
-
-	public static enum RelayType {
-		STUN, TURN;
-	}
-
-	public static class RelayServer {
-		
-		public final RelayType type;
-		public final String address;
-		public final String username;
-		public final String password;
-		
-		protected RelayServer(RelayType type, String address, String username, String password) {
-			this.type = type;
-			this.address = address;
-			this.username = username;
-			this.password = password;
-		}
-		
-		protected RelayServer(RelayType type, String address) {
-			this.type = type;
-			this.address = address;
-			this.username = null;
-			this.password = null;
-		}
-
-		public String getICEString() {
-			if(username == null) {
-				return address;
-			}else {
-				return address + ";" + username + ";" + password;
-			}
-		}
-		
-	}
-	
-}
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/relay/pkt/IPacket.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/relay/pkt/IPacket.java
deleted file mode 100644
index 33dc3a09..00000000
--- a/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/relay/pkt/IPacket.java
+++ /dev/null
@@ -1,165 +0,0 @@
-package net.lax1dude.eaglercraft.v1_8.sp.relay.pkt;
-
-import java.io.DataInputStream;
-import java.io.DataOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.util.HashMap;
-import java.util.Map;
-
-import net.lax1dude.eaglercraft.v1_8.EaglerOutputStream;
-import net.lax1dude.eaglercraft.v1_8.log4j.LogManager;
-import net.lax1dude.eaglercraft.v1_8.log4j.Logger;
-
-/**
- * Copyright (c) 2022 lax1dude. All Rights Reserved.
- * 
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
- * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- * 
- */
-public class IPacket {
-
-	private static final Logger logger = LogManager.getLogger("RelayPacket");
-
-	private static final Map<Integer,Class<? extends IPacket>> definedPacketClasses = new HashMap();
-	private static final Map<Class<? extends IPacket>,Integer> definedPacketIds = new HashMap();
-	
-	private static void register(int id, Class<? extends IPacket> clazz) {
-		definedPacketClasses.put(id, clazz);
-		definedPacketIds.put(clazz, id);
-	}
-	
-	static {
-		register(0x00, IPacket00Handshake.class);
-		register(0x01, IPacket01ICEServers.class);
-		register(0x02, IPacket02NewClient.class);
-		register(0x03, IPacket03ICECandidate.class);
-		register(0x04, IPacket04Description.class);
-		register(0x05, IPacket05ClientSuccess.class);
-		register(0x06, IPacket06ClientFailure.class);
-		register(0x07, IPacket07LocalWorlds.class);
-		register(0x69, IPacket69Pong.class);
-		register(0x70, IPacket70SpecialUpdate.class);
-		register(0xFE, IPacketFEDisconnectClient.class);
-		register(0xFF, IPacketFFErrorCode.class);
-	}
-	
-	public static IPacket readPacket(DataInputStream input) throws IOException {
-		int i = input.read();
-		try {
-			Class<? extends IPacket> clazz = definedPacketClasses.get(i);
-			if(clazz == null) {
-				throw new IOException("Unknown packet type: " + i);
-			}
-			IPacket pkt = clazz.newInstance();
-			pkt.read(input);
-			return pkt;
-		} catch (InstantiationException | IllegalAccessException e) {
-			throw new IOException("Unknown packet type: " + i);
-		}
-	}
-	
-	public static byte[] writePacket(IPacket packet) throws IOException {
-		Integer i = definedPacketIds.get(packet.getClass());
-		if(i != null) {
-			int len = packet.packetLength();
-			EaglerOutputStream bao = len == -1 ? new EaglerOutputStream() :
-				new EaglerOutputStream(len + 1);
-			bao.write(i);
-			packet.write(new DataOutputStream(bao));
-			byte[] ret = bao.toByteArray();
-			if(len != -1 && ret.length != len + 1) {
-				logger.error("writePacket buffer for packet {} {} by {} bytes", packet.getClass().getSimpleName(),
-						(len + 1 < ret.length ? "overflowed" : "underflowed"),
-						(len + 1 < ret.length ? ret.length - len - 1 : len + 1 - ret.length));
-			}
-			return ret;
-		}else {
-			throw new IOException("Unknown packet type: " + packet.getClass().getSimpleName());
-		}
-	}
-
-	public void read(DataInputStream input) throws IOException {
-	}
-
-	public void write(DataOutputStream output) throws IOException {
-	}
-	
-	public int packetLength() {
-		return -1;
-	}
-	
-	public static String readASCII(InputStream is, int len) throws IOException {
-		char[] ret = new char[len];
-		for(int i = 0; i < len; ++i) {
-			int j = is.read();
-			if(j < 0) {
-				return null;
-			}
-			ret[i] = (char)j;
-		}
-		return new String(ret);
-	}
-	
-	public static void writeASCII(OutputStream is, String txt) throws IOException {
-		for(int i = 0, l = txt.length(); i < l; ++i) {
-			is.write((int)txt.charAt(i));
-		}
-	}
-	
-	public static String readASCII8(InputStream is) throws IOException {
-		int i = is.read();
-		if(i < 0) {
-			return null;
-		}else {
-			return readASCII(is, i);
-		}
-	}
-	
-	public static void writeASCII8(OutputStream is, String txt) throws IOException {
-		if(txt == null) {
-			is.write(0);
-		}else {
-			int l = txt.length();
-			is.write(l);
-			for(int i = 0; i < l; ++i) {
-				is.write((int)txt.charAt(i));
-			}
-		}
-	}
-
-	public static String readASCII16(InputStream is) throws IOException {
-		int hi = is.read();
-		int lo = is.read();
-		if(hi < 0 || lo < 0) {
-			return null;
-		}else {
-			return readASCII(is, (hi << 8) | lo);
-		}
-	}
-	
-	public static void writeASCII16(OutputStream is, String txt) throws IOException {
-		if(txt == null) {
-			is.write(0);
-			is.write(0);
-		}else {
-			int l = txt.length();
-			is.write((l >>> 8) & 0xFF);
-			is.write(l & 0xFF);
-			for(int i = 0; i < l; ++i) {
-				is.write((int)txt.charAt(i));
-			}
-		}
-	}
-	
-}
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/relay/pkt/IPacket00Handshake.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/relay/pkt/IPacket00Handshake.java
deleted file mode 100644
index 1c224902..00000000
--- a/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/relay/pkt/IPacket00Handshake.java
+++ /dev/null
@@ -1,57 +0,0 @@
-package net.lax1dude.eaglercraft.v1_8.sp.relay.pkt;
-
-import java.io.DataInputStream;
-import java.io.DataOutputStream;
-import java.io.IOException;
-
-/**
- * Copyright (c) 2022 lax1dude. All Rights Reserved.
- * 
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
- * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- * 
- */
-public class IPacket00Handshake extends IPacket {
-
-	public int connectionType = 0;
-	public int connectionVersion = 1;
-	public String connectionCode = null;
-	
-	public IPacket00Handshake() {
-	}
-	
-	public IPacket00Handshake(int connectionType, int connectionVersion,
-			String connectionCode) {
-		this.connectionType = connectionType;
-		this.connectionVersion = connectionVersion;
-		this.connectionCode = connectionCode;
-	}
-	
-	@Override
-	public void read(DataInputStream input) throws IOException {
-		connectionType = input.read();
-		connectionVersion = input.read();
-		connectionCode = IPacket.readASCII8(input);
-	}
-	
-	@Override
-	public void write(DataOutputStream output) throws IOException {
-		output.write(connectionType);
-		output.write(connectionVersion);
-		IPacket.writeASCII8(output, connectionCode);
-	}
-	
-	@Override
-	public int packetLength() {
-		return 1 + 1 + (connectionCode != null ? 1 + connectionCode.length() : 0);
-	}
-
-}
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/relay/pkt/IPacket01ICEServers.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/relay/pkt/IPacket01ICEServers.java
deleted file mode 100644
index 7d327612..00000000
--- a/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/relay/pkt/IPacket01ICEServers.java
+++ /dev/null
@@ -1,53 +0,0 @@
-package net.lax1dude.eaglercraft.v1_8.sp.relay.pkt;
-
-import java.io.DataInputStream;
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.Collection;
-
-/**
- * Copyright (c) 2022 lax1dude. All Rights Reserved.
- * 
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
- * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- * 
- */
-public class IPacket01ICEServers extends IPacket {
-	
-	public final Collection<ICEServerSet.RelayServer> servers;
-	
-	public IPacket01ICEServers() {
-		servers = new ArrayList();
-	}
-	
-	public void read(DataInputStream input) throws IOException {
-		servers.clear();
-		int l = input.readUnsignedShort();
-		for(int i = 0; i < l; ++i) {
-			char type = (char)input.read();
-			ICEServerSet.RelayType typeEnum;
-			if(type == 'S') {
-				typeEnum = ICEServerSet.RelayType.STUN;
-			}else if(type == 'T') {
-				typeEnum = ICEServerSet.RelayType.TURN;
-			}else {
-				throw new IOException("Unknown/Unsupported Relay Type: '" + type + "'");
-			}
-			servers.add(new ICEServerSet.RelayServer(
-					typeEnum,
-					readASCII16(input),
-					readASCII8(input),
-					readASCII8(input)
-			));
-		}
-	}
-	
-}
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/relay/pkt/IPacket03ICECandidate.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/relay/pkt/IPacket03ICECandidate.java
deleted file mode 100644
index 985f0409..00000000
--- a/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/relay/pkt/IPacket03ICECandidate.java
+++ /dev/null
@@ -1,49 +0,0 @@
-package net.lax1dude.eaglercraft.v1_8.sp.relay.pkt;
-
-import java.io.DataInputStream;
-import java.io.DataOutputStream;
-import java.io.IOException;
-
-/**
- * Copyright (c) 2022 lax1dude. All Rights Reserved.
- * 
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
- * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- * 
- */
-public class IPacket03ICECandidate extends IPacket {
-
-	public String peerId;
-	public String candidate;
-	
-	public IPacket03ICECandidate(String peerId, String desc) {
-		this.peerId = peerId;
-		this.candidate = desc;
-	}
-	
-	public IPacket03ICECandidate() {
-	}
-	
-	public void read(DataInputStream input) throws IOException {
-		peerId = readASCII8(input);
-		candidate = readASCII16(input);
-	}
-
-	public void write(DataOutputStream output) throws IOException {
-		writeASCII8(output, peerId);
-		writeASCII16(output, candidate);
-	}
-	
-	public int packetLength() {
-		return 1 + peerId.length() + 2 + candidate.length();
-	}
-
-}
\ No newline at end of file
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/relay/pkt/IPacket04Description.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/relay/pkt/IPacket04Description.java
deleted file mode 100644
index 6bc3f8f1..00000000
--- a/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/relay/pkt/IPacket04Description.java
+++ /dev/null
@@ -1,49 +0,0 @@
-package net.lax1dude.eaglercraft.v1_8.sp.relay.pkt;
-
-import java.io.DataInputStream;
-import java.io.DataOutputStream;
-import java.io.IOException;
-
-/**
- * Copyright (c) 2022 lax1dude. All Rights Reserved.
- * 
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
- * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- * 
- */
-public class IPacket04Description extends IPacket {
-
-	public String peerId;
-	public String description;
-	
-	public IPacket04Description(String peerId, String desc) {
-		this.peerId = peerId;
-		this.description = desc;
-	}
-	
-	public IPacket04Description() {
-	}
-	
-	public void read(DataInputStream input) throws IOException {
-		peerId = readASCII8(input);
-		description = readASCII16(input);
-	}
-
-	public void write(DataOutputStream output) throws IOException {
-		writeASCII8(output, peerId);
-		writeASCII16(output, description);
-	}
-	
-	public int packetLength() {
-		return 1 + peerId.length() + 2 + description.length();
-	}
-
-}
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/relay/pkt/IPacketFEDisconnectClient.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/relay/pkt/IPacketFEDisconnectClient.java
deleted file mode 100644
index 77a787fd..00000000
--- a/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/relay/pkt/IPacketFEDisconnectClient.java
+++ /dev/null
@@ -1,67 +0,0 @@
-package net.lax1dude.eaglercraft.v1_8.sp.relay.pkt;
-
-import java.io.DataInputStream;
-import java.io.DataOutputStream;
-import java.io.IOException;
-import java.nio.ByteBuffer;
-
-/**
- * Copyright (c) 2022 lax1dude. All Rights Reserved.
- * 
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
- * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- * 
- */
-public class IPacketFEDisconnectClient extends IPacket {
-
-	public static final int TYPE_FINISHED_SUCCESS = 0x00;
-	public static final int TYPE_FINISHED_FAILED = 0x01;
-	public static final int TYPE_TIMEOUT = 0x02;
-	public static final int TYPE_INVALID_OPERATION = 0x03;
-	public static final int TYPE_INTERNAL_ERROR = 0x04;
-	public static final int TYPE_SERVER_DISCONNECT = 0x05;
-	public static final int TYPE_UNKNOWN = 0xFF;
-	
-	public String clientId;
-	public int code;
-	public String reason;
-	
-	public IPacketFEDisconnectClient() {
-	}
-	
-	public IPacketFEDisconnectClient(String clientId, int code, String reason) {
-		this.clientId = clientId;
-		this.code = code;
-		this.reason = reason;
-	}
-	
-	public void read(DataInputStream input) throws IOException {
-		clientId = readASCII8(input);
-		code = input.read();
-		reason = readASCII16(input);
-	}
-
-	public void write(DataOutputStream output) throws IOException {
-		writeASCII8(output, clientId);
-		output.write(code);
-		writeASCII16(output, reason);
-	}
-	
-	public int packetLength() {
-		return -1;
-	}
-
-	public static final ByteBuffer ratelimitPacketTooMany = ByteBuffer.wrap(new byte[] { (byte)0xFC, (byte)0x00 });
-	public static final ByteBuffer ratelimitPacketBlock = ByteBuffer.wrap(new byte[] { (byte)0xFC, (byte)0x01 });
-	public static final ByteBuffer ratelimitPacketBlockLock = ByteBuffer.wrap(new byte[] { (byte)0xFC, (byte)0x02 });
-	public static final ByteBuffer ratelimitPacketLocked = ByteBuffer.wrap(new byte[] { (byte)0xFC, (byte)0x03 });
-	
-}
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/relay/pkt/IPacketFFErrorCode.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/relay/pkt/IPacketFFErrorCode.java
deleted file mode 100644
index 4475d75b..00000000
--- a/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/relay/pkt/IPacketFFErrorCode.java
+++ /dev/null
@@ -1,82 +0,0 @@
-package net.lax1dude.eaglercraft.v1_8.sp.relay.pkt;
-
-import java.io.DataInputStream;
-import java.io.DataOutputStream;
-import java.io.IOException;
-
-/**
- * Copyright (c) 2022 lax1dude. All Rights Reserved.
- * 
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
- * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- * 
- */
-public class IPacketFFErrorCode extends IPacket {
-
-	public static final int TYPE_INTERNAL_ERROR = 0x00;
-	public static final int TYPE_PROTOCOL_VERSION = 0x01;
-	public static final int TYPE_INVALID_PACKET = 0x02;
-	public static final int TYPE_ILLEGAL_OPERATION = 0x03;
-	public static final int TYPE_CODE_LENGTH = 0x04;
-	public static final int TYPE_INCORRECT_CODE = 0x05;
-	public static final int TYPE_SERVER_DISCONNECTED = 0x06;
-	public static final int TYPE_UNKNOWN_CLIENT = 0x07;
-	
-	public static final String[] packetTypes = new String[0x08];
-	
-	static {
-		packetTypes[TYPE_INTERNAL_ERROR] = "TYPE_INTERNAL_ERROR";
-		packetTypes[TYPE_PROTOCOL_VERSION] = "TYPE_PROTOCOL_VERSION";
-		packetTypes[TYPE_INVALID_PACKET] = "TYPE_INVALID_PACKET";
-		packetTypes[TYPE_ILLEGAL_OPERATION] = "TYPE_ILLEGAL_OPERATION";
-		packetTypes[TYPE_CODE_LENGTH] = "TYPE_CODE_LENGTH";
-		packetTypes[TYPE_INCORRECT_CODE] = "TYPE_INCORRECT_CODE";
-		packetTypes[TYPE_SERVER_DISCONNECTED] = "TYPE_SERVER_DISCONNECTED";
-		packetTypes[TYPE_UNKNOWN_CLIENT] = "TYPE_UNKNOWN_CLIENT";
-	}
-	
-	public static String code2string(int i) {
-		if(i >= 0 || i < packetTypes.length) {
-			return packetTypes[i];
-		}else {
-			return "UNKNOWN";
-		}
-	}
-	
-	public int code;
-	public String desc;
-	
-	public IPacketFFErrorCode() {
-	}
-	
-	public IPacketFFErrorCode(int code, String desc) {
-		this.code = code;
-		this.desc = desc;
-	}
-	
-	@Override
-	public void read(DataInputStream input) throws IOException {
-		code = input.read();
-		desc = readASCII16(input);
-	}
-
-	@Override
-	public void write(DataOutputStream input) throws IOException {
-		input.write(code);
-		writeASCII16(input, desc);
-	}
-
-	@Override
-	public int packetLength() {
-		return 1 + 2 + desc.length();
-	}
-
-}
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/server/EaglerChunkLoader.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/server/EaglerChunkLoader.java
index 403280b6..11bd903e 100644
--- a/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/server/EaglerChunkLoader.java
+++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/server/EaglerChunkLoader.java
@@ -71,7 +71,7 @@ public class EaglerChunkLoader extends AnvilChunkLoader {
 
 	@Override
 	public Chunk loadChunk(World var1, int var2, int var3) throws IOException {
-		VFile2 file = new VFile2(chunkDirectory, getChunkPath(var2, var3) + ".dat");
+		VFile2 file = WorldsDB.newVFile(chunkDirectory, getChunkPath(var2, var3) + ".dat");
 		if(!file.exists()) {
 			return null;
 		}
@@ -93,7 +93,7 @@ public class EaglerChunkLoader extends AnvilChunkLoader {
 		this.writeChunkToNBT(var2, var1, chunkData);
 		NBTTagCompound fileData = new NBTTagCompound();
 		fileData.setTag("Level", chunkData);
-		VFile2 file = new VFile2(chunkDirectory, getChunkPath(var2.xPosition, var2.zPosition) + ".dat");
+		VFile2 file = WorldsDB.newVFile(chunkDirectory, getChunkPath(var2.xPosition, var2.zPosition) + ".dat");
 		try(OutputStream os = file.getOutputStream()) {
 			CompressedStreamTools.writeCompressed(fileData, os);
 		}
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/server/EaglerIntegratedServerWorker.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/server/EaglerIntegratedServerWorker.java
index 20c96bee..0aad61cb 100644
--- a/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/server/EaglerIntegratedServerWorker.java
+++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/server/EaglerIntegratedServerWorker.java
@@ -58,7 +58,7 @@ public class EaglerIntegratedServerWorker {
 
 	public static final EaglerSaveFormat saveFormat = new EaglerSaveFormat(EaglerSaveFormat.worldsFolder);
 
-	private static final Map<String, IntegratedServerPlayerNetworkManager> openChannels = new HashMap();
+	private static final Map<String, IntegratedServerPlayerNetworkManager> openChannels = new HashMap<>();
 
 	private static final IPCPacketManager packetManagerInstance = new IPCPacketManager();
 
@@ -197,7 +197,7 @@ public class EaglerIntegratedServerWorker {
 				}
 				String[] worldsTxt = EaglerSaveFormat.worldsList.getAllLines();
 				if(worldsTxt != null) {
-					List<String> newWorlds = new ArrayList();
+					List<String> newWorlds = new ArrayList<>();
 					for(int i = 0; i < worldsTxt.length; ++i) {
 						String str = worldsTxt[i];
 						if(!str.equalsIgnoreCase(pkt.worldName)) {
@@ -301,18 +301,18 @@ public class EaglerIntegratedServerWorker {
 				}else {
 					String[] worlds = EaglerSaveFormat.worldsList.getAllLines();
 					if(worlds == null) {
-						sendIPCPacket(new IPCPacket16NBTList(IPCPacket16NBTList.WORLD_LIST, new LinkedList<NBTTagCompound>()));
+						sendIPCPacket(new IPCPacket16NBTList(IPCPacket16NBTList.WORLD_LIST, new LinkedList<>()));
 						break;
 					}
-					LinkedHashSet<String> updatedList = new LinkedHashSet();
-					LinkedList<NBTTagCompound> sendListNBT = new LinkedList();
+					LinkedHashSet<String> updatedList = new LinkedHashSet<>();
+					LinkedList<NBTTagCompound> sendListNBT = new LinkedList<>();
 					boolean rewrite = false;
 					for(int i = 0; i < worlds.length; ++i) {
 						String w = worlds[i].trim();
 						if(w.length() > 0) {
-							VFile2 vf = new VFile2(EaglerSaveFormat.worldsFolder, w, "level.dat");
+							VFile2 vf = WorldsDB.newVFile(EaglerSaveFormat.worldsFolder, w, "level.dat");
 							if(!vf.exists()) {
-								vf = new VFile2(EaglerSaveFormat.worldsFolder, w, "level.dat_old");
+								vf = WorldsDB.newVFile(EaglerSaveFormat.worldsFolder, w, "level.dat_old");
 							}
 							if(vf.exists()) {
 								try(InputStream dat = vf.getInputStream()) {
@@ -391,8 +391,8 @@ public class EaglerIntegratedServerWorker {
 				}
 				break;
 			}
-			case IPCPacket21EnableLogging.ID: {
-				enableLoggingRedirector(((IPCPacket21EnableLogging)ipc).enable);
+			case IPCPacket1BEnableLogging.ID: {
+				enableLoggingRedirector(((IPCPacket1BEnableLogging)ipc).enable);
 				break;
 			}
 			default: 
@@ -418,7 +418,7 @@ public class EaglerIntegratedServerWorker {
 	}
 
 	public static void sendLogMessagePacket(String txt, boolean err) {
-		sendIPCPacket(new IPCPacket20LoggerMessage(txt, err));
+		sendIPCPacket(new IPCPacket1ALoggerMessage(txt, err));
 	}
 
 	public static void sendIPCPacket(IPCPacketBase ipc) {
@@ -454,12 +454,12 @@ public class EaglerIntegratedServerWorker {
 		currentProcess = null;
 	}
 
-	private static void mainLoop() {
+	private static void mainLoop(boolean singleThreadMode) {
 		processAsyncMessageQueue();
 		
 		if(currentProcess != null) {
 			if(currentProcess.isServerRunning()) {
-				currentProcess.mainLoop();
+				currentProcess.mainLoop(singleThreadMode);
 			}
 			if(!currentProcess.isServerRunning()) {
 				currentProcess.stopServer();
@@ -467,7 +467,9 @@ public class EaglerIntegratedServerWorker {
 				sendIPCPacket(new IPCPacketFFProcessKeepAlive(IPCPacket01StopServer.ID));
 			}
 		}else {
-			EagUtils.sleep(50l);
+			if(!singleThreadMode) {
+				EagUtils.sleep(50l);
+			}
 		}
 	}
 
@@ -476,12 +478,16 @@ public class EaglerIntegratedServerWorker {
 			currentProcess = null;
 			logger.info("Starting EaglercraftX integrated server worker...");
 			
+			if(ServerPlatformSingleplayer.getWorldsDatabase().isRamdisk()) {
+				sendIPCPacket(new IPCPacket1CIssueDetected(IPCPacket1CIssueDetected.ISSUE_RAMDISK_MODE));
+			}
+			
 			// signal thread startup successful
 			sendIPCPacket(new IPCPacketFFProcessKeepAlive(0xFF));
 			
 			while(true) {
-				mainLoop();
-				EagUtils.sleep(0l);
+				mainLoop(false);
+				ServerPlatformSingleplayer.immediateContinue();
 			}
 		}catch(Throwable tt) {
 			if(tt instanceof ReportedException) {
@@ -506,4 +512,17 @@ public class EaglerIntegratedServerWorker {
 			sendIPCPacket(new IPCPacketFFProcessKeepAlive(IPCPacketFFProcessKeepAlive.EXITED));
 		}
 	}
+
+	public static void singleThreadMain() {
+		logger.info("Starting EaglercraftX integrated server worker...");
+		if(ServerPlatformSingleplayer.getWorldsDatabase().isRamdisk()) {
+			sendIPCPacket(new IPCPacket1CIssueDetected(IPCPacket1CIssueDetected.ISSUE_RAMDISK_MODE));
+		}
+		sendIPCPacket(new IPCPacketFFProcessKeepAlive(0xFF));
+	}
+
+	public static void singleThreadUpdate() {
+		mainLoop(true);
+	}
+
 }
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/server/EaglerMinecraftServer.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/server/EaglerMinecraftServer.java
index 6e76ca96..7f995361 100644
--- a/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/server/EaglerMinecraftServer.java
+++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/server/EaglerMinecraftServer.java
@@ -1,11 +1,12 @@
 package net.lax1dude.eaglercraft.v1_8.sp.server;
 
 import java.io.IOException;
-import java.util.ArrayList;
-import java.util.Arrays;
 import java.util.LinkedList;
 import java.util.List;
 
+import com.google.common.collect.Lists;
+
+import net.lax1dude.eaglercraft.v1_8.EagRuntime;
 import net.lax1dude.eaglercraft.v1_8.internal.vfs2.VFile2;
 import net.lax1dude.eaglercraft.v1_8.log4j.Logger;
 import net.minecraft.entity.player.EntityPlayer;
@@ -39,7 +40,7 @@ public class EaglerMinecraftServer extends MinecraftServer {
 
 	public static final Logger logger = EaglerIntegratedServerWorker.logger;
 
-	public static final VFile2 savesDir = new VFile2("worlds");
+	public static final VFile2 savesDir = WorldsDB.newVFile("worlds");
 
 	protected EnumDifficulty difficulty;
 	protected GameType gamemode;
@@ -59,13 +60,13 @@ public class EaglerMinecraftServer extends MinecraftServer {
 	public static int counterTileUpdate = 0;
 	public static int counterLightUpdate = 0;
 
-	private final List<Runnable> scheduledTasks = new LinkedList();
+	private final List<Runnable> scheduledTasks = new LinkedList<>();
 
 	public EaglerMinecraftServer(String world, String owner, int viewDistance, WorldSettings currentWorldSettings, boolean demo) {
 		super(world);
 		Bootstrap.register();
 		this.saveHandler = new EaglerSaveHandler(savesDir, world);
-		this.skinService = new IntegratedSkinService(new VFile2(saveHandler.getWorldDirectory(), "eagler/skulls"));
+		this.skinService = new IntegratedSkinService(WorldsDB.newVFile(saveHandler.getWorldDirectory(), "eagler/skulls"));
 		this.capeService = new IntegratedCapeService();
 		this.voiceService = null;
 		this.setServerOwner(owner);
@@ -131,7 +132,7 @@ public class EaglerMinecraftServer extends MinecraftServer {
 		EaglerIntegratedServerWorker.saveFormat.deleteWorldDirectory(getFolderName());
 	}
 
-	public void mainLoop() {
+	public void mainLoop(boolean singleThreadMode) {
 		long k = getCurrentTimeMillis();
 		this.sendTPSToClient(k);
 		if(paused && this.playersOnline.size() <= 1) {
@@ -140,7 +141,7 @@ public class EaglerMinecraftServer extends MinecraftServer {
 		}
 
 		long j = k - this.currentTime;
-		if (j > 2000L && this.currentTime - this.timeOfLastWarning >= 15000L) {
+		if (j > (singleThreadMode ? 500L : 2000L) && this.currentTime - this.timeOfLastWarning >= (singleThreadMode ? 5000L : 15000L)) {
 			logger.warn(
 					"Can\'t keep up! Did the system time change, or is the server overloaded? Running {}ms behind, skipping {} tick(s)",
 					new Object[] { Long.valueOf(j), Long.valueOf(j / 50L) });
@@ -177,13 +178,13 @@ public class EaglerMinecraftServer extends MinecraftServer {
 		if(millis - lastTPSUpdate > 1000l) {
 			lastTPSUpdate = millis;
 			if(serverRunning && this.worldServers != null) {
-				List<String> lst = new ArrayList<>(Arrays.asList(
+				List<String> lst = Lists.newArrayList(
 						"TPS: " + counterTicksPerSecond + "/20",
 						"Chunks: " + countChunksLoaded(this.worldServers) + "/" + countChunksTotal(this.worldServers),
 						"Entities: " + countEntities(this.worldServers) + "+" + countTileEntities(this.worldServers),
 						"R: " + counterChunkRead + ", G: " + counterChunkGenerate + ", W: " + counterChunkWrite,
 						"TU: " + counterTileUpdate + ", LU: " + counterLightUpdate
-				));
+				);
 				int players = countPlayerEntities(this.worldServers);
 				if(players > 1) {
 					lst.add("Players: " + players);
@@ -252,7 +253,7 @@ public class EaglerMinecraftServer extends MinecraftServer {
 	public void setPaused(boolean p) {
 		paused = p;
 		if(!p) {
-			currentTime = System.currentTimeMillis();
+			currentTime = EagRuntime.steadyTimeMillis();
 		}
 	}
 	
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/server/EaglerSaveFormat.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/server/EaglerSaveFormat.java
index 0f2d4b20..4fb29bdb 100644
--- a/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/server/EaglerSaveFormat.java
+++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/server/EaglerSaveFormat.java
@@ -30,13 +30,13 @@ import net.minecraft.world.storage.WorldInfo;
  */
 public class EaglerSaveFormat extends SaveFormatOld {
 
-	public static final VFile2 worldsList = new VFile2("worlds_list.txt");
-	public static final VFile2 worldsFolder = new VFile2("worlds");
-
 	public EaglerSaveFormat(VFile2 parFile) {
 		super(parFile);
 	}
 
+	public static final VFile2 worldsList = WorldsDB.newVFile("worlds_list.txt");
+	public static final VFile2 worldsFolder = WorldsDB.newVFile("worlds");
+
 	public String getName() {
 		return "eagler";
 	}
@@ -46,7 +46,7 @@ public class EaglerSaveFormat extends SaveFormatOld {
 	}
 
 	public List<SaveFormatComparator> getSaveList() {
-		ArrayList arraylist = Lists.newArrayList();
+		ArrayList<SaveFormatComparator> arraylist = Lists.newArrayList();
 		if(worldsList.exists()) {
 			String[] lines = worldsList.getAllLines();
 			for (int i = 0; i < lines.length; ++i) {
@@ -70,7 +70,7 @@ public class EaglerSaveFormat extends SaveFormatOld {
 	}
 
 	public void clearPlayers(String worldFolder) {
-		VFile2 file1 = new VFile2(this.savesDirectory, worldFolder, "player");
+		VFile2 file1 = WorldsDB.newVFile(this.savesDirectory, worldFolder, "player");
 		deleteFiles(file1.listFiles(true), null);
 	}
 
@@ -80,12 +80,12 @@ public class EaglerSaveFormat extends SaveFormatOld {
 
 	public boolean duplicateWorld(String worldFolder, String displayName) {
 		String newFolderName = displayName.replaceAll("[\\./\"]", "_");
-		VFile2 newFolder = new VFile2(savesDirectory, newFolderName);
-		while((new VFile2(newFolder, "level.dat")).exists() || (new VFile2(newFolder, "level.dat_old")).exists()) {
+		VFile2 newFolder = WorldsDB.newVFile(savesDirectory, newFolderName);
+		while((WorldsDB.newVFile(newFolder, "level.dat")).exists() || (WorldsDB.newVFile(newFolder, "level.dat_old")).exists()) {
 			newFolderName += "_";
-			newFolder = new VFile2(savesDirectory, newFolderName);
+			newFolder = WorldsDB.newVFile(savesDirectory, newFolderName);
 		}
-		VFile2 oldFolder = new VFile2(this.savesDirectory, worldFolder);
+		VFile2 oldFolder = WorldsDB.newVFile(this.savesDirectory, worldFolder);
 		String oldPath = oldFolder.getPath();
 		int totalSize = 0;
 		int lastUpdate = 0;
@@ -94,7 +94,7 @@ public class EaglerSaveFormat extends SaveFormatOld {
 		for(int i = 0, l = vfl.size(); i < l; ++i) {
 			VFile2 vf = vfl.get(i);
 			String fileNameRelative = vf.getPath().substring(oldPath.length() + 1);
-			totalSize += VFile2.copyFile(vf, new VFile2(finalNewFolder, fileNameRelative));
+			totalSize += VFile2.copyFile(vf, WorldsDB.newVFile(finalNewFolder, fileNameRelative));
 			if (totalSize - lastUpdate > 10000) {
 				lastUpdate = totalSize;
 				EaglerIntegratedServerWorker.sendProgress("singleplayer.busy.duplicating", totalSize);
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/server/EaglerSaveHandler.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/server/EaglerSaveHandler.java
index 0e7fe7ae..dae1b7ec 100644
--- a/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/server/EaglerSaveHandler.java
+++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/server/EaglerSaveHandler.java
@@ -29,7 +29,7 @@ public class EaglerSaveHandler extends SaveHandler {
 	}
 
 	public IChunkLoader getChunkLoader(WorldProvider provider) {
-		return new EaglerChunkLoader(new VFile2(this.getWorldDirectory(), "level" + provider.getDimensionId()));
+		return new EaglerChunkLoader(WorldsDB.newVFile(this.getWorldDirectory(), "level" + provider.getDimensionId()));
 	}
 
 	public void saveWorldInfoWithPlayer(WorldInfo worldInformation, NBTTagCompound tagCompound) {
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/server/WorldsDB.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/server/WorldsDB.java
new file mode 100644
index 00000000..401c3fd9
--- /dev/null
+++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/server/WorldsDB.java
@@ -0,0 +1,32 @@
+package net.lax1dude.eaglercraft.v1_8.sp.server;
+
+import java.util.function.Supplier;
+
+import net.lax1dude.eaglercraft.v1_8.internal.IEaglerFilesystem;
+import net.lax1dude.eaglercraft.v1_8.internal.vfs2.VFile2;
+import net.lax1dude.eaglercraft.v1_8.sp.server.internal.ServerPlatformSingleplayer;
+
+/**
+ * Copyright (c) 2024 lax1dude. All Rights Reserved.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ * 
+ */
+public class WorldsDB {
+
+	private static final Supplier<IEaglerFilesystem> fsGetter = ServerPlatformSingleplayer::getWorldsDatabase;
+
+	public static VFile2 newVFile(Object... path) {
+		return VFile2.create(fsGetter, path);
+	}
+
+}
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/server/export/EPKCompiler.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/server/export/EPKCompiler.java
index 86e198c9..e20eb498 100644
--- a/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/server/export/EPKCompiler.java
+++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/server/export/EPKCompiler.java
@@ -7,8 +7,8 @@ import java.text.SimpleDateFormat;
 import java.util.Date;
 import java.util.zip.CRC32;
 
-import net.lax1dude.eaglercraft.v1_8.EagRuntime;
 import net.lax1dude.eaglercraft.v1_8.EaglerOutputStream;
+import net.lax1dude.eaglercraft.v1_8.EaglerZLIB;
 
 /**
  * Copyright (c) 2022-2024 lax1dude. All Rights Reserved.
@@ -28,11 +28,16 @@ import net.lax1dude.eaglercraft.v1_8.EaglerOutputStream;
 public class EPKCompiler {
 
 	private final EaglerOutputStream os;
+	private final OutputStream dos;
 	private final CRC32 checkSum = new CRC32();
 	private int lengthIntegerOffset = 0;
 	private int totalFileCount = 0;
 
 	public EPKCompiler(String name, String owner, String type) {
+		this(name, owner, type, false, true, null);
+	}
+
+	public EPKCompiler(String name, String owner, String type, boolean gzip, boolean world, String commentStr) {
 		os = new EaglerOutputStream(0x200000);
 		try {
 			
@@ -44,10 +49,11 @@ public class EPKCompiler {
 			os.write(filename.length);
 			os.write(filename);
 			
-			byte[] comment = ("\n\n #  Eagler EPK v2.0 (c) " + EagRuntime.fixDateFormat(new SimpleDateFormat("yyyy")).format(d) + " " +
-					owner + "\n #  export: on " + EagRuntime.fixDateFormat(new SimpleDateFormat("MM/dd/yyyy")).format(d) + " at " +
-					EagRuntime.fixDateFormat(new SimpleDateFormat("hh:mm:ss aa")).format(d) + "\n\n #  world name: " + name + "\n\n")
-					.getBytes(StandardCharsets.UTF_8);
+			byte[] comment = (world ? ("\n\n #  Eagler EPK v2.0 (c) "
+					+ (new SimpleDateFormat("yyyy")).format(d) + " " + owner
+					+ "\n #  export: on " + (new SimpleDateFormat("MM/dd/yyyy")).format(d)
+					+ " at " + (new SimpleDateFormat("hh:mm:ss aa")).format(d)
+					+ "\n\n #  world name: " + name + "\n\n") : commentStr).getBytes(StandardCharsets.UTF_8);
 
 			os.write((comment.length >>> 8) & 255);
 			os.write(comment.length & 255);
@@ -58,40 +64,50 @@ public class EPKCompiler {
 			lengthIntegerOffset = os.size();
 			os.write(new byte[]{(byte)255,(byte)255,(byte)255,(byte)255}); // this will be replaced with the file count
 			
-			os.write('0'); // compression type: none
+			if(gzip) {
+				os.write('G'); // compression type: gzip
+				dos = EaglerZLIB.newGZIPOutputStream(os);
+			}else {
+				os.write('0'); // compression type: none
+				dos = os;
+			}
 			
-			os.write(new byte[]{(byte)72,(byte)69,(byte)65,(byte)68}); // HEAD
-			os.write(new byte[]{(byte)9,(byte)102,(byte)105,(byte)108,(byte)101,(byte)45,(byte)116,(byte)121,
+			dos.write(new byte[]{(byte)72,(byte)69,(byte)65,(byte)68}); // HEAD
+			dos.write(new byte[]{(byte)9,(byte)102,(byte)105,(byte)108,(byte)101,(byte)45,(byte)116,(byte)121,
 					(byte)112,(byte)101}); // 9 + file-type
 			
 			byte[] typeBytes = type.getBytes(StandardCharsets.UTF_8);
-			writeInt(typeBytes.length, os);
-			os.write(typeBytes); // write type
-			os.write('>');
+			writeInt(typeBytes.length, dos);
+			dos.write(typeBytes); // write type
+			dos.write('>');
 			
 			++totalFileCount;
 			
-			os.write(new byte[]{(byte)72,(byte)69,(byte)65,(byte)68}); // HEAD
-			os.write(new byte[]{(byte)10,(byte)119,(byte)111,(byte)114,(byte)108,(byte)100,(byte)45,(byte)110,
-					(byte)97,(byte)109,(byte)101}); // 10 + world-name
+			if(world) {
+				dos.write(new byte[]{(byte)72,(byte)69,(byte)65,(byte)68}); // HEAD
+				dos.write(new byte[]{(byte)10,(byte)119,(byte)111,(byte)114,(byte)108,(byte)100,(byte)45,(byte)110,
+						(byte)97,(byte)109,(byte)101}); // 10 + world-name
+				
+				byte[] nameBytes = name.getBytes(StandardCharsets.UTF_8);
+				writeInt(nameBytes.length, dos);
+				dos.write(nameBytes); // write name
+				dos.write('>');
+				
+				++totalFileCount;
+			}
 			
-			byte[] nameBytes = name.getBytes(StandardCharsets.UTF_8);
-			writeInt(nameBytes.length, os);
-			os.write(nameBytes); // write name
-			os.write('>');
-			
-			++totalFileCount;
-			
-			os.write(new byte[]{(byte)72,(byte)69,(byte)65,(byte)68}); // HEAD
-			os.write(new byte[]{(byte)11,(byte)119,(byte)111,(byte)114,(byte)108,(byte)100,(byte)45,(byte)111,
-					(byte)119,(byte)110,(byte)101,(byte)114}); // 11 + world-owner
-			
-			byte[] ownerBytes = owner.getBytes(StandardCharsets.UTF_8);
-			writeInt(ownerBytes.length, os);
-			os.write(ownerBytes); // write owner
-			os.write('>');
-			
-			++totalFileCount;
+			if(world && owner != null) {
+				dos.write(new byte[]{(byte)72,(byte)69,(byte)65,(byte)68}); // HEAD
+				dos.write(new byte[]{(byte)11,(byte)119,(byte)111,(byte)114,(byte)108,(byte)100,(byte)45,(byte)111,
+						(byte)119,(byte)110,(byte)101,(byte)114}); // 11 + world-owner
+				
+				byte[] ownerBytes = owner.getBytes(StandardCharsets.UTF_8);
+				writeInt(ownerBytes.length, dos);
+				dos.write(ownerBytes); // write owner
+				dos.write('>');
+				
+				++totalFileCount;
+			}
 			
 		}catch(IOException ex) {
 			throw new RuntimeException("This happened somehow", ex);
@@ -105,19 +121,19 @@ public class EPKCompiler {
 			checkSum.update(dat, 0, dat.length);
 			long sum = checkSum.getValue();
 			
-			os.write(new byte[]{(byte)70,(byte)73,(byte)76,(byte)69}); // FILE
+			dos.write(new byte[]{(byte)70,(byte)73,(byte)76,(byte)69}); // FILE
 			
 			byte[] nameBytes = name.getBytes(StandardCharsets.UTF_8);
-			os.write(nameBytes.length);
-			os.write(nameBytes);
+			dos.write(nameBytes.length);
+			dos.write(nameBytes);
 			
-			writeInt(dat.length + 5, os);
-			writeInt((int)sum, os);
+			writeInt(dat.length + 5, dos);
+			writeInt((int)sum, dos);
 			
-			os.write(dat);
+			dos.write(dat);
 			
-			os.write(':');
-			os.write('>');
+			dos.write(':');
+			dos.write('>');
 			
 			++totalFileCount;
 			
@@ -128,8 +144,9 @@ public class EPKCompiler {
 	
 	public byte[] complete() {
 		try {
+			dos.write(new byte[]{(byte)69,(byte)78,(byte)68,(byte)36}); // END$
+			dos.close();
 			
-			os.write(new byte[]{(byte)69,(byte)78,(byte)68,(byte)36}); // END$
 			os.write(new byte[]{(byte)58,(byte)58,(byte)58,(byte)89,(byte)69,(byte)69,(byte)58,(byte)62}); // :::YEE:>
 			
 			byte[] ret = os.toByteArray();
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/server/export/WorldConverterEPK.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/server/export/WorldConverterEPK.java
index bf6ae1a8..524de859 100644
--- a/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/server/export/WorldConverterEPK.java
+++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/server/export/WorldConverterEPK.java
@@ -10,6 +10,7 @@ import net.lax1dude.eaglercraft.v1_8.log4j.LogManager;
 import net.lax1dude.eaglercraft.v1_8.log4j.Logger;
 import net.lax1dude.eaglercraft.v1_8.sp.server.EaglerIntegratedServerWorker;
 import net.lax1dude.eaglercraft.v1_8.sp.server.EaglerSaveFormat;
+import net.lax1dude.eaglercraft.v1_8.sp.server.WorldsDB;
 import net.minecraft.nbt.CompressedStreamTools;
 import net.minecraft.nbt.NBTTagCompound;
 import net.minecraft.world.storage.WorldInfo;
@@ -37,7 +38,7 @@ public class WorldConverterEPK {
 		logger.info("Importing world \"{}\" from EPK", newName);
 		String folderName = newName.replaceAll("[\\./\"]", "_");
 		VFile2 worldDir = EaglerIntegratedServerWorker.saveFormat.getSaveLoader(folderName, false).getWorldDirectory();
-		while((new VFile2(worldDir, "level.dat")).exists() || (new VFile2(worldDir, "level.dat_old")).exists()) {
+		while(WorldsDB.newVFile(worldDir, "level.dat").exists() || WorldsDB.newVFile(worldDir, "level.dat_old").exists()) {
 			folderName += "_";
 			worldDir = EaglerIntegratedServerWorker.saveFormat.getSaveLoader(folderName, false).getWorldDirectory();
 		}
@@ -74,7 +75,7 @@ public class WorldConverterEPK {
 						CompressedStreamTools.writeCompressed(worldDatNBT, tmp);
 						b = tmp.toByteArray();
 					}
-					VFile2 ff = new VFile2(worldDir, f.name);
+					VFile2 ff = WorldsDB.newVFile(worldDir, f.name);
 					ff.setAllBytes(b);
 					prog += b.length;
 					++cnt;
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/server/export/WorldConverterMCA.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/server/export/WorldConverterMCA.java
index ce8e5900..7e5bfa5e 100644
--- a/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/server/export/WorldConverterMCA.java
+++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/server/export/WorldConverterMCA.java
@@ -19,6 +19,7 @@ import net.lax1dude.eaglercraft.v1_8.log4j.Logger;
 import net.lax1dude.eaglercraft.v1_8.sp.server.EaglerChunkLoader;
 import net.lax1dude.eaglercraft.v1_8.sp.server.EaglerIntegratedServerWorker;
 import net.lax1dude.eaglercraft.v1_8.sp.server.EaglerSaveFormat;
+import net.lax1dude.eaglercraft.v1_8.sp.server.WorldsDB;
 import net.minecraft.world.chunk.storage.RegionFile;
 import net.minecraft.world.storage.WorldInfo;
 import net.minecraft.nbt.CompressedStreamTools;
@@ -47,7 +48,7 @@ public class WorldConverterMCA {
 		logger.info("Importing world \"{}\" from MCA", newName);
 		String folderName = newName.replaceAll("[\\./\"]", "_");
 		VFile2 worldDir = EaglerIntegratedServerWorker.saveFormat.getSaveLoader(folderName, false).getWorldDirectory();
-		while((new VFile2(worldDir, "level.dat")).exists() || (new VFile2(worldDir, "level.dat_old")).exists()) {
+		while(WorldsDB.newVFile(worldDir, "level.dat").exists() || WorldsDB.newVFile(worldDir, "level.dat_old").exists()) {
 			folderName += "_";
 			worldDir = EaglerIntegratedServerWorker.saveFormat.getSaveLoader(folderName, false).getWorldDirectory();
 		}
@@ -105,11 +106,11 @@ public class WorldConverterMCA {
 					EaglerOutputStream bo = new EaglerOutputStream();
 					CompressedStreamTools.writeCompressed(worldDatNBT, bo);
 					b = bo.toByteArray();
-					VFile2 ff = new VFile2(worldDir, fileName);
+					VFile2 ff = WorldsDB.newVFile(worldDir, fileName);
 					ff.setAllBytes(b);
 					prog += b.length;
 				} else if ((fileName.endsWith(".mcr") || fileName.endsWith(".mca")) && (fileName.startsWith("region/") || fileName.startsWith("DIM1/region/") || fileName.startsWith("DIM-1/region/"))) {
-					VFile2 chunkFolder = new VFile2(worldDir, fileName.startsWith("DIM1") ? "level1" : (fileName.startsWith("DIM-1") ? "level-1" : "level0"));
+					VFile2 chunkFolder = WorldsDB.newVFile(worldDir, fileName.startsWith("DIM1") ? "level1" : (fileName.startsWith("DIM-1") ? "level-1" : "level0"));
 					RegionFile mca = new RegionFile(new RandomAccessMemoryFile(b, b.length));
 					int loadChunksCount = 0;
 					for(int j = 0; j < 32; ++j) {
@@ -130,7 +131,7 @@ public class WorldConverterMCA {
 								}
 								int chunkX = chunkLevel.getInteger("xPos");
 								int chunkZ = chunkLevel.getInteger("zPos");
-								VFile2 chunkOut = new VFile2(chunkFolder, EaglerChunkLoader.getChunkPath(chunkX, chunkZ) + ".dat");
+								VFile2 chunkOut = WorldsDB.newVFile(chunkFolder, EaglerChunkLoader.getChunkPath(chunkX, chunkZ) + ".dat");
 								if(chunkOut.exists()) {
 									logger.error("{}: Chunk already exists: {}", fileName, chunkOut.getPath());
 									continue;
@@ -152,7 +153,7 @@ public class WorldConverterMCA {
 				} else if (fileName.startsWith("playerdata/") || fileName.startsWith("stats/")) {
 					//TODO: LAN player inventories
 				} else if (fileName.startsWith("data/") || fileName.startsWith("players/") || fileName.startsWith("eagler/skulls/")) {
-					VFile2 ff = new VFile2(worldDir, fileName);
+					VFile2 ff = WorldsDB.newVFile(worldDir, fileName);
 					ff.setAllBytes(b);
 					prog += b.length;
 				} else if (!fileName.equals("level.dat_mcr") && !fileName.equals("session.lock")) {
@@ -184,7 +185,7 @@ public class WorldConverterMCA {
 			zos.setComment("contains backup of world '" + folderName + "'");
 			worldFolder = EaglerIntegratedServerWorker.saveFormat.getSaveLoader(folderName, false).getWorldDirectory();
 			logger.info("Exporting world directory \"{}\" as MCA", worldFolder.getPath());
-			VFile2 vf = new VFile2(worldFolder, "level.dat");
+			VFile2 vf = WorldsDB.newVFile(worldFolder, "level.dat");
 			byte[] b;
 			int lastProgUpdate = 0;
 			int prog = 0;
@@ -196,7 +197,7 @@ public class WorldConverterMCA {
 				prog += b.length;
 				safe = true;
 			}
-			vf = new VFile2(worldFolder, "level.dat_old");
+			vf = WorldsDB.newVFile(worldFolder, "level.dat_old");
 			if(vf.exists()) {
 				zos.putNextEntry(new ZipEntry(folderName + "/level.dat_old"));
 				b = vf.getAllBytes();
@@ -212,11 +213,11 @@ public class WorldConverterMCA {
 			String[] dstFolderNames = new String[] { "/region/", "/DIM-1/region/", "/DIM1/region/" };
 			List<VFile2> fileList;
 			for(int i = 0; i < 3; ++i) {
-				vf = new VFile2(worldFolder, srcFolderNames[i]);
+				vf = WorldsDB.newVFile(worldFolder, srcFolderNames[i]);
 				fileList = vf.listFiles(true);
 				String regionFolder = folderName + dstFolderNames[i];
 				logger.info("Converting chunks in \"{}\" as MCA to \"{}\"...", vf.getPath(), regionFolder);
-				Map<String,RegionFile> regionFiles = new HashMap();
+				Map<String,RegionFile> regionFiles = new HashMap<>();
 				for(int k = 0, l = fileList.size(); k < l; ++k) {
 					VFile2 chunkFile = fileList.get(k);
 					NBTTagCompound chunkNBT;
@@ -266,7 +267,7 @@ public class WorldConverterMCA {
 				}
 			}
 			logger.info("Copying extra world data...");
-			fileList = (new VFile2(worldFolder, "data")).listFiles(false);
+			fileList = WorldsDB.newVFile(worldFolder, "data").listFiles(false);
 			for(int k = 0, l = fileList.size(); k < l; ++k) {
 				VFile2 dataFile = fileList.get(k);
 				zos.putNextEntry(new ZipEntry(folderName + "/data/" + dataFile.getName()));
@@ -278,7 +279,7 @@ public class WorldConverterMCA {
 					EaglerIntegratedServerWorker.sendProgress("singleplayer.busy.exporting.2", prog);
 				}
 			}
-			fileList = (new VFile2(worldFolder, "players")).listFiles(false);
+			fileList = WorldsDB.newVFile(worldFolder, "players").listFiles(false);
 			for(int k = 0, l = fileList.size(); k < l; ++k) {
 				VFile2 dataFile = fileList.get(k);
 				zos.putNextEntry(new ZipEntry(folderName + "/players/" + dataFile.getName()));
@@ -290,7 +291,7 @@ public class WorldConverterMCA {
 					EaglerIntegratedServerWorker.sendProgress("singleplayer.busy.exporting.2", prog);
 				}
 			}
-			fileList = (new VFile2(worldFolder, "eagler/skulls")).listFiles(false);
+			fileList = WorldsDB.newVFile(worldFolder, "eagler/skulls").listFiles(false);
 			for(int k = 0, l = fileList.size(); k < l; ++k) {
 				VFile2 dataFile = fileList.get(k);
 				zos.putNextEntry(new ZipEntry(folderName + "/eagler/skulls/" + dataFile.getName()));
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/server/skins/CustomSkullData.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/server/skins/CustomSkullData.java
index 5a90a9e2..b37a5562 100644
--- a/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/server/skins/CustomSkullData.java
+++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/server/skins/CustomSkullData.java
@@ -1,5 +1,12 @@
 package net.lax1dude.eaglercraft.v1_8.sp.server.skins;
 
+import net.lax1dude.eaglercraft.v1_8.EagRuntime;
+import net.lax1dude.eaglercraft.v1_8.EaglercraftUUID;
+import net.lax1dude.eaglercraft.v1_8.socket.protocol.GamePluginMessageProtocol;
+import net.lax1dude.eaglercraft.v1_8.socket.protocol.pkt.GameMessagePacket;
+import net.lax1dude.eaglercraft.v1_8.socket.protocol.pkt.server.SPacketOtherSkinCustomV3EAG;
+import net.lax1dude.eaglercraft.v1_8.socket.protocol.util.SkinPacketVersionCache;
+
 /**
  * Copyright (c) 2022-2024 lax1dude. All Rights Reserved.
  * 
@@ -19,21 +26,25 @@ public class CustomSkullData {
 
 	public String skinURL;
 	public long lastHit;
-	public byte[] skinData;
+	public SkinPacketVersionCache skinData;
 
 	public CustomSkullData(String skinURL, byte[] skinData) {
 		this.skinURL = skinURL;
-		this.lastHit = System.currentTimeMillis();
-		this.skinData = skinData;
+		this.lastHit = EagRuntime.steadyTimeMillis();
+		if(skinData.length != 16384) {
+			byte[] fixed = new byte[16384];
+			System.arraycopy(skinData, 0, fixed, 0, skinData.length > fixed.length ? fixed.length : skinData.length);
+			skinData = fixed;
+		}
+		this.skinData = SkinPacketVersionCache.createCustomV3(0l, 0l, 0, skinData);
 	}
 
 	public byte[] getFullSkin() {
-		if(skinData.length == 16384) {
-			return skinData;
-		}
-		byte[] ret = new byte[16384];
-		System.arraycopy(skinData, 0, ret, 0, skinData.length > ret.length ? ret.length : skinData.length);
-		return ret;
+		return ((SPacketOtherSkinCustomV3EAG)skinData.getV3()).customSkin;
+	}
+
+	public GameMessagePacket getSkinPacket(EaglercraftUUID uuid, GamePluginMessageProtocol protocol) {
+		return SkinPacketVersionCache.rewriteUUID(skinData.get(protocol), uuid.getMostSignificantBits(), uuid.getLeastSignificantBits());
 	}
 
 }
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/server/skins/IntegratedCapePackets.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/server/skins/IntegratedCapePackets.java
index 402cde5d..6df2b5c3 100644
--- a/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/server/skins/IntegratedCapePackets.java
+++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/server/skins/IntegratedCapePackets.java
@@ -3,7 +3,9 @@ package net.lax1dude.eaglercraft.v1_8.sp.server.skins;
 import java.io.IOException;
 
 import net.lax1dude.eaglercraft.v1_8.EaglercraftUUID;
-import net.minecraft.entity.player.EntityPlayerMP;
+import net.lax1dude.eaglercraft.v1_8.socket.protocol.pkt.GameMessagePacket;
+import net.lax1dude.eaglercraft.v1_8.socket.protocol.pkt.server.SPacketOtherCapeCustomEAG;
+import net.lax1dude.eaglercraft.v1_8.socket.protocol.pkt.server.SPacketOtherCapePresetEAG;
 
 /**
  * Copyright (c) 2024 lax1dude. All Rights Reserved.
@@ -24,56 +26,27 @@ public class IntegratedCapePackets {
 
 	public static final int PACKET_MY_CAPE_PRESET = 0x01;
 	public static final int PACKET_MY_CAPE_CUSTOM = 0x02;
-	public static final int PACKET_GET_OTHER_CAPE = 0x03;
-	public static final int PACKET_OTHER_CAPE_PRESET = 0x04;
-	public static final int PACKET_OTHER_CAPE_CUSTOM = 0x05;
-
-	public static void processPacket(byte[] data, EntityPlayerMP sender, IntegratedCapeService capeService) throws IOException {
-		if(data.length == 0) {
-			throw new IOException("Zero-length packet recieved");
-		}
-		int packetId = (int)data[0] & 0xFF;
-		try {
-			switch(packetId) {
-			case PACKET_GET_OTHER_CAPE:
-				processGetOtherCape(data, sender, capeService);
-				break;
-			default:
-				throw new IOException("Unknown packet type " + packetId);
-			}
-		}catch(IOException ex) {
-			throw ex;
-		}catch(Throwable t) {
-			throw new IOException("Unhandled exception handling packet type " + packetId, t);
-		}
-	}
-
-	private static void processGetOtherCape(byte[] data, EntityPlayerMP sender, IntegratedCapeService capeService) throws IOException {
-		if(data.length != 17) {
-			throw new IOException("Invalid length " + data.length + " for skin request packet");
-		}
-		EaglercraftUUID searchUUID = IntegratedSkinPackets.bytesToUUID(data, 1);
-		capeService.processGetOtherCape(searchUUID, sender);
-	}
 
 	public static void registerEaglerPlayer(EaglercraftUUID clientUUID, byte[] bs, IntegratedCapeService capeService) throws IOException {
 		if(bs.length == 0) {
 			throw new IOException("Zero-length packet recieved");
 		}
-		byte[] generatedPacket;
+		GameMessagePacket generatedPacket;
 		int packetType = (int)bs[0] & 0xFF;
 		switch(packetType) {
 		case PACKET_MY_CAPE_PRESET:
 			if(bs.length != 5) {
 				throw new IOException("Invalid length " + bs.length + " for preset cape packet");
 			}
-			generatedPacket = IntegratedCapePackets.makePresetResponse(clientUUID, (bs[1] << 24) | (bs[2] << 16) | (bs[3] << 8) | (bs[4] & 0xFF));
+			generatedPacket = new SPacketOtherCapePresetEAG(clientUUID.msb, clientUUID.lsb, (bs[1] << 24) | (bs[2] << 16) | (bs[3] << 8) | (bs[4] & 0xFF));
 			break;
 		case PACKET_MY_CAPE_CUSTOM:
 			if(bs.length != 1174) {
 				throw new IOException("Invalid length " + bs.length + " for custom cape packet");
 			}
-			generatedPacket = IntegratedCapePackets.makeCustomResponse(clientUUID, bs, 1, 1173);
+			byte[] capePixels = new byte[bs.length - 1];
+			System.arraycopy(bs, 1, capePixels, 0, capePixels.length);
+			generatedPacket = new SPacketOtherCapeCustomEAG(clientUUID.msb, clientUUID.lsb, capePixels);
 			break;
 		default:
 			throw new IOException("Unknown skin packet type: " + packetType);
@@ -82,29 +55,7 @@ public class IntegratedCapePackets {
 	}
 
 	public static void registerEaglerPlayerFallback(EaglercraftUUID clientUUID, IntegratedCapeService capeService) {
-		capeService.registerEaglercraftPlayer(clientUUID, IntegratedCapePackets.makePresetResponse(clientUUID, 0));
+		capeService.registerEaglercraftPlayer(clientUUID, new SPacketOtherCapePresetEAG(clientUUID.msb, clientUUID.lsb, 0));
 	}
 
-	public static byte[] makePresetResponse(EaglercraftUUID uuid, int presetId) {
-		byte[] ret = new byte[1 + 16 + 4];
-		ret[0] = (byte)PACKET_OTHER_CAPE_PRESET;
-		IntegratedSkinPackets.UUIDToBytes(uuid, ret, 1);
-		ret[17] = (byte)(presetId >>> 24);
-		ret[18] = (byte)(presetId >>> 16);
-		ret[19] = (byte)(presetId >>> 8);
-		ret[20] = (byte)(presetId & 0xFF);
-		return ret;
-	}
-
-	public static byte[] makeCustomResponse(EaglercraftUUID uuid, byte[] pixels) {
-		return makeCustomResponse(uuid, pixels, 0, pixels.length);
-	}
-
-	public static byte[] makeCustomResponse(EaglercraftUUID uuid, byte[] pixels, int offset, int length) {
-		byte[] ret = new byte[1 + 16 + length];
-		ret[0] = (byte)PACKET_OTHER_CAPE_CUSTOM;
-		IntegratedSkinPackets.UUIDToBytes(uuid, ret, 1);
-		System.arraycopy(pixels, offset, ret, 17, length);
-		return ret;
-	}
 }
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/server/skins/IntegratedCapeService.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/server/skins/IntegratedCapeService.java
index b3401a83..7e17e673 100644
--- a/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/server/skins/IntegratedCapeService.java
+++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/server/skins/IntegratedCapeService.java
@@ -7,10 +7,9 @@ import java.util.Map;
 import net.lax1dude.eaglercraft.v1_8.EaglercraftUUID;
 import net.lax1dude.eaglercraft.v1_8.log4j.LogManager;
 import net.lax1dude.eaglercraft.v1_8.log4j.Logger;
-import net.lax1dude.eaglercraft.v1_8.netty.Unpooled;
+import net.lax1dude.eaglercraft.v1_8.socket.protocol.pkt.GameMessagePacket;
+import net.lax1dude.eaglercraft.v1_8.socket.protocol.pkt.server.SPacketOtherCapePresetEAG;
 import net.minecraft.entity.player.EntityPlayerMP;
-import net.minecraft.network.PacketBuffer;
-import net.minecraft.network.play.server.S3FPacketCustomPayload;
 
 /**
  * Copyright (c) 2024 lax1dude. All Rights Reserved.
@@ -33,19 +32,7 @@ public class IntegratedCapeService {
 
 	public static final int masterRateLimitPerPlayer = 250;
 
-	public static final String CHANNEL = "EAG|Capes-1.8";
-
-	private final Map<EaglercraftUUID, byte[]> capesCache = new HashMap();
-
-	public void processPacket(byte[] packetData, EntityPlayerMP sender) {
-		try {
-			IntegratedCapePackets.processPacket(packetData, sender, this);
-		} catch (IOException e) {
-			logger.error("Invalid skin request packet recieved from player {}!", sender.getName());
-			logger.error(e);
-			sender.playerNetServerHandler.kickPlayerFromServer("Invalid skin request packet recieved!");
-		}
-	}
+	private final Map<EaglercraftUUID, GameMessagePacket> capesCache = new HashMap<>();
 
 	public void processLoginPacket(byte[] packetData, EntityPlayerMP sender) {
 		try {
@@ -57,16 +44,16 @@ public class IntegratedCapeService {
 		}
 	}
 
-	public void registerEaglercraftPlayer(EaglercraftUUID playerUUID, byte[] capePacket) {
+	public void registerEaglercraftPlayer(EaglercraftUUID playerUUID, GameMessagePacket capePacket) {
 		capesCache.put(playerUUID, capePacket);
 	}
 
 	public void processGetOtherCape(EaglercraftUUID searchUUID, EntityPlayerMP sender) {
-		byte[] maybeCape = capesCache.get(searchUUID);
+		GameMessagePacket maybeCape = capesCache.get(searchUUID);
 		if(maybeCape == null) {
-			maybeCape = IntegratedCapePackets.makePresetResponse(searchUUID, 0);
+			maybeCape = new SPacketOtherCapePresetEAG(searchUUID.msb, searchUUID.lsb, 0);
 		}
-		sender.playerNetServerHandler.sendPacket(new S3FPacketCustomPayload(CHANNEL, new PacketBuffer(Unpooled.buffer(maybeCape, maybeCape.length).writerIndex(maybeCape.length))));
+		sender.playerNetServerHandler.sendEaglerMessage(maybeCape);
 	}
 
 	public void unregisterPlayer(EaglercraftUUID playerUUID) {
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/server/skins/IntegratedSkinPackets.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/server/skins/IntegratedSkinPackets.java
index 4c93d562..67da9f9d 100644
--- a/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/server/skins/IntegratedSkinPackets.java
+++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/server/skins/IntegratedSkinPackets.java
@@ -3,7 +3,9 @@ package net.lax1dude.eaglercraft.v1_8.sp.server.skins;
 import java.io.IOException;
 
 import net.lax1dude.eaglercraft.v1_8.EaglercraftUUID;
-import net.minecraft.entity.player.EntityPlayerMP;
+import net.lax1dude.eaglercraft.v1_8.socket.protocol.pkt.GameMessagePacket;
+import net.lax1dude.eaglercraft.v1_8.socket.protocol.pkt.server.*;
+import net.lax1dude.eaglercraft.v1_8.socket.protocol.util.SkinPacketVersionCache;
 
 /**
  * Copyright (c) 2022-2024 lax1dude. All Rights Reserved.
@@ -24,76 +26,14 @@ public class IntegratedSkinPackets {
 
 	public static final int PACKET_MY_SKIN_PRESET = 0x01;
 	public static final int PACKET_MY_SKIN_CUSTOM = 0x02;
-	public static final int PACKET_GET_OTHER_SKIN = 0x03;
-	public static final int PACKET_OTHER_SKIN_PRESET = 0x04;
-	public static final int PACKET_OTHER_SKIN_CUSTOM = 0x05;
-	public static final int PACKET_GET_SKIN_BY_URL = 0x06;
-	public static final int PACKET_INSTALL_NEW_SKIN = 0x07;
 	
-	public static void processPacket(byte[] data, EntityPlayerMP sender, IntegratedSkinService skinService) throws IOException {
-		if(data.length == 0) {
-			throw new IOException("Zero-length packet recieved");
-		}
-		int packetId = (int)data[0] & 0xFF;
-		try {
-			switch(packetId) {
-			case PACKET_GET_OTHER_SKIN:
-				processGetOtherSkin(data, sender, skinService);
-				break;
-			case PACKET_GET_SKIN_BY_URL:
-				processGetOtherSkinByURL(data, sender, skinService);
-				break;
-			case PACKET_INSTALL_NEW_SKIN:
-				processInstallNewSkin(data, sender, skinService);
-				break;
-			default:
-				throw new IOException("Unknown packet type " + packetId);
-			}
-		}catch(IOException ex) {
-			throw ex;
-		}catch(Throwable t) {
-			throw new IOException("Unhandled exception handling packet type " + packetId, t);
-		}
-	}
-	
-	private static void processGetOtherSkin(byte[] data, EntityPlayerMP sender, IntegratedSkinService skinService) throws IOException {
-		if(data.length != 17) {
-			throw new IOException("Invalid length " + data.length + " for skin request packet");
-		}
-		EaglercraftUUID searchUUID = bytesToUUID(data, 1);
-		skinService.processPacketGetOtherSkin(searchUUID, sender);
-	}
-	
-	private static void processGetOtherSkinByURL(byte[] data, EntityPlayerMP sender, IntegratedSkinService skinService) throws IOException {
-		if(data.length < 20) {
-			throw new IOException("Invalid length " + data.length + " for skin request packet");
-		}
-		EaglercraftUUID searchUUID = bytesToUUID(data, 1);
-		int urlLength = (data[17] << 8) | data[18];
-		if(data.length < 19 + urlLength) {
-			throw new IOException("Invalid length " + data.length + " for skin request packet with " + urlLength + " length URL");
-		}
-		skinService.processPacketGetOtherSkin(searchUUID, bytesToAscii(data, 19, urlLength), sender);
-	}
-	
-	private static void processInstallNewSkin(byte[] data, EntityPlayerMP sender, IntegratedSkinService skinService) throws IOException {
-		if(data.length < 3) {
-			throw new IOException("Invalid length " + data.length + " for skin data packet");
-		}
-		int dataLength = (data[1] << 8) | data[2];
-		byte[] dataBmp = new byte[dataLength];
-		if(data.length != dataLength + 3) {
-			throw new IOException("Invalid data length " + dataLength + " for " + data.length + " byte skin data packet");
-		}
-		System.arraycopy(data, 3, dataBmp, 0, dataLength);
-		skinService.processPacketInstallNewSkin(dataBmp, sender);
-	}
-	
-	public static void registerEaglerPlayer(EaglercraftUUID clientUUID, byte[] bs, IntegratedSkinService skinService) throws IOException {
+	public static void registerEaglerPlayer(EaglercraftUUID clientUUID, byte[] bs, IntegratedSkinService skinService,
+			int protocolVers) throws IOException {
 		if(bs.length == 0) {
 			throw new IOException("Zero-length packet recieved");
 		}
-		byte[] generatedPacket;
+		GameMessagePacket generatedPacketV3 = null;
+		GameMessagePacket generatedPacketV4 = null;
 		int skinModel = -1;
 		int packetType = (int)bs[0] & 0xFF;
 		switch(packetType) {
@@ -101,118 +41,63 @@ public class IntegratedSkinPackets {
 			if(bs.length != 5) {
 				throw new IOException("Invalid length " + bs.length + " for preset skin packet");
 			}
-			generatedPacket = makePresetResponse(clientUUID, (bs[1] << 24) | (bs[2] << 16) | (bs[3] << 8) | (bs[4] & 0xFF));
+			generatedPacketV3 = generatedPacketV4 = new SPacketOtherSkinPresetEAG(clientUUID.msb, clientUUID.lsb,
+					(bs[1] << 24) | (bs[2] << 16) | (bs[3] << 8) | (bs[4] & 0xFF));
 			break;
 		case PACKET_MY_SKIN_CUSTOM:
-			byte[] pixels = new byte[16384];
-			if(bs.length != 2 + pixels.length) {
-				throw new IOException("Invalid length " + bs.length + " for custom skin packet");
+			if(protocolVers <= 3) {
+				byte[] pixels = new byte[16384];
+				if(bs.length != 2 + pixels.length) {
+					throw new IOException("Invalid length " + bs.length + " for custom skin packet");
+				}
+				setAlphaForChestV3(pixels);
+				System.arraycopy(bs, 2, pixels, 0, pixels.length);
+				generatedPacketV3 = new SPacketOtherSkinCustomV3EAG(clientUUID.msb, clientUUID.lsb, (skinModel = (int)bs[1] & 0xFF), pixels);
+			}else {
+				byte[] pixels = new byte[12288];
+				if(bs.length != 2 + pixels.length) {
+					throw new IOException("Invalid length " + bs.length + " for custom skin packet");
+				}
+				setAlphaForChestV4(pixels);
+				System.arraycopy(bs, 2, pixels, 0, pixels.length);
+				generatedPacketV4 = new SPacketOtherSkinCustomV4EAG(clientUUID.msb, clientUUID.lsb, (skinModel = (int)bs[1] & 0xFF), pixels);
 			}
-			setAlphaForChest(pixels, (byte)255);
-			System.arraycopy(bs, 2, pixels, 0, pixels.length);
-			generatedPacket = makeCustomResponse(clientUUID, (skinModel = (int)bs[1] & 0xFF), pixels);
 			break;
 		default:
 			throw new IOException("Unknown skin packet type: " + packetType);
 		}
-		skinService.processPacketPlayerSkin(clientUUID, generatedPacket, skinModel);
+		skinService.processPacketPlayerSkin(clientUUID, new SkinPacketVersionCache(generatedPacketV3, generatedPacketV4), skinModel);
 	}
 	
 	public static void registerEaglerPlayerFallback(EaglercraftUUID clientUUID, IntegratedSkinService skinService) throws IOException {
 		int skinModel = (clientUUID.hashCode() & 1) != 0 ? 1 : 0;
-		byte[] generatedPacket = makePresetResponse(clientUUID, skinModel);
-		skinService.processPacketPlayerSkin(clientUUID, generatedPacket, skinModel);
+		skinService.processPacketPlayerSkin(clientUUID, SkinPacketVersionCache.createPreset(clientUUID.msb, clientUUID.lsb, skinModel), skinModel);
 	}
 	
-	public static void setAlphaForChest(byte[] skin64x64, byte alpha) {
+	public static void setAlphaForChestV3(byte[] skin64x64) {
 		if(skin64x64.length != 16384) {
 			throw new IllegalArgumentException("Skin is not 64x64!");
 		}
 		for(int y = 20; y < 32; ++y) {
 			for(int x = 16; x < 40; ++x) {
-				skin64x64[(y << 8) | (x << 2)] = alpha;
+				skin64x64[(y << 8) | (x << 2)] = (byte)0xFF;
 			}
 		}
 	}
 	
-	public static byte[] makePresetResponse(EaglercraftUUID uuid) {
-		return makePresetResponse(uuid, (uuid.hashCode() & 1) != 0 ? 1 : 0);
-	}
-	
-	public static byte[] makePresetResponse(EaglercraftUUID uuid, int presetId) {
-		byte[] ret = new byte[1 + 16 + 4];
-		ret[0] = (byte)PACKET_OTHER_SKIN_PRESET;
-		UUIDToBytes(uuid, ret, 1);
-		ret[17] = (byte)(presetId >>> 24);
-		ret[18] = (byte)(presetId >>> 16);
-		ret[19] = (byte)(presetId >>> 8);
-		ret[20] = (byte)(presetId & 0xFF);
-		return ret;
-	}
-	
-	public static byte[] makeCustomResponse(EaglercraftUUID uuid, int model, byte[] pixels) {
-		byte[] ret = new byte[1 + 16 + 1 + pixels.length];
-		ret[0] = (byte)PACKET_OTHER_SKIN_CUSTOM;
-		UUIDToBytes(uuid, ret, 1);
-		ret[17] = (byte)model;
-		System.arraycopy(pixels, 0, ret, 18, pixels.length);
-		return ret;
-	}
-	
-	public static EaglercraftUUID bytesToUUID(byte[] bytes, int off) {
-		long msb = (((long) bytes[off] & 0xFFl) << 56l) | (((long) bytes[off + 1] & 0xFFl) << 48l)
-				| (((long) bytes[off + 2] & 0xFFl) << 40l) | (((long) bytes[off + 3] & 0xFFl) << 32l)
-				| (((long) bytes[off + 4] & 0xFFl) << 24l) | (((long) bytes[off + 5] & 0xFFl) << 16l)
-				| (((long) bytes[off + 6] & 0xFFl) << 8l) | ((long) bytes[off + 7] & 0xFFl);
-		long lsb = (((long) bytes[off + 8] & 0xFFl) << 56l) | (((long) bytes[off + 9] & 0xFFl) << 48l)
-				| (((long) bytes[off + 10] & 0xFFl) << 40l) | (((long) bytes[off + 11] & 0xFFl) << 32l)
-				| (((long) bytes[off + 12] & 0xFFl) << 24l) | (((long) bytes[off + 13] & 0xFFl) << 16l)
-				| (((long) bytes[off + 14] & 0xFFl) << 8l) | ((long) bytes[off + 15] & 0xFFl);
-		return new EaglercraftUUID(msb, lsb);
-	}
-	
-	private static final String hex = "0123456789abcdef";
-	
-	public static String bytesToString(byte[] bytes, int off, int len) {
-		char[] ret = new char[len << 1];
-		for(int i = 0; i < len; ++i) {
-			ret[i * 2] = hex.charAt((bytes[off + i] >> 4) & 0xF);
-			ret[i * 2 + 1] = hex.charAt(bytes[off + i] & 0xF);
+	public static void setAlphaForChestV4(byte[] skin64x64) {
+		if(skin64x64.length != 12288) {
+			throw new IllegalArgumentException("Skin is not 64x64!");
 		}
-		return new String(ret);
-	}
-	
-	public static String bytesToAscii(byte[] bytes, int off, int len) {
-		char[] ret = new char[len];
-		for(int i = 0; i < len; ++i) {
-			ret[i] = (char)((int)bytes[off + i] & 0xFF);
+		for(int y = 20; y < 32; ++y) {
+			for(int x = 16; x < 40; ++x) {
+				skin64x64[((y << 6) | x) * 3] |= 0x80;
+			}
 		}
-		return new String(ret);
-	}
-
-	public static String bytesToAscii(byte[] bytes) {
-		return bytesToAscii(bytes, 0, bytes.length);
 	}
 	
-	public static void UUIDToBytes(EaglercraftUUID uuid, byte[] bytes, int off) {
-		long msb = uuid.getMostSignificantBits();
-		long lsb = uuid.getLeastSignificantBits();
-		bytes[off] = (byte)(msb >>> 56l);
-		bytes[off + 1] = (byte)(msb >>> 48l);
-		bytes[off + 2] = (byte)(msb >>> 40l);
-		bytes[off + 3] = (byte)(msb >>> 32l);
-		bytes[off + 4] = (byte)(msb >>> 24l);
-		bytes[off + 5] = (byte)(msb >>> 16l);
-		bytes[off + 6] = (byte)(msb >>> 8l);
-		bytes[off + 7] = (byte)(msb & 0xFFl);
-		bytes[off + 8] = (byte)(lsb >>> 56l);
-		bytes[off + 9] = (byte)(lsb >>> 48l);
-		bytes[off + 10] = (byte)(lsb >>> 40l);
-		bytes[off + 11] = (byte)(lsb >>> 32l);
-		bytes[off + 12] = (byte)(lsb >>> 24l);
-		bytes[off + 13] = (byte)(lsb >>> 16l);
-		bytes[off + 14] = (byte)(lsb >>> 8l);
-		bytes[off + 15] = (byte)(lsb & 0xFFl);
+	public static SPacketOtherSkinPresetEAG makePresetResponse(EaglercraftUUID uuid) {
+		return new SPacketOtherSkinPresetEAG(uuid.msb, uuid.lsb, (uuid.hashCode() & 1) != 0 ? 1 : 0);
 	}
 	
 	public static byte[] asciiString(String string) {
@@ -231,21 +116,4 @@ public class IntegratedSkinPackets {
 		return "slim".equalsIgnoreCase(modelName) ? 1 : 0;
 	}
 
-	public static byte[] rewriteUUID(EaglercraftUUID newUUID, byte[] pkt) {
-		byte[] ret = new byte[pkt.length];
-		System.arraycopy(pkt, 0, ret, 0, pkt.length);
-		UUIDToBytes(newUUID, ret, 1);
-		return ret;
-	}
-
-	public static byte[] rewriteUUIDModel(EaglercraftUUID newUUID, byte[] pkt, int model) {
-		byte[] ret = new byte[pkt.length];
-		System.arraycopy(pkt, 0, ret, 0, pkt.length);
-		UUIDToBytes(newUUID, ret, 1);
-		if(ret[0] == (byte)PACKET_OTHER_SKIN_CUSTOM) {
-			ret[17] = (byte)model;
-		}
-		return ret;
-	}
-
 }
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/server/skins/IntegratedSkinService.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/server/skins/IntegratedSkinService.java
index e2a89173..0aa1ce1c 100644
--- a/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/server/skins/IntegratedSkinService.java
+++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/server/skins/IntegratedSkinService.java
@@ -7,17 +7,19 @@ import java.util.Iterator;
 import java.util.Map;
 
 import net.lax1dude.eaglercraft.v1_8.Base64;
+import net.lax1dude.eaglercraft.v1_8.EagRuntime;
 import net.lax1dude.eaglercraft.v1_8.EaglercraftUUID;
 import net.lax1dude.eaglercraft.v1_8.crypto.SHA1Digest;
 import net.lax1dude.eaglercraft.v1_8.internal.vfs2.VFile2;
 import net.lax1dude.eaglercraft.v1_8.log4j.LogManager;
 import net.lax1dude.eaglercraft.v1_8.log4j.Logger;
-import net.lax1dude.eaglercraft.v1_8.netty.Unpooled;
+import net.lax1dude.eaglercraft.v1_8.socket.protocol.pkt.GameMessagePacket;
+import net.lax1dude.eaglercraft.v1_8.socket.protocol.pkt.server.SPacketOtherSkinPresetEAG;
+import net.lax1dude.eaglercraft.v1_8.socket.protocol.util.SkinPacketVersionCache;
+import net.lax1dude.eaglercraft.v1_8.sp.server.WorldsDB;
 import net.minecraft.entity.player.EntityPlayerMP;
 import net.minecraft.init.Items;
 import net.minecraft.item.ItemStack;
-import net.minecraft.network.PacketBuffer;
-import net.minecraft.network.play.server.S3FPacketCustomPayload;
 import net.minecraft.util.ChatComponentTranslation;
 import net.minecraft.util.EnumChatFormatting;
 import net.minecraft.nbt.NBTTagCompound;
@@ -43,8 +45,6 @@ public class IntegratedSkinService {
 
 	public static final Logger logger = LogManager.getLogger("IntegratedSkinService");
 
-	public static final String CHANNEL = "EAG|Skins-1.8";
-
 	public static final byte[] skullNotFoundTexture = new byte[4096];
 
 	static {
@@ -62,8 +62,8 @@ public class IntegratedSkinService {
 
 	public final VFile2 skullsDirectory;
 
-	public final Map<EaglercraftUUID,byte[]> playerSkins = new HashMap();
-	public final Map<String,CustomSkullData> customSkulls = new HashMap();
+	public final Map<EaglercraftUUID,SkinPacketVersionCache> playerSkins = new HashMap<>();
+	public final Map<String,CustomSkullData> customSkulls = new HashMap<>();
 
 	private long lastFlush = 0l;
 
@@ -71,19 +71,9 @@ public class IntegratedSkinService {
 		this.skullsDirectory = skullsDirectory;
 	}
 
-	public void processPacket(byte[] packetData, EntityPlayerMP sender) {
+	public void processLoginPacket(byte[] packetData, EntityPlayerMP sender, int protocolVers) {
 		try {
-			IntegratedSkinPackets.processPacket(packetData, sender, this);
-		} catch (IOException e) {
-			logger.error("Invalid skin request packet recieved from player {}!", sender.getName());
-			logger.error(e);
-			sender.playerNetServerHandler.kickPlayerFromServer("Invalid skin request packet recieved!");
-		}
-	}
-
-	public void processLoginPacket(byte[] packetData, EntityPlayerMP sender) {
-		try {
-			IntegratedSkinPackets.registerEaglerPlayer(sender.getUniqueID(), packetData, this);
+			IntegratedSkinPackets.registerEaglerPlayer(sender.getUniqueID(), packetData, this, protocolVers);
 		} catch (IOException e) {
 			logger.error("Invalid skin data packet recieved from player {}!", sender.getName());
 			logger.error(e);
@@ -92,36 +82,39 @@ public class IntegratedSkinService {
 	}
 
 	public void processPacketGetOtherSkin(EaglercraftUUID searchUUID, EntityPlayerMP sender) {
-		byte[] playerSkin = playerSkins.get(searchUUID);
-		if(playerSkin == null) {
-			playerSkin = IntegratedSkinPackets.makePresetResponse(searchUUID);
+		SkinPacketVersionCache playerSkin = playerSkins.get(searchUUID);
+		GameMessagePacket toSend = null;
+		if(playerSkin != null) {
+			toSend = playerSkin.get(sender.playerNetServerHandler.getEaglerMessageProtocol());
+		}else {
+			toSend = IntegratedSkinPackets.makePresetResponse(searchUUID);
 		}
-		sender.playerNetServerHandler.sendPacket(new S3FPacketCustomPayload(CHANNEL, new PacketBuffer(Unpooled.buffer(playerSkin, playerSkin.length).writerIndex(playerSkin.length))));
+		sender.playerNetServerHandler.sendEaglerMessage(toSend);
 	}
 
 	public void processPacketGetOtherSkin(EaglercraftUUID searchUUID, String urlStr, EntityPlayerMP sender) {
 		urlStr = urlStr.toLowerCase();
-		byte[] playerSkin;
+		GameMessagePacket playerSkin;
 		if(!urlStr.startsWith("eagler://")) {
-			playerSkin = IntegratedSkinPackets.makePresetResponse(searchUUID, 0);
+			playerSkin = new SPacketOtherSkinPresetEAG(searchUUID.msb, searchUUID.lsb, 0);
 		}else {
 			urlStr = urlStr.substring(9);
 			if(urlStr.contains(VFile2.pathSeperator)) {
-				playerSkin = IntegratedSkinPackets.makePresetResponse(searchUUID, 0);
+				playerSkin = new SPacketOtherSkinPresetEAG(searchUUID.msb, searchUUID.lsb, 0);
 			}else {
 				CustomSkullData sk = customSkulls.get(urlStr);
 				if(sk == null) {
 					customSkulls.put(urlStr, sk = loadCustomSkull(urlStr));
 				}else {
-					sk.lastHit = System.currentTimeMillis();
+					sk.lastHit = EagRuntime.steadyTimeMillis();
 				}
-				playerSkin = IntegratedSkinPackets.makeCustomResponse(searchUUID, 0, sk.getFullSkin());
+				playerSkin = sk.getSkinPacket(searchUUID, sender.playerNetServerHandler.getEaglerMessageProtocol());
 			}
 		}
-		sender.playerNetServerHandler.sendPacket(new S3FPacketCustomPayload(CHANNEL, new PacketBuffer(Unpooled.buffer(playerSkin, playerSkin.length).writerIndex(playerSkin.length))));
+		sender.playerNetServerHandler.sendEaglerMessage(playerSkin);
 	}
 
-	public void processPacketPlayerSkin(EaglercraftUUID clientUUID, byte[] generatedPacket, int skinModel) {
+	public void processPacketPlayerSkin(EaglercraftUUID clientUUID, SkinPacketVersionCache generatedPacket, int skinModel) {
 		playerSkins.put(clientUUID, generatedPacket);
 	}
 
@@ -188,12 +181,12 @@ public class IntegratedSkinService {
 		}
 		String str = "skin-" + new String(hashText) + ".bmp";
 		customSkulls.put(str, new CustomSkullData(str, skullData));
-		(new VFile2(skullsDirectory, str)).setAllBytes(skullData);
+		WorldsDB.newVFile(skullsDirectory, str).setAllBytes(skullData);
 		return str;
 	}
 
 	private CustomSkullData loadCustomSkull(String urlStr) {
-		byte[] data = (new VFile2(skullsDirectory, urlStr)).getAllBytes();
+		byte[] data = WorldsDB.newVFile(skullsDirectory, urlStr).getAllBytes();
 		if(data == null) {
 			return new CustomSkullData(urlStr, skullNotFoundTexture);
 		}else {
@@ -202,7 +195,7 @@ public class IntegratedSkinService {
 	}
 
 	public void flushCache() {
-		long cur = System.currentTimeMillis();
+		long cur = EagRuntime.steadyTimeMillis();
 		if(cur - lastFlush > 300000l) {
 			lastFlush = cur;
 			Iterator<CustomSkullData> customSkullsItr = customSkulls.values().iterator();
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/server/socket/IntegratedServerPlayerNetworkManager.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/server/socket/IntegratedServerPlayerNetworkManager.java
index 89b949c5..419c69b6 100644
--- a/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/server/socket/IntegratedServerPlayerNetworkManager.java
+++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/server/socket/IntegratedServerPlayerNetworkManager.java
@@ -56,7 +56,7 @@ public class IntegratedServerPlayerNetworkManager {
 
 	private boolean firstPacket = true;
 
-	private List<byte[]> fragmentedPacket = new ArrayList();
+	private List<byte[]> fragmentedPacket = new ArrayList<>();
 
 	public static final int fragmentSize = 0xFF00;
 	public static final int compressionThreshold = 1024;
@@ -124,8 +124,7 @@ public class IntegratedServerPlayerNetworkManager {
 							kickDAO.write(0x00);
 							kickDAO.write(msg.length());
 							for(int j = 0, l = msg.length(); j < l; ++j) {
-								kickDAO.write(0);
-								kickDAO.write(msg.codePointAt(j));
+								kickDAO.writeChar(msg.charAt(j));
 							}
 						}catch(IOException ex) {
 							throw new RuntimeException(ex);
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/server/socket/protocol/ServerV3MessageHandler.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/server/socket/protocol/ServerV3MessageHandler.java
new file mode 100644
index 00000000..cc6cf034
--- /dev/null
+++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/server/socket/protocol/ServerV3MessageHandler.java
@@ -0,0 +1,90 @@
+package net.lax1dude.eaglercraft.v1_8.sp.server.socket.protocol;
+
+import net.lax1dude.eaglercraft.v1_8.EaglercraftUUID;
+import net.lax1dude.eaglercraft.v1_8.socket.protocol.pkt.GameMessageHandler;
+import net.lax1dude.eaglercraft.v1_8.socket.protocol.pkt.client.*;
+import net.lax1dude.eaglercraft.v1_8.sp.server.EaglerMinecraftServer;
+import net.lax1dude.eaglercraft.v1_8.sp.server.voice.IntegratedVoiceService;
+import net.minecraft.network.NetHandlerPlayServer;
+
+/**
+ * Copyright (c) 2024 lax1dude. All Rights Reserved.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ * 
+ */
+public class ServerV3MessageHandler implements GameMessageHandler {
+
+	private final NetHandlerPlayServer netHandler;
+	private final EaglerMinecraftServer server;
+
+	public ServerV3MessageHandler(NetHandlerPlayServer netHandler) {
+		this.netHandler = netHandler;
+		this.server = (EaglerMinecraftServer)netHandler.serverController;
+	}
+
+	public void handleClient(CPacketGetOtherCapeEAG packet) {
+		server.getCapeService().processGetOtherCape(new EaglercraftUUID(packet.uuidMost, packet.uuidLeast), netHandler.playerEntity);
+	}
+
+	public void handleClient(CPacketGetOtherSkinEAG packet) {
+		server.getSkinService().processPacketGetOtherSkin(new EaglercraftUUID(packet.uuidMost, packet.uuidLeast), netHandler.playerEntity);
+	}
+
+	public void handleClient(CPacketGetSkinByURLEAG packet) {
+		server.getSkinService().processPacketGetOtherSkin(new EaglercraftUUID(packet.uuidMost, packet.uuidLeast), packet.url, netHandler.playerEntity);
+	}
+
+	public void handleClient(CPacketInstallSkinSPEAG packet) {
+		server.getSkinService().processPacketInstallNewSkin(packet.customSkin, netHandler.playerEntity);
+	}
+
+	public void handleClient(CPacketVoiceSignalConnectEAG packet) {
+		IntegratedVoiceService voiceSvc = server.getVoiceService();
+		if(voiceSvc != null) {
+			voiceSvc.handleVoiceSignalPacketTypeConnect(netHandler.playerEntity);
+		}
+	}
+
+	public void handleClient(CPacketVoiceSignalDescEAG packet) {
+		IntegratedVoiceService voiceSvc = server.getVoiceService();
+		if(voiceSvc != null) {
+			voiceSvc.handleVoiceSignalPacketTypeDesc(new EaglercraftUUID(packet.uuidMost, packet.uuidLeast), packet.desc, netHandler.playerEntity);
+		}
+	}
+
+	public void handleClient(CPacketVoiceSignalDisconnectV3EAG packet) {
+		IntegratedVoiceService voiceSvc = server.getVoiceService();
+		if(voiceSvc != null) {
+			if(packet.isPeerType) {
+				voiceSvc.handleVoiceSignalPacketTypeDisconnectPeer(new EaglercraftUUID(packet.uuidMost, packet.uuidLeast), netHandler.playerEntity);
+			}else {
+				voiceSvc.handleVoiceSignalPacketTypeDisconnect(netHandler.playerEntity);
+			}
+		}
+	}
+
+	public void handleClient(CPacketVoiceSignalICEEAG packet) {
+		IntegratedVoiceService voiceSvc = server.getVoiceService();
+		if(voiceSvc != null) {
+			voiceSvc.handleVoiceSignalPacketTypeICE(new EaglercraftUUID(packet.uuidMost, packet.uuidLeast), packet.ice, netHandler.playerEntity);
+		}
+	}
+
+	public void handleClient(CPacketVoiceSignalRequestEAG packet) {
+		IntegratedVoiceService voiceSvc = server.getVoiceService();
+		if(voiceSvc != null) {
+			voiceSvc.handleVoiceSignalPacketTypeRequest(new EaglercraftUUID(packet.uuidMost, packet.uuidLeast), netHandler.playerEntity);
+		}
+	}
+
+}
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/server/socket/protocol/ServerV4MessageHandler.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/server/socket/protocol/ServerV4MessageHandler.java
new file mode 100644
index 00000000..a8f993f8
--- /dev/null
+++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/server/socket/protocol/ServerV4MessageHandler.java
@@ -0,0 +1,104 @@
+package net.lax1dude.eaglercraft.v1_8.sp.server.socket.protocol;
+
+import net.lax1dude.eaglercraft.v1_8.EaglercraftUUID;
+import net.lax1dude.eaglercraft.v1_8.socket.protocol.pkt.GameMessageHandler;
+import net.lax1dude.eaglercraft.v1_8.socket.protocol.pkt.client.*;
+import net.lax1dude.eaglercraft.v1_8.socket.protocol.pkt.server.SPacketOtherPlayerClientUUIDV4EAG;
+import net.lax1dude.eaglercraft.v1_8.sp.server.EaglerMinecraftServer;
+import net.lax1dude.eaglercraft.v1_8.sp.server.voice.IntegratedVoiceService;
+import net.minecraft.entity.player.EntityPlayerMP;
+import net.minecraft.network.NetHandlerPlayServer;
+
+/**
+ * Copyright (c) 2024 lax1dude. All Rights Reserved.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ * 
+ */
+public class ServerV4MessageHandler implements GameMessageHandler {
+
+	private final NetHandlerPlayServer netHandler;
+	private final EaglerMinecraftServer server;
+
+	public ServerV4MessageHandler(NetHandlerPlayServer netHandler) {
+		this.netHandler = netHandler;
+		this.server = (EaglerMinecraftServer)netHandler.serverController;
+	}
+
+	public void handleClient(CPacketGetOtherCapeEAG packet) {
+		server.getCapeService().processGetOtherCape(new EaglercraftUUID(packet.uuidMost, packet.uuidLeast), netHandler.playerEntity);
+	}
+
+	public void handleClient(CPacketGetOtherSkinEAG packet) {
+		server.getSkinService().processPacketGetOtherSkin(new EaglercraftUUID(packet.uuidMost, packet.uuidLeast), netHandler.playerEntity);
+	}
+
+	public void handleClient(CPacketGetSkinByURLEAG packet) {
+		server.getSkinService().processPacketGetOtherSkin(new EaglercraftUUID(packet.uuidMost, packet.uuidLeast), packet.url, netHandler.playerEntity);
+	}
+
+	public void handleClient(CPacketInstallSkinSPEAG packet) {
+		server.getSkinService().processPacketInstallNewSkin(packet.customSkin, netHandler.playerEntity);
+	}
+
+	public void handleClient(CPacketVoiceSignalConnectEAG packet) {
+		IntegratedVoiceService voiceSvc = server.getVoiceService();
+		if(voiceSvc != null) {
+			voiceSvc.handleVoiceSignalPacketTypeConnect(netHandler.playerEntity);
+		}
+	}
+
+	public void handleClient(CPacketVoiceSignalDescEAG packet) {
+		IntegratedVoiceService voiceSvc = server.getVoiceService();
+		if(voiceSvc != null) {
+			voiceSvc.handleVoiceSignalPacketTypeDesc(new EaglercraftUUID(packet.uuidMost, packet.uuidLeast), packet.desc, netHandler.playerEntity);
+		}
+	}
+
+	public void handleClient(CPacketVoiceSignalDisconnectV4EAG packet) {
+		IntegratedVoiceService voiceSvc = server.getVoiceService();
+		if(voiceSvc != null) {
+			voiceSvc.handleVoiceSignalPacketTypeDisconnect(netHandler.playerEntity);
+		}
+	}
+
+	public void handleClient(CPacketVoiceSignalDisconnectPeerV4EAG packet) {
+		IntegratedVoiceService voiceSvc = server.getVoiceService();
+		if(voiceSvc != null) {
+			voiceSvc.handleVoiceSignalPacketTypeDisconnectPeer(new EaglercraftUUID(packet.uuidMost, packet.uuidLeast), netHandler.playerEntity);
+		}
+	}
+
+	public void handleClient(CPacketVoiceSignalICEEAG packet) {
+		IntegratedVoiceService voiceSvc = server.getVoiceService();
+		if(voiceSvc != null) {
+			voiceSvc.handleVoiceSignalPacketTypeICE(new EaglercraftUUID(packet.uuidMost, packet.uuidLeast), packet.ice, netHandler.playerEntity);
+		}
+	}
+
+	public void handleClient(CPacketVoiceSignalRequestEAG packet) {
+		IntegratedVoiceService voiceSvc = server.getVoiceService();
+		if(voiceSvc != null) {
+			voiceSvc.handleVoiceSignalPacketTypeRequest(new EaglercraftUUID(packet.uuidMost, packet.uuidLeast), netHandler.playerEntity);
+		}
+	}
+
+	public void handleClient(CPacketGetOtherClientUUIDV4EAG packet) {
+		EntityPlayerMP player = server.getConfigurationManager().getPlayerByUUID(new EaglercraftUUID(packet.playerUUIDMost, packet.playerUUIDLeast));
+		if(player != null && player.clientBrandUUID != null) {
+			netHandler.sendEaglerMessage(new SPacketOtherPlayerClientUUIDV4EAG(packet.requestId, player.clientBrandUUID.msb, player.clientBrandUUID.lsb));
+		}else {
+			netHandler.sendEaglerMessage(new SPacketOtherPlayerClientUUIDV4EAG(packet.requestId, 0l, 0l));
+		}
+	}
+
+}
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/server/voice/IntegratedVoiceService.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/server/voice/IntegratedVoiceService.java
index bb20af2b..f6a802ac 100644
--- a/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/server/voice/IntegratedVoiceService.java
+++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/server/voice/IntegratedVoiceService.java
@@ -1,6 +1,7 @@
 package net.lax1dude.eaglercraft.v1_8.sp.server.voice;
 
-import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collection;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Iterator;
@@ -10,11 +11,10 @@ import java.util.Set;
 import net.lax1dude.eaglercraft.v1_8.EaglercraftUUID;
 import net.lax1dude.eaglercraft.v1_8.log4j.LogManager;
 import net.lax1dude.eaglercraft.v1_8.log4j.Logger;
-import net.lax1dude.eaglercraft.v1_8.netty.Unpooled;
+import net.lax1dude.eaglercraft.v1_8.socket.protocol.pkt.GameMessagePacket;
+import net.lax1dude.eaglercraft.v1_8.socket.protocol.pkt.server.*;
 import net.lax1dude.eaglercraft.v1_8.voice.ExpiringSet;
 import net.minecraft.entity.player.EntityPlayerMP;
-import net.minecraft.network.PacketBuffer;
-import net.minecraft.network.play.server.S3FPacketCustomPayload;
 
 /**
  * Copyright (c) 2024 lax1dude. All Rights Reserved.
@@ -35,20 +35,18 @@ public class IntegratedVoiceService {
 
 	public static final Logger logger = LogManager.getLogger("IntegratedVoiceService");
 
-	public static final String CHANNEL = "EAG|Voice-1.8";
-
-	private byte[] iceServersPacket;
+	private GameMessagePacket iceServersPacket;
 
 	private final Map<EaglercraftUUID, EntityPlayerMP> voicePlayers = new HashMap<>();
 	private final Map<EaglercraftUUID, ExpiringSet<EaglercraftUUID>> voiceRequests = new HashMap<>();
 	private final Set<VoicePair> voicePairs = new HashSet<>();
 
 	public IntegratedVoiceService(String[] iceServers) {
-		iceServersPacket = IntegratedVoiceSignalPackets.makeVoiceSignalPacketAllowed(true, iceServers);
+		iceServersPacket = new SPacketVoiceSignalAllowedEAG(true, iceServers);
 	}
 
 	public void changeICEServers(String[] iceServers) {
-		iceServersPacket = IntegratedVoiceSignalPackets.makeVoiceSignalPacketAllowed(true, iceServers);
+		iceServersPacket = new SPacketVoiceSignalAllowedEAG(true, iceServers);
 	}
 
 	private static class VoicePair {
@@ -85,25 +83,14 @@ public class IntegratedVoiceService {
 	}
 
 	public void handlePlayerLoggedIn(EntityPlayerMP player) {
-		player.playerNetServerHandler.sendPacket(new S3FPacketCustomPayload(CHANNEL, new PacketBuffer(
-				Unpooled.buffer(iceServersPacket, iceServersPacket.length).writerIndex(iceServersPacket.length))));
+		player.playerNetServerHandler.sendEaglerMessage(iceServersPacket);
 	}
 
 	public void handlePlayerLoggedOut(EntityPlayerMP player) {
 		removeUser(player.getUniqueID());
 	}
 
-	public void processPacket(PacketBuffer packetData, EntityPlayerMP sender) {
-		try {
-			IntegratedVoiceSignalPackets.processPacket(packetData, sender, this);
-		} catch (IOException e) {
-			logger.error("Invalid voice signal packet recieved from player {}!", sender.getName());
-			logger.error(e);
-			sender.playerNetServerHandler.kickPlayerFromServer("Invalid voice signal packet recieved!");
-		}
-	}
-
-	void handleVoiceSignalPacketTypeRequest(EaglercraftUUID player, EntityPlayerMP sender) {
+	public void handleVoiceSignalPacketTypeRequest(EaglercraftUUID player, EntityPlayerMP sender) {
 		EaglercraftUUID senderUUID = sender.getUniqueID();
 		if (senderUUID.equals(player))
 			return; // prevent duplicates
@@ -134,14 +121,24 @@ public class IntegratedVoiceService {
 				voiceRequests.remove(senderUUID);
 			// send each other add data
 			voicePairs.add(newPair);
-			targetPlayerCon.playerNetServerHandler.sendPacket(new S3FPacketCustomPayload(CHANNEL,
-					IntegratedVoiceSignalPackets.makeVoiceSignalPacketConnect(senderUUID, false)));
-			sender.playerNetServerHandler.sendPacket(new S3FPacketCustomPayload(CHANNEL,
-					IntegratedVoiceSignalPackets.makeVoiceSignalPacketConnect(player, true)));
+			if(targetPlayerCon.playerNetServerHandler.getEaglerMessageProtocol().ver <= 3) {
+				targetPlayerCon.playerNetServerHandler
+						.sendEaglerMessage(new SPacketVoiceSignalConnectV3EAG(senderUUID.msb, senderUUID.lsb, false, false));
+			}else {
+				targetPlayerCon.playerNetServerHandler
+						.sendEaglerMessage(new SPacketVoiceSignalConnectV4EAG(senderUUID.msb, senderUUID.lsb, false));
+			}
+			if(sender.playerNetServerHandler.getEaglerMessageProtocol().ver <= 3) {
+				sender.playerNetServerHandler
+						.sendEaglerMessage(new SPacketVoiceSignalConnectV3EAG(player.msb, player.lsb, false, true));
+			}else {
+				sender.playerNetServerHandler
+						.sendEaglerMessage(new SPacketVoiceSignalConnectV4EAG(player.msb, player.lsb, true));
+			}
 		}
 	}
 
-	void handleVoiceSignalPacketTypeConnect(EntityPlayerMP sender) {
+	public void handleVoiceSignalPacketTypeConnect(EntityPlayerMP sender) {
 		if (voicePlayers.containsKey(sender.getUniqueID())) {
 			return;
 		}
@@ -150,63 +147,60 @@ public class IntegratedVoiceService {
 		if (hasNoOtherPlayers) {
 			return;
 		}
-		byte[] packetToBroadcast = IntegratedVoiceSignalPackets.makeVoiceSignalPacketGlobal(voicePlayers.values());
+		Collection<SPacketVoiceSignalGlobalEAG.UserData> userDatas = new ArrayList<>(voicePlayers.size());
+		for(EntityPlayerMP player : voicePlayers.values()) {
+			EaglercraftUUID uuid = player.getUniqueID();
+			userDatas.add(new SPacketVoiceSignalGlobalEAG.UserData(uuid.msb, uuid.lsb, player.getName()));
+		}
+		SPacketVoiceSignalGlobalEAG packetToBroadcast = new SPacketVoiceSignalGlobalEAG(userDatas);
 		for (EntityPlayerMP userCon : voicePlayers.values()) {
-			userCon.playerNetServerHandler.sendPacket(new S3FPacketCustomPayload(CHANNEL, new PacketBuffer(Unpooled
-					.buffer(packetToBroadcast, packetToBroadcast.length).writerIndex(packetToBroadcast.length))));
+			userCon.playerNetServerHandler.sendEaglerMessage(packetToBroadcast);
 		}
 	}
 
-	void handleVoiceSignalPacketTypeICE(EaglercraftUUID player, String str, EntityPlayerMP sender) {
-		VoicePair pair = new VoicePair(player, sender.getUniqueID());
+	public void handleVoiceSignalPacketTypeICE(EaglercraftUUID player, byte[] str, EntityPlayerMP sender) {
+		EaglercraftUUID uuid = sender.getUniqueID();
+		VoicePair pair = new VoicePair(player, uuid);
 		EntityPlayerMP pass = voicePairs.contains(pair) ? voicePlayers.get(player) : null;
 		if (pass != null) {
-			pass.playerNetServerHandler.sendPacket(new S3FPacketCustomPayload(CHANNEL,
-					IntegratedVoiceSignalPackets.makeVoiceSignalPacketICE(sender.getUniqueID(), str)));
+			pass.playerNetServerHandler.sendEaglerMessage(new SPacketVoiceSignalICEEAG(uuid.msb, uuid.lsb, str));
 		}
 	}
 
-	void handleVoiceSignalPacketTypeDesc(EaglercraftUUID player, String str, EntityPlayerMP sender) {
-		VoicePair pair = new VoicePair(player, sender.getUniqueID());
+	public void handleVoiceSignalPacketTypeDesc(EaglercraftUUID player, byte[] str, EntityPlayerMP sender) {
+		EaglercraftUUID uuid = sender.getUniqueID();
+		VoicePair pair = new VoicePair(player, uuid);
 		EntityPlayerMP pass = voicePairs.contains(pair) ? voicePlayers.get(player) : null;
 		if (pass != null) {
-			pass.playerNetServerHandler.sendPacket(new S3FPacketCustomPayload(CHANNEL,
-					IntegratedVoiceSignalPackets.makeVoiceSignalPacketDesc(sender.getUniqueID(), str)));
+			pass.playerNetServerHandler.sendEaglerMessage(new SPacketVoiceSignalDescEAG(uuid.msb, uuid.lsb, str));
 		}
 	}
 
-	void handleVoiceSignalPacketTypeDisconnect(EaglercraftUUID player, EntityPlayerMP sender) {
-		if (player != null) {
-			if (!voicePlayers.containsKey(player)) {
-				return;
+	public void handleVoiceSignalPacketTypeDisconnect(EntityPlayerMP sender) {
+		removeUser(sender.getUniqueID());
+	}
+
+	public void handleVoiceSignalPacketTypeDisconnectPeer(EaglercraftUUID player, EntityPlayerMP sender) {
+		if (!voicePlayers.containsKey(player)) {
+			return;
+		}
+		Iterator<VoicePair> pairsItr = voicePairs.iterator();
+		while (pairsItr.hasNext()) {
+			VoicePair voicePair = pairsItr.next();
+			EaglercraftUUID target = null;
+			if (voicePair.uuid1.equals(player)) {
+				target = voicePair.uuid2;
+			} else if (voicePair.uuid2.equals(player)) {
+				target = voicePair.uuid1;
 			}
-			byte[] userDisconnectPacket = null;
-			Iterator<VoicePair> pairsItr = voicePairs.iterator();
-			while (pairsItr.hasNext()) {
-				VoicePair voicePair = pairsItr.next();
-				EaglercraftUUID target = null;
-				if (voicePair.uuid1.equals(player)) {
-					target = voicePair.uuid2;
-				} else if (voicePair.uuid2.equals(player)) {
-					target = voicePair.uuid1;
-				}
-				if (target != null) {
-					pairsItr.remove();
-					EntityPlayerMP conn = voicePlayers.get(target);
-					if (conn != null) {
-						if (userDisconnectPacket == null) {
-							userDisconnectPacket = IntegratedVoiceSignalPackets.makeVoiceSignalPacketDisconnect(player);
-						}
-						conn.playerNetServerHandler.sendPacket(new S3FPacketCustomPayload(CHANNEL,
-								new PacketBuffer(Unpooled.buffer(userDisconnectPacket, userDisconnectPacket.length)
-										.writerIndex(userDisconnectPacket.length))));
-					}
-					sender.playerNetServerHandler.sendPacket(new S3FPacketCustomPayload(CHANNEL,
-							IntegratedVoiceSignalPackets.makeVoiceSignalPacketDisconnectPB(target)));
+			if (target != null) {
+				pairsItr.remove();
+				EntityPlayerMP conn = voicePlayers.get(target);
+				if (conn != null) {
+					conn.playerNetServerHandler.sendEaglerMessage(new SPacketVoiceSignalDisconnectPeerEAG(player.msb, player.lsb));
 				}
+				sender.playerNetServerHandler.sendEaglerMessage(new SPacketVoiceSignalDisconnectPeerEAG(target.msb, target.lsb));
 			}
-		} else {
-			removeUser(sender.getUniqueID());
 		}
 	}
 
@@ -216,16 +210,16 @@ public class IntegratedVoiceService {
 		}
 		voiceRequests.remove(user);
 		if (voicePlayers.size() > 0) {
-			byte[] voicePlayersPkt = IntegratedVoiceSignalPackets.makeVoiceSignalPacketGlobal(voicePlayers.values());
+			Collection<SPacketVoiceSignalGlobalEAG.UserData> userDatas = new ArrayList<>(voicePlayers.size());
+			for(EntityPlayerMP player : voicePlayers.values()) {
+				EaglercraftUUID uuid = player.getUniqueID();
+				userDatas.add(new SPacketVoiceSignalGlobalEAG.UserData(uuid.msb, uuid.lsb, player.getName()));
+			}
+			SPacketVoiceSignalGlobalEAG packetToBroadcast = new SPacketVoiceSignalGlobalEAG(userDatas);
 			for (EntityPlayerMP userCon : voicePlayers.values()) {
-				if (!user.equals(userCon.getUniqueID())) {
-					userCon.playerNetServerHandler.sendPacket(new S3FPacketCustomPayload(CHANNEL,
-							new PacketBuffer(Unpooled.buffer(voicePlayersPkt, voicePlayersPkt.length)
-									.writerIndex(voicePlayersPkt.length))));
-				}
+				userCon.playerNetServerHandler.sendEaglerMessage(packetToBroadcast);
 			}
 		}
-		byte[] userDisconnectPacket = null;
 		Iterator<VoicePair> pairsItr = voicePairs.iterator();
 		while (pairsItr.hasNext()) {
 			VoicePair voicePair = pairsItr.next();
@@ -240,12 +234,7 @@ public class IntegratedVoiceService {
 				if (voicePlayers.size() > 0) {
 					EntityPlayerMP conn = voicePlayers.get(target);
 					if (conn != null) {
-						if (userDisconnectPacket == null) {
-							userDisconnectPacket = IntegratedVoiceSignalPackets.makeVoiceSignalPacketDisconnect(user);
-						}
-						conn.playerNetServerHandler.sendPacket(new S3FPacketCustomPayload(CHANNEL,
-								new PacketBuffer(Unpooled.buffer(userDisconnectPacket, userDisconnectPacket.length)
-										.writerIndex(userDisconnectPacket.length))));
+						conn.playerNetServerHandler.sendEaglerMessage(new SPacketVoiceSignalDisconnectPeerEAG(user.msb, user.lsb));
 					}
 				}
 			}
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/server/voice/IntegratedVoiceSignalPackets.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/server/voice/IntegratedVoiceSignalPackets.java
deleted file mode 100644
index 017916b5..00000000
--- a/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/server/voice/IntegratedVoiceSignalPackets.java
+++ /dev/null
@@ -1,198 +0,0 @@
-package net.lax1dude.eaglercraft.v1_8.sp.server.voice;
-
-import java.io.IOException;
-import java.nio.charset.StandardCharsets;
-import java.util.Collection;
-
-import net.lax1dude.eaglercraft.v1_8.EaglercraftUUID;
-import net.lax1dude.eaglercraft.v1_8.netty.ByteBuf;
-import net.lax1dude.eaglercraft.v1_8.netty.Unpooled;
-import net.minecraft.entity.player.EntityPlayerMP;
-import net.minecraft.network.PacketBuffer;
-
-/**
- * Copyright (c) 2024 lax1dude. All Rights Reserved.
- * 
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
- * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- * 
- */
-public class IntegratedVoiceSignalPackets {
-
-	static final int VOICE_SIGNAL_ALLOWED = 0;
-	static final int VOICE_SIGNAL_REQUEST = 0;
-	static final int VOICE_SIGNAL_CONNECT = 1;
-	static final int VOICE_SIGNAL_DISCONNECT = 2;
-	static final int VOICE_SIGNAL_ICE = 3;
-	static final int VOICE_SIGNAL_DESC = 4;
-	static final int VOICE_SIGNAL_GLOBAL = 5;
-
-	public static void processPacket(PacketBuffer buffer, EntityPlayerMP sender, IntegratedVoiceService voiceService) throws IOException {
-		int packetId = -1;
-		if(buffer.readableBytes() == 0) {
-			throw new IOException("Zero-length packet recieved");
-		}
-		try {
-			packetId = buffer.readUnsignedByte();
-			switch(packetId) {
-				case VOICE_SIGNAL_REQUEST: {
-					voiceService.handleVoiceSignalPacketTypeRequest(buffer.readUuid(), sender);
-					break;
-				}
-				case VOICE_SIGNAL_CONNECT: {
-					voiceService.handleVoiceSignalPacketTypeConnect(sender);
-					break;
-				}
-				case VOICE_SIGNAL_ICE: {
-					voiceService.handleVoiceSignalPacketTypeICE(buffer.readUuid(), buffer.readStringFromBuffer(32767), sender);
-					break;
-				}
-				case VOICE_SIGNAL_DESC: {
-					voiceService.handleVoiceSignalPacketTypeDesc(buffer.readUuid(), buffer.readStringFromBuffer(32767), sender);
-					break;
-				}
-				case VOICE_SIGNAL_DISCONNECT: {
-					voiceService.handleVoiceSignalPacketTypeDisconnect(buffer.readableBytes() > 0 ? buffer.readUuid() : null, sender);
-					break;
-				}
-				default: {
-					throw new IOException("Unknown packet type " + packetId);
-				}
-			}
-			if(buffer.readableBytes() > 0) {
-				throw new IOException("Voice packet is too long!");
-			}
-		}catch(IOException ex) {
-			throw ex;
-		}catch(Throwable t) {
-			throw new IOException("Unhandled exception handling voice packet type " + packetId, t);
-		}
-	}
-
-	static byte[] makeVoiceSignalPacketAllowed(boolean allowed, String[] iceServers) {
-		if (iceServers == null) {
-			byte[] ret = new byte[2];
-			ByteBuf wrappedBuffer = Unpooled.buffer(ret, ret.length);
-			wrappedBuffer.writeByte(VOICE_SIGNAL_ALLOWED);
-			wrappedBuffer.writeBoolean(allowed);
-			return ret;
-		}
-		byte[][] iceServersBytes = new byte[iceServers.length][];
-		int totalLen = 2 + PacketBuffer.getVarIntSize(iceServers.length);
-		for(int i = 0; i < iceServers.length; ++i) {
-			byte[] b = iceServersBytes[i] = iceServers[i].getBytes(StandardCharsets.UTF_8);
-			totalLen += PacketBuffer.getVarIntSize(b.length) + b.length;
-		}
-		byte[] ret = new byte[totalLen];
-		PacketBuffer wrappedBuffer = new PacketBuffer(Unpooled.buffer(ret, ret.length));
-		wrappedBuffer.writeByte(VOICE_SIGNAL_ALLOWED);
-		wrappedBuffer.writeBoolean(allowed);
-		wrappedBuffer.writeVarIntToBuffer(iceServersBytes.length);
-		for(int i = 0; i < iceServersBytes.length; ++i) {
-			byte[] b = iceServersBytes[i];
-			wrappedBuffer.writeVarIntToBuffer(b.length);
-			wrappedBuffer.writeBytes(b);
-		}
-		return ret;
-	}
-
-	static byte[] makeVoiceSignalPacketGlobal(Collection<EntityPlayerMP> users) {
-		int cnt = users.size();
-		byte[][] displayNames = new byte[cnt][];
-		int i = 0;
-		for(EntityPlayerMP user : users) {
-			String name = user.getName();
-			if(name.length() > 16) name = name.substring(0, 16);
-			displayNames[i++] = name.getBytes(StandardCharsets.UTF_8);
-		}
-		int totalLength = 1 + PacketBuffer.getVarIntSize(cnt) + (cnt << 4);
-		for(i = 0; i < cnt; ++i) {
-			totalLength += PacketBuffer.getVarIntSize(displayNames[i].length) + displayNames[i].length;
-		}
-		byte[] ret = new byte[totalLength];
-		PacketBuffer wrappedBuffer = new PacketBuffer(Unpooled.buffer(ret, ret.length));
-		wrappedBuffer.writeByte(VOICE_SIGNAL_GLOBAL);
-		wrappedBuffer.writeVarIntToBuffer(cnt);
-		for(EntityPlayerMP user : users) {
-			wrappedBuffer.writeUuid(user.getUniqueID());
-		}
-		for(i = 0; i < cnt; ++i) {
-			wrappedBuffer.writeVarIntToBuffer(displayNames[i].length);
-			wrappedBuffer.writeBytes(displayNames[i]);
-		}
-		return ret;
-	}
-
-	static PacketBuffer makeVoiceSignalPacketConnect(EaglercraftUUID player, boolean offer) {
-		byte[] ret = new byte[18];
-		PacketBuffer wrappedBuffer = new PacketBuffer(Unpooled.buffer(ret, ret.length));
-		wrappedBuffer.writeByte(VOICE_SIGNAL_CONNECT);
-		wrappedBuffer.writeUuid(player);
-		wrappedBuffer.writeBoolean(offer);
-		return wrappedBuffer;
-	}
-
-	static byte[] makeVoiceSignalPacketConnectAnnounce(EaglercraftUUID player) {
-		byte[] ret = new byte[17];
-		PacketBuffer wrappedBuffer = new PacketBuffer(Unpooled.buffer(ret, ret.length));
-		wrappedBuffer.writeByte(VOICE_SIGNAL_CONNECT);
-		wrappedBuffer.writeUuid(player);
-		return ret;
-	}
-
-	static byte[] makeVoiceSignalPacketDisconnect(EaglercraftUUID player) {
-		if(player == null) {
-			return new byte[] { (byte)VOICE_SIGNAL_DISCONNECT };
-		}
-		byte[] ret = new byte[17];
-		PacketBuffer wrappedBuffer = new PacketBuffer(Unpooled.buffer(ret, ret.length));
-		wrappedBuffer.writeByte(VOICE_SIGNAL_DISCONNECT);
-		wrappedBuffer.writeUuid(player);
-		return ret;
-	}
-
-	static PacketBuffer makeVoiceSignalPacketDisconnectPB(EaglercraftUUID player) {
-		if(player == null) {
-			byte[] ret = new byte[1];
-			PacketBuffer wrappedBuffer = new PacketBuffer(Unpooled.buffer(ret, ret.length));
-			wrappedBuffer.writeByte(VOICE_SIGNAL_DISCONNECT);
-			return wrappedBuffer;
-		}
-		byte[] ret = new byte[17];
-		PacketBuffer wrappedBuffer = new PacketBuffer(Unpooled.buffer(ret, ret.length));
-		wrappedBuffer.writeByte(VOICE_SIGNAL_DISCONNECT);
-		wrappedBuffer.writeUuid(player);
-		return wrappedBuffer;
-	}
-
-	static PacketBuffer makeVoiceSignalPacketICE(EaglercraftUUID player, String str) {
-		byte[] strBytes = str.getBytes(StandardCharsets.UTF_8);
-		byte[] ret = new byte[17 + PacketBuffer.getVarIntSize(strBytes.length) + strBytes.length];
-		PacketBuffer wrappedBuffer = new PacketBuffer(Unpooled.buffer(ret, ret.length));
-		wrappedBuffer.writeByte(VOICE_SIGNAL_ICE);
-		wrappedBuffer.writeUuid(player);
-		wrappedBuffer.writeVarIntToBuffer(strBytes.length);
-		wrappedBuffer.writeBytes(strBytes);
-		return wrappedBuffer;
-	}
-
-	static PacketBuffer makeVoiceSignalPacketDesc(EaglercraftUUID player, String str) {
-		byte[] strBytes = str.getBytes(StandardCharsets.UTF_8);
-		byte[] ret = new byte[17 + PacketBuffer.getVarIntSize(strBytes.length) + strBytes.length];
-		PacketBuffer wrappedBuffer = new PacketBuffer(Unpooled.buffer(ret, ret.length));
-		wrappedBuffer.writeByte(VOICE_SIGNAL_DESC);
-		wrappedBuffer.writeUuid(player);
-		wrappedBuffer.writeVarIntToBuffer(strBytes.length);
-		wrappedBuffer.writeBytes(strBytes);
-		return wrappedBuffer;
-	}
-
-}
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/socket/NetHandlerSingleplayerLogin.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/socket/NetHandlerSingleplayerLogin.java
index 8bcc2f4f..5736b45c 100644
--- a/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/socket/NetHandlerSingleplayerLogin.java
+++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/socket/NetHandlerSingleplayerLogin.java
@@ -1,7 +1,12 @@
 package net.lax1dude.eaglercraft.v1_8.sp.socket;
 
+import net.lax1dude.eaglercraft.v1_8.log4j.LogManager;
+import net.lax1dude.eaglercraft.v1_8.log4j.Logger;
 import net.lax1dude.eaglercraft.v1_8.netty.Unpooled;
 import net.lax1dude.eaglercraft.v1_8.socket.EaglercraftNetworkManager;
+import net.lax1dude.eaglercraft.v1_8.socket.protocol.GamePluginMessageConstants;
+import net.lax1dude.eaglercraft.v1_8.socket.protocol.GamePluginMessageProtocol;
+import net.lax1dude.eaglercraft.v1_8.socket.protocol.client.GameProtocolMessageController;
 import net.lax1dude.eaglercraft.v1_8.update.UpdateService;
 import net.minecraft.client.Minecraft;
 import net.minecraft.client.gui.GuiDisconnected;
@@ -15,6 +20,7 @@ import net.minecraft.network.login.server.S01PacketEncryptionRequest;
 import net.minecraft.network.login.server.S02PacketLoginSuccess;
 import net.minecraft.network.login.server.S03PacketEnableCompression;
 import net.minecraft.network.play.client.C17PacketCustomPayload;
+import net.minecraft.util.ChatComponentText;
 import net.minecraft.util.IChatComponent;
 
 /**
@@ -38,6 +44,8 @@ public class NetHandlerSingleplayerLogin implements INetHandlerLoginClient {
 	private final GuiScreen previousGuiScreen;
 	private final EaglercraftNetworkManager networkManager;
 
+	private static final Logger logger = LogManager.getLogger("NetHandlerSingleplayerLogin");
+
 	public NetHandlerSingleplayerLogin(EaglercraftNetworkManager parNetworkManager, Minecraft mcIn, GuiScreen parGuiScreen) {
 		this.networkManager = parNetworkManager;
 		this.mc = mcIn;
@@ -57,7 +65,19 @@ public class NetHandlerSingleplayerLogin implements INetHandlerLoginClient {
 	@Override
 	public void handleLoginSuccess(S02PacketLoginSuccess var1) {
 		this.networkManager.setConnectionState(EnumConnectionState.PLAY);
-		this.networkManager.setNetHandler(new NetHandlerPlayClient(this.mc, this.previousGuiScreen, this.networkManager, var1.getProfile()));
+		int p = var1.getSelectedProtocol();
+		GamePluginMessageProtocol mp = GamePluginMessageProtocol.getByVersion(p);
+		if(mp == null) {
+			this.networkManager.closeChannel(new ChatComponentText("Unknown protocol selected: " + p));
+			return;
+		}
+		logger.info("Server is using protocol: {}", p);
+		NetHandlerPlayClient netHandler = new NetHandlerPlayClient(this.mc, this.previousGuiScreen, this.networkManager, var1.getProfile());
+		netHandler.setEaglerMessageController(
+				new GameProtocolMessageController(mp, GamePluginMessageConstants.CLIENT_TO_SERVER,
+						GameProtocolMessageController.createClientHandler(p, netHandler),
+						(ch, msg) -> netHandler.addToSendQueue(new C17PacketCustomPayload(ch, msg))));
+		this.networkManager.setNetHandler(netHandler);
 		byte[] b = UpdateService.getClientSignatureData();
 		if(b != null) {
 			this.networkManager.sendPacket(new C17PacketCustomPayload("EAG|MyUpdCert-1.8", new PacketBuffer(Unpooled.buffer(b, b.length).writerIndex(b.length))));
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/touch_gui/EnumTouchControl.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/touch_gui/EnumTouchControl.java
new file mode 100644
index 00000000..f86a9c45
--- /dev/null
+++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/touch_gui/EnumTouchControl.java
@@ -0,0 +1,579 @@
+package net.lax1dude.eaglercraft.v1_8.touch_gui;
+
+import net.lax1dude.eaglercraft.v1_8.Touch;
+import net.lax1dude.eaglercraft.v1_8.minecraft.EnumInputEvent;
+import net.minecraft.client.Minecraft;
+import net.minecraft.client.entity.EntityPlayerSP;
+import net.minecraft.client.gui.GuiChat;
+import net.minecraft.client.gui.GuiMainMenu;
+import net.minecraft.client.gui.GuiScreen;
+import net.minecraft.client.gui.ScaledResolution;
+import net.minecraft.client.settings.GameSettings;
+
+/**
+ * Copyright (c) 2024 lax1dude, ayunami2000. All Rights Reserved.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ * 
+ */
+public enum EnumTouchControl {
+	
+	DPAD_UP(EnumTouchControlPos.BOTTOM_LEFT, 60, 109, 44, null, (enumIn, x, y, pressed, mc, res) -> {
+		mc.getTextureManager().bindTexture(TouchOverlayRenderer.spriteSheet);
+		int[] pos = enumIn.getLocation(res, TouchOverlayRenderer._fuck);
+		TouchOverlayRenderer.drawTexturedModalRect(pos[0], pos[1], 56, 0, 22, 22, 2);
+	}),
+	
+	
+	DPAD_LEFT(EnumTouchControlPos.BOTTOM_LEFT, 11, 60, 44, null, (enumIn, x, y, pressed, mc, res) -> {
+		mc.getTextureManager().bindTexture(TouchOverlayRenderer.spriteSheet);
+		int[] pos = enumIn.getLocation(res, TouchOverlayRenderer._fuck);
+		TouchOverlayRenderer.drawTexturedModalRect(pos[0], pos[1], 56, 22, 22, 22, 2);
+	}),
+	
+	
+	DPAD_RIGHT(EnumTouchControlPos.BOTTOM_LEFT, 109, 60, 44, null, (enumIn, x, y, pressed, mc, res) -> {
+		mc.getTextureManager().bindTexture(TouchOverlayRenderer.spriteSheet);
+		int[] pos = enumIn.getLocation(res, TouchOverlayRenderer._fuck);
+		TouchOverlayRenderer.drawTexturedModalRect(pos[0], pos[1], 56, 66, 22, 22, 2);
+	}),
+	
+	
+	DPAD_DOWN(EnumTouchControlPos.BOTTOM_LEFT, 60, 11, 44, null, (enumIn, x, y, pressed, mc, res) -> {
+		mc.getTextureManager().bindTexture(TouchOverlayRenderer.spriteSheet);
+		int[] pos = enumIn.getLocation(res, TouchOverlayRenderer._fuck);
+		TouchOverlayRenderer.drawTexturedModalRect(pos[0], pos[1], 56, 44, 22, 22, 2);
+	}),
+	
+	
+	DPAD_UP_LEFT(EnumTouchControlPos.BOTTOM_LEFT, 16, 112, 36, null, (enumIn, x, y, pressed, mc, res) -> {
+		mc.getTextureManager().bindTexture(TouchOverlayRenderer.spriteSheet);
+		int[] pos = enumIn.getLocation(res, TouchOverlayRenderer._fuck);
+		TouchOverlayRenderer.drawTexturedModalRect(pos[0], pos[1], 18, 0, 18, 18, 2);
+	}),
+	
+	
+	DPAD_UP_RIGHT(EnumTouchControlPos.BOTTOM_LEFT, 112, 112, 36, null, (enumIn, x, y, pressed, mc, res) -> {
+		mc.getTextureManager().bindTexture(TouchOverlayRenderer.spriteSheet);
+		int[] pos = enumIn.getLocation(res, TouchOverlayRenderer._fuck);
+		TouchOverlayRenderer.drawTexturedModalRect(pos[0], pos[1], 18, 18, 18, 18, 2);
+	}),
+	
+	
+	JUMP(EnumTouchControlPos.BOTTOM_RIGHT, 64, 64, 36, (enumIn, x, y) -> {
+		if(!TouchControls.isPressed(enumIn)) {
+			if(TouchControls.isSneakToggled) {
+				TouchControls.resetSneakInvalidate();
+			}
+		}
+	}, (enumIn, x, y, pressed, mc, res) -> {
+		mc.getTextureManager().bindTexture(TouchOverlayRenderer.spriteSheet);
+		int[] pos = enumIn.getLocation(res, TouchOverlayRenderer._fuck);
+		TouchOverlayRenderer.drawTexturedModalRect(pos[0], pos[1], 18, 90, 18, 18, 2);
+	}),
+	
+	
+	SNEAK(EnumTouchControlPos.BOTTOM_LEFT, 64, 64, 36, (enumIn, x, y) -> {
+		if(!TouchControls.isPressed(enumIn)) {
+			enumIn.invalid = true;
+			TouchControls.isSneakToggled = !TouchControls.isSneakToggled;
+		}
+	}, (enumIn, x, y, pressed, mc, res) -> {
+		mc.getTextureManager().bindTexture(TouchOverlayRenderer.spriteSheet);
+		int[] pos = enumIn.getLocation(res, TouchOverlayRenderer._fuck);
+		TouchOverlayRenderer.drawTexturedModalRect(pos[0], pos[1], 18, TouchControls.isSneakToggled ? 126 : 108, 18, 18, 2);
+	}),
+	
+	
+	BACK(EnumTouchControlPos.TOP, -18, 0, 36, (enumIn, x, y) -> {
+		if(!TouchControls.isPressed(enumIn)) {
+			if(Touch.isDeviceKeyboardOpenMAYBE()) {
+				Touch.closeDeviceKeyboard();
+			}else {
+				Minecraft mc = Minecraft.getMinecraft();
+				if(mc.thePlayer != null) {
+					mc.setIngameFocus();
+				}else if(mc.currentScreen != null && !(mc.currentScreen instanceof GuiMainMenu)) {
+					mc.displayGuiScreen(null);
+				}
+			}
+		}
+	}, (enumIn, x, y, pressed, mc, res) -> {
+		mc.getTextureManager().bindTexture(TouchOverlayRenderer.spriteSheet);
+		int[] pos = enumIn.getLocation(res, TouchOverlayRenderer._fuck);
+		TouchOverlayRenderer.drawTexturedModalRect(pos[0], pos[1], 0, 36, 18, 18, 2);
+	}),
+	
+	
+	BACK_DISABLED(EnumTouchControlPos.TOP, -18, 0, 36, null, (enumIn, x, y, pressed, mc, res) -> {
+		mc.getTextureManager().bindTexture(TouchOverlayRenderer.spriteSheet);
+		int[] pos = enumIn.getLocation(res, TouchOverlayRenderer._fuck);
+		TouchOverlayRenderer.drawTexturedModalRect(pos[0], pos[1], 0, 54, 18, 18, 2);
+	}),
+	
+	
+	KEYBOARD(EnumTouchControlPos.TOP, 18, 0, 36, null, (enumIn, x, y, pressed, mc, res) -> {
+		mc.getTextureManager().bindTexture(TouchOverlayRenderer.spriteSheet);
+		int[] pos = enumIn.getLocation(res, TouchOverlayRenderer._fuck);
+		TouchOverlayRenderer.drawTexturedModalRect(pos[0], pos[1], 0, 72, 18, 18, 2);
+	}),
+	
+	
+	PAUSE(EnumTouchControlPos.TOP, -18, 0, 36, (enumIn, x, y) -> {
+		if(!TouchControls.isPressed(enumIn)) {
+			Minecraft mc = Minecraft.getMinecraft();
+			mc.displayInGameMenu();
+		}
+	}, (enumIn, x, y, pressed, mc, res) -> {
+		mc.getTextureManager().bindTexture(TouchOverlayRenderer.spriteSheet);
+		int[] pos = enumIn.getLocation(res, TouchOverlayRenderer._fuck);
+		TouchOverlayRenderer.drawTexturedModalRect(pos[0], pos[1], 0, 0, 18, 18, 2);
+	}),
+	
+	
+	CHAT(EnumTouchControlPos.TOP, 18, 0, 36, (enumIn, x, y) -> {
+		if(!TouchControls.isPressed(enumIn)) {
+			Minecraft mc = Minecraft.getMinecraft();
+			mc.displayGuiScreen(new GuiChat());
+		}
+	}, (enumIn, x, y, pressed, mc, res) -> {
+		mc.getTextureManager().bindTexture(TouchOverlayRenderer.spriteSheet);
+		int[] pos = enumIn.getLocation(res, TouchOverlayRenderer._fuck);
+		TouchOverlayRenderer.drawTexturedModalRect(pos[0], pos[1], 0, 18, 18, 18, 2);
+	}),
+	
+	
+	F3(EnumTouchControlPos.TOP, 144, 0, 36, (enumIn, x, y) -> {
+		if(!TouchControls.isPressed(enumIn)) {
+			Minecraft mc = Minecraft.getMinecraft();
+			GameSettings gameSettings = mc.gameSettings;
+			gameSettings.showDebugInfo = !gameSettings.showDebugInfo;
+		}
+	}, (enumIn, x, y, pressed, mc, res) -> {
+		mc.getTextureManager().bindTexture(TouchOverlayRenderer.spriteSheet);
+		int[] pos = enumIn.getLocation(res, TouchOverlayRenderer._fuck);
+		TouchOverlayRenderer.drawTexturedModalRect(pos[0], pos[1], 218, 220, 18, 18, 2);
+	}),
+	
+	
+	F5(EnumTouchControlPos.TOP, 90, 0, 36, (enumIn, x, y) -> {
+		if(!TouchControls.isPressed(enumIn)) {
+			Minecraft mc = Minecraft.getMinecraft();
+			mc.togglePerspective();
+		}
+	}, (enumIn, x, y, pressed, mc, res) -> {
+		mc.getTextureManager().bindTexture(TouchOverlayRenderer.spriteSheet);
+		int[] pos = enumIn.getLocation(res, TouchOverlayRenderer._fuck);
+		TouchOverlayRenderer.drawTexturedModalRect(pos[0], pos[1], 218, 184, 18, 18, 2);
+	}),
+	
+	
+	PASTE(EnumTouchControlPos.TOP, 144, 0, 36, (enumIn, x, y) -> {
+		if(!TouchControls.isPressed(enumIn)) {
+			GuiScreen screen = Minecraft.getMinecraft().currentScreen;
+			if(screen != null) {
+				screen.fireInputEvent(EnumInputEvent.CLIPBOARD_PASTE, null);
+			}
+		}
+	}, (enumIn, x, y, pressed, mc, res) -> {
+		mc.getTextureManager().bindTexture(TouchOverlayRenderer.spriteSheet);
+		int[] pos = enumIn.getLocation(res, TouchOverlayRenderer._fuck);
+		TouchOverlayRenderer.drawTexturedModalRect(pos[0], pos[1], 218, 148, 18, 18, 2);
+	}),
+	
+	
+	COPY(EnumTouchControlPos.TOP, 90, 0, 36, (enumIn, x, y) -> {
+		if(!TouchControls.isPressed(enumIn)) {
+			GuiScreen screen = Minecraft.getMinecraft().currentScreen;
+			if(screen != null) {
+				screen.fireInputEvent(EnumInputEvent.CLIPBOARD_COPY, null);
+			}
+		}
+	}, (enumIn, x, y, pressed, mc, res) -> {
+		mc.getTextureManager().bindTexture(TouchOverlayRenderer.spriteSheet);
+		int[] pos = enumIn.getLocation(res, TouchOverlayRenderer._fuck);
+		TouchOverlayRenderer.drawTexturedModalRect(pos[0], pos[1], 218, 166, 18, 18, 2);
+	}),
+	
+	
+	PICK(EnumTouchControlPos.BOTTOM_RIGHT, 62, 125, 40, (enumIn, x, y) -> {
+		if(!TouchControls.isPressed(enumIn)) {
+			Minecraft.getMinecraft().middleClickMouse();
+		}
+	}, (enumIn, x, y, pressed, mc, res) -> {
+		mc.getTextureManager().bindTexture(TouchOverlayRenderer.spriteSheet);
+		int[] pos = enumIn.getLocation(res, TouchOverlayRenderer._fuck);
+		TouchOverlayRenderer.drawTexturedModalRect(pos[0], pos[1], 36, 20, 20, 20, 2);
+	}),
+	
+	
+	FLY(EnumTouchControlPos.BOTTOM_LEFT, 16, 16, 36, (enumIn, x, y) -> {
+		if(!TouchControls.isPressed(enumIn)) {
+			TouchControls.resetSneak();
+			EntityPlayerSP player = Minecraft.getMinecraft().thePlayer;
+			player.jump();
+			player.capabilities.isFlying = true;
+		}
+	}, (enumIn, x, y, pressed, mc, res) -> {
+		mc.getTextureManager().bindTexture(TouchOverlayRenderer.spriteSheet);
+		int[] pos = enumIn.getLocation(res, TouchOverlayRenderer._fuck);
+		TouchOverlayRenderer.drawTexturedModalRect(pos[0], pos[1], 18, 72, 18, 18, 2);
+	}),
+	
+	
+	FLY_UP(EnumTouchControlPos.BOTTOM_RIGHT, 12, 120, 36, null, (enumIn, x, y, pressed, mc, res) -> {
+		mc.getTextureManager().bindTexture(TouchOverlayRenderer.spriteSheet);
+		int[] pos = enumIn.getLocation(res, TouchOverlayRenderer._fuck);
+		TouchOverlayRenderer.drawTexturedModalRect(pos[0], pos[1], 18, 36, 18, 18, 2);
+	}),
+	
+	
+	FLY_DOWN(EnumTouchControlPos.BOTTOM_RIGHT, 12, 75, 36, null, (enumIn, x, y, pressed, mc, res) -> {
+		mc.getTextureManager().bindTexture(TouchOverlayRenderer.spriteSheet);
+		int[] pos = enumIn.getLocation(res, TouchOverlayRenderer._fuck);
+		TouchOverlayRenderer.drawTexturedModalRect(pos[0], pos[1], 18, 54, 18, 18, 2);
+	}),
+	
+	
+	FLY_END(EnumTouchControlPos.BOTTOM_RIGHT, 64, 64, 36, (enumIn, x, y) -> {
+		if(!TouchControls.isPressed(enumIn)) {
+			Minecraft.getMinecraft().thePlayer.capabilities.isFlying = false;
+		}
+	}, (enumIn, x, y, pressed, mc, res) -> {
+		mc.getTextureManager().bindTexture(TouchOverlayRenderer.spriteSheet);
+		int[] pos = enumIn.getLocation(res, TouchOverlayRenderer._fuck);
+		TouchOverlayRenderer.drawTexturedModalRect(pos[0], pos[1], 18, 72, 18, 18, 2);
+	});
+
+	public static interface TouchAction {
+		void call(EnumTouchControl enumIn, int x, int y);
+	}
+
+	public static interface TouchRender {
+		void call(EnumTouchControl enumIn, int x, int y, boolean pressed, Minecraft mc, ScaledResolution res);
+	}
+
+	protected final EnumTouchControlPos pos;
+	protected final int offX;
+	protected final int offY;
+	protected final int size;
+	protected final TouchAction action;
+	protected final TouchRender render;
+
+	protected boolean visible = true;
+	protected boolean invalid = true;
+	
+	public static final EnumTouchControl[] _VALUES = values();
+
+	EnumTouchControl(EnumTouchControlPos pos, int offX, int offY, int size, TouchAction action, TouchRender render) {
+		this.pos = pos;
+		this.offX = offX;
+		this.offY = offY;
+		this.size = size;
+		this.action = action;
+		this.render = render;
+	}
+
+	public int[] getLocation(ScaledResolution scaledResolution, int[] loc) {
+		if(loc == null) {
+			loc = new int[2];
+		}
+		int sz = size;
+		switch (pos) {
+			case TOP_LEFT:
+				loc[0] = offX;
+				loc[1] = offY;
+				break;
+			case TOP:
+				loc[0] = offX + (scaledResolution.getScaledWidth() - sz) / 2;
+				loc[1] = offY;
+				break;
+			case TOP_RIGHT:
+				loc[0] = -offX + (scaledResolution.getScaledWidth() - sz);
+				loc[1] = offY;
+				break;
+			case LEFT:
+				loc[0] = offX;
+				loc[1] = offY + (scaledResolution.getScaledHeight() - sz) / 2;
+				break;
+			case RIGHT:
+				loc[0] = -offX + (scaledResolution.getScaledWidth() - sz);
+				loc[1] = offY + (scaledResolution.getScaledHeight() - sz) / 2;
+				break;
+			case BOTTOM_LEFT:
+				loc[0] = offX;
+				loc[1] = -offY + (scaledResolution.getScaledHeight() - sz);
+				break;
+			case BOTTOM:
+				loc[0] = offX + (scaledResolution.getScaledWidth() - sz) / 2;
+				loc[1] = -offY + (scaledResolution.getScaledHeight() - sz);
+				break;
+			case BOTTOM_RIGHT:
+				loc[0] = -offX + (scaledResolution.getScaledWidth() - sz);
+				loc[1] = -offY + (scaledResolution.getScaledHeight() - sz);
+				break;
+		}
+		return loc;
+	}
+
+	public void setVisible(TouchOverlayRenderer renderer, boolean vis) {
+		if(visible != vis) {
+			visible = vis;
+			invalid = true;
+			if(vis) {
+				renderer.invalidate();
+			}else {
+				renderer.invalidateDeep();
+			}
+		}
+	}
+
+	public int getSize() {
+		return size;
+	}
+
+	public TouchAction getAction() {
+		return action;
+	}
+
+	public TouchRender getRender() {
+		return render;
+	}
+
+	protected static EnumTouchLayoutState currentLayout = null;
+
+	public static void setLayoutState(TouchOverlayRenderer renderer, EnumTouchLayoutState layout) {
+		if(layout == currentLayout) return;
+		switch(layout) {
+		case IN_GUI:
+			DPAD_UP.setVisible(renderer, false);
+			DPAD_LEFT.setVisible(renderer, false);
+			DPAD_RIGHT.setVisible(renderer, false);
+			DPAD_DOWN.setVisible(renderer, false);
+			DPAD_UP_LEFT.setVisible(renderer, false);
+			DPAD_UP_RIGHT.setVisible(renderer, false);
+			JUMP.setVisible(renderer, false);
+			SNEAK.setVisible(renderer, false);
+			BACK.setVisible(renderer, true);
+			BACK_DISABLED.setVisible(renderer, false);
+			KEYBOARD.setVisible(renderer, true);
+			PAUSE.setVisible(renderer, false);
+			CHAT.setVisible(renderer, false);
+			F3.setVisible(renderer, false);
+			F5.setVisible(renderer, false);
+			PASTE.setVisible(renderer, false);
+			COPY.setVisible(renderer, false);
+			PICK.setVisible(renderer, false);
+			FLY.setVisible(renderer, false);
+			FLY_UP.setVisible(renderer, false);
+			FLY_DOWN.setVisible(renderer, false);
+			FLY_END.setVisible(renderer, false);
+			break;
+		case IN_GUI_TYPING:
+			DPAD_UP.setVisible(renderer, false);
+			DPAD_LEFT.setVisible(renderer, false);
+			DPAD_RIGHT.setVisible(renderer, false);
+			DPAD_DOWN.setVisible(renderer, false);
+			DPAD_UP_LEFT.setVisible(renderer, false);
+			DPAD_UP_RIGHT.setVisible(renderer, false);
+			JUMP.setVisible(renderer, false);
+			SNEAK.setVisible(renderer, false);
+			BACK.setVisible(renderer, true);
+			BACK_DISABLED.setVisible(renderer, false);
+			KEYBOARD.setVisible(renderer, true);
+			PAUSE.setVisible(renderer, false);
+			CHAT.setVisible(renderer, false);
+			F3.setVisible(renderer, false);
+			F5.setVisible(renderer, false);
+			PASTE.setVisible(renderer, true);
+			COPY.setVisible(renderer, true);
+			PICK.setVisible(renderer, false);
+			FLY.setVisible(renderer, false);
+			FLY_UP.setVisible(renderer, false);
+			FLY_DOWN.setVisible(renderer, false);
+			FLY_END.setVisible(renderer, false);
+			break;
+		case IN_GUI_NO_BACK:
+			DPAD_UP.setVisible(renderer, false);
+			DPAD_LEFT.setVisible(renderer, false);
+			DPAD_RIGHT.setVisible(renderer, false);
+			DPAD_DOWN.setVisible(renderer, false);
+			DPAD_UP_LEFT.setVisible(renderer, false);
+			DPAD_UP_RIGHT.setVisible(renderer, false);
+			JUMP.setVisible(renderer, false);
+			SNEAK.setVisible(renderer, false);
+			BACK.setVisible(renderer, false);
+			BACK_DISABLED.setVisible(renderer, true);
+			KEYBOARD.setVisible(renderer, true);
+			PAUSE.setVisible(renderer, false);
+			CHAT.setVisible(renderer, false);
+			F3.setVisible(renderer, false);
+			F5.setVisible(renderer, false);
+			PASTE.setVisible(renderer, false);
+			COPY.setVisible(renderer, false);
+			PICK.setVisible(renderer, false);
+			FLY.setVisible(renderer, false);
+			FLY_UP.setVisible(renderer, false);
+			FLY_DOWN.setVisible(renderer, false);
+			FLY_END.setVisible(renderer, false);
+			break;
+		case IN_GAME:
+			DPAD_UP.setVisible(renderer, true);
+			DPAD_LEFT.setVisible(renderer, true);
+			DPAD_RIGHT.setVisible(renderer, true);
+			DPAD_DOWN.setVisible(renderer, true);
+			DPAD_UP_LEFT.setVisible(renderer, false);
+			DPAD_UP_RIGHT.setVisible(renderer, false);
+			JUMP.setVisible(renderer, true);
+			SNEAK.setVisible(renderer, true);
+			BACK.setVisible(renderer, false);
+			BACK_DISABLED.setVisible(renderer, false);
+			KEYBOARD.setVisible(renderer, false);
+			PAUSE.setVisible(renderer, true);
+			CHAT.setVisible(renderer, true);
+			F3.setVisible(renderer, true);
+			F5.setVisible(renderer, true);
+			PASTE.setVisible(renderer, false);
+			COPY.setVisible(renderer, false);
+			PICK.setVisible(renderer, true);
+			FLY.setVisible(renderer, false);
+			FLY_UP.setVisible(renderer, false);
+			FLY_DOWN.setVisible(renderer, false);
+			FLY_END.setVisible(renderer, false);
+			break;
+		case IN_GAME_WALK:
+			DPAD_UP.setVisible(renderer, true);
+			DPAD_LEFT.setVisible(renderer, true);
+			DPAD_RIGHT.setVisible(renderer, true);
+			DPAD_DOWN.setVisible(renderer, true);
+			DPAD_UP_LEFT.setVisible(renderer, true);
+			DPAD_UP_RIGHT.setVisible(renderer, true);
+			JUMP.setVisible(renderer, true);
+			SNEAK.setVisible(renderer, true);
+			BACK.setVisible(renderer, false);
+			BACK_DISABLED.setVisible(renderer, false);
+			KEYBOARD.setVisible(renderer, false);
+			PAUSE.setVisible(renderer, true);
+			CHAT.setVisible(renderer, true);
+			F3.setVisible(renderer, true);
+			F5.setVisible(renderer, true);
+			PASTE.setVisible(renderer, false);
+			COPY.setVisible(renderer, false);
+			PICK.setVisible(renderer, true);
+			FLY.setVisible(renderer, false);
+			FLY_UP.setVisible(renderer, false);
+			FLY_DOWN.setVisible(renderer, false);
+			FLY_END.setVisible(renderer, false);
+			break;
+		case IN_GAME_CAN_FLY:
+			DPAD_UP.setVisible(renderer, true);
+			DPAD_LEFT.setVisible(renderer, true);
+			DPAD_RIGHT.setVisible(renderer, true);
+			DPAD_DOWN.setVisible(renderer, true);
+			DPAD_UP_LEFT.setVisible(renderer, false);
+			DPAD_UP_RIGHT.setVisible(renderer, false);
+			JUMP.setVisible(renderer, true);
+			SNEAK.setVisible(renderer, true);
+			BACK.setVisible(renderer, false);
+			BACK_DISABLED.setVisible(renderer, false);
+			KEYBOARD.setVisible(renderer, false);
+			PAUSE.setVisible(renderer, true);
+			CHAT.setVisible(renderer, true);
+			F3.setVisible(renderer, true);
+			F5.setVisible(renderer, true);
+			PASTE.setVisible(renderer, false);
+			COPY.setVisible(renderer, false);
+			PICK.setVisible(renderer, true);
+			FLY.setVisible(renderer, true);
+			FLY_UP.setVisible(renderer, false);
+			FLY_DOWN.setVisible(renderer, false);
+			FLY_END.setVisible(renderer, false);
+			break;
+		case IN_GAME_WALK_CAN_FLY:
+			DPAD_UP.setVisible(renderer, true);
+			DPAD_LEFT.setVisible(renderer, true);
+			DPAD_RIGHT.setVisible(renderer, true);
+			DPAD_DOWN.setVisible(renderer, true);
+			DPAD_UP_LEFT.setVisible(renderer, true);
+			DPAD_UP_RIGHT.setVisible(renderer, true);
+			JUMP.setVisible(renderer, true);
+			SNEAK.setVisible(renderer, true);
+			BACK.setVisible(renderer, false);
+			BACK_DISABLED.setVisible(renderer, false);
+			KEYBOARD.setVisible(renderer, false);
+			PAUSE.setVisible(renderer, true);
+			CHAT.setVisible(renderer, true);
+			F3.setVisible(renderer, true);
+			F5.setVisible(renderer, true);
+			PASTE.setVisible(renderer, false);
+			COPY.setVisible(renderer, false);
+			PICK.setVisible(renderer, true);
+			FLY.setVisible(renderer, true);
+			FLY_UP.setVisible(renderer, false);
+			FLY_DOWN.setVisible(renderer, false);
+			FLY_END.setVisible(renderer, false);
+			break;
+		case IN_GAME_FLYING:
+			DPAD_UP.setVisible(renderer, true);
+			DPAD_LEFT.setVisible(renderer, true);
+			DPAD_RIGHT.setVisible(renderer, true);
+			DPAD_DOWN.setVisible(renderer, true);
+			DPAD_UP_LEFT.setVisible(renderer, false);
+			DPAD_UP_RIGHT.setVisible(renderer, false);
+			JUMP.setVisible(renderer, false);
+			SNEAK.setVisible(renderer, true);
+			BACK.setVisible(renderer, false);
+			BACK_DISABLED.setVisible(renderer, false);
+			KEYBOARD.setVisible(renderer, false);
+			PAUSE.setVisible(renderer, true);
+			CHAT.setVisible(renderer, true);
+			F3.setVisible(renderer, true);
+			F5.setVisible(renderer, true);
+			PASTE.setVisible(renderer, false);
+			COPY.setVisible(renderer, false);
+			PICK.setVisible(renderer, true);
+			FLY.setVisible(renderer, false);
+			FLY_UP.setVisible(renderer, true);
+			FLY_DOWN.setVisible(renderer, true);
+			FLY_END.setVisible(renderer, true);
+			break;
+		case IN_GAME_WALK_FLYING:
+			DPAD_UP.setVisible(renderer, true);
+			DPAD_LEFT.setVisible(renderer, true);
+			DPAD_RIGHT.setVisible(renderer, true);
+			DPAD_DOWN.setVisible(renderer, true);
+			DPAD_UP_LEFT.setVisible(renderer, true);
+			DPAD_UP_RIGHT.setVisible(renderer, true);
+			JUMP.setVisible(renderer, false);
+			SNEAK.setVisible(renderer, true);
+			BACK.setVisible(renderer, false);
+			BACK_DISABLED.setVisible(renderer, false);
+			KEYBOARD.setVisible(renderer, false);
+			PAUSE.setVisible(renderer, true);
+			CHAT.setVisible(renderer, true);
+			F3.setVisible(renderer, true);
+			F5.setVisible(renderer, true);
+			PASTE.setVisible(renderer, false);
+			COPY.setVisible(renderer, false);
+			PICK.setVisible(renderer, true);
+			FLY.setVisible(renderer, false);
+			FLY_UP.setVisible(renderer, true);
+			FLY_DOWN.setVisible(renderer, true);
+			FLY_END.setVisible(renderer, true);
+			break;
+		default:
+			throw new IllegalStateException();
+		}
+		currentLayout = layout;
+	}
+
+}
\ No newline at end of file
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/touch_gui/EnumTouchControlPos.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/touch_gui/EnumTouchControlPos.java
new file mode 100644
index 00000000..fa10bd87
--- /dev/null
+++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/touch_gui/EnumTouchControlPos.java
@@ -0,0 +1,20 @@
+package net.lax1dude.eaglercraft.v1_8.touch_gui;
+
+/**
+ * Copyright (c) 2024 ayunami2000. All Rights Reserved.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ * 
+ */
+public enum EnumTouchControlPos {
+	TOP_LEFT, TOP, TOP_RIGHT, LEFT, RIGHT, BOTTOM_LEFT, BOTTOM, BOTTOM_RIGHT
+}
\ No newline at end of file
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/touch_gui/EnumTouchLayoutState.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/touch_gui/EnumTouchLayoutState.java
new file mode 100644
index 00000000..55601f14
--- /dev/null
+++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/touch_gui/EnumTouchLayoutState.java
@@ -0,0 +1,28 @@
+package net.lax1dude.eaglercraft.v1_8.touch_gui;
+
+/**
+ * Copyright (c) 2024 lax1due. All Rights Reserved.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ * 
+ */
+public enum EnumTouchLayoutState {
+	IN_GUI,
+	IN_GUI_TYPING,
+	IN_GUI_NO_BACK,
+	IN_GAME,
+	IN_GAME_WALK,
+	IN_GAME_CAN_FLY,
+	IN_GAME_WALK_CAN_FLY,
+	IN_GAME_FLYING,
+	IN_GAME_WALK_FLYING;
+}
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/touch_gui/TouchControlInput.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/touch_gui/TouchControlInput.java
new file mode 100644
index 00000000..03d01059
--- /dev/null
+++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/touch_gui/TouchControlInput.java
@@ -0,0 +1,27 @@
+package net.lax1dude.eaglercraft.v1_8.touch_gui;
+
+/**
+ * Copyright (c) 2024 ayunami2000. All Rights Reserved.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ * 
+ */
+public class TouchControlInput {
+	public int x;
+	public int y;
+	public final EnumTouchControl control;
+	public TouchControlInput(int x, int y, EnumTouchControl control) {
+		this.x = x;
+		this.y = y;
+		this.control = control;
+	}
+}
\ No newline at end of file
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/touch_gui/TouchControls.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/touch_gui/TouchControls.java
new file mode 100644
index 00000000..aa1b59cf
--- /dev/null
+++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/touch_gui/TouchControls.java
@@ -0,0 +1,164 @@
+package net.lax1dude.eaglercraft.v1_8.touch_gui;
+
+import net.lax1dude.eaglercraft.v1_8.Touch;
+import net.lax1dude.eaglercraft.v1_8.touch_gui.EnumTouchControl.TouchAction;
+import net.minecraft.client.Minecraft;
+import net.minecraft.client.gui.ScaledResolution;
+
+import java.util.*;
+
+/**
+ * Copyright (c) 2024 lax1dude, ayunami2000. All Rights Reserved.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ * 
+ */
+public class TouchControls {
+
+	public static final Map<Integer, TouchControlInput> touchControls = new HashMap<>();
+	protected static Set<EnumTouchControl> touchControlPressed = EnumSet.noneOf(EnumTouchControl.class);
+
+	protected static boolean isSneakToggled = false;
+
+	public static void update(boolean screenTouched) {
+		Minecraft mc = Minecraft.getMinecraft();
+		int h = mc.displayHeight;
+		final ScaledResolution sr = mc.scaledResolution;
+		int fac = sr.getScaleFactor();
+		if(screenTouched) {
+			int touchPoints = Touch.touchPointCount();
+			int[] loc;
+			for(int i = 0; i < touchPoints; ++i) {
+				int x = Touch.touchPointX(i);
+				int y = h - Touch.touchPointY(i) - 1;
+				int uid = Touch.touchPointUID(i);
+				TouchControlInput input = touchControls.get(uid);
+				if(input != null) {
+					EnumTouchControl ctrl = input.control;
+					loc = ctrl.getLocation(sr, TouchOverlayRenderer._fuck);
+					loc[0] *= fac;
+					loc[1] *= fac;
+					int size = ctrl.getSize() * fac;
+					if (x >= loc[0] && y >= loc[1] && x < loc[0] + size && y < loc[1] + size) {
+						continue;
+					}
+					EnumTouchControl[] en = EnumTouchControl._VALUES;
+					for (int j = 0; j < en.length; ++j) {
+						EnumTouchControl control = en[j];
+						if(!control.visible) continue;
+						loc = control.getLocation(sr, TouchOverlayRenderer._fuck);
+						loc[0] *= fac;
+						loc[1] *= fac;
+						size = control.getSize() * fac;
+						if (x >= loc[0] && y >= loc[1] && x < loc[0] + size && y < loc[1] + size) {
+							touchControls.put(uid, new TouchControlInput(x / fac, y / fac, control));
+							break;
+						}
+					}
+				}
+			}
+			mc.ingameGUI.updateTouchEagler(mc.currentScreen == null);
+		}else {
+			touchControls.clear();
+			touchControlPressed.clear();
+			mc.ingameGUI.updateTouchEagler(false);
+		}
+	}
+
+	public static boolean handleTouchBegin(int uid, int pointX, int pointY) {
+		Minecraft mc = Minecraft.getMinecraft();
+		pointY = mc.displayHeight - pointY - 1;
+		EnumTouchControl control = overlappingControl0(pointX, pointY, mc.scaledResolution);
+		if(control != null) {
+			int fac = mc.scaledResolution.getScaleFactor();
+			touchControls.put(uid, new TouchControlInput(pointX / fac, pointY / fac, control));
+			return true;
+		}else {
+			return mc.currentScreen == null && Minecraft.getMinecraft().ingameGUI.handleTouchBeginEagler(uid, pointX, pointY);
+		}
+	}
+
+	public static boolean handleTouchEnd(int uid, int pointX, int pointY) {
+		if(touchControls.remove(uid) != null) {
+			return true;
+		}else {
+			Minecraft mc = Minecraft.getMinecraft();
+			return mc.currentScreen == null && mc.ingameGUI.handleTouchEndEagler(uid, pointX, mc.displayHeight - pointY - 1);
+		}
+	}
+
+	public static void resetSneak() {
+		isSneakToggled = false;
+	}
+
+	public static void resetSneakInvalidate() {
+		if(isSneakToggled) {
+			isSneakToggled = false;
+			EnumTouchControl.SNEAK.invalid = true;
+			Minecraft.getMinecraft().touchOverlayRenderer.invalidate();
+		}
+	}
+
+	public static void handleInput() {
+		if(!touchControls.isEmpty()) {
+			Set<EnumTouchControl> newPressed = EnumSet.noneOf(EnumTouchControl.class);
+			TouchOverlayRenderer renderer = Minecraft.getMinecraft().touchOverlayRenderer;
+			for (TouchControlInput input : touchControls.values()) {
+				TouchAction action = input.control.getAction();
+				if(action != null) {
+					action.call(input.control, input.x, input.y);
+				}
+				if(input.control.invalid) {
+					renderer.invalidate();
+				}
+				newPressed.add(input.control);
+			}
+			touchControlPressed = newPressed;
+		}else {
+			touchControlPressed.clear();
+		}
+	}
+
+	public static boolean isPressed(EnumTouchControl control) {
+		return touchControlPressed.contains(control);
+	}
+
+	public static boolean getSneakToggled() {
+		return isSneakToggled;
+	}
+
+	public static EnumTouchControl overlappingControl(int tx, int ty) {
+		Minecraft mc = Minecraft.getMinecraft();
+		ty = mc.displayHeight - ty - 1;
+		return overlappingControl0(tx, ty, mc.scaledResolution);
+	}
+
+	private static EnumTouchControl overlappingControl0(int pointX, int pointY, ScaledResolution sr) {
+		EnumTouchControl[] en = EnumTouchControl._VALUES;
+		int[] loc;
+		int fac = sr.getScaleFactor();
+		int size;
+		for (int j = 0; j < en.length; ++j) {
+			EnumTouchControl control = en[j];
+			if(!control.visible) continue;
+			loc = control.getLocation(sr, TouchOverlayRenderer._fuck);
+			loc[0] *= fac;
+			loc[1] *= fac;
+			size = control.getSize() * fac;
+			if (pointX >= loc[0] && pointY >= loc[1] && pointX < loc[0] + size && pointY < loc[1] + size) {
+				return control;
+			}
+		}
+		return null;
+	}
+
+}
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/touch_gui/TouchOverlayRenderer.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/touch_gui/TouchOverlayRenderer.java
new file mode 100644
index 00000000..040f28ac
--- /dev/null
+++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/touch_gui/TouchOverlayRenderer.java
@@ -0,0 +1,197 @@
+package net.lax1dude.eaglercraft.v1_8.touch_gui;
+
+import net.lax1dude.eaglercraft.v1_8.PointerInputAbstraction;
+import net.lax1dude.eaglercraft.v1_8.Touch;
+import net.lax1dude.eaglercraft.v1_8.opengl.GameOverlayFramebuffer;
+import net.lax1dude.eaglercraft.v1_8.opengl.GlStateManager;
+import net.lax1dude.eaglercraft.v1_8.opengl.WorldRenderer;
+import net.minecraft.client.Minecraft;
+import net.minecraft.client.entity.EntityPlayerSP;
+import net.minecraft.client.gui.ScaledResolution;
+import net.minecraft.client.renderer.Tessellator;
+import net.minecraft.client.renderer.vertex.DefaultVertexFormats;
+import net.minecraft.util.MathHelper;
+import net.minecraft.util.ResourceLocation;
+
+import static net.lax1dude.eaglercraft.v1_8.opengl.RealOpenGLEnums.*;
+
+import java.util.Set;
+
+import com.google.common.collect.Sets;
+
+/**
+ * Copyright (c) 2024 lax1dude. All Rights Reserved.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ * 
+ */
+public class TouchOverlayRenderer {
+
+	public static final ResourceLocation spriteSheet = new ResourceLocation("eagler:gui/touch_gui.png");
+
+	static final int[] _fuck = new int[2];
+
+	private GameOverlayFramebuffer overlayFramebuffer;
+	private final Minecraft mc;
+	private boolean invalid = false;
+	private boolean invalidDeep = false;
+	private int currentWidth = -1;
+	private int currentHeight = -1;
+
+	public TouchOverlayRenderer(Minecraft mc) {
+		this.mc = mc;
+		this.overlayFramebuffer = new GameOverlayFramebuffer(false);
+		EnumTouchControl.currentLayout = null;
+		EnumTouchControl.setLayoutState(this, EnumTouchLayoutState.IN_GUI);
+	}
+
+	public void invalidate() {
+		invalid = true;
+	}
+
+	public void invalidateDeep() {
+		invalid = true;
+		invalidDeep = true;
+	}
+
+	public void render(int w, int h, ScaledResolution scaledResolution) {
+		if(PointerInputAbstraction.isTouchMode()) {
+			render0(w, h, scaledResolution);
+			if(EnumTouchControl.KEYBOARD.visible) {
+				int[] pos = EnumTouchControl.KEYBOARD.getLocation(scaledResolution, _fuck);
+				int scale = scaledResolution.getScaleFactor();
+				int size = EnumTouchControl.KEYBOARD.size * scale;
+				Touch.touchSetOpenKeyboardZone(pos[0] * scale,
+						(scaledResolution.getScaledHeight() - pos[1] - 1) * scale - size, size, size);
+			}else {
+				Touch.touchSetOpenKeyboardZone(0, 0, 0, 0);
+			}
+		}else {
+			Touch.touchSetOpenKeyboardZone(0, 0, 0, 0);
+		}
+	}
+
+	private void render0(int w, int h, ScaledResolution scaledResolution) {
+		EnumTouchControl.setLayoutState(this, hashLayoutState());
+		int sw = scaledResolution.getScaledWidth();
+		int sh = scaledResolution.getScaledHeight();
+		if(currentWidth != sw || currentHeight != sh) {
+			invalidateDeep();
+		}
+		GlStateManager.disableDepth();
+		GlStateManager.disableBlend();
+		GlStateManager.disableLighting();
+		GlStateManager.enableAlpha();
+		GlStateManager.depthMask(false);
+		if(invalid) {
+			GlStateManager.pushMatrix();
+			invalidDeep |= overlayFramebuffer.beginRender(sw, sh);
+			GlStateManager.viewport(0, 0, sw, sh);
+			if(invalidDeep) {
+				currentWidth = sw;
+				currentHeight = sh;
+				GlStateManager.clearColor(0.0f, 0.0f, 0.0f, 0.0f);
+				GlStateManager.clear(GL_COLOR_BUFFER_BIT);
+			}
+			Set<EnumTouchControl> controls = Sets.newHashSet(EnumTouchControl._VALUES);
+			for (TouchControlInput input : TouchControls.touchControls.values()) {
+				controls.remove(input.control);
+			}
+			for (EnumTouchControl control : controls) {
+				if(invalidDeep || control.invalid) {
+					if(control.visible) {
+						GlStateManager.color(1.0f, 1.0f, 1.0f, 1.0f);
+						control.getRender().call(control, 0, 0, false, mc, scaledResolution);
+					}
+					control.invalid = false;
+				}
+			}
+			for (TouchControlInput input : TouchControls.touchControls.values()) {
+				EnumTouchControl control = input.control;
+				if(invalidDeep || control.invalid) {
+					if(control.visible) {
+						GlStateManager.color(1.0f, 1.0f, 1.0f, 1.0f);
+						control.getRender().call(control, input.x, input.y, true, mc, scaledResolution);
+					}
+					control.invalid = false;
+				}
+			}
+			overlayFramebuffer.endRender();
+			invalid = false;
+			invalidDeep = false;
+			GlStateManager.popMatrix();
+			GlStateManager.viewport(0, 0, w, h);
+		}
+		GlStateManager.bindTexture(overlayFramebuffer.getTexture());
+		GlStateManager.enableBlend();
+		GlStateManager.blendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+		GlStateManager.enableAlpha();
+		GlStateManager.color(1.0f, 1.0f, 1.0f, MathHelper.clamp_float(mc.gameSettings.touchControlOpacity, 0.0f, 1.0f));
+		Tessellator tessellator = Tessellator.getInstance();
+		WorldRenderer worldrenderer = tessellator.getWorldRenderer();
+		worldrenderer.begin(7, DefaultVertexFormats.POSITION_TEX);
+		worldrenderer.pos(0.0D, (double) sh, 500.0D).tex(0.0D, 0.0D).endVertex();
+		worldrenderer.pos((double) sw, (double) sh, 500.0D).tex(1.0D, 0.0D).endVertex();
+		worldrenderer.pos((double) sw, 0.0D, 500.0D).tex(1.0D, 1.0D).endVertex();
+		worldrenderer.pos(0.0D, 0.0D, 500.0D).tex(0.0D, 1.0D).endVertex();
+		tessellator.draw();
+		GlStateManager.color(1.0f, 1.0f, 1.0f, 1.0f);
+		GlStateManager.enableDepth();
+		GlStateManager.depthMask(true);
+	}
+
+	private EnumTouchLayoutState hashLayoutState() {
+		if(mc.currentScreen != null) {
+			return mc.currentScreen.showCopyPasteButtons() ? EnumTouchLayoutState.IN_GUI_TYPING
+					: (mc.currentScreen.canCloseGui() ? EnumTouchLayoutState.IN_GUI
+							: EnumTouchLayoutState.IN_GUI_NO_BACK);
+		}
+		EntityPlayerSP player = mc.thePlayer;
+		if(player != null) {
+			if(player.capabilities.isFlying) {
+				 return showDiagButtons() ? EnumTouchLayoutState.IN_GAME_WALK_FLYING : EnumTouchLayoutState.IN_GAME_FLYING;
+			}else {
+				if(player.capabilities.allowFlying) {
+					return showDiagButtons() ? EnumTouchLayoutState.IN_GAME_WALK_CAN_FLY : EnumTouchLayoutState.IN_GAME_CAN_FLY;
+				}else {
+					return showDiagButtons() ? EnumTouchLayoutState.IN_GAME_WALK : EnumTouchLayoutState.IN_GAME;
+				}
+			}
+		}else {
+			return showDiagButtons() ? EnumTouchLayoutState.IN_GAME_WALK : EnumTouchLayoutState.IN_GAME;
+		}
+	}
+
+	private boolean showDiagButtons() {
+		return TouchControls.isPressed(EnumTouchControl.DPAD_UP)
+				|| TouchControls.isPressed(EnumTouchControl.DPAD_UP_LEFT)
+				|| TouchControls.isPressed(EnumTouchControl.DPAD_UP_RIGHT);
+	}
+
+	protected static void drawTexturedModalRect(float xCoord, float yCoord, int minU, int minV, int maxU, int maxV, int scaleFac) {
+		float f = 0.00390625F;
+		float f1 = 0.00390625F;
+		Tessellator tessellator = Tessellator.getInstance();
+		WorldRenderer worldrenderer = tessellator.getWorldRenderer();
+		worldrenderer.begin(7, DefaultVertexFormats.POSITION_TEX);
+		worldrenderer.pos((double) (xCoord + 0.0F), (double) (yCoord + (float) maxV * scaleFac), 0.0)
+				.tex((double) ((float) (minU + 0) * f), (double) ((float) (minV + maxV) * f1)).endVertex();
+		worldrenderer.pos((double) (xCoord + (float) maxU * scaleFac), (double) (yCoord + (float) maxV * scaleFac), 0.0)
+				.tex((double) ((float) (minU + maxU) * f), (double) ((float) (minV + maxV) * f1)).endVertex();
+		worldrenderer.pos((double) (xCoord + (float) maxU * scaleFac), (double) (yCoord + 0.0F), 0.0)
+				.tex((double) ((float) (minU + maxU) * f), (double) ((float) (minV + 0) * f1)).endVertex();
+		worldrenderer.pos((double) (xCoord + 0.0F), (double) (yCoord + 0.0F), 0.0)
+				.tex((double) ((float) (minU + 0) * f), (double) ((float) (minV + 0) * f1)).endVertex();
+		tessellator.draw();
+	}
+
+}
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/update/GuiUpdateDownloadSuccess.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/update/GuiUpdateDownloadSuccess.java
new file mode 100644
index 00000000..00a79a86
--- /dev/null
+++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/update/GuiUpdateDownloadSuccess.java
@@ -0,0 +1,60 @@
+package net.lax1dude.eaglercraft.v1_8.update;
+
+import net.minecraft.client.gui.GuiButton;
+import net.minecraft.client.gui.GuiScreen;
+import net.minecraft.client.resources.I18n;
+
+/**
+ * Copyright (c) 2024 lax1dude. All Rights Reserved.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ * 
+ */
+public class GuiUpdateDownloadSuccess extends GuiScreen {
+
+	protected final GuiScreen parent;
+	protected final UpdateDataObj updateData;
+
+	public GuiUpdateDownloadSuccess(GuiScreen parent, UpdateDataObj updateData) {
+		this.parent = parent;
+		this.updateData = updateData;
+	}
+
+	public void initGui() {
+		this.buttonList.clear();
+		this.buttonList.add(new GuiButton(0, this.width / 2 - 100, this.height / 6 + 56, I18n.format("updateSuccess.downloadOffline")));
+		this.buttonList.add(new GuiButton(1, this.width / 2 - 100, this.height / 6 + 86, I18n.format("updateSuccess.installToBootMenu")));
+		this.buttonList.add(new GuiButton(2, this.width / 2 - 100, this.height / 6 + 130, I18n.format("gui.cancel")));
+	}
+
+	public void actionPerformed(GuiButton btn) {
+		if(btn.id == 0) {
+			this.mc.loadingScreen.eaglerShow(I18n.format("updateSuccess.downloading"), null);
+			UpdateService.quine(updateData.clientSignature, updateData.clientBundle);
+			this.mc.displayGuiScreen(parent);
+		}else if(btn.id == 1) {
+			this.mc.displayGuiScreen(new GuiUpdateInstallOptions(this, parent, updateData));
+		}else if(btn.id == 2) {
+			this.mc.displayGuiScreen(parent);
+		}
+	}
+
+	public void drawScreen(int par1, int par2, float par3) {
+		this.drawDefaultBackground();
+		this.drawCenteredString(fontRendererObj, I18n.format("updateSuccess.title"), this.width / 2, 50, 11184810);
+		this.drawCenteredString(fontRendererObj,
+				updateData.clientSignature.bundleDisplayName + " " + updateData.clientSignature.bundleDisplayVersion,
+				this.width / 2, 70, 0xFFFFAA);
+		super.drawScreen(par1, par2, par3);
+	}
+
+}
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/update/GuiUpdateInstallOptions.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/update/GuiUpdateInstallOptions.java
new file mode 100644
index 00000000..444e25b3
--- /dev/null
+++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/update/GuiUpdateInstallOptions.java
@@ -0,0 +1,84 @@
+package net.lax1dude.eaglercraft.v1_8.update;
+
+import net.lax1dude.eaglercraft.v1_8.EaglercraftVersion;
+import net.lax1dude.eaglercraft.v1_8.minecraft.GuiScreenGenericErrorMessage;
+import net.minecraft.client.gui.GuiButton;
+import net.minecraft.client.gui.GuiScreen;
+import net.minecraft.client.resources.I18n;
+
+/**
+ * Copyright (c) 2024 lax1dude. All Rights Reserved.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ * 
+ */
+public class GuiUpdateInstallOptions extends GuiScreen {
+
+	protected final GuiScreen parent;
+	protected final GuiScreen onDone;
+	protected final UpdateDataObj updateData;
+	protected boolean makeDefault;
+	protected boolean enableCountdown;
+	protected GuiButton makeDefaultBtn;
+	protected GuiButton enableCountdownBtn;
+
+	public GuiUpdateInstallOptions(GuiScreen parent, GuiScreen onDone, UpdateDataObj updateData) {
+		this.parent = parent;
+		this.onDone = onDone;
+		this.updateData = updateData;
+		makeDefault = updateData.clientSignature.bundleVersionInteger > EaglercraftVersion.updateBundlePackageVersionInt;
+		enableCountdown = makeDefault;
+	}
+
+	public void initGui() {
+		this.buttonList.clear();
+		this.buttonList.add(makeDefaultBtn = new GuiButton(0, this.width / 2 - 100, this.height / 6 + 46,
+				I18n.format("updateInstall.setDefault") + ": " + I18n.format(makeDefault ? "gui.yes" : "gui.no")));
+		this.buttonList.add(enableCountdownBtn = new GuiButton(1, this.width / 2 - 100, this.height / 6 + 76,
+				I18n.format("updateInstall.setCountdown") + ": "
+						+ I18n.format(enableCountdown ? "gui.yes" : "gui.no")));
+		this.buttonList.add(new GuiButton(2, this.width / 2 - 100, this.height / 6 + 110, I18n.format("updateInstall.install")));
+		this.buttonList.add(new GuiButton(3, this.width / 2 - 100, this.height / 6 + 140, I18n.format("gui.cancel")));
+		
+	}
+
+	public void actionPerformed(GuiButton btn) {
+		if(btn.id == 0) {
+			makeDefault = !makeDefault;
+			makeDefaultBtn.displayString = I18n.format("updateInstall.setDefault") + ": " + I18n.format(makeDefault ? "gui.yes" : "gui.no");
+		}else if(btn.id == 1) {
+			enableCountdown = !enableCountdown;
+			enableCountdownBtn.displayString = I18n.format("updateInstall.setCountdown") + ": " + I18n.format(enableCountdown ? "gui.yes" : "gui.no");
+		}else if(btn.id == 2) {
+			mc.loadingScreen.eaglerShow(I18n.format("updateSuccess.installing"), null);
+			try {
+				UpdateService.installSignedClient(updateData.clientSignature, updateData.clientBundle, makeDefault, enableCountdown);
+			}catch(Throwable t) {
+				mc.displayGuiScreen(new GuiScreenGenericErrorMessage("installFailed.title", t.toString(), onDone));
+				return;
+			}
+			mc.displayGuiScreen(onDone);
+		}else if(btn.id == 3) {
+			mc.displayGuiScreen(parent);
+		}
+	}
+
+	public void drawScreen(int mx, int my, float partialTicks) {
+		this.drawDefaultBackground();
+		this.drawCenteredString(fontRendererObj, I18n.format("updateInstall.title"), this.width / 2, 40, 11184810);
+		this.drawCenteredString(fontRendererObj,
+				updateData.clientSignature.bundleDisplayName + " " + updateData.clientSignature.bundleDisplayVersion,
+				this.width / 2, 60, 0xFFFFAA);
+		super.drawScreen(mx, my, partialTicks);
+	}
+
+}
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/update/GuiUpdateVersionList.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/update/GuiUpdateVersionList.java
index 905fc161..b965e909 100644
--- a/sources/main/java/net/lax1dude/eaglercraft/v1_8/update/GuiUpdateVersionList.java
+++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/update/GuiUpdateVersionList.java
@@ -1,6 +1,8 @@
 package net.lax1dude.eaglercraft.v1_8.update;
 
 import java.io.IOException;
+
+import net.lax1dude.eaglercraft.v1_8.opengl.GlStateManager;
 import net.minecraft.client.Minecraft;
 import net.minecraft.client.gui.GuiButton;
 import net.minecraft.client.gui.GuiScreen;
@@ -60,12 +62,13 @@ public class GuiUpdateVersionList extends GuiScreen {
 				UpdateService.startClientUpdateFrom(slots.certList.get(selected));
 			}
 		case 0:
-		default:
 			mc.displayGuiScreen(back);
 			break;
 		case 2:
 			this.initGui();
 			break;
+		default:
+			break;
 		}
 	}
 
@@ -79,6 +82,7 @@ public class GuiUpdateVersionList extends GuiScreen {
 		super.drawScreen(par1, par2, par3);
 		if(tooltip != null) {
 			drawHoveringText(mc.fontRendererObj.listFormattedStringToWidth(tooltip, 180), par1, par2);
+			GlStateManager.disableLighting();
 			tooltip = null;
 		}
 	}
@@ -88,4 +92,11 @@ public class GuiUpdateVersionList extends GuiScreen {
 		super.handleMouseInput();
 		slots.handleMouseInput();
 	}
+
+	@Override
+	public void handleTouchInput() throws IOException {
+		super.handleTouchInput();
+		slots.handleTouchInput();
+	}
+
 }
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/update/GuiUpdateVersionSlot.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/update/GuiUpdateVersionSlot.java
index 0ed90084..37a2d499 100644
--- a/sources/main/java/net/lax1dude/eaglercraft/v1_8/update/GuiUpdateVersionSlot.java
+++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/update/GuiUpdateVersionSlot.java
@@ -8,7 +8,6 @@ import java.util.Collection;
 import java.util.Date;
 import java.util.List;
 
-import net.lax1dude.eaglercraft.v1_8.EagRuntime;
 import net.lax1dude.eaglercraft.v1_8.EaglercraftVersion;
 import net.lax1dude.eaglercraft.v1_8.opengl.EaglercraftGPU;
 import net.lax1dude.eaglercraft.v1_8.opengl.GlStateManager;
@@ -35,7 +34,7 @@ public class GuiUpdateVersionSlot extends GuiSlot {
 
 	private static final ResourceLocation eaglerGuiTex = new ResourceLocation("eagler:gui/eagler_gui.png");
 
-	final List<UpdateCertificate> certList = new ArrayList();
+	final List<UpdateCertificate> certList = new ArrayList<>();
 
 	final GuiUpdateVersionList screen;
 
@@ -86,7 +85,7 @@ public class GuiUpdateVersionSlot extends GuiSlot {
 		screen.drawBackground(0);
 	}
 
-	public static final SimpleDateFormat dateFmt = EagRuntime.fixDateFormat(new SimpleDateFormat("M/dd/yyyy"));
+	public static final SimpleDateFormat dateFmt = new SimpleDateFormat("M/dd/yyyy");
 	private static final char[] hexChars = new char[] { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
 
 	@Override
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/update/RelayUpdateChecker.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/update/RelayUpdateChecker.java
index 2ee5eeb9..f5746807 100644
--- a/sources/main/java/net/lax1dude/eaglercraft/v1_8/update/RelayUpdateChecker.java
+++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/update/RelayUpdateChecker.java
@@ -13,7 +13,7 @@ import net.lax1dude.eaglercraft.v1_8.internal.PlatformApplication;
 import net.lax1dude.eaglercraft.v1_8.internal.PlatformWebRTC;
 import net.lax1dude.eaglercraft.v1_8.sp.relay.RelayManager;
 import net.lax1dude.eaglercraft.v1_8.sp.relay.RelayServerSocket;
-import net.lax1dude.eaglercraft.v1_8.sp.relay.pkt.IPacket00Handshake;
+import net.lax1dude.eaglercraft.v1_8.sp.relay.pkt.RelayPacket00Handshake;
 import net.minecraft.client.Minecraft;
 
 /**
@@ -46,7 +46,7 @@ public class RelayUpdateChecker {
 		
 	}
 
-	private static final List<RelayEntry> relaysList = new ArrayList();
+	private static final List<RelayEntry> relaysList = new ArrayList<>();
 
 	private static long lastUpdateCheck = -1l;
 	private static boolean hasInit = false;
@@ -74,7 +74,8 @@ public class RelayUpdateChecker {
 		}
 		long millis = System.currentTimeMillis();
 		Minecraft mc = Minecraft.getMinecraft();
-		if((mc.theWorld == null || mc.isSingleplayer()) && millis - lastUpdateCheck > updateCheckRate) {
+		if ((mc.theWorld == null || mc.isSingleplayer())
+				&& (millis - lastUpdateCheck > updateCheckRate || millis + 60000l < lastUpdateCheck)) {
 			lastUpdateCheck = millis;
 			try {
 				EaglerOutputStream bao = new EaglerOutputStream(8);
@@ -120,12 +121,13 @@ public class RelayUpdateChecker {
 
 	private static void updateRelay(RelayEntry socket) {
 		try {
+			socket.currentSocket.update();
 			if(socket.currentSocket.isClosed()) {
 				socket.currentSocket = null;
 			}else if(socket.currentSocket.isOpen()) {
 				if(!socket.handshake) {
 					socket.handshake = true;
-					socket.currentSocket.writePacket(new IPacket00Handshake(0x02, RelayManager.preferredRelayVersion, magic));
+					socket.currentSocket.writePacket(new RelayPacket00Handshake(0x02, RelayManager.preferredRelayVersion, magic));
 				}else {
 					// close immediately
 					if(socket.currentSocket.nextPacket() != null) {
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/update/UpdateDataObj.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/update/UpdateDataObj.java
new file mode 100644
index 00000000..e039d16b
--- /dev/null
+++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/update/UpdateDataObj.java
@@ -0,0 +1,28 @@
+package net.lax1dude.eaglercraft.v1_8.update;
+
+/**
+ * Copyright (c) 2024 lax1dude. All Rights Reserved.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ * 
+ */
+public class UpdateDataObj {
+
+	public final UpdateCertificate clientSignature;
+	public final byte[] clientBundle;
+
+	public UpdateDataObj(UpdateCertificate clientSignature, byte[] clientBundle) {
+		this.clientSignature = clientSignature;
+		this.clientBundle = clientBundle;
+	}
+
+}
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/relay/pkt/IPacket06ClientFailure.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/update/UpdateResultObj.java
similarity index 53%
rename from sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/relay/pkt/IPacket06ClientFailure.java
rename to sources/main/java/net/lax1dude/eaglercraft/v1_8/update/UpdateResultObj.java
index 9506c373..238d8183 100644
--- a/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/relay/pkt/IPacket06ClientFailure.java
+++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/update/UpdateResultObj.java
@@ -1,11 +1,7 @@
-package net.lax1dude.eaglercraft.v1_8.sp.relay.pkt;
-
-import java.io.DataInputStream;
-import java.io.DataOutputStream;
-import java.io.IOException;
+package net.lax1dude.eaglercraft.v1_8.update;
 
 /**
- * Copyright (c) 2022 lax1dude. All Rights Reserved.
+ * Copyright (c) 2024 lax1dude. All Rights Reserved.
  * 
  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
@@ -19,27 +15,34 @@ import java.io.IOException;
  * POSSIBILITY OF SUCH DAMAGE.
  * 
  */
-public class IPacket06ClientFailure extends IPacket {
-	
-	public String clientId;
-	
-	public IPacket06ClientFailure() {
-	}
-	
-	public IPacket06ClientFailure(String clientId) {
-		this.clientId = clientId;
-	}
-	
-	public void read(DataInputStream input) throws IOException {
-		clientId = readASCII8(input);
+public class UpdateResultObj {
+
+	private final boolean success;
+	private final Object dataObj;
+
+	private UpdateResultObj(boolean success, Object dataObj) {
+		this.success = success;
+		this.dataObj = dataObj;
 	}
 
-	public void write(DataOutputStream output) throws IOException {
-		writeASCII8(output, clientId);
+	public static UpdateResultObj createSuccess(UpdateDataObj dataObj) {
+		return new UpdateResultObj(true, dataObj);
 	}
-	
-	public int packetLength() {
-		return 1 + clientId.length();
+
+	public static UpdateResultObj createFailure(String dataObj) {
+		return new UpdateResultObj(false, dataObj);
 	}
-	
+
+	public boolean isSuccess() {
+		return success;
+	}
+
+	public UpdateDataObj getSuccess() {
+		return (UpdateDataObj)dataObj;
+	}
+
+	public String getFailure() {
+		return (String)dataObj;
+	}
+
 }
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/update/UpdateService.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/update/UpdateService.java
index 32c1b68d..0e7216d6 100644
--- a/sources/main/java/net/lax1dude/eaglercraft/v1_8/update/UpdateService.java
+++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/update/UpdateService.java
@@ -37,9 +37,9 @@ public class UpdateService {
 	private static boolean isBundleDataValid = false;
 
 	private static UpdateCertificate latestUpdateFound = null;
-	private static final Set<UpdateCertificate> availableUpdates = new HashSet();
-	private static final Set<RawKnownCertHolder> fastUpdateKnownCheckSet = new HashSet();
-	private static final Set<UpdateCertificate> dismissedUpdates = new HashSet();
+	private static final Set<UpdateCertificate> availableUpdates = new HashSet<>();
+	private static final Set<RawKnownCertHolder> fastUpdateKnownCheckSet = new HashSet<>();
+	private static final Set<UpdateCertificate> dismissedUpdates = new HashSet<>();
 
 	private static class RawKnownCertHolder {
 
@@ -50,7 +50,7 @@ public class UpdateService {
 		public RawKnownCertHolder(byte[] data) {
 			this.data = data;
 			this.hashcode = Arrays.hashCode(data);
-			this.age = System.currentTimeMillis();
+			this.age = EagRuntime.steadyTimeMillis();
 		}
 
 		public int hashCode() {
@@ -176,7 +176,7 @@ public class UpdateService {
 
 	private static void freeMemory() {
 		if(fastUpdateKnownCheckSet.size() > 127) {
-			List<RawKnownCertHolder> lst = new ArrayList(fastUpdateKnownCheckSet);
+			List<RawKnownCertHolder> lst = new ArrayList<>(fastUpdateKnownCheckSet);
 			fastUpdateKnownCheckSet.clear();
 			lst.sort((c1, c2) -> { return (int)(c2.age - c1.age); });
 			for(int i = 0; i < 64; ++i) {
@@ -193,6 +193,15 @@ public class UpdateService {
 		return PlatformUpdateSvc.getUpdatingStatus();
 	}
 
+	public static UpdateResultObj getUpdateResult() {
+		return PlatformUpdateSvc.getUpdateResult();
+	}
+
+	public static void installSignedClient(UpdateCertificate clientCert, byte[] clientPayload, boolean setDefault,
+			boolean setTimeout) {
+		PlatformUpdateSvc.installSignedClient(clientCert, clientPayload, setDefault, setTimeout);
+	}
+
 	public static UpdateCertificate getLatestUpdateFound() {
 		return latestUpdateFound;
 	}
@@ -221,6 +230,10 @@ public class UpdateService {
 		}
 	}
 
+	public static void quine(UpdateCertificate cert, byte[] payload) {
+		PlatformUpdateSvc.quine(cert, payload);
+	}
+
 	public static boolean shouldDisableDownloadButton() {
 		return EagRuntime.getConfiguration().getDownloadOfflineButtonLink() == null && (myUpdateCert == null
 				|| (getClientBundleData() == null && PlatformUpdateSvc.getUpdatingStatus().isBusy));
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/voice/ExpiringSet.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/voice/ExpiringSet.java
index 79af3a27..a3228f67 100644
--- a/sources/main/java/net/lax1dude/eaglercraft/v1_8/voice/ExpiringSet.java
+++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/voice/ExpiringSet.java
@@ -5,6 +5,8 @@ import java.util.HashSet;
 import java.util.Iterator;
 import java.util.Map;
 
+import net.lax1dude.eaglercraft.v1_8.EagRuntime;
+
 /**
  * Copyright (c) 2022 ayunami2000. All Rights Reserved.
  * 
@@ -42,7 +44,7 @@ public class ExpiringSet<T> extends HashSet<T> {
 
     public void checkForExpirations() {
         Iterator<T> iterator = this.timestamps.keySet().iterator();
-        long now = System.currentTimeMillis();
+        long now = EagRuntime.steadyTimeMillis();
         while (iterator.hasNext()) {
             T element = iterator.next();
             if (super.contains(element)) {
@@ -61,7 +63,7 @@ public class ExpiringSet<T> extends HashSet<T> {
     public boolean add(T o) {
         checkForExpirations();
         boolean success = super.add(o);
-        if (success) timestamps.put(o, System.currentTimeMillis());
+        if (success) timestamps.put(o, EagRuntime.steadyTimeMillis());
         return success;
     }
 
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/voice/GuiVoiceMenu.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/voice/GuiVoiceMenu.java
index 2794a68d..caa72908 100644
--- a/sources/main/java/net/lax1dude/eaglercraft/v1_8/voice/GuiVoiceMenu.java
+++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/voice/GuiVoiceMenu.java
@@ -5,8 +5,10 @@ import static net.lax1dude.eaglercraft.v1_8.opengl.RealOpenGLEnums.*;
 import java.util.List;
 import java.util.Set;
 
+import net.lax1dude.eaglercraft.v1_8.EagRuntime;
 import net.lax1dude.eaglercraft.v1_8.EaglercraftUUID;
 import net.lax1dude.eaglercraft.v1_8.Keyboard;
+import net.lax1dude.eaglercraft.v1_8.PointerInputAbstraction;
 import net.lax1dude.eaglercraft.v1_8.opengl.GlStateManager;
 import net.lax1dude.eaglercraft.v1_8.sp.gui.GuiSlider2;
 import net.minecraft.client.Minecraft;
@@ -124,17 +126,8 @@ public class GuiVoiceMenu extends Gui {
 	
 	public void initGui() {
 		this.sliderBlocks = new GuiSlider2(-1, (width - 150) / 2, height / 3 + 20, 150, 20, (VoiceClientController.getVoiceProximity() - 5) / 17.0f, 1.0f) {
-			public boolean mousePressed(Minecraft par1Minecraft, int par2, int par3) {
-				if(super.mousePressed(par1Minecraft, par2, par3)) {
-					this.displayString = "" + (int)((sliderValue * 17.0f) + 5.0f) + " Blocks";
-					return true;
-				}else {
-					return false;
-				}
-			}
-			public void mouseDragged(Minecraft par1Minecraft, int par2, int par3) {
-				super.mouseDragged(par1Minecraft, par2, par3);
-				this.displayString = "" + (int)((sliderValue * 17.0f) + 5.0f) + " Blocks";
+			protected String updateDisplayString() {
+				return (int)((sliderValue * 17.0f) + 5.0f) + " Blocks";
 			}
 		};
 		sliderBlocks.displayString = "" + VoiceClientController.getVoiceProximity() + " Blocks";
@@ -386,7 +379,7 @@ public class GuiVoiceMenu extends Gui {
 				}
 				
 			}else if(status == EnumVoiceChannelStatus.CONNECTING) {
-				float fadeTimer = MathHelper.sin((float)((System.currentTimeMillis() % 700l) * 0.0014d) * 3.14159f) * 0.35f + 0.3f;
+				float fadeTimer = MathHelper.sin((float)((EagRuntime.steadyTimeMillis() % 700l) * 0.0014d) * 3.14159f) * 0.35f + 0.3f;
 				txt = I18n.format("voice.connecting");
 				GlStateManager.enableBlend();
 				GlStateManager.blendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
@@ -487,7 +480,7 @@ public class GuiVoiceMenu extends Gui {
 			
 			drawNotice(I18n.format("voice.unsupportedWarning1"), false, I18n.format("voice.unsupportedWarning2"), I18n.format("voice.unsupportedWarning3"),
 					"", I18n.format("voice.unsupportedWarning4"), I18n.format("voice.unsupportedWarning5"), I18n.format("voice.unsupportedWarning6"),
-					I18n.format("voice.unsupportedWarning7"), I18n.format("voice.unsupportedWarning8"), I18n.format("voice.unsupportedWarning9"));
+					I18n.format("voice.unsupportedWarning7"), "", I18n.format("voice.unsupportedWarning8"), I18n.format("voice.unsupportedWarning9"));
 			
 			noticeContinueButton.visible = true;
 			noticeCancelButton.visible = false;
@@ -495,8 +488,7 @@ public class GuiVoiceMenu extends Gui {
 			
 			drawNotice(I18n.format("voice.ipGrabWarning1"), true, I18n.format("voice.ipGrabWarning2"), I18n.format("voice.ipGrabWarning3"),
 					I18n.format("voice.ipGrabWarning4"), "", I18n.format("voice.ipGrabWarning5"), I18n.format("voice.ipGrabWarning6"),
-					I18n.format("voice.ipGrabWarning7"), I18n.format("voice.ipGrabWarning8"), I18n.format("voice.ipGrabWarning9"),
-					I18n.format("voice.ipGrabWarning10"), I18n.format("voice.ipGrabWarning11"), I18n.format("voice.ipGrabWarning12"));
+					I18n.format("voice.ipGrabWarning7"));
 			
 			noticeContinueButton.visible = true;
 			noticeCancelButton.visible = true;
@@ -590,17 +582,21 @@ public class GuiVoiceMenu extends Gui {
 	}
 	
 	public void mouseReleased(int par1, int par2, int par3) {
-		applyRadiusButton.mouseReleased(par1, par2);
-		applyVolumeButton.mouseReleased(par1, par2);
-		noticeContinueButton.mouseReleased(par1, par2);
-		noticeCancelButton.mouseReleased(par1, par2);
+		if(par3 != 0 && par3 != 12345) return;
+		boolean touchMode = PointerInputAbstraction.isTouchMode();
+		if(!touchMode || par3 == 0) {
+			applyRadiusButton.mouseReleased(par1, par2);
+			applyVolumeButton.mouseReleased(par1, par2);
+			noticeContinueButton.mouseReleased(par1, par2);
+			noticeCancelButton.mouseReleased(par1, par2);
+		}
 		if(showSliderBlocks || showSliderVolume) {
 			if(showSliderBlocks) {
-				if(par3 == 0) {
+				if(!touchMode || par3 == 12345) {
 					sliderBlocks.mouseReleased(par1, par2);
 				}
 			}else if(showSliderVolume) {
-				if(par3 == 0) {
+				if(!touchMode || par3 == 12345) {
 					sliderListenVolume.mouseReleased(par1, par2);
 					sliderSpeakVolume.mouseReleased(par1, par2);
 				}
@@ -624,19 +620,23 @@ public class GuiVoiceMenu extends Gui {
 	}
 	
 	public void mouseClicked(int mx, int my, int button) {
+		if(button != 0 && button != 12345) return;
+		boolean touchMode = PointerInputAbstraction.isTouchMode();
 		if(showSliderBlocks || showSliderVolume || showPTTKeyConfig || showingCompatWarning || showingTrackingWarning) {
 			if(showSliderBlocks) {
-				sliderBlocks.mousePressed(mc, mx, my);
+				if(!touchMode || button == 12345) {
+					sliderBlocks.mousePressed(mc, mx, my);
+				}
 			}else if(showSliderVolume) {
-				sliderListenVolume.mousePressed(mc, mx, my);
-				sliderSpeakVolume.mousePressed(mc, mx, my);
-			}
-			if(button == 0) {
-				if(applyRadiusButton.mousePressed(mc, mx, my)) actionPerformed(applyRadiusButton);
-				if(applyVolumeButton.mousePressed(mc, mx, my)) actionPerformed(applyVolumeButton);
-				if(noticeContinueButton.mousePressed(mc, mx, my)) actionPerformed(noticeContinueButton);
-				if(noticeCancelButton.mousePressed(mc, mx, my)) actionPerformed(noticeCancelButton);
+				if(!touchMode || button == 12345) {
+					sliderListenVolume.mousePressed(mc, mx, my);
+					sliderSpeakVolume.mousePressed(mc, mx, my);
+				}
 			}
+			if((!touchMode || button == 0) && applyRadiusButton.mousePressed(mc, mx, my)) actionPerformed(applyRadiusButton);
+			if((!touchMode || button == 0) && applyVolumeButton.mousePressed(mc, mx, my)) actionPerformed(applyVolumeButton);
+			if((!touchMode || button == 0) && noticeContinueButton.mousePressed(mc, mx, my)) actionPerformed(noticeContinueButton);
+			if((!touchMode || button == 0) && noticeCancelButton.mousePressed(mc, mx, my)) actionPerformed(noticeCancelButton);
 			throw new AbortedException();
 		}
 		
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/voice/GuiVoiceOverlay.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/voice/GuiVoiceOverlay.java
index 2621c60b..b6534cb6 100644
--- a/sources/main/java/net/lax1dude/eaglercraft/v1_8/voice/GuiVoiceOverlay.java
+++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/voice/GuiVoiceOverlay.java
@@ -6,6 +6,7 @@ import java.util.ArrayList;
 import java.util.List;
 import java.util.Set;
 
+import net.lax1dude.eaglercraft.v1_8.EagRuntime;
 import net.lax1dude.eaglercraft.v1_8.EaglercraftUUID;
 import net.lax1dude.eaglercraft.v1_8.Keyboard;
 import net.lax1dude.eaglercraft.v1_8.opengl.GlStateManager;
@@ -82,7 +83,7 @@ public class GuiVoiceOverlay extends Gui {
 			mc.getTextureManager().bindTexture(voiceGuiIcons);
 			
 			if((mc.currentScreen == null || !mc.currentScreen.blockPTTKey()) && Keyboard.isKeyDown(mc.gameSettings.voicePTTKey)) {
-				long millis = System.currentTimeMillis();
+				long millis = EagRuntime.steadyTimeMillis();
 				if(pttTimer == 0l) {
 					pttTimer = millis;
 				}
@@ -118,7 +119,7 @@ public class GuiVoiceOverlay extends Gui {
 					Set<EaglercraftUUID> speakers = VoiceClientController.getVoiceSpeaking();
 					Set<EaglercraftUUID> muted = VoiceClientController.getVoiceMuted();
 					
-					List<EaglercraftUUID> listenerList = new ArrayList();
+					List<EaglercraftUUID> listenerList = new ArrayList<>();
 					listenerList.addAll(listeners);
 					listenerList.removeAll(muted);
 					
@@ -145,7 +146,7 @@ public class GuiVoiceOverlay extends Gui {
 						hh -= 15;
 					}
 					
-					List<String> listenerListStr = new ArrayList(Math.min(5, listenerList.size()));
+					List<String> listenerListStr = new ArrayList<>(Math.min(5, listenerList.size()));
 					
 					int left = 50;
 					for(int i = 0, l = listenerList.size(); i < l && i < 5; ++i) {
@@ -196,7 +197,7 @@ public class GuiVoiceOverlay extends Gui {
 				Set<EaglercraftUUID> speakers = VoiceClientController.getVoiceSpeaking();
 				Set<EaglercraftUUID> muted = VoiceClientController.getVoiceMuted();
 				
-				List<EaglercraftUUID> listenerList = new ArrayList();
+				List<EaglercraftUUID> listenerList = new ArrayList<>();
 				listenerList.addAll(speakers);
 				listenerList.removeAll(muted);
 				
@@ -209,7 +210,7 @@ public class GuiVoiceOverlay extends Gui {
 					hh -= 15;
 				}
 				
-				List<String> listenerListStr = new ArrayList(Math.min(5, listenerList.size()));
+				List<String> listenerListStr = new ArrayList<>(Math.min(5, listenerList.size()));
 				
 				int left = 50;
 				for(int i = 0, l = listenerList.size(); i < l && i < 5; ++i) {
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/voice/VoiceClientController.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/voice/VoiceClientController.java
index 5e3dc801..4e177ad1 100644
--- a/sources/main/java/net/lax1dude/eaglercraft/v1_8/voice/VoiceClientController.java
+++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/voice/VoiceClientController.java
@@ -1,6 +1,7 @@
 package net.lax1dude.eaglercraft.v1_8.voice;
 
 import java.util.ArrayList;
+import java.util.Collection;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
@@ -16,9 +17,11 @@ import net.lax1dude.eaglercraft.v1_8.internal.PlatformVoiceClient;
 import net.lax1dude.eaglercraft.v1_8.log4j.LogManager;
 import net.lax1dude.eaglercraft.v1_8.log4j.Logger;
 import net.lax1dude.eaglercraft.v1_8.profile.EaglerProfile;
+import net.lax1dude.eaglercraft.v1_8.socket.protocol.pkt.GameMessagePacket;
+import net.lax1dude.eaglercraft.v1_8.socket.protocol.pkt.client.*;
+import net.lax1dude.eaglercraft.v1_8.socket.protocol.pkt.server.SPacketVoiceSignalGlobalEAG;
 import net.minecraft.client.Minecraft;
 import net.minecraft.entity.player.EntityPlayer;
-import net.minecraft.network.PacketBuffer;
 
 /**
  * Copyright (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved.
@@ -43,7 +46,8 @@ public class VoiceClientController {
 
 	private static boolean clientSupport = false;
 	private static boolean serverSupport = false;
-	private static Consumer<PacketBuffer> packetSendCallback = null;
+	private static Consumer<GameMessagePacket> packetSendCallback = null;
+	private static int protocolVersion = -1;
 	private static EnumVoiceChannelType voiceChannel = EnumVoiceChannelType.NONE;
 	private static final HashSet<EaglercraftUUID> nearbyPlayers = new HashSet<>();
 	private static final ExpiringSet<EaglercraftUUID> recentlyNearbyPlayers = new ExpiringSet<>(5000, uuid -> {
@@ -71,17 +75,14 @@ public class VoiceClientController {
 		return serverSupport;
 	}
 
-	public static void initializeVoiceClient(Consumer<PacketBuffer> signalSendCallbackIn) {
+	public static void initializeVoiceClient(Consumer<GameMessagePacket> signalSendCallbackIn, int proto) {
 		packetSendCallback = signalSendCallbackIn;
+		protocolVersion = proto;
 		uuidToNameLookup.clear();
 		if (getVoiceChannel() != EnumVoiceChannelType.NONE) sendInitialVoice();
 	}
 
-	public static void handleVoiceSignalPacket(PacketBuffer packetData) {
-		VoiceSignalPackets.handleVoiceSignal(packetData);
-	}
-
-	static void handleVoiceSignalPacketTypeGlobal(EaglercraftUUID[] voicePlayers, String[] voiceNames) {
+	public static void handleVoiceSignalPacketTypeGlobal(EaglercraftUUID[] voicePlayers, String[] voiceNames) {
 		uuidToNameLookup.clear();
 		for (int i = 0; i < voicePlayers.length; i++) {
 			if(voiceNames != null) {
@@ -91,6 +92,17 @@ public class VoiceClientController {
 		}
 	}
 
+	public static void handleVoiceSignalPacketTypeGlobalNew(Collection<SPacketVoiceSignalGlobalEAG.UserData> voicePlayers) {
+		uuidToNameLookup.clear();
+		for (SPacketVoiceSignalGlobalEAG.UserData player : voicePlayers) {
+			EaglercraftUUID uuid = new EaglercraftUUID(player.uuidMost, player.uuidLeast);
+			if(player.username != null) {
+				uuidToNameLookup.put(uuid, player.username);
+			}
+			sendPacketRequestIfNeeded(uuid);
+		}
+	}
+
 	public static void handleServerDisconnect() {
 		if(!isClientSupported()) return;
 		serverSupport = false;
@@ -110,7 +122,7 @@ public class VoiceClientController {
 		activateVoice(false);
 	}
 
-	static void handleVoiceSignalPacketTypeAllowed(boolean voiceAvailableStat, String[] servs) {
+	public static void handleVoiceSignalPacketTypeAllowed(boolean voiceAvailableStat, String[] servs) {
 		serverSupport = voiceAvailableStat;
 		PlatformVoiceClient.setICEServers(servs);
 		if(isSupported()) {
@@ -120,23 +132,23 @@ public class VoiceClientController {
 		}
 	}
 
-	static void handleVoiceSignalPacketTypeConnect(EaglercraftUUID user, boolean offer) {
+	public static void handleVoiceSignalPacketTypeConnect(EaglercraftUUID user, boolean offer) {
 		PlatformVoiceClient.signalConnect(user, offer);
 	}
 
-	static void handleVoiceSignalPacketTypeConnectAnnounce(EaglercraftUUID user) {
+	public static void handleVoiceSignalPacketTypeConnectAnnounce(EaglercraftUUID user) {
 		sendPacketRequest(user);
 	}
 
-	static void handleVoiceSignalPacketTypeDisconnect(EaglercraftUUID user) {
+	public static void handleVoiceSignalPacketTypeDisconnect(EaglercraftUUID user) {
 		PlatformVoiceClient.signalDisconnect(user, true);
 	}
 
-	static void handleVoiceSignalPacketTypeICECandidate(EaglercraftUUID user, String ice) {
+	public static void handleVoiceSignalPacketTypeICECandidate(EaglercraftUUID user, String ice) {
 		PlatformVoiceClient.signalICECandidate(user, ice);
 	}
 
-	static void handleVoiceSignalPacketTypeDescription(EaglercraftUUID user, String desc) {
+	public static void handleVoiceSignalPacketTypeDescription(EaglercraftUUID user, String desc) {
 		PlatformVoiceClient.signalDescription(user, desc);
 	}
 
@@ -211,7 +223,7 @@ public class VoiceClientController {
 			for (EaglercraftUUID uuid : antiConcurrentModificationUUIDs) {
 				PlatformVoiceClient.signalDisconnect(uuid, false);
 			}
-			sendPacketDisconnect(null);
+			sendPacketDisconnect();
 			activateVoice(false);
 		} else if (voiceChannel == EnumVoiceChannelType.PROXIMITY) {
 			for (EaglercraftUUID uuid : nearbyPlayers) {
@@ -222,7 +234,7 @@ public class VoiceClientController {
 			}
 			nearbyPlayers.clear();
 			recentlyNearbyPlayers.clear();
-			sendPacketDisconnect(null);
+			sendPacketDisconnect();
 		} else if(voiceChannel == EnumVoiceChannelType.GLOBAL) {
 			Set<EaglercraftUUID> antiConcurrentModificationUUIDs = new HashSet<>(listeningSet);
 			antiConcurrentModificationUUIDs.removeAll(nearbyPlayers);
@@ -230,7 +242,7 @@ public class VoiceClientController {
 			for (EaglercraftUUID uuid : antiConcurrentModificationUUIDs) {
 				PlatformVoiceClient.signalDisconnect(uuid, false);
 			}
-			sendPacketDisconnect(null);
+			sendPacketDisconnect();
 		}
 		voiceChannel = channel;
 		if (channel != EnumVoiceChannelType.NONE) {
@@ -340,23 +352,35 @@ public class VoiceClientController {
 	}
 
 	public static void sendPacketICE(EaglercraftUUID peerId, String candidate) {
-		packetSendCallback.accept(VoiceSignalPackets.makeVoiceSignalPacketICE(peerId, candidate));
+		packetSendCallback.accept(new CPacketVoiceSignalICEEAG(peerId.msb, peerId.lsb, candidate));
 	}
 
 	public static void sendPacketDesc(EaglercraftUUID peerId, String desc) {
-		packetSendCallback.accept(VoiceSignalPackets.makeVoiceSignalPacketDesc(peerId, desc));
+		packetSendCallback.accept(new CPacketVoiceSignalDescEAG(peerId.msb, peerId.lsb, desc));
 	}
 
-	public static void sendPacketDisconnect(EaglercraftUUID peerId) {
-		packetSendCallback.accept(VoiceSignalPackets.makeVoiceSignalPacketDisconnect(peerId));
+	public static void sendPacketDisconnect() {
+		if(protocolVersion <= 3) {
+			packetSendCallback.accept(new CPacketVoiceSignalDisconnectV3EAG());
+		}else {
+			packetSendCallback.accept(new CPacketVoiceSignalDisconnectV4EAG());
+		}
+	}
+
+	public static void sendPacketDisconnectPeer(EaglercraftUUID peerId) {
+		if(protocolVersion <= 3) {
+			packetSendCallback.accept(new CPacketVoiceSignalDisconnectV3EAG(true, peerId.msb, peerId.lsb));
+		}else {
+			packetSendCallback.accept(new CPacketVoiceSignalDisconnectPeerV4EAG(peerId.msb, peerId.lsb));
+		}
 	}
 
 	public static void sendPacketConnect() {
-		packetSendCallback.accept(VoiceSignalPackets.makeVoiceSignalPacketConnect());
+		packetSendCallback.accept(new CPacketVoiceSignalConnectEAG());
 	}
 
 	public static void sendPacketRequest(EaglercraftUUID peerId) {
-		packetSendCallback.accept(VoiceSignalPackets.makeVoiceSignalPacketRequest(peerId));
+		packetSendCallback.accept(new CPacketVoiceSignalRequestEAG(peerId.msb, peerId.lsb));
 	}
 
 	private static void sendPacketRequestIfNeeded(EaglercraftUUID uuid) {
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/voice/VoiceSignalPackets.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/voice/VoiceSignalPackets.java
deleted file mode 100644
index 07643a8b..00000000
--- a/sources/main/java/net/lax1dude/eaglercraft/v1_8/voice/VoiceSignalPackets.java
+++ /dev/null
@@ -1,142 +0,0 @@
-package net.lax1dude.eaglercraft.v1_8.voice;
-
-import java.nio.charset.StandardCharsets;
-
-import net.lax1dude.eaglercraft.v1_8.EaglercraftUUID;
-import net.lax1dude.eaglercraft.v1_8.netty.Unpooled;
-import net.minecraft.network.PacketBuffer;
-
-/**
- * Copyright (c) 2024 lax1dude, ayunami2000. All Rights Reserved.
- * 
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
- * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- * 
- */
-public class VoiceSignalPackets {
-
-	static final int VOICE_SIGNAL_ALLOWED = 0;
-	static final int VOICE_SIGNAL_REQUEST = 0;
-	static final int VOICE_SIGNAL_CONNECT = 1;
-	static final int VOICE_SIGNAL_DISCONNECT = 2;
-	static final int VOICE_SIGNAL_ICE = 3;
-	static final int VOICE_SIGNAL_DESC = 4;
-	static final int VOICE_SIGNAL_GLOBAL = 5;
-
-	static void handleVoiceSignal(PacketBuffer streamIn) {
-		try {
-			int sig = streamIn.readUnsignedByte();
-			switch(sig) {
-				case VOICE_SIGNAL_ALLOWED: {
-					boolean voiceAvailableStat = streamIn.readUnsignedByte() == 1;
-					String[] servs = null;
-					if(voiceAvailableStat) {
-						servs = new String[streamIn.readVarIntFromBuffer()];
-						for(int i = 0; i < servs.length; i++) {
-							servs[i] = streamIn.readStringFromBuffer(1024);
-						}
-					}
-					VoiceClientController.handleVoiceSignalPacketTypeAllowed(voiceAvailableStat, servs);
-					break;
-				}
-				case VOICE_SIGNAL_GLOBAL: {
-					if (VoiceClientController.getVoiceChannel() != EnumVoiceChannelType.GLOBAL) return;
-					EaglercraftUUID[] voiceIds = new EaglercraftUUID[streamIn.readVarIntFromBuffer()];
-					for(int i = 0; i < voiceIds.length; i++) {
-						voiceIds[i] = streamIn.readUuid();
-					}
-					String[] voiceNames = null;
-					if (streamIn.isReadable()) {
-						voiceNames = new String[voiceIds.length];
-						for(int i = 0; i < voiceNames.length; i++) {
-							voiceNames[i] = streamIn.readStringFromBuffer(16);
-						}
-					}
-					VoiceClientController.handleVoiceSignalPacketTypeGlobal(voiceIds, voiceNames);
-					break;
-				}
-				case VOICE_SIGNAL_CONNECT: {
-					EaglercraftUUID uuid = streamIn.readUuid();
-					if (streamIn.isReadable()) {
-						VoiceClientController.handleVoiceSignalPacketTypeConnect(uuid, streamIn.readBoolean());
-					} else if (VoiceClientController.getVoiceChannel() != EnumVoiceChannelType.PROXIMITY || VoiceClientController.getVoiceListening().contains(uuid)) {
-						VoiceClientController.handleVoiceSignalPacketTypeConnectAnnounce(uuid);
-					}
-					break;
-				}
-				case VOICE_SIGNAL_DISCONNECT: {
-					VoiceClientController.handleVoiceSignalPacketTypeDisconnect(streamIn.readableBytes() > 0 ? streamIn.readUuid() : null);
-					break;
-				}
-				case VOICE_SIGNAL_ICE: {
-					VoiceClientController.handleVoiceSignalPacketTypeICECandidate(streamIn.readUuid(), streamIn.readStringFromBuffer(32767));
-					break;
-				}
-				case VOICE_SIGNAL_DESC: {
-					VoiceClientController.handleVoiceSignalPacketTypeDescription(streamIn.readUuid(), streamIn.readStringFromBuffer(32767));
-					break;
-				}
-				default: {
-					VoiceClientController.logger.error("Unknown voice signal packet '{}'!", sig);
-					break;
-				}
-			}
-		}catch(Throwable ex) {
-			VoiceClientController.logger.error("Failed to handle signal packet!");
-			VoiceClientController.logger.error(ex);
-		}
-	}
-
-	static PacketBuffer makeVoiceSignalPacketRequest(EaglercraftUUID user) {
-		PacketBuffer ret = new PacketBuffer(Unpooled.buffer(17, 17));
-		ret.writeByte(VOICE_SIGNAL_REQUEST);
-		ret.writeUuid(user);
-		return ret;
-	}
-
-	static PacketBuffer makeVoiceSignalPacketICE(EaglercraftUUID user, String icePacket) {
-		byte[] str = icePacket.getBytes(StandardCharsets.UTF_8);
-		int estLen = 17 + PacketBuffer.getVarIntSize(str.length) + str.length;
-		PacketBuffer ret = new PacketBuffer(Unpooled.buffer(estLen, estLen));
-		ret.writeByte(VOICE_SIGNAL_ICE);
-		ret.writeUuid(user);
-		ret.writeByteArray(str);
-		return ret;
-	}
-
-	static PacketBuffer makeVoiceSignalPacketDesc(EaglercraftUUID user, String descPacket) {
-		byte[] str = descPacket.getBytes(StandardCharsets.UTF_8);
-		int estLen = 17 + PacketBuffer.getVarIntSize(str.length) + str.length;
-		PacketBuffer ret = new PacketBuffer(Unpooled.buffer(estLen, estLen));
-		ret.writeByte(VOICE_SIGNAL_DESC);
-		ret.writeUuid(user);
-		ret.writeByteArray(str);
-		return ret;
-	}
-
-	static PacketBuffer makeVoiceSignalPacketDisconnect(EaglercraftUUID user) {
-		if (user == null) {
-			PacketBuffer ret = new PacketBuffer(Unpooled.buffer(1, 1));
-			ret.writeByte(VOICE_SIGNAL_DISCONNECT);
-			return ret;
-		}
-		PacketBuffer ret = new PacketBuffer(Unpooled.buffer(17, 17));
-		ret.writeByte(VOICE_SIGNAL_DISCONNECT);
-		ret.writeUuid(user);
-		return ret;
-	}
-
-	public static PacketBuffer makeVoiceSignalPacketConnect() {
-		PacketBuffer ret = new PacketBuffer(Unpooled.buffer(1, 1));
-		ret.writeByte(VOICE_SIGNAL_CONNECT);
-		return ret;
-	}
-}
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/voice/VoiceTagRenderer.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/voice/VoiceTagRenderer.java
index 5c047152..b04bf214 100644
--- a/sources/main/java/net/lax1dude/eaglercraft/v1_8/voice/VoiceTagRenderer.java
+++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/voice/VoiceTagRenderer.java
@@ -33,7 +33,7 @@ public class VoiceTagRenderer {
 
 	private static final ResourceLocation voiceGuiIcons = new ResourceLocation("eagler:gui/eagler_gui.png");
 
-	private static final Set<EaglercraftUUID> voiceTagsDrawnThisFrame = new HashSet();
+	private static final Set<EaglercraftUUID> voiceTagsDrawnThisFrame = new HashSet<>();
 
 	public static void renderVoiceNameTag(Minecraft mc, EntityOtherPlayerMP player, int offset) {
 		EaglercraftUUID uuid = player.getUniqueID();
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/webview/GuiScreenPhishingWaring.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/webview/GuiScreenPhishingWaring.java
new file mode 100644
index 00000000..e96895fa
--- /dev/null
+++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/webview/GuiScreenPhishingWaring.java
@@ -0,0 +1,104 @@
+package net.lax1dude.eaglercraft.v1_8.webview;
+
+import net.lax1dude.eaglercraft.v1_8.opengl.GlStateManager;
+import net.minecraft.client.audio.PositionedSoundRecord;
+import net.minecraft.client.gui.GuiButton;
+import net.minecraft.client.gui.GuiScreen;
+import net.minecraft.client.resources.I18n;
+import net.minecraft.util.EnumChatFormatting;
+import net.minecraft.util.ResourceLocation;
+
+/**
+ * Copyright (c) 2024 lax1dude. All Rights Reserved.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ * 
+ */
+public class GuiScreenPhishingWaring extends GuiScreen {
+
+	public static boolean hasShownMessage = false;
+
+	private static final ResourceLocation beaconGuiTexture = new ResourceLocation("textures/gui/container/beacon.png");
+
+	private GuiScreen cont;
+	private boolean mouseOverCheck;
+	private boolean hasCheckedBox;
+
+	public GuiScreenPhishingWaring(GuiScreen cont) {
+		this.cont = cont;
+	}
+
+	public void initGui() {
+		this.buttonList.clear();
+		this.buttonList.add(new GuiButton(0, this.width / 2 - 100, this.height / 6 + 134, I18n.format("webviewPhishingWaring.continue")));
+	}
+
+	public void drawScreen(int mx, int my, float pt) {
+		this.drawDefaultBackground();
+		this.drawCenteredString(fontRendererObj, EnumChatFormatting.BOLD + I18n.format("webviewPhishingWaring.title"), this.width / 2, 70, 0xFF4444);
+		this.drawCenteredString(fontRendererObj, I18n.format("webviewPhishingWaring.text0"), this.width / 2, 90, 16777215);
+		this.drawCenteredString(fontRendererObj, I18n.format("webviewPhishingWaring.text1"), this.width / 2, 102, 16777215);
+		this.drawCenteredString(fontRendererObj, I18n.format("webviewPhishingWaring.text2"), this.width / 2, 114, 16777215);
+		
+		String dontShowAgain = I18n.format("webviewPhishingWaring.dontShowAgain");
+		int w = fontRendererObj.getStringWidth(dontShowAgain) + 20;
+		int ww = (this.width - w) / 2;
+		this.drawString(fontRendererObj, dontShowAgain, ww + 20, 137, 0xCCCCCC);
+		
+		mouseOverCheck = ww < mx && ww + 17 > mx && 133 < my && 150 > my;
+		
+		if(mouseOverCheck) {
+			GlStateManager.color(0.7f, 0.7f, 1.0f, 1.0f);
+		}else {
+			GlStateManager.color(0.6f, 0.6f, 0.6f, 1.0f);
+		}
+		
+		mc.getTextureManager().bindTexture(beaconGuiTexture);
+		
+		GlStateManager.pushMatrix();
+		GlStateManager.scale(0.75f, 0.75f, 0.75f);
+		drawTexturedModalRect(ww * 4 / 3, 133 * 4 / 3, 22, 219, 22, 22);
+		GlStateManager.popMatrix();
+		
+		if(hasCheckedBox) {
+			GlStateManager.pushMatrix();
+			GlStateManager.color(1.1f, 1.1f, 1.1f, 1.0f);
+			GlStateManager.translate(0.5f, 0.5f, 0.0f);
+			drawTexturedModalRect(ww, 133, 90, 222, 16, 16);
+			GlStateManager.popMatrix();
+		}
+		
+		super.drawScreen(mx, my, pt);
+	}
+
+	protected void actionPerformed(GuiButton par1GuiButton) {
+		if(par1GuiButton.id == 0) {
+			if(hasCheckedBox && !mc.gameSettings.hasHiddenPhishWarning) {
+				mc.gameSettings.hasHiddenPhishWarning = true;
+				mc.gameSettings.saveOptions();
+			}
+			hasShownMessage = true;
+			mc.displayGuiScreen(cont);
+		}
+	}
+
+	@Override
+	protected void mouseClicked(int mx, int my, int btn) {
+		if(btn == 0 && mouseOverCheck) {
+			hasCheckedBox = !hasCheckedBox;
+			mc.getSoundHandler().playSound(PositionedSoundRecord.create(new ResourceLocation("gui.button.press"), 1.0F));
+			return;
+		}
+		super.mouseClicked(mx, my, btn);
+	}
+
+}
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/webview/GuiScreenRecieveServerInfo.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/webview/GuiScreenRecieveServerInfo.java
new file mode 100644
index 00000000..995a35c0
--- /dev/null
+++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/webview/GuiScreenRecieveServerInfo.java
@@ -0,0 +1,203 @@
+package net.lax1dude.eaglercraft.v1_8.webview;
+
+import java.io.DataInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Arrays;
+
+import net.lax1dude.eaglercraft.v1_8.EaglerInputStream;
+import net.lax1dude.eaglercraft.v1_8.EaglerZLIB;
+import net.lax1dude.eaglercraft.v1_8.IOUtils;
+import net.lax1dude.eaglercraft.v1_8.crypto.SHA1Digest;
+import net.lax1dude.eaglercraft.v1_8.internal.WebViewOptions;
+import net.lax1dude.eaglercraft.v1_8.log4j.LogManager;
+import net.lax1dude.eaglercraft.v1_8.log4j.Logger;
+import net.lax1dude.eaglercraft.v1_8.minecraft.GuiScreenGenericErrorMessage;
+import net.lax1dude.eaglercraft.v1_8.opengl.GlStateManager;
+import net.lax1dude.eaglercraft.v1_8.opengl.WorldRenderer;
+import net.lax1dude.eaglercraft.v1_8.socket.protocol.pkt.client.CPacketRequestServerInfoV4EAG;
+import net.minecraft.client.gui.GuiButton;
+import net.minecraft.client.gui.GuiScreen;
+import net.minecraft.client.renderer.Tessellator;
+import net.minecraft.client.renderer.vertex.DefaultVertexFormats;
+import net.minecraft.client.resources.I18n;
+
+/**
+ * Copyright (c) 2024 lax1dude. All Rights Reserved.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ * 
+ */
+public class GuiScreenRecieveServerInfo extends GuiScreen {
+
+	private static final Logger logger = LogManager.getLogger("GuiScreenRecieveServerInfo");
+
+	protected final GuiScreen parent;
+	protected final byte[] expectHash;
+	protected int timer;
+	protected int timer2;
+	protected String statusString = "recieveServerInfo.checkingCache";
+
+	public GuiScreenRecieveServerInfo(GuiScreen parent, byte[] expectHash) {
+		this.parent = parent;
+		this.expectHash = expectHash;
+	}
+
+	public void initGui() {
+		this.buttonList.clear();
+		this.buttonList.add(new GuiButton(0, this.width / 2 - 100, this.height / 6 + 106, I18n.format("gui.cancel")));
+	}
+
+	public void drawScreen(int par1, int par2, float par3) {
+		this.drawDefaultBackground();
+		this.drawCenteredString(fontRendererObj, I18n.format("recieveServerInfo.title"), this.width / 2, 70, 11184810);
+		this.drawCenteredString(fontRendererObj, I18n.format(statusString), this.width / 2, 90, 16777215);
+		if(Arrays.equals(ServerInfoCache.chunkRecieveHash, expectHash) && ServerInfoCache.chunkFinalSize > 0) {
+			int progress = ServerInfoCache.chunkCurrentSize * 100 / ServerInfoCache.chunkFinalSize;
+			if(progress < 0) progress = 0;
+			if(progress > 100) progress = 100;
+			if(ServerInfoCache.hasLastChunk) {
+				progress = 100;
+			}
+			Tessellator tessellator = Tessellator.getInstance();
+			WorldRenderer worldrenderer = tessellator.getWorldRenderer();
+			byte b0 = 100;
+			byte b1 = 2;
+			int i1 = width / 2 - b0 / 2;
+			int j1 = 103;
+			GlStateManager.disableTexture2D();
+			worldrenderer.begin(7, DefaultVertexFormats.POSITION_COLOR);
+			worldrenderer.pos((double) i1, (double) j1, 0.0D).color(128, 128, 128, 255).endVertex();
+			worldrenderer.pos((double) i1, (double) (j1 + b1), 0.0D).color(128, 128, 128, 255).endVertex();
+			worldrenderer.pos((double) (i1 + b0), (double) (j1 + b1), 0.0D).color(128, 128, 128, 255)
+					.endVertex();
+			worldrenderer.pos((double) (i1 + b0), (double) j1, 0.0D).color(128, 128, 128, 255).endVertex();
+			worldrenderer.pos((double) i1, (double) j1, 0.0D).color(128, 255, 128, 255).endVertex();
+			worldrenderer.pos((double) i1, (double) (j1 + b1), 0.0D).color(128, 255, 128, 255).endVertex();
+			worldrenderer.pos((double) (i1 + progress), (double) (j1 + b1), 0.0D).color(128, 255, 128, 255)
+					.endVertex();
+			worldrenderer.pos((double) (i1 + progress), (double) j1, 0.0D).color(128, 255, 128, 255)
+					.endVertex();
+			tessellator.draw();
+			GlStateManager.enableTexture2D();
+		}
+		super.drawScreen(par1, par2, par3);
+	}
+
+	public void actionPerformed(GuiButton button) {
+		if(button.id == 0) {
+			mc.displayGuiScreen(parent);
+		}
+	}
+
+	public void updateScreen() {
+		if(mc.thePlayer == null) {
+			mc.displayGuiScreen(parent);
+			return;
+		}
+		++timer;
+		if(timer == 1) {
+			byte[] data = ServerInfoCache.loadFromCache(expectHash);
+			if(data != null) {
+				mc.displayGuiScreen(GuiScreenServerInfo.createForCurrentState(parent, data, WebViewOptions.getEmbedOriginUUID(expectHash)));
+			}else {
+				byte[] b = mc.thePlayer.sendQueue.cachedServerInfoData;
+				if(b != null) {
+					if(b.length == 0) {
+						mc.displayGuiScreen(new GuiScreenGenericErrorMessage("serverInfoFailure.title", "serverInfoFailure.desc", parent));
+					}else {
+						ServerInfoCache.storeInCache(expectHash, b);
+						mc.displayGuiScreen(GuiScreenServerInfo.createForCurrentState(parent, b, WebViewOptions.getEmbedOriginUUID(expectHash)));
+					}
+				}else {
+					statusString = "recieveServerInfo.contactingServer";
+					if(!mc.thePlayer.sendQueue.hasRequestedServerInfo) {
+						if(!ServerInfoCache.hasLastChunk || !Arrays.equals(ServerInfoCache.chunkRecieveHash, expectHash)) {
+							ServerInfoCache.clearDownload();
+							mc.thePlayer.sendQueue.sendEaglerMessage(new CPacketRequestServerInfoV4EAG(expectHash));
+							mc.thePlayer.sendQueue.hasRequestedServerInfo = true;
+						}
+					}
+				}
+			}
+		}else if(timer > 1) {
+			if(Arrays.equals(ServerInfoCache.chunkRecieveHash, expectHash)) {
+				if(ServerInfoCache.hasLastChunk) {
+					statusString = "recieveServerInfo.decompressing";
+					++timer2;
+					if(timer2 == 2) {
+						byte[] finalData = new byte[ServerInfoCache.chunkCurrentSize];
+						int i = 0;
+						for(byte[] b : ServerInfoCache.chunkRecieveBuffer) {
+							System.arraycopy(b, 0, finalData, i, b.length);
+							i += b.length;
+						}
+						if(i != ServerInfoCache.chunkCurrentSize) {
+							logger.error("An unknown error occured!");
+							mc.thePlayer.sendQueue.cachedServerInfoData = new byte[0];
+							mc.displayGuiScreen(new GuiScreenGenericErrorMessage("serverInfoFailure.title", "serverInfoFailure.desc", parent));
+							return;
+						}
+						ServerInfoCache.clearDownload();
+						try {
+							EaglerInputStream bis = new EaglerInputStream(finalData);
+							int finalSize = (new DataInputStream(bis)).readInt();
+							if(finalSize < 0) {
+								logger.error("The response data was corrupt, decompressed size is negative!");
+								mc.thePlayer.sendQueue.cachedServerInfoData = new byte[0];
+								mc.displayGuiScreen(new GuiScreenGenericErrorMessage("serverInfoFailure.title", "serverInfoFailure.desc", parent));
+								return;
+							}
+							if(finalSize > ServerInfoCache.CACHE_MAX_SIZE * 2) {
+								logger.error("Failed to decompress/verify server info response! Size is massive, {} " + finalSize + " bytes reported!");
+								logger.error("Aborting decompression. Rejoin the server to try again.");
+								mc.thePlayer.sendQueue.cachedServerInfoData = new byte[0];
+								mc.displayGuiScreen(new GuiScreenGenericErrorMessage("serverInfoFailure.title", "serverInfoFailure.desc", parent));
+								return;
+							}
+							byte[] decompressed = new byte[finalSize];
+							try(InputStream is = EaglerZLIB.newGZIPInputStream(bis)) {
+								IOUtils.readFully(is, decompressed);
+							}
+							SHA1Digest digest = new SHA1Digest();
+							digest.update(decompressed, 0, decompressed.length);
+							byte[] csum = new byte[20];
+							digest.doFinal(csum, 0);
+							if(Arrays.equals(csum, expectHash)) {
+								ServerInfoCache.storeInCache(csum, decompressed);
+								mc.thePlayer.sendQueue.cachedServerInfoData = decompressed;
+								mc.displayGuiScreen(GuiScreenServerInfo.createForCurrentState(parent, decompressed, WebViewOptions.getEmbedOriginUUID(expectHash)));
+							}else {
+								logger.error("The data recieved from the server did not have the correct SHA1 checksum! Rejoin the server to try again.");
+								mc.thePlayer.sendQueue.cachedServerInfoData = new byte[0];
+								mc.displayGuiScreen(new GuiScreenGenericErrorMessage("serverInfoFailure.title", "serverInfoFailure.desc", parent));
+							}
+						}catch(IOException ex) {
+							logger.error("Failed to decompress/verify server info response! Rejoin the server to try again.");
+							logger.error(ex);
+							mc.thePlayer.sendQueue.cachedServerInfoData = new byte[0];
+							mc.displayGuiScreen(new GuiScreenGenericErrorMessage("serverInfoFailure.title", "serverInfoFailure.desc", parent));
+						}
+					}
+				}else {
+					statusString = "recieveServerInfo.recievingData";
+				}
+			}else {
+				statusString = "recieveServerInfo.contactingServer";
+			}
+		}
+	}
+
+	protected boolean isPartOfPauseMenu() {
+		return true;
+	}
+}
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/webview/GuiScreenServerInfo.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/webview/GuiScreenServerInfo.java
new file mode 100644
index 00000000..b2a3e6bb
--- /dev/null
+++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/webview/GuiScreenServerInfo.java
@@ -0,0 +1,128 @@
+package net.lax1dude.eaglercraft.v1_8.webview;
+
+import java.net.URI;
+import java.net.URISyntaxException;
+
+import net.lax1dude.eaglercraft.v1_8.EaglercraftUUID;
+import net.lax1dude.eaglercraft.v1_8.PauseMenuCustomizeState;
+import net.lax1dude.eaglercraft.v1_8.internal.EnumWebViewContentMode;
+import net.lax1dude.eaglercraft.v1_8.internal.WebViewOptions;
+import net.lax1dude.eaglercraft.v1_8.log4j.LogManager;
+import net.lax1dude.eaglercraft.v1_8.log4j.Logger;
+import net.lax1dude.eaglercraft.v1_8.minecraft.GuiScreenGenericErrorMessage;
+import net.minecraft.client.gui.GuiButton;
+import net.minecraft.client.gui.GuiScreen;
+import net.minecraft.client.gui.ScaledResolution;
+import net.minecraft.client.resources.I18n;
+
+/**
+ * Copyright (c) 2024 lax1dude. All Rights Reserved.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ * 
+ */
+public class GuiScreenServerInfo extends GuiScreen {
+
+	private static final Logger logger = LogManager.getLogger("GuiScreenServerInfo");
+
+	private final GuiScreen parent;
+	private final WebViewOptions opts;
+	private boolean isShowing = false;
+
+	public GuiScreenServerInfo(GuiScreen parent, WebViewOptions opts) {
+		this.parent = parent;
+		this.opts = opts;
+	}
+
+	public static GuiScreen createForCurrentState(GuiScreen parent, String url) {
+		URI urlObj;
+		try {
+			urlObj = new URI(url);
+		}catch(URISyntaxException ex) {
+			logger.error("Refusing to iframe an invalid URL: {}", url);
+			logger.error(ex);
+			return new GuiScreenGenericErrorMessage("webviewInvalidURL.title", "webviewInvalidURL.desc", parent);
+		}
+		return createForCurrentState(parent, urlObj);
+	}
+
+	public static GuiScreen createForCurrentState(GuiScreen parent, URI url) {
+		boolean support = WebViewOverlayController.supported();
+		boolean fallbackSupport = WebViewOverlayController.fallbackSupported();
+		if(!support && !fallbackSupport) {
+			return new GuiScreenGenericErrorMessage("webviewNotSupported.title", "webviewNotSupported.desc", parent);
+		}
+		WebViewOptions opts = new WebViewOptions();
+		opts.contentMode = EnumWebViewContentMode.URL_BASED;
+		opts.url = url;
+		setupState(opts);
+		opts.permissionsOriginUUID = WebViewOptions.getURLOriginUUID(url);
+		return support ? new GuiScreenServerInfo(parent, opts) : new GuiScreenServerInfoDesktop(parent, opts);
+	}
+
+	public static GuiScreen createForCurrentState(GuiScreen parent, byte[] blob, EaglercraftUUID permissionsOriginUUID) {
+		boolean support = WebViewOverlayController.supported();
+		boolean fallbackSupport = WebViewOverlayController.fallbackSupported();
+		if(!support && !fallbackSupport) {
+			return new GuiScreenGenericErrorMessage("webviewNotSupported.title", "webviewNotSupported.desc", parent);
+		}
+		WebViewOptions opts = new WebViewOptions();
+		opts.contentMode = EnumWebViewContentMode.BLOB_BASED;
+		opts.blob = blob;
+		setupState(opts);
+		opts.permissionsOriginUUID = permissionsOriginUUID;
+		return support ? new GuiScreenServerInfo(parent, opts) : new GuiScreenServerInfoDesktop(parent, opts);
+	}
+
+	public static void setupState(WebViewOptions opts) {
+		opts.scriptEnabled = (PauseMenuCustomizeState.serverInfoEmbedPerms & PauseMenuCustomizeState.SERVER_INFO_EMBED_PERMS_JAVASCRIPT) != 0;
+		opts.strictCSPEnable = (PauseMenuCustomizeState.serverInfoEmbedPerms & PauseMenuCustomizeState.SERVER_INFO_EMBED_PERMS_STRICT_CSP) != 0;
+		opts.serverMessageAPIEnabled = (PauseMenuCustomizeState.serverInfoEmbedPerms & PauseMenuCustomizeState.SERVER_INFO_EMBED_PERMS_MESSAGE_API) != 0;
+		opts.fallbackTitle = PauseMenuCustomizeState.serverInfoEmbedTitle;
+	}
+
+	public void initGui() {
+		ScaledResolution res = mc.scaledResolution;
+		if(!isShowing) {
+			isShowing = true;
+			WebViewOverlayController.beginShowingSmart(opts, res, 30, 30, width - 60, height - 60);
+		}else {
+			WebViewOverlayController.resizeSmart(res, 30, 30, width - 60, height - 60);
+		}
+		buttonList.clear();
+		buttonList.add(new GuiButton(0, (width - 200) / 2, height - 25, I18n.format("gui.done")));
+	}
+
+	public void onGuiClosed() {
+		if(isShowing) {
+			isShowing = false;
+			WebViewOverlayController.endShowing();
+		}
+	}
+
+	public void actionPerformed(GuiButton btn) {
+		if(btn.id == 0) {
+			mc.displayGuiScreen(parent);
+		}
+	}
+
+	public void drawScreen(int mx, int my, float pt) {
+		drawDefaultBackground();
+		drawCenteredString(fontRendererObj, PauseMenuCustomizeState.serverInfoEmbedTitle == null ? "Server Info"
+				: PauseMenuCustomizeState.serverInfoEmbedTitle, width / 2, 13, 0xFFFFFF);
+		super.drawScreen(mx, my, pt);
+	}
+
+	protected boolean isPartOfPauseMenu() {
+		return true;
+	}
+}
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/webview/GuiScreenServerInfoDesktop.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/webview/GuiScreenServerInfoDesktop.java
new file mode 100644
index 00000000..19f0b2d3
--- /dev/null
+++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/webview/GuiScreenServerInfoDesktop.java
@@ -0,0 +1,92 @@
+package net.lax1dude.eaglercraft.v1_8.webview;
+
+import net.lax1dude.eaglercraft.v1_8.EagRuntime;
+import net.lax1dude.eaglercraft.v1_8.PauseMenuCustomizeState;
+import net.lax1dude.eaglercraft.v1_8.internal.WebViewOptions;
+import net.minecraft.client.gui.GuiButton;
+import net.minecraft.client.gui.GuiScreen;
+import net.minecraft.client.resources.I18n;
+
+/**
+ * Copyright (c) 2024 lax1dude. All Rights Reserved.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ * 
+ */
+public class GuiScreenServerInfoDesktop extends GuiScreen {
+
+	private final GuiScreen parent;
+	private final WebViewOptions opts;
+
+	private int timer = 0;
+	private boolean hasStarted = false;
+
+	private GuiButton btnOpen;
+
+	public GuiScreenServerInfoDesktop(GuiScreen parent, WebViewOptions opts) {
+		this.parent = parent;
+		this.opts = opts;
+	}
+
+	public void initGui() {
+		buttonList.clear();
+		buttonList.add(btnOpen = new GuiButton(0, (width - 200) / 2, height / 6 + 110, I18n.format("fallbackWebViewScreen.openButton")));
+		btnOpen.enabled = false;
+		buttonList.add(new GuiButton(1, (width - 200) / 2, height / 6 + 140, I18n.format("fallbackWebViewScreen.exitButton")));
+	}
+
+	public void updateScreen() {
+		++timer;
+		if(timer == 2) {
+			WebViewOverlayController.endFallbackServer();
+			WebViewOverlayController.launchFallback(opts);
+		}else if(timer > 2) {
+			if(WebViewOverlayController.fallbackRunning()) {
+				btnOpen.enabled = WebViewOverlayController.getFallbackURL() != null;
+				hasStarted = true;
+			}else {
+				btnOpen.enabled = false;
+			}
+		}
+	}
+
+	public void actionPerformed(GuiButton button) {
+		if(button.id == 0) {
+			String link = WebViewOverlayController.getFallbackURL();
+			if(link != null) {
+				EagRuntime.openLink(link);
+			}
+		}else if(button.id == 1) {
+			mc.displayGuiScreen(parent);
+		}
+	}
+
+	public void onGuiClosed() {
+		WebViewOverlayController.endFallbackServer();
+	}
+
+	public void drawScreen(int mx, int my, float pt) {
+		drawDefaultBackground();
+		drawCenteredString(fontRendererObj, PauseMenuCustomizeState.serverInfoEmbedTitle, this.width / 2, 70, 16777215);
+		drawCenteredString(fontRendererObj, I18n.format("fallbackWebViewScreen.text0"), this.width / 2, 90, 11184810);
+		String link = WebViewOverlayController.fallbackRunning() ? WebViewOverlayController.getFallbackURL()
+				: I18n.format(hasStarted ? "fallbackWebViewScreen.exited" : "fallbackWebViewScreen.startingUp");
+		drawCenteredString(fontRendererObj, link != null ? link : I18n.format("fallbackWebViewScreen.pleaseWait"),
+				width / 2, 110, 16777215);
+		super.drawScreen(mx, my, pt);
+	}
+
+	protected boolean isPartOfPauseMenu() {
+		return true;
+	}
+
+}
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/webview/PermissionsCache.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/webview/PermissionsCache.java
new file mode 100644
index 00000000..bcd5e6ac
--- /dev/null
+++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/webview/PermissionsCache.java
@@ -0,0 +1,64 @@
+package net.lax1dude.eaglercraft.v1_8.webview;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import net.lax1dude.eaglercraft.v1_8.EaglercraftUUID;
+
+/**
+ * Copyright (c) 2024 lax1dude. All Rights Reserved.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ * 
+ */
+public class PermissionsCache {
+
+	public static class Permission {
+
+		public final int perm;
+		public final boolean choice;
+
+		private Permission(int perm, boolean choice) {
+			this.perm = perm;
+			this.choice = choice;
+		}
+
+	}
+
+	private static final Map<EaglercraftUUID,Permission> javaScriptAllowed = new HashMap<>();
+
+	public static Permission getJavaScriptAllowed(EaglercraftUUID uuid, int flags) {
+		synchronized(javaScriptAllowed) {
+			if(uuid == null) {
+				return null;
+			}
+			Permission p = javaScriptAllowed.get(uuid);
+			if(p == null) {
+				return null;
+			}
+			return (p.perm | flags) != p.perm ? null : p;
+		}
+	}
+
+	public static void setJavaScriptAllowed(EaglercraftUUID uuid, int flags, boolean allowed) {
+		synchronized(javaScriptAllowed) {
+			if(uuid != null) javaScriptAllowed.put(uuid, new Permission(flags, allowed));
+		}
+	}
+
+	public static void clearJavaScriptAllowed(EaglercraftUUID uuid) {
+		synchronized(javaScriptAllowed) {
+			if(uuid != null) javaScriptAllowed.remove(uuid);
+		}
+	}
+
+}
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/webview/ServerInfoCache.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/webview/ServerInfoCache.java
new file mode 100644
index 00000000..2faa3562
--- /dev/null
+++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/webview/ServerInfoCache.java
@@ -0,0 +1,130 @@
+package net.lax1dude.eaglercraft.v1_8.webview;
+
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+
+import net.lax1dude.eaglercraft.v1_8.EagRuntime;
+import net.lax1dude.eaglercraft.v1_8.HashKey;
+import net.lax1dude.eaglercraft.v1_8.socket.protocol.pkt.server.SPacketServerInfoDataChunkV4EAG;
+
+/**
+ * Copyright (c) 2024 lax1dude. All Rights Reserved.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ * 
+ */
+public class ServerInfoCache {
+
+	public static final int CACHE_MAX_SIZE = 0x200000; // 2 MB
+
+	private static final Map<HashKey,CacheEntry> cache = new HashMap<>();
+	private static int cacheSize = 0;
+
+	private static class CacheEntry {
+
+		private final byte[] data;
+		private final HashKey hash;
+		private long lastHit;
+
+		private CacheEntry(byte[] data, HashKey hash) {
+			this.data = data;
+			this.hash = hash;
+			this.lastHit = EagRuntime.steadyTimeMillis();
+		}
+
+	}
+
+	protected static final List<byte[]> chunkRecieveBuffer = new LinkedList<>();
+	protected static byte[] chunkRecieveHash = null;
+	protected static int chunkCurrentSize = 0;
+	protected static int chunkFinalSize = 0;
+	protected static boolean hasLastChunk = false;
+
+	public static void handleChunk(SPacketServerInfoDataChunkV4EAG chunk) {
+		//System.out.println("p: " + chunk.seqId + " " + chunk.finalSize + " " + Base64.encodeBase64String(chunk.finalHash) + " " + chunk.lastChunk);
+		if (chunkRecieveHash == null || hasLastChunk || !Arrays.equals(chunk.finalHash, chunkRecieveHash)
+				|| chunk.seqId != chunkRecieveBuffer.size()) {
+			chunkRecieveBuffer.clear();
+			hasLastChunk = false;
+			chunkRecieveHash = null;
+			chunkCurrentSize = 0;
+			chunkFinalSize = 0;
+			if(chunk.seqId != 0) {
+				return;
+			}
+			chunkRecieveHash = chunk.finalHash;
+		}
+		chunkRecieveBuffer.add(chunk.data);
+		chunkCurrentSize += chunk.data.length;
+		chunkFinalSize = chunk.finalSize;
+		hasLastChunk = chunk.lastChunk;
+	}
+
+	public static void clearDownload() {
+		chunkRecieveBuffer.clear();
+		hasLastChunk = false;
+		chunkRecieveHash = null;
+		chunkCurrentSize = 0;
+		chunkFinalSize = 0;
+	}
+
+	public static byte[] loadFromCache(byte[] hash) {
+		if(hash == null || hash.length != 20) {
+			return null;
+		}
+		CacheEntry etr = cache.get(new HashKey(hash));
+		if(etr != null) {
+			etr.lastHit = EagRuntime.steadyTimeMillis();
+			return etr.data;
+		}else {
+			return null;
+		}
+	}
+
+	public static void storeInCache(byte[] hash, byte[] data) {
+		if(hash == null || hash.length != 20 || data == null) {
+			return;
+		}
+		HashKey hashObj = new HashKey(hash);
+		if(cache.containsKey(hashObj)) {
+			return;
+		}
+		shrink(data.length);
+		cache.put(hashObj, new CacheEntry(data, hashObj));
+		cacheSize += data.length;
+	}
+
+	private static void shrink(int toAdd) {
+		if(toAdd > CACHE_MAX_SIZE) {
+			cache.clear();
+			cacheSize = 0;
+			return;
+		}
+		while(!cache.isEmpty() && cacheSize + toAdd > CACHE_MAX_SIZE) {
+			CacheEntry oldest = null;
+			for(CacheEntry e : cache.values()) {
+				if(oldest == null || e.lastHit < oldest.lastHit) {
+					oldest = e;
+				}
+			}
+			if(cache.remove(oldest.hash) != null) {
+				cacheSize -= oldest.data.length;
+			}else {
+				break; //wtf?
+			}
+		}
+	}
+
+}
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/webview/WebViewOverlayController.java b/sources/main/java/net/lax1dude/eaglercraft/v1_8/webview/WebViewOverlayController.java
new file mode 100644
index 00000000..3c6e4d75
--- /dev/null
+++ b/sources/main/java/net/lax1dude/eaglercraft/v1_8/webview/WebViewOverlayController.java
@@ -0,0 +1,92 @@
+package net.lax1dude.eaglercraft.v1_8.webview;
+
+import net.lax1dude.eaglercraft.v1_8.internal.PlatformWebView;
+import net.lax1dude.eaglercraft.v1_8.internal.WebViewOptions;
+import net.lax1dude.eaglercraft.v1_8.socket.protocol.pkt.GameMessagePacket;
+import net.lax1dude.eaglercraft.v1_8.socket.protocol.pkt.server.SPacketWebViewMessageV4EAG;
+import net.minecraft.client.gui.ScaledResolution;
+
+/**
+ * Copyright (c) 2024 lax1dude. All Rights Reserved.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ * 
+ */
+public class WebViewOverlayController {
+
+	public static boolean supported() {
+		return PlatformWebView.supported();
+	}
+
+	public static boolean isShowing() {
+		return PlatformWebView.isShowing();
+	}
+
+	public static void beginShowing(WebViewOptions options, int x, int y, int w, int h) {
+		PlatformWebView.beginShowing(options, x, y, w, h);
+	}
+
+	public static void resize(int x, int y, int w, int h) {
+		PlatformWebView.resize(x, y, w, h);
+	}
+
+	public static void beginShowingSmart(WebViewOptions options, ScaledResolution res, int x, int y, int w, int h) {
+		int fac = res.getScaleFactor();
+		PlatformWebView.beginShowing(options, x * fac, y * fac, w * fac, h * fac);
+	}
+
+	public static void resizeSmart(ScaledResolution res, int x, int y, int w, int h) {
+		int fac = res.getScaleFactor();
+		PlatformWebView.resize(x * fac, y * fac, w * fac, h * fac);
+	}
+
+	public static void endShowing() {
+		PlatformWebView.endShowing();
+	}
+
+	public static boolean fallbackSupported() {
+		return PlatformWebView.fallbackSupported();
+	}
+
+	public static void launchFallback(WebViewOptions options) {
+		PlatformWebView.launchFallback(options);
+	}
+
+	public static boolean fallbackRunning() {
+		return PlatformWebView.fallbackRunning();
+	}
+
+	public static String getFallbackURL() {
+		return PlatformWebView.getFallbackURL();
+	}
+
+	public static void endFallbackServer() {
+		PlatformWebView.endFallbackServer();
+	}
+
+	public static void handleMessagePacket(SPacketWebViewMessageV4EAG packet) {
+		PlatformWebView.handleMessageFromServer(packet);
+	}
+
+	public static interface IPacketSendCallback {
+		boolean sendPacket(GameMessagePacket packet);
+	}
+
+	public static void setPacketSendCallback(IPacketSendCallback callback) {
+		PlatformWebView.setPacketSendCallback(callback);
+	}
+
+	public static void runTick() {
+		PlatformWebView.runTick();
+	}
+
+}
diff --git a/sources/main/java/org/json/JSONArray.java b/sources/main/java/org/json/JSONArray.java
index 3be3e145..f86075e6 100644
--- a/sources/main/java/org/json/JSONArray.java
+++ b/sources/main/java/org/json/JSONArray.java
@@ -149,11 +149,40 @@ public class JSONArray implements Iterable<Object> {
      *            A Collection.
      */
     public JSONArray(Collection<?> collection) {
+      this(collection, 0, new JSONParserConfiguration());
+    }
+
+    /**
+     * Construct a JSONArray from a Collection.
+     *
+     * @param collection
+     *            A Collection.
+     * @param jsonParserConfiguration
+     *            Configuration object for the JSON parser
+     */
+    public JSONArray(Collection<?> collection, JSONParserConfiguration jsonParserConfiguration) {
+        this(collection, 0, jsonParserConfiguration);
+    }
+
+    /**
+     * Construct a JSONArray from a collection with recursion depth.
+     *
+     * @param collection
+     *             A Collection.
+     * @param recursionDepth
+     *             Variable for tracking the count of nested object creations.
+     * @param jsonParserConfiguration
+     *             Configuration object for the JSON parser
+     */
+    JSONArray(Collection<?> collection, int recursionDepth, JSONParserConfiguration jsonParserConfiguration) {
+        if (recursionDepth > jsonParserConfiguration.getMaxNestingDepth()) {
+          throw new JSONException("JSONArray has reached recursion depth limit of " + jsonParserConfiguration.getMaxNestingDepth());
+        }
         if (collection == null) {
             this.myArrayList = new ArrayList<Object>();
         } else {
             this.myArrayList = new ArrayList<Object>(collection.size());
-            this.addAll(collection, true);
+            this.addAll(collection, true, recursionDepth, jsonParserConfiguration);
         }
     }
 
@@ -205,7 +234,7 @@ public class JSONArray implements Iterable<Object> {
             throw new JSONException(
                     "JSONArray initial value should be a string or collection or array.");
         }
-        this.addAll(array, true);
+        this.addAll(array, true, 0);
     }
 
     /**
@@ -599,6 +628,38 @@ public class JSONArray implements Iterable<Object> {
         }
     }
 
+    /**
+     * Get the optional Boolean object associated with an index. It returns false
+     * if there is no value at that index, or if the value is not Boolean.TRUE
+     * or the String "true".
+     *
+     * @param index
+     *            The index must be between 0 and length() - 1.
+     * @return The truth.
+     */
+    public Boolean optBooleanObject(int index) {
+        return this.optBooleanObject(index, false);
+    }
+
+    /**
+     * Get the optional Boolean object associated with an index. It returns the
+     * defaultValue if there is no value at that index or if it is not a Boolean
+     * or the String "true" or "false" (case insensitive).
+     *
+     * @param index
+     *            The index must be between 0 and length() - 1.
+     * @param defaultValue
+     *            A boolean default.
+     * @return The truth.
+     */
+    public Boolean optBooleanObject(int index, Boolean defaultValue) {
+        try {
+            return this.getBoolean(index);
+        } catch (Exception e) {
+            return defaultValue;
+        }
+    }
+
     /**
      * Get the optional double value associated with an index. NaN is returned
      * if there is no value for the index, or if the value is not a number and
@@ -635,6 +696,42 @@ public class JSONArray implements Iterable<Object> {
         return doubleValue;
     }
 
+    /**
+     * Get the optional Double object associated with an index. NaN is returned
+     * if there is no value for the index, or if the value is not a number and
+     * cannot be converted to a number.
+     *
+     * @param index
+     *            The index must be between 0 and length() - 1.
+     * @return The object.
+     */
+    public Double optDoubleObject(int index) {
+        return this.optDoubleObject(index, Double.NaN);
+    }
+
+    /**
+     * Get the optional double value associated with an index. The defaultValue
+     * is returned if there is no value for the index, or if the value is not a
+     * number and cannot be converted to a number.
+     *
+     * @param index
+     *            subscript
+     * @param defaultValue
+     *            The default object.
+     * @return The object.
+     */
+    public Double optDoubleObject(int index, Double defaultValue) {
+        final Number val = this.optNumber(index, null);
+        if (val == null) {
+            return defaultValue;
+        }
+        final Double doubleValue = val.doubleValue();
+        // if (Double.isNaN(doubleValue) || Double.isInfinite(doubleValue)) {
+        // return defaultValue;
+        // }
+        return doubleValue;
+    }
+
     /**
      * Get the optional float value associated with an index. NaN is returned
      * if there is no value for the index, or if the value is not a number and
@@ -671,6 +768,42 @@ public class JSONArray implements Iterable<Object> {
         return floatValue;
     }
 
+    /**
+     * Get the optional Float object associated with an index. NaN is returned
+     * if there is no value for the index, or if the value is not a number and
+     * cannot be converted to a number.
+     *
+     * @param index
+     *            The index must be between 0 and length() - 1.
+     * @return The object.
+     */
+    public Float optFloatObject(int index) {
+        return this.optFloatObject(index, Float.NaN);
+    }
+
+    /**
+     * Get the optional Float object associated with an index. The defaultValue
+     * is returned if there is no value for the index, or if the value is not a
+     * number and cannot be converted to a number.
+     *
+     * @param index
+     *            subscript
+     * @param defaultValue
+     *            The default object.
+     * @return The object.
+     */
+    public Float optFloatObject(int index, Float defaultValue) {
+        final Number val = this.optNumber(index, null);
+        if (val == null) {
+            return defaultValue;
+        }
+        final Float floatValue = val.floatValue();
+        // if (Float.isNaN(floatValue) || Float.isInfinite(floatValue)) {
+        // return floatValue;
+        // }
+        return floatValue;
+    }
+
     /**
      * Get the optional int value associated with an index. Zero is returned if
      * there is no value for the index, or if the value is not a number and
@@ -703,6 +836,38 @@ public class JSONArray implements Iterable<Object> {
         return val.intValue();
     }
 
+    /**
+     * Get the optional Integer object associated with an index. Zero is returned if
+     * there is no value for the index, or if the value is not a number and
+     * cannot be converted to a number.
+     *
+     * @param index
+     *            The index must be between 0 and length() - 1.
+     * @return The object.
+     */
+    public Integer optIntegerObject(int index) {
+        return this.optIntegerObject(index, 0);
+    }
+
+    /**
+     * Get the optional Integer object associated with an index. The defaultValue is
+     * returned if there is no value for the index, or if the value is not a
+     * number and cannot be converted to a number.
+     *
+     * @param index
+     *            The index must be between 0 and length() - 1.
+     * @param defaultValue
+     *            The default object.
+     * @return The object.
+     */
+    public Integer optIntegerObject(int index, Integer defaultValue) {
+        final Number val = this.optNumber(index, null);
+        if (val == null) {
+            return defaultValue;
+        }
+        return val.intValue();
+    }
+
     /**
      * Get the enum value associated with a key.
      * 
@@ -788,30 +953,57 @@ public class JSONArray implements Iterable<Object> {
     }
 
     /**
-     * Get the optional JSONArray associated with an index.
+     * Get the optional JSONArray associated with an index. Null is returned if
+     * there is no value at that index or if the value is not a JSONArray.
      *
      * @param index
-     *            subscript
-     * @return A JSONArray value, or null if the index has no value, or if the
-     *         value is not a JSONArray.
+     *            The index must be between 0 and length() - 1.
+     * @return A JSONArray value.
      */
     public JSONArray optJSONArray(int index) {
-        Object o = this.opt(index);
-        return o instanceof JSONArray ? (JSONArray) o : null;
+        return this.optJSONArray(index, null);
+    }
+
+    /**
+     * Get the optional JSONArray associated with an index. The defaultValue is returned if
+     * there is no value at that index or if the value is not a JSONArray.
+     *
+     * @param index
+     *            The index must be between 0 and length() - 1.
+     * @param defaultValue
+     *            The default.
+     * @return A JSONArray value.
+     */
+    public JSONArray optJSONArray(int index, JSONArray defaultValue) {
+        Object object = this.opt(index);
+        return object instanceof JSONArray ? (JSONArray) object : defaultValue;
     }
 
     /**
      * Get the optional JSONObject associated with an index. Null is returned if
-     * the key is not found, or null if the index has no value, or if the value
-     * is not a JSONObject.
+     * there is no value at that index or if the value is not a JSONObject.
      *
      * @param index
      *            The index must be between 0 and length() - 1.
      * @return A JSONObject value.
      */
     public JSONObject optJSONObject(int index) {
-        Object o = this.opt(index);
-        return o instanceof JSONObject ? (JSONObject) o : null;
+        return this.optJSONObject(index, null);
+    }
+
+    /**
+     * Get the optional JSONObject associated with an index. The defaultValue is returned if
+     * there is no value at that index or if the value is not a JSONObject.
+     *
+     * @param index
+     *            The index must be between 0 and length() - 1.
+     * @param defaultValue
+     *            The default.
+     * @return A JSONObject value.
+     */
+    public JSONObject optJSONObject(int index, JSONObject defaultValue) {
+        Object object = this.opt(index);
+        return object instanceof JSONObject ? (JSONObject) object : defaultValue;
     }
 
     /**
@@ -846,6 +1038,38 @@ public class JSONArray implements Iterable<Object> {
         return val.longValue();
     }
 
+    /**
+     * Get the optional Long object associated with an index. Zero is returned if
+     * there is no value for the index, or if the value is not a number and
+     * cannot be converted to a number.
+     *
+     * @param index
+     *            The index must be between 0 and length() - 1.
+     * @return The object.
+     */
+    public Long optLongObject(int index) {
+        return this.optLongObject(index, 0L);
+    }
+
+    /**
+     * Get the optional Long object associated with an index. The defaultValue is
+     * returned if there is no value for the index, or if the value is not a
+     * number and cannot be converted to a number.
+     *
+     * @param index
+     *            The index must be between 0 and length() - 1.
+     * @param defaultValue
+     *            The default object.
+     * @return The object.
+     */
+    public Long optLongObject(int index, Long defaultValue) {
+        final Number val = this.optNumber(index, null);
+        if (val == null) {
+            return defaultValue;
+        }
+        return val.longValue();
+    }
+
     /**
      * Get an optional {@link Number} value associated with a key, or <code>null</code>
      * if there is no such key or if the value is not a number. If the value is a string,
@@ -1135,7 +1359,8 @@ public class JSONArray implements Iterable<Object> {
      *            The subscript.
      * @param value
      *            The Map value.
-     * @return this.
+     * @return
+     *             reference to self
      * @throws JSONException
      *             If the index is negative or if the value is an invalid
      *             number.
@@ -1143,7 +1368,27 @@ public class JSONArray implements Iterable<Object> {
      *             If a key in the map is <code>null</code>
      */
     public JSONArray put(int index, Map<?, ?> value) throws JSONException {
-        this.put(index, new JSONObject(value));
+        this.put(index, new JSONObject(value, new JSONParserConfiguration()));
+        return this;
+    }
+
+    /**
+     * Put a value in the JSONArray, where the value will be a JSONObject that
+     * is produced from a Map.
+     *
+     * @param index
+     *          The subscript
+     * @param value
+     *          The Map value.
+     * @param jsonParserConfiguration
+     *          Configuration object for the JSON parser
+     * @return reference to self
+     * @throws JSONException
+     *          If the index is negative or if the value is an invalid
+     *          number.
+     */
+    public JSONArray put(int index, Map<?, ?> value, JSONParserConfiguration jsonParserConfiguration) throws JSONException {
+        this.put(index, new JSONObject(value, jsonParserConfiguration));
         return this;
     }
 
@@ -1451,9 +1696,7 @@ public class JSONArray implements Iterable<Object> {
     @SuppressWarnings("resource")
     public String toString(int indentFactor) throws JSONException {
         StringWriter sw = new StringWriter();
-        synchronized (sw.getBuffer()) {
-            return this.write(sw, indentFactor, 0).toString();
-        }
+        return this.write(sw, indentFactor, 0).toString();
     }
 
     /**
@@ -1586,13 +1829,14 @@ public class JSONArray implements Iterable<Object> {
      * @param wrap
      *            {@code true} to call {@link JSONObject#wrap(Object)} for each item,
      *            {@code false} to add the items directly
-     *            
+     * @param recursionDepth
+     *            Variable for tracking the count of nested object creations.
      */
-    private void addAll(Collection<?> collection, boolean wrap) {
+    private void addAll(Collection<?> collection, boolean wrap, int recursionDepth, JSONParserConfiguration jsonParserConfiguration) {
         this.myArrayList.ensureCapacity(this.myArrayList.size() + collection.size());
         if (wrap) {
             for (Object o: collection){
-                this.put(JSONObject.wrap(o));
+                this.put(JSONObject.wrap(o, recursionDepth + 1, jsonParserConfiguration));
             }
         } else {
             for (Object o: collection){
@@ -1621,7 +1865,24 @@ public class JSONArray implements Iterable<Object> {
             }
         }
     }
-    
+
+    /**
+     * Add an array's elements to the JSONArray.
+     *
+     * @param array
+     *          Array. If the parameter passed is null, or not an array,
+     *          JSONArray, Collection, or Iterable, an exception will be
+     *          thrown.
+     * @param wrap
+     *          {@code true} to call {@link JSONObject#wrap(Object)} for each item,
+     *          {@code false} to add the items directly
+     * @throws JSONException
+     *          If not an array or if an array value is non-finite number.
+     */
+    private void addAll(Object array, boolean wrap) throws JSONException {
+      this.addAll(array, wrap, 0);
+    }
+
     /**
      * Add an array's elements to the JSONArray.
      *
@@ -1630,21 +1891,40 @@ public class JSONArray implements Iterable<Object> {
      *            JSONArray, Collection, or Iterable, an exception will be
      *            thrown.
      * @param wrap
+     *          {@code true} to call {@link JSONObject#wrap(Object)} for each item,
+     *          {@code false} to add the items directly
+     * @param recursionDepth
+     *          Variable for tracking the count of nested object creations.
+     */
+    private void addAll(Object array, boolean wrap, int recursionDepth) {
+        addAll(array, wrap, recursionDepth, new JSONParserConfiguration());
+    }
+    /**
+     * Add an array's elements to the JSONArray.
+     *`
+     * @param array
+     *            Array. If the parameter passed is null, or not an array,
+     *            JSONArray, Collection, or Iterable, an exception will be
+     *            thrown.
+     * @param wrap
      *            {@code true} to call {@link JSONObject#wrap(Object)} for each item,
      *            {@code false} to add the items directly
-     *
+     * @param recursionDepth
+     *            Variable for tracking the count of nested object creations.
+     * @param jsonParserConfiguration
+     *            Variable to pass parser custom configuration for json parsing.
      * @throws JSONException
      *            If not an array or if an array value is non-finite number.
      * @throws NullPointerException
      *            Thrown if the array parameter is null.
      */
-    private void addAll(Object array, boolean wrap) throws JSONException {
+    private void addAll(Object array, boolean wrap, int recursionDepth, JSONParserConfiguration jsonParserConfiguration) throws JSONException {
         if (array.getClass().isArray()) {
             int length = Array.getLength(array);
             this.myArrayList.ensureCapacity(this.myArrayList.size() + length);
             if (wrap) {
                 for (int i = 0; i < length; i += 1) {
-                    this.put(JSONObject.wrap(Array.get(array, i)));
+                    this.put(JSONObject.wrap(Array.get(array, i), recursionDepth + 1, jsonParserConfiguration));
                 }
             } else {
                 for (int i = 0; i < length; i += 1) {
@@ -1657,7 +1937,7 @@ public class JSONArray implements Iterable<Object> {
             // JSONArray
             this.myArrayList.addAll(((JSONArray)array).myArrayList);
         } else if (array instanceof Collection) {
-            this.addAll((Collection<?>)array, wrap);
+            this.addAll((Collection<?>)array, wrap, recursionDepth);
         } else if (array instanceof Iterable) {
             this.addAll((Iterable<?>)array, wrap);
         } else {
diff --git a/sources/main/java/org/json/JSONObject.java b/sources/main/java/org/json/JSONObject.java
index b133a7f3..6494f934 100644
--- a/sources/main/java/org/json/JSONObject.java
+++ b/sources/main/java/org/json/JSONObject.java
@@ -145,6 +145,11 @@ public class JSONObject {
      */
     private final Map<String, Object> map;
 
+    /**
+     * Retrieves the type of the underlying Map in this class.
+     *
+     * @return The class object representing the type of the underlying Map.
+     */
     public Class<? extends Map> getMapType() {
         return map.getClass();
     }
@@ -208,22 +213,14 @@ public class JSONObject {
             throw x.syntaxError("A JSONObject text must begin with '{'");
         }
         for (;;) {
-            char prev = x.getPrevious();
             c = x.nextClean();
             switch (c) {
             case 0:
                 throw x.syntaxError("A JSONObject text must end with '}'");
             case '}':
                 return;
-            case '{':
-            case '[':
-                if(prev=='{') {
-                    throw x.syntaxError("A JSON Object can not directly nest another JSON Object or JSON Array.");
-                }
-                // fall through
             default:
-                x.back();
-                key = x.nextValue().toString();
+                key = x.nextSimpleValue(c).toString();
             }
 
             // The key is followed by ':'.
@@ -237,12 +234,10 @@ public class JSONObject {
 
             if (key != null) {
                 // Check if key exists
-				/*
                 if (this.opt(key) != null) {
                     // key already exists
                     throw x.syntaxError("Duplicate key \"" + key + "\"");
                 }
-                */
                 // Only add value if non-null
                 Object value = x.nextValue();
                 if (value!=null) {
@@ -258,6 +253,9 @@ public class JSONObject {
                 if (x.nextClean() == '}') {
                     return;
                 }
+                if (x.end()) {
+                    throw x.syntaxError("A JSONObject text must end with '}'");
+                }
                 x.back();
                 break;
             case '}':
@@ -280,6 +278,30 @@ public class JSONObject {
      *            If a key in the map is <code>null</code>
      */
     public JSONObject(Map<?, ?> m) {
+      this(m, 0, new JSONParserConfiguration());
+    }
+
+    /**
+     * Construct a JSONObject from a Map with custom json parse configurations.
+     *
+     * @param m
+     *            A map object that can be used to initialize the contents of
+     *            the JSONObject.
+     * @param jsonParserConfiguration
+     *            Variable to pass parser custom configuration for json parsing.
+     */
+    public JSONObject(Map<?, ?> m, JSONParserConfiguration jsonParserConfiguration) {
+        this(m, 0, jsonParserConfiguration);
+    }
+
+    /**
+     * Construct a JSONObject from a map with recursion depth.
+     *
+     */
+    private JSONObject(Map<?, ?> m, int recursionDepth, JSONParserConfiguration jsonParserConfiguration) {
+        if (recursionDepth > jsonParserConfiguration.getMaxNestingDepth()) {
+          throw new JSONException("JSONObject has reached recursion depth limit of " + jsonParserConfiguration.getMaxNestingDepth());
+        }
         if (m == null) {
             this.map = new HashMap<String, Object>();
         } else {
@@ -290,7 +312,8 @@ public class JSONObject {
         	    }
                 final Object value = e.getValue();
                 if (value != null) {
-                    this.map.put(String.valueOf(e.getKey()), wrap(value));
+                    testValidity(value);
+                    this.map.put(String.valueOf(e.getKey()), wrap(value, recursionDepth + 1, jsonParserConfiguration));
                 }
             }
         }
@@ -348,11 +371,12 @@ public class JSONObject {
      * &#64;JSONPropertyIgnore
      * public String getName() { return this.name; }
      * </pre>
-     * <p>
      *
      * @param bean
      *            An object that has getter methods that should be used to make
      *            a JSONObject.
+     * @throws JSONException
+     *            If a getter returned a non-finite number.
      */
     public JSONObject(Object bean) {
         this();
@@ -1133,6 +1157,45 @@ public class JSONObject {
         }
     }
 
+    /**
+     * Get an optional boolean object associated with a key. It returns false if there
+     * is no such key, or if the value is not Boolean.TRUE or the String "true".
+     *
+     * @param key
+     *            A key string.
+     * @return The truth.
+     */
+    public Boolean optBooleanObject(String key) {
+        return this.optBooleanObject(key, false);
+    }
+
+    /**
+     * Get an optional boolean object associated with a key. It returns the
+     * defaultValue if there is no such key, or if it is not a Boolean or the
+     * String "true" or "false" (case insensitive).
+     *
+     * @param key
+     *            A key string.
+     * @param defaultValue
+     *            The default.
+     * @return The truth.
+     */
+    public Boolean optBooleanObject(String key, Boolean defaultValue) {
+        Object val = this.opt(key);
+        if (NULL.equals(val)) {
+            return defaultValue;
+        }
+        if (val instanceof Boolean){
+            return ((Boolean) val).booleanValue();
+        }
+        try {
+            // we'll use the get anyway because it does string conversion.
+            return this.getBoolean(key);
+        } catch (Exception e) {
+            return defaultValue;
+        }
+    }
+
     /**
      * Get an optional BigDecimal associated with a key, or the defaultValue if
      * there is no such key or if its value is not a number. If the value is a
@@ -1292,15 +1355,43 @@ public class JSONObject {
         if (val == null) {
             return defaultValue;
         }
-        final double doubleValue = val.doubleValue();
-        // if (Double.isNaN(doubleValue) || Double.isInfinite(doubleValue)) {
-        // return defaultValue;
-        // }
-        return doubleValue;
+        return val.doubleValue();
     }
 
     /**
-     * Get the optional double value associated with an index. NaN is returned
+     * Get an optional Double object associated with a key, or NaN if there is no such
+     * key or if its value is not a number. If the value is a string, an attempt
+     * will be made to evaluate it as a number.
+     *
+     * @param key
+     *            A string which is the key.
+     * @return An object which is the value.
+     */
+    public Double optDoubleObject(String key) {
+        return this.optDoubleObject(key, Double.NaN);
+    }
+
+    /**
+     * Get an optional Double object associated with a key, or the defaultValue if
+     * there is no such key or if its value is not a number. If the value is a
+     * string, an attempt will be made to evaluate it as a number.
+     *
+     * @param key
+     *            A key string.
+     * @param defaultValue
+     *            The default.
+     * @return An object which is the value.
+     */
+    public Double optDoubleObject(String key, Double defaultValue) {
+        Number val = this.optNumber(key);
+        if (val == null) {
+            return defaultValue;
+        }
+        return val.doubleValue();
+    }
+
+    /**
+     * Get the optional float value associated with an index. NaN is returned
      * if there is no value for the index, or if the value is not a number and
      * cannot be converted to a number.
      *
@@ -1313,7 +1404,7 @@ public class JSONObject {
     }
 
     /**
-     * Get the optional double value associated with an index. The defaultValue
+     * Get the optional float value associated with an index. The defaultValue
      * is returned if there is no value for the index, or if the value is not a
      * number and cannot be converted to a number.
      *
@@ -1335,6 +1426,42 @@ public class JSONObject {
         return floatValue;
     }
 
+    /**
+     * Get the optional Float object associated with an index. NaN is returned
+     * if there is no value for the index, or if the value is not a number and
+     * cannot be converted to a number.
+     *
+     * @param key
+     *            A key string.
+     * @return The object.
+     */
+    public Float optFloatObject(String key) {
+        return this.optFloatObject(key, Float.NaN);
+    }
+
+    /**
+     * Get the optional Float object associated with an index. The defaultValue
+     * is returned if there is no value for the index, or if the value is not a
+     * number and cannot be converted to a number.
+     *
+     * @param key
+     *            A key string.
+     * @param defaultValue
+     *            The default object.
+     * @return The object.
+     */
+    public Float optFloatObject(String key, Float defaultValue) {
+        Number val = this.optNumber(key);
+        if (val == null) {
+            return defaultValue;
+        }
+        final Float floatValue = val.floatValue();
+        // if (Float.isNaN(floatValue) || Float.isInfinite(floatValue)) {
+        // return defaultValue;
+        // }
+        return floatValue;
+    }
+
     /**
      * Get an optional int value associated with a key, or zero if there is no
      * such key or if the value is not a number. If the value is a string, an
@@ -1367,6 +1494,38 @@ public class JSONObject {
         return val.intValue();
     }
 
+    /**
+     * Get an optional Integer object associated with a key, or zero if there is no
+     * such key or if the value is not a number. If the value is a string, an
+     * attempt will be made to evaluate it as a number.
+     *
+     * @param key
+     *            A key string.
+     * @return An object which is the value.
+     */
+    public Integer optIntegerObject(String key) {
+        return this.optIntegerObject(key, 0);
+    }
+
+    /**
+     * Get an optional Integer object associated with a key, or the default if there
+     * is no such key or if the value is not a number. If the value is a string,
+     * an attempt will be made to evaluate it as a number.
+     *
+     * @param key
+     *            A key string.
+     * @param defaultValue
+     *            The default.
+     * @return An object which is the value.
+     */
+    public Integer optIntegerObject(String key, Integer defaultValue) {
+        final Number val = this.optNumber(key, null);
+        if (val == null) {
+            return defaultValue;
+        }
+        return val.intValue();
+    }
+
     /**
      * Get an optional JSONArray associated with a key. It returns null if there
      * is no such key, or if its value is not a JSONArray.
@@ -1376,8 +1535,22 @@ public class JSONObject {
      * @return A JSONArray which is the value.
      */
     public JSONArray optJSONArray(String key) {
-        Object o = this.opt(key);
-        return o instanceof JSONArray ? (JSONArray) o : null;
+        return this.optJSONArray(key, null);
+    }
+
+    /**
+     * Get an optional JSONArray associated with a key, or the default if there
+     * is no such key, or if its value is not a JSONArray.
+     *
+     * @param key
+     *            A key string.
+     * @param defaultValue
+     *            The default.
+     * @return A JSONArray which is the value.
+     */
+    public JSONArray optJSONArray(String key, JSONArray defaultValue) {
+        Object object = this.opt(key);
+        return object instanceof JSONArray ? (JSONArray) object : defaultValue;
     }
 
     /**
@@ -1438,6 +1611,39 @@ public class JSONObject {
         return val.longValue();
     }
 
+    /**
+     * Get an optional Long object associated with a key, or zero if there is no
+     * such key or if the value is not a number. If the value is a string, an
+     * attempt will be made to evaluate it as a number.
+     *
+     * @param key
+     *            A key string.
+     * @return An object which is the value.
+     */
+    public Long optLongObject(String key) {
+        return this.optLongObject(key, 0L);
+    }
+
+    /**
+     * Get an optional Long object associated with a key, or the default if there
+     * is no such key or if the value is not a number. If the value is a string,
+     * an attempt will be made to evaluate it as a number.
+     *
+     * @param key
+     *            A key string.
+     * @param defaultValue
+     *            The default.
+     * @return An object which is the value.
+     */
+    public Long optLongObject(String key, Long defaultValue) {
+        final Number val = this.optNumber(key, null);
+        if (val == null) {
+            return defaultValue;
+        }
+
+        return val.longValue();
+    }
+
     /**
      * Get an optional {@link Number} value associated with a key, or <code>null</code>
      * if there is no such key or if the value is not a number. If the value is a string,
@@ -1516,6 +1722,8 @@ public class JSONObject {
      *
      * @param bean
      *            the bean
+     * @throws JSONException
+     *            If a getter returned a non-finite number.
      */
     private void populateMap(Object bean) {
         populateMap(bean, Collections.newSetFromMap(new IdentityHashMap<Object, Boolean>()));
@@ -1543,21 +1751,22 @@ public class JSONObject {
                         final Object result = method.invoke(bean);
                         if (result != null) {
                             // check cyclic dependency and throw error if needed
-                            // the wrap and populateMap combination method is 
+                            // the wrap and populateMap combination method is
                             // itself DFS recursive
                             if (objectsRecord.contains(result)) {
                                 throw recursivelyDefinedObjectException(key);
                             }
-                            
+
                             objectsRecord.add(result);
 
+                            testValidity(result);
                             this.map.put(key, wrap(result, objectsRecord));
 
                             objectsRecord.remove(result);
 
                             // we don't use the result anywhere outside of wrap
                             // if it's a resource we should be sure to close it
-                            // after calling toString 
+                            // after calling toString
                             if (result instanceof Closeable) {
                                 try {
                                     ((Closeable) result).close();
@@ -1657,6 +1866,10 @@ public class JSONObject {
             }
         }
 
+        //If the superclass is Object, no annotations will be found any more
+        if (c.getSuperclass().equals(Object.class))
+            return null;
+
         try {
             return getAnnotation(
                     c.getSuperclass().getMethod(m.getName(), m.getParameterTypes()),
@@ -1711,6 +1924,10 @@ public class JSONObject {
             }
         }
 
+        //If the superclass is Object, no annotations will be found any more
+        if (c.getSuperclass().equals(Object.class))
+            return -1;
+
         try {
             int d = getAnnotationDepth(
                     c.getSuperclass().getMethod(m.getName(), m.getParameterTypes()),
@@ -2008,16 +2225,22 @@ public class JSONObject {
     @SuppressWarnings("resource")
     public static String quote(String string) {
         StringWriter sw = new StringWriter();
-        synchronized (sw.getBuffer()) {
-            try {
-                return quote(string, sw).toString();
-            } catch (IOException ignored) {
-                // will never happen - we are writing to a string writer
-                return "";
-            }
+        try {
+            return quote(string, sw).toString();
+        } catch (IOException ignored) {
+            // will never happen - we are writing to a string writer
+            return "";
         }
     }
 
+    /**
+     * Quotes a string and appends the result to a given Writer.
+     *
+     * @param string The input string to be quoted.
+     * @param w      The Writer to which the quoted string will be appended.
+     * @return The same Writer instance after appending the quoted string.
+     * @throws IOException If an I/O error occurs while writing to the Writer.
+     */
     public static Writer quote(String string, Writer w) throws IOException {
         if (string == null || string.isEmpty()) {
             w.write("\"\"");
@@ -2201,6 +2424,49 @@ public class JSONObject {
                 || val.indexOf('E') > -1 || "-0".equals(val);
     }
 
+    /**
+     * Try to convert a string into a number, boolean, or null. If the string
+     * can't be converted, return the string.
+     *
+     * @param string
+     *            A String. can not be null.
+     * @return A simple JSON value.
+     * @throws NullPointerException
+     *             Thrown if the string is null.
+     */
+    // Changes to this method must be copied to the corresponding method in
+    // the XML class to keep full support for Android
+    public static Object stringToValue(String string) {
+        if ("".equals(string)) {
+            return string;
+        }
+
+        // check JSON key words true/false/null
+        if ("true".equalsIgnoreCase(string)) {
+            return Boolean.TRUE;
+        }
+        if ("false".equalsIgnoreCase(string)) {
+            return Boolean.FALSE;
+        }
+        if ("null".equalsIgnoreCase(string)) {
+            return JSONObject.NULL;
+        }
+
+        /*
+         * If it might be a number, try converting it. If a number cannot be
+         * produced, then the value will just be a string.
+         */
+
+        char initial = string.charAt(0);
+        if ((initial >= '0' && initial <= '9') || initial == '-') {
+            try {
+                return stringToNumber(string);
+            } catch (Exception ignore) {
+            }
+        }
+        return string;
+    }
+
     /**
      * Converts a string to a number using the narrowest possible type. Possible
      * returns for this function are BigDecimal, Double, BigInteger, Long, and Integer.
@@ -2271,49 +2537,6 @@ public class JSONObject {
         throw new NumberFormatException("val ["+val+"] is not a valid number.");
     }
 
-    /**
-     * Try to convert a string into a number, boolean, or null. If the string
-     * can't be converted, return the string.
-     *
-     * @param string
-     *            A String. can not be null.
-     * @return A simple JSON value.
-     * @throws NullPointerException
-     *             Thrown if the string is null.
-     */
-    // Changes to this method must be copied to the corresponding method in
-    // the XML class to keep full support for Android
-    public static Object stringToValue(String string) {
-        if ("".equals(string)) {
-            return string;
-        }
-
-        // check JSON key words true/false/null
-        if ("true".equalsIgnoreCase(string)) {
-            return Boolean.TRUE;
-        }
-        if ("false".equalsIgnoreCase(string)) {
-            return Boolean.FALSE;
-        }
-        if ("null".equalsIgnoreCase(string)) {
-            return JSONObject.NULL;
-        }
-
-        /*
-         * If it might be a number, try converting it. If a number cannot be
-         * produced, then the value will just be a string.
-         */
-
-        char initial = string.charAt(0);
-        if ((initial >= '0' && initial <= '9') || initial == '-') {
-            try {
-                return stringToNumber(string);
-            } catch (Exception ignore) {
-            }
-        }
-        return string;
-    }
-
     /**
      * Throw an exception if the object is a NaN or infinite number.
      *
@@ -2401,9 +2624,7 @@ public class JSONObject {
     @SuppressWarnings("resource")
     public String toString(int indentFactor) throws JSONException {
         StringWriter w = new StringWriter();
-        synchronized (w.getBuffer()) {
-            return this.write(w, indentFactor, 0).toString();
-        }
+        return this.write(w, indentFactor, 0).toString();
     }
 
     /**
@@ -2454,7 +2675,31 @@ public class JSONObject {
         return wrap(object, null);
     }
 
+    /**
+     * Wrap an object, if necessary. If the object is <code>null</code>, return the NULL
+     * object. If it is an array or collection, wrap it in a JSONArray. If it is
+     * a map, wrap it in a JSONObject. If it is a standard property (Double,
+     * String, et al) then it is already wrapped. Otherwise, if it comes from
+     * one of the java packages, turn it into a string. And if it doesn't, try
+     * to wrap it in a JSONObject. If the wrapping fails, then null is returned.
+     *
+     * @param object
+     *            The object to wrap
+     * @param recursionDepth
+     *            Variable for tracking the count of nested object creations.
+     * @param jsonParserConfiguration
+     *            Variable to pass parser custom configuration for json parsing.
+     * @return The wrapped value
+     */
+    static Object wrap(Object object, int recursionDepth, JSONParserConfiguration jsonParserConfiguration) {
+      return wrap(object, null, recursionDepth, jsonParserConfiguration);
+    }
+
     private static Object wrap(Object object, Set<Object> objectsRecord) {
+      return wrap(object, objectsRecord, 0, new JSONParserConfiguration());
+    }
+
+    private static Object wrap(Object object, Set<Object> objectsRecord, int recursionDepth, JSONParserConfiguration jsonParserConfiguration) {
         try {
             if (NULL.equals(object)) {
                 return NULL;
@@ -2472,14 +2717,14 @@ public class JSONObject {
 
             if (object instanceof Collection) {
                 Collection<?> coll = (Collection<?>) object;
-                return new JSONArray(coll);
+                return new JSONArray(coll, recursionDepth, jsonParserConfiguration);
             }
             if (object.getClass().isArray()) {
                 return new JSONArray(object);
             }
             if (object instanceof Map) {
                 Map<?, ?> map = (Map<?, ?>) object;
-                return new JSONObject(map);
+                return new JSONObject(map, recursionDepth, jsonParserConfiguration);
             }
             Package objectPackage = object.getClass().getPackage();
             String objectPackageName = objectPackage != null ? objectPackage
@@ -2715,4 +2960,24 @@ public class JSONObject {
             "JavaBean object contains recursively defined member variable of key " + quote(key)
         );
     }
+
+    /**
+     * For a prospective number, remove the leading zeros
+     * @param value prospective number
+     * @return number without leading zeros
+     */
+    private static String removeLeadingZerosOfNumber(String value){
+        if (value.equals("-")){return value;}
+        boolean negativeFirstChar = (value.charAt(0) == '-');
+        int counter = negativeFirstChar ? 1:0;
+        while (counter < value.length()){
+            if (value.charAt(counter) != '0'){
+                if (negativeFirstChar) {return "-".concat(value.substring(counter));}
+                return value.substring(counter);
+            }
+            ++counter;
+        }
+        if (negativeFirstChar) {return "-0";}
+        return "0";
+    }
 }
diff --git a/sources/main/java/org/json/JSONParserConfiguration.java b/sources/main/java/org/json/JSONParserConfiguration.java
new file mode 100644
index 00000000..f95e2442
--- /dev/null
+++ b/sources/main/java/org/json/JSONParserConfiguration.java
@@ -0,0 +1,26 @@
+package org.json;
+
+/**
+ * Configuration object for the JSON parser. The configuration is immutable.
+ */
+public class JSONParserConfiguration extends ParserConfiguration {
+
+  /**
+   * Configuration with the default values.
+   */
+  public JSONParserConfiguration() {
+    super();
+  }
+
+  @Override
+  protected JSONParserConfiguration clone() {
+    return new JSONParserConfiguration();
+  }
+
+  @SuppressWarnings("unchecked")
+  @Override
+  public JSONParserConfiguration withMaxNestingDepth(final int maxNestingDepth) {
+    return super.withMaxNestingDepth(maxNestingDepth);
+  }
+
+}
diff --git a/sources/main/java/org/json/JSONPointer.java b/sources/main/java/org/json/JSONPointer.java
index b3b39c81..3553b063 100644
--- a/sources/main/java/org/json/JSONPointer.java
+++ b/sources/main/java/org/json/JSONPointer.java
@@ -42,6 +42,12 @@ public class JSONPointer {
      */
     public static class Builder {
 
+        /**
+         * Constructs a new Builder object.
+         */
+        public Builder() {
+        }
+
         // Segments for the eventual JSONPointer string
         private final List<String> refTokens = new ArrayList<String>();
 
@@ -163,6 +169,12 @@ public class JSONPointer {
         //}
     }
 
+    /**
+     * Constructs a new JSONPointer instance with the provided list of reference tokens.
+     *
+     * @param refTokens A list of strings representing the reference tokens for the JSON Pointer.
+     *                  Each token identifies a step in the path to the targeted value.
+     */
     public JSONPointer(List<String> refTokens) {
         this.refTokens = new ArrayList<String>(refTokens);
     }
diff --git a/sources/main/java/org/json/JSONPointerException.java b/sources/main/java/org/json/JSONPointerException.java
index a0e128cd..dc5a25ad 100644
--- a/sources/main/java/org/json/JSONPointerException.java
+++ b/sources/main/java/org/json/JSONPointerException.java
@@ -14,10 +14,21 @@ Public Domain.
 public class JSONPointerException extends JSONException {
     private static final long serialVersionUID = 8872944667561856751L;
 
+    /**
+     * Constructs a new JSONPointerException with the specified error message.
+     *
+     * @param message The detail message describing the reason for the exception.
+     */
     public JSONPointerException(String message) {
         super(message);
     }
 
+    /**
+     * Constructs a new JSONPointerException with the specified error message and cause.
+     *
+     * @param message The detail message describing the reason for the exception.
+     * @param cause   The cause of the exception.
+     */
     public JSONPointerException(String message, Throwable cause) {
         super(message, cause);
     }
diff --git a/sources/main/java/org/json/JSONPropertyIgnore.java b/sources/main/java/org/json/JSONPropertyIgnore.java
index 7c5fa538..d3a5bc5a 100644
--- a/sources/main/java/org/json/JSONPropertyIgnore.java
+++ b/sources/main/java/org/json/JSONPropertyIgnore.java
@@ -11,13 +11,13 @@ import java.lang.annotation.Documented;
 import java.lang.annotation.Retention;
 import java.lang.annotation.Target;
 
-@Documented
-@Retention(RUNTIME)
-@Target({METHOD})
 /**
  * Use this annotation on a getter method to override the Bean name
  * parser for Bean -&gt; JSONObject mapping. If this annotation is
  * present at any level in the class hierarchy, then the method will
  * not be serialized from the bean into the JSONObject.
  */
+@Documented
+@Retention(RUNTIME)
+@Target({METHOD})
 public @interface JSONPropertyIgnore { }
diff --git a/sources/main/java/org/json/JSONPropertyName.java b/sources/main/java/org/json/JSONPropertyName.java
index a66f4ad4..0e4123f3 100644
--- a/sources/main/java/org/json/JSONPropertyName.java
+++ b/sources/main/java/org/json/JSONPropertyName.java
@@ -11,16 +11,17 @@ import java.lang.annotation.Documented;
 import java.lang.annotation.Retention;
 import java.lang.annotation.Target;
 
-@Documented
-@Retention(RUNTIME)
-@Target({METHOD})
 /**
  * Use this annotation on a getter method to override the Bean name
  * parser for Bean -&gt; JSONObject mapping. A value set to empty string <code>""</code>
  * will have the Bean parser fall back to the default field name processing.
  */
+@Documented
+@Retention(RUNTIME)
+@Target({METHOD})
 public @interface JSONPropertyName {
     /**
+     * The value of the JSON property.
      * @return The name of the property as to be used in the JSON Object.
      */
     String value();
diff --git a/sources/main/java/org/json/JSONString.java b/sources/main/java/org/json/JSONString.java
index cd8d1847..ee82720a 100644
--- a/sources/main/java/org/json/JSONString.java
+++ b/sources/main/java/org/json/JSONString.java
@@ -21,3 +21,4 @@ public interface JSONString {
      */
     public String toJSONString();
 }
+
diff --git a/sources/main/java/org/json/JSONTokener.java b/sources/main/java/org/json/JSONTokener.java
index e9ffff66..0bc6dfb6 100644
--- a/sources/main/java/org/json/JSONTokener.java
+++ b/sources/main/java/org/json/JSONTokener.java
@@ -1,11 +1,7 @@
 package org.json;
 
-import java.io.BufferedReader;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.io.Reader;
-import java.io.StringReader;
+import java.io.*;
+import java.nio.charset.Charset;
 
 /*
 Public Domain.
@@ -61,7 +57,7 @@ public class JSONTokener {
      * @param inputStream The source.
      */
     public JSONTokener(InputStream inputStream) {
-        this(new InputStreamReader(inputStream));
+        this(new InputStreamReader(inputStream, Charset.forName("UTF-8")));
     }
 
 
@@ -125,7 +121,7 @@ public class JSONTokener {
 
     /**
      * Checks if the end of the input has been reached.
-     *  
+     *
      * @return true if at the end of the file and we didn't step back
      */
     public boolean end() {
@@ -189,7 +185,7 @@ public class JSONTokener {
         this.previous = (char) c;
         return this.previous;
     }
-    
+
     /**
      * Get the last character read from the input or '\0' if nothing has been read yet.
      * @return the last character read from the input.
@@ -301,9 +297,9 @@ public class JSONTokener {
             c = this.next();
             switch (c) {
             case 0:
+            case '\n':
+            case '\r':
                 throw this.syntaxError("Unterminated string");
-			case '\r':
-				break;
             case '\\':
                 c = this.next();
                 switch (c) {
@@ -406,12 +402,7 @@ public class JSONTokener {
      */
     public Object nextValue() throws JSONException {
         char c = this.nextClean();
-        String string;
-
         switch (c) {
-        case '"':
-        case '\'':
-            return this.nextString(c);
         case '{':
             this.back();
             try {
@@ -427,6 +418,17 @@ public class JSONTokener {
                 throw new JSONException("JSON Array or Object depth too large to process.", e);
             }
         }
+        return nextSimpleValue(c);
+    }
+
+    Object nextSimpleValue(char c) {
+        String string;
+
+        switch (c) {
+        case '"':
+        case '\'':
+            return this.nextString(c);
+        }
 
         /*
          * Handle unquoted text. This could be the values true, false, or
@@ -522,4 +524,15 @@ public class JSONTokener {
         return " at " + this.index + " [character " + this.character + " line " +
                 this.line + "]";
     }
+
+    /**
+     * Closes the underlying reader, releasing any resources associated with it.
+     *
+     * @throws IOException If an I/O error occurs while closing the reader.
+     */
+    public void close() throws IOException {
+        if(reader!=null){
+            reader.close();
+        }
+    }
 }
diff --git a/sources/main/java/org/json/ParserConfiguration.java b/sources/main/java/org/json/ParserConfiguration.java
new file mode 100644
index 00000000..5cdc10d8
--- /dev/null
+++ b/sources/main/java/org/json/ParserConfiguration.java
@@ -0,0 +1,126 @@
+package org.json;
+/*
+Public Domain.
+*/
+
+/**
+ * Configuration base object for parsers. The configuration is immutable.
+ */
+@SuppressWarnings({""})
+public class ParserConfiguration {
+    /**
+     * Used to indicate there's no defined limit to the maximum nesting depth when parsing a document.
+     */
+    public static final int UNDEFINED_MAXIMUM_NESTING_DEPTH = -1;
+
+    /**
+     * The default maximum nesting depth when parsing a document.
+     */
+    public static final int DEFAULT_MAXIMUM_NESTING_DEPTH = 512;
+
+    /**
+     * Specifies if values should be kept as strings (<code>true</code>), or if
+     * they should try to be guessed into JSON values (numeric, boolean, string)
+     */
+    protected boolean keepStrings;
+
+    /**
+     * The maximum nesting depth when parsing a document.
+     */
+    protected int maxNestingDepth;
+
+    /**
+     * Constructs a new ParserConfiguration with default settings.
+     */
+    public ParserConfiguration() {
+        this.keepStrings = false;
+        this.maxNestingDepth = DEFAULT_MAXIMUM_NESTING_DEPTH;
+    }
+
+    /**
+     * Constructs a new ParserConfiguration with the specified settings.
+     *
+     * @param keepStrings     A boolean indicating whether to preserve strings during parsing.
+     * @param maxNestingDepth An integer representing the maximum allowed nesting depth.
+     */
+    protected ParserConfiguration(final boolean keepStrings, final int maxNestingDepth) {
+        this.keepStrings = keepStrings;
+        this.maxNestingDepth = maxNestingDepth;
+    }
+
+    /**
+     * Provides a new instance of the same configuration.
+     */
+    @Override
+    protected ParserConfiguration clone() {
+        // future modifications to this method should always ensure a "deep"
+        // clone in the case of collections. i.e. if a Map is added as a configuration
+        // item, a new map instance should be created and if possible each value in the
+        // map should be cloned as well. If the values of the map are known to also
+        // be immutable, then a shallow clone of the map is acceptable.
+        return new ParserConfiguration(
+            this.keepStrings,
+            this.maxNestingDepth
+        );
+    }
+
+    /**
+     * When parsing the XML into JSONML, specifies if values should be kept as strings (<code>true</code>), or if
+     * they should try to be guessed into JSON values (numeric, boolean, string)
+     *
+     * @return The <code>keepStrings</code> configuration value.
+     */
+    public boolean isKeepStrings() {
+        return this.keepStrings;
+    }
+
+    /**
+     * When parsing the XML into JSONML, specifies if values should be kept as strings (<code>true</code>), or if
+     * they should try to be guessed into JSON values (numeric, boolean, string)
+     *
+     * @param newVal
+     *      new value to use for the <code>keepStrings</code> configuration option.
+     * @param <T> the type of the configuration object
+     * 
+     * @return The existing configuration will not be modified. A new configuration is returned.
+     */
+    @SuppressWarnings("unchecked")
+    public <T extends ParserConfiguration> T withKeepStrings(final boolean newVal) {
+        T newConfig = (T)this.clone();
+        newConfig.keepStrings = newVal;
+        return newConfig;
+    }
+
+    /**
+     * The maximum nesting depth that the parser will descend before throwing an exception
+     * when parsing the XML into JSONML.
+     * @return the maximum nesting depth set for this configuration
+     */
+    public int getMaxNestingDepth() {
+        return maxNestingDepth;
+    }
+
+    /**
+     * Defines the maximum nesting depth that the parser will descend before throwing an exception
+     * when parsing the XML into JSONML. The default max nesting depth is 512, which means the parser
+     * will throw a JsonException if the maximum depth is reached.
+     * Using any negative value as a parameter is equivalent to setting no limit to the nesting depth,
+     * which means the parses will go as deep as the maximum call stack size allows.
+     * @param maxNestingDepth the maximum nesting depth allowed to the XML parser
+     * @param <T> the type of the configuration object
+     * 
+     * @return The existing configuration will not be modified. A new configuration is returned.
+     */
+    @SuppressWarnings("unchecked")
+    public <T extends ParserConfiguration> T withMaxNestingDepth(int maxNestingDepth) {
+        T newConfig = (T)this.clone();
+
+        if (maxNestingDepth > UNDEFINED_MAXIMUM_NESTING_DEPTH) {
+            newConfig.maxNestingDepth = maxNestingDepth;
+        } else {
+            newConfig.maxNestingDepth = UNDEFINED_MAXIMUM_NESTING_DEPTH;
+        }
+
+        return newConfig;
+    }
+}
diff --git a/sources/protocol-relay/java/net/lax1dude/eaglercraft/v1_8/sp/relay/pkt/RelayPacket.java b/sources/protocol-relay/java/net/lax1dude/eaglercraft/v1_8/sp/relay/pkt/RelayPacket.java
index fd793eaf..3f5f1ee2 100644
--- a/sources/protocol-relay/java/net/lax1dude/eaglercraft/v1_8/sp/relay/pkt/RelayPacket.java
+++ b/sources/protocol-relay/java/net/lax1dude/eaglercraft/v1_8/sp/relay/pkt/RelayPacket.java
@@ -27,8 +27,8 @@ import java.util.Map;
  */
 public class RelayPacket {
 
-	private static final Map<Integer,Class<? extends RelayPacket>> definedPacketClasses = new HashMap();
-	private static final Map<Class<? extends RelayPacket>,Integer> definedPacketIds = new HashMap();
+	private static final Map<Integer,Class<? extends RelayPacket>> definedPacketClasses = new HashMap<>();
+	private static final Map<Class<? extends RelayPacket>,Integer> definedPacketIds = new HashMap<>();
 
 	private static void register(int id, Class<? extends RelayPacket> clazz) {
 		definedPacketClasses.put(id, clazz);
diff --git a/sources/protocol-relay/java/net/lax1dude/eaglercraft/v1_8/sp/relay/pkt/RelayPacket01ICEServers.java b/sources/protocol-relay/java/net/lax1dude/eaglercraft/v1_8/sp/relay/pkt/RelayPacket01ICEServers.java
index a7bc7f63..84829891 100644
--- a/sources/protocol-relay/java/net/lax1dude/eaglercraft/v1_8/sp/relay/pkt/RelayPacket01ICEServers.java
+++ b/sources/protocol-relay/java/net/lax1dude/eaglercraft/v1_8/sp/relay/pkt/RelayPacket01ICEServers.java
@@ -55,7 +55,7 @@ public class RelayPacket01ICEServers extends RelayPacket {
 	}
 
 	public RelayPacket01ICEServers() {
-		this.servers = new ArrayList();
+		this.servers = new ArrayList<>();
 	}
 
 	public RelayPacket01ICEServers(Collection<RelayServer> servers) {
diff --git a/sources/protocol-relay/java/net/lax1dude/eaglercraft/v1_8/sp/relay/pkt/RelayPacket07LocalWorlds.java b/sources/protocol-relay/java/net/lax1dude/eaglercraft/v1_8/sp/relay/pkt/RelayPacket07LocalWorlds.java
index 23ece948..b53f29b5 100644
--- a/sources/protocol-relay/java/net/lax1dude/eaglercraft/v1_8/sp/relay/pkt/RelayPacket07LocalWorlds.java
+++ b/sources/protocol-relay/java/net/lax1dude/eaglercraft/v1_8/sp/relay/pkt/RelayPacket07LocalWorlds.java
@@ -64,7 +64,7 @@ public class RelayPacket07LocalWorlds extends RelayPacket {
 	public void read(DataInputStream input) throws IOException {
 		int l = input.read();
 		if(worldsList == null) {
-			worldsList = new ArrayList(l);
+			worldsList = new ArrayList<>(l);
 		}else {
 			worldsList.clear();
 		}
diff --git a/sources/resources/SignedClientTemplate.txt b/sources/resources/SignedClientTemplate.txt
index 32731d94..247d3f69 100644
--- a/sources/resources/SignedClientTemplate.txt
+++ b/sources/resources/SignedClientTemplate.txt
@@ -1,8 +1,8 @@
 <!DOCTYPE html>
-<html>
+<html style="width:100%;height:100%;background-color:black;">
 <head>
 <meta charset="UTF-8" />
-<meta name="viewport" content="width=device-width, initial-scale=1.0" />
+<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0" />
 <meta name="description" content="EaglercraftX 1.8 Offline" />
 <meta name="keywords" content="eaglercraft, eaglercraftx, minecraft, 1.8, 1.8.8" />
 <title>EaglercraftX 1.8</title>
@@ -12,7 +12,7 @@
 <meta property="og:description" content="Play minecraft 1.8 in your browser" />
 <script type="text/javascript">
 "use strict";
-const relayId = Math.floor(Math.random() * 3);
+var relayId = Math.floor(Math.random() * 3);
 
 // %%%%%%%%% launch options %%%%%%%%%%%%
 
@@ -36,7 +36,7 @@ window.eaglercraftXOptsHints = {
 <script type="text/javascript">
 "use strict";
 (function(){
-	function eaglerBundleUnwrap(tagIn) { const e = document.getElementById(tagIn); const ret = e.innerText; e.remove(); return ret;  }
+	function eaglerBundleUnwrap(tagIn) { var e = document.getElementById(tagIn); var ret = e.innerText; document.head.removeChild(e); return ret;  }
 	window.eaglercraftXClientSignature = eaglerBundleUnwrap("eaglercraftXClientSignature");
 	window.eaglercraftXClientBundle = eaglerBundleUnwrap("eaglercraftXClientBundle");
 })();
@@ -44,42 +44,161 @@ window.eaglercraftXOptsHints = {
 <script type="text/javascript">
 "use strict";
 (function(){
-	function fetchB64PayloadSafe() {
-		const dataURL = window.eaglercraftXClientBundle;
-		if(!dataURL.startsWith("data:application/octet-stream;base64,")) {
-			return fetch(dataURL, { cache: "force-cache" }).then((response) => response.blob());
-		}
-		return new Promise((resolve) => {
-			fetch(dataURL)
-				.then((response) => response.blob())
-				.then((blob) => { resolve(blob); })
-				.catch((err) => {
-					console.error("Caught an error decoding base64 via fetch, doing it the slow way instead...");
-					// MIT License - https://github.com/beatgammit/base64-js
-					const base64js = (function(){return function(){function b(d,e,g){function a(j,i){if(!e[j]){if(!d[j]){var f="function"==typeof require&&require;if(!i&&f)return f(j,!0);if(h)return h(j,!0);var c=new Error("Cannot find module '"+j+"'");throw c.code="MODULE_NOT_FOUND",c}var k=e[j]={exports:{}};d[j][0].call(k.exports,function(b){var c=d[j][1][b];return a(c||b)},k,k.exports,b,d,e,g)}return e[j].exports}for(var h="function"==typeof require&&require,c=0;c<g.length;c++)a(g[c]);return a}return b}()({"/":[function(a,b,c){"use strict";function d(a){var b=a.length;if(0<b%4)throw new Error("Invalid string. Length must be a multiple of 4");var c=a.indexOf("=");-1===c&&(c=b);var d=c===b?0:4-c%4;return[c,d]}function e(a,b,c){return 3*(b+c)/4-c}function f(a){var b,c,f=d(a),g=f[0],j=f[1],k=new Uint8Array(e(a,g,j)),l=0,m=0<j?g-4:g;for(c=0;c<m;c+=4)b=h[a.charCodeAt(c)]<<18|h[a.charCodeAt(c+1)]<<12|h[a.charCodeAt(c+2)]<<6|h[a.charCodeAt(c+3)],k[l++]=255&b>>16,k[l++]=255&b>>8,k[l++]=255&b;return 2===j&&(b=h[a.charCodeAt(c)]<<2|h[a.charCodeAt(c+1)]>>4,k[l++]=255&b),1===j&&(b=h[a.charCodeAt(c)]<<10|h[a.charCodeAt(c+1)]<<4|h[a.charCodeAt(c+2)]>>2,k[l++]=255&b>>8,k[l++]=255&b),k}c.byteLength=function b(a){var c=d(a),e=c[0],f=c[1];return 3*(e+f)/4-f},c.toByteArray=f;for(var g=[],h=[],j="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",k=0,l=j.length;k<l;++k)g[k]=j[k],h[j.charCodeAt(k)]=k;h[45]=62,h[95]=63},{}]},{},[])("/")})();
-					const bytesDec = base64js.toByteArray(dataURL.substring(37)).buffer;
-					const bytesBlob = new Blob([bytesDec], { type: "application/octet-stream" });
-					window.eaglercraftXClientBundle = URL.createObjectURL(bytesBlob);
-					console.error("Created " + bytesDec.byteLength + " byte object URL: " + window.eaglercraftXClientBundle);
-					resolve(bytesBlob);
+	(function(a){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=a();else if("function"==typeof define&&define.amd)define([],a);else{var b;b="undefined"==typeof window?"undefined"==typeof global?"undefined"==typeof self?this:self:global:window,b.base64js=a()}})(function(){return function(){function b(d,e,g){function a(j,i){if(!e[j]){if(!d[j]){var f="function"==typeof require&&require;if(!i&&f)return f(j,!0);if(h)return h(j,!0);var c=new Error("Cannot find module '"+j+"'");throw c.code="MODULE_NOT_FOUND",c}var k=e[j]={exports:{}};d[j][0].call(k.exports,function(b){var c=d[j][1][b];return a(c||b)},k,k.exports,b,d,e,g)}return e[j].exports}for(var h="function"==typeof require&&require,c=0;c<g.length;c++)a(g[c]);return a}return b}()({"/":[function(a,b,c){'use strict';function d(a){var b=a.length;if(0<b%4)throw new Error("Invalid string. Length must be a multiple of 4");var c=a.indexOf("=");-1===c&&(c=b);var d=c===b?0:4-c%4;return[c,d]}function e(a,b,c){return 3*(b+c)/4-c}function f(a){var b,c,f=d(a),g=f[0],h=f[1],j=new m(e(a,g,h)),k=0,n=0<h?g-4:g;for(c=0;c<n;c+=4)b=l[a.charCodeAt(c)]<<18|l[a.charCodeAt(c+1)]<<12|l[a.charCodeAt(c+2)]<<6|l[a.charCodeAt(c+3)],j[k++]=255&b>>16,j[k++]=255&b>>8,j[k++]=255&b;return 2===h&&(b=l[a.charCodeAt(c)]<<2|l[a.charCodeAt(c+1)]>>4,j[k++]=255&b),1===h&&(b=l[a.charCodeAt(c)]<<10|l[a.charCodeAt(c+1)]<<4|l[a.charCodeAt(c+2)]>>2,j[k++]=255&b>>8,j[k++]=255&b),j}function g(a){return k[63&a>>18]+k[63&a>>12]+k[63&a>>6]+k[63&a]}function h(a,b,c){for(var d,e=[],f=b;f<c;f+=3)d=(16711680&a[f]<<16)+(65280&a[f+1]<<8)+(255&a[f+2]),e.push(g(d));return e.join("")}function j(a){for(var b,c=a.length,d=c%3,e=[],f=16383,g=0,j=c-d;g<j;g+=f)e.push(h(a,g,g+f>j?j:g+f));return 1===d?(b=a[c-1],e.push(k[b>>2]+k[63&b<<4]+"==")):2===d&&(b=(a[c-2]<<8)+a[c-1],e.push(k[b>>10]+k[63&b>>4]+k[63&b<<2]+"=")),e.join("")}c.byteLength=function(a){var b=d(a),c=b[0],e=b[1];return 3*(c+e)/4-e},c.toByteArray=f,c.fromByteArray=j;for(var k=[],l=[],m="undefined"==typeof Uint8Array?Array:Uint8Array,n="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",o=0,p=n.length;o<p;++o)k[o]=n[o],l[n.charCodeAt(o)]=o;l[45]=62,l[95]=63},{}]},{},[])("/")});
+	var sameOriginSupport = -1;
+	var checkSameOriginSupport = function(callback0) {
+		if(sameOriginSupport == -1) {
+			try {
+				(function(callback) {
+					if((typeof URL === "undefined") || (typeof URL.createObjectURL !== "function")) {
+						sameOriginSupport = 1;
+						callback(false);
+					}else {
+						var theObjURL = URL.createObjectURL(new Blob([new Uint8Array([69, 69, 69, 69])]));
+						if(!theObjURL) {
+							sameOriginSupport = 1;
+							callback(false);
+						}
+						doXHR(theObjURL, function(dataRet) {
+							if(dataRet) {
+								var typedArr = new Uint8Array(dataRet);
+								if(typedArr.length === 4 && typedArr[0] === 69 && typedArr[1] === 69 && typedArr[2] === 69 && typedArr[3] === 69) {
+									sameOriginSupport = 0;
+									callback(true);
+								}else {
+									sameOriginSupport = 1;
+									callback(false);
+								}
+							}else {
+								sameOriginSupport = 1;
+								callback(false);
+							}
+						});
+					}
+				})(function(valRet) {
+					if(!valRet) {
+						console.error("Same origin XHR support detected as false, using data: url...");
+					}
+					callback0(valRet);
 				});
-		});
-	}
-	var ds = new DecompressionStream("gzip");
-	var result = [];
-	function fetchStream(reader) {
-		reader.read().then(function processData({ done, value }) {
-			if (done) {
-				window.clientScriptSrcURL = URL.createObjectURL(new Blob(result, { type: "text/javascript;charset=utf-8" }));
-				result = [];
-				ds = null;
-				return;
+			}catch(ex) {
+				console.error("Same origin XHR support detection failed, using data: url...");
+				callback0(false);
+			}
+		}else {
+			callback0(!sameOriginSupport);
+		}
+	};
+	var blobToArrayBuffer = function(blobIn, callback) {
+		if(typeof blobIn.arrayBuffer === "undefined") {
+			blobIn.arrayBuffer().then(callback);
+		}else {
+			(function(phileReader) {
+				phileReader.addEventListener("load", function(evt) {
+					callback(phileReader.result);
+				});
+				phileReader.readAsArrayBuffer(blobIn);
+			})(new FileReader());
+		}
+	};
+	var completeXHR = function(callback, arg) {
+		if(!callback.comp) {
+			callback.comp = true;
+			callback.cb(arg);
+		}
+	};
+	var doXHR = function(urlIn, callback) {
+		(function(theXHRObj, callbackStruct){
+			theXHRObj.responseType = "arraybuffer";
+			theXHRObj.addEventListener("load", function(evt) { var stat = theXHRObj.status; if(stat === 0 || (stat >= 200 && stat < 400)) { completeXHR(callbackStruct, theXHRObj.response); } else { completeXHR(callbackStruct, null); } });
+			theXHRObj.addEventListener("error", function(evt) {  completeXHR(callbackStruct, null); });
+			theXHRObj.open("GET", urlIn, true);
+			theXHRObj.send();
+		})(new XMLHttpRequest(), { cb: callback, comp: false });
+	};
+	var decodeBase64URL = function(urlIn, callbackOut) {
+		doXHR(urlIn, function(data) {
+			if(!data) {
+				try {
+					console.error("Caught an error decoding base64 via fetch, doing it the slow way instead...");
+					callbackOut(base64js.toByteArray(urlIn.substring(37)).buffer);
+				}catch(ex) {
+					console.error("Failed to decode base64!");
+					console.error(ex);
+					callbackOut(null);
+				}
+			}else {
+				callbackOut(data);
+			}
+		});
+	};
+	if(typeof window.DecompressionStream === "undefined") {
+		checkSameOriginSupport(function(soSupported) {
+			var theWorkerObj;
+			var workerSrc = "InVzZSBzdHJpY3QiOwovKiEgcGFrbyAyLjEuMCBodHRwczovL2dpdGh1Yi5jb20vbm9kZWNhL3Bha28gQGxpY2Vuc2UgKE1JVCBBTkQgWmxpYikgKi8KIWZ1bmN0aW9uKGUsdCl7Im9iamVjdCI9PXR5cGVvZiBleHBvcnRzJiYidW5kZWZpbmVkIiE9dHlwZW9mIG1vZHVsZT90KGV4cG9ydHMpOiJmdW5jdGlvbiI9PXR5cGVvZiBkZWZpbmUmJmRlZmluZS5hbWQ/ZGVmaW5lKFsiZXhwb3J0cyJdLHQpOnQoKGU9InVuZGVmaW5lZCIhPXR5cGVvZiBnbG9iYWxUaGlzP2dsb2JhbFRoaXM6ZXx8c2VsZikucGFrbz17fSl9KHRoaXMsKGZ1bmN0aW9uKGUpeyJ1c2Ugc3RyaWN0Ijt2YXIgdD1mdW5jdGlvbihlLHQsaSxuKXtmb3IodmFyIGE9NjU1MzUmZXwwLHI9ZT4+PjE2JjY1NTM1fDAsbz0wOzAhPT1pOyl7aS09bz1pPjJlMz8yZTM6aTtkb3tyPXIrKGE9YSt0W24rK118MCl8MH13aGlsZSgtLW8pO2ElPTY1NTIxLHIlPTY1NTIxfXJldHVybiBhfHI8PDE2fDB9LGk9bmV3IFVpbnQzMkFycmF5KGZ1bmN0aW9uKCl7Zm9yKHZhciBlLHQ9W10saT0wO2k8MjU2O2krKyl7ZT1pO2Zvcih2YXIgbj0wO248ODtuKyspZT0xJmU/Mzk4ODI5MjM4NF5lPj4+MTplPj4+MTt0W2ldPWV9cmV0dXJuIHR9KCkpLG49ZnVuY3Rpb24oZSx0LG4sYSl7dmFyIHI9aSxvPWErbjtlXj0tMTtmb3IodmFyIHM9YTtzPG87cysrKWU9ZT4+PjheclsyNTUmKGVedFtzXSldO3JldHVybi0xXmV9LGE9MTYyMDkscj1mdW5jdGlvbihlLHQpe3ZhciBpLG4scixvLHMsbCxmLGQsaCxjLHUsdyxiLG0sayxfLHYsZyxwLHkseCxFLFIsQSxaPWUuc3RhdGU7aT1lLm5leHRfaW4sUj1lLmlucHV0LG49aSsoZS5hdmFpbF9pbi01KSxyPWUubmV4dF9vdXQsQT1lLm91dHB1dCxvPXItKHQtZS5hdmFpbF9vdXQpLHM9cisoZS5hdmFpbF9vdXQtMjU3KSxsPVouZG1heCxmPVoud3NpemUsZD1aLndoYXZlLGg9Wi53bmV4dCxjPVoud2luZG93LHU9Wi5ob2xkLHc9Wi5iaXRzLGI9Wi5sZW5jb2RlLG09Wi5kaXN0Y29kZSxrPSgxPDxaLmxlbmJpdHMpLTEsXz0oMTw8Wi5kaXN0Yml0cyktMTtlOmRve3c8MTUmJih1Kz1SW2krK108PHcsdys9OCx1Kz1SW2krK108PHcsdys9OCksdj1iW3Uma107dDpmb3IoOzspe2lmKHU+Pj49Zz12Pj4+MjQsdy09ZywwPT09KGc9dj4+PjE2JjI1NSkpQVtyKytdPTY1NTM1JnY7ZWxzZXtpZighKDE2JmcpKXtpZigwPT0oNjQmZykpe3Y9YlsoNjU1MzUmdikrKHUmKDE8PGcpLTEpXTtjb250aW51ZSB0fWlmKDMyJmcpe1oubW9kZT0xNjE5MTticmVhayBlfWUubXNnPSJpbnZhbGlkIGxpdGVyYWwvbGVuZ3RoIGNvZGUiLFoubW9kZT1hO2JyZWFrIGV9cD02NTUzNSZ2LChnJj0xNSkmJih3PGcmJih1Kz1SW2krK108PHcsdys9OCkscCs9dSYoMTw8ZyktMSx1Pj4+PWcsdy09ZyksdzwxNSYmKHUrPVJbaSsrXTw8dyx3Kz04LHUrPVJbaSsrXTw8dyx3Kz04KSx2PW1bdSZfXTtpOmZvcig7Oyl7aWYodT4+Pj1nPXY+Pj4yNCx3LT1nLCEoMTYmKGc9dj4+PjE2JjI1NSkpKXtpZigwPT0oNjQmZykpe3Y9bVsoNjU1MzUmdikrKHUmKDE8PGcpLTEpXTtjb250aW51ZSBpfWUubXNnPSJpbnZhbGlkIGRpc3RhbmNlIGNvZGUiLFoubW9kZT1hO2JyZWFrIGV9aWYoeT02NTUzNSZ2LHc8KGcmPTE1KSYmKHUrPVJbaSsrXTw8dywodys9OCk8ZyYmKHUrPVJbaSsrXTw8dyx3Kz04KSksKHkrPXUmKDE8PGcpLTEpPmwpe2UubXNnPSJpbnZhbGlkIGRpc3RhbmNlIHRvbyBmYXIgYmFjayIsWi5tb2RlPWE7YnJlYWsgZX1pZih1Pj4+PWcsdy09Zyx5PihnPXItbykpe2lmKChnPXktZyk+ZCYmWi5zYW5lKXtlLm1zZz0iaW52YWxpZCBkaXN0YW5jZSB0b28gZmFyIGJhY2siLFoubW9kZT1hO2JyZWFrIGV9aWYoeD0wLEU9YywwPT09aCl7aWYoeCs9Zi1nLGc8cCl7cC09Zztkb3tBW3IrK109Y1t4KytdfXdoaWxlKC0tZyk7eD1yLXksRT1BfX1lbHNlIGlmKGg8Zyl7aWYoeCs9ZitoLWcsKGctPWgpPHApe3AtPWc7ZG97QVtyKytdPWNbeCsrXX13aGlsZSgtLWcpO2lmKHg9MCxoPHApe3AtPWc9aDtkb3tBW3IrK109Y1t4KytdfXdoaWxlKC0tZyk7eD1yLXksRT1BfX19ZWxzZSBpZih4Kz1oLWcsZzxwKXtwLT1nO2Rve0FbcisrXT1jW3grK119d2hpbGUoLS1nKTt4PXIteSxFPUF9Zm9yKDtwPjI7KUFbcisrXT1FW3grK10sQVtyKytdPUVbeCsrXSxBW3IrK109RVt4KytdLHAtPTM7cCYmKEFbcisrXT1FW3grK10scD4xJiYoQVtyKytdPUVbeCsrXSkpfWVsc2V7eD1yLXk7ZG97QVtyKytdPUFbeCsrXSxBW3IrK109QVt4KytdLEFbcisrXT1BW3grK10scC09M313aGlsZShwPjIpO3AmJihBW3IrK109QVt4KytdLHA+MSYmKEFbcisrXT1BW3grK10pKX1icmVha319YnJlYWt9fXdoaWxlKGk8biYmcjxzKTtpLT1wPXc+PjMsdSY9KDE8PCh3LT1wPDwzKSktMSxlLm5leHRfaW49aSxlLm5leHRfb3V0PXIsZS5hdmFpbF9pbj1pPG4/bi1pKzU6NS0oaS1uKSxlLmF2YWlsX291dD1yPHM/cy1yKzI1NzoyNTctKHItcyksWi5ob2xkPXUsWi5iaXRzPXd9LG89MTUscz1uZXcgVWludDE2QXJyYXkoWzMsNCw1LDYsNyw4LDksMTAsMTEsMTMsMTUsMTcsMTksMjMsMjcsMzEsMzUsNDMsNTEsNTksNjcsODMsOTksMTE1LDEzMSwxNjMsMTk1LDIyNywyNTgsMCwwXSksbD1uZXcgVWludDhBcnJheShbMTYsMTYsMTYsMTYsMTYsMTYsMTYsMTYsMTcsMTcsMTcsMTcsMTgsMTgsMTgsMTgsMTksMTksMTksMTksMjAsMjAsMjAsMjAsMjEsMjEsMjEsMjEsMTYsNzIsNzhdKSxmPW5ldyBVaW50MTZBcnJheShbMSwyLDMsNCw1LDcsOSwxMywxNywyNSwzMyw0OSw2NSw5NywxMjksMTkzLDI1NywzODUsNTEzLDc2OSwxMDI1LDE1MzcsMjA0OSwzMDczLDQwOTcsNjE0NSw4MTkzLDEyMjg5LDE2Mzg1LDI0NTc3LDAsMF0pLGQ9bmV3IFVpbnQ4QXJyYXkoWzE2LDE2LDE2LDE2LDE3LDE3LDE4LDE4LDE5LDE5LDIwLDIwLDIxLDIxLDIyLDIyLDIzLDIzLDI0LDI0LDI1LDI1LDI2LDI2LDI3LDI3LDI4LDI4LDI5LDI5LDY0LDY0XSksaD1mdW5jdGlvbihlLHQsaSxuLGEscixoLGMpe3ZhciB1LHcsYixtLGssXyx2LGcscCx5PWMuYml0cyx4PTAsRT0wLFI9MCxBPTAsWj0wLFM9MCxUPTAsTz0wLFU9MCxEPTAsST1udWxsLEI9bmV3IFVpbnQxNkFycmF5KDE2KSxOPW5ldyBVaW50MTZBcnJheSgxNiksQz1udWxsO2Zvcih4PTA7eDw9bzt4KyspQlt4XT0wO2ZvcihFPTA7RTxuO0UrKylCW3RbaStFXV0rKztmb3IoWj15LEE9bztBPj0xJiYwPT09QltBXTtBLS0pO2lmKFo+QSYmKFo9QSksMD09PUEpcmV0dXJuIGFbcisrXT0yMDk3MTUyMCxhW3IrK109MjA5NzE1MjAsYy5iaXRzPTEsMDtmb3IoUj0xO1I8QSYmMD09PUJbUl07UisrKTtmb3IoWjxSJiYoWj1SKSxPPTEseD0xO3g8PW87eCsrKWlmKE88PD0xLChPLT1CW3hdKTwwKXJldHVybi0xO2lmKE8+MCYmKDA9PT1lfHwxIT09QSkpcmV0dXJuLTE7Zm9yKE5bMV09MCx4PTE7eDxvO3grKylOW3grMV09Tlt4XStCW3hdO2ZvcihFPTA7RTxuO0UrKykwIT09dFtpK0VdJiYoaFtOW3RbaStFXV0rK109RSk7aWYoMD09PWU/KEk9Qz1oLF89MjApOjE9PT1lPyhJPXMsQz1sLF89MjU3KTooST1mLEM9ZCxfPTApLEQ9MCxFPTAseD1SLGs9cixTPVosVD0wLGI9LTEsbT0oVT0xPDxaKS0xLDE9PT1lJiZVPjg1Mnx8Mj09PWUmJlU+NTkyKXJldHVybiAxO2Zvcig7Oyl7dj14LVQsaFtFXSsxPF8/KGc9MCxwPWhbRV0pOmhbRV0+PV8/KGc9Q1toW0VdLV9dLHA9SVtoW0VdLV9dKTooZz05NixwPTApLHU9MTw8eC1ULFI9dz0xPDxTO2Rve2FbaysoRD4+VCkrKHctPXUpXT12PDwyNHxnPDwxNnxwfDB9d2hpbGUoMCE9PXcpO2Zvcih1PTE8PHgtMTtEJnU7KXU+Pj0xO2lmKDAhPT11PyhEJj11LTEsRCs9dSk6RD0wLEUrKywwPT0tLUJbeF0pe2lmKHg9PT1BKWJyZWFrO3g9dFtpK2hbRV1dfWlmKHg+WiYmKEQmbSkhPT1iKXtmb3IoMD09PVQmJihUPVopLGsrPVIsTz0xPDwoUz14LVQpO1MrVDxBJiYhKChPLT1CW1MrVF0pPD0wKTspUysrLE88PD0xO2lmKFUrPTE8PFMsMT09PWUmJlU+ODUyfHwyPT09ZSYmVT41OTIpcmV0dXJuIDE7YVtiPUQmbV09Wjw8MjR8Uzw8MTZ8ay1yfDB9fXJldHVybiAwIT09RCYmKGFbaytEXT14LVQ8PDI0fDY0PDwxNnwwKSxjLmJpdHM9WiwwfSxjPXtaX05PX0ZMVVNIOjAsWl9QQVJUSUFMX0ZMVVNIOjEsWl9TWU5DX0ZMVVNIOjIsWl9GVUxMX0ZMVVNIOjMsWl9GSU5JU0g6NCxaX0JMT0NLOjUsWl9UUkVFUzo2LFpfT0s6MCxaX1NUUkVBTV9FTkQ6MSxaX05FRURfRElDVDoyLFpfRVJSTk86LTEsWl9TVFJFQU1fRVJST1I6LTIsWl9EQVRBX0VSUk9SOi0zLFpfTUVNX0VSUk9SOi00LFpfQlVGX0VSUk9SOi01LFpfTk9fQ09NUFJFU1NJT046MCxaX0JFU1RfU1BFRUQ6MSxaX0JFU1RfQ09NUFJFU1NJT046OSxaX0RFRkFVTFRfQ09NUFJFU1NJT046LTEsWl9GSUxURVJFRDoxLFpfSFVGRk1BTl9PTkxZOjIsWl9STEU6MyxaX0ZJWEVEOjQsWl9ERUZBVUxUX1NUUkFURUdZOjAsWl9CSU5BUlk6MCxaX1RFWFQ6MSxaX1VOS05PV046MixaX0RFRkxBVEVEOjh9LHU9Yy5aX0ZJTklTSCx3PWMuWl9CTE9DSyxiPWMuWl9UUkVFUyxtPWMuWl9PSyxrPWMuWl9TVFJFQU1fRU5ELF89Yy5aX05FRURfRElDVCx2PWMuWl9TVFJFQU1fRVJST1IsZz1jLlpfREFUQV9FUlJPUixwPWMuWl9NRU1fRVJST1IseT1jLlpfQlVGX0VSUk9SLHg9Yy5aX0RFRkxBVEVELEU9MTYxODAsUj0xNjE5MCxBPTE2MTkxLFo9MTYxOTIsUz0xNjE5NCxUPTE2MTk5LE89MTYyMDAsVT0xNjIwNixEPTE2MjA5LEk9ZnVuY3Rpb24oZSl7cmV0dXJuKGU+Pj4yNCYyNTUpKyhlPj4+OCY2NTI4MCkrKCg2NTI4MCZlKTw8OCkrKCgyNTUmZSk8PDI0KX07ZnVuY3Rpb24gQigpe3RoaXMuc3RybT1udWxsLHRoaXMubW9kZT0wLHRoaXMubGFzdD0hMSx0aGlzLndyYXA9MCx0aGlzLmhhdmVkaWN0PSExLHRoaXMuZmxhZ3M9MCx0aGlzLmRtYXg9MCx0aGlzLmNoZWNrPTAsdGhpcy50b3RhbD0wLHRoaXMuaGVhZD1udWxsLHRoaXMud2JpdHM9MCx0aGlzLndzaXplPTAsdGhpcy53aGF2ZT0wLHRoaXMud25leHQ9MCx0aGlzLndpbmRvdz1udWxsLHRoaXMuaG9sZD0wLHRoaXMuYml0cz0wLHRoaXMubGVuZ3RoPTAsdGhpcy5vZmZzZXQ9MCx0aGlzLmV4dHJhPTAsdGhpcy5sZW5jb2RlPW51bGwsdGhpcy5kaXN0Y29kZT1udWxsLHRoaXMubGVuYml0cz0wLHRoaXMuZGlzdGJpdHM9MCx0aGlzLm5jb2RlPTAsdGhpcy5ubGVuPTAsdGhpcy5uZGlzdD0wLHRoaXMuaGF2ZT0wLHRoaXMubmV4dD1udWxsLHRoaXMubGVucz1uZXcgVWludDE2QXJyYXkoMzIwKSx0aGlzLndvcms9bmV3IFVpbnQxNkFycmF5KDI4OCksdGhpcy5sZW5keW49bnVsbCx0aGlzLmRpc3RkeW49bnVsbCx0aGlzLnNhbmU9MCx0aGlzLmJhY2s9MCx0aGlzLndhcz0wfXZhciBOLEMsej1mdW5jdGlvbihlKXtpZighZSlyZXR1cm4gMTt2YXIgdD1lLnN0YXRlO3JldHVybiF0fHx0LnN0cm0hPT1lfHx0Lm1vZGU8RXx8dC5tb2RlPjE2MjExPzE6MH0sRj1mdW5jdGlvbihlKXtpZih6KGUpKXJldHVybiB2O3ZhciB0PWUuc3RhdGU7cmV0dXJuIGUudG90YWxfaW49ZS50b3RhbF9vdXQ9dC50b3RhbD0wLGUubXNnPSIiLHQud3JhcCYmKGUuYWRsZXI9MSZ0LndyYXApLHQubW9kZT1FLHQubGFzdD0wLHQuaGF2ZWRpY3Q9MCx0LmZsYWdzPS0xLHQuZG1heD0zMjc2OCx0LmhlYWQ9bnVsbCx0LmhvbGQ9MCx0LmJpdHM9MCx0LmxlbmNvZGU9dC5sZW5keW49bmV3IEludDMyQXJyYXkoODUyKSx0LmRpc3Rjb2RlPXQuZGlzdGR5bj1uZXcgSW50MzJBcnJheSg1OTIpLHQuc2FuZT0xLHQuYmFjaz0tMSxtfSxMPWZ1bmN0aW9uKGUpe2lmKHooZSkpcmV0dXJuIHY7dmFyIHQ9ZS5zdGF0ZTtyZXR1cm4gdC53c2l6ZT0wLHQud2hhdmU9MCx0LnduZXh0PTAsRihlKX0sTT1mdW5jdGlvbihlLHQpe3ZhciBpO2lmKHooZSkpcmV0dXJuIHY7dmFyIG49ZS5zdGF0ZTtyZXR1cm4gdDwwPyhpPTAsdD0tdCk6KGk9NSsodD4+NCksdDw0OCYmKHQmPTE1KSksdCYmKHQ8OHx8dD4xNSk/djoobnVsbCE9PW4ud2luZG93JiZuLndiaXRzIT09dCYmKG4ud2luZG93PW51bGwpLG4ud3JhcD1pLG4ud2JpdHM9dCxMKGUpKX0sSD1mdW5jdGlvbihlLHQpe2lmKCFlKXJldHVybiB2O3ZhciBpPW5ldyBCO2Uuc3RhdGU9aSxpLnN0cm09ZSxpLndpbmRvdz1udWxsLGkubW9kZT1FO3ZhciBuPU0oZSx0KTtyZXR1cm4gbiE9PW0mJihlLnN0YXRlPW51bGwpLG59LGo9ITAsSz1mdW5jdGlvbihlKXtpZihqKXtOPW5ldyBJbnQzMkFycmF5KDUxMiksQz1uZXcgSW50MzJBcnJheSgzMik7Zm9yKHZhciB0PTA7dDwxNDQ7KWUubGVuc1t0KytdPTg7Zm9yKDt0PDI1NjspZS5sZW5zW3QrK109OTtmb3IoO3Q8MjgwOyllLmxlbnNbdCsrXT03O2Zvcig7dDwyODg7KWUubGVuc1t0KytdPTg7Zm9yKGgoMSxlLmxlbnMsMCwyODgsTiwwLGUud29yayx7Yml0czo5fSksdD0wO3Q8MzI7KWUubGVuc1t0KytdPTU7aCgyLGUubGVucywwLDMyLEMsMCxlLndvcmsse2JpdHM6NX0pLGo9ITF9ZS5sZW5jb2RlPU4sZS5sZW5iaXRzPTksZS5kaXN0Y29kZT1DLGUuZGlzdGJpdHM9NX0sUD1mdW5jdGlvbihlLHQsaSxuKXt2YXIgYSxyPWUuc3RhdGU7cmV0dXJuIG51bGw9PT1yLndpbmRvdyYmKHIud3NpemU9MTw8ci53Yml0cyxyLnduZXh0PTAsci53aGF2ZT0wLHIud2luZG93PW5ldyBVaW50OEFycmF5KHIud3NpemUpKSxuPj1yLndzaXplPyhyLndpbmRvdy5zZXQodC5zdWJhcnJheShpLXIud3NpemUsaSksMCksci53bmV4dD0wLHIud2hhdmU9ci53c2l6ZSk6KChhPXIud3NpemUtci53bmV4dCk+biYmKGE9biksci53aW5kb3cuc2V0KHQuc3ViYXJyYXkoaS1uLGktbithKSxyLnduZXh0KSwobi09YSk/KHIud2luZG93LnNldCh0LnN1YmFycmF5KGktbixpKSwwKSxyLnduZXh0PW4sci53aGF2ZT1yLndzaXplKTooci53bmV4dCs9YSxyLnduZXh0PT09ci53c2l6ZSYmKHIud25leHQ9MCksci53aGF2ZTxyLndzaXplJiYoci53aGF2ZSs9YSkpKSwwfSxZPXtpbmZsYXRlUmVzZXQ6TCxpbmZsYXRlUmVzZXQyOk0saW5mbGF0ZVJlc2V0S2VlcDpGLGluZmxhdGVJbml0OmZ1bmN0aW9uKGUpe3JldHVybiBIKGUsMTUpfSxpbmZsYXRlSW5pdDI6SCxpbmZsYXRlOmZ1bmN0aW9uKGUsaSl7dmFyIGEsbyxzLGwsZixkLGMsQixOLEMsRixMLE0sSCxqLFksRyxYLFcscSxKLFEsViwkLGVlPTAsdGU9bmV3IFVpbnQ4QXJyYXkoNCksaWU9bmV3IFVpbnQ4QXJyYXkoWzE2LDE3LDE4LDAsOCw3LDksNiwxMCw1LDExLDQsMTIsMywxMywyLDE0LDEsMTVdKTtpZih6KGUpfHwhZS5vdXRwdXR8fCFlLmlucHV0JiYwIT09ZS5hdmFpbF9pbilyZXR1cm4gdjsoYT1lLnN0YXRlKS5tb2RlPT09QSYmKGEubW9kZT1aKSxmPWUubmV4dF9vdXQscz1lLm91dHB1dCxjPWUuYXZhaWxfb3V0LGw9ZS5uZXh0X2luLG89ZS5pbnB1dCxkPWUuYXZhaWxfaW4sQj1hLmhvbGQsTj1hLmJpdHMsQz1kLEY9YyxRPW07ZTpmb3IoOzspc3dpdGNoKGEubW9kZSl7Y2FzZSBFOmlmKDA9PT1hLndyYXApe2EubW9kZT1aO2JyZWFrfWZvcig7TjwxNjspe2lmKDA9PT1kKWJyZWFrIGU7ZC0tLEIrPW9bbCsrXTw8TixOKz04fWlmKDImYS53cmFwJiYzNTYxNT09PUIpezA9PT1hLndiaXRzJiYoYS53Yml0cz0xNSksYS5jaGVjaz0wLHRlWzBdPTI1NSZCLHRlWzFdPUI+Pj44JjI1NSxhLmNoZWNrPW4oYS5jaGVjayx0ZSwyLDApLEI9MCxOPTAsYS5tb2RlPTE2MTgxO2JyZWFrfWlmKGEuaGVhZCYmKGEuaGVhZC5kb25lPSExKSwhKDEmYS53cmFwKXx8KCgoMjU1JkIpPDw4KSsoQj4+OCkpJTMxKXtlLm1zZz0iaW5jb3JyZWN0IGhlYWRlciBjaGVjayIsYS5tb2RlPUQ7YnJlYWt9aWYoKDE1JkIpIT09eCl7ZS5tc2c9InVua25vd24gY29tcHJlc3Npb24gbWV0aG9kIixhLm1vZGU9RDticmVha31pZihOLT00LEo9OCsoMTUmKEI+Pj49NCkpLDA9PT1hLndiaXRzJiYoYS53Yml0cz1KKSxKPjE1fHxKPmEud2JpdHMpe2UubXNnPSJpbnZhbGlkIHdpbmRvdyBzaXplIixhLm1vZGU9RDticmVha31hLmRtYXg9MTw8YS53Yml0cyxhLmZsYWdzPTAsZS5hZGxlcj1hLmNoZWNrPTEsYS5tb2RlPTUxMiZCPzE2MTg5OkEsQj0wLE49MDticmVhaztjYXNlIDE2MTgxOmZvcig7TjwxNjspe2lmKDA9PT1kKWJyZWFrIGU7ZC0tLEIrPW9bbCsrXTw8TixOKz04fWlmKGEuZmxhZ3M9QiwoMjU1JmEuZmxhZ3MpIT09eCl7ZS5tc2c9InVua25vd24gY29tcHJlc3Npb24gbWV0aG9kIixhLm1vZGU9RDticmVha31pZig1NzM0NCZhLmZsYWdzKXtlLm1zZz0idW5rbm93biBoZWFkZXIgZmxhZ3Mgc2V0IixhLm1vZGU9RDticmVha31hLmhlYWQmJihhLmhlYWQudGV4dD1CPj44JjEpLDUxMiZhLmZsYWdzJiY0JmEud3JhcCYmKHRlWzBdPTI1NSZCLHRlWzFdPUI+Pj44JjI1NSxhLmNoZWNrPW4oYS5jaGVjayx0ZSwyLDApKSxCPTAsTj0wLGEubW9kZT0xNjE4MjtjYXNlIDE2MTgyOmZvcig7TjwzMjspe2lmKDA9PT1kKWJyZWFrIGU7ZC0tLEIrPW9bbCsrXTw8TixOKz04fWEuaGVhZCYmKGEuaGVhZC50aW1lPUIpLDUxMiZhLmZsYWdzJiY0JmEud3JhcCYmKHRlWzBdPTI1NSZCLHRlWzFdPUI+Pj44JjI1NSx0ZVsyXT1CPj4+MTYmMjU1LHRlWzNdPUI+Pj4yNCYyNTUsYS5jaGVjaz1uKGEuY2hlY2ssdGUsNCwwKSksQj0wLE49MCxhLm1vZGU9MTYxODM7Y2FzZSAxNjE4Mzpmb3IoO048MTY7KXtpZigwPT09ZClicmVhayBlO2QtLSxCKz1vW2wrK108PE4sTis9OH1hLmhlYWQmJihhLmhlYWQueGZsYWdzPTI1NSZCLGEuaGVhZC5vcz1CPj44KSw1MTImYS5mbGFncyYmNCZhLndyYXAmJih0ZVswXT0yNTUmQix0ZVsxXT1CPj4+OCYyNTUsYS5jaGVjaz1uKGEuY2hlY2ssdGUsMiwwKSksQj0wLE49MCxhLm1vZGU9MTYxODQ7Y2FzZSAxNjE4NDppZigxMDI0JmEuZmxhZ3Mpe2Zvcig7TjwxNjspe2lmKDA9PT1kKWJyZWFrIGU7ZC0tLEIrPW9bbCsrXTw8TixOKz04fWEubGVuZ3RoPUIsYS5oZWFkJiYoYS5oZWFkLmV4dHJhX2xlbj1CKSw1MTImYS5mbGFncyYmNCZhLndyYXAmJih0ZVswXT0yNTUmQix0ZVsxXT1CPj4+OCYyNTUsYS5jaGVjaz1uKGEuY2hlY2ssdGUsMiwwKSksQj0wLE49MH1lbHNlIGEuaGVhZCYmKGEuaGVhZC5leHRyYT1udWxsKTthLm1vZGU9MTYxODU7Y2FzZSAxNjE4NTppZigxMDI0JmEuZmxhZ3MmJigoTD1hLmxlbmd0aCk+ZCYmKEw9ZCksTCYmKGEuaGVhZCYmKEo9YS5oZWFkLmV4dHJhX2xlbi1hLmxlbmd0aCxhLmhlYWQuZXh0cmF8fChhLmhlYWQuZXh0cmE9bmV3IFVpbnQ4QXJyYXkoYS5oZWFkLmV4dHJhX2xlbikpLGEuaGVhZC5leHRyYS5zZXQoby5zdWJhcnJheShsLGwrTCksSikpLDUxMiZhLmZsYWdzJiY0JmEud3JhcCYmKGEuY2hlY2s9bihhLmNoZWNrLG8sTCxsKSksZC09TCxsKz1MLGEubGVuZ3RoLT1MKSxhLmxlbmd0aCkpYnJlYWsgZTthLmxlbmd0aD0wLGEubW9kZT0xNjE4NjtjYXNlIDE2MTg2OmlmKDIwNDgmYS5mbGFncyl7aWYoMD09PWQpYnJlYWsgZTtMPTA7ZG97Sj1vW2wrTCsrXSxhLmhlYWQmJkomJmEubGVuZ3RoPDY1NTM2JiYoYS5oZWFkLm5hbWUrPVN0cmluZy5mcm9tQ2hhckNvZGUoSikpfXdoaWxlKEomJkw8ZCk7aWYoNTEyJmEuZmxhZ3MmJjQmYS53cmFwJiYoYS5jaGVjaz1uKGEuY2hlY2ssbyxMLGwpKSxkLT1MLGwrPUwsSilicmVhayBlfWVsc2UgYS5oZWFkJiYoYS5oZWFkLm5hbWU9bnVsbCk7YS5sZW5ndGg9MCxhLm1vZGU9MTYxODc7Y2FzZSAxNjE4NzppZig0MDk2JmEuZmxhZ3Mpe2lmKDA9PT1kKWJyZWFrIGU7TD0wO2Rve0o9b1tsK0wrK10sYS5oZWFkJiZKJiZhLmxlbmd0aDw2NTUzNiYmKGEuaGVhZC5jb21tZW50Kz1TdHJpbmcuZnJvbUNoYXJDb2RlKEopKX13aGlsZShKJiZMPGQpO2lmKDUxMiZhLmZsYWdzJiY0JmEud3JhcCYmKGEuY2hlY2s9bihhLmNoZWNrLG8sTCxsKSksZC09TCxsKz1MLEopYnJlYWsgZX1lbHNlIGEuaGVhZCYmKGEuaGVhZC5jb21tZW50PW51bGwpO2EubW9kZT0xNjE4ODtjYXNlIDE2MTg4OmlmKDUxMiZhLmZsYWdzKXtmb3IoO048MTY7KXtpZigwPT09ZClicmVhayBlO2QtLSxCKz1vW2wrK108PE4sTis9OH1pZig0JmEud3JhcCYmQiE9PSg2NTUzNSZhLmNoZWNrKSl7ZS5tc2c9ImhlYWRlciBjcmMgbWlzbWF0Y2giLGEubW9kZT1EO2JyZWFrfUI9MCxOPTB9YS5oZWFkJiYoYS5oZWFkLmhjcmM9YS5mbGFncz4+OSYxLGEuaGVhZC5kb25lPSEwKSxlLmFkbGVyPWEuY2hlY2s9MCxhLm1vZGU9QTticmVhaztjYXNlIDE2MTg5OmZvcig7TjwzMjspe2lmKDA9PT1kKWJyZWFrIGU7ZC0tLEIrPW9bbCsrXTw8TixOKz04fWUuYWRsZXI9YS5jaGVjaz1JKEIpLEI9MCxOPTAsYS5tb2RlPVI7Y2FzZSBSOmlmKDA9PT1hLmhhdmVkaWN0KXJldHVybiBlLm5leHRfb3V0PWYsZS5hdmFpbF9vdXQ9YyxlLm5leHRfaW49bCxlLmF2YWlsX2luPWQsYS5ob2xkPUIsYS5iaXRzPU4sXztlLmFkbGVyPWEuY2hlY2s9MSxhLm1vZGU9QTtjYXNlIEE6aWYoaT09PXd8fGk9PT1iKWJyZWFrIGU7Y2FzZSBaOmlmKGEubGFzdCl7Qj4+Pj03Jk4sTi09NyZOLGEubW9kZT1VO2JyZWFrfWZvcig7TjwzOyl7aWYoMD09PWQpYnJlYWsgZTtkLS0sQis9b1tsKytdPDxOLE4rPTh9c3dpdGNoKGEubGFzdD0xJkIsTi09MSwzJihCPj4+PTEpKXtjYXNlIDA6YS5tb2RlPTE2MTkzO2JyZWFrO2Nhc2UgMTppZihLKGEpLGEubW9kZT1ULGk9PT1iKXtCPj4+PTIsTi09MjticmVhayBlfWJyZWFrO2Nhc2UgMjphLm1vZGU9MTYxOTY7YnJlYWs7Y2FzZSAzOmUubXNnPSJpbnZhbGlkIGJsb2NrIHR5cGUiLGEubW9kZT1EfUI+Pj49MixOLT0yO2JyZWFrO2Nhc2UgMTYxOTM6Zm9yKEI+Pj49NyZOLE4tPTcmTjtOPDMyOyl7aWYoMD09PWQpYnJlYWsgZTtkLS0sQis9b1tsKytdPDxOLE4rPTh9aWYoKDY1NTM1JkIpIT0oQj4+PjE2XjY1NTM1KSl7ZS5tc2c9ImludmFsaWQgc3RvcmVkIGJsb2NrIGxlbmd0aHMiLGEubW9kZT1EO2JyZWFrfWlmKGEubGVuZ3RoPTY1NTM1JkIsQj0wLE49MCxhLm1vZGU9UyxpPT09YilicmVhayBlO2Nhc2UgUzphLm1vZGU9MTYxOTU7Y2FzZSAxNjE5NTppZihMPWEubGVuZ3RoKXtpZihMPmQmJihMPWQpLEw+YyYmKEw9YyksMD09PUwpYnJlYWsgZTtzLnNldChvLnN1YmFycmF5KGwsbCtMKSxmKSxkLT1MLGwrPUwsYy09TCxmKz1MLGEubGVuZ3RoLT1MO2JyZWFrfWEubW9kZT1BO2JyZWFrO2Nhc2UgMTYxOTY6Zm9yKDtOPDE0Oyl7aWYoMD09PWQpYnJlYWsgZTtkLS0sQis9b1tsKytdPDxOLE4rPTh9aWYoYS5ubGVuPTI1NysoMzEmQiksQj4+Pj01LE4tPTUsYS5uZGlzdD0xKygzMSZCKSxCPj4+PTUsTi09NSxhLm5jb2RlPTQrKDE1JkIpLEI+Pj49NCxOLT00LGEubmxlbj4yODZ8fGEubmRpc3Q+MzApe2UubXNnPSJ0b28gbWFueSBsZW5ndGggb3IgZGlzdGFuY2Ugc3ltYm9scyIsYS5tb2RlPUQ7YnJlYWt9YS5oYXZlPTAsYS5tb2RlPTE2MTk3O2Nhc2UgMTYxOTc6Zm9yKDthLmhhdmU8YS5uY29kZTspe2Zvcig7TjwzOyl7aWYoMD09PWQpYnJlYWsgZTtkLS0sQis9b1tsKytdPDxOLE4rPTh9YS5sZW5zW2llW2EuaGF2ZSsrXV09NyZCLEI+Pj49MyxOLT0zfWZvcig7YS5oYXZlPDE5OylhLmxlbnNbaWVbYS5oYXZlKytdXT0wO2lmKGEubGVuY29kZT1hLmxlbmR5bixhLmxlbmJpdHM9NyxWPXtiaXRzOmEubGVuYml0c30sUT1oKDAsYS5sZW5zLDAsMTksYS5sZW5jb2RlLDAsYS53b3JrLFYpLGEubGVuYml0cz1WLmJpdHMsUSl7ZS5tc2c9ImludmFsaWQgY29kZSBsZW5ndGhzIHNldCIsYS5tb2RlPUQ7YnJlYWt9YS5oYXZlPTAsYS5tb2RlPTE2MTk4O2Nhc2UgMTYxOTg6Zm9yKDthLmhhdmU8YS5ubGVuK2EubmRpc3Q7KXtmb3IoO1k9KGVlPWEubGVuY29kZVtCJigxPDxhLmxlbmJpdHMpLTFdKT4+PjE2JjI1NSxHPTY1NTM1JmVlLCEoKGo9ZWU+Pj4yNCk8PU4pOyl7aWYoMD09PWQpYnJlYWsgZTtkLS0sQis9b1tsKytdPDxOLE4rPTh9aWYoRzwxNilCPj4+PWosTi09aixhLmxlbnNbYS5oYXZlKytdPUc7ZWxzZXtpZigxNj09PUcpe2ZvcigkPWorMjtOPCQ7KXtpZigwPT09ZClicmVhayBlO2QtLSxCKz1vW2wrK108PE4sTis9OH1pZihCPj4+PWosTi09aiwwPT09YS5oYXZlKXtlLm1zZz0iaW52YWxpZCBiaXQgbGVuZ3RoIHJlcGVhdCIsYS5tb2RlPUQ7YnJlYWt9Sj1hLmxlbnNbYS5oYXZlLTFdLEw9MysoMyZCKSxCPj4+PTIsTi09Mn1lbHNlIGlmKDE3PT09Ryl7Zm9yKCQ9aiszO048JDspe2lmKDA9PT1kKWJyZWFrIGU7ZC0tLEIrPW9bbCsrXTw8TixOKz04fU4tPWosSj0wLEw9MysoNyYoQj4+Pj1qKSksQj4+Pj0zLE4tPTN9ZWxzZXtmb3IoJD1qKzc7TjwkOyl7aWYoMD09PWQpYnJlYWsgZTtkLS0sQis9b1tsKytdPDxOLE4rPTh9Ti09aixKPTAsTD0xMSsoMTI3JihCPj4+PWopKSxCPj4+PTcsTi09N31pZihhLmhhdmUrTD5hLm5sZW4rYS5uZGlzdCl7ZS5tc2c9ImludmFsaWQgYml0IGxlbmd0aCByZXBlYXQiLGEubW9kZT1EO2JyZWFrfWZvcig7TC0tOylhLmxlbnNbYS5oYXZlKytdPUp9fWlmKGEubW9kZT09PUQpYnJlYWs7aWYoMD09PWEubGVuc1syNTZdKXtlLm1zZz0iaW52YWxpZCBjb2RlIC0tIG1pc3NpbmcgZW5kLW9mLWJsb2NrIixhLm1vZGU9RDticmVha31pZihhLmxlbmJpdHM9OSxWPXtiaXRzOmEubGVuYml0c30sUT1oKDEsYS5sZW5zLDAsYS5ubGVuLGEubGVuY29kZSwwLGEud29yayxWKSxhLmxlbmJpdHM9Vi5iaXRzLFEpe2UubXNnPSJpbnZhbGlkIGxpdGVyYWwvbGVuZ3RocyBzZXQiLGEubW9kZT1EO2JyZWFrfWlmKGEuZGlzdGJpdHM9NixhLmRpc3Rjb2RlPWEuZGlzdGR5bixWPXtiaXRzOmEuZGlzdGJpdHN9LFE9aCgyLGEubGVucyxhLm5sZW4sYS5uZGlzdCxhLmRpc3Rjb2RlLDAsYS53b3JrLFYpLGEuZGlzdGJpdHM9Vi5iaXRzLFEpe2UubXNnPSJpbnZhbGlkIGRpc3RhbmNlcyBzZXQiLGEubW9kZT1EO2JyZWFrfWlmKGEubW9kZT1ULGk9PT1iKWJyZWFrIGU7Y2FzZSBUOmEubW9kZT1PO2Nhc2UgTzppZihkPj02JiZjPj0yNTgpe2UubmV4dF9vdXQ9ZixlLmF2YWlsX291dD1jLGUubmV4dF9pbj1sLGUuYXZhaWxfaW49ZCxhLmhvbGQ9QixhLmJpdHM9TixyKGUsRiksZj1lLm5leHRfb3V0LHM9ZS5vdXRwdXQsYz1lLmF2YWlsX291dCxsPWUubmV4dF9pbixvPWUuaW5wdXQsZD1lLmF2YWlsX2luLEI9YS5ob2xkLE49YS5iaXRzLGEubW9kZT09PUEmJihhLmJhY2s9LTEpO2JyZWFrfWZvcihhLmJhY2s9MDtZPShlZT1hLmxlbmNvZGVbQiYoMTw8YS5sZW5iaXRzKS0xXSk+Pj4xNiYyNTUsRz02NTUzNSZlZSwhKChqPWVlPj4+MjQpPD1OKTspe2lmKDA9PT1kKWJyZWFrIGU7ZC0tLEIrPW9bbCsrXTw8TixOKz04fWlmKFkmJjA9PSgyNDAmWSkpe2ZvcihYPWosVz1ZLHE9RztZPShlZT1hLmxlbmNvZGVbcSsoKEImKDE8PFgrVyktMSk+PlgpXSk+Pj4xNiYyNTUsRz02NTUzNSZlZSwhKFgrKGo9ZWU+Pj4yNCk8PU4pOyl7aWYoMD09PWQpYnJlYWsgZTtkLS0sQis9b1tsKytdPDxOLE4rPTh9Qj4+Pj1YLE4tPVgsYS5iYWNrKz1YfWlmKEI+Pj49aixOLT1qLGEuYmFjays9aixhLmxlbmd0aD1HLDA9PT1ZKXthLm1vZGU9MTYyMDU7YnJlYWt9aWYoMzImWSl7YS5iYWNrPS0xLGEubW9kZT1BO2JyZWFrfWlmKDY0Jlkpe2UubXNnPSJpbnZhbGlkIGxpdGVyYWwvbGVuZ3RoIGNvZGUiLGEubW9kZT1EO2JyZWFrfWEuZXh0cmE9MTUmWSxhLm1vZGU9MTYyMDE7Y2FzZSAxNjIwMTppZihhLmV4dHJhKXtmb3IoJD1hLmV4dHJhO048JDspe2lmKDA9PT1kKWJyZWFrIGU7ZC0tLEIrPW9bbCsrXTw8TixOKz04fWEubGVuZ3RoKz1CJigxPDxhLmV4dHJhKS0xLEI+Pj49YS5leHRyYSxOLT1hLmV4dHJhLGEuYmFjays9YS5leHRyYX1hLndhcz1hLmxlbmd0aCxhLm1vZGU9MTYyMDI7Y2FzZSAxNjIwMjpmb3IoO1k9KGVlPWEuZGlzdGNvZGVbQiYoMTw8YS5kaXN0Yml0cyktMV0pPj4+MTYmMjU1LEc9NjU1MzUmZWUsISgoaj1lZT4+PjI0KTw9Tik7KXtpZigwPT09ZClicmVhayBlO2QtLSxCKz1vW2wrK108PE4sTis9OH1pZigwPT0oMjQwJlkpKXtmb3IoWD1qLFc9WSxxPUc7WT0oZWU9YS5kaXN0Y29kZVtxKygoQiYoMTw8WCtXKS0xKT4+WCldKT4+PjE2JjI1NSxHPTY1NTM1JmVlLCEoWCsoaj1lZT4+PjI0KTw9Tik7KXtpZigwPT09ZClicmVhayBlO2QtLSxCKz1vW2wrK108PE4sTis9OH1CPj4+PVgsTi09WCxhLmJhY2srPVh9aWYoQj4+Pj1qLE4tPWosYS5iYWNrKz1qLDY0Jlkpe2UubXNnPSJpbnZhbGlkIGRpc3RhbmNlIGNvZGUiLGEubW9kZT1EO2JyZWFrfWEub2Zmc2V0PUcsYS5leHRyYT0xNSZZLGEubW9kZT0xNjIwMztjYXNlIDE2MjAzOmlmKGEuZXh0cmEpe2ZvcigkPWEuZXh0cmE7TjwkOyl7aWYoMD09PWQpYnJlYWsgZTtkLS0sQis9b1tsKytdPDxOLE4rPTh9YS5vZmZzZXQrPUImKDE8PGEuZXh0cmEpLTEsQj4+Pj1hLmV4dHJhLE4tPWEuZXh0cmEsYS5iYWNrKz1hLmV4dHJhfWlmKGEub2Zmc2V0PmEuZG1heCl7ZS5tc2c9ImludmFsaWQgZGlzdGFuY2UgdG9vIGZhciBiYWNrIixhLm1vZGU9RDticmVha31hLm1vZGU9MTYyMDQ7Y2FzZSAxNjIwNDppZigwPT09YylicmVhayBlO2lmKEw9Ri1jLGEub2Zmc2V0Pkwpe2lmKChMPWEub2Zmc2V0LUwpPmEud2hhdmUmJmEuc2FuZSl7ZS5tc2c9ImludmFsaWQgZGlzdGFuY2UgdG9vIGZhciBiYWNrIixhLm1vZGU9RDticmVha31MPmEud25leHQ/KEwtPWEud25leHQsTT1hLndzaXplLUwpOk09YS53bmV4dC1MLEw+YS5sZW5ndGgmJihMPWEubGVuZ3RoKSxIPWEud2luZG93fWVsc2UgSD1zLE09Zi1hLm9mZnNldCxMPWEubGVuZ3RoO0w+YyYmKEw9YyksYy09TCxhLmxlbmd0aC09TDtkb3tzW2YrK109SFtNKytdfXdoaWxlKC0tTCk7MD09PWEubGVuZ3RoJiYoYS5tb2RlPU8pO2JyZWFrO2Nhc2UgMTYyMDU6aWYoMD09PWMpYnJlYWsgZTtzW2YrK109YS5sZW5ndGgsYy0tLGEubW9kZT1PO2JyZWFrO2Nhc2UgVTppZihhLndyYXApe2Zvcig7TjwzMjspe2lmKDA9PT1kKWJyZWFrIGU7ZC0tLEJ8PW9bbCsrXTw8TixOKz04fWlmKEYtPWMsZS50b3RhbF9vdXQrPUYsYS50b3RhbCs9Riw0JmEud3JhcCYmRiYmKGUuYWRsZXI9YS5jaGVjaz1hLmZsYWdzP24oYS5jaGVjayxzLEYsZi1GKTp0KGEuY2hlY2sscyxGLGYtRikpLEY9Yyw0JmEud3JhcCYmKGEuZmxhZ3M/QjpJKEIpKSE9PWEuY2hlY2spe2UubXNnPSJpbmNvcnJlY3QgZGF0YSBjaGVjayIsYS5tb2RlPUQ7YnJlYWt9Qj0wLE49MH1hLm1vZGU9MTYyMDc7Y2FzZSAxNjIwNzppZihhLndyYXAmJmEuZmxhZ3Mpe2Zvcig7TjwzMjspe2lmKDA9PT1kKWJyZWFrIGU7ZC0tLEIrPW9bbCsrXTw8TixOKz04fWlmKDQmYS53cmFwJiZCIT09KDQyOTQ5NjcyOTUmYS50b3RhbCkpe2UubXNnPSJpbmNvcnJlY3QgbGVuZ3RoIGNoZWNrIixhLm1vZGU9RDticmVha31CPTAsTj0wfWEubW9kZT0xNjIwODtjYXNlIDE2MjA4OlE9azticmVhayBlO2Nhc2UgRDpRPWc7YnJlYWsgZTtjYXNlIDE2MjEwOnJldHVybiBwO2RlZmF1bHQ6cmV0dXJuIHZ9cmV0dXJuIGUubmV4dF9vdXQ9ZixlLmF2YWlsX291dD1jLGUubmV4dF9pbj1sLGUuYXZhaWxfaW49ZCxhLmhvbGQ9QixhLmJpdHM9TiwoYS53c2l6ZXx8RiE9PWUuYXZhaWxfb3V0JiZhLm1vZGU8RCYmKGEubW9kZTxVfHxpIT09dSkpJiZQKGUsZS5vdXRwdXQsZS5uZXh0X291dCxGLWUuYXZhaWxfb3V0KSxDLT1lLmF2YWlsX2luLEYtPWUuYXZhaWxfb3V0LGUudG90YWxfaW4rPUMsZS50b3RhbF9vdXQrPUYsYS50b3RhbCs9Riw0JmEud3JhcCYmRiYmKGUuYWRsZXI9YS5jaGVjaz1hLmZsYWdzP24oYS5jaGVjayxzLEYsZS5uZXh0X291dC1GKTp0KGEuY2hlY2sscyxGLGUubmV4dF9vdXQtRikpLGUuZGF0YV90eXBlPWEuYml0cysoYS5sYXN0PzY0OjApKyhhLm1vZGU9PT1BPzEyODowKSsoYS5tb2RlPT09VHx8YS5tb2RlPT09Uz8yNTY6MCksKDA9PT1DJiYwPT09Rnx8aT09PXUpJiZRPT09bSYmKFE9eSksUX0saW5mbGF0ZUVuZDpmdW5jdGlvbihlKXtpZih6KGUpKXJldHVybiB2O3ZhciB0PWUuc3RhdGU7cmV0dXJuIHQud2luZG93JiYodC53aW5kb3c9bnVsbCksZS5zdGF0ZT1udWxsLG19LGluZmxhdGVHZXRIZWFkZXI6ZnVuY3Rpb24oZSx0KXtpZih6KGUpKXJldHVybiB2O3ZhciBpPWUuc3RhdGU7cmV0dXJuIDA9PSgyJmkud3JhcCk/djooaS5oZWFkPXQsdC5kb25lPSExLG0pfSxpbmZsYXRlU2V0RGljdGlvbmFyeTpmdW5jdGlvbihlLGkpe3ZhciBuLGE9aS5sZW5ndGg7cmV0dXJuIHooZSl8fDAhPT0obj1lLnN0YXRlKS53cmFwJiZuLm1vZGUhPT1SP3Y6bi5tb2RlPT09UiYmdCgxLGksYSwwKSE9PW4uY2hlY2s/ZzpQKGUsaSxhLGEpPyhuLm1vZGU9MTYyMTAscCk6KG4uaGF2ZWRpY3Q9MSxtKX0saW5mbGF0ZUluZm86InBha28gaW5mbGF0ZSAoZnJvbSBOb2RlY2EgcHJvamVjdCkifTtmdW5jdGlvbiBHKGUpe3JldHVybiBHPSJmdW5jdGlvbiI9PXR5cGVvZiBTeW1ib2wmJiJzeW1ib2wiPT10eXBlb2YgU3ltYm9sLml0ZXJhdG9yP2Z1bmN0aW9uKGUpe3JldHVybiB0eXBlb2YgZX06ZnVuY3Rpb24oZSl7cmV0dXJuIGUmJiJmdW5jdGlvbiI9PXR5cGVvZiBTeW1ib2wmJmUuY29uc3RydWN0b3I9PT1TeW1ib2wmJmUhPT1TeW1ib2wucHJvdG90eXBlPyJzeW1ib2wiOnR5cGVvZiBlfSxHKGUpfXZhciBYPWZ1bmN0aW9uKGUsdCl7cmV0dXJuIE9iamVjdC5wcm90b3R5cGUuaGFzT3duUHJvcGVydHkuY2FsbChlLHQpfSxXPWZ1bmN0aW9uKGUpe2Zvcih2YXIgdD1BcnJheS5wcm90b3R5cGUuc2xpY2UuY2FsbChhcmd1bWVudHMsMSk7dC5sZW5ndGg7KXt2YXIgaT10LnNoaWZ0KCk7aWYoaSl7aWYoIm9iamVjdCIhPT1HKGkpKXRocm93IG5ldyBUeXBlRXJyb3IoaSsibXVzdCBiZSBub24tb2JqZWN0Iik7Zm9yKHZhciBuIGluIGkpWChpLG4pJiYoZVtuXT1pW25dKX19cmV0dXJuIGV9LHE9ZnVuY3Rpb24oZSl7Zm9yKHZhciB0PTAsaT0wLG49ZS5sZW5ndGg7aTxuO2krKyl0Kz1lW2ldLmxlbmd0aDtmb3IodmFyIGE9bmV3IFVpbnQ4QXJyYXkodCkscj0wLG89MCxzPWUubGVuZ3RoO3I8cztyKyspe3ZhciBsPWVbcl07YS5zZXQobCxvKSxvKz1sLmxlbmd0aH1yZXR1cm4gYX0sSj0hMDt0cnl7U3RyaW5nLmZyb21DaGFyQ29kZS5hcHBseShudWxsLG5ldyBVaW50OEFycmF5KDEpKX1jYXRjaChlKXtKPSExfWZvcih2YXIgUT1uZXcgVWludDhBcnJheSgyNTYpLFY9MDtWPDI1NjtWKyspUVtWXT1WPj0yNTI/NjpWPj0yNDg/NTpWPj0yNDA/NDpWPj0yMjQ/MzpWPj0xOTI/MjoxO1FbMjU0XT1RWzI1NF09MTt2YXIgJD1mdW5jdGlvbihlKXtpZigiZnVuY3Rpb24iPT10eXBlb2YgVGV4dEVuY29kZXImJlRleHRFbmNvZGVyLnByb3RvdHlwZS5lbmNvZGUpcmV0dXJuKG5ldyBUZXh0RW5jb2RlcikuZW5jb2RlKGUpO3ZhciB0LGksbixhLHIsbz1lLmxlbmd0aCxzPTA7Zm9yKGE9MDthPG87YSsrKTU1Mjk2PT0oNjQ1MTImKGk9ZS5jaGFyQ29kZUF0KGEpKSkmJmErMTxvJiY1NjMyMD09KDY0NTEyJihuPWUuY2hhckNvZGVBdChhKzEpKSkmJihpPTY1NTM2KyhpLTU1Mjk2PDwxMCkrKG4tNTYzMjApLGErKykscys9aTwxMjg/MTppPDIwNDg/MjppPDY1NTM2PzM6NDtmb3IodD1uZXcgVWludDhBcnJheShzKSxyPTAsYT0wO3I8czthKyspNTUyOTY9PSg2NDUxMiYoaT1lLmNoYXJDb2RlQXQoYSkpKSYmYSsxPG8mJjU2MzIwPT0oNjQ1MTImKG49ZS5jaGFyQ29kZUF0KGErMSkpKSYmKGk9NjU1MzYrKGktNTUyOTY8PDEwKSsobi01NjMyMCksYSsrKSxpPDEyOD90W3IrK109aTppPDIwNDg/KHRbcisrXT0xOTJ8aT4+PjYsdFtyKytdPTEyOHw2MyZpKTppPDY1NTM2Pyh0W3IrK109MjI0fGk+Pj4xMix0W3IrK109MTI4fGk+Pj42JjYzLHRbcisrXT0xMjh8NjMmaSk6KHRbcisrXT0yNDB8aT4+PjE4LHRbcisrXT0xMjh8aT4+PjEyJjYzLHRbcisrXT0xMjh8aT4+PjYmNjMsdFtyKytdPTEyOHw2MyZpKTtyZXR1cm4gdH0sZWU9ZnVuY3Rpb24oZSx0KXt2YXIgaSxuLGE9dHx8ZS5sZW5ndGg7aWYoImZ1bmN0aW9uIj09dHlwZW9mIFRleHREZWNvZGVyJiZUZXh0RGVjb2Rlci5wcm90b3R5cGUuZGVjb2RlKXJldHVybihuZXcgVGV4dERlY29kZXIpLmRlY29kZShlLnN1YmFycmF5KDAsdCkpO3ZhciByPW5ldyBBcnJheSgyKmEpO2ZvcihuPTAsaT0wO2k8YTspe3ZhciBvPWVbaSsrXTtpZihvPDEyOClyW24rK109bztlbHNle3ZhciBzPVFbb107aWYocz40KXJbbisrXT02NTUzMyxpKz1zLTE7ZWxzZXtmb3IobyY9Mj09PXM/MzE6Mz09PXM/MTU6NztzPjEmJmk8YTspbz1vPDw2fDYzJmVbaSsrXSxzLS07cz4xP3JbbisrXT02NTUzMzpvPDY1NTM2P3JbbisrXT1vOihvLT02NTUzNixyW24rK109NTUyOTZ8bz4+MTAmMTAyMyxyW24rK109NTYzMjB8MTAyMyZvKX19fXJldHVybiBmdW5jdGlvbihlLHQpe2lmKHQ8NjU1MzQmJmUuc3ViYXJyYXkmJkopcmV0dXJuIFN0cmluZy5mcm9tQ2hhckNvZGUuYXBwbHkobnVsbCxlLmxlbmd0aD09PXQ/ZTplLnN1YmFycmF5KDAsdCkpO2Zvcih2YXIgaT0iIixuPTA7bjx0O24rKylpKz1TdHJpbmcuZnJvbUNoYXJDb2RlKGVbbl0pO3JldHVybiBpfShyLG4pfSx0ZT1mdW5jdGlvbihlLHQpeyh0PXR8fGUubGVuZ3RoKT5lLmxlbmd0aCYmKHQ9ZS5sZW5ndGgpO2Zvcih2YXIgaT10LTE7aT49MCYmMTI4PT0oMTkyJmVbaV0pOylpLS07cmV0dXJuIGk8MHx8MD09PWk/dDppK1FbZVtpXV0+dD9pOnR9LGllPXsyOiJuZWVkIGRpY3Rpb25hcnkiLDE6InN0cmVhbSBlbmQiLDA6IiIsIi0xIjoiZmlsZSBlcnJvciIsIi0yIjoic3RyZWFtIGVycm9yIiwiLTMiOiJkYXRhIGVycm9yIiwiLTQiOiJpbnN1ZmZpY2llbnQgbWVtb3J5IiwiLTUiOiJidWZmZXIgZXJyb3IiLCItNiI6ImluY29tcGF0aWJsZSB2ZXJzaW9uIn07dmFyIG5lPWZ1bmN0aW9uKCl7dGhpcy5pbnB1dD1udWxsLHRoaXMubmV4dF9pbj0wLHRoaXMuYXZhaWxfaW49MCx0aGlzLnRvdGFsX2luPTAsdGhpcy5vdXRwdXQ9bnVsbCx0aGlzLm5leHRfb3V0PTAsdGhpcy5hdmFpbF9vdXQ9MCx0aGlzLnRvdGFsX291dD0wLHRoaXMubXNnPSIiLHRoaXMuc3RhdGU9bnVsbCx0aGlzLmRhdGFfdHlwZT0yLHRoaXMuYWRsZXI9MH07dmFyIGFlPWZ1bmN0aW9uKCl7dGhpcy50ZXh0PTAsdGhpcy50aW1lPTAsdGhpcy54ZmxhZ3M9MCx0aGlzLm9zPTAsdGhpcy5leHRyYT1udWxsLHRoaXMuZXh0cmFfbGVuPTAsdGhpcy5uYW1lPSIiLHRoaXMuY29tbWVudD0iIix0aGlzLmhjcmM9MCx0aGlzLmRvbmU9ITF9LHJlPU9iamVjdC5wcm90b3R5cGUudG9TdHJpbmcsb2U9Yy5aX05PX0ZMVVNILHNlPWMuWl9GSU5JU0gsbGU9Yy5aX09LLGZlPWMuWl9TVFJFQU1fRU5ELGRlPWMuWl9ORUVEX0RJQ1QsaGU9Yy5aX1NUUkVBTV9FUlJPUixjZT1jLlpfREFUQV9FUlJPUix1ZT1jLlpfTUVNX0VSUk9SO2Z1bmN0aW9uIHdlKGUpe3RoaXMub3B0aW9ucz1XKHtjaHVua1NpemU6NjU1MzYsd2luZG93Qml0czoxNSx0bzoiIn0sZXx8e30pO3ZhciB0PXRoaXMub3B0aW9uczt0LnJhdyYmdC53aW5kb3dCaXRzPj0wJiZ0LndpbmRvd0JpdHM8MTYmJih0LndpbmRvd0JpdHM9LXQud2luZG93Qml0cywwPT09dC53aW5kb3dCaXRzJiYodC53aW5kb3dCaXRzPS0xNSkpLCEodC53aW5kb3dCaXRzPj0wJiZ0LndpbmRvd0JpdHM8MTYpfHxlJiZlLndpbmRvd0JpdHN8fCh0LndpbmRvd0JpdHMrPTMyKSx0LndpbmRvd0JpdHM+MTUmJnQud2luZG93Qml0czw0OCYmMD09KDE1JnQud2luZG93Qml0cykmJih0LndpbmRvd0JpdHN8PTE1KSx0aGlzLmVycj0wLHRoaXMubXNnPSIiLHRoaXMuZW5kZWQ9ITEsdGhpcy5jaHVua3M9W10sdGhpcy5zdHJtPW5ldyBuZSx0aGlzLnN0cm0uYXZhaWxfb3V0PTA7dmFyIGk9WS5pbmZsYXRlSW5pdDIodGhpcy5zdHJtLHQud2luZG93Qml0cyk7aWYoaSE9PWxlKXRocm93IG5ldyBFcnJvcihpZVtpXSk7aWYodGhpcy5oZWFkZXI9bmV3IGFlLFkuaW5mbGF0ZUdldEhlYWRlcih0aGlzLnN0cm0sdGhpcy5oZWFkZXIpLHQuZGljdGlvbmFyeSYmKCJzdHJpbmciPT10eXBlb2YgdC5kaWN0aW9uYXJ5P3QuZGljdGlvbmFyeT0kKHQuZGljdGlvbmFyeSk6IltvYmplY3QgQXJyYXlCdWZmZXJdIj09PXJlLmNhbGwodC5kaWN0aW9uYXJ5KSYmKHQuZGljdGlvbmFyeT1uZXcgVWludDhBcnJheSh0LmRpY3Rpb25hcnkpKSx0LnJhdyYmKGk9WS5pbmZsYXRlU2V0RGljdGlvbmFyeSh0aGlzLnN0cm0sdC5kaWN0aW9uYXJ5KSkhPT1sZSkpdGhyb3cgbmV3IEVycm9yKGllW2ldKX1mdW5jdGlvbiBiZShlLHQpe3ZhciBpPW5ldyB3ZSh0KTtpZihpLnB1c2goZSksaS5lcnIpdGhyb3cgaS5tc2d8fGllW2kuZXJyXTtyZXR1cm4gaS5yZXN1bHR9d2UucHJvdG90eXBlLnB1c2g9ZnVuY3Rpb24oZSx0KXt2YXIgaSxuLGEscj10aGlzLnN0cm0sbz10aGlzLm9wdGlvbnMuY2h1bmtTaXplLHM9dGhpcy5vcHRpb25zLmRpY3Rpb25hcnk7aWYodGhpcy5lbmRlZClyZXR1cm4hMTtmb3Iobj10PT09fn50P3Q6ITA9PT10P3NlOm9lLCJbb2JqZWN0IEFycmF5QnVmZmVyXSI9PT1yZS5jYWxsKGUpP3IuaW5wdXQ9bmV3IFVpbnQ4QXJyYXkoZSk6ci5pbnB1dD1lLHIubmV4dF9pbj0wLHIuYXZhaWxfaW49ci5pbnB1dC5sZW5ndGg7Oyl7Zm9yKDA9PT1yLmF2YWlsX291dCYmKHIub3V0cHV0PW5ldyBVaW50OEFycmF5KG8pLHIubmV4dF9vdXQ9MCxyLmF2YWlsX291dD1vKSwoaT1ZLmluZmxhdGUocixuKSk9PT1kZSYmcyYmKChpPVkuaW5mbGF0ZVNldERpY3Rpb25hcnkocixzKSk9PT1sZT9pPVkuaW5mbGF0ZShyLG4pOmk9PT1jZSYmKGk9ZGUpKTtyLmF2YWlsX2luPjAmJmk9PT1mZSYmci5zdGF0ZS53cmFwPjAmJjAhPT1lW3IubmV4dF9pbl07KVkuaW5mbGF0ZVJlc2V0KHIpLGk9WS5pbmZsYXRlKHIsbik7c3dpdGNoKGkpe2Nhc2UgaGU6Y2FzZSBjZTpjYXNlIGRlOmNhc2UgdWU6cmV0dXJuIHRoaXMub25FbmQoaSksdGhpcy5lbmRlZD0hMCwhMX1pZihhPXIuYXZhaWxfb3V0LHIubmV4dF9vdXQmJigwPT09ci5hdmFpbF9vdXR8fGk9PT1mZSkpaWYoInN0cmluZyI9PT10aGlzLm9wdGlvbnMudG8pe3ZhciBsPXRlKHIub3V0cHV0LHIubmV4dF9vdXQpLGY9ci5uZXh0X291dC1sLGQ9ZWUoci5vdXRwdXQsbCk7ci5uZXh0X291dD1mLHIuYXZhaWxfb3V0PW8tZixmJiZyLm91dHB1dC5zZXQoci5vdXRwdXQuc3ViYXJyYXkobCxsK2YpLDApLHRoaXMub25EYXRhKGQpfWVsc2UgdGhpcy5vbkRhdGEoci5vdXRwdXQubGVuZ3RoPT09ci5uZXh0X291dD9yLm91dHB1dDpyLm91dHB1dC5zdWJhcnJheSgwLHIubmV4dF9vdXQpKTtpZihpIT09bGV8fDAhPT1hKXtpZihpPT09ZmUpcmV0dXJuIGk9WS5pbmZsYXRlRW5kKHRoaXMuc3RybSksdGhpcy5vbkVuZChpKSx0aGlzLmVuZGVkPSEwLCEwO2lmKDA9PT1yLmF2YWlsX2luKWJyZWFrfX1yZXR1cm4hMH0sd2UucHJvdG90eXBlLm9uRGF0YT1mdW5jdGlvbihlKXt0aGlzLmNodW5rcy5wdXNoKGUpfSx3ZS5wcm90b3R5cGUub25FbmQ9ZnVuY3Rpb24oZSl7ZT09PWxlJiYoInN0cmluZyI9PT10aGlzLm9wdGlvbnMudG8/dGhpcy5yZXN1bHQ9dGhpcy5jaHVua3Muam9pbigiIik6dGhpcy5yZXN1bHQ9cSh0aGlzLmNodW5rcykpLHRoaXMuY2h1bmtzPVtdLHRoaXMuZXJyPWUsdGhpcy5tc2c9dGhpcy5zdHJtLm1zZ307dmFyIG1lPXdlLGtlPWJlLF9lPWZ1bmN0aW9uKGUsdCl7cmV0dXJuKHQ9dHx8e30pLnJhdz0hMCxiZShlLHQpfSx2ZT1iZSxnZT1jLHBlPXtJbmZsYXRlOm1lLGluZmxhdGU6a2UsaW5mbGF0ZVJhdzpfZSx1bmd6aXA6dmUsY29uc3RhbnRzOmdlfTtlLkluZmxhdGU9bWUsZS5jb25zdGFudHM9Z2UsZS5kZWZhdWx0PXBlLGUuaW5mbGF0ZT1rZSxlLmluZmxhdGVSYXc9X2UsZS51bmd6aXA9dmUsT2JqZWN0LmRlZmluZVByb3BlcnR5KGUsIl9fZXNNb2R1bGUiLHt2YWx1ZTohMH0pfSkpOwphZGRFdmVudExpc3RlbmVyKCJtZXNzYWdlIiwgZnVuY3Rpb24obykgeyB0cnkgeyBwb3N0TWVzc2FnZSh7IHN0YXR1czogInN1Y2Nlc3MiLCBkYXRhOiBwYWtvLmluZmxhdGUoby5kYXRhLCB7IHRvOiAiYXJyYXlidWZmZXIiIH0pIH0pOyB9IGNhdGNoKGV4KSB7IGxvZ2dlci5lcnJvcihleCk7IHBvc3RNZXNzYWdlKHsgc3RhdHVzOiAiZXJyb3IiIH0pOyB9IH0pOwpwb3N0TWVzc2FnZSh7IHN0YXR1czogInJlYWR5IiB9KTs=";
+			if(soSupported) {
+				theWorkerObj = new Worker(URL.createObjectURL(new Blob([base64js.toByteArray(workerSrc).buffer], { type: "text/javascript" })));
+			}else {
+				theWorkerObj = new Worker("data:text/javascript;base64," + workerSrc);
+			}
+			theWorkerObj.addEventListener("message", function(evt) {
+				if(evt.data.status === "ready") {
+					decodeBase64URL(window.eaglercraftXClientBundle, function(cbData) {
+						if(cbData) {
+							theWorkerObj.postMessage(cbData);
+						}else {
+							alert("Failed to decode eaglercraftXClientBundle base64!");
+						}
+					});
+				}else if(evt.data.status === "success") {
+					if(soSupported) {
+						window.clientScriptSrcURL = URL.createObjectURL(new Blob([evt.data.data.buffer], { type: "text/javascript;charset=utf-8" }));
+					}else {
+						window.clientScriptSrcURL = "data:text/javascript;charset=utf-8;base64," + base64js.fromByteArray(evt.data.data);
+					}
+				}else {
+					alert("Failed to decompress classes.js via legacy javascript implementation!");
+				}
+			});
+			theWorkerObj.addEventListener("error", function(evt) {
+				console.error(evt.error);
+			});
+		});
+	}else {
+		var ds = new window.DecompressionStream("gzip");
+		var result = [];
+		var fetchStream = function(reader) {
+			var processData;
+			reader.read().then(processData = function(evt) {
+				if (evt.done) {
+					(function(blobObj){
+						checkSameOriginSupport(function(supported) {
+							if(supported) {
+								window.clientScriptSrcURL = URL.createObjectURL(blobObj);
+							}else {
+								blobToArrayBuffer(blobObj, function(arr) {
+									console.log(arr);
+									window.clientScriptSrcURL = "data:text/javascript;charset=utf-8;base64," + base64js.fromByteArray(new Uint8Array(arr));
+								});
+							}
+						});
+					})(new Blob(result, { type: "text/javascript;charset=utf-8" }));
+					result = [];
+					ds = null;
+					return;
+				}
+				result.push(evt.value);
+				return reader.read().then(processData);
+			});
+		};
+		decodeBase64URL(window.eaglercraftXClientBundle, function(cbData) {
+			if(cbData) {
+				fetchStream((new Blob([cbData])).stream().pipeThrough(ds).getReader());
+			}else {
+				alert("Failed to decode eaglercraftXClientBundle base64!");
 			}
-			result.push(value);
-			return reader.read().then(processData);
 		});
 	}
-	fetchB64PayloadSafe().then((blob) => fetchStream(blob.stream().pipeThrough(ds).getReader()));
 })();
 </script>
 <script type="text/javascript">
@@ -89,13 +208,15 @@ window.eaglercraftXOptsHints = {
 	var launchCounter = 1;
 	var launchCountdownNumberElement = null;
 	var launchCountdownProgressElement = null;
-	function launchTick() {
-		if(launchCounter > 100) {
+	var launchSkipCountdown = false;
+	var launchTick = function() {
+		if(launchCounter > 100 || launchSkipCountdown) {
 			if(window.clientScriptSrcURL) {
 				clearInterval(launchInterval);
-				setTimeout(() => {
-					document.getElementById("launch_countdown_screen").remove();
-					const script = document.createElement("script");
+				setTimeout(function() {
+					document.body.removeChild(document.getElementById("launch_countdown_screen"));
+					document.body.style.backgroundColor = "black";
+					var script = document.createElement("script");
 					script.type = "text/javascript";
 					script.src = window.clientScriptSrcURL;
 					window.clientScriptSrcURL = null;
@@ -104,25 +225,39 @@ window.eaglercraftXOptsHints = {
 			}
 			return;
 		}
-		launchCountdownNumberElement.innerText = "" + Math.floor(6.0 - launchCounter * 0.06);
+		if(launchCounter === 100) {
+			document.getElementById("gameWillLaunchIn").innerText = "Decompressing...";
+		}else {
+			launchCountdownNumberElement.innerText = "" + Math.floor(6.0 - launchCounter * 0.06);
+		}
 		launchCountdownProgressElement.style.width = "" + launchCounter + "%";
 		++launchCounter;
-	}
-	window.addEventListener("load", () => {
+	};
+	window.addEventListener("load", function() {
 		launchCountdownNumberElement = document.getElementById("launchCountdownNumber");
 		launchCountdownProgressElement = document.getElementById("launchCountdownProgress");
 		launchInterval = setInterval(launchTick, 50);
+		document.getElementById("skipCountdown").addEventListener("click", function() {
+			launchSkipCountdown = true;
+			document.getElementById("gameWillLaunchIn").innerText = "Decompressing...";
+		});
+		document.getElementById("bootMenu").addEventListener("click", function() {
+			launchSkipCountdown = true;
+			document.getElementById("gameWillLaunchIn").innerText = "Decompressing...";
+			window.eaglercraftXOptsHints.showBootMenuOnLaunch = true;
+		});
 	});
 })();
 </script>
 <link type="image/png" rel="shortcut icon" href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAIAAAD8GO2jAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAAFiUAABYlAUlSJPAAAAR/SURBVEhLtZXZK3ZRFMYPcqXc+gv413DHxVuGIpIhkciQWaRccCNjSCkligwXSOZ5nmfv9zvn2e8+58V753sudmuvvdZ61l5r7XOc8H+GS/D19aUNkPz5+aktQH5/f//4+LBKZKuRkpUtQjCUYG5gD2T38vLy/PwsDfL9/f3Dw8PT05M0b29vnKLhCKCBT4L4gvBLBIei4//4+Hh1dUVEQutUuLu7E83FxQUGnKLBWKfQaA3S+AREVxaEOD8/Pzk50XpzcyMDcH19zdZG3N3d3dzc3Nvb01aX5pQUpQGGQJxcQpfNysoKhUIdHR1o1tbWbInYAgxIPDMzMy8vLzc3FxqOdMoRqwJK8G8ALUYIhHMiSEhIwI6CyIb0qQzC4eGhsXCc1tZWnZIEKzdQJQSXgKxfX18RCM3Z5eWlcfVAxKOjo+Pj49PTU88lTOk2NjbMsePc3t6SAfcgFdszOyMuAdeBg0CQi2lhYUHOeOLDCisN8FzcPFZXV3t7ezHY3t5GQ+6it+2xMASsKhEEWKsmRLRBBUpPvpJ/TpFKFBwKYAiITmicsbYhdHfJAltqhUCVsCQhwslmeXmZxiBQT9c0Ar9E2O3v72sYSE0N1yQArkKy0kBMXLqlZqIZHR3t6empqqqSDcBdhXEJSJ/bUc3q6uq+vj629GB9fR1WsLW1NTs7u7S0RN2locMjIyOEm5ubQ7+4uJienk4/+vv77Y1hwhLBEKhwWHitdVFfX9/Y2Gg2HuLi4owUAysrK8yCG97rh0+ApP5Q2ZycHFlPTExUVFRIBvn5+WhKSkp2dnaMKhptbW2426GgQ/rwuAQCZ1hwFayLiork9hMFBQV1dXVmE0BLS4vqw3QFB8kn4IAxoGPkYpxi4FeDmpqas7Mz4pClAgqGwD48rjY2NmacYqC0tJQ1KSlJWyE5OZkpUKkBAxZVIntAoZh04+Q48fHxPNGBgYHExMT29naj9cBodnZ2mo3jlJWVMeW2OGQck4B1amqqoaGhqamJjx2lGxwcpL0mUgR8fJhsWqJtSkoKU2SbHHUDpkhPBujd8xuQG6PJRM/Pz09PT7O1NNnZ2Tw3fgZkXVhYKCUlUhBATP+hCVyKZGky17RV0g04laayslJ6hlVeFHB4eFhKaogGd0LxtmTgE+hbhKDnPjMzgw8E3qGL2tpaBWpubjYqj2BoaEj6rq4uNATRZ0ZwCbiL6gXEzINk5vCBQJ9rMD4+rkA8QNK036uDg4Py8vLu7m680KjIBNR3zBDoWQM1g98snyB+VSoRW8C/UwR81/SvhgNj9JOTkwwVERUdRBEI0BAdLRVERkhLS8vIyEDQlrsTPTU1lVFhKxARvZgUlFLbegCf4BvIsbi4mIg4E5EogIHhiKCMtU0WUFiVy06j5fAJIDdSBDQw+PegDfBRcbOPwH4F9LuFWIIQdQNKwWqzIE0aoFUaBsw+SQuFw0uNtC9A+F4i3QNrbg3IDn+SAsHh+wYiEpeyBEMLv/cAO6KzAijxxB+Y4wisBhssJUhjEbPJf4Nw+B+JXqLW3bw+wQAAAABJRU5ErkJggg==" />
 </head>
-<body style="margin:0px;width:100vw;height:100vh;overflow:hidden;" id="game_frame">
+<body style="margin:0px;width:100%;height:100%;overflow:hidden;background-color:white;" id="game_frame">
 <div style="margin:0px;width:100%;height:100%;font-family:sans-serif;display:flex;align-items:center;user-select:none;" id="launch_countdown_screen">
 <div style="margin:auto;text-align:center;">
 <h1>This file is from <span style="color:#AA0000;">${date}</span></h1>
-<h2>Game will launch in <span id="launchCountdownNumber">5</span>...</h2>
-<div style="border:2px solid black;width:100%;height:15px;padding:1px;margin-bottom:20vh;"><div id="launchCountdownProgress" style="background-color:#555555;width:0%;height:100%;"></div></div>
+<h2 id="gameWillLaunchIn">Game will launch in <span id="launchCountdownNumber">5</span>...</h2>
+<div style="border:2px solid black;width:100%;height:15px;padding:1px;margin-bottom:20vh;"><div id="launchCountdownProgress" style="background-color:#555555;width:0%;height:100%;"></div>
+<p style="margin-top:30px;"><button id="skipCountdown" autofocus>Skip Countdown</button>&emsp;<button id="bootMenu">Enter Boot Menu</button></p></div>
 </div>
 </div>
 </body>
diff --git a/sources/resources/assets/eagler/CREDITS.txt b/sources/resources/assets/eagler/CREDITS.txt
index 0bade97b..5a34b1d6 100644
--- a/sources/resources/assets/eagler/CREDITS.txt
+++ b/sources/resources/assets/eagler/CREDITS.txt
@@ -3,24 +3,26 @@
  ~~~~~~~~~~~~~~~~~~~~~~~
 
  lax1dude:
- 
+
   - Creator of Eaglercraft
   - Ported the Minecraft 1.8 src to TeaVM
   - Wrote HW accelerated OpenGL 1.3 emulator
   - Wrote the default shader pack
   - Made the integrated PBR resource pack
+  - Added touch and mobile device support
   - Wrote all desktop emulation code
   - Wrote EaglercraftXBungee
   - Wrote EaglercraftXVelocity
   - Wrote WebRTC relay server
   - Wrote voice chat server
   - Wrote the patch and build system
- 
+
  ayunami2000:
- 
+
   - Many bug fixes
   - WebRTC LAN worlds
   - WebRTC voice chat
+  - Worked on touch support
   - Made velocity plugin work
   - Added resource packs
   - Added screen recording
@@ -410,7 +412,7 @@
  Project Author: The Legion of the Bouncy Castle
  Project URL: https://www.bouncycastle.org/java.html
  
- Used For: MD5, SHA-1, SHA-256 implementations
+ Used For: MD5, SHA-1, SHA-256, and AES implementations
  
  * Copyright (c) 2000-2021 The Legion of the Bouncy Castle Inc. (https://www.bouncycastle.org)
  *
@@ -668,23 +670,23 @@
  Project Author: ymnk, JCraft Inc.
  Project URL: http://www.jcraft.com/jorbis/
  
- Used For: Audio in desktop runtime
+ Used For: Audio in desktop runtime and browsers that don't support OGG
  
  * JOrbis
  * Copyright (C) 2000 ymnk, JCraft,Inc.
- *  
+ * 
  * Written by: 2000 ymnk<ymnk@jcraft.com>
  *   
  * Many thanks to 
  *   Monty <monty@xiph.org> and 
  *   The XIPHOPHORUS Company http://www.xiph.org/ .
  * JOrbis has been based on their awesome works, Vorbis codec.
- *   
+ * 
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Library General Public License
  * as published by the Free Software Foundation; either version 2 of
  * the License, or (at your option) any later version.
-   
+ * 
  * This program is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
@@ -696,6 +698,44 @@
  
  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  
+ Project Name: NanoHTTPD
+ Project Author: NanoHTTPD 
+ Project URL: http://nanohttpd.org/
+ 
+ Used For: HTTP server in the desktop runtime
+ 
+ * Copyright (c) 2012-2013 by Paul S. Hawke,
+ * 2001,2005-2013 by Jarno Elonen,
+ * 2010 by Konstantinos Togias All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * 
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 
+ * Neither the name of the NanoHttpd organization nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ 
+ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+ 
  Project Name: sqlite-jdbc
  Project Author: Taro L. Saito (xerial)
  Project URL: https://github.com/xerial/sqlite-jdbc
diff --git a/sources/resources/assets/eagler/audioctx_test_ogg.dat b/sources/resources/assets/eagler/audioctx_test_ogg.dat
new file mode 100644
index 0000000000000000000000000000000000000000..ff379a7ceae88520037fd572272fae9f8849c371
GIT binary patch
literal 3980
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
Sb?xg8eI%auvENs%9)AbWp+dg^

literal 0
HcmV?d00001

diff --git a/sources/resources/assets/eagler/audioctx_test_wav16.dat b/sources/resources/assets/eagler/audioctx_test_wav16.dat
new file mode 100644
index 0000000000000000000000000000000000000000..cfa8ce9c66935e16f64cb45f6a57f13a48441ab6
GIT binary patch
literal 2106
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
Y8XGn$JZwaGc;K?kl-w1oQZiTn9~UI?Y5)KL

literal 0
HcmV?d00001

diff --git a/sources/resources/assets/eagler/audioctx_test_wav32f.dat b/sources/resources/assets/eagler/audioctx_test_wav32f.dat
new file mode 100644
index 0000000000000000000000000000000000000000..13ed4a860ec99188b9cfcc7ab055d9a222ac88a4
GIT binary patch
literal 4144
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

literal 0
HcmV?d00001

diff --git a/sources/resources/assets/eagler/boot_menu/boot_menu_markup.html b/sources/resources/assets/eagler/boot_menu/boot_menu_markup.html
new file mode 100644
index 00000000..ec3abaae
--- /dev/null
+++ b/sources/resources/assets/eagler/boot_menu/boot_menu_markup.html
@@ -0,0 +1,88 @@
+<style type="text/css" style="display:none !important;">{% embed eval `boot_menu_style.css` %}</style>
+<div class="_eaglercraftX_boot_menu {% global `root_class_gen` %}">
+	<div class="_eaglercraftX_boot_menu_inner">
+		<div class="_eaglercraftX_boot_menu_header">
+			<p class="_eaglercraftX_boot_menu_header_title">EaglercraftX 1.8 Boot Manager</p>
+		</div>
+		<div class="_eaglercraftX_boot_menu_content">
+			<div class="_eaglercraftX_boot_menu_content_inner">
+				<div class="_eaglercraftX_boot_menu_content_view_selection" style="display:none;">
+					<div class="_eaglercraftX_boot_menu_content_selection"></div>
+				</div>
+				<div class="_eaglercraftX_boot_menu_content_view_editor" style="display:none;">
+					<div class="_eaglercraftX_boot_menu_launch_conf">
+						<div class="_eaglercraftX_boot_menu_launch_conf_inner">
+							<div class="_eaglercraftX_boot_menu_launch_conf_item_wide" style="padding: 20px;">
+								<p>Profile Name: <input type="text" class="_eaglercraftX_boot_menu_launch_conf_val_profile_name"></p>
+							</div>
+							<div class="_eaglercraftX_boot_menu_launch_conf_item_wide">
+								<div class="_eaglercraftX_boot_menu_launch_conf_item _eaglercraftX_boot_menu_launch_conf_data_format">
+									<p>Data Format: <span class="_eaglercraftX_boot_menu_launch_conf_val_data_format">Standard Offline</span></p>
+								</div>
+								<div class="_eaglercraftX_boot_menu_launch_conf_item _eaglercraftX_boot_menu_launch_conf_launch_type">
+									<p>Launch Type:
+										<select class="_eaglercraftX_boot_menu_launch_conf_val_launch_type">
+											<option class="_eaglercraftX_boot_menu_launch_conf_val_launch_type_opt" value="EAGLERX_SIGNED_V1">EaglercraftX Signed Client</option>
+											<option class="_eaglercraftX_boot_menu_launch_conf_val_launch_type_opt" value="EAGLERX_V1">EaglercraftX Standard Offline</option>
+											<option class="_eaglercraftX_boot_menu_launch_conf_val_launch_type_opt" value="EAGLER_1_5_V2">Eaglercraft 1.5 (post-22w34a)</option>
+											<option class="_eaglercraftX_boot_menu_launch_conf_val_launch_type_opt" value="EAGLER_1_5_V1">Eaglercraft 1.5 (pre-22w34a)</option>
+											<option class="_eaglercraftX_boot_menu_launch_conf_val_launch_type_opt" value="EAGLER_BETA_V1">Eaglercraft Beta 1.3</option>
+											<option class="_eaglercraftX_boot_menu_launch_conf_val_launch_type_opt" value="PEYTON_V1">PeytonPlayz585 Indev</option>
+											<option class="_eaglercraftX_boot_menu_launch_conf_val_launch_type_opt" value="PEYTON_V2">PeytonPlayz585 Alpha/Beta</option>
+											<option class="_eaglercraftX_boot_menu_launch_conf_val_launch_type_opt" value="STANDARD_OFFLINE_V1">Standard Offline</option>
+											<option class="_eaglercraftX_boot_menu_launch_conf_val_launch_type_opt" value="IFRAME_SANDBOX_V1">IFrame HTML File</option>
+										</select>
+									</p>
+								</div>
+								<div class="_eaglercraftX_boot_menu_launch_conf_item _eaglercraftX_boot_menu_launch_conf_join_server" style="display:none;">
+									<p>Join Server: <input type="text" class="_eaglercraftX_boot_menu_launch_conf_val_join_server"></p>
+								</div>
+								<div class="_eaglercraftX_boot_menu_launch_conf_item _eaglercraftX_boot_menu_launch_conf_opts_name" style="display:none;">
+									<p>Opt Variable Name: <input type="text" class="_eaglercraftX_boot_menu_launch_conf_val_opts_name"></p>
+								</div>
+								<div class="_eaglercraftX_boot_menu_launch_conf_item _eaglercraftX_boot_menu_launch_conf_assetsURI" style="display:none;">
+									<p>Assets URI Opt: <input type="text" class="_eaglercraftX_boot_menu_launch_conf_val_assetsURI"></p>
+								</div>
+								<div class="_eaglercraftX_boot_menu_launch_conf_item _eaglercraftX_boot_menu_launch_conf_container" style="display:none;">
+									<p>Container ID Opt: <input type="text" class="_eaglercraftX_boot_menu_launch_conf_val_container"></p>
+								</div>
+								<div class="_eaglercraftX_boot_menu_launch_conf_item _eaglercraftX_boot_menu_launch_conf_main_func" style="display:none;">
+									<p>Main function: <input type="text" class="_eaglercraftX_boot_menu_launch_conf_val_main_func"></p>
+								</div>
+								<div class="_eaglercraftX_boot_menu_launch_conf_item _eaglercraftX_boot_menu_launch_conf_clear_cookies">
+									<p>Clear Cookies Before Launch: <input type="checkbox" class="_eaglercraftX_boot_menu_launch_conf_val_clear_cookies"></p>
+								</div>
+							</div>
+						</div>
+					</div>
+					<textarea class="_eaglercraftX_boot_menu_launch_opt_editor" spellcheck="false"></textarea>
+				</div>
+				<div class="_eaglercraftX_boot_menu_popup" style="display:none;">
+					<div class="_eaglercraftX_boot_menu_popup_inner">
+						<div class="_eaglercraftX_boot_menu_popup_view_confirm" style="display:none;">
+							<p class="_eaglercraftX_boot_menu_popup_confirm_title"></p>
+							<p class="_eaglercraftX_boot_menu_popup_confirm_opts"></p>
+						</div>
+						<div class="_eaglercraftX_boot_menu_popup_view_selection" style="display:none;">
+							<p class="_eaglercraftX_boot_menu_popup_selection_title"></p>
+							<div class="_eaglercraftX_boot_menu_popup_selection"></div>
+						</div>
+						<div class="_eaglercraftX_boot_menu_popup_view_input" style="display:none;">
+							<p class="_eaglercraftX_boot_menu_popup_input_title"></p>
+							<p class="_eaglercraftX_boot_menu_popup_input_val_container"><input class="_eaglercraftX_boot_menu_popup_input_val" type="text"></p>
+							<p class="_eaglercraftX_boot_menu_popup_input_opts"><span class="_eaglercraftX_boot_menu_popup_input_opt _eaglercraftX_boot_menu_popup_input_opt_cancel">&nbsp;&lt;&nbsp;Cancel&nbsp;&gt;&nbsp;</span> &emsp; <span class="_eaglercraftX_boot_menu_popup_input_opt _eaglercraftX_boot_menu_popup_input_opt_done _eaglercraftX_boot_menu_popup_input_opt_selected">&nbsp;&lt;&nbsp;Done&nbsp;&gt;&nbsp;</span></p>
+						</div>
+					</div>
+				</div>
+			</div>
+		</div>
+		<div class="_eaglercraftX_boot_menu_footer">
+			<p class="_eaglercraftX_boot_menu_footer_text _eaglercraftX_boot_menu_footer_text_boot_select" style="display:none;">Use the &uarr; and &darr; keys to select which entry is highlighted.<br>Press enter to boot the selected client, `e' to edit eaglercraft opts before booting, or ESC to exit and boot normally.</p>
+			<p class="_eaglercraftX_boot_menu_footer_text _eaglercraftX_boot_menu_footer_text_boot_select_count" style="display:none;">Use the &uarr; and &darr; keys to select which entry is highlighted.<br>Press enter to boot the selected client, `e' to edit eaglercraft opts before booting.<br>The first option will be executed in <span class="_eaglercraftX_boot_menu_footer_text_boot_countdown">0</span> seconds. Press any key to cancel.</p>
+			<p class="_eaglercraftX_boot_menu_footer_text _eaglercraftX_boot_menu_footer_text_menu_select" style="display:none;">Use the &uarr; and &darr; keys to select which entry is highlighted.<br>Press enter to select, or ESC return to the previous screen.</p>
+			<p class="_eaglercraftX_boot_menu_footer_text _eaglercraftX_boot_menu_footer_text_opts_editor" style="display:none;">Press CTRL+SHIFT to open editor menu.<br>Press CTRL+ENTER to boot, or ESC return to the previous menu.</p>
+			<p class="_eaglercraftX_boot_menu_footer_text _eaglercraftX_boot_menu_footer_text_opts_editor_alt" style="display:none;">Press CTRL+SHIFT to open editor menu.<br>Press CTRL+ENTER to save, or ESC return to the previous menu.</p>
+			<p class="_eaglercraftX_boot_menu_footer_text _eaglercraftX_boot_menu_footer_text_boot_order" style="display:none;">Use the &uarr; and &darr; keys to select which entry is highlighted.<br>Press CTRL+&uarr; and CTRL+&darr; to adjust item order, or ESC to cancel.</p>
+		</div>
+	</div>
+</div>
\ No newline at end of file
diff --git a/sources/resources/assets/eagler/boot_menu/boot_menu_style.css b/sources/resources/assets/eagler/boot_menu/boot_menu_style.css
new file mode 100644
index 00000000..1f2fb19e
--- /dev/null
+++ b/sources/resources/assets/eagler/boot_menu/boot_menu_style.css
@@ -0,0 +1,328 @@
+@font-face {
+	font-family: "{% global `root_class_gen` %}_font0";
+	src: url("data:font/woff;base64,{% embed base64 `web_cl_eagleiii_8x16.woff` %}") format("woff");
+}
+.{% global `root_class_gen` %} {
+	font: 24px "{% global `root_class_gen` %}_font0";
+	color: #CCCCCC;
+	background-color: #000000;
+	user-select: none;
+	width: 100%;
+	height: 100%;
+	overflow-y: auto;
+}
+.{% global `root_class_gen` %}::-moz-selection {
+	color: #000000;
+	background-color: #CCCCCC;
+}
+.{% global `root_class_gen` %}::selection {
+	color: #000000;
+	background-color: #CCCCCC;
+}
+.{% global `root_class_gen` %}::-webkit-scrollbar {
+	width: 12px;
+}
+.{% global `root_class_gen` %} ::-webkit-scrollbar {
+	width: 12px;
+}
+.{% global `root_class_gen` %}::-webkit-scrollbar-track, .{% global `root_class_gen` %} ::-webkit-scrollbar-track {
+	background-color: #000000;
+}
+.{% global `root_class_gen` %}::-webkit-scrollbar-thumb, .{% global `root_class_gen` %} ::-webkit-scrollbar-thumb {
+	background-color: #CCCCCC;
+}
+.{% global `root_class_gen` %}::-webkit-scrollbar-button, .{% global `root_class_gen` %} ::-webkit-scrollbar-button {
+	display: none;
+}
+.{% global `root_class_gen` %}::-webkit-scrollbar-corner, .{% global `root_class_gen` %} ::-webkit-scrollbar-corner {
+	background-color: #CCCCCC;
+}
+.{% global `root_class_gen` %} ._eaglercraftX_boot_menu_inner {
+	width: 100%;
+	height: 100%;
+	min-height: 480px;
+	display: flex;
+	flex-flow: column;
+}
+.{% global `root_class_gen` %} p {
+	margin-block-start: 0px;
+	margin-block-end: 0px;
+	-webkit-margin-before:0px;
+	-webkit-margin-after:0px;
+}
+.{% global `root_class_gen` %} ._eaglercraftX_boot_menu_header {
+	flex: 0 1 auto;
+}
+.{% global `root_class_gen` %} ._eaglercraftX_boot_menu_header_title {
+	text-align: center;
+	padding: 32px 0px 0px 0px;
+	color: #CCCCCC;
+	white-space: pre-wrap;
+}
+.{% global `root_class_gen` %} ._eaglercraftX_boot_menu_content {
+	flex: 1 1 auto;
+	position: relative;
+}
+.{% global `root_class_gen` %} ._eaglercraftX_boot_menu_content_inner {
+	position: absolute;
+	top: 32px;
+	left: 32px;
+	bottom: 32px;
+	right: 32px;
+	border: 2px solid white;
+	z-index: 1;
+}
+.{% global `root_class_gen` %} ._eaglercraftX_boot_menu_popup {
+	position: absolute;
+	top: 128px;
+	left: 64px;
+	bottom: 64px;
+	right: 64px;
+	z-index: 10;
+}
+.{% global `root_class_gen` %} ._eaglercraftX_boot_menu_popup_inner {
+	width: 50%;
+	min-width: min(calc(100% - 20px), 400px);
+	max-width: 800px;
+	max-height: calc(100% - 20px);
+	margin-left: auto;
+	margin-right: auto;
+	border: 2px solid white;
+	background-color: #000000;
+	padding: 10px;
+	overflow-y: auto;
+}
+.{% global `root_class_gen` %} ._eaglercraftX_boot_menu_popup_confirm_title {
+	text-align: center;
+	padding: 16px;
+	color: #CCCCCC;
+	white-space: pre-wrap;
+}
+.{% global `root_class_gen` %} ._eaglercraftX_boot_menu_popup_confirm_opts {
+	text-align: center;
+	padding: 16px;
+	color: #CCCCCC;
+}
+.{% global `root_class_gen` %} ._eaglercraftX_boot_menu_popup_confirm_opt {
+	cursor: pointer;
+}
+.{% global `root_class_gen` %} ._eaglercraftX_boot_menu_popup_confirm_opt_selected {
+	color: #000000;
+	background-color: #CCCCCC;
+}
+.{% global `root_class_gen` %} ._eaglercraftX_boot_menu_popup_confirm_opt_disabled {
+	color: #888888;
+	cursor: default;
+}
+.{% global `root_class_gen` %} ._eaglercraftX_boot_menu_popup_selection_title {
+	text-align: center;
+	padding: 16px;
+	color: #CCCCCC;
+}
+.{% global `root_class_gen` %} ._eaglercraftX_boot_menu_popup_selection {
+	width: calc(100% - 8px);
+	padding: 8px 4px;
+}
+.{% global `root_class_gen` %} ._eaglercraftX_boot_menu_popup_input_title {
+	text-align: center;
+	padding: 16px;
+	color: #CCCCCC;
+	white-space: pre-wrap;
+}
+.{% global `root_class_gen` %} ._eaglercraftX_boot_menu_popup_input_opts {
+	text-align: center;
+	padding: 16px;
+	color: #CCCCCC;
+}
+.{% global `root_class_gen` %} ._eaglercraftX_boot_menu_popup_input_opt {
+	cursor: pointer;
+}
+.{% global `root_class_gen` %} ._eaglercraftX_boot_menu_popup_input_opt_selected {
+	color: #000000;
+	background-color: #CCCCCC;
+}
+.{% global `root_class_gen` %} ._eaglercraftX_boot_menu_popup_input_opt_disabled {
+	color: #888888;
+	cursor: default;
+}
+.{% global `root_class_gen` %} ._eaglercraftX_boot_menu_popup_input_val_container {
+	text-align: center;
+}
+.{% global `root_class_gen` %} ._eaglercraftX_boot_menu_popup_input_val {
+	min-width: 15em;
+	width: calc(90% - 50px);
+	font: 24px "{% global `root_class_gen` %}_font0";
+	outline: none;
+	resize: none;
+	background-color: #000000;
+	color: #CCCCCC;
+	border: 2px solid white;
+	padding: 2px 4px;
+}
+.{% global `root_class_gen` %} ._eaglercraftX_boot_menu_popup_input_val:disabled {
+	color: #888888;
+}
+.{% global `root_class_gen` %} ._eaglercraftX_boot_menu_popup_input_val::-moz-selection {
+	color: #000000;
+	background-color: #CCCCCC;
+}
+.{% global `root_class_gen` %} ._eaglercraftX_boot_menu_popup_input_val::selection {
+	color: #000000;
+	background-color: #CCCCCC;
+}
+.{% global `root_class_gen` %} ._eaglercraftX_boot_menu_content_view_selection {
+	width: 100%;
+	height: 100%;
+}
+.{% global `root_class_gen` %} ._eaglercraftX_boot_menu_content_selection {
+	width: calc(100% - 8px);
+	height: calc(100% - 16px);
+	padding: 8px 4px;
+	overflow-y: auto;
+}
+.{% global `root_class_gen` %} ._eaglercraftX_boot_menu_content_item {
+	width: 100%;
+	overflow-y: auto;
+	cursor: pointer;
+}
+.{% global `root_class_gen` %} ._eaglercraftX_boot_menu_content_item::before {
+	content: "\00a0";
+}
+.{% global `root_class_gen` %} ._eaglercraftX_boot_menu_content_item_selected {
+	color: #000000;
+	background-color: #CCCCCC;
+}
+.{% global `root_class_gen` %} ._eaglercraftX_boot_menu_content_item_selected::before {
+	content: "*";
+}
+.{% global `root_class_gen` %} ._eaglercraftX_boot_menu_content_item_disabled {
+	color: #888888;
+	cursor: default;
+}
+.{% global `root_class_gen` %} ._eaglercraftX_boot_menu_content_view_editor {
+	width: 100%;
+	height: 100%;
+	position: relative;
+}
+.{% global `root_class_gen` %} ._eaglercraftX_boot_menu_launch_conf {
+	position: absolute;
+	top: 0px;
+	left: 0px;
+	right: 0px;
+	height: calc(25% - 20px);
+	padding: 10px;
+	overflow-x: hidden;
+	overflow-y: auto;
+	color: #CCCCCC;
+}
+.{% global `root_class_gen` %} ._eaglercraftX_boot_menu_launch_conf_item_wide {
+	width: 100%;
+}
+.{% global `root_class_gen` %} ._eaglercraftX_boot_menu_launch_conf_item {
+	display: inline-block;
+	padding: 20px;
+}
+.{% global `root_class_gen` %} ._eaglercraftX_boot_menu_launch_conf_item input[type=text] {
+	min-width: 15em;
+	font: 24px "{% global `root_class_gen` %}_font0";
+	outline: none;
+	resize: none;
+	background-color: #000000;
+	color: #CCCCCC;
+	border: 2px solid white;
+	padding: 2px 4px;
+}
+.{% global `root_class_gen` %} ._eaglercraftX_boot_menu_launch_conf_item input[type=text]:disabled {
+	color: #888888;
+}
+.{% global `root_class_gen` %} ._eaglercraftX_boot_menu_launch_conf_item input[type=checkbox] {
+	zoom: 2;
+	padding: 2px 4px;
+}
+.{% global `root_class_gen` %} ._eaglercraftX_boot_menu_launch_conf_item select {
+	font: 24px "{% global `root_class_gen` %}_font0";
+	outline: none;
+	resize: none;
+	background-color: #000000;
+	color: #CCCCCC;
+	border: 2px solid white;
+	padding: 2px 4px;
+}
+.{% global `root_class_gen` %} ._eaglercraftX_boot_menu_launch_conf_item option:checked {
+	background-color: #CCCCCC;
+	color: #000000;
+}
+.{% global `root_class_gen` %} ._eaglercraftX_boot_menu_launch_conf_item option:disabled {
+	color: #888888;
+}
+.{% global `root_class_gen` %} ._eaglercraftX_boot_menu_launch_conf_item input::-moz-selection {
+	color: #000000;
+	background-color: #CCCCCC;
+}
+.{% global `root_class_gen` %} ._eaglercraftX_boot_menu_launch_conf_item input::selection {
+	color: #000000;
+	background-color: #CCCCCC;
+}
+.{% global `root_class_gen` %} ._eaglercraftX_boot_menu_launch_conf_val_profile_name {
+	width: calc(100% - 10em);
+	font: 24px "{% global `root_class_gen` %}_font0";
+	outline: none;
+	resize: none;
+	background-color: #000000;
+	color: #CCCCCC;
+	border: 2px solid white;
+	padding: 2px 4px;
+}
+.{% global `root_class_gen` %} ._eaglercraftX_boot_menu_launch_conf_val_profile_name::-moz-selection {
+	color: #000000;
+	background-color: #CCCCCC;
+}
+.{% global `root_class_gen` %} ._eaglercraftX_boot_menu_launch_conf_val_profile_name::selection {
+	color: #000000;
+	background-color: #CCCCCC;
+}
+.{% global `root_class_gen` %} ._eaglercraftX_boot_menu_launch_conf_val_profile_name:disabled {
+	color: #888888;
+}
+.{% global `root_class_gen` %} ._eaglercraftX_boot_menu_launch_conf_val_data_format {
+	padding: 2px 4px;
+	border: 2px solid white;
+}
+.{% global `root_class_gen` %} ._eaglercraftX_boot_menu_launch_opt_editor {
+	position: absolute;
+	bottom: 0px;
+	left: 0px;
+	right: 0px;
+	height: calc(75% - 22px);
+	width: calc(100% - 20px);
+	margin: 0px;
+	padding: 10px;
+	font: 24px "{% global `root_class_gen` %}_font0";
+	border: none;
+	border-top: 2px solid white;
+	outline: none;
+	resize: none;
+	background-color: #000000;
+	color: #CCCCCC;
+	overflow: auto;
+	tab-size: 4;
+}
+.{% global `root_class_gen` %} ._eaglercraftX_boot_menu_launch_opt_editor:disabled {
+	color: #888888;
+}
+.{% global `root_class_gen` %} ._eaglercraftX_boot_menu_launch_opt_editor::-moz-selection {
+	color: #000000;
+	background-color: #CCCCCC;
+}
+.{% global `root_class_gen` %} ._eaglercraftX_boot_menu_launch_opt_editor::selection {
+	color: #000000;
+	background-color: #CCCCCC;
+}
+.{% global `root_class_gen` %} ._eaglercraftX_boot_menu_footer {
+	flex: 0 1 auto;
+}
+.{% global `root_class_gen` %} ._eaglercraftX_boot_menu_footer_text {
+	text-align: left;
+	padding: 0px 0px 32px 64px;
+	color: #CCCCCC;
+}
\ No newline at end of file
diff --git a/sources/resources/assets/eagler/boot_menu/conf_template_eaglercraftX_1_8.json b/sources/resources/assets/eagler/boot_menu/conf_template_eaglercraftX_1_8.json
new file mode 100644
index 00000000..5e28b463
--- /dev/null
+++ b/sources/resources/assets/eagler/boot_menu/conf_template_eaglercraftX_1_8.json
@@ -0,0 +1,4 @@
+{
+	"client_launch_type": "EAGLERX_V1",
+	"clear_cookies_before_launch": false
+}
\ No newline at end of file
diff --git a/sources/resources/assets/eagler/boot_menu/conf_template_eaglercraftX_1_8_signed.json b/sources/resources/assets/eagler/boot_menu/conf_template_eaglercraftX_1_8_signed.json
new file mode 100644
index 00000000..5cc54c53
--- /dev/null
+++ b/sources/resources/assets/eagler/boot_menu/conf_template_eaglercraftX_1_8_signed.json
@@ -0,0 +1,4 @@
+{
+	"client_launch_type": "EAGLERX_SIGNED_V1",
+	"clear_cookies_before_launch": false
+}
\ No newline at end of file
diff --git a/sources/resources/assets/eagler/boot_menu/conf_template_eaglercraft_1_5.json b/sources/resources/assets/eagler/boot_menu/conf_template_eaglercraft_1_5.json
new file mode 100644
index 00000000..fc1f47f6
--- /dev/null
+++ b/sources/resources/assets/eagler/boot_menu/conf_template_eaglercraft_1_5.json
@@ -0,0 +1,4 @@
+{
+	"client_launch_type": "EAGLER_1_5_V2",
+	"clear_cookies_before_launch": false
+}
\ No newline at end of file
diff --git a/sources/resources/assets/eagler/boot_menu/conf_template_eaglercraft_1_5_legacy.json b/sources/resources/assets/eagler/boot_menu/conf_template_eaglercraft_1_5_legacy.json
new file mode 100644
index 00000000..b3190b8e
--- /dev/null
+++ b/sources/resources/assets/eagler/boot_menu/conf_template_eaglercraft_1_5_legacy.json
@@ -0,0 +1,5 @@
+{
+	"client_launch_type": "EAGLER_1_5_V1",
+	"join_server": "",
+	"clear_cookies_before_launch": false
+}
\ No newline at end of file
diff --git a/sources/resources/assets/eagler/boot_menu/conf_template_eaglercraft_b1_3.json b/sources/resources/assets/eagler/boot_menu/conf_template_eaglercraft_b1_3.json
new file mode 100644
index 00000000..9abb4f24
--- /dev/null
+++ b/sources/resources/assets/eagler/boot_menu/conf_template_eaglercraft_b1_3.json
@@ -0,0 +1,5 @@
+{
+	"client_launch_type": "EAGLER_BETA_V1",
+	"join_server": "",
+	"clear_cookies_before_launch": false
+}
\ No newline at end of file
diff --git a/sources/resources/assets/eagler/boot_menu/conf_template_peytonplayz585_a1_2_6.json b/sources/resources/assets/eagler/boot_menu/conf_template_peytonplayz585_a1_2_6.json
new file mode 100644
index 00000000..7d79d672
--- /dev/null
+++ b/sources/resources/assets/eagler/boot_menu/conf_template_peytonplayz585_a1_2_6.json
@@ -0,0 +1,4 @@
+{
+	"client_launch_type": "PEYTON_V2",
+	"clear_cookies_before_launch": false
+}
\ No newline at end of file
diff --git a/sources/resources/assets/eagler/boot_menu/conf_template_peytonplayz585_b1_7_3.json b/sources/resources/assets/eagler/boot_menu/conf_template_peytonplayz585_b1_7_3.json
new file mode 100644
index 00000000..7d79d672
--- /dev/null
+++ b/sources/resources/assets/eagler/boot_menu/conf_template_peytonplayz585_b1_7_3.json
@@ -0,0 +1,4 @@
+{
+	"client_launch_type": "PEYTON_V2",
+	"clear_cookies_before_launch": false
+}
\ No newline at end of file
diff --git a/sources/resources/assets/eagler/boot_menu/conf_template_peytonplayz585_indev.json b/sources/resources/assets/eagler/boot_menu/conf_template_peytonplayz585_indev.json
new file mode 100644
index 00000000..e9fdd8c9
--- /dev/null
+++ b/sources/resources/assets/eagler/boot_menu/conf_template_peytonplayz585_indev.json
@@ -0,0 +1,4 @@
+{
+	"client_launch_type": "PEYTON_V1",
+	"clear_cookies_before_launch": false
+}
\ No newline at end of file
diff --git a/sources/resources/assets/eagler/boot_menu/conf_template_standard_offline.json b/sources/resources/assets/eagler/boot_menu/conf_template_standard_offline.json
new file mode 100644
index 00000000..5cf08d9c
--- /dev/null
+++ b/sources/resources/assets/eagler/boot_menu/conf_template_standard_offline.json
@@ -0,0 +1,8 @@
+{
+	"client_launch_type": "STANDARD_OFFLINE_V1",
+	"client_launch_opts_var": "eaglercraftXOpts",
+	"client_launch_opts_assetsURI_var": "assetsURI",
+	"client_launch_opts_container_var": "container",
+	"client_launch_main_func": "main",
+	"clear_cookies_before_launch": false
+}
\ No newline at end of file
diff --git a/sources/resources/assets/eagler/boot_menu/meta_opts_templates.json b/sources/resources/assets/eagler/boot_menu/meta_opts_templates.json
new file mode 100644
index 00000000..46f98127
--- /dev/null
+++ b/sources/resources/assets/eagler/boot_menu/meta_opts_templates.json
@@ -0,0 +1,192 @@
+{
+	"defaults": {
+		"EAGLERX_SIGNED_V1": {
+			"conf": "conf_template_eaglercraftX_1_8_signed.json",
+			"opts": "opts_template_eaglercraftX_1_8.txt"
+		},
+		"EAGLERX_V1": {
+			"conf": "conf_template_eaglercraftX_1_8.json",
+			"opts": "opts_template_eaglercraftX_1_8.txt"
+		},
+		"EAGLER_BETA_V1": {
+			"conf": "conf_template_eaglercraft_b1_3.json",
+			"opts": null
+		},
+		"EAGLER_1_5_V1": {
+			"conf": "conf_template_eaglercraft_1_5_legacy.json",
+			"opts": "opts_template_eaglercraft_1_5_legacy.txt"
+		},
+		"EAGLER_1_5_V2": {
+			"conf": "conf_template_eaglercraft_1_5.json",
+			"opts": "opts_template_eaglercraft_1_5.txt"
+		},
+		"PEYTON_V1": {
+			"conf": "conf_template_peytonplayz585_indev.json",
+			"opts": null
+		},
+		"PEYTON_V2": {
+			"conf": "conf_template_peytonplayz585_a1_2_6.json",
+			"opts": "opts_template_peytonplayz585_a1_2_6.txt"
+		},
+		"STANDARD_OFFLINE_V1": {
+			"conf": "conf_template_standard_offline.json",
+			"opts": null
+		}
+	},
+	"templates": [
+		{
+			"name": "EaglercraftX 1.8",
+			"conf": "conf_template_eaglercraftX_1_8.json",
+			"opts": "opts_template_eaglercraftX_1_8.txt",
+			"allow": [
+				"EAGLER_STANDARD_OFFLINE"
+			],
+			"parseTypes": [
+				"EAGLERCRAFTX_1_8_OFFLINE"
+			]
+		},
+		{
+			"name": "EaglercraftX 1.8 Demo",
+			"conf": "conf_template_eaglercraftX_1_8.json",
+			"opts": "opts_template_eaglercraftX_1_8_demo.txt",
+			"allow": [
+				"EAGLER_STANDARD_OFFLINE"
+			],
+			"parseTypes": [
+				"EAGLERCRAFTX_1_8_OFFLINE"
+			]
+		},
+		{
+			"name": "EaglercraftX 1.8 HTML5 Cursors",
+			"conf": "conf_template_eaglercraftX_1_8.json",
+			"opts": "opts_template_eaglercraftX_1_8_html5Cursors.txt",
+			"allow": [
+				"EAGLER_STANDARD_OFFLINE"
+			],
+			"parseTypes": [
+				"EAGLERCRAFTX_1_8_OFFLINE"
+			]
+		},
+		{
+			"name": "EaglercraftX 1.8 Signed",
+			"conf": "conf_template_eaglercraftX_1_8_signed.json",
+			"opts": "opts_template_eaglercraftX_1_8.txt",
+			"allow": [
+				"EAGLER_SIGNED_OFFLINE"
+			],
+			"parseTypes": [
+				"EAGLERCRAFTX_1_8_SIGNED"
+			]
+		},
+		{
+			"name": "EaglercraftX 1.8 Signed Demo",
+			"conf": "conf_template_eaglercraftX_1_8_signed.json",
+			"opts": "opts_template_eaglercraftX_1_8_demo.txt",
+			"allow": [
+				"EAGLER_SIGNED_OFFLINE"
+			],
+			"parseTypes": [
+				"EAGLERCRAFTX_1_8_SIGNED"
+			]
+		},
+		{
+			"name": "EaglercraftX 1.8 Signed HTML5 Cursors",
+			"conf": "conf_template_eaglercraftX_1_8_signed.json",
+			"opts": "opts_template_eaglercraftX_1_8_html5Cursors.txt",
+			"allow": [
+				"EAGLER_SIGNED_OFFLINE"
+			],
+			"parseTypes": [
+				"EAGLERCRAFTX_1_8_SIGNED"
+			]
+		},
+		{
+			"name": "Eaglercraft 1.5.2 (post-22w34a)",
+			"conf": "conf_template_eaglercraft_1_5.json",
+			"opts": "opts_template_eaglercraft_1_5.txt",
+			"allow": [
+				"EAGLER_STANDARD_1_5_OFFLINE"
+			],
+			"parseTypes": [
+				"EAGLERCRAFT_1_5_NEW_OFFLINE"
+			]
+		},
+		{
+			"name": "Eaglercraft 1.5.2 Live Music (post-22w34a)",
+			"conf": "conf_template_eaglercraft_1_5.json",
+			"opts": "opts_template_eaglercraft_1_5_livestream.txt",
+			"allow": [
+				"EAGLER_STANDARD_1_5_OFFLINE"
+			],
+			"parseTypes": [
+				"EAGLERCRAFT_1_5_NEW_OFFLINE"
+			]
+		},
+		{
+			"name": "Eaglercraft 1.5.2 (pre-22w34a)",
+			"conf": "conf_template_eaglercraft_1_5_legacy.json",
+			"opts": "opts_template_eaglercraft_1_5_legacy.txt",
+			"allow": [
+				"EAGLER_STANDARD_OFFLINE"
+			],
+			"parseTypes": [
+				"EAGLERCRAFT_1_5_OLD_OFFLINE"
+			]
+		},
+		{
+			"name": "Eaglercraft Beta 1.3",
+			"conf": "conf_template_eaglercraft_b1_3.json",
+			"opts": null,
+			"allow": [
+				"EAGLER_STANDARD_OFFLINE"
+			],
+			"parseTypes": [
+				"EAGLERCRAFT_BETA_B1_3_OFFLINE"
+			]
+		},
+		{
+			"name": "PeytonPlayz585 Beta 1.7.3",
+			"conf": "conf_template_peytonplayz585_b1_7_3.json",
+			"opts": "opts_template_peytonplayz585_b1_7_3.txt",
+			"allow": [
+				"EAGLER_STANDARD_OFFLINE"
+			],
+			"parseTypes": [
+				"PEYTONPLAYZ585_ALPHA_BETA"
+			]
+		},
+		{
+			"name": "PeytonPlayz585 Alpha 1.2.6",
+			"conf": "conf_template_peytonplayz585_a1_2_6.json",
+			"opts": "opts_template_peytonplayz585_a1_2_6.txt",
+			"allow": [
+				"EAGLER_STANDARD_OFFLINE"
+			],
+			"parseTypes": [
+				"PEYTONPLAYZ585_ALPHA_BETA"
+			]
+		},
+		{
+			"name": "PeytonPlayz585 Indev",
+			"conf": "conf_template_peytonplayz585_indev.json",
+			"opts": null,
+			"allow": [
+				"EAGLER_STANDARD_OFFLINE"
+			],
+			"parseTypes": [
+				"PEYTONPLAYZ585_INDEV"
+			]
+		},
+		{
+			"name": "Standard Offline Download",
+			"conf": "conf_template_standard_offline.json",
+			"opts": null,
+			"allow": [
+				"EAGLER_STANDARD_OFFLINE"
+			],
+			"parseTypes": [
+				"EXPORTED_STANDARD_OFFLINE"
+			]
+		}
+	]
+}
\ No newline at end of file
diff --git a/sources/resources/assets/eagler/boot_menu/offline_template_eaglercraftX_1_8.html b/sources/resources/assets/eagler/boot_menu/offline_template_eaglercraftX_1_8.html
new file mode 100644
index 00000000..f0d3ef7c
--- /dev/null
+++ b/sources/resources/assets/eagler/boot_menu/offline_template_eaglercraftX_1_8.html
@@ -0,0 +1,86 @@
+<!DOCTYPE html>
+
+<!--
+
+This file is from ${date}, it was generated using EaglercraftX 1.8 boot manager
+
+-->
+
+<html style="width:100%;height:100%;background-color:black;">
+<head>
+<meta charset="UTF-8" />
+<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0" />
+<meta name="description" content="${client_name}" />
+<meta name="keywords" content="eaglercraft, eaglercraftx, minecraft, 1.8, 1.8.8" />
+<title>${client_name}</title>
+<meta property="og:locale" content="en-US" />
+<meta property="og:type" content="website" />
+<meta property="og:title" content="${client_name}" />
+<meta property="og:description" content="this file is not a website, whoever uploaded it to this URL is a dumbass" />
+<style type="eaglercraftOfflineParseHint">{"type":"EAGLERCRAFTX_1_8_OFFLINE","launchConf":${launch_conf_json}}</style>
+<script type="text/javascript">
+"use strict";
+var relayIdMax = ${relayId_max};
+var relayId = relayIdMax > 1 ? Math.floor(Math.random() * relayIdMax) : 0;
+
+// %%%%%%%%% launch options %%%%%%%%%%%%
+
+window.eaglercraftXOpts = ${launch_opts};
+
+// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+</script>
+<script type="text/javascript">
+"use strict";
+if(typeof window !== "undefined") window.eaglercraftXClientScriptElement = document.currentScript;
+
+${classes_js}
+</script>
+<script type="text/javascript">
+"use strict";
+(function(){
+	window.eaglercraftXOpts.container = "game_frame";
+	window.eaglercraftXOpts.assetsURI = ${assets_epk};
+
+	var launchInterval = -1;
+	var launchCounter = 1;
+	var launchCountdownNumberElement = null;
+	var launchCountdownProgressElement = null;
+	var launchSkipCountdown = false;
+
+	var launchTick = function() {
+		launchCountdownNumberElement.innerText = "" + Math.floor(6.0 - launchCounter * 0.06);
+		launchCountdownProgressElement.style.width = "" + launchCounter + "%";
+		if(++launchCounter > 100 || launchSkipCountdown) {
+			clearInterval(launchInterval);
+			setTimeout(function() { document.body.removeChild(document.getElementById("launch_countdown_screen")); document.body.style.backgroundColor = "black"; main(); }, 50);
+		}
+	};
+
+	window.addEventListener("load", function() {
+		launchCountdownNumberElement = document.getElementById("launchCountdownNumber");
+		launchCountdownProgressElement = document.getElementById("launchCountdownProgress");
+		launchInterval = setInterval(launchTick, 50);
+		document.getElementById("skipCountdown").addEventListener("click", function() {
+			launchSkipCountdown = true;
+		});
+		document.getElementById("bootMenu").addEventListener("click", function() {
+			launchSkipCountdown = true;
+			window.eaglercraftXOpts.showBootMenuOnLaunch = true;
+		});
+	});
+})();
+</script>
+<link type="image/png" rel="shortcut icon" href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAIAAAD8GO2jAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAAFiUAABYlAUlSJPAAAAR/SURBVEhLtZXZK3ZRFMYPcqXc+gv413DHxVuGIpIhkciQWaRccCNjSCkligwXSOZ5nmfv9zvn2e8+58V753sudmuvvdZ61l5r7XOc8H+GS/D19aUNkPz5+aktQH5/f//4+LBKZKuRkpUtQjCUYG5gD2T38vLy/PwsDfL9/f3Dw8PT05M0b29vnKLhCKCBT4L4gvBLBIei4//4+Hh1dUVEQutUuLu7E83FxQUGnKLBWKfQaA3S+AREVxaEOD8/Pzk50XpzcyMDcH19zdZG3N3d3dzc3Nvb01aX5pQUpQGGQJxcQpfNysoKhUIdHR1o1tbWbInYAgxIPDMzMy8vLzc3FxqOdMoRqwJK8G8ALUYIhHMiSEhIwI6CyIb0qQzC4eGhsXCc1tZWnZIEKzdQJQSXgKxfX18RCM3Z5eWlcfVAxKOjo+Pj49PTU88lTOk2NjbMsePc3t6SAfcgFdszOyMuAdeBg0CQi2lhYUHOeOLDCisN8FzcPFZXV3t7ezHY3t5GQ+6it+2xMASsKhEEWKsmRLRBBUpPvpJ/TpFKFBwKYAiITmicsbYhdHfJAltqhUCVsCQhwslmeXmZxiBQT9c0Ar9E2O3v72sYSE0N1yQArkKy0kBMXLqlZqIZHR3t6empqqqSDcBdhXEJSJ/bUc3q6uq+vj629GB9fR1WsLW1NTs7u7S0RN2locMjIyOEm5ubQ7+4uJienk4/+vv77Y1hwhLBEKhwWHitdVFfX9/Y2Gg2HuLi4owUAysrK8yCG97rh0+ApP5Q2ZycHFlPTExUVFRIBvn5+WhKSkp2dnaMKhptbW2426GgQ/rwuAQCZ1hwFayLiork9hMFBQV1dXVmE0BLS4vqw3QFB8kn4IAxoGPkYpxi4FeDmpqas7Mz4pClAgqGwD48rjY2NmacYqC0tJQ1KSlJWyE5OZkpUKkBAxZVIntAoZh04+Q48fHxPNGBgYHExMT29naj9cBodnZ2mo3jlJWVMeW2OGQck4B1amqqoaGhqamJjx2lGxwcpL0mUgR8fJhsWqJtSkoKU2SbHHUDpkhPBujd8xuQG6PJRM/Pz09PT7O1NNnZ2Tw3fgZkXVhYKCUlUhBATP+hCVyKZGky17RV0g04laayslJ6hlVeFHB4eFhKaogGd0LxtmTgE+hbhKDnPjMzgw8E3qGL2tpaBWpubjYqj2BoaEj6rq4uNATRZ0ZwCbiL6gXEzINk5vCBQJ9rMD4+rkA8QNK036uDg4Py8vLu7m680KjIBNR3zBDoWQM1g98snyB+VSoRW8C/UwR81/SvhgNj9JOTkwwVERUdRBEI0BAdLRVERkhLS8vIyEDQlrsTPTU1lVFhKxARvZgUlFLbegCf4BvIsbi4mIg4E5EogIHhiKCMtU0WUFiVy06j5fAJIDdSBDQw+PegDfBRcbOPwH4F9LuFWIIQdQNKwWqzIE0aoFUaBsw+SQuFw0uNtC9A+F4i3QNrbg3IDn+SAsHh+wYiEpeyBEMLv/cAO6KzAijxxB+Y4wisBhssJUhjEbPJf4Nw+B+JXqLW3bw+wQAAAABJRU5ErkJggg==" />
+</head>
+<body style="margin:0px;width:100%;height:100%;overflow:hidden;background-color:white;" id="game_frame">
+<div style="margin:0px;width:100%;height:100%;font-family:sans-serif;display:flex;align-items:center;user-select:none;" id="launch_countdown_screen">
+<div style="margin:auto;text-align:center;">
+<h1>${client_name}</h1>
+<h2>Game will launch in <span id="launchCountdownNumber">5</span>...</h2>
+<div style="border:2px solid black;width:100%;height:15px;padding:1px;margin-bottom:20vh;"><div id="launchCountdownProgress" style="background-color:#555555;width:0%;height:100%;"></div>
+<p style="margin-top:30px;"><button id="skipCountdown" autofocus>Skip Countdown</button>&emsp;<button id="bootMenu">Enter Boot Menu</button></p></div>
+</div>
+</div>
+</body>
+</html>
diff --git a/sources/resources/assets/eagler/boot_menu/offline_template_eaglercraftX_1_8_fat_offline.html b/sources/resources/assets/eagler/boot_menu/offline_template_eaglercraftX_1_8_fat_offline.html
new file mode 100644
index 00000000..9813ea6f
--- /dev/null
+++ b/sources/resources/assets/eagler/boot_menu/offline_template_eaglercraftX_1_8_fat_offline.html
@@ -0,0 +1,85 @@
+<!DOCTYPE html>
+
+<!--
+
+This file is from ${date}, it was generated using EaglercraftX 1.8 boot manager
+
+-->
+
+<html style="width:100%;height:100%;background-color:black;">
+<head>
+<meta charset="UTF-8" />
+<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0" />
+<meta name="description" content="EaglercraftX 1.8" />
+<meta name="keywords" content="eaglercraft, eaglercraftx, minecraft, 1.8, 1.8.8" />
+<title>EaglercraftX 1.8</title>
+<meta property="og:locale" content="en-US" />
+<meta property="og:type" content="website" />
+<meta property="og:title" content="EaglercraftX 1.8" />
+<meta property="og:description" content="this file is not a website, whoever uploaded it to this URL is a dumbass" />
+<style type="eaglercraftOfflineParseHint">{"type":"EAGLERCRAFTX_1_8_FAT_OFFLINE","launchConf":${launch_conf_json}}</style>
+<script type="text/javascript">
+"use strict";
+var relayIdMax = ${relayId_max};
+var relayId = relayIdMax > 1 ? Math.floor(Math.random() * relayIdMax) : 0;
+
+// %%%%%%%%% launch options %%%%%%%%%%%%
+
+window.eaglercraftXOpts = ${launch_opts};
+
+// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+</script>
+<script type="text/javascript">
+"use strict";
+if(typeof window !== "undefined") window.eaglercraftXClientScriptElement = document.currentScript;
+
+${classes_js}
+</script>
+<script type="text/javascript">
+"use strict";
+(function(){
+	window.eaglercraftXOpts.container = "game_frame";
+	window.eaglercraftXOpts.assetsURI = ${assets_epk};
+	window.eaglercraftXOpts.showBootMenuOnLaunch = true;
+
+	var launchInterval = -1;
+	var launchCounter = 1;
+	var launchCountdownNumberElement = null;
+	var launchCountdownProgressElement = null;
+	var launchSkipCountdown = false;
+
+	var launchTick = function() {
+		launchCountdownNumberElement.innerText = "" + Math.floor(6.0 - launchCounter * 0.06);
+		launchCountdownProgressElement.style.width = "" + launchCounter + "%";
+		if(++launchCounter > 100 || launchSkipCountdown) {
+			clearInterval(launchInterval);
+			setTimeout(function() { document.body.removeChild(document.getElementById("launch_countdown_screen")); document.body.style.backgroundColor = "black"; main(); }, 50);
+		}
+	};
+
+	window.addEventListener("load", function() {
+		launchCountdownNumberElement = document.getElementById("launchCountdownNumber");
+		launchCountdownProgressElement = document.getElementById("launchCountdownProgress");
+		launchInterval = setInterval(launchTick, 50);
+		document.getElementById("skipCountdown").addEventListener("click", function() {
+			launchSkipCountdown = true;
+		});
+	});
+})();
+</script>
+<link type="image/png" rel="shortcut icon" href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAIAAAD8GO2jAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAAFiUAABYlAUlSJPAAAAR/SURBVEhLtZXZK3ZRFMYPcqXc+gv413DHxVuGIpIhkciQWaRccCNjSCkligwXSOZ5nmfv9zvn2e8+58V753sudmuvvdZ61l5r7XOc8H+GS/D19aUNkPz5+aktQH5/f//4+LBKZKuRkpUtQjCUYG5gD2T38vLy/PwsDfL9/f3Dw8PT05M0b29vnKLhCKCBT4L4gvBLBIei4//4+Hh1dUVEQutUuLu7E83FxQUGnKLBWKfQaA3S+AREVxaEOD8/Pzk50XpzcyMDcH19zdZG3N3d3dzc3Nvb01aX5pQUpQGGQJxcQpfNysoKhUIdHR1o1tbWbInYAgxIPDMzMy8vLzc3FxqOdMoRqwJK8G8ALUYIhHMiSEhIwI6CyIb0qQzC4eGhsXCc1tZWnZIEKzdQJQSXgKxfX18RCM3Z5eWlcfVAxKOjo+Pj49PTU88lTOk2NjbMsePc3t6SAfcgFdszOyMuAdeBg0CQi2lhYUHOeOLDCisN8FzcPFZXV3t7ezHY3t5GQ+6it+2xMASsKhEEWKsmRLRBBUpPvpJ/TpFKFBwKYAiITmicsbYhdHfJAltqhUCVsCQhwslmeXmZxiBQT9c0Ar9E2O3v72sYSE0N1yQArkKy0kBMXLqlZqIZHR3t6empqqqSDcBdhXEJSJ/bUc3q6uq+vj629GB9fR1WsLW1NTs7u7S0RN2locMjIyOEm5ubQ7+4uJienk4/+vv77Y1hwhLBEKhwWHitdVFfX9/Y2Gg2HuLi4owUAysrK8yCG97rh0+ApP5Q2ZycHFlPTExUVFRIBvn5+WhKSkp2dnaMKhptbW2426GgQ/rwuAQCZ1hwFayLiork9hMFBQV1dXVmE0BLS4vqw3QFB8kn4IAxoGPkYpxi4FeDmpqas7Mz4pClAgqGwD48rjY2NmacYqC0tJQ1KSlJWyE5OZkpUKkBAxZVIntAoZh04+Q48fHxPNGBgYHExMT29naj9cBodnZ2mo3jlJWVMeW2OGQck4B1amqqoaGhqamJjx2lGxwcpL0mUgR8fJhsWqJtSkoKU2SbHHUDpkhPBujd8xuQG6PJRM/Pz09PT7O1NNnZ2Tw3fgZkXVhYKCUlUhBATP+hCVyKZGky17RV0g04laayslJ6hlVeFHB4eFhKaogGd0LxtmTgE+hbhKDnPjMzgw8E3qGL2tpaBWpubjYqj2BoaEj6rq4uNATRZ0ZwCbiL6gXEzINk5vCBQJ9rMD4+rkA8QNK036uDg4Py8vLu7m680KjIBNR3zBDoWQM1g98snyB+VSoRW8C/UwR81/SvhgNj9JOTkwwVERUdRBEI0BAdLRVERkhLS8vIyEDQlrsTPTU1lVFhKxARvZgUlFLbegCf4BvIsbi4mIg4E5EogIHhiKCMtU0WUFiVy06j5fAJIDdSBDQw+PegDfBRcbOPwH4F9LuFWIIQdQNKwWqzIE0aoFUaBsw+SQuFw0uNtC9A+F4i3QNrbg3IDn+SAsHh+wYiEpeyBEMLv/cAO6KzAijxxB+Y4wisBhssJUhjEbPJf4Nw+B+JXqLW3bw+wQAAAABJRU5ErkJggg==" />
+${fat_offline_data}
+</head>
+<body style="margin:0px;width:100%;height:100%;overflow:hidden;background-color:white;" id="game_frame">
+<div style="margin:0px;width:100%;height:100%;font-family:sans-serif;display:flex;align-items:center;user-select:none;" id="launch_countdown_screen">
+<div style="margin:auto;text-align:center;">
+<h1>EaglercraftX 1.8 "Fat Offline"</h1>
+<h3>Contains: ${num_clients} Client(s)</h3>
+<h2>Game will launch in <span id="launchCountdownNumber">5</span>...</h2>
+<div style="border:2px solid black;width:100%;height:15px;padding:1px;margin-bottom:20vh;"><div id="launchCountdownProgress" style="background-color:#555555;width:0%;height:100%;"></div>
+<p style="margin-top:30px;"><button id="skipCountdown" autofocus>Skip Countdown</button></p></div>
+</div>
+</div>
+</body>
+</html>
diff --git a/sources/resources/assets/eagler/boot_menu/offline_template_eaglercraftX_1_8_fat_signed.html b/sources/resources/assets/eagler/boot_menu/offline_template_eaglercraftX_1_8_fat_signed.html
new file mode 100644
index 00000000..0666b518
--- /dev/null
+++ b/sources/resources/assets/eagler/boot_menu/offline_template_eaglercraftX_1_8_fat_signed.html
@@ -0,0 +1,268 @@
+<!DOCTYPE html>
+
+<!--
+
+This file is from ${date}, it was generated using EaglercraftX 1.8 boot manager
+
+-->
+
+<html style="width:100%;height:100%;background-color:black;">
+<head>
+<meta charset="UTF-8" />
+<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0" />
+<meta name="description" content="EaglercraftX 1.8" />
+<meta name="keywords" content="eaglercraft, eaglercraftx, minecraft, 1.8, 1.8.8" />
+<title>EaglercraftX 1.8</title>
+<meta property="og:locale" content="en-US" />
+<meta property="og:type" content="website" />
+<meta property="og:title" content="EaglercraftX 1.8" />
+<meta property="og:description" content="Play minecraft 1.8 in your browser" />
+<style type="eaglercraftOfflineParseHint">{"type":"EAGLERCRAFTX_1_8_FAT_SIGNED","launchConf":${launch_conf_json}}</style>
+<script type="text/javascript">
+"use strict";
+var relayIdMax = ${relayId_max};
+var relayId = relayIdMax > 1 ? Math.floor(Math.random() * relayIdMax) : 0;
+
+// %%%%%%%%% launch options %%%%%%%%%%%%
+
+window.eaglercraftXOptsHints = ${launch_opts};
+window.eaglercraftXOptsHints.hintsVersion = 1;
+window.eaglercraftXOptsHints.container = "game_frame";
+window.eaglercraftXOptsHints.showBootMenuOnLaunch = true;
+
+// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+</script>
+<style type="eaglercraft" id="eaglercraftXClientSignature">data:application/octet-stream;base64,${client_signature}</style>
+<style type="eaglercraft" id="eaglercraftXClientBundle">data:application/octet-stream;base64,${client_bundle}</style>
+<script type="text/javascript">
+"use strict";
+(function(){
+	function eaglerBundleUnwrap(tagIn) { var e = document.getElementById(tagIn); var ret = e.innerText; document.head.removeChild(e); return ret;  }
+	window.eaglercraftXClientSignature = eaglerBundleUnwrap("eaglercraftXClientSignature");
+	window.eaglercraftXClientBundle = eaglerBundleUnwrap("eaglercraftXClientBundle");
+})();
+</script>
+<script type="text/javascript">
+"use strict";
+(function(){
+	(function(a){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=a();else if("function"==typeof define&&define.amd)define([],a);else{var b;b="undefined"==typeof window?"undefined"==typeof global?"undefined"==typeof self?this:self:global:window,b.base64js=a()}})(function(){return function(){function b(d,e,g){function a(j,i){if(!e[j]){if(!d[j]){var f="function"==typeof require&&require;if(!i&&f)return f(j,!0);if(h)return h(j,!0);var c=new Error("Cannot find module '"+j+"'");throw c.code="MODULE_NOT_FOUND",c}var k=e[j]={exports:{}};d[j][0].call(k.exports,function(b){var c=d[j][1][b];return a(c||b)},k,k.exports,b,d,e,g)}return e[j].exports}for(var h="function"==typeof require&&require,c=0;c<g.length;c++)a(g[c]);return a}return b}()({"/":[function(a,b,c){'use strict';function d(a){var b=a.length;if(0<b%4)throw new Error("Invalid string. Length must be a multiple of 4");var c=a.indexOf("=");-1===c&&(c=b);var d=c===b?0:4-c%4;return[c,d]}function e(a,b,c){return 3*(b+c)/4-c}function f(a){var b,c,f=d(a),g=f[0],h=f[1],j=new m(e(a,g,h)),k=0,n=0<h?g-4:g;for(c=0;c<n;c+=4)b=l[a.charCodeAt(c)]<<18|l[a.charCodeAt(c+1)]<<12|l[a.charCodeAt(c+2)]<<6|l[a.charCodeAt(c+3)],j[k++]=255&b>>16,j[k++]=255&b>>8,j[k++]=255&b;return 2===h&&(b=l[a.charCodeAt(c)]<<2|l[a.charCodeAt(c+1)]>>4,j[k++]=255&b),1===h&&(b=l[a.charCodeAt(c)]<<10|l[a.charCodeAt(c+1)]<<4|l[a.charCodeAt(c+2)]>>2,j[k++]=255&b>>8,j[k++]=255&b),j}function g(a){return k[63&a>>18]+k[63&a>>12]+k[63&a>>6]+k[63&a]}function h(a,b,c){for(var d,e=[],f=b;f<c;f+=3)d=(16711680&a[f]<<16)+(65280&a[f+1]<<8)+(255&a[f+2]),e.push(g(d));return e.join("")}function j(a){for(var b,c=a.length,d=c%3,e=[],f=16383,g=0,j=c-d;g<j;g+=f)e.push(h(a,g,g+f>j?j:g+f));return 1===d?(b=a[c-1],e.push(k[b>>2]+k[63&b<<4]+"==")):2===d&&(b=(a[c-2]<<8)+a[c-1],e.push(k[b>>10]+k[63&b>>4]+k[63&b<<2]+"=")),e.join("")}c.byteLength=function(a){var b=d(a),c=b[0],e=b[1];return 3*(c+e)/4-e},c.toByteArray=f,c.fromByteArray=j;for(var k=[],l=[],m="undefined"==typeof Uint8Array?Array:Uint8Array,n="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",o=0,p=n.length;o<p;++o)k[o]=n[o],l[n.charCodeAt(o)]=o;l[45]=62,l[95]=63},{}]},{},[])("/")});
+	var sameOriginSupport = -1;
+	var checkSameOriginSupport = function(callback0) {
+		if(sameOriginSupport == -1) {
+			try {
+				(function(callback) {
+					if((typeof URL === "undefined") || (typeof URL.createObjectURL !== "function")) {
+						sameOriginSupport = 1;
+						callback(false);
+					}else {
+						var theObjURL = URL.createObjectURL(new Blob([new Uint8Array([69, 69, 69, 69])]));
+						if(!theObjURL) {
+							sameOriginSupport = 1;
+							callback(false);
+						}
+						doXHR(theObjURL, function(dataRet) {
+							if(dataRet) {
+								var typedArr = new Uint8Array(dataRet);
+								if(typedArr.length === 4 && typedArr[0] === 69 && typedArr[1] === 69 && typedArr[2] === 69 && typedArr[3] === 69) {
+									sameOriginSupport = 0;
+									callback(true);
+								}else {
+									sameOriginSupport = 1;
+									callback(false);
+								}
+							}else {
+								sameOriginSupport = 1;
+								callback(false);
+							}
+						});
+					}
+				})(function(valRet) {
+					if(!valRet) {
+						console.error("Same origin XHR support detected as false, using data: url...");
+					}
+					callback0(valRet);
+				});
+			}catch(ex) {
+				console.error("Same origin XHR support detection failed, using data: url...");
+				callback0(false);
+			}
+		}else {
+			callback0(!sameOriginSupport);
+		}
+	};
+	var blobToArrayBuffer = function(blobIn, callback) {
+		if(typeof blobIn.arrayBuffer === "undefined") {
+			blobIn.arrayBuffer().then(callback);
+		}else {
+			(function(phileReader) {
+				phileReader.addEventListener("load", function(evt) {
+					callback(phileReader.result);
+				});
+				phileReader.readAsArrayBuffer(blobIn);
+			})(new FileReader());
+		}
+	};
+	var completeXHR = function(callback, arg) {
+		if(!callback.comp) {
+			callback.comp = true;
+			callback.cb(arg);
+		}
+	};
+	var doXHR = function(urlIn, callback) {
+		(function(theXHRObj, callbackStruct){
+			theXHRObj.responseType = "arraybuffer";
+			theXHRObj.addEventListener("load", function(evt) { var stat = theXHRObj.status; if(stat === 0 || (stat >= 200 && stat < 400)) { completeXHR(callbackStruct, theXHRObj.response); } else { completeXHR(callbackStruct, null); } });
+			theXHRObj.addEventListener("error", function(evt) {  completeXHR(callbackStruct, null); });
+			theXHRObj.open("GET", urlIn, true);
+			theXHRObj.send();
+		})(new XMLHttpRequest(), { cb: callback, comp: false });
+	};
+	var decodeBase64URL = function(urlIn, callbackOut) {
+		doXHR(urlIn, function(data) {
+			if(!data) {
+				try {
+					console.error("Caught an error decoding base64 via fetch, doing it the slow way instead...");
+					callbackOut(base64js.toByteArray(urlIn.substring(37)).buffer);
+				}catch(ex) {
+					console.error("Failed to decode base64!");
+					console.error(ex);
+					callbackOut(null);
+				}
+			}else {
+				callbackOut(data);
+			}
+		});
+	};
+	if(typeof window.DecompressionStream === "undefined") {
+		checkSameOriginSupport(function(soSupported) {
+			var theWorkerObj;
+			var workerSrc = "InVzZSBzdHJpY3QiOwovKiEgcGFrbyAyLjEuMCBodHRwczovL2dpdGh1Yi5jb20vbm9kZWNhL3Bha28gQGxpY2Vuc2UgKE1JVCBBTkQgWmxpYikgKi8KIWZ1bmN0aW9uKGUsdCl7Im9iamVjdCI9PXR5cGVvZiBleHBvcnRzJiYidW5kZWZpbmVkIiE9dHlwZW9mIG1vZHVsZT90KGV4cG9ydHMpOiJmdW5jdGlvbiI9PXR5cGVvZiBkZWZpbmUmJmRlZmluZS5hbWQ/ZGVmaW5lKFsiZXhwb3J0cyJdLHQpOnQoKGU9InVuZGVmaW5lZCIhPXR5cGVvZiBnbG9iYWxUaGlzP2dsb2JhbFRoaXM6ZXx8c2VsZikucGFrbz17fSl9KHRoaXMsKGZ1bmN0aW9uKGUpeyJ1c2Ugc3RyaWN0Ijt2YXIgdD1mdW5jdGlvbihlLHQsaSxuKXtmb3IodmFyIGE9NjU1MzUmZXwwLHI9ZT4+PjE2JjY1NTM1fDAsbz0wOzAhPT1pOyl7aS09bz1pPjJlMz8yZTM6aTtkb3tyPXIrKGE9YSt0W24rK118MCl8MH13aGlsZSgtLW8pO2ElPTY1NTIxLHIlPTY1NTIxfXJldHVybiBhfHI8PDE2fDB9LGk9bmV3IFVpbnQzMkFycmF5KGZ1bmN0aW9uKCl7Zm9yKHZhciBlLHQ9W10saT0wO2k8MjU2O2krKyl7ZT1pO2Zvcih2YXIgbj0wO248ODtuKyspZT0xJmU/Mzk4ODI5MjM4NF5lPj4+MTplPj4+MTt0W2ldPWV9cmV0dXJuIHR9KCkpLG49ZnVuY3Rpb24oZSx0LG4sYSl7dmFyIHI9aSxvPWErbjtlXj0tMTtmb3IodmFyIHM9YTtzPG87cysrKWU9ZT4+PjheclsyNTUmKGVedFtzXSldO3JldHVybi0xXmV9LGE9MTYyMDkscj1mdW5jdGlvbihlLHQpe3ZhciBpLG4scixvLHMsbCxmLGQsaCxjLHUsdyxiLG0sayxfLHYsZyxwLHkseCxFLFIsQSxaPWUuc3RhdGU7aT1lLm5leHRfaW4sUj1lLmlucHV0LG49aSsoZS5hdmFpbF9pbi01KSxyPWUubmV4dF9vdXQsQT1lLm91dHB1dCxvPXItKHQtZS5hdmFpbF9vdXQpLHM9cisoZS5hdmFpbF9vdXQtMjU3KSxsPVouZG1heCxmPVoud3NpemUsZD1aLndoYXZlLGg9Wi53bmV4dCxjPVoud2luZG93LHU9Wi5ob2xkLHc9Wi5iaXRzLGI9Wi5sZW5jb2RlLG09Wi5kaXN0Y29kZSxrPSgxPDxaLmxlbmJpdHMpLTEsXz0oMTw8Wi5kaXN0Yml0cyktMTtlOmRve3c8MTUmJih1Kz1SW2krK108PHcsdys9OCx1Kz1SW2krK108PHcsdys9OCksdj1iW3Uma107dDpmb3IoOzspe2lmKHU+Pj49Zz12Pj4+MjQsdy09ZywwPT09KGc9dj4+PjE2JjI1NSkpQVtyKytdPTY1NTM1JnY7ZWxzZXtpZighKDE2JmcpKXtpZigwPT0oNjQmZykpe3Y9YlsoNjU1MzUmdikrKHUmKDE8PGcpLTEpXTtjb250aW51ZSB0fWlmKDMyJmcpe1oubW9kZT0xNjE5MTticmVhayBlfWUubXNnPSJpbnZhbGlkIGxpdGVyYWwvbGVuZ3RoIGNvZGUiLFoubW9kZT1hO2JyZWFrIGV9cD02NTUzNSZ2LChnJj0xNSkmJih3PGcmJih1Kz1SW2krK108PHcsdys9OCkscCs9dSYoMTw8ZyktMSx1Pj4+PWcsdy09ZyksdzwxNSYmKHUrPVJbaSsrXTw8dyx3Kz04LHUrPVJbaSsrXTw8dyx3Kz04KSx2PW1bdSZfXTtpOmZvcig7Oyl7aWYodT4+Pj1nPXY+Pj4yNCx3LT1nLCEoMTYmKGc9dj4+PjE2JjI1NSkpKXtpZigwPT0oNjQmZykpe3Y9bVsoNjU1MzUmdikrKHUmKDE8PGcpLTEpXTtjb250aW51ZSBpfWUubXNnPSJpbnZhbGlkIGRpc3RhbmNlIGNvZGUiLFoubW9kZT1hO2JyZWFrIGV9aWYoeT02NTUzNSZ2LHc8KGcmPTE1KSYmKHUrPVJbaSsrXTw8dywodys9OCk8ZyYmKHUrPVJbaSsrXTw8dyx3Kz04KSksKHkrPXUmKDE8PGcpLTEpPmwpe2UubXNnPSJpbnZhbGlkIGRpc3RhbmNlIHRvbyBmYXIgYmFjayIsWi5tb2RlPWE7YnJlYWsgZX1pZih1Pj4+PWcsdy09Zyx5PihnPXItbykpe2lmKChnPXktZyk+ZCYmWi5zYW5lKXtlLm1zZz0iaW52YWxpZCBkaXN0YW5jZSB0b28gZmFyIGJhY2siLFoubW9kZT1hO2JyZWFrIGV9aWYoeD0wLEU9YywwPT09aCl7aWYoeCs9Zi1nLGc8cCl7cC09Zztkb3tBW3IrK109Y1t4KytdfXdoaWxlKC0tZyk7eD1yLXksRT1BfX1lbHNlIGlmKGg8Zyl7aWYoeCs9ZitoLWcsKGctPWgpPHApe3AtPWc7ZG97QVtyKytdPWNbeCsrXX13aGlsZSgtLWcpO2lmKHg9MCxoPHApe3AtPWc9aDtkb3tBW3IrK109Y1t4KytdfXdoaWxlKC0tZyk7eD1yLXksRT1BfX19ZWxzZSBpZih4Kz1oLWcsZzxwKXtwLT1nO2Rve0FbcisrXT1jW3grK119d2hpbGUoLS1nKTt4PXIteSxFPUF9Zm9yKDtwPjI7KUFbcisrXT1FW3grK10sQVtyKytdPUVbeCsrXSxBW3IrK109RVt4KytdLHAtPTM7cCYmKEFbcisrXT1FW3grK10scD4xJiYoQVtyKytdPUVbeCsrXSkpfWVsc2V7eD1yLXk7ZG97QVtyKytdPUFbeCsrXSxBW3IrK109QVt4KytdLEFbcisrXT1BW3grK10scC09M313aGlsZShwPjIpO3AmJihBW3IrK109QVt4KytdLHA+MSYmKEFbcisrXT1BW3grK10pKX1icmVha319YnJlYWt9fXdoaWxlKGk8biYmcjxzKTtpLT1wPXc+PjMsdSY9KDE8PCh3LT1wPDwzKSktMSxlLm5leHRfaW49aSxlLm5leHRfb3V0PXIsZS5hdmFpbF9pbj1pPG4/bi1pKzU6NS0oaS1uKSxlLmF2YWlsX291dD1yPHM/cy1yKzI1NzoyNTctKHItcyksWi5ob2xkPXUsWi5iaXRzPXd9LG89MTUscz1uZXcgVWludDE2QXJyYXkoWzMsNCw1LDYsNyw4LDksMTAsMTEsMTMsMTUsMTcsMTksMjMsMjcsMzEsMzUsNDMsNTEsNTksNjcsODMsOTksMTE1LDEzMSwxNjMsMTk1LDIyNywyNTgsMCwwXSksbD1uZXcgVWludDhBcnJheShbMTYsMTYsMTYsMTYsMTYsMTYsMTYsMTYsMTcsMTcsMTcsMTcsMTgsMTgsMTgsMTgsMTksMTksMTksMTksMjAsMjAsMjAsMjAsMjEsMjEsMjEsMjEsMTYsNzIsNzhdKSxmPW5ldyBVaW50MTZBcnJheShbMSwyLDMsNCw1LDcsOSwxMywxNywyNSwzMyw0OSw2NSw5NywxMjksMTkzLDI1NywzODUsNTEzLDc2OSwxMDI1LDE1MzcsMjA0OSwzMDczLDQwOTcsNjE0NSw4MTkzLDEyMjg5LDE2Mzg1LDI0NTc3LDAsMF0pLGQ9bmV3IFVpbnQ4QXJyYXkoWzE2LDE2LDE2LDE2LDE3LDE3LDE4LDE4LDE5LDE5LDIwLDIwLDIxLDIxLDIyLDIyLDIzLDIzLDI0LDI0LDI1LDI1LDI2LDI2LDI3LDI3LDI4LDI4LDI5LDI5LDY0LDY0XSksaD1mdW5jdGlvbihlLHQsaSxuLGEscixoLGMpe3ZhciB1LHcsYixtLGssXyx2LGcscCx5PWMuYml0cyx4PTAsRT0wLFI9MCxBPTAsWj0wLFM9MCxUPTAsTz0wLFU9MCxEPTAsST1udWxsLEI9bmV3IFVpbnQxNkFycmF5KDE2KSxOPW5ldyBVaW50MTZBcnJheSgxNiksQz1udWxsO2Zvcih4PTA7eDw9bzt4KyspQlt4XT0wO2ZvcihFPTA7RTxuO0UrKylCW3RbaStFXV0rKztmb3IoWj15LEE9bztBPj0xJiYwPT09QltBXTtBLS0pO2lmKFo+QSYmKFo9QSksMD09PUEpcmV0dXJuIGFbcisrXT0yMDk3MTUyMCxhW3IrK109MjA5NzE1MjAsYy5iaXRzPTEsMDtmb3IoUj0xO1I8QSYmMD09PUJbUl07UisrKTtmb3IoWjxSJiYoWj1SKSxPPTEseD0xO3g8PW87eCsrKWlmKE88PD0xLChPLT1CW3hdKTwwKXJldHVybi0xO2lmKE8+MCYmKDA9PT1lfHwxIT09QSkpcmV0dXJuLTE7Zm9yKE5bMV09MCx4PTE7eDxvO3grKylOW3grMV09Tlt4XStCW3hdO2ZvcihFPTA7RTxuO0UrKykwIT09dFtpK0VdJiYoaFtOW3RbaStFXV0rK109RSk7aWYoMD09PWU/KEk9Qz1oLF89MjApOjE9PT1lPyhJPXMsQz1sLF89MjU3KTooST1mLEM9ZCxfPTApLEQ9MCxFPTAseD1SLGs9cixTPVosVD0wLGI9LTEsbT0oVT0xPDxaKS0xLDE9PT1lJiZVPjg1Mnx8Mj09PWUmJlU+NTkyKXJldHVybiAxO2Zvcig7Oyl7dj14LVQsaFtFXSsxPF8/KGc9MCxwPWhbRV0pOmhbRV0+PV8/KGc9Q1toW0VdLV9dLHA9SVtoW0VdLV9dKTooZz05NixwPTApLHU9MTw8eC1ULFI9dz0xPDxTO2Rve2FbaysoRD4+VCkrKHctPXUpXT12PDwyNHxnPDwxNnxwfDB9d2hpbGUoMCE9PXcpO2Zvcih1PTE8PHgtMTtEJnU7KXU+Pj0xO2lmKDAhPT11PyhEJj11LTEsRCs9dSk6RD0wLEUrKywwPT0tLUJbeF0pe2lmKHg9PT1BKWJyZWFrO3g9dFtpK2hbRV1dfWlmKHg+WiYmKEQmbSkhPT1iKXtmb3IoMD09PVQmJihUPVopLGsrPVIsTz0xPDwoUz14LVQpO1MrVDxBJiYhKChPLT1CW1MrVF0pPD0wKTspUysrLE88PD0xO2lmKFUrPTE8PFMsMT09PWUmJlU+ODUyfHwyPT09ZSYmVT41OTIpcmV0dXJuIDE7YVtiPUQmbV09Wjw8MjR8Uzw8MTZ8ay1yfDB9fXJldHVybiAwIT09RCYmKGFbaytEXT14LVQ8PDI0fDY0PDwxNnwwKSxjLmJpdHM9WiwwfSxjPXtaX05PX0ZMVVNIOjAsWl9QQVJUSUFMX0ZMVVNIOjEsWl9TWU5DX0ZMVVNIOjIsWl9GVUxMX0ZMVVNIOjMsWl9GSU5JU0g6NCxaX0JMT0NLOjUsWl9UUkVFUzo2LFpfT0s6MCxaX1NUUkVBTV9FTkQ6MSxaX05FRURfRElDVDoyLFpfRVJSTk86LTEsWl9TVFJFQU1fRVJST1I6LTIsWl9EQVRBX0VSUk9SOi0zLFpfTUVNX0VSUk9SOi00LFpfQlVGX0VSUk9SOi01LFpfTk9fQ09NUFJFU1NJT046MCxaX0JFU1RfU1BFRUQ6MSxaX0JFU1RfQ09NUFJFU1NJT046OSxaX0RFRkFVTFRfQ09NUFJFU1NJT046LTEsWl9GSUxURVJFRDoxLFpfSFVGRk1BTl9PTkxZOjIsWl9STEU6MyxaX0ZJWEVEOjQsWl9ERUZBVUxUX1NUUkFURUdZOjAsWl9CSU5BUlk6MCxaX1RFWFQ6MSxaX1VOS05PV046MixaX0RFRkxBVEVEOjh9LHU9Yy5aX0ZJTklTSCx3PWMuWl9CTE9DSyxiPWMuWl9UUkVFUyxtPWMuWl9PSyxrPWMuWl9TVFJFQU1fRU5ELF89Yy5aX05FRURfRElDVCx2PWMuWl9TVFJFQU1fRVJST1IsZz1jLlpfREFUQV9FUlJPUixwPWMuWl9NRU1fRVJST1IseT1jLlpfQlVGX0VSUk9SLHg9Yy5aX0RFRkxBVEVELEU9MTYxODAsUj0xNjE5MCxBPTE2MTkxLFo9MTYxOTIsUz0xNjE5NCxUPTE2MTk5LE89MTYyMDAsVT0xNjIwNixEPTE2MjA5LEk9ZnVuY3Rpb24oZSl7cmV0dXJuKGU+Pj4yNCYyNTUpKyhlPj4+OCY2NTI4MCkrKCg2NTI4MCZlKTw8OCkrKCgyNTUmZSk8PDI0KX07ZnVuY3Rpb24gQigpe3RoaXMuc3RybT1udWxsLHRoaXMubW9kZT0wLHRoaXMubGFzdD0hMSx0aGlzLndyYXA9MCx0aGlzLmhhdmVkaWN0PSExLHRoaXMuZmxhZ3M9MCx0aGlzLmRtYXg9MCx0aGlzLmNoZWNrPTAsdGhpcy50b3RhbD0wLHRoaXMuaGVhZD1udWxsLHRoaXMud2JpdHM9MCx0aGlzLndzaXplPTAsdGhpcy53aGF2ZT0wLHRoaXMud25leHQ9MCx0aGlzLndpbmRvdz1udWxsLHRoaXMuaG9sZD0wLHRoaXMuYml0cz0wLHRoaXMubGVuZ3RoPTAsdGhpcy5vZmZzZXQ9MCx0aGlzLmV4dHJhPTAsdGhpcy5sZW5jb2RlPW51bGwsdGhpcy5kaXN0Y29kZT1udWxsLHRoaXMubGVuYml0cz0wLHRoaXMuZGlzdGJpdHM9MCx0aGlzLm5jb2RlPTAsdGhpcy5ubGVuPTAsdGhpcy5uZGlzdD0wLHRoaXMuaGF2ZT0wLHRoaXMubmV4dD1udWxsLHRoaXMubGVucz1uZXcgVWludDE2QXJyYXkoMzIwKSx0aGlzLndvcms9bmV3IFVpbnQxNkFycmF5KDI4OCksdGhpcy5sZW5keW49bnVsbCx0aGlzLmRpc3RkeW49bnVsbCx0aGlzLnNhbmU9MCx0aGlzLmJhY2s9MCx0aGlzLndhcz0wfXZhciBOLEMsej1mdW5jdGlvbihlKXtpZighZSlyZXR1cm4gMTt2YXIgdD1lLnN0YXRlO3JldHVybiF0fHx0LnN0cm0hPT1lfHx0Lm1vZGU8RXx8dC5tb2RlPjE2MjExPzE6MH0sRj1mdW5jdGlvbihlKXtpZih6KGUpKXJldHVybiB2O3ZhciB0PWUuc3RhdGU7cmV0dXJuIGUudG90YWxfaW49ZS50b3RhbF9vdXQ9dC50b3RhbD0wLGUubXNnPSIiLHQud3JhcCYmKGUuYWRsZXI9MSZ0LndyYXApLHQubW9kZT1FLHQubGFzdD0wLHQuaGF2ZWRpY3Q9MCx0LmZsYWdzPS0xLHQuZG1heD0zMjc2OCx0LmhlYWQ9bnVsbCx0LmhvbGQ9MCx0LmJpdHM9MCx0LmxlbmNvZGU9dC5sZW5keW49bmV3IEludDMyQXJyYXkoODUyKSx0LmRpc3Rjb2RlPXQuZGlzdGR5bj1uZXcgSW50MzJBcnJheSg1OTIpLHQuc2FuZT0xLHQuYmFjaz0tMSxtfSxMPWZ1bmN0aW9uKGUpe2lmKHooZSkpcmV0dXJuIHY7dmFyIHQ9ZS5zdGF0ZTtyZXR1cm4gdC53c2l6ZT0wLHQud2hhdmU9MCx0LnduZXh0PTAsRihlKX0sTT1mdW5jdGlvbihlLHQpe3ZhciBpO2lmKHooZSkpcmV0dXJuIHY7dmFyIG49ZS5zdGF0ZTtyZXR1cm4gdDwwPyhpPTAsdD0tdCk6KGk9NSsodD4+NCksdDw0OCYmKHQmPTE1KSksdCYmKHQ8OHx8dD4xNSk/djoobnVsbCE9PW4ud2luZG93JiZuLndiaXRzIT09dCYmKG4ud2luZG93PW51bGwpLG4ud3JhcD1pLG4ud2JpdHM9dCxMKGUpKX0sSD1mdW5jdGlvbihlLHQpe2lmKCFlKXJldHVybiB2O3ZhciBpPW5ldyBCO2Uuc3RhdGU9aSxpLnN0cm09ZSxpLndpbmRvdz1udWxsLGkubW9kZT1FO3ZhciBuPU0oZSx0KTtyZXR1cm4gbiE9PW0mJihlLnN0YXRlPW51bGwpLG59LGo9ITAsSz1mdW5jdGlvbihlKXtpZihqKXtOPW5ldyBJbnQzMkFycmF5KDUxMiksQz1uZXcgSW50MzJBcnJheSgzMik7Zm9yKHZhciB0PTA7dDwxNDQ7KWUubGVuc1t0KytdPTg7Zm9yKDt0PDI1NjspZS5sZW5zW3QrK109OTtmb3IoO3Q8MjgwOyllLmxlbnNbdCsrXT03O2Zvcig7dDwyODg7KWUubGVuc1t0KytdPTg7Zm9yKGgoMSxlLmxlbnMsMCwyODgsTiwwLGUud29yayx7Yml0czo5fSksdD0wO3Q8MzI7KWUubGVuc1t0KytdPTU7aCgyLGUubGVucywwLDMyLEMsMCxlLndvcmsse2JpdHM6NX0pLGo9ITF9ZS5sZW5jb2RlPU4sZS5sZW5iaXRzPTksZS5kaXN0Y29kZT1DLGUuZGlzdGJpdHM9NX0sUD1mdW5jdGlvbihlLHQsaSxuKXt2YXIgYSxyPWUuc3RhdGU7cmV0dXJuIG51bGw9PT1yLndpbmRvdyYmKHIud3NpemU9MTw8ci53Yml0cyxyLnduZXh0PTAsci53aGF2ZT0wLHIud2luZG93PW5ldyBVaW50OEFycmF5KHIud3NpemUpKSxuPj1yLndzaXplPyhyLndpbmRvdy5zZXQodC5zdWJhcnJheShpLXIud3NpemUsaSksMCksci53bmV4dD0wLHIud2hhdmU9ci53c2l6ZSk6KChhPXIud3NpemUtci53bmV4dCk+biYmKGE9biksci53aW5kb3cuc2V0KHQuc3ViYXJyYXkoaS1uLGktbithKSxyLnduZXh0KSwobi09YSk/KHIud2luZG93LnNldCh0LnN1YmFycmF5KGktbixpKSwwKSxyLnduZXh0PW4sci53aGF2ZT1yLndzaXplKTooci53bmV4dCs9YSxyLnduZXh0PT09ci53c2l6ZSYmKHIud25leHQ9MCksci53aGF2ZTxyLndzaXplJiYoci53aGF2ZSs9YSkpKSwwfSxZPXtpbmZsYXRlUmVzZXQ6TCxpbmZsYXRlUmVzZXQyOk0saW5mbGF0ZVJlc2V0S2VlcDpGLGluZmxhdGVJbml0OmZ1bmN0aW9uKGUpe3JldHVybiBIKGUsMTUpfSxpbmZsYXRlSW5pdDI6SCxpbmZsYXRlOmZ1bmN0aW9uKGUsaSl7dmFyIGEsbyxzLGwsZixkLGMsQixOLEMsRixMLE0sSCxqLFksRyxYLFcscSxKLFEsViwkLGVlPTAsdGU9bmV3IFVpbnQ4QXJyYXkoNCksaWU9bmV3IFVpbnQ4QXJyYXkoWzE2LDE3LDE4LDAsOCw3LDksNiwxMCw1LDExLDQsMTIsMywxMywyLDE0LDEsMTVdKTtpZih6KGUpfHwhZS5vdXRwdXR8fCFlLmlucHV0JiYwIT09ZS5hdmFpbF9pbilyZXR1cm4gdjsoYT1lLnN0YXRlKS5tb2RlPT09QSYmKGEubW9kZT1aKSxmPWUubmV4dF9vdXQscz1lLm91dHB1dCxjPWUuYXZhaWxfb3V0LGw9ZS5uZXh0X2luLG89ZS5pbnB1dCxkPWUuYXZhaWxfaW4sQj1hLmhvbGQsTj1hLmJpdHMsQz1kLEY9YyxRPW07ZTpmb3IoOzspc3dpdGNoKGEubW9kZSl7Y2FzZSBFOmlmKDA9PT1hLndyYXApe2EubW9kZT1aO2JyZWFrfWZvcig7TjwxNjspe2lmKDA9PT1kKWJyZWFrIGU7ZC0tLEIrPW9bbCsrXTw8TixOKz04fWlmKDImYS53cmFwJiYzNTYxNT09PUIpezA9PT1hLndiaXRzJiYoYS53Yml0cz0xNSksYS5jaGVjaz0wLHRlWzBdPTI1NSZCLHRlWzFdPUI+Pj44JjI1NSxhLmNoZWNrPW4oYS5jaGVjayx0ZSwyLDApLEI9MCxOPTAsYS5tb2RlPTE2MTgxO2JyZWFrfWlmKGEuaGVhZCYmKGEuaGVhZC5kb25lPSExKSwhKDEmYS53cmFwKXx8KCgoMjU1JkIpPDw4KSsoQj4+OCkpJTMxKXtlLm1zZz0iaW5jb3JyZWN0IGhlYWRlciBjaGVjayIsYS5tb2RlPUQ7YnJlYWt9aWYoKDE1JkIpIT09eCl7ZS5tc2c9InVua25vd24gY29tcHJlc3Npb24gbWV0aG9kIixhLm1vZGU9RDticmVha31pZihOLT00LEo9OCsoMTUmKEI+Pj49NCkpLDA9PT1hLndiaXRzJiYoYS53Yml0cz1KKSxKPjE1fHxKPmEud2JpdHMpe2UubXNnPSJpbnZhbGlkIHdpbmRvdyBzaXplIixhLm1vZGU9RDticmVha31hLmRtYXg9MTw8YS53Yml0cyxhLmZsYWdzPTAsZS5hZGxlcj1hLmNoZWNrPTEsYS5tb2RlPTUxMiZCPzE2MTg5OkEsQj0wLE49MDticmVhaztjYXNlIDE2MTgxOmZvcig7TjwxNjspe2lmKDA9PT1kKWJyZWFrIGU7ZC0tLEIrPW9bbCsrXTw8TixOKz04fWlmKGEuZmxhZ3M9QiwoMjU1JmEuZmxhZ3MpIT09eCl7ZS5tc2c9InVua25vd24gY29tcHJlc3Npb24gbWV0aG9kIixhLm1vZGU9RDticmVha31pZig1NzM0NCZhLmZsYWdzKXtlLm1zZz0idW5rbm93biBoZWFkZXIgZmxhZ3Mgc2V0IixhLm1vZGU9RDticmVha31hLmhlYWQmJihhLmhlYWQudGV4dD1CPj44JjEpLDUxMiZhLmZsYWdzJiY0JmEud3JhcCYmKHRlWzBdPTI1NSZCLHRlWzFdPUI+Pj44JjI1NSxhLmNoZWNrPW4oYS5jaGVjayx0ZSwyLDApKSxCPTAsTj0wLGEubW9kZT0xNjE4MjtjYXNlIDE2MTgyOmZvcig7TjwzMjspe2lmKDA9PT1kKWJyZWFrIGU7ZC0tLEIrPW9bbCsrXTw8TixOKz04fWEuaGVhZCYmKGEuaGVhZC50aW1lPUIpLDUxMiZhLmZsYWdzJiY0JmEud3JhcCYmKHRlWzBdPTI1NSZCLHRlWzFdPUI+Pj44JjI1NSx0ZVsyXT1CPj4+MTYmMjU1LHRlWzNdPUI+Pj4yNCYyNTUsYS5jaGVjaz1uKGEuY2hlY2ssdGUsNCwwKSksQj0wLE49MCxhLm1vZGU9MTYxODM7Y2FzZSAxNjE4Mzpmb3IoO048MTY7KXtpZigwPT09ZClicmVhayBlO2QtLSxCKz1vW2wrK108PE4sTis9OH1hLmhlYWQmJihhLmhlYWQueGZsYWdzPTI1NSZCLGEuaGVhZC5vcz1CPj44KSw1MTImYS5mbGFncyYmNCZhLndyYXAmJih0ZVswXT0yNTUmQix0ZVsxXT1CPj4+OCYyNTUsYS5jaGVjaz1uKGEuY2hlY2ssdGUsMiwwKSksQj0wLE49MCxhLm1vZGU9MTYxODQ7Y2FzZSAxNjE4NDppZigxMDI0JmEuZmxhZ3Mpe2Zvcig7TjwxNjspe2lmKDA9PT1kKWJyZWFrIGU7ZC0tLEIrPW9bbCsrXTw8TixOKz04fWEubGVuZ3RoPUIsYS5oZWFkJiYoYS5oZWFkLmV4dHJhX2xlbj1CKSw1MTImYS5mbGFncyYmNCZhLndyYXAmJih0ZVswXT0yNTUmQix0ZVsxXT1CPj4+OCYyNTUsYS5jaGVjaz1uKGEuY2hlY2ssdGUsMiwwKSksQj0wLE49MH1lbHNlIGEuaGVhZCYmKGEuaGVhZC5leHRyYT1udWxsKTthLm1vZGU9MTYxODU7Y2FzZSAxNjE4NTppZigxMDI0JmEuZmxhZ3MmJigoTD1hLmxlbmd0aCk+ZCYmKEw9ZCksTCYmKGEuaGVhZCYmKEo9YS5oZWFkLmV4dHJhX2xlbi1hLmxlbmd0aCxhLmhlYWQuZXh0cmF8fChhLmhlYWQuZXh0cmE9bmV3IFVpbnQ4QXJyYXkoYS5oZWFkLmV4dHJhX2xlbikpLGEuaGVhZC5leHRyYS5zZXQoby5zdWJhcnJheShsLGwrTCksSikpLDUxMiZhLmZsYWdzJiY0JmEud3JhcCYmKGEuY2hlY2s9bihhLmNoZWNrLG8sTCxsKSksZC09TCxsKz1MLGEubGVuZ3RoLT1MKSxhLmxlbmd0aCkpYnJlYWsgZTthLmxlbmd0aD0wLGEubW9kZT0xNjE4NjtjYXNlIDE2MTg2OmlmKDIwNDgmYS5mbGFncyl7aWYoMD09PWQpYnJlYWsgZTtMPTA7ZG97Sj1vW2wrTCsrXSxhLmhlYWQmJkomJmEubGVuZ3RoPDY1NTM2JiYoYS5oZWFkLm5hbWUrPVN0cmluZy5mcm9tQ2hhckNvZGUoSikpfXdoaWxlKEomJkw8ZCk7aWYoNTEyJmEuZmxhZ3MmJjQmYS53cmFwJiYoYS5jaGVjaz1uKGEuY2hlY2ssbyxMLGwpKSxkLT1MLGwrPUwsSilicmVhayBlfWVsc2UgYS5oZWFkJiYoYS5oZWFkLm5hbWU9bnVsbCk7YS5sZW5ndGg9MCxhLm1vZGU9MTYxODc7Y2FzZSAxNjE4NzppZig0MDk2JmEuZmxhZ3Mpe2lmKDA9PT1kKWJyZWFrIGU7TD0wO2Rve0o9b1tsK0wrK10sYS5oZWFkJiZKJiZhLmxlbmd0aDw2NTUzNiYmKGEuaGVhZC5jb21tZW50Kz1TdHJpbmcuZnJvbUNoYXJDb2RlKEopKX13aGlsZShKJiZMPGQpO2lmKDUxMiZhLmZsYWdzJiY0JmEud3JhcCYmKGEuY2hlY2s9bihhLmNoZWNrLG8sTCxsKSksZC09TCxsKz1MLEopYnJlYWsgZX1lbHNlIGEuaGVhZCYmKGEuaGVhZC5jb21tZW50PW51bGwpO2EubW9kZT0xNjE4ODtjYXNlIDE2MTg4OmlmKDUxMiZhLmZsYWdzKXtmb3IoO048MTY7KXtpZigwPT09ZClicmVhayBlO2QtLSxCKz1vW2wrK108PE4sTis9OH1pZig0JmEud3JhcCYmQiE9PSg2NTUzNSZhLmNoZWNrKSl7ZS5tc2c9ImhlYWRlciBjcmMgbWlzbWF0Y2giLGEubW9kZT1EO2JyZWFrfUI9MCxOPTB9YS5oZWFkJiYoYS5oZWFkLmhjcmM9YS5mbGFncz4+OSYxLGEuaGVhZC5kb25lPSEwKSxlLmFkbGVyPWEuY2hlY2s9MCxhLm1vZGU9QTticmVhaztjYXNlIDE2MTg5OmZvcig7TjwzMjspe2lmKDA9PT1kKWJyZWFrIGU7ZC0tLEIrPW9bbCsrXTw8TixOKz04fWUuYWRsZXI9YS5jaGVjaz1JKEIpLEI9MCxOPTAsYS5tb2RlPVI7Y2FzZSBSOmlmKDA9PT1hLmhhdmVkaWN0KXJldHVybiBlLm5leHRfb3V0PWYsZS5hdmFpbF9vdXQ9YyxlLm5leHRfaW49bCxlLmF2YWlsX2luPWQsYS5ob2xkPUIsYS5iaXRzPU4sXztlLmFkbGVyPWEuY2hlY2s9MSxhLm1vZGU9QTtjYXNlIEE6aWYoaT09PXd8fGk9PT1iKWJyZWFrIGU7Y2FzZSBaOmlmKGEubGFzdCl7Qj4+Pj03Jk4sTi09NyZOLGEubW9kZT1VO2JyZWFrfWZvcig7TjwzOyl7aWYoMD09PWQpYnJlYWsgZTtkLS0sQis9b1tsKytdPDxOLE4rPTh9c3dpdGNoKGEubGFzdD0xJkIsTi09MSwzJihCPj4+PTEpKXtjYXNlIDA6YS5tb2RlPTE2MTkzO2JyZWFrO2Nhc2UgMTppZihLKGEpLGEubW9kZT1ULGk9PT1iKXtCPj4+PTIsTi09MjticmVhayBlfWJyZWFrO2Nhc2UgMjphLm1vZGU9MTYxOTY7YnJlYWs7Y2FzZSAzOmUubXNnPSJpbnZhbGlkIGJsb2NrIHR5cGUiLGEubW9kZT1EfUI+Pj49MixOLT0yO2JyZWFrO2Nhc2UgMTYxOTM6Zm9yKEI+Pj49NyZOLE4tPTcmTjtOPDMyOyl7aWYoMD09PWQpYnJlYWsgZTtkLS0sQis9b1tsKytdPDxOLE4rPTh9aWYoKDY1NTM1JkIpIT0oQj4+PjE2XjY1NTM1KSl7ZS5tc2c9ImludmFsaWQgc3RvcmVkIGJsb2NrIGxlbmd0aHMiLGEubW9kZT1EO2JyZWFrfWlmKGEubGVuZ3RoPTY1NTM1JkIsQj0wLE49MCxhLm1vZGU9UyxpPT09YilicmVhayBlO2Nhc2UgUzphLm1vZGU9MTYxOTU7Y2FzZSAxNjE5NTppZihMPWEubGVuZ3RoKXtpZihMPmQmJihMPWQpLEw+YyYmKEw9YyksMD09PUwpYnJlYWsgZTtzLnNldChvLnN1YmFycmF5KGwsbCtMKSxmKSxkLT1MLGwrPUwsYy09TCxmKz1MLGEubGVuZ3RoLT1MO2JyZWFrfWEubW9kZT1BO2JyZWFrO2Nhc2UgMTYxOTY6Zm9yKDtOPDE0Oyl7aWYoMD09PWQpYnJlYWsgZTtkLS0sQis9b1tsKytdPDxOLE4rPTh9aWYoYS5ubGVuPTI1NysoMzEmQiksQj4+Pj01LE4tPTUsYS5uZGlzdD0xKygzMSZCKSxCPj4+PTUsTi09NSxhLm5jb2RlPTQrKDE1JkIpLEI+Pj49NCxOLT00LGEubmxlbj4yODZ8fGEubmRpc3Q+MzApe2UubXNnPSJ0b28gbWFueSBsZW5ndGggb3IgZGlzdGFuY2Ugc3ltYm9scyIsYS5tb2RlPUQ7YnJlYWt9YS5oYXZlPTAsYS5tb2RlPTE2MTk3O2Nhc2UgMTYxOTc6Zm9yKDthLmhhdmU8YS5uY29kZTspe2Zvcig7TjwzOyl7aWYoMD09PWQpYnJlYWsgZTtkLS0sQis9b1tsKytdPDxOLE4rPTh9YS5sZW5zW2llW2EuaGF2ZSsrXV09NyZCLEI+Pj49MyxOLT0zfWZvcig7YS5oYXZlPDE5OylhLmxlbnNbaWVbYS5oYXZlKytdXT0wO2lmKGEubGVuY29kZT1hLmxlbmR5bixhLmxlbmJpdHM9NyxWPXtiaXRzOmEubGVuYml0c30sUT1oKDAsYS5sZW5zLDAsMTksYS5sZW5jb2RlLDAsYS53b3JrLFYpLGEubGVuYml0cz1WLmJpdHMsUSl7ZS5tc2c9ImludmFsaWQgY29kZSBsZW5ndGhzIHNldCIsYS5tb2RlPUQ7YnJlYWt9YS5oYXZlPTAsYS5tb2RlPTE2MTk4O2Nhc2UgMTYxOTg6Zm9yKDthLmhhdmU8YS5ubGVuK2EubmRpc3Q7KXtmb3IoO1k9KGVlPWEubGVuY29kZVtCJigxPDxhLmxlbmJpdHMpLTFdKT4+PjE2JjI1NSxHPTY1NTM1JmVlLCEoKGo9ZWU+Pj4yNCk8PU4pOyl7aWYoMD09PWQpYnJlYWsgZTtkLS0sQis9b1tsKytdPDxOLE4rPTh9aWYoRzwxNilCPj4+PWosTi09aixhLmxlbnNbYS5oYXZlKytdPUc7ZWxzZXtpZigxNj09PUcpe2ZvcigkPWorMjtOPCQ7KXtpZigwPT09ZClicmVhayBlO2QtLSxCKz1vW2wrK108PE4sTis9OH1pZihCPj4+PWosTi09aiwwPT09YS5oYXZlKXtlLm1zZz0iaW52YWxpZCBiaXQgbGVuZ3RoIHJlcGVhdCIsYS5tb2RlPUQ7YnJlYWt9Sj1hLmxlbnNbYS5oYXZlLTFdLEw9MysoMyZCKSxCPj4+PTIsTi09Mn1lbHNlIGlmKDE3PT09Ryl7Zm9yKCQ9aiszO048JDspe2lmKDA9PT1kKWJyZWFrIGU7ZC0tLEIrPW9bbCsrXTw8TixOKz04fU4tPWosSj0wLEw9MysoNyYoQj4+Pj1qKSksQj4+Pj0zLE4tPTN9ZWxzZXtmb3IoJD1qKzc7TjwkOyl7aWYoMD09PWQpYnJlYWsgZTtkLS0sQis9b1tsKytdPDxOLE4rPTh9Ti09aixKPTAsTD0xMSsoMTI3JihCPj4+PWopKSxCPj4+PTcsTi09N31pZihhLmhhdmUrTD5hLm5sZW4rYS5uZGlzdCl7ZS5tc2c9ImludmFsaWQgYml0IGxlbmd0aCByZXBlYXQiLGEubW9kZT1EO2JyZWFrfWZvcig7TC0tOylhLmxlbnNbYS5oYXZlKytdPUp9fWlmKGEubW9kZT09PUQpYnJlYWs7aWYoMD09PWEubGVuc1syNTZdKXtlLm1zZz0iaW52YWxpZCBjb2RlIC0tIG1pc3NpbmcgZW5kLW9mLWJsb2NrIixhLm1vZGU9RDticmVha31pZihhLmxlbmJpdHM9OSxWPXtiaXRzOmEubGVuYml0c30sUT1oKDEsYS5sZW5zLDAsYS5ubGVuLGEubGVuY29kZSwwLGEud29yayxWKSxhLmxlbmJpdHM9Vi5iaXRzLFEpe2UubXNnPSJpbnZhbGlkIGxpdGVyYWwvbGVuZ3RocyBzZXQiLGEubW9kZT1EO2JyZWFrfWlmKGEuZGlzdGJpdHM9NixhLmRpc3Rjb2RlPWEuZGlzdGR5bixWPXtiaXRzOmEuZGlzdGJpdHN9LFE9aCgyLGEubGVucyxhLm5sZW4sYS5uZGlzdCxhLmRpc3Rjb2RlLDAsYS53b3JrLFYpLGEuZGlzdGJpdHM9Vi5iaXRzLFEpe2UubXNnPSJpbnZhbGlkIGRpc3RhbmNlcyBzZXQiLGEubW9kZT1EO2JyZWFrfWlmKGEubW9kZT1ULGk9PT1iKWJyZWFrIGU7Y2FzZSBUOmEubW9kZT1PO2Nhc2UgTzppZihkPj02JiZjPj0yNTgpe2UubmV4dF9vdXQ9ZixlLmF2YWlsX291dD1jLGUubmV4dF9pbj1sLGUuYXZhaWxfaW49ZCxhLmhvbGQ9QixhLmJpdHM9TixyKGUsRiksZj1lLm5leHRfb3V0LHM9ZS5vdXRwdXQsYz1lLmF2YWlsX291dCxsPWUubmV4dF9pbixvPWUuaW5wdXQsZD1lLmF2YWlsX2luLEI9YS5ob2xkLE49YS5iaXRzLGEubW9kZT09PUEmJihhLmJhY2s9LTEpO2JyZWFrfWZvcihhLmJhY2s9MDtZPShlZT1hLmxlbmNvZGVbQiYoMTw8YS5sZW5iaXRzKS0xXSk+Pj4xNiYyNTUsRz02NTUzNSZlZSwhKChqPWVlPj4+MjQpPD1OKTspe2lmKDA9PT1kKWJyZWFrIGU7ZC0tLEIrPW9bbCsrXTw8TixOKz04fWlmKFkmJjA9PSgyNDAmWSkpe2ZvcihYPWosVz1ZLHE9RztZPShlZT1hLmxlbmNvZGVbcSsoKEImKDE8PFgrVyktMSk+PlgpXSk+Pj4xNiYyNTUsRz02NTUzNSZlZSwhKFgrKGo9ZWU+Pj4yNCk8PU4pOyl7aWYoMD09PWQpYnJlYWsgZTtkLS0sQis9b1tsKytdPDxOLE4rPTh9Qj4+Pj1YLE4tPVgsYS5iYWNrKz1YfWlmKEI+Pj49aixOLT1qLGEuYmFjays9aixhLmxlbmd0aD1HLDA9PT1ZKXthLm1vZGU9MTYyMDU7YnJlYWt9aWYoMzImWSl7YS5iYWNrPS0xLGEubW9kZT1BO2JyZWFrfWlmKDY0Jlkpe2UubXNnPSJpbnZhbGlkIGxpdGVyYWwvbGVuZ3RoIGNvZGUiLGEubW9kZT1EO2JyZWFrfWEuZXh0cmE9MTUmWSxhLm1vZGU9MTYyMDE7Y2FzZSAxNjIwMTppZihhLmV4dHJhKXtmb3IoJD1hLmV4dHJhO048JDspe2lmKDA9PT1kKWJyZWFrIGU7ZC0tLEIrPW9bbCsrXTw8TixOKz04fWEubGVuZ3RoKz1CJigxPDxhLmV4dHJhKS0xLEI+Pj49YS5leHRyYSxOLT1hLmV4dHJhLGEuYmFjays9YS5leHRyYX1hLndhcz1hLmxlbmd0aCxhLm1vZGU9MTYyMDI7Y2FzZSAxNjIwMjpmb3IoO1k9KGVlPWEuZGlzdGNvZGVbQiYoMTw8YS5kaXN0Yml0cyktMV0pPj4+MTYmMjU1LEc9NjU1MzUmZWUsISgoaj1lZT4+PjI0KTw9Tik7KXtpZigwPT09ZClicmVhayBlO2QtLSxCKz1vW2wrK108PE4sTis9OH1pZigwPT0oMjQwJlkpKXtmb3IoWD1qLFc9WSxxPUc7WT0oZWU9YS5kaXN0Y29kZVtxKygoQiYoMTw8WCtXKS0xKT4+WCldKT4+PjE2JjI1NSxHPTY1NTM1JmVlLCEoWCsoaj1lZT4+PjI0KTw9Tik7KXtpZigwPT09ZClicmVhayBlO2QtLSxCKz1vW2wrK108PE4sTis9OH1CPj4+PVgsTi09WCxhLmJhY2srPVh9aWYoQj4+Pj1qLE4tPWosYS5iYWNrKz1qLDY0Jlkpe2UubXNnPSJpbnZhbGlkIGRpc3RhbmNlIGNvZGUiLGEubW9kZT1EO2JyZWFrfWEub2Zmc2V0PUcsYS5leHRyYT0xNSZZLGEubW9kZT0xNjIwMztjYXNlIDE2MjAzOmlmKGEuZXh0cmEpe2ZvcigkPWEuZXh0cmE7TjwkOyl7aWYoMD09PWQpYnJlYWsgZTtkLS0sQis9b1tsKytdPDxOLE4rPTh9YS5vZmZzZXQrPUImKDE8PGEuZXh0cmEpLTEsQj4+Pj1hLmV4dHJhLE4tPWEuZXh0cmEsYS5iYWNrKz1hLmV4dHJhfWlmKGEub2Zmc2V0PmEuZG1heCl7ZS5tc2c9ImludmFsaWQgZGlzdGFuY2UgdG9vIGZhciBiYWNrIixhLm1vZGU9RDticmVha31hLm1vZGU9MTYyMDQ7Y2FzZSAxNjIwNDppZigwPT09YylicmVhayBlO2lmKEw9Ri1jLGEub2Zmc2V0Pkwpe2lmKChMPWEub2Zmc2V0LUwpPmEud2hhdmUmJmEuc2FuZSl7ZS5tc2c9ImludmFsaWQgZGlzdGFuY2UgdG9vIGZhciBiYWNrIixhLm1vZGU9RDticmVha31MPmEud25leHQ/KEwtPWEud25leHQsTT1hLndzaXplLUwpOk09YS53bmV4dC1MLEw+YS5sZW5ndGgmJihMPWEubGVuZ3RoKSxIPWEud2luZG93fWVsc2UgSD1zLE09Zi1hLm9mZnNldCxMPWEubGVuZ3RoO0w+YyYmKEw9YyksYy09TCxhLmxlbmd0aC09TDtkb3tzW2YrK109SFtNKytdfXdoaWxlKC0tTCk7MD09PWEubGVuZ3RoJiYoYS5tb2RlPU8pO2JyZWFrO2Nhc2UgMTYyMDU6aWYoMD09PWMpYnJlYWsgZTtzW2YrK109YS5sZW5ndGgsYy0tLGEubW9kZT1PO2JyZWFrO2Nhc2UgVTppZihhLndyYXApe2Zvcig7TjwzMjspe2lmKDA9PT1kKWJyZWFrIGU7ZC0tLEJ8PW9bbCsrXTw8TixOKz04fWlmKEYtPWMsZS50b3RhbF9vdXQrPUYsYS50b3RhbCs9Riw0JmEud3JhcCYmRiYmKGUuYWRsZXI9YS5jaGVjaz1hLmZsYWdzP24oYS5jaGVjayxzLEYsZi1GKTp0KGEuY2hlY2sscyxGLGYtRikpLEY9Yyw0JmEud3JhcCYmKGEuZmxhZ3M/QjpJKEIpKSE9PWEuY2hlY2spe2UubXNnPSJpbmNvcnJlY3QgZGF0YSBjaGVjayIsYS5tb2RlPUQ7YnJlYWt9Qj0wLE49MH1hLm1vZGU9MTYyMDc7Y2FzZSAxNjIwNzppZihhLndyYXAmJmEuZmxhZ3Mpe2Zvcig7TjwzMjspe2lmKDA9PT1kKWJyZWFrIGU7ZC0tLEIrPW9bbCsrXTw8TixOKz04fWlmKDQmYS53cmFwJiZCIT09KDQyOTQ5NjcyOTUmYS50b3RhbCkpe2UubXNnPSJpbmNvcnJlY3QgbGVuZ3RoIGNoZWNrIixhLm1vZGU9RDticmVha31CPTAsTj0wfWEubW9kZT0xNjIwODtjYXNlIDE2MjA4OlE9azticmVhayBlO2Nhc2UgRDpRPWc7YnJlYWsgZTtjYXNlIDE2MjEwOnJldHVybiBwO2RlZmF1bHQ6cmV0dXJuIHZ9cmV0dXJuIGUubmV4dF9vdXQ9ZixlLmF2YWlsX291dD1jLGUubmV4dF9pbj1sLGUuYXZhaWxfaW49ZCxhLmhvbGQ9QixhLmJpdHM9TiwoYS53c2l6ZXx8RiE9PWUuYXZhaWxfb3V0JiZhLm1vZGU8RCYmKGEubW9kZTxVfHxpIT09dSkpJiZQKGUsZS5vdXRwdXQsZS5uZXh0X291dCxGLWUuYXZhaWxfb3V0KSxDLT1lLmF2YWlsX2luLEYtPWUuYXZhaWxfb3V0LGUudG90YWxfaW4rPUMsZS50b3RhbF9vdXQrPUYsYS50b3RhbCs9Riw0JmEud3JhcCYmRiYmKGUuYWRsZXI9YS5jaGVjaz1hLmZsYWdzP24oYS5jaGVjayxzLEYsZS5uZXh0X291dC1GKTp0KGEuY2hlY2sscyxGLGUubmV4dF9vdXQtRikpLGUuZGF0YV90eXBlPWEuYml0cysoYS5sYXN0PzY0OjApKyhhLm1vZGU9PT1BPzEyODowKSsoYS5tb2RlPT09VHx8YS5tb2RlPT09Uz8yNTY6MCksKDA9PT1DJiYwPT09Rnx8aT09PXUpJiZRPT09bSYmKFE9eSksUX0saW5mbGF0ZUVuZDpmdW5jdGlvbihlKXtpZih6KGUpKXJldHVybiB2O3ZhciB0PWUuc3RhdGU7cmV0dXJuIHQud2luZG93JiYodC53aW5kb3c9bnVsbCksZS5zdGF0ZT1udWxsLG19LGluZmxhdGVHZXRIZWFkZXI6ZnVuY3Rpb24oZSx0KXtpZih6KGUpKXJldHVybiB2O3ZhciBpPWUuc3RhdGU7cmV0dXJuIDA9PSgyJmkud3JhcCk/djooaS5oZWFkPXQsdC5kb25lPSExLG0pfSxpbmZsYXRlU2V0RGljdGlvbmFyeTpmdW5jdGlvbihlLGkpe3ZhciBuLGE9aS5sZW5ndGg7cmV0dXJuIHooZSl8fDAhPT0obj1lLnN0YXRlKS53cmFwJiZuLm1vZGUhPT1SP3Y6bi5tb2RlPT09UiYmdCgxLGksYSwwKSE9PW4uY2hlY2s/ZzpQKGUsaSxhLGEpPyhuLm1vZGU9MTYyMTAscCk6KG4uaGF2ZWRpY3Q9MSxtKX0saW5mbGF0ZUluZm86InBha28gaW5mbGF0ZSAoZnJvbSBOb2RlY2EgcHJvamVjdCkifTtmdW5jdGlvbiBHKGUpe3JldHVybiBHPSJmdW5jdGlvbiI9PXR5cGVvZiBTeW1ib2wmJiJzeW1ib2wiPT10eXBlb2YgU3ltYm9sLml0ZXJhdG9yP2Z1bmN0aW9uKGUpe3JldHVybiB0eXBlb2YgZX06ZnVuY3Rpb24oZSl7cmV0dXJuIGUmJiJmdW5jdGlvbiI9PXR5cGVvZiBTeW1ib2wmJmUuY29uc3RydWN0b3I9PT1TeW1ib2wmJmUhPT1TeW1ib2wucHJvdG90eXBlPyJzeW1ib2wiOnR5cGVvZiBlfSxHKGUpfXZhciBYPWZ1bmN0aW9uKGUsdCl7cmV0dXJuIE9iamVjdC5wcm90b3R5cGUuaGFzT3duUHJvcGVydHkuY2FsbChlLHQpfSxXPWZ1bmN0aW9uKGUpe2Zvcih2YXIgdD1BcnJheS5wcm90b3R5cGUuc2xpY2UuY2FsbChhcmd1bWVudHMsMSk7dC5sZW5ndGg7KXt2YXIgaT10LnNoaWZ0KCk7aWYoaSl7aWYoIm9iamVjdCIhPT1HKGkpKXRocm93IG5ldyBUeXBlRXJyb3IoaSsibXVzdCBiZSBub24tb2JqZWN0Iik7Zm9yKHZhciBuIGluIGkpWChpLG4pJiYoZVtuXT1pW25dKX19cmV0dXJuIGV9LHE9ZnVuY3Rpb24oZSl7Zm9yKHZhciB0PTAsaT0wLG49ZS5sZW5ndGg7aTxuO2krKyl0Kz1lW2ldLmxlbmd0aDtmb3IodmFyIGE9bmV3IFVpbnQ4QXJyYXkodCkscj0wLG89MCxzPWUubGVuZ3RoO3I8cztyKyspe3ZhciBsPWVbcl07YS5zZXQobCxvKSxvKz1sLmxlbmd0aH1yZXR1cm4gYX0sSj0hMDt0cnl7U3RyaW5nLmZyb21DaGFyQ29kZS5hcHBseShudWxsLG5ldyBVaW50OEFycmF5KDEpKX1jYXRjaChlKXtKPSExfWZvcih2YXIgUT1uZXcgVWludDhBcnJheSgyNTYpLFY9MDtWPDI1NjtWKyspUVtWXT1WPj0yNTI/NjpWPj0yNDg/NTpWPj0yNDA/NDpWPj0yMjQ/MzpWPj0xOTI/MjoxO1FbMjU0XT1RWzI1NF09MTt2YXIgJD1mdW5jdGlvbihlKXtpZigiZnVuY3Rpb24iPT10eXBlb2YgVGV4dEVuY29kZXImJlRleHRFbmNvZGVyLnByb3RvdHlwZS5lbmNvZGUpcmV0dXJuKG5ldyBUZXh0RW5jb2RlcikuZW5jb2RlKGUpO3ZhciB0LGksbixhLHIsbz1lLmxlbmd0aCxzPTA7Zm9yKGE9MDthPG87YSsrKTU1Mjk2PT0oNjQ1MTImKGk9ZS5jaGFyQ29kZUF0KGEpKSkmJmErMTxvJiY1NjMyMD09KDY0NTEyJihuPWUuY2hhckNvZGVBdChhKzEpKSkmJihpPTY1NTM2KyhpLTU1Mjk2PDwxMCkrKG4tNTYzMjApLGErKykscys9aTwxMjg/MTppPDIwNDg/MjppPDY1NTM2PzM6NDtmb3IodD1uZXcgVWludDhBcnJheShzKSxyPTAsYT0wO3I8czthKyspNTUyOTY9PSg2NDUxMiYoaT1lLmNoYXJDb2RlQXQoYSkpKSYmYSsxPG8mJjU2MzIwPT0oNjQ1MTImKG49ZS5jaGFyQ29kZUF0KGErMSkpKSYmKGk9NjU1MzYrKGktNTUyOTY8PDEwKSsobi01NjMyMCksYSsrKSxpPDEyOD90W3IrK109aTppPDIwNDg/KHRbcisrXT0xOTJ8aT4+PjYsdFtyKytdPTEyOHw2MyZpKTppPDY1NTM2Pyh0W3IrK109MjI0fGk+Pj4xMix0W3IrK109MTI4fGk+Pj42JjYzLHRbcisrXT0xMjh8NjMmaSk6KHRbcisrXT0yNDB8aT4+PjE4LHRbcisrXT0xMjh8aT4+PjEyJjYzLHRbcisrXT0xMjh8aT4+PjYmNjMsdFtyKytdPTEyOHw2MyZpKTtyZXR1cm4gdH0sZWU9ZnVuY3Rpb24oZSx0KXt2YXIgaSxuLGE9dHx8ZS5sZW5ndGg7aWYoImZ1bmN0aW9uIj09dHlwZW9mIFRleHREZWNvZGVyJiZUZXh0RGVjb2Rlci5wcm90b3R5cGUuZGVjb2RlKXJldHVybihuZXcgVGV4dERlY29kZXIpLmRlY29kZShlLnN1YmFycmF5KDAsdCkpO3ZhciByPW5ldyBBcnJheSgyKmEpO2ZvcihuPTAsaT0wO2k8YTspe3ZhciBvPWVbaSsrXTtpZihvPDEyOClyW24rK109bztlbHNle3ZhciBzPVFbb107aWYocz40KXJbbisrXT02NTUzMyxpKz1zLTE7ZWxzZXtmb3IobyY9Mj09PXM/MzE6Mz09PXM/MTU6NztzPjEmJmk8YTspbz1vPDw2fDYzJmVbaSsrXSxzLS07cz4xP3JbbisrXT02NTUzMzpvPDY1NTM2P3JbbisrXT1vOihvLT02NTUzNixyW24rK109NTUyOTZ8bz4+MTAmMTAyMyxyW24rK109NTYzMjB8MTAyMyZvKX19fXJldHVybiBmdW5jdGlvbihlLHQpe2lmKHQ8NjU1MzQmJmUuc3ViYXJyYXkmJkopcmV0dXJuIFN0cmluZy5mcm9tQ2hhckNvZGUuYXBwbHkobnVsbCxlLmxlbmd0aD09PXQ/ZTplLnN1YmFycmF5KDAsdCkpO2Zvcih2YXIgaT0iIixuPTA7bjx0O24rKylpKz1TdHJpbmcuZnJvbUNoYXJDb2RlKGVbbl0pO3JldHVybiBpfShyLG4pfSx0ZT1mdW5jdGlvbihlLHQpeyh0PXR8fGUubGVuZ3RoKT5lLmxlbmd0aCYmKHQ9ZS5sZW5ndGgpO2Zvcih2YXIgaT10LTE7aT49MCYmMTI4PT0oMTkyJmVbaV0pOylpLS07cmV0dXJuIGk8MHx8MD09PWk/dDppK1FbZVtpXV0+dD9pOnR9LGllPXsyOiJuZWVkIGRpY3Rpb25hcnkiLDE6InN0cmVhbSBlbmQiLDA6IiIsIi0xIjoiZmlsZSBlcnJvciIsIi0yIjoic3RyZWFtIGVycm9yIiwiLTMiOiJkYXRhIGVycm9yIiwiLTQiOiJpbnN1ZmZpY2llbnQgbWVtb3J5IiwiLTUiOiJidWZmZXIgZXJyb3IiLCItNiI6ImluY29tcGF0aWJsZSB2ZXJzaW9uIn07dmFyIG5lPWZ1bmN0aW9uKCl7dGhpcy5pbnB1dD1udWxsLHRoaXMubmV4dF9pbj0wLHRoaXMuYXZhaWxfaW49MCx0aGlzLnRvdGFsX2luPTAsdGhpcy5vdXRwdXQ9bnVsbCx0aGlzLm5leHRfb3V0PTAsdGhpcy5hdmFpbF9vdXQ9MCx0aGlzLnRvdGFsX291dD0wLHRoaXMubXNnPSIiLHRoaXMuc3RhdGU9bnVsbCx0aGlzLmRhdGFfdHlwZT0yLHRoaXMuYWRsZXI9MH07dmFyIGFlPWZ1bmN0aW9uKCl7dGhpcy50ZXh0PTAsdGhpcy50aW1lPTAsdGhpcy54ZmxhZ3M9MCx0aGlzLm9zPTAsdGhpcy5leHRyYT1udWxsLHRoaXMuZXh0cmFfbGVuPTAsdGhpcy5uYW1lPSIiLHRoaXMuY29tbWVudD0iIix0aGlzLmhjcmM9MCx0aGlzLmRvbmU9ITF9LHJlPU9iamVjdC5wcm90b3R5cGUudG9TdHJpbmcsb2U9Yy5aX05PX0ZMVVNILHNlPWMuWl9GSU5JU0gsbGU9Yy5aX09LLGZlPWMuWl9TVFJFQU1fRU5ELGRlPWMuWl9ORUVEX0RJQ1QsaGU9Yy5aX1NUUkVBTV9FUlJPUixjZT1jLlpfREFUQV9FUlJPUix1ZT1jLlpfTUVNX0VSUk9SO2Z1bmN0aW9uIHdlKGUpe3RoaXMub3B0aW9ucz1XKHtjaHVua1NpemU6NjU1MzYsd2luZG93Qml0czoxNSx0bzoiIn0sZXx8e30pO3ZhciB0PXRoaXMub3B0aW9uczt0LnJhdyYmdC53aW5kb3dCaXRzPj0wJiZ0LndpbmRvd0JpdHM8MTYmJih0LndpbmRvd0JpdHM9LXQud2luZG93Qml0cywwPT09dC53aW5kb3dCaXRzJiYodC53aW5kb3dCaXRzPS0xNSkpLCEodC53aW5kb3dCaXRzPj0wJiZ0LndpbmRvd0JpdHM8MTYpfHxlJiZlLndpbmRvd0JpdHN8fCh0LndpbmRvd0JpdHMrPTMyKSx0LndpbmRvd0JpdHM+MTUmJnQud2luZG93Qml0czw0OCYmMD09KDE1JnQud2luZG93Qml0cykmJih0LndpbmRvd0JpdHN8PTE1KSx0aGlzLmVycj0wLHRoaXMubXNnPSIiLHRoaXMuZW5kZWQ9ITEsdGhpcy5jaHVua3M9W10sdGhpcy5zdHJtPW5ldyBuZSx0aGlzLnN0cm0uYXZhaWxfb3V0PTA7dmFyIGk9WS5pbmZsYXRlSW5pdDIodGhpcy5zdHJtLHQud2luZG93Qml0cyk7aWYoaSE9PWxlKXRocm93IG5ldyBFcnJvcihpZVtpXSk7aWYodGhpcy5oZWFkZXI9bmV3IGFlLFkuaW5mbGF0ZUdldEhlYWRlcih0aGlzLnN0cm0sdGhpcy5oZWFkZXIpLHQuZGljdGlvbmFyeSYmKCJzdHJpbmciPT10eXBlb2YgdC5kaWN0aW9uYXJ5P3QuZGljdGlvbmFyeT0kKHQuZGljdGlvbmFyeSk6IltvYmplY3QgQXJyYXlCdWZmZXJdIj09PXJlLmNhbGwodC5kaWN0aW9uYXJ5KSYmKHQuZGljdGlvbmFyeT1uZXcgVWludDhBcnJheSh0LmRpY3Rpb25hcnkpKSx0LnJhdyYmKGk9WS5pbmZsYXRlU2V0RGljdGlvbmFyeSh0aGlzLnN0cm0sdC5kaWN0aW9uYXJ5KSkhPT1sZSkpdGhyb3cgbmV3IEVycm9yKGllW2ldKX1mdW5jdGlvbiBiZShlLHQpe3ZhciBpPW5ldyB3ZSh0KTtpZihpLnB1c2goZSksaS5lcnIpdGhyb3cgaS5tc2d8fGllW2kuZXJyXTtyZXR1cm4gaS5yZXN1bHR9d2UucHJvdG90eXBlLnB1c2g9ZnVuY3Rpb24oZSx0KXt2YXIgaSxuLGEscj10aGlzLnN0cm0sbz10aGlzLm9wdGlvbnMuY2h1bmtTaXplLHM9dGhpcy5vcHRpb25zLmRpY3Rpb25hcnk7aWYodGhpcy5lbmRlZClyZXR1cm4hMTtmb3Iobj10PT09fn50P3Q6ITA9PT10P3NlOm9lLCJbb2JqZWN0IEFycmF5QnVmZmVyXSI9PT1yZS5jYWxsKGUpP3IuaW5wdXQ9bmV3IFVpbnQ4QXJyYXkoZSk6ci5pbnB1dD1lLHIubmV4dF9pbj0wLHIuYXZhaWxfaW49ci5pbnB1dC5sZW5ndGg7Oyl7Zm9yKDA9PT1yLmF2YWlsX291dCYmKHIub3V0cHV0PW5ldyBVaW50OEFycmF5KG8pLHIubmV4dF9vdXQ9MCxyLmF2YWlsX291dD1vKSwoaT1ZLmluZmxhdGUocixuKSk9PT1kZSYmcyYmKChpPVkuaW5mbGF0ZVNldERpY3Rpb25hcnkocixzKSk9PT1sZT9pPVkuaW5mbGF0ZShyLG4pOmk9PT1jZSYmKGk9ZGUpKTtyLmF2YWlsX2luPjAmJmk9PT1mZSYmci5zdGF0ZS53cmFwPjAmJjAhPT1lW3IubmV4dF9pbl07KVkuaW5mbGF0ZVJlc2V0KHIpLGk9WS5pbmZsYXRlKHIsbik7c3dpdGNoKGkpe2Nhc2UgaGU6Y2FzZSBjZTpjYXNlIGRlOmNhc2UgdWU6cmV0dXJuIHRoaXMub25FbmQoaSksdGhpcy5lbmRlZD0hMCwhMX1pZihhPXIuYXZhaWxfb3V0LHIubmV4dF9vdXQmJigwPT09ci5hdmFpbF9vdXR8fGk9PT1mZSkpaWYoInN0cmluZyI9PT10aGlzLm9wdGlvbnMudG8pe3ZhciBsPXRlKHIub3V0cHV0LHIubmV4dF9vdXQpLGY9ci5uZXh0X291dC1sLGQ9ZWUoci5vdXRwdXQsbCk7ci5uZXh0X291dD1mLHIuYXZhaWxfb3V0PW8tZixmJiZyLm91dHB1dC5zZXQoci5vdXRwdXQuc3ViYXJyYXkobCxsK2YpLDApLHRoaXMub25EYXRhKGQpfWVsc2UgdGhpcy5vbkRhdGEoci5vdXRwdXQubGVuZ3RoPT09ci5uZXh0X291dD9yLm91dHB1dDpyLm91dHB1dC5zdWJhcnJheSgwLHIubmV4dF9vdXQpKTtpZihpIT09bGV8fDAhPT1hKXtpZihpPT09ZmUpcmV0dXJuIGk9WS5pbmZsYXRlRW5kKHRoaXMuc3RybSksdGhpcy5vbkVuZChpKSx0aGlzLmVuZGVkPSEwLCEwO2lmKDA9PT1yLmF2YWlsX2luKWJyZWFrfX1yZXR1cm4hMH0sd2UucHJvdG90eXBlLm9uRGF0YT1mdW5jdGlvbihlKXt0aGlzLmNodW5rcy5wdXNoKGUpfSx3ZS5wcm90b3R5cGUub25FbmQ9ZnVuY3Rpb24oZSl7ZT09PWxlJiYoInN0cmluZyI9PT10aGlzLm9wdGlvbnMudG8/dGhpcy5yZXN1bHQ9dGhpcy5jaHVua3Muam9pbigiIik6dGhpcy5yZXN1bHQ9cSh0aGlzLmNodW5rcykpLHRoaXMuY2h1bmtzPVtdLHRoaXMuZXJyPWUsdGhpcy5tc2c9dGhpcy5zdHJtLm1zZ307dmFyIG1lPXdlLGtlPWJlLF9lPWZ1bmN0aW9uKGUsdCl7cmV0dXJuKHQ9dHx8e30pLnJhdz0hMCxiZShlLHQpfSx2ZT1iZSxnZT1jLHBlPXtJbmZsYXRlOm1lLGluZmxhdGU6a2UsaW5mbGF0ZVJhdzpfZSx1bmd6aXA6dmUsY29uc3RhbnRzOmdlfTtlLkluZmxhdGU9bWUsZS5jb25zdGFudHM9Z2UsZS5kZWZhdWx0PXBlLGUuaW5mbGF0ZT1rZSxlLmluZmxhdGVSYXc9X2UsZS51bmd6aXA9dmUsT2JqZWN0LmRlZmluZVByb3BlcnR5KGUsIl9fZXNNb2R1bGUiLHt2YWx1ZTohMH0pfSkpOwphZGRFdmVudExpc3RlbmVyKCJtZXNzYWdlIiwgZnVuY3Rpb24obykgeyB0cnkgeyBwb3N0TWVzc2FnZSh7IHN0YXR1czogInN1Y2Nlc3MiLCBkYXRhOiBwYWtvLmluZmxhdGUoby5kYXRhLCB7IHRvOiAiYXJyYXlidWZmZXIiIH0pIH0pOyB9IGNhdGNoKGV4KSB7IGxvZ2dlci5lcnJvcihleCk7IHBvc3RNZXNzYWdlKHsgc3RhdHVzOiAiZXJyb3IiIH0pOyB9IH0pOwpwb3N0TWVzc2FnZSh7IHN0YXR1czogInJlYWR5IiB9KTs=";
+			if(soSupported) {
+				theWorkerObj = new Worker(URL.createObjectURL(new Blob([base64js.toByteArray(workerSrc).buffer], { type: "text/javascript" })));
+			}else {
+				theWorkerObj = new Worker("data:text/javascript;base64," + workerSrc);
+			}
+			theWorkerObj.addEventListener("message", function(evt) {
+				if(evt.data.status === "ready") {
+					decodeBase64URL(window.eaglercraftXClientBundle, function(cbData) {
+						if(cbData) {
+							theWorkerObj.postMessage(cbData);
+						}else {
+							alert("Failed to decode eaglercraftXClientBundle base64!");
+						}
+					});
+				}else if(evt.data.status === "success") {
+					if(soSupported) {
+						window.clientScriptSrcURL = URL.createObjectURL(new Blob([evt.data.data.buffer], { type: "text/javascript;charset=utf-8" }));
+					}else {
+						window.clientScriptSrcURL = "data:text/javascript;charset=utf-8;base64," + base64js.fromByteArray(evt.data.data);
+					}
+				}else {
+					alert("Failed to decompress classes.js via legacy javascript implementation!");
+				}
+			});
+			theWorkerObj.addEventListener("error", function(evt) {
+				console.error(evt.error);
+			});
+		});
+	}else {
+		var ds = new window.DecompressionStream("gzip");
+		var result = [];
+		var fetchStream = function(reader) {
+			var processData;
+			reader.read().then(processData = function(evt) {
+				if (evt.done) {
+					(function(blobObj){
+						checkSameOriginSupport(function(supported) {
+							if(supported) {
+								window.clientScriptSrcURL = URL.createObjectURL(blobObj);
+							}else {
+								blobToArrayBuffer(blobObj, function(arr) {
+									console.log(arr);
+									window.clientScriptSrcURL = "data:text/javascript;charset=utf-8;base64," + base64js.fromByteArray(new Uint8Array(arr));
+								});
+							}
+						});
+					})(new Blob(result, { type: "text/javascript;charset=utf-8" }));
+					result = [];
+					ds = null;
+					return;
+				}
+				result.push(evt.value);
+				return reader.read().then(processData);
+			});
+		};
+		decodeBase64URL(window.eaglercraftXClientBundle, function(cbData) {
+			if(cbData) {
+				fetchStream((new Blob([cbData])).stream().pipeThrough(ds).getReader());
+			}else {
+				alert("Failed to decode eaglercraftXClientBundle base64!");
+			}
+		});
+	}
+})();
+</script>
+<script type="text/javascript">
+"use strict";
+(function(){
+	var launchInterval = -1;
+	var launchCounter = 1;
+	var launchCountdownNumberElement = null;
+	var launchCountdownProgressElement = null;
+	var launchSkipCountdown = false;
+	var launchTick = function() {
+		if(launchCounter > 100 || launchSkipCountdown) {
+			if(window.clientScriptSrcURL) {
+				clearInterval(launchInterval);
+				setTimeout(function() {
+					document.body.removeChild(document.getElementById("launch_countdown_screen"));
+					document.body.style.backgroundColor = "black";
+					var script = document.createElement("script");
+					script.type = "text/javascript";
+					script.src = window.clientScriptSrcURL;
+					window.clientScriptSrcURL = null;
+					document.head.appendChild(script);
+				}, 50);
+			}
+			return;
+		}
+		if(launchCounter === 100) {
+			document.getElementById("gameWillLaunchIn").innerText = "Decompressing...";
+		}else {
+			launchCountdownNumberElement.innerText = "" + Math.floor(6.0 - launchCounter * 0.06);
+		}
+		launchCountdownProgressElement.style.width = "" + launchCounter + "%";
+		++launchCounter;
+	};
+	window.addEventListener("load", function() {
+		launchCountdownNumberElement = document.getElementById("launchCountdownNumber");
+		launchCountdownProgressElement = document.getElementById("launchCountdownProgress");
+		launchInterval = setInterval(launchTick, 50);
+		document.getElementById("skipCountdown").addEventListener("click", function() {
+			launchSkipCountdown = true;
+			document.getElementById("gameWillLaunchIn").innerText = "Decompressing...";
+		});
+		document.getElementById("bootMenu").addEventListener("click", function() {
+			launchSkipCountdown = true;
+			document.getElementById("gameWillLaunchIn").innerText = "Decompressing...";
+			window.eaglercraftXOptsHints.showBootMenuOnLaunch = true;
+		});
+	});
+})();
+</script>
+<link type="image/png" rel="shortcut icon" href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAIAAAD8GO2jAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAAFiUAABYlAUlSJPAAAAR/SURBVEhLtZXZK3ZRFMYPcqXc+gv413DHxVuGIpIhkciQWaRccCNjSCkligwXSOZ5nmfv9zvn2e8+58V753sudmuvvdZ61l5r7XOc8H+GS/D19aUNkPz5+aktQH5/f//4+LBKZKuRkpUtQjCUYG5gD2T38vLy/PwsDfL9/f3Dw8PT05M0b29vnKLhCKCBT4L4gvBLBIei4//4+Hh1dUVEQutUuLu7E83FxQUGnKLBWKfQaA3S+AREVxaEOD8/Pzk50XpzcyMDcH19zdZG3N3d3dzc3Nvb01aX5pQUpQGGQJxcQpfNysoKhUIdHR1o1tbWbInYAgxIPDMzMy8vLzc3FxqOdMoRqwJK8G8ALUYIhHMiSEhIwI6CyIb0qQzC4eGhsXCc1tZWnZIEKzdQJQSXgKxfX18RCM3Z5eWlcfVAxKOjo+Pj49PTU88lTOk2NjbMsePc3t6SAfcgFdszOyMuAdeBg0CQi2lhYUHOeOLDCisN8FzcPFZXV3t7ezHY3t5GQ+6it+2xMASsKhEEWKsmRLRBBUpPvpJ/TpFKFBwKYAiITmicsbYhdHfJAltqhUCVsCQhwslmeXmZxiBQT9c0Ar9E2O3v72sYSE0N1yQArkKy0kBMXLqlZqIZHR3t6empqqqSDcBdhXEJSJ/bUc3q6uq+vj629GB9fR1WsLW1NTs7u7S0RN2locMjIyOEm5ubQ7+4uJienk4/+vv77Y1hwhLBEKhwWHitdVFfX9/Y2Gg2HuLi4owUAysrK8yCG97rh0+ApP5Q2ZycHFlPTExUVFRIBvn5+WhKSkp2dnaMKhptbW2426GgQ/rwuAQCZ1hwFayLiork9hMFBQV1dXVmE0BLS4vqw3QFB8kn4IAxoGPkYpxi4FeDmpqas7Mz4pClAgqGwD48rjY2NmacYqC0tJQ1KSlJWyE5OZkpUKkBAxZVIntAoZh04+Q48fHxPNGBgYHExMT29naj9cBodnZ2mo3jlJWVMeW2OGQck4B1amqqoaGhqamJjx2lGxwcpL0mUgR8fJhsWqJtSkoKU2SbHHUDpkhPBujd8xuQG6PJRM/Pz09PT7O1NNnZ2Tw3fgZkXVhYKCUlUhBATP+hCVyKZGky17RV0g04laayslJ6hlVeFHB4eFhKaogGd0LxtmTgE+hbhKDnPjMzgw8E3qGL2tpaBWpubjYqj2BoaEj6rq4uNATRZ0ZwCbiL6gXEzINk5vCBQJ9rMD4+rkA8QNK036uDg4Py8vLu7m680KjIBNR3zBDoWQM1g98snyB+VSoRW8C/UwR81/SvhgNj9JOTkwwVERUdRBEI0BAdLRVERkhLS8vIyEDQlrsTPTU1lVFhKxARvZgUlFLbegCf4BvIsbi4mIg4E5EogIHhiKCMtU0WUFiVy06j5fAJIDdSBDQw+PegDfBRcbOPwH4F9LuFWIIQdQNKwWqzIE0aoFUaBsw+SQuFw0uNtC9A+F4i3QNrbg3IDn+SAsHh+wYiEpeyBEMLv/cAO6KzAijxxB+Y4wisBhssJUhjEbPJf4Nw+B+JXqLW3bw+wQAAAABJRU5ErkJggg==" />
+${fat_offline_data}
+</head>
+<body style="margin:0px;width:100%;height:100%;overflow:hidden;background-color:white;" id="game_frame">
+<div style="margin:0px;width:100%;height:100%;font-family:sans-serif;display:flex;align-items:center;user-select:none;" id="launch_countdown_screen">
+<div style="margin:auto;text-align:center;">
+<h1>EaglercraftX 1.8 "Fat Offline"</h1>
+<h3>Contains: ${num_clients} Client(s)</h3>
+<h2 id="gameWillLaunchIn">Game will launch in <span id="launchCountdownNumber">5</span>...</h2>
+<div style="border:2px solid black;width:100%;height:15px;padding:1px;margin-bottom:20vh;"><div id="launchCountdownProgress" style="background-color:#555555;width:0%;height:100%;"></div>
+<p style="margin-top:30px;"><button id="skipCountdown" autofocus>Skip Countdown</button></p></div>
+</div>
+</div>
+</body>
+</html>
diff --git a/sources/resources/assets/eagler/boot_menu/offline_template_eaglercraftX_1_8_signed.html b/sources/resources/assets/eagler/boot_menu/offline_template_eaglercraftX_1_8_signed.html
new file mode 100644
index 00000000..ab884730
--- /dev/null
+++ b/sources/resources/assets/eagler/boot_menu/offline_template_eaglercraftX_1_8_signed.html
@@ -0,0 +1,267 @@
+<!DOCTYPE html>
+
+<!--
+
+This file is from ${date}, it was generated using EaglercraftX 1.8 boot manager
+
+Signature: ${signature_details}
+
+-->
+
+<html style="width:100%;height:100%;background-color:black;">
+<head>
+<meta charset="UTF-8" />
+<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0" />
+<meta name="description" content="${client_name}" />
+<meta name="keywords" content="eaglercraft, eaglercraftx, minecraft, 1.8, 1.8.8" />
+<title>${client_name}</title>
+<meta property="og:locale" content="en-US" />
+<meta property="og:type" content="website" />
+<meta property="og:title" content="${client_name}" />
+<meta property="og:description" content="Play minecraft 1.8 in your browser" />
+<style type="eaglercraftOfflineParseHint">{"type":"EAGLERCRAFTX_1_8_SIGNED","launchConf":${launch_conf_json}}</style>
+<script type="text/javascript">
+"use strict";
+var relayIdMax = ${relayId_max};
+var relayId = relayIdMax > 1 ? Math.floor(Math.random() * relayIdMax) : 0;
+
+// %%%%%%%%% launch options %%%%%%%%%%%%
+
+window.eaglercraftXOptsHints = ${launch_opts};
+window.eaglercraftXOptsHints.hintsVersion = 1;
+window.eaglercraftXOptsHints.container = "game_frame";
+
+// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+</script>
+<style type="eaglercraft" id="eaglercraftXClientSignature">data:application/octet-stream;base64,${client_signature}</style>
+<style type="eaglercraft" id="eaglercraftXClientBundle">data:application/octet-stream;base64,${client_bundle}</style>
+<script type="text/javascript">
+"use strict";
+(function(){
+	function eaglerBundleUnwrap(tagIn) { var e = document.getElementById(tagIn); var ret = e.innerText; document.head.removeChild(e); return ret;  }
+	window.eaglercraftXClientSignature = eaglerBundleUnwrap("eaglercraftXClientSignature");
+	window.eaglercraftXClientBundle = eaglerBundleUnwrap("eaglercraftXClientBundle");
+})();
+</script>
+<script type="text/javascript">
+"use strict";
+(function(){
+	(function(a){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=a();else if("function"==typeof define&&define.amd)define([],a);else{var b;b="undefined"==typeof window?"undefined"==typeof global?"undefined"==typeof self?this:self:global:window,b.base64js=a()}})(function(){return function(){function b(d,e,g){function a(j,i){if(!e[j]){if(!d[j]){var f="function"==typeof require&&require;if(!i&&f)return f(j,!0);if(h)return h(j,!0);var c=new Error("Cannot find module '"+j+"'");throw c.code="MODULE_NOT_FOUND",c}var k=e[j]={exports:{}};d[j][0].call(k.exports,function(b){var c=d[j][1][b];return a(c||b)},k,k.exports,b,d,e,g)}return e[j].exports}for(var h="function"==typeof require&&require,c=0;c<g.length;c++)a(g[c]);return a}return b}()({"/":[function(a,b,c){'use strict';function d(a){var b=a.length;if(0<b%4)throw new Error("Invalid string. Length must be a multiple of 4");var c=a.indexOf("=");-1===c&&(c=b);var d=c===b?0:4-c%4;return[c,d]}function e(a,b,c){return 3*(b+c)/4-c}function f(a){var b,c,f=d(a),g=f[0],h=f[1],j=new m(e(a,g,h)),k=0,n=0<h?g-4:g;for(c=0;c<n;c+=4)b=l[a.charCodeAt(c)]<<18|l[a.charCodeAt(c+1)]<<12|l[a.charCodeAt(c+2)]<<6|l[a.charCodeAt(c+3)],j[k++]=255&b>>16,j[k++]=255&b>>8,j[k++]=255&b;return 2===h&&(b=l[a.charCodeAt(c)]<<2|l[a.charCodeAt(c+1)]>>4,j[k++]=255&b),1===h&&(b=l[a.charCodeAt(c)]<<10|l[a.charCodeAt(c+1)]<<4|l[a.charCodeAt(c+2)]>>2,j[k++]=255&b>>8,j[k++]=255&b),j}function g(a){return k[63&a>>18]+k[63&a>>12]+k[63&a>>6]+k[63&a]}function h(a,b,c){for(var d,e=[],f=b;f<c;f+=3)d=(16711680&a[f]<<16)+(65280&a[f+1]<<8)+(255&a[f+2]),e.push(g(d));return e.join("")}function j(a){for(var b,c=a.length,d=c%3,e=[],f=16383,g=0,j=c-d;g<j;g+=f)e.push(h(a,g,g+f>j?j:g+f));return 1===d?(b=a[c-1],e.push(k[b>>2]+k[63&b<<4]+"==")):2===d&&(b=(a[c-2]<<8)+a[c-1],e.push(k[b>>10]+k[63&b>>4]+k[63&b<<2]+"=")),e.join("")}c.byteLength=function(a){var b=d(a),c=b[0],e=b[1];return 3*(c+e)/4-e},c.toByteArray=f,c.fromByteArray=j;for(var k=[],l=[],m="undefined"==typeof Uint8Array?Array:Uint8Array,n="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",o=0,p=n.length;o<p;++o)k[o]=n[o],l[n.charCodeAt(o)]=o;l[45]=62,l[95]=63},{}]},{},[])("/")});
+	var sameOriginSupport = -1;
+	var checkSameOriginSupport = function(callback0) {
+		if(sameOriginSupport == -1) {
+			try {
+				(function(callback) {
+					if((typeof URL === "undefined") || (typeof URL.createObjectURL !== "function")) {
+						sameOriginSupport = 1;
+						callback(false);
+					}else {
+						var theObjURL = URL.createObjectURL(new Blob([new Uint8Array([69, 69, 69, 69])]));
+						if(!theObjURL) {
+							sameOriginSupport = 1;
+							callback(false);
+						}
+						doXHR(theObjURL, function(dataRet) {
+							if(dataRet) {
+								var typedArr = new Uint8Array(dataRet);
+								if(typedArr.length === 4 && typedArr[0] === 69 && typedArr[1] === 69 && typedArr[2] === 69 && typedArr[3] === 69) {
+									sameOriginSupport = 0;
+									callback(true);
+								}else {
+									sameOriginSupport = 1;
+									callback(false);
+								}
+							}else {
+								sameOriginSupport = 1;
+								callback(false);
+							}
+						});
+					}
+				})(function(valRet) {
+					if(!valRet) {
+						console.error("Same origin XHR support detected as false, using data: url...");
+					}
+					callback0(valRet);
+				});
+			}catch(ex) {
+				console.error("Same origin XHR support detection failed, using data: url...");
+				callback0(false);
+			}
+		}else {
+			callback0(!sameOriginSupport);
+		}
+	};
+	var blobToArrayBuffer = function(blobIn, callback) {
+		if(typeof blobIn.arrayBuffer === "undefined") {
+			blobIn.arrayBuffer().then(callback);
+		}else {
+			(function(phileReader) {
+				phileReader.addEventListener("load", function(evt) {
+					callback(phileReader.result);
+				});
+				phileReader.readAsArrayBuffer(blobIn);
+			})(new FileReader());
+		}
+	};
+	var completeXHR = function(callback, arg) {
+		if(!callback.comp) {
+			callback.comp = true;
+			callback.cb(arg);
+		}
+	};
+	var doXHR = function(urlIn, callback) {
+		(function(theXHRObj, callbackStruct){
+			theXHRObj.responseType = "arraybuffer";
+			theXHRObj.addEventListener("load", function(evt) { var stat = theXHRObj.status; if(stat === 0 || (stat >= 200 && stat < 400)) { completeXHR(callbackStruct, theXHRObj.response); } else { completeXHR(callbackStruct, null); } });
+			theXHRObj.addEventListener("error", function(evt) {  completeXHR(callbackStruct, null); });
+			theXHRObj.open("GET", urlIn, true);
+			theXHRObj.send();
+		})(new XMLHttpRequest(), { cb: callback, comp: false });
+	};
+	var decodeBase64URL = function(urlIn, callbackOut) {
+		doXHR(urlIn, function(data) {
+			if(!data) {
+				try {
+					console.error("Caught an error decoding base64 via fetch, doing it the slow way instead...");
+					callbackOut(base64js.toByteArray(urlIn.substring(37)).buffer);
+				}catch(ex) {
+					console.error("Failed to decode base64!");
+					console.error(ex);
+					callbackOut(null);
+				}
+			}else {
+				callbackOut(data);
+			}
+		});
+	};
+	if(typeof window.DecompressionStream === "undefined") {
+		checkSameOriginSupport(function(soSupported) {
+			var theWorkerObj;
+			var workerSrc = "InVzZSBzdHJpY3QiOwovKiEgcGFrbyAyLjEuMCBodHRwczovL2dpdGh1Yi5jb20vbm9kZWNhL3Bha28gQGxpY2Vuc2UgKE1JVCBBTkQgWmxpYikgKi8KIWZ1bmN0aW9uKGUsdCl7Im9iamVjdCI9PXR5cGVvZiBleHBvcnRzJiYidW5kZWZpbmVkIiE9dHlwZW9mIG1vZHVsZT90KGV4cG9ydHMpOiJmdW5jdGlvbiI9PXR5cGVvZiBkZWZpbmUmJmRlZmluZS5hbWQ/ZGVmaW5lKFsiZXhwb3J0cyJdLHQpOnQoKGU9InVuZGVmaW5lZCIhPXR5cGVvZiBnbG9iYWxUaGlzP2dsb2JhbFRoaXM6ZXx8c2VsZikucGFrbz17fSl9KHRoaXMsKGZ1bmN0aW9uKGUpeyJ1c2Ugc3RyaWN0Ijt2YXIgdD1mdW5jdGlvbihlLHQsaSxuKXtmb3IodmFyIGE9NjU1MzUmZXwwLHI9ZT4+PjE2JjY1NTM1fDAsbz0wOzAhPT1pOyl7aS09bz1pPjJlMz8yZTM6aTtkb3tyPXIrKGE9YSt0W24rK118MCl8MH13aGlsZSgtLW8pO2ElPTY1NTIxLHIlPTY1NTIxfXJldHVybiBhfHI8PDE2fDB9LGk9bmV3IFVpbnQzMkFycmF5KGZ1bmN0aW9uKCl7Zm9yKHZhciBlLHQ9W10saT0wO2k8MjU2O2krKyl7ZT1pO2Zvcih2YXIgbj0wO248ODtuKyspZT0xJmU/Mzk4ODI5MjM4NF5lPj4+MTplPj4+MTt0W2ldPWV9cmV0dXJuIHR9KCkpLG49ZnVuY3Rpb24oZSx0LG4sYSl7dmFyIHI9aSxvPWErbjtlXj0tMTtmb3IodmFyIHM9YTtzPG87cysrKWU9ZT4+PjheclsyNTUmKGVedFtzXSldO3JldHVybi0xXmV9LGE9MTYyMDkscj1mdW5jdGlvbihlLHQpe3ZhciBpLG4scixvLHMsbCxmLGQsaCxjLHUsdyxiLG0sayxfLHYsZyxwLHkseCxFLFIsQSxaPWUuc3RhdGU7aT1lLm5leHRfaW4sUj1lLmlucHV0LG49aSsoZS5hdmFpbF9pbi01KSxyPWUubmV4dF9vdXQsQT1lLm91dHB1dCxvPXItKHQtZS5hdmFpbF9vdXQpLHM9cisoZS5hdmFpbF9vdXQtMjU3KSxsPVouZG1heCxmPVoud3NpemUsZD1aLndoYXZlLGg9Wi53bmV4dCxjPVoud2luZG93LHU9Wi5ob2xkLHc9Wi5iaXRzLGI9Wi5sZW5jb2RlLG09Wi5kaXN0Y29kZSxrPSgxPDxaLmxlbmJpdHMpLTEsXz0oMTw8Wi5kaXN0Yml0cyktMTtlOmRve3c8MTUmJih1Kz1SW2krK108PHcsdys9OCx1Kz1SW2krK108PHcsdys9OCksdj1iW3Uma107dDpmb3IoOzspe2lmKHU+Pj49Zz12Pj4+MjQsdy09ZywwPT09KGc9dj4+PjE2JjI1NSkpQVtyKytdPTY1NTM1JnY7ZWxzZXtpZighKDE2JmcpKXtpZigwPT0oNjQmZykpe3Y9YlsoNjU1MzUmdikrKHUmKDE8PGcpLTEpXTtjb250aW51ZSB0fWlmKDMyJmcpe1oubW9kZT0xNjE5MTticmVhayBlfWUubXNnPSJpbnZhbGlkIGxpdGVyYWwvbGVuZ3RoIGNvZGUiLFoubW9kZT1hO2JyZWFrIGV9cD02NTUzNSZ2LChnJj0xNSkmJih3PGcmJih1Kz1SW2krK108PHcsdys9OCkscCs9dSYoMTw8ZyktMSx1Pj4+PWcsdy09ZyksdzwxNSYmKHUrPVJbaSsrXTw8dyx3Kz04LHUrPVJbaSsrXTw8dyx3Kz04KSx2PW1bdSZfXTtpOmZvcig7Oyl7aWYodT4+Pj1nPXY+Pj4yNCx3LT1nLCEoMTYmKGc9dj4+PjE2JjI1NSkpKXtpZigwPT0oNjQmZykpe3Y9bVsoNjU1MzUmdikrKHUmKDE8PGcpLTEpXTtjb250aW51ZSBpfWUubXNnPSJpbnZhbGlkIGRpc3RhbmNlIGNvZGUiLFoubW9kZT1hO2JyZWFrIGV9aWYoeT02NTUzNSZ2LHc8KGcmPTE1KSYmKHUrPVJbaSsrXTw8dywodys9OCk8ZyYmKHUrPVJbaSsrXTw8dyx3Kz04KSksKHkrPXUmKDE8PGcpLTEpPmwpe2UubXNnPSJpbnZhbGlkIGRpc3RhbmNlIHRvbyBmYXIgYmFjayIsWi5tb2RlPWE7YnJlYWsgZX1pZih1Pj4+PWcsdy09Zyx5PihnPXItbykpe2lmKChnPXktZyk+ZCYmWi5zYW5lKXtlLm1zZz0iaW52YWxpZCBkaXN0YW5jZSB0b28gZmFyIGJhY2siLFoubW9kZT1hO2JyZWFrIGV9aWYoeD0wLEU9YywwPT09aCl7aWYoeCs9Zi1nLGc8cCl7cC09Zztkb3tBW3IrK109Y1t4KytdfXdoaWxlKC0tZyk7eD1yLXksRT1BfX1lbHNlIGlmKGg8Zyl7aWYoeCs9ZitoLWcsKGctPWgpPHApe3AtPWc7ZG97QVtyKytdPWNbeCsrXX13aGlsZSgtLWcpO2lmKHg9MCxoPHApe3AtPWc9aDtkb3tBW3IrK109Y1t4KytdfXdoaWxlKC0tZyk7eD1yLXksRT1BfX19ZWxzZSBpZih4Kz1oLWcsZzxwKXtwLT1nO2Rve0FbcisrXT1jW3grK119d2hpbGUoLS1nKTt4PXIteSxFPUF9Zm9yKDtwPjI7KUFbcisrXT1FW3grK10sQVtyKytdPUVbeCsrXSxBW3IrK109RVt4KytdLHAtPTM7cCYmKEFbcisrXT1FW3grK10scD4xJiYoQVtyKytdPUVbeCsrXSkpfWVsc2V7eD1yLXk7ZG97QVtyKytdPUFbeCsrXSxBW3IrK109QVt4KytdLEFbcisrXT1BW3grK10scC09M313aGlsZShwPjIpO3AmJihBW3IrK109QVt4KytdLHA+MSYmKEFbcisrXT1BW3grK10pKX1icmVha319YnJlYWt9fXdoaWxlKGk8biYmcjxzKTtpLT1wPXc+PjMsdSY9KDE8PCh3LT1wPDwzKSktMSxlLm5leHRfaW49aSxlLm5leHRfb3V0PXIsZS5hdmFpbF9pbj1pPG4/bi1pKzU6NS0oaS1uKSxlLmF2YWlsX291dD1yPHM/cy1yKzI1NzoyNTctKHItcyksWi5ob2xkPXUsWi5iaXRzPXd9LG89MTUscz1uZXcgVWludDE2QXJyYXkoWzMsNCw1LDYsNyw4LDksMTAsMTEsMTMsMTUsMTcsMTksMjMsMjcsMzEsMzUsNDMsNTEsNTksNjcsODMsOTksMTE1LDEzMSwxNjMsMTk1LDIyNywyNTgsMCwwXSksbD1uZXcgVWludDhBcnJheShbMTYsMTYsMTYsMTYsMTYsMTYsMTYsMTYsMTcsMTcsMTcsMTcsMTgsMTgsMTgsMTgsMTksMTksMTksMTksMjAsMjAsMjAsMjAsMjEsMjEsMjEsMjEsMTYsNzIsNzhdKSxmPW5ldyBVaW50MTZBcnJheShbMSwyLDMsNCw1LDcsOSwxMywxNywyNSwzMyw0OSw2NSw5NywxMjksMTkzLDI1NywzODUsNTEzLDc2OSwxMDI1LDE1MzcsMjA0OSwzMDczLDQwOTcsNjE0NSw4MTkzLDEyMjg5LDE2Mzg1LDI0NTc3LDAsMF0pLGQ9bmV3IFVpbnQ4QXJyYXkoWzE2LDE2LDE2LDE2LDE3LDE3LDE4LDE4LDE5LDE5LDIwLDIwLDIxLDIxLDIyLDIyLDIzLDIzLDI0LDI0LDI1LDI1LDI2LDI2LDI3LDI3LDI4LDI4LDI5LDI5LDY0LDY0XSksaD1mdW5jdGlvbihlLHQsaSxuLGEscixoLGMpe3ZhciB1LHcsYixtLGssXyx2LGcscCx5PWMuYml0cyx4PTAsRT0wLFI9MCxBPTAsWj0wLFM9MCxUPTAsTz0wLFU9MCxEPTAsST1udWxsLEI9bmV3IFVpbnQxNkFycmF5KDE2KSxOPW5ldyBVaW50MTZBcnJheSgxNiksQz1udWxsO2Zvcih4PTA7eDw9bzt4KyspQlt4XT0wO2ZvcihFPTA7RTxuO0UrKylCW3RbaStFXV0rKztmb3IoWj15LEE9bztBPj0xJiYwPT09QltBXTtBLS0pO2lmKFo+QSYmKFo9QSksMD09PUEpcmV0dXJuIGFbcisrXT0yMDk3MTUyMCxhW3IrK109MjA5NzE1MjAsYy5iaXRzPTEsMDtmb3IoUj0xO1I8QSYmMD09PUJbUl07UisrKTtmb3IoWjxSJiYoWj1SKSxPPTEseD0xO3g8PW87eCsrKWlmKE88PD0xLChPLT1CW3hdKTwwKXJldHVybi0xO2lmKE8+MCYmKDA9PT1lfHwxIT09QSkpcmV0dXJuLTE7Zm9yKE5bMV09MCx4PTE7eDxvO3grKylOW3grMV09Tlt4XStCW3hdO2ZvcihFPTA7RTxuO0UrKykwIT09dFtpK0VdJiYoaFtOW3RbaStFXV0rK109RSk7aWYoMD09PWU/KEk9Qz1oLF89MjApOjE9PT1lPyhJPXMsQz1sLF89MjU3KTooST1mLEM9ZCxfPTApLEQ9MCxFPTAseD1SLGs9cixTPVosVD0wLGI9LTEsbT0oVT0xPDxaKS0xLDE9PT1lJiZVPjg1Mnx8Mj09PWUmJlU+NTkyKXJldHVybiAxO2Zvcig7Oyl7dj14LVQsaFtFXSsxPF8/KGc9MCxwPWhbRV0pOmhbRV0+PV8/KGc9Q1toW0VdLV9dLHA9SVtoW0VdLV9dKTooZz05NixwPTApLHU9MTw8eC1ULFI9dz0xPDxTO2Rve2FbaysoRD4+VCkrKHctPXUpXT12PDwyNHxnPDwxNnxwfDB9d2hpbGUoMCE9PXcpO2Zvcih1PTE8PHgtMTtEJnU7KXU+Pj0xO2lmKDAhPT11PyhEJj11LTEsRCs9dSk6RD0wLEUrKywwPT0tLUJbeF0pe2lmKHg9PT1BKWJyZWFrO3g9dFtpK2hbRV1dfWlmKHg+WiYmKEQmbSkhPT1iKXtmb3IoMD09PVQmJihUPVopLGsrPVIsTz0xPDwoUz14LVQpO1MrVDxBJiYhKChPLT1CW1MrVF0pPD0wKTspUysrLE88PD0xO2lmKFUrPTE8PFMsMT09PWUmJlU+ODUyfHwyPT09ZSYmVT41OTIpcmV0dXJuIDE7YVtiPUQmbV09Wjw8MjR8Uzw8MTZ8ay1yfDB9fXJldHVybiAwIT09RCYmKGFbaytEXT14LVQ8PDI0fDY0PDwxNnwwKSxjLmJpdHM9WiwwfSxjPXtaX05PX0ZMVVNIOjAsWl9QQVJUSUFMX0ZMVVNIOjEsWl9TWU5DX0ZMVVNIOjIsWl9GVUxMX0ZMVVNIOjMsWl9GSU5JU0g6NCxaX0JMT0NLOjUsWl9UUkVFUzo2LFpfT0s6MCxaX1NUUkVBTV9FTkQ6MSxaX05FRURfRElDVDoyLFpfRVJSTk86LTEsWl9TVFJFQU1fRVJST1I6LTIsWl9EQVRBX0VSUk9SOi0zLFpfTUVNX0VSUk9SOi00LFpfQlVGX0VSUk9SOi01LFpfTk9fQ09NUFJFU1NJT046MCxaX0JFU1RfU1BFRUQ6MSxaX0JFU1RfQ09NUFJFU1NJT046OSxaX0RFRkFVTFRfQ09NUFJFU1NJT046LTEsWl9GSUxURVJFRDoxLFpfSFVGRk1BTl9PTkxZOjIsWl9STEU6MyxaX0ZJWEVEOjQsWl9ERUZBVUxUX1NUUkFURUdZOjAsWl9CSU5BUlk6MCxaX1RFWFQ6MSxaX1VOS05PV046MixaX0RFRkxBVEVEOjh9LHU9Yy5aX0ZJTklTSCx3PWMuWl9CTE9DSyxiPWMuWl9UUkVFUyxtPWMuWl9PSyxrPWMuWl9TVFJFQU1fRU5ELF89Yy5aX05FRURfRElDVCx2PWMuWl9TVFJFQU1fRVJST1IsZz1jLlpfREFUQV9FUlJPUixwPWMuWl9NRU1fRVJST1IseT1jLlpfQlVGX0VSUk9SLHg9Yy5aX0RFRkxBVEVELEU9MTYxODAsUj0xNjE5MCxBPTE2MTkxLFo9MTYxOTIsUz0xNjE5NCxUPTE2MTk5LE89MTYyMDAsVT0xNjIwNixEPTE2MjA5LEk9ZnVuY3Rpb24oZSl7cmV0dXJuKGU+Pj4yNCYyNTUpKyhlPj4+OCY2NTI4MCkrKCg2NTI4MCZlKTw8OCkrKCgyNTUmZSk8PDI0KX07ZnVuY3Rpb24gQigpe3RoaXMuc3RybT1udWxsLHRoaXMubW9kZT0wLHRoaXMubGFzdD0hMSx0aGlzLndyYXA9MCx0aGlzLmhhdmVkaWN0PSExLHRoaXMuZmxhZ3M9MCx0aGlzLmRtYXg9MCx0aGlzLmNoZWNrPTAsdGhpcy50b3RhbD0wLHRoaXMuaGVhZD1udWxsLHRoaXMud2JpdHM9MCx0aGlzLndzaXplPTAsdGhpcy53aGF2ZT0wLHRoaXMud25leHQ9MCx0aGlzLndpbmRvdz1udWxsLHRoaXMuaG9sZD0wLHRoaXMuYml0cz0wLHRoaXMubGVuZ3RoPTAsdGhpcy5vZmZzZXQ9MCx0aGlzLmV4dHJhPTAsdGhpcy5sZW5jb2RlPW51bGwsdGhpcy5kaXN0Y29kZT1udWxsLHRoaXMubGVuYml0cz0wLHRoaXMuZGlzdGJpdHM9MCx0aGlzLm5jb2RlPTAsdGhpcy5ubGVuPTAsdGhpcy5uZGlzdD0wLHRoaXMuaGF2ZT0wLHRoaXMubmV4dD1udWxsLHRoaXMubGVucz1uZXcgVWludDE2QXJyYXkoMzIwKSx0aGlzLndvcms9bmV3IFVpbnQxNkFycmF5KDI4OCksdGhpcy5sZW5keW49bnVsbCx0aGlzLmRpc3RkeW49bnVsbCx0aGlzLnNhbmU9MCx0aGlzLmJhY2s9MCx0aGlzLndhcz0wfXZhciBOLEMsej1mdW5jdGlvbihlKXtpZighZSlyZXR1cm4gMTt2YXIgdD1lLnN0YXRlO3JldHVybiF0fHx0LnN0cm0hPT1lfHx0Lm1vZGU8RXx8dC5tb2RlPjE2MjExPzE6MH0sRj1mdW5jdGlvbihlKXtpZih6KGUpKXJldHVybiB2O3ZhciB0PWUuc3RhdGU7cmV0dXJuIGUudG90YWxfaW49ZS50b3RhbF9vdXQ9dC50b3RhbD0wLGUubXNnPSIiLHQud3JhcCYmKGUuYWRsZXI9MSZ0LndyYXApLHQubW9kZT1FLHQubGFzdD0wLHQuaGF2ZWRpY3Q9MCx0LmZsYWdzPS0xLHQuZG1heD0zMjc2OCx0LmhlYWQ9bnVsbCx0LmhvbGQ9MCx0LmJpdHM9MCx0LmxlbmNvZGU9dC5sZW5keW49bmV3IEludDMyQXJyYXkoODUyKSx0LmRpc3Rjb2RlPXQuZGlzdGR5bj1uZXcgSW50MzJBcnJheSg1OTIpLHQuc2FuZT0xLHQuYmFjaz0tMSxtfSxMPWZ1bmN0aW9uKGUpe2lmKHooZSkpcmV0dXJuIHY7dmFyIHQ9ZS5zdGF0ZTtyZXR1cm4gdC53c2l6ZT0wLHQud2hhdmU9MCx0LnduZXh0PTAsRihlKX0sTT1mdW5jdGlvbihlLHQpe3ZhciBpO2lmKHooZSkpcmV0dXJuIHY7dmFyIG49ZS5zdGF0ZTtyZXR1cm4gdDwwPyhpPTAsdD0tdCk6KGk9NSsodD4+NCksdDw0OCYmKHQmPTE1KSksdCYmKHQ8OHx8dD4xNSk/djoobnVsbCE9PW4ud2luZG93JiZuLndiaXRzIT09dCYmKG4ud2luZG93PW51bGwpLG4ud3JhcD1pLG4ud2JpdHM9dCxMKGUpKX0sSD1mdW5jdGlvbihlLHQpe2lmKCFlKXJldHVybiB2O3ZhciBpPW5ldyBCO2Uuc3RhdGU9aSxpLnN0cm09ZSxpLndpbmRvdz1udWxsLGkubW9kZT1FO3ZhciBuPU0oZSx0KTtyZXR1cm4gbiE9PW0mJihlLnN0YXRlPW51bGwpLG59LGo9ITAsSz1mdW5jdGlvbihlKXtpZihqKXtOPW5ldyBJbnQzMkFycmF5KDUxMiksQz1uZXcgSW50MzJBcnJheSgzMik7Zm9yKHZhciB0PTA7dDwxNDQ7KWUubGVuc1t0KytdPTg7Zm9yKDt0PDI1NjspZS5sZW5zW3QrK109OTtmb3IoO3Q8MjgwOyllLmxlbnNbdCsrXT03O2Zvcig7dDwyODg7KWUubGVuc1t0KytdPTg7Zm9yKGgoMSxlLmxlbnMsMCwyODgsTiwwLGUud29yayx7Yml0czo5fSksdD0wO3Q8MzI7KWUubGVuc1t0KytdPTU7aCgyLGUubGVucywwLDMyLEMsMCxlLndvcmsse2JpdHM6NX0pLGo9ITF9ZS5sZW5jb2RlPU4sZS5sZW5iaXRzPTksZS5kaXN0Y29kZT1DLGUuZGlzdGJpdHM9NX0sUD1mdW5jdGlvbihlLHQsaSxuKXt2YXIgYSxyPWUuc3RhdGU7cmV0dXJuIG51bGw9PT1yLndpbmRvdyYmKHIud3NpemU9MTw8ci53Yml0cyxyLnduZXh0PTAsci53aGF2ZT0wLHIud2luZG93PW5ldyBVaW50OEFycmF5KHIud3NpemUpKSxuPj1yLndzaXplPyhyLndpbmRvdy5zZXQodC5zdWJhcnJheShpLXIud3NpemUsaSksMCksci53bmV4dD0wLHIud2hhdmU9ci53c2l6ZSk6KChhPXIud3NpemUtci53bmV4dCk+biYmKGE9biksci53aW5kb3cuc2V0KHQuc3ViYXJyYXkoaS1uLGktbithKSxyLnduZXh0KSwobi09YSk/KHIud2luZG93LnNldCh0LnN1YmFycmF5KGktbixpKSwwKSxyLnduZXh0PW4sci53aGF2ZT1yLndzaXplKTooci53bmV4dCs9YSxyLnduZXh0PT09ci53c2l6ZSYmKHIud25leHQ9MCksci53aGF2ZTxyLndzaXplJiYoci53aGF2ZSs9YSkpKSwwfSxZPXtpbmZsYXRlUmVzZXQ6TCxpbmZsYXRlUmVzZXQyOk0saW5mbGF0ZVJlc2V0S2VlcDpGLGluZmxhdGVJbml0OmZ1bmN0aW9uKGUpe3JldHVybiBIKGUsMTUpfSxpbmZsYXRlSW5pdDI6SCxpbmZsYXRlOmZ1bmN0aW9uKGUsaSl7dmFyIGEsbyxzLGwsZixkLGMsQixOLEMsRixMLE0sSCxqLFksRyxYLFcscSxKLFEsViwkLGVlPTAsdGU9bmV3IFVpbnQ4QXJyYXkoNCksaWU9bmV3IFVpbnQ4QXJyYXkoWzE2LDE3LDE4LDAsOCw3LDksNiwxMCw1LDExLDQsMTIsMywxMywyLDE0LDEsMTVdKTtpZih6KGUpfHwhZS5vdXRwdXR8fCFlLmlucHV0JiYwIT09ZS5hdmFpbF9pbilyZXR1cm4gdjsoYT1lLnN0YXRlKS5tb2RlPT09QSYmKGEubW9kZT1aKSxmPWUubmV4dF9vdXQscz1lLm91dHB1dCxjPWUuYXZhaWxfb3V0LGw9ZS5uZXh0X2luLG89ZS5pbnB1dCxkPWUuYXZhaWxfaW4sQj1hLmhvbGQsTj1hLmJpdHMsQz1kLEY9YyxRPW07ZTpmb3IoOzspc3dpdGNoKGEubW9kZSl7Y2FzZSBFOmlmKDA9PT1hLndyYXApe2EubW9kZT1aO2JyZWFrfWZvcig7TjwxNjspe2lmKDA9PT1kKWJyZWFrIGU7ZC0tLEIrPW9bbCsrXTw8TixOKz04fWlmKDImYS53cmFwJiYzNTYxNT09PUIpezA9PT1hLndiaXRzJiYoYS53Yml0cz0xNSksYS5jaGVjaz0wLHRlWzBdPTI1NSZCLHRlWzFdPUI+Pj44JjI1NSxhLmNoZWNrPW4oYS5jaGVjayx0ZSwyLDApLEI9MCxOPTAsYS5tb2RlPTE2MTgxO2JyZWFrfWlmKGEuaGVhZCYmKGEuaGVhZC5kb25lPSExKSwhKDEmYS53cmFwKXx8KCgoMjU1JkIpPDw4KSsoQj4+OCkpJTMxKXtlLm1zZz0iaW5jb3JyZWN0IGhlYWRlciBjaGVjayIsYS5tb2RlPUQ7YnJlYWt9aWYoKDE1JkIpIT09eCl7ZS5tc2c9InVua25vd24gY29tcHJlc3Npb24gbWV0aG9kIixhLm1vZGU9RDticmVha31pZihOLT00LEo9OCsoMTUmKEI+Pj49NCkpLDA9PT1hLndiaXRzJiYoYS53Yml0cz1KKSxKPjE1fHxKPmEud2JpdHMpe2UubXNnPSJpbnZhbGlkIHdpbmRvdyBzaXplIixhLm1vZGU9RDticmVha31hLmRtYXg9MTw8YS53Yml0cyxhLmZsYWdzPTAsZS5hZGxlcj1hLmNoZWNrPTEsYS5tb2RlPTUxMiZCPzE2MTg5OkEsQj0wLE49MDticmVhaztjYXNlIDE2MTgxOmZvcig7TjwxNjspe2lmKDA9PT1kKWJyZWFrIGU7ZC0tLEIrPW9bbCsrXTw8TixOKz04fWlmKGEuZmxhZ3M9QiwoMjU1JmEuZmxhZ3MpIT09eCl7ZS5tc2c9InVua25vd24gY29tcHJlc3Npb24gbWV0aG9kIixhLm1vZGU9RDticmVha31pZig1NzM0NCZhLmZsYWdzKXtlLm1zZz0idW5rbm93biBoZWFkZXIgZmxhZ3Mgc2V0IixhLm1vZGU9RDticmVha31hLmhlYWQmJihhLmhlYWQudGV4dD1CPj44JjEpLDUxMiZhLmZsYWdzJiY0JmEud3JhcCYmKHRlWzBdPTI1NSZCLHRlWzFdPUI+Pj44JjI1NSxhLmNoZWNrPW4oYS5jaGVjayx0ZSwyLDApKSxCPTAsTj0wLGEubW9kZT0xNjE4MjtjYXNlIDE2MTgyOmZvcig7TjwzMjspe2lmKDA9PT1kKWJyZWFrIGU7ZC0tLEIrPW9bbCsrXTw8TixOKz04fWEuaGVhZCYmKGEuaGVhZC50aW1lPUIpLDUxMiZhLmZsYWdzJiY0JmEud3JhcCYmKHRlWzBdPTI1NSZCLHRlWzFdPUI+Pj44JjI1NSx0ZVsyXT1CPj4+MTYmMjU1LHRlWzNdPUI+Pj4yNCYyNTUsYS5jaGVjaz1uKGEuY2hlY2ssdGUsNCwwKSksQj0wLE49MCxhLm1vZGU9MTYxODM7Y2FzZSAxNjE4Mzpmb3IoO048MTY7KXtpZigwPT09ZClicmVhayBlO2QtLSxCKz1vW2wrK108PE4sTis9OH1hLmhlYWQmJihhLmhlYWQueGZsYWdzPTI1NSZCLGEuaGVhZC5vcz1CPj44KSw1MTImYS5mbGFncyYmNCZhLndyYXAmJih0ZVswXT0yNTUmQix0ZVsxXT1CPj4+OCYyNTUsYS5jaGVjaz1uKGEuY2hlY2ssdGUsMiwwKSksQj0wLE49MCxhLm1vZGU9MTYxODQ7Y2FzZSAxNjE4NDppZigxMDI0JmEuZmxhZ3Mpe2Zvcig7TjwxNjspe2lmKDA9PT1kKWJyZWFrIGU7ZC0tLEIrPW9bbCsrXTw8TixOKz04fWEubGVuZ3RoPUIsYS5oZWFkJiYoYS5oZWFkLmV4dHJhX2xlbj1CKSw1MTImYS5mbGFncyYmNCZhLndyYXAmJih0ZVswXT0yNTUmQix0ZVsxXT1CPj4+OCYyNTUsYS5jaGVjaz1uKGEuY2hlY2ssdGUsMiwwKSksQj0wLE49MH1lbHNlIGEuaGVhZCYmKGEuaGVhZC5leHRyYT1udWxsKTthLm1vZGU9MTYxODU7Y2FzZSAxNjE4NTppZigxMDI0JmEuZmxhZ3MmJigoTD1hLmxlbmd0aCk+ZCYmKEw9ZCksTCYmKGEuaGVhZCYmKEo9YS5oZWFkLmV4dHJhX2xlbi1hLmxlbmd0aCxhLmhlYWQuZXh0cmF8fChhLmhlYWQuZXh0cmE9bmV3IFVpbnQ4QXJyYXkoYS5oZWFkLmV4dHJhX2xlbikpLGEuaGVhZC5leHRyYS5zZXQoby5zdWJhcnJheShsLGwrTCksSikpLDUxMiZhLmZsYWdzJiY0JmEud3JhcCYmKGEuY2hlY2s9bihhLmNoZWNrLG8sTCxsKSksZC09TCxsKz1MLGEubGVuZ3RoLT1MKSxhLmxlbmd0aCkpYnJlYWsgZTthLmxlbmd0aD0wLGEubW9kZT0xNjE4NjtjYXNlIDE2MTg2OmlmKDIwNDgmYS5mbGFncyl7aWYoMD09PWQpYnJlYWsgZTtMPTA7ZG97Sj1vW2wrTCsrXSxhLmhlYWQmJkomJmEubGVuZ3RoPDY1NTM2JiYoYS5oZWFkLm5hbWUrPVN0cmluZy5mcm9tQ2hhckNvZGUoSikpfXdoaWxlKEomJkw8ZCk7aWYoNTEyJmEuZmxhZ3MmJjQmYS53cmFwJiYoYS5jaGVjaz1uKGEuY2hlY2ssbyxMLGwpKSxkLT1MLGwrPUwsSilicmVhayBlfWVsc2UgYS5oZWFkJiYoYS5oZWFkLm5hbWU9bnVsbCk7YS5sZW5ndGg9MCxhLm1vZGU9MTYxODc7Y2FzZSAxNjE4NzppZig0MDk2JmEuZmxhZ3Mpe2lmKDA9PT1kKWJyZWFrIGU7TD0wO2Rve0o9b1tsK0wrK10sYS5oZWFkJiZKJiZhLmxlbmd0aDw2NTUzNiYmKGEuaGVhZC5jb21tZW50Kz1TdHJpbmcuZnJvbUNoYXJDb2RlKEopKX13aGlsZShKJiZMPGQpO2lmKDUxMiZhLmZsYWdzJiY0JmEud3JhcCYmKGEuY2hlY2s9bihhLmNoZWNrLG8sTCxsKSksZC09TCxsKz1MLEopYnJlYWsgZX1lbHNlIGEuaGVhZCYmKGEuaGVhZC5jb21tZW50PW51bGwpO2EubW9kZT0xNjE4ODtjYXNlIDE2MTg4OmlmKDUxMiZhLmZsYWdzKXtmb3IoO048MTY7KXtpZigwPT09ZClicmVhayBlO2QtLSxCKz1vW2wrK108PE4sTis9OH1pZig0JmEud3JhcCYmQiE9PSg2NTUzNSZhLmNoZWNrKSl7ZS5tc2c9ImhlYWRlciBjcmMgbWlzbWF0Y2giLGEubW9kZT1EO2JyZWFrfUI9MCxOPTB9YS5oZWFkJiYoYS5oZWFkLmhjcmM9YS5mbGFncz4+OSYxLGEuaGVhZC5kb25lPSEwKSxlLmFkbGVyPWEuY2hlY2s9MCxhLm1vZGU9QTticmVhaztjYXNlIDE2MTg5OmZvcig7TjwzMjspe2lmKDA9PT1kKWJyZWFrIGU7ZC0tLEIrPW9bbCsrXTw8TixOKz04fWUuYWRsZXI9YS5jaGVjaz1JKEIpLEI9MCxOPTAsYS5tb2RlPVI7Y2FzZSBSOmlmKDA9PT1hLmhhdmVkaWN0KXJldHVybiBlLm5leHRfb3V0PWYsZS5hdmFpbF9vdXQ9YyxlLm5leHRfaW49bCxlLmF2YWlsX2luPWQsYS5ob2xkPUIsYS5iaXRzPU4sXztlLmFkbGVyPWEuY2hlY2s9MSxhLm1vZGU9QTtjYXNlIEE6aWYoaT09PXd8fGk9PT1iKWJyZWFrIGU7Y2FzZSBaOmlmKGEubGFzdCl7Qj4+Pj03Jk4sTi09NyZOLGEubW9kZT1VO2JyZWFrfWZvcig7TjwzOyl7aWYoMD09PWQpYnJlYWsgZTtkLS0sQis9b1tsKytdPDxOLE4rPTh9c3dpdGNoKGEubGFzdD0xJkIsTi09MSwzJihCPj4+PTEpKXtjYXNlIDA6YS5tb2RlPTE2MTkzO2JyZWFrO2Nhc2UgMTppZihLKGEpLGEubW9kZT1ULGk9PT1iKXtCPj4+PTIsTi09MjticmVhayBlfWJyZWFrO2Nhc2UgMjphLm1vZGU9MTYxOTY7YnJlYWs7Y2FzZSAzOmUubXNnPSJpbnZhbGlkIGJsb2NrIHR5cGUiLGEubW9kZT1EfUI+Pj49MixOLT0yO2JyZWFrO2Nhc2UgMTYxOTM6Zm9yKEI+Pj49NyZOLE4tPTcmTjtOPDMyOyl7aWYoMD09PWQpYnJlYWsgZTtkLS0sQis9b1tsKytdPDxOLE4rPTh9aWYoKDY1NTM1JkIpIT0oQj4+PjE2XjY1NTM1KSl7ZS5tc2c9ImludmFsaWQgc3RvcmVkIGJsb2NrIGxlbmd0aHMiLGEubW9kZT1EO2JyZWFrfWlmKGEubGVuZ3RoPTY1NTM1JkIsQj0wLE49MCxhLm1vZGU9UyxpPT09YilicmVhayBlO2Nhc2UgUzphLm1vZGU9MTYxOTU7Y2FzZSAxNjE5NTppZihMPWEubGVuZ3RoKXtpZihMPmQmJihMPWQpLEw+YyYmKEw9YyksMD09PUwpYnJlYWsgZTtzLnNldChvLnN1YmFycmF5KGwsbCtMKSxmKSxkLT1MLGwrPUwsYy09TCxmKz1MLGEubGVuZ3RoLT1MO2JyZWFrfWEubW9kZT1BO2JyZWFrO2Nhc2UgMTYxOTY6Zm9yKDtOPDE0Oyl7aWYoMD09PWQpYnJlYWsgZTtkLS0sQis9b1tsKytdPDxOLE4rPTh9aWYoYS5ubGVuPTI1NysoMzEmQiksQj4+Pj01LE4tPTUsYS5uZGlzdD0xKygzMSZCKSxCPj4+PTUsTi09NSxhLm5jb2RlPTQrKDE1JkIpLEI+Pj49NCxOLT00LGEubmxlbj4yODZ8fGEubmRpc3Q+MzApe2UubXNnPSJ0b28gbWFueSBsZW5ndGggb3IgZGlzdGFuY2Ugc3ltYm9scyIsYS5tb2RlPUQ7YnJlYWt9YS5oYXZlPTAsYS5tb2RlPTE2MTk3O2Nhc2UgMTYxOTc6Zm9yKDthLmhhdmU8YS5uY29kZTspe2Zvcig7TjwzOyl7aWYoMD09PWQpYnJlYWsgZTtkLS0sQis9b1tsKytdPDxOLE4rPTh9YS5sZW5zW2llW2EuaGF2ZSsrXV09NyZCLEI+Pj49MyxOLT0zfWZvcig7YS5oYXZlPDE5OylhLmxlbnNbaWVbYS5oYXZlKytdXT0wO2lmKGEubGVuY29kZT1hLmxlbmR5bixhLmxlbmJpdHM9NyxWPXtiaXRzOmEubGVuYml0c30sUT1oKDAsYS5sZW5zLDAsMTksYS5sZW5jb2RlLDAsYS53b3JrLFYpLGEubGVuYml0cz1WLmJpdHMsUSl7ZS5tc2c9ImludmFsaWQgY29kZSBsZW5ndGhzIHNldCIsYS5tb2RlPUQ7YnJlYWt9YS5oYXZlPTAsYS5tb2RlPTE2MTk4O2Nhc2UgMTYxOTg6Zm9yKDthLmhhdmU8YS5ubGVuK2EubmRpc3Q7KXtmb3IoO1k9KGVlPWEubGVuY29kZVtCJigxPDxhLmxlbmJpdHMpLTFdKT4+PjE2JjI1NSxHPTY1NTM1JmVlLCEoKGo9ZWU+Pj4yNCk8PU4pOyl7aWYoMD09PWQpYnJlYWsgZTtkLS0sQis9b1tsKytdPDxOLE4rPTh9aWYoRzwxNilCPj4+PWosTi09aixhLmxlbnNbYS5oYXZlKytdPUc7ZWxzZXtpZigxNj09PUcpe2ZvcigkPWorMjtOPCQ7KXtpZigwPT09ZClicmVhayBlO2QtLSxCKz1vW2wrK108PE4sTis9OH1pZihCPj4+PWosTi09aiwwPT09YS5oYXZlKXtlLm1zZz0iaW52YWxpZCBiaXQgbGVuZ3RoIHJlcGVhdCIsYS5tb2RlPUQ7YnJlYWt9Sj1hLmxlbnNbYS5oYXZlLTFdLEw9MysoMyZCKSxCPj4+PTIsTi09Mn1lbHNlIGlmKDE3PT09Ryl7Zm9yKCQ9aiszO048JDspe2lmKDA9PT1kKWJyZWFrIGU7ZC0tLEIrPW9bbCsrXTw8TixOKz04fU4tPWosSj0wLEw9MysoNyYoQj4+Pj1qKSksQj4+Pj0zLE4tPTN9ZWxzZXtmb3IoJD1qKzc7TjwkOyl7aWYoMD09PWQpYnJlYWsgZTtkLS0sQis9b1tsKytdPDxOLE4rPTh9Ti09aixKPTAsTD0xMSsoMTI3JihCPj4+PWopKSxCPj4+PTcsTi09N31pZihhLmhhdmUrTD5hLm5sZW4rYS5uZGlzdCl7ZS5tc2c9ImludmFsaWQgYml0IGxlbmd0aCByZXBlYXQiLGEubW9kZT1EO2JyZWFrfWZvcig7TC0tOylhLmxlbnNbYS5oYXZlKytdPUp9fWlmKGEubW9kZT09PUQpYnJlYWs7aWYoMD09PWEubGVuc1syNTZdKXtlLm1zZz0iaW52YWxpZCBjb2RlIC0tIG1pc3NpbmcgZW5kLW9mLWJsb2NrIixhLm1vZGU9RDticmVha31pZihhLmxlbmJpdHM9OSxWPXtiaXRzOmEubGVuYml0c30sUT1oKDEsYS5sZW5zLDAsYS5ubGVuLGEubGVuY29kZSwwLGEud29yayxWKSxhLmxlbmJpdHM9Vi5iaXRzLFEpe2UubXNnPSJpbnZhbGlkIGxpdGVyYWwvbGVuZ3RocyBzZXQiLGEubW9kZT1EO2JyZWFrfWlmKGEuZGlzdGJpdHM9NixhLmRpc3Rjb2RlPWEuZGlzdGR5bixWPXtiaXRzOmEuZGlzdGJpdHN9LFE9aCgyLGEubGVucyxhLm5sZW4sYS5uZGlzdCxhLmRpc3Rjb2RlLDAsYS53b3JrLFYpLGEuZGlzdGJpdHM9Vi5iaXRzLFEpe2UubXNnPSJpbnZhbGlkIGRpc3RhbmNlcyBzZXQiLGEubW9kZT1EO2JyZWFrfWlmKGEubW9kZT1ULGk9PT1iKWJyZWFrIGU7Y2FzZSBUOmEubW9kZT1PO2Nhc2UgTzppZihkPj02JiZjPj0yNTgpe2UubmV4dF9vdXQ9ZixlLmF2YWlsX291dD1jLGUubmV4dF9pbj1sLGUuYXZhaWxfaW49ZCxhLmhvbGQ9QixhLmJpdHM9TixyKGUsRiksZj1lLm5leHRfb3V0LHM9ZS5vdXRwdXQsYz1lLmF2YWlsX291dCxsPWUubmV4dF9pbixvPWUuaW5wdXQsZD1lLmF2YWlsX2luLEI9YS5ob2xkLE49YS5iaXRzLGEubW9kZT09PUEmJihhLmJhY2s9LTEpO2JyZWFrfWZvcihhLmJhY2s9MDtZPShlZT1hLmxlbmNvZGVbQiYoMTw8YS5sZW5iaXRzKS0xXSk+Pj4xNiYyNTUsRz02NTUzNSZlZSwhKChqPWVlPj4+MjQpPD1OKTspe2lmKDA9PT1kKWJyZWFrIGU7ZC0tLEIrPW9bbCsrXTw8TixOKz04fWlmKFkmJjA9PSgyNDAmWSkpe2ZvcihYPWosVz1ZLHE9RztZPShlZT1hLmxlbmNvZGVbcSsoKEImKDE8PFgrVyktMSk+PlgpXSk+Pj4xNiYyNTUsRz02NTUzNSZlZSwhKFgrKGo9ZWU+Pj4yNCk8PU4pOyl7aWYoMD09PWQpYnJlYWsgZTtkLS0sQis9b1tsKytdPDxOLE4rPTh9Qj4+Pj1YLE4tPVgsYS5iYWNrKz1YfWlmKEI+Pj49aixOLT1qLGEuYmFjays9aixhLmxlbmd0aD1HLDA9PT1ZKXthLm1vZGU9MTYyMDU7YnJlYWt9aWYoMzImWSl7YS5iYWNrPS0xLGEubW9kZT1BO2JyZWFrfWlmKDY0Jlkpe2UubXNnPSJpbnZhbGlkIGxpdGVyYWwvbGVuZ3RoIGNvZGUiLGEubW9kZT1EO2JyZWFrfWEuZXh0cmE9MTUmWSxhLm1vZGU9MTYyMDE7Y2FzZSAxNjIwMTppZihhLmV4dHJhKXtmb3IoJD1hLmV4dHJhO048JDspe2lmKDA9PT1kKWJyZWFrIGU7ZC0tLEIrPW9bbCsrXTw8TixOKz04fWEubGVuZ3RoKz1CJigxPDxhLmV4dHJhKS0xLEI+Pj49YS5leHRyYSxOLT1hLmV4dHJhLGEuYmFjays9YS5leHRyYX1hLndhcz1hLmxlbmd0aCxhLm1vZGU9MTYyMDI7Y2FzZSAxNjIwMjpmb3IoO1k9KGVlPWEuZGlzdGNvZGVbQiYoMTw8YS5kaXN0Yml0cyktMV0pPj4+MTYmMjU1LEc9NjU1MzUmZWUsISgoaj1lZT4+PjI0KTw9Tik7KXtpZigwPT09ZClicmVhayBlO2QtLSxCKz1vW2wrK108PE4sTis9OH1pZigwPT0oMjQwJlkpKXtmb3IoWD1qLFc9WSxxPUc7WT0oZWU9YS5kaXN0Y29kZVtxKygoQiYoMTw8WCtXKS0xKT4+WCldKT4+PjE2JjI1NSxHPTY1NTM1JmVlLCEoWCsoaj1lZT4+PjI0KTw9Tik7KXtpZigwPT09ZClicmVhayBlO2QtLSxCKz1vW2wrK108PE4sTis9OH1CPj4+PVgsTi09WCxhLmJhY2srPVh9aWYoQj4+Pj1qLE4tPWosYS5iYWNrKz1qLDY0Jlkpe2UubXNnPSJpbnZhbGlkIGRpc3RhbmNlIGNvZGUiLGEubW9kZT1EO2JyZWFrfWEub2Zmc2V0PUcsYS5leHRyYT0xNSZZLGEubW9kZT0xNjIwMztjYXNlIDE2MjAzOmlmKGEuZXh0cmEpe2ZvcigkPWEuZXh0cmE7TjwkOyl7aWYoMD09PWQpYnJlYWsgZTtkLS0sQis9b1tsKytdPDxOLE4rPTh9YS5vZmZzZXQrPUImKDE8PGEuZXh0cmEpLTEsQj4+Pj1hLmV4dHJhLE4tPWEuZXh0cmEsYS5iYWNrKz1hLmV4dHJhfWlmKGEub2Zmc2V0PmEuZG1heCl7ZS5tc2c9ImludmFsaWQgZGlzdGFuY2UgdG9vIGZhciBiYWNrIixhLm1vZGU9RDticmVha31hLm1vZGU9MTYyMDQ7Y2FzZSAxNjIwNDppZigwPT09YylicmVhayBlO2lmKEw9Ri1jLGEub2Zmc2V0Pkwpe2lmKChMPWEub2Zmc2V0LUwpPmEud2hhdmUmJmEuc2FuZSl7ZS5tc2c9ImludmFsaWQgZGlzdGFuY2UgdG9vIGZhciBiYWNrIixhLm1vZGU9RDticmVha31MPmEud25leHQ/KEwtPWEud25leHQsTT1hLndzaXplLUwpOk09YS53bmV4dC1MLEw+YS5sZW5ndGgmJihMPWEubGVuZ3RoKSxIPWEud2luZG93fWVsc2UgSD1zLE09Zi1hLm9mZnNldCxMPWEubGVuZ3RoO0w+YyYmKEw9YyksYy09TCxhLmxlbmd0aC09TDtkb3tzW2YrK109SFtNKytdfXdoaWxlKC0tTCk7MD09PWEubGVuZ3RoJiYoYS5tb2RlPU8pO2JyZWFrO2Nhc2UgMTYyMDU6aWYoMD09PWMpYnJlYWsgZTtzW2YrK109YS5sZW5ndGgsYy0tLGEubW9kZT1PO2JyZWFrO2Nhc2UgVTppZihhLndyYXApe2Zvcig7TjwzMjspe2lmKDA9PT1kKWJyZWFrIGU7ZC0tLEJ8PW9bbCsrXTw8TixOKz04fWlmKEYtPWMsZS50b3RhbF9vdXQrPUYsYS50b3RhbCs9Riw0JmEud3JhcCYmRiYmKGUuYWRsZXI9YS5jaGVjaz1hLmZsYWdzP24oYS5jaGVjayxzLEYsZi1GKTp0KGEuY2hlY2sscyxGLGYtRikpLEY9Yyw0JmEud3JhcCYmKGEuZmxhZ3M/QjpJKEIpKSE9PWEuY2hlY2spe2UubXNnPSJpbmNvcnJlY3QgZGF0YSBjaGVjayIsYS5tb2RlPUQ7YnJlYWt9Qj0wLE49MH1hLm1vZGU9MTYyMDc7Y2FzZSAxNjIwNzppZihhLndyYXAmJmEuZmxhZ3Mpe2Zvcig7TjwzMjspe2lmKDA9PT1kKWJyZWFrIGU7ZC0tLEIrPW9bbCsrXTw8TixOKz04fWlmKDQmYS53cmFwJiZCIT09KDQyOTQ5NjcyOTUmYS50b3RhbCkpe2UubXNnPSJpbmNvcnJlY3QgbGVuZ3RoIGNoZWNrIixhLm1vZGU9RDticmVha31CPTAsTj0wfWEubW9kZT0xNjIwODtjYXNlIDE2MjA4OlE9azticmVhayBlO2Nhc2UgRDpRPWc7YnJlYWsgZTtjYXNlIDE2MjEwOnJldHVybiBwO2RlZmF1bHQ6cmV0dXJuIHZ9cmV0dXJuIGUubmV4dF9vdXQ9ZixlLmF2YWlsX291dD1jLGUubmV4dF9pbj1sLGUuYXZhaWxfaW49ZCxhLmhvbGQ9QixhLmJpdHM9TiwoYS53c2l6ZXx8RiE9PWUuYXZhaWxfb3V0JiZhLm1vZGU8RCYmKGEubW9kZTxVfHxpIT09dSkpJiZQKGUsZS5vdXRwdXQsZS5uZXh0X291dCxGLWUuYXZhaWxfb3V0KSxDLT1lLmF2YWlsX2luLEYtPWUuYXZhaWxfb3V0LGUudG90YWxfaW4rPUMsZS50b3RhbF9vdXQrPUYsYS50b3RhbCs9Riw0JmEud3JhcCYmRiYmKGUuYWRsZXI9YS5jaGVjaz1hLmZsYWdzP24oYS5jaGVjayxzLEYsZS5uZXh0X291dC1GKTp0KGEuY2hlY2sscyxGLGUubmV4dF9vdXQtRikpLGUuZGF0YV90eXBlPWEuYml0cysoYS5sYXN0PzY0OjApKyhhLm1vZGU9PT1BPzEyODowKSsoYS5tb2RlPT09VHx8YS5tb2RlPT09Uz8yNTY6MCksKDA9PT1DJiYwPT09Rnx8aT09PXUpJiZRPT09bSYmKFE9eSksUX0saW5mbGF0ZUVuZDpmdW5jdGlvbihlKXtpZih6KGUpKXJldHVybiB2O3ZhciB0PWUuc3RhdGU7cmV0dXJuIHQud2luZG93JiYodC53aW5kb3c9bnVsbCksZS5zdGF0ZT1udWxsLG19LGluZmxhdGVHZXRIZWFkZXI6ZnVuY3Rpb24oZSx0KXtpZih6KGUpKXJldHVybiB2O3ZhciBpPWUuc3RhdGU7cmV0dXJuIDA9PSgyJmkud3JhcCk/djooaS5oZWFkPXQsdC5kb25lPSExLG0pfSxpbmZsYXRlU2V0RGljdGlvbmFyeTpmdW5jdGlvbihlLGkpe3ZhciBuLGE9aS5sZW5ndGg7cmV0dXJuIHooZSl8fDAhPT0obj1lLnN0YXRlKS53cmFwJiZuLm1vZGUhPT1SP3Y6bi5tb2RlPT09UiYmdCgxLGksYSwwKSE9PW4uY2hlY2s/ZzpQKGUsaSxhLGEpPyhuLm1vZGU9MTYyMTAscCk6KG4uaGF2ZWRpY3Q9MSxtKX0saW5mbGF0ZUluZm86InBha28gaW5mbGF0ZSAoZnJvbSBOb2RlY2EgcHJvamVjdCkifTtmdW5jdGlvbiBHKGUpe3JldHVybiBHPSJmdW5jdGlvbiI9PXR5cGVvZiBTeW1ib2wmJiJzeW1ib2wiPT10eXBlb2YgU3ltYm9sLml0ZXJhdG9yP2Z1bmN0aW9uKGUpe3JldHVybiB0eXBlb2YgZX06ZnVuY3Rpb24oZSl7cmV0dXJuIGUmJiJmdW5jdGlvbiI9PXR5cGVvZiBTeW1ib2wmJmUuY29uc3RydWN0b3I9PT1TeW1ib2wmJmUhPT1TeW1ib2wucHJvdG90eXBlPyJzeW1ib2wiOnR5cGVvZiBlfSxHKGUpfXZhciBYPWZ1bmN0aW9uKGUsdCl7cmV0dXJuIE9iamVjdC5wcm90b3R5cGUuaGFzT3duUHJvcGVydHkuY2FsbChlLHQpfSxXPWZ1bmN0aW9uKGUpe2Zvcih2YXIgdD1BcnJheS5wcm90b3R5cGUuc2xpY2UuY2FsbChhcmd1bWVudHMsMSk7dC5sZW5ndGg7KXt2YXIgaT10LnNoaWZ0KCk7aWYoaSl7aWYoIm9iamVjdCIhPT1HKGkpKXRocm93IG5ldyBUeXBlRXJyb3IoaSsibXVzdCBiZSBub24tb2JqZWN0Iik7Zm9yKHZhciBuIGluIGkpWChpLG4pJiYoZVtuXT1pW25dKX19cmV0dXJuIGV9LHE9ZnVuY3Rpb24oZSl7Zm9yKHZhciB0PTAsaT0wLG49ZS5sZW5ndGg7aTxuO2krKyl0Kz1lW2ldLmxlbmd0aDtmb3IodmFyIGE9bmV3IFVpbnQ4QXJyYXkodCkscj0wLG89MCxzPWUubGVuZ3RoO3I8cztyKyspe3ZhciBsPWVbcl07YS5zZXQobCxvKSxvKz1sLmxlbmd0aH1yZXR1cm4gYX0sSj0hMDt0cnl7U3RyaW5nLmZyb21DaGFyQ29kZS5hcHBseShudWxsLG5ldyBVaW50OEFycmF5KDEpKX1jYXRjaChlKXtKPSExfWZvcih2YXIgUT1uZXcgVWludDhBcnJheSgyNTYpLFY9MDtWPDI1NjtWKyspUVtWXT1WPj0yNTI/NjpWPj0yNDg/NTpWPj0yNDA/NDpWPj0yMjQ/MzpWPj0xOTI/MjoxO1FbMjU0XT1RWzI1NF09MTt2YXIgJD1mdW5jdGlvbihlKXtpZigiZnVuY3Rpb24iPT10eXBlb2YgVGV4dEVuY29kZXImJlRleHRFbmNvZGVyLnByb3RvdHlwZS5lbmNvZGUpcmV0dXJuKG5ldyBUZXh0RW5jb2RlcikuZW5jb2RlKGUpO3ZhciB0LGksbixhLHIsbz1lLmxlbmd0aCxzPTA7Zm9yKGE9MDthPG87YSsrKTU1Mjk2PT0oNjQ1MTImKGk9ZS5jaGFyQ29kZUF0KGEpKSkmJmErMTxvJiY1NjMyMD09KDY0NTEyJihuPWUuY2hhckNvZGVBdChhKzEpKSkmJihpPTY1NTM2KyhpLTU1Mjk2PDwxMCkrKG4tNTYzMjApLGErKykscys9aTwxMjg/MTppPDIwNDg/MjppPDY1NTM2PzM6NDtmb3IodD1uZXcgVWludDhBcnJheShzKSxyPTAsYT0wO3I8czthKyspNTUyOTY9PSg2NDUxMiYoaT1lLmNoYXJDb2RlQXQoYSkpKSYmYSsxPG8mJjU2MzIwPT0oNjQ1MTImKG49ZS5jaGFyQ29kZUF0KGErMSkpKSYmKGk9NjU1MzYrKGktNTUyOTY8PDEwKSsobi01NjMyMCksYSsrKSxpPDEyOD90W3IrK109aTppPDIwNDg/KHRbcisrXT0xOTJ8aT4+PjYsdFtyKytdPTEyOHw2MyZpKTppPDY1NTM2Pyh0W3IrK109MjI0fGk+Pj4xMix0W3IrK109MTI4fGk+Pj42JjYzLHRbcisrXT0xMjh8NjMmaSk6KHRbcisrXT0yNDB8aT4+PjE4LHRbcisrXT0xMjh8aT4+PjEyJjYzLHRbcisrXT0xMjh8aT4+PjYmNjMsdFtyKytdPTEyOHw2MyZpKTtyZXR1cm4gdH0sZWU9ZnVuY3Rpb24oZSx0KXt2YXIgaSxuLGE9dHx8ZS5sZW5ndGg7aWYoImZ1bmN0aW9uIj09dHlwZW9mIFRleHREZWNvZGVyJiZUZXh0RGVjb2Rlci5wcm90b3R5cGUuZGVjb2RlKXJldHVybihuZXcgVGV4dERlY29kZXIpLmRlY29kZShlLnN1YmFycmF5KDAsdCkpO3ZhciByPW5ldyBBcnJheSgyKmEpO2ZvcihuPTAsaT0wO2k8YTspe3ZhciBvPWVbaSsrXTtpZihvPDEyOClyW24rK109bztlbHNle3ZhciBzPVFbb107aWYocz40KXJbbisrXT02NTUzMyxpKz1zLTE7ZWxzZXtmb3IobyY9Mj09PXM/MzE6Mz09PXM/MTU6NztzPjEmJmk8YTspbz1vPDw2fDYzJmVbaSsrXSxzLS07cz4xP3JbbisrXT02NTUzMzpvPDY1NTM2P3JbbisrXT1vOihvLT02NTUzNixyW24rK109NTUyOTZ8bz4+MTAmMTAyMyxyW24rK109NTYzMjB8MTAyMyZvKX19fXJldHVybiBmdW5jdGlvbihlLHQpe2lmKHQ8NjU1MzQmJmUuc3ViYXJyYXkmJkopcmV0dXJuIFN0cmluZy5mcm9tQ2hhckNvZGUuYXBwbHkobnVsbCxlLmxlbmd0aD09PXQ/ZTplLnN1YmFycmF5KDAsdCkpO2Zvcih2YXIgaT0iIixuPTA7bjx0O24rKylpKz1TdHJpbmcuZnJvbUNoYXJDb2RlKGVbbl0pO3JldHVybiBpfShyLG4pfSx0ZT1mdW5jdGlvbihlLHQpeyh0PXR8fGUubGVuZ3RoKT5lLmxlbmd0aCYmKHQ9ZS5sZW5ndGgpO2Zvcih2YXIgaT10LTE7aT49MCYmMTI4PT0oMTkyJmVbaV0pOylpLS07cmV0dXJuIGk8MHx8MD09PWk/dDppK1FbZVtpXV0+dD9pOnR9LGllPXsyOiJuZWVkIGRpY3Rpb25hcnkiLDE6InN0cmVhbSBlbmQiLDA6IiIsIi0xIjoiZmlsZSBlcnJvciIsIi0yIjoic3RyZWFtIGVycm9yIiwiLTMiOiJkYXRhIGVycm9yIiwiLTQiOiJpbnN1ZmZpY2llbnQgbWVtb3J5IiwiLTUiOiJidWZmZXIgZXJyb3IiLCItNiI6ImluY29tcGF0aWJsZSB2ZXJzaW9uIn07dmFyIG5lPWZ1bmN0aW9uKCl7dGhpcy5pbnB1dD1udWxsLHRoaXMubmV4dF9pbj0wLHRoaXMuYXZhaWxfaW49MCx0aGlzLnRvdGFsX2luPTAsdGhpcy5vdXRwdXQ9bnVsbCx0aGlzLm5leHRfb3V0PTAsdGhpcy5hdmFpbF9vdXQ9MCx0aGlzLnRvdGFsX291dD0wLHRoaXMubXNnPSIiLHRoaXMuc3RhdGU9bnVsbCx0aGlzLmRhdGFfdHlwZT0yLHRoaXMuYWRsZXI9MH07dmFyIGFlPWZ1bmN0aW9uKCl7dGhpcy50ZXh0PTAsdGhpcy50aW1lPTAsdGhpcy54ZmxhZ3M9MCx0aGlzLm9zPTAsdGhpcy5leHRyYT1udWxsLHRoaXMuZXh0cmFfbGVuPTAsdGhpcy5uYW1lPSIiLHRoaXMuY29tbWVudD0iIix0aGlzLmhjcmM9MCx0aGlzLmRvbmU9ITF9LHJlPU9iamVjdC5wcm90b3R5cGUudG9TdHJpbmcsb2U9Yy5aX05PX0ZMVVNILHNlPWMuWl9GSU5JU0gsbGU9Yy5aX09LLGZlPWMuWl9TVFJFQU1fRU5ELGRlPWMuWl9ORUVEX0RJQ1QsaGU9Yy5aX1NUUkVBTV9FUlJPUixjZT1jLlpfREFUQV9FUlJPUix1ZT1jLlpfTUVNX0VSUk9SO2Z1bmN0aW9uIHdlKGUpe3RoaXMub3B0aW9ucz1XKHtjaHVua1NpemU6NjU1MzYsd2luZG93Qml0czoxNSx0bzoiIn0sZXx8e30pO3ZhciB0PXRoaXMub3B0aW9uczt0LnJhdyYmdC53aW5kb3dCaXRzPj0wJiZ0LndpbmRvd0JpdHM8MTYmJih0LndpbmRvd0JpdHM9LXQud2luZG93Qml0cywwPT09dC53aW5kb3dCaXRzJiYodC53aW5kb3dCaXRzPS0xNSkpLCEodC53aW5kb3dCaXRzPj0wJiZ0LndpbmRvd0JpdHM8MTYpfHxlJiZlLndpbmRvd0JpdHN8fCh0LndpbmRvd0JpdHMrPTMyKSx0LndpbmRvd0JpdHM+MTUmJnQud2luZG93Qml0czw0OCYmMD09KDE1JnQud2luZG93Qml0cykmJih0LndpbmRvd0JpdHN8PTE1KSx0aGlzLmVycj0wLHRoaXMubXNnPSIiLHRoaXMuZW5kZWQ9ITEsdGhpcy5jaHVua3M9W10sdGhpcy5zdHJtPW5ldyBuZSx0aGlzLnN0cm0uYXZhaWxfb3V0PTA7dmFyIGk9WS5pbmZsYXRlSW5pdDIodGhpcy5zdHJtLHQud2luZG93Qml0cyk7aWYoaSE9PWxlKXRocm93IG5ldyBFcnJvcihpZVtpXSk7aWYodGhpcy5oZWFkZXI9bmV3IGFlLFkuaW5mbGF0ZUdldEhlYWRlcih0aGlzLnN0cm0sdGhpcy5oZWFkZXIpLHQuZGljdGlvbmFyeSYmKCJzdHJpbmciPT10eXBlb2YgdC5kaWN0aW9uYXJ5P3QuZGljdGlvbmFyeT0kKHQuZGljdGlvbmFyeSk6IltvYmplY3QgQXJyYXlCdWZmZXJdIj09PXJlLmNhbGwodC5kaWN0aW9uYXJ5KSYmKHQuZGljdGlvbmFyeT1uZXcgVWludDhBcnJheSh0LmRpY3Rpb25hcnkpKSx0LnJhdyYmKGk9WS5pbmZsYXRlU2V0RGljdGlvbmFyeSh0aGlzLnN0cm0sdC5kaWN0aW9uYXJ5KSkhPT1sZSkpdGhyb3cgbmV3IEVycm9yKGllW2ldKX1mdW5jdGlvbiBiZShlLHQpe3ZhciBpPW5ldyB3ZSh0KTtpZihpLnB1c2goZSksaS5lcnIpdGhyb3cgaS5tc2d8fGllW2kuZXJyXTtyZXR1cm4gaS5yZXN1bHR9d2UucHJvdG90eXBlLnB1c2g9ZnVuY3Rpb24oZSx0KXt2YXIgaSxuLGEscj10aGlzLnN0cm0sbz10aGlzLm9wdGlvbnMuY2h1bmtTaXplLHM9dGhpcy5vcHRpb25zLmRpY3Rpb25hcnk7aWYodGhpcy5lbmRlZClyZXR1cm4hMTtmb3Iobj10PT09fn50P3Q6ITA9PT10P3NlOm9lLCJbb2JqZWN0IEFycmF5QnVmZmVyXSI9PT1yZS5jYWxsKGUpP3IuaW5wdXQ9bmV3IFVpbnQ4QXJyYXkoZSk6ci5pbnB1dD1lLHIubmV4dF9pbj0wLHIuYXZhaWxfaW49ci5pbnB1dC5sZW5ndGg7Oyl7Zm9yKDA9PT1yLmF2YWlsX291dCYmKHIub3V0cHV0PW5ldyBVaW50OEFycmF5KG8pLHIubmV4dF9vdXQ9MCxyLmF2YWlsX291dD1vKSwoaT1ZLmluZmxhdGUocixuKSk9PT1kZSYmcyYmKChpPVkuaW5mbGF0ZVNldERpY3Rpb25hcnkocixzKSk9PT1sZT9pPVkuaW5mbGF0ZShyLG4pOmk9PT1jZSYmKGk9ZGUpKTtyLmF2YWlsX2luPjAmJmk9PT1mZSYmci5zdGF0ZS53cmFwPjAmJjAhPT1lW3IubmV4dF9pbl07KVkuaW5mbGF0ZVJlc2V0KHIpLGk9WS5pbmZsYXRlKHIsbik7c3dpdGNoKGkpe2Nhc2UgaGU6Y2FzZSBjZTpjYXNlIGRlOmNhc2UgdWU6cmV0dXJuIHRoaXMub25FbmQoaSksdGhpcy5lbmRlZD0hMCwhMX1pZihhPXIuYXZhaWxfb3V0LHIubmV4dF9vdXQmJigwPT09ci5hdmFpbF9vdXR8fGk9PT1mZSkpaWYoInN0cmluZyI9PT10aGlzLm9wdGlvbnMudG8pe3ZhciBsPXRlKHIub3V0cHV0LHIubmV4dF9vdXQpLGY9ci5uZXh0X291dC1sLGQ9ZWUoci5vdXRwdXQsbCk7ci5uZXh0X291dD1mLHIuYXZhaWxfb3V0PW8tZixmJiZyLm91dHB1dC5zZXQoci5vdXRwdXQuc3ViYXJyYXkobCxsK2YpLDApLHRoaXMub25EYXRhKGQpfWVsc2UgdGhpcy5vbkRhdGEoci5vdXRwdXQubGVuZ3RoPT09ci5uZXh0X291dD9yLm91dHB1dDpyLm91dHB1dC5zdWJhcnJheSgwLHIubmV4dF9vdXQpKTtpZihpIT09bGV8fDAhPT1hKXtpZihpPT09ZmUpcmV0dXJuIGk9WS5pbmZsYXRlRW5kKHRoaXMuc3RybSksdGhpcy5vbkVuZChpKSx0aGlzLmVuZGVkPSEwLCEwO2lmKDA9PT1yLmF2YWlsX2luKWJyZWFrfX1yZXR1cm4hMH0sd2UucHJvdG90eXBlLm9uRGF0YT1mdW5jdGlvbihlKXt0aGlzLmNodW5rcy5wdXNoKGUpfSx3ZS5wcm90b3R5cGUub25FbmQ9ZnVuY3Rpb24oZSl7ZT09PWxlJiYoInN0cmluZyI9PT10aGlzLm9wdGlvbnMudG8/dGhpcy5yZXN1bHQ9dGhpcy5jaHVua3Muam9pbigiIik6dGhpcy5yZXN1bHQ9cSh0aGlzLmNodW5rcykpLHRoaXMuY2h1bmtzPVtdLHRoaXMuZXJyPWUsdGhpcy5tc2c9dGhpcy5zdHJtLm1zZ307dmFyIG1lPXdlLGtlPWJlLF9lPWZ1bmN0aW9uKGUsdCl7cmV0dXJuKHQ9dHx8e30pLnJhdz0hMCxiZShlLHQpfSx2ZT1iZSxnZT1jLHBlPXtJbmZsYXRlOm1lLGluZmxhdGU6a2UsaW5mbGF0ZVJhdzpfZSx1bmd6aXA6dmUsY29uc3RhbnRzOmdlfTtlLkluZmxhdGU9bWUsZS5jb25zdGFudHM9Z2UsZS5kZWZhdWx0PXBlLGUuaW5mbGF0ZT1rZSxlLmluZmxhdGVSYXc9X2UsZS51bmd6aXA9dmUsT2JqZWN0LmRlZmluZVByb3BlcnR5KGUsIl9fZXNNb2R1bGUiLHt2YWx1ZTohMH0pfSkpOwphZGRFdmVudExpc3RlbmVyKCJtZXNzYWdlIiwgZnVuY3Rpb24obykgeyB0cnkgeyBwb3N0TWVzc2FnZSh7IHN0YXR1czogInN1Y2Nlc3MiLCBkYXRhOiBwYWtvLmluZmxhdGUoby5kYXRhLCB7IHRvOiAiYXJyYXlidWZmZXIiIH0pIH0pOyB9IGNhdGNoKGV4KSB7IGxvZ2dlci5lcnJvcihleCk7IHBvc3RNZXNzYWdlKHsgc3RhdHVzOiAiZXJyb3IiIH0pOyB9IH0pOwpwb3N0TWVzc2FnZSh7IHN0YXR1czogInJlYWR5IiB9KTs=";
+			if(soSupported) {
+				theWorkerObj = new Worker(URL.createObjectURL(new Blob([base64js.toByteArray(workerSrc).buffer], { type: "text/javascript" })));
+			}else {
+				theWorkerObj = new Worker("data:text/javascript;base64," + workerSrc);
+			}
+			theWorkerObj.addEventListener("message", function(evt) {
+				if(evt.data.status === "ready") {
+					decodeBase64URL(window.eaglercraftXClientBundle, function(cbData) {
+						if(cbData) {
+							theWorkerObj.postMessage(cbData);
+						}else {
+							alert("Failed to decode eaglercraftXClientBundle base64!");
+						}
+					});
+				}else if(evt.data.status === "success") {
+					if(soSupported) {
+						window.clientScriptSrcURL = URL.createObjectURL(new Blob([evt.data.data.buffer], { type: "text/javascript;charset=utf-8" }));
+					}else {
+						window.clientScriptSrcURL = "data:text/javascript;charset=utf-8;base64," + base64js.fromByteArray(evt.data.data);
+					}
+				}else {
+					alert("Failed to decompress classes.js via legacy javascript implementation!");
+				}
+			});
+			theWorkerObj.addEventListener("error", function(evt) {
+				console.error(evt.error);
+			});
+		});
+	}else {
+		var ds = new window.DecompressionStream("gzip");
+		var result = [];
+		var fetchStream = function(reader) {
+			var processData;
+			reader.read().then(processData = function(evt) {
+				if (evt.done) {
+					(function(blobObj){
+						checkSameOriginSupport(function(supported) {
+							if(supported) {
+								window.clientScriptSrcURL = URL.createObjectURL(blobObj);
+							}else {
+								blobToArrayBuffer(blobObj, function(arr) {
+									console.log(arr);
+									window.clientScriptSrcURL = "data:text/javascript;charset=utf-8;base64," + base64js.fromByteArray(new Uint8Array(arr));
+								});
+							}
+						});
+					})(new Blob(result, { type: "text/javascript;charset=utf-8" }));
+					result = [];
+					ds = null;
+					return;
+				}
+				result.push(evt.value);
+				return reader.read().then(processData);
+			});
+		};
+		decodeBase64URL(window.eaglercraftXClientBundle, function(cbData) {
+			if(cbData) {
+				fetchStream((new Blob([cbData])).stream().pipeThrough(ds).getReader());
+			}else {
+				alert("Failed to decode eaglercraftXClientBundle base64!");
+			}
+		});
+	}
+})();
+</script>
+<script type="text/javascript">
+"use strict";
+(function(){
+	var launchInterval = -1;
+	var launchCounter = 1;
+	var launchCountdownNumberElement = null;
+	var launchCountdownProgressElement = null;
+	var launchSkipCountdown = false;
+	var launchTick = function() {
+		if(launchCounter > 100 || launchSkipCountdown) {
+			if(window.clientScriptSrcURL) {
+				clearInterval(launchInterval);
+				setTimeout(function() {
+					document.body.removeChild(document.getElementById("launch_countdown_screen"));
+					document.body.style.backgroundColor = "black";
+					var script = document.createElement("script");
+					script.type = "text/javascript";
+					script.src = window.clientScriptSrcURL;
+					window.clientScriptSrcURL = null;
+					document.head.appendChild(script);
+				}, 50);
+			}
+			return;
+		}
+		if(launchCounter === 100) {
+			document.getElementById("gameWillLaunchIn").innerText = "Decompressing...";
+		}else {
+			launchCountdownNumberElement.innerText = "" + Math.floor(6.0 - launchCounter * 0.06);
+		}
+		launchCountdownProgressElement.style.width = "" + launchCounter + "%";
+		++launchCounter;
+	};
+	window.addEventListener("load", function() {
+		launchCountdownNumberElement = document.getElementById("launchCountdownNumber");
+		launchCountdownProgressElement = document.getElementById("launchCountdownProgress");
+		launchInterval = setInterval(launchTick, 50);
+		document.getElementById("skipCountdown").addEventListener("click", function() {
+			launchSkipCountdown = true;
+			document.getElementById("gameWillLaunchIn").innerText = "Decompressing...";
+		});
+		document.getElementById("bootMenu").addEventListener("click", function() {
+			launchSkipCountdown = true;
+			document.getElementById("gameWillLaunchIn").innerText = "Decompressing...";
+			window.eaglercraftXOptsHints.showBootMenuOnLaunch = true;
+		});
+	});
+})();
+</script>
+<link type="image/png" rel="shortcut icon" href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAIAAAD8GO2jAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAAFiUAABYlAUlSJPAAAAR/SURBVEhLtZXZK3ZRFMYPcqXc+gv413DHxVuGIpIhkciQWaRccCNjSCkligwXSOZ5nmfv9zvn2e8+58V753sudmuvvdZ61l5r7XOc8H+GS/D19aUNkPz5+aktQH5/f//4+LBKZKuRkpUtQjCUYG5gD2T38vLy/PwsDfL9/f3Dw8PT05M0b29vnKLhCKCBT4L4gvBLBIei4//4+Hh1dUVEQutUuLu7E83FxQUGnKLBWKfQaA3S+AREVxaEOD8/Pzk50XpzcyMDcH19zdZG3N3d3dzc3Nvb01aX5pQUpQGGQJxcQpfNysoKhUIdHR1o1tbWbInYAgxIPDMzMy8vLzc3FxqOdMoRqwJK8G8ALUYIhHMiSEhIwI6CyIb0qQzC4eGhsXCc1tZWnZIEKzdQJQSXgKxfX18RCM3Z5eWlcfVAxKOjo+Pj49PTU88lTOk2NjbMsePc3t6SAfcgFdszOyMuAdeBg0CQi2lhYUHOeOLDCisN8FzcPFZXV3t7ezHY3t5GQ+6it+2xMASsKhEEWKsmRLRBBUpPvpJ/TpFKFBwKYAiITmicsbYhdHfJAltqhUCVsCQhwslmeXmZxiBQT9c0Ar9E2O3v72sYSE0N1yQArkKy0kBMXLqlZqIZHR3t6empqqqSDcBdhXEJSJ/bUc3q6uq+vj629GB9fR1WsLW1NTs7u7S0RN2locMjIyOEm5ubQ7+4uJienk4/+vv77Y1hwhLBEKhwWHitdVFfX9/Y2Gg2HuLi4owUAysrK8yCG97rh0+ApP5Q2ZycHFlPTExUVFRIBvn5+WhKSkp2dnaMKhptbW2426GgQ/rwuAQCZ1hwFayLiork9hMFBQV1dXVmE0BLS4vqw3QFB8kn4IAxoGPkYpxi4FeDmpqas7Mz4pClAgqGwD48rjY2NmacYqC0tJQ1KSlJWyE5OZkpUKkBAxZVIntAoZh04+Q48fHxPNGBgYHExMT29naj9cBodnZ2mo3jlJWVMeW2OGQck4B1amqqoaGhqamJjx2lGxwcpL0mUgR8fJhsWqJtSkoKU2SbHHUDpkhPBujd8xuQG6PJRM/Pz09PT7O1NNnZ2Tw3fgZkXVhYKCUlUhBATP+hCVyKZGky17RV0g04laayslJ6hlVeFHB4eFhKaogGd0LxtmTgE+hbhKDnPjMzgw8E3qGL2tpaBWpubjYqj2BoaEj6rq4uNATRZ0ZwCbiL6gXEzINk5vCBQJ9rMD4+rkA8QNK036uDg4Py8vLu7m680KjIBNR3zBDoWQM1g98snyB+VSoRW8C/UwR81/SvhgNj9JOTkwwVERUdRBEI0BAdLRVERkhLS8vIyEDQlrsTPTU1lVFhKxARvZgUlFLbegCf4BvIsbi4mIg4E5EogIHhiKCMtU0WUFiVy06j5fAJIDdSBDQw+PegDfBRcbOPwH4F9LuFWIIQdQNKwWqzIE0aoFUaBsw+SQuFw0uNtC9A+F4i3QNrbg3IDn+SAsHh+wYiEpeyBEMLv/cAO6KzAijxxB+Y4wisBhssJUhjEbPJf4Nw+B+JXqLW3bw+wQAAAABJRU5ErkJggg==" />
+</head>
+<body style="margin:0px;width:100%;height:100%;overflow:hidden;background-color:white;" id="game_frame">
+<div style="margin:0px;width:100%;height:100%;font-family:sans-serif;display:flex;align-items:center;user-select:none;" id="launch_countdown_screen">
+<div style="margin:auto;text-align:center;">
+<h1>${client_name_or_origin_date}</h1>
+<h2 id="gameWillLaunchIn">Game will launch in <span id="launchCountdownNumber">5</span>...</h2>
+<div style="border:2px solid black;width:100%;height:15px;padding:1px;margin-bottom:20vh;"><div id="launchCountdownProgress" style="background-color:#555555;width:0%;height:100%;"></div>
+<p style="margin-top:30px;"><button id="skipCountdown" autofocus>Skip Countdown</button>&emsp;<button id="bootMenu">Enter Boot Menu</button></p></div>
+</div>
+</div>
+</body>
+</html>
diff --git a/sources/resources/assets/eagler/boot_menu/offline_template_eaglercraft_1_5.html b/sources/resources/assets/eagler/boot_menu/offline_template_eaglercraft_1_5.html
new file mode 100644
index 00000000..69e7333b
--- /dev/null
+++ b/sources/resources/assets/eagler/boot_menu/offline_template_eaglercraft_1_5.html
@@ -0,0 +1,78 @@
+<!DOCTYPE html>
+
+<!--
+
+This file is from ${date}, it was generated using EaglercraftX 1.8 boot manager
+
+-->
+
+<html style="width:100%;height:100%;">
+<head>
+<meta charset="UTF-8" />
+<meta name="viewport" content="width=device-width, initial-scale=1.0" />
+<title>My Drive - Google Drive</title>
+
+<style type="eaglercraftOfflineParseHint">{"type":"EAGLERCRAFT_1_5_NEW_OFFLINE","launchConf":${launch_conf_json}}</style>
+
+<script type="text/javascript">
+window.addEventListener("load", function() {
+	countdown();
+	setTimeout(function(){
+		document.getElementById("locally").remove();
+		const relayIdMax = ${relayId_max};
+		const relayId = relayIdMax > 1 ? Math.floor(Math.random() * relayIdMax) : 0;
+		window.eaglercraftOpts = ${launch_opts};
+		window.eaglercraftOpts.container = "game_frame";
+		window.eaglercraftOpts.assetsURI = getAssetsURI();
+		window.eaglercraftOpts.serverWorkerURI = createWorkerURI("sp_worker");
+		main();
+	}, 6000);
+});
+</script>
+
+<script type="text/javascript">
+function getAssetsURI() {
+	return "data:application/octet-stream;base64,${assets_epk}";
+}
+</script>
+
+<script type="text/javascript">
+function createWorkerURI(el) {
+	var eee = document.getElementById(el);
+	var str = eee.innerHTML;
+	eee.remove();
+	str = "\"use strict\";var eaglercraftServerOpts;onmessage = function(o) { eaglercraftServerOpts = o.data; main(); };" + str;
+	return URL.createObjectURL(new Blob([str], {type:"text/javascript"}));
+}
+</script>
+
+<link type="image/png" rel="shortcut icon" href="data:image/png;base64,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" />
+
+<script type="text/javascript">
+"use strict";
+${classes_js}
+</script>
+
+<script type="text/eaglerworker" id="sp_worker">
+${classes_server_js}
+</script>
+
+<script type="text/javascript">
+function countdown() {
+	const c = document.getElementById("countdown");
+	setTimeout(function(){ c.innerText = "(Game will launch in 4)"; }, 1000);
+	setTimeout(function(){ c.innerText = "(Game will launch in 3)"; }, 2000);
+	setTimeout(function(){ c.innerText = "(Game will launch in 2)"; }, 3000);
+	setTimeout(function(){ c.innerText = "(Game will launch in 1)"; }, 4000);
+	setTimeout(function(){ c.innerText = "(Game will launch in 0)"; }, 5000);
+}
+</script>
+</head>
+<body style="margin:0px;width:100%;height:100%;font-family:sans-serif;overflow:hidden;" id="game_frame">
+<div id="locally" style="text-align:center;">
+<div style="height:5vh;"></div>
+<h2>${client_name}</h2>
+<p id="countdown" style="text-align:center;">(Game will launch in 5)</p>
+</div>
+</body>
+</html>
\ No newline at end of file
diff --git a/sources/resources/assets/eagler/boot_menu/offline_template_eaglercraft_1_5_legacy.html b/sources/resources/assets/eagler/boot_menu/offline_template_eaglercraft_1_5_legacy.html
new file mode 100644
index 00000000..0b1ef3cb
--- /dev/null
+++ b/sources/resources/assets/eagler/boot_menu/offline_template_eaglercraft_1_5_legacy.html
@@ -0,0 +1,59 @@
+<!DOCTYPE html>
+
+<!--
+
+This file is from ${date}, it was generated using EaglercraftX 1.8 boot manager
+
+-->
+
+<html style="width:100%;height:100%;">
+<head>
+<meta charset="UTF-8" />
+<meta name="viewport" content="width=device-width, initial-scale=1.0" />
+<title>${client_name}</title>
+
+<style type="eaglercraftOfflineParseHint">{"type":"EAGLERCRAFT_1_5_OLD_OFFLINE","launchConf":${launch_conf_json}}</style>
+
+<script type="text/javascript">
+window.addEventListener("load", function() {
+	countdown();
+	setTimeout(function(){
+		document.getElementById("locally").remove();
+		window.minecraftOpts = [ "game_frame", getAssetsURI(), "${launch_opts}" ];
+		main();
+	}, 6000);
+});
+</script>
+
+<script type="text/javascript">
+function getAssetsURI() {
+	return "data:application/octet-stream;base64,${assets_epk}";
+}
+</script>
+
+<link type="image/x-icon" rel="shortcut icon" href="data:image/x-icon;base64,AAABAAEAICAQAAEABADoAgAAFgAAACgAAAAgAAAAQAAAAAEABAAAAAAAgAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAACAAAAAgIAAgAAAAIAAgACAgAAAgICAAMDAwAAAAP8AAP8AAAD//wD/AAAA/wD/AP//AAD///8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAd3d3d3d3d3d3d3d3d3d3cHiIiIiIiIiIiIiIiIiIiHB4f/////////////////hweH/////////////////4cHh/////cAAHiI//////+HB4f///8REREAiIj/////hweH///3GNmREHAAAIiI/4cHh///8Y2ZmREHeqoIiI+HB4f///GNmZmRB3qqIIiIhweH///xjZmZkQd6qiIIiIcHh///8Y2ZmZEHqqoiD/+HB4f///cY2ZmRd6qqIg//hweH////EY2ZEXqqqiIP/4cHh/////cREXL6qqoiD/+HB4f////////y////Ig//hweH/////////yIiIoIP/4cHh//////////yIiIoD/+HB4f//////////yIiIn//hweH/////////////////4cHh/////////////////+HB4d3d3d3d3d3d3d3d3d3hweIiIiIiIiIiIiIiIiIiIcHhMwiRERERERERAAAAAAHB4TsokRERERERESICICIBweEETNEREREREREiAiAiAcHhJGzRERERERERERERERHB4iIiIiIiIiIiIiIiIiIhwd3d3d3d3d3d3d3d3d3d3cAAAAAAAAAAAAAAAAAAAAAD//////////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/////w==" />
+
+<script type="text/javascript">
+"use strict";
+${classes_js}
+</script>
+
+<script type="text/javascript">
+function countdown() {
+	const c = document.getElementById("countdown");
+	setTimeout(function(){ c.innerText = "(Game will launch in 4)"; }, 1000);
+	setTimeout(function(){ c.innerText = "(Game will launch in 3)"; }, 2000);
+	setTimeout(function(){ c.innerText = "(Game will launch in 2)"; }, 3000);
+	setTimeout(function(){ c.innerText = "(Game will launch in 1)"; }, 4000);
+	setTimeout(function(){ c.innerText = "(Game will launch in 0)"; }, 5000);
+}
+</script>
+</head>
+<body style="margin:0px;width:100%;height:100%;font-family:sans-serif;overflow:hidden;" id="game_frame">
+<div id="locally" style="text-align:center;">
+<div style="height:5vh;"></div>
+<h2>${client_name}</h2>
+<p id="countdown" style="text-align:center;">(Game will launch in 5)</p>
+</div>
+</body>
+</html>
\ No newline at end of file
diff --git a/sources/resources/assets/eagler/boot_menu/offline_template_eaglercraft_b1_3.html b/sources/resources/assets/eagler/boot_menu/offline_template_eaglercraft_b1_3.html
new file mode 100644
index 00000000..c060bb33
--- /dev/null
+++ b/sources/resources/assets/eagler/boot_menu/offline_template_eaglercraft_b1_3.html
@@ -0,0 +1,59 @@
+<!DOCTYPE html>
+
+<!--
+
+This file is from ${date}, it was generated using EaglercraftX 1.8 boot manager
+
+-->
+
+<html style="width:100%;height:100%;">
+<head>
+<meta charset="UTF-8" />
+<meta name="viewport" content="width=device-width, initial-scale=1.0" />
+<title>${client_name}</title>
+
+<style type="eaglercraftOfflineParseHint">{"type":"EAGLERCRAFT_BETA_B1_3_OFFLINE","launchConf":${launch_conf_json}}</style>
+
+<script type="text/javascript">
+window.addEventListener("load", function() {
+	countdown();
+	setTimeout(function(){
+		document.getElementById("locally").remove();
+		window.minecraftOpts = [ "game_frame", getAssetsURI() ];
+		main();
+	}, 6000);
+});
+</script>
+
+<script type="text/javascript">
+function getAssetsURI() {
+	return "data:application/octet-stream;base64,${assets_epk}";
+}
+</script>
+
+<link type="image/x-icon" rel="shortcut icon" href="data:image/x-icon;base64,AAABAAEAICAQAAEABADoAgAAFgAAACgAAAAgAAAAQAAAAAEABAAAAAAAgAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAACAAAAAgIAAgAAAAIAAgACAgAAAgICAAMDAwAAAAP8AAP8AAAD//wD/AAAA/wD/AP//AAD///8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAd3d3d3d3d3d3d3d3d3d3cHiIiIiIiIiIiIiIiIiIiHB4f/////////////////hweH/////////////////4cHh/////cAAHiI//////+HB4f///8REREAiIj/////hweH///3GNmREHAAAIiI/4cHh///8Y2ZmREHeqoIiI+HB4f///GNmZmRB3qqIIiIhweH///xjZmZkQd6qiIIiIcHh///8Y2ZmZEHqqoiD/+HB4f///cY2ZmRd6qqIg//hweH////EY2ZEXqqqiIP/4cHh/////cREXL6qqoiD/+HB4f////////y////Ig//hweH/////////yIiIoIP/4cHh//////////yIiIoD/+HB4f//////////yIiIn//hweH/////////////////4cHh/////////////////+HB4d3d3d3d3d3d3d3d3d3hweIiIiIiIiIiIiIiIiIiIcHhMwiRERERERERAAAAAAHB4TsokRERERERESICICIBweEETNEREREREREiAiAiAcHhJGzRERERERERERERERHB4iIiIiIiIiIiIiIiIiIhwd3d3d3d3d3d3d3d3d3d3cAAAAAAAAAAAAAAAAAAAAAD//////////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/////w==" />
+
+<script type="text/javascript">
+"use strict";
+${classes_js}
+</script>
+
+<script type="text/javascript">
+function countdown() {
+	const c = document.getElementById("countdown");
+	setTimeout(function(){ c.innerText = "(Game will launch in 4)"; }, 1000);
+	setTimeout(function(){ c.innerText = "(Game will launch in 3)"; }, 2000);
+	setTimeout(function(){ c.innerText = "(Game will launch in 2)"; }, 3000);
+	setTimeout(function(){ c.innerText = "(Game will launch in 1)"; }, 4000);
+	setTimeout(function(){ c.innerText = "(Game will launch in 0)"; }, 5000);
+}
+</script>
+</head>
+<body style="margin:0px;width:100%;height:100%;font-family:sans-serif;overflow:hidden;" id="game_frame">
+<div id="locally" style="text-align:center;">
+<div style="height:5vh;"></div>
+<h2>${client_name}</h2>
+<p id="countdown" style="text-align:center;">(Game will launch in 5)</p>
+</div>
+</body>
+</html>
\ No newline at end of file
diff --git a/sources/resources/assets/eagler/boot_menu/offline_template_peytonplayz585_a_b.html b/sources/resources/assets/eagler/boot_menu/offline_template_peytonplayz585_a_b.html
new file mode 100644
index 00000000..d1cb8d2b
--- /dev/null
+++ b/sources/resources/assets/eagler/boot_menu/offline_template_peytonplayz585_a_b.html
@@ -0,0 +1,40 @@
+<!DOCTYPE html>
+
+<!--
+
+This file is from ${date}, it was generated using EaglercraftX 1.8 boot manager
+
+-->
+
+<html style="width:100%;height:100%;">
+<head>
+<meta charset="UTF-8" />
+<meta name="viewport" content="width=device-width, initial-scale=1.0" />
+<title>${client_name}</title>
+
+<style type="eaglercraftOfflineParseHint">{"type":"PEYTONPLAYZ585_ALPHA_BETA","launchConf":${launch_conf_json}}</style>
+
+<script type="text/javascript">
+window.addEventListener("load", function() {
+	window.config = ${launch_opts};
+	window.config.gameContainer = "game_frame";
+	window.config.assetsLocation = getAssetsURI();
+	main();
+});
+</script>
+
+<script type="text/javascript">
+function getAssetsURI() {
+	return "data:application/octet-stream;base64,${assets_epk}";
+}
+</script>
+
+<script type="text/javascript">
+"use strict";
+${classes_js}
+</script>
+
+</head>
+<body style="margin:0px;width:100%;height:100%;overflow:hidden;" id="game_frame">
+</body>
+</html>
\ No newline at end of file
diff --git a/sources/resources/assets/eagler/boot_menu/offline_template_peytonplayz585_indev.html b/sources/resources/assets/eagler/boot_menu/offline_template_peytonplayz585_indev.html
new file mode 100644
index 00000000..6abcb13e
--- /dev/null
+++ b/sources/resources/assets/eagler/boot_menu/offline_template_peytonplayz585_indev.html
@@ -0,0 +1,38 @@
+<!DOCTYPE html>
+
+<!--
+
+This file is from ${date}, it was generated using EaglercraftX 1.8 boot manager
+
+-->
+
+<html style="width:100%;height:100%;">
+<head>
+<meta charset="UTF-8" />
+<meta name="viewport" content="width=device-width, initial-scale=1.0" />
+<title>${client_name}</title>
+
+<style type="eaglercraftOfflineParseHint">{"type":"PEYTONPLAYZ585_INDEV","launchConf":${launch_conf_json}}</style>
+
+<script type="text/javascript">
+window.addEventListener("load", function() {
+	window.classicConfig = [ "game_frame", getAssetsURI() ];
+	main();
+});
+</script>
+
+<script type="text/javascript">
+function getAssetsURI() {
+	return "data:application/octet-stream;base64,${assets_epk}";
+}
+</script>
+
+<script type="text/javascript">
+"use strict";
+${classes_js}
+</script>
+
+</head>
+<body style="margin:0px;width:100%;height:100%;overflow:hidden;" id="game_frame">
+</body>
+</html>
\ No newline at end of file
diff --git a/sources/resources/assets/eagler/boot_menu/offline_template_standard_offline.html b/sources/resources/assets/eagler/boot_menu/offline_template_standard_offline.html
new file mode 100644
index 00000000..cf505c67
--- /dev/null
+++ b/sources/resources/assets/eagler/boot_menu/offline_template_standard_offline.html
@@ -0,0 +1,77 @@
+<!DOCTYPE html>
+
+<!--
+
+This file is from ${date}, it was generated using EaglercraftX 1.8 boot manager
+
+-->
+
+<html style="width:100%;height:100%;">
+<head>
+<meta charset="UTF-8" />
+<meta name="viewport" content="width=device-width, initial-scale=1.0" />
+<meta name="description" content="${client_name}" />
+<meta name="keywords" content="eaglercraft, eaglercraftx, minecraft, 1.8, 1.8.8" />
+<title>${client_name}</title>
+<meta property="og:locale" content="en-US" />
+<meta property="og:type" content="website" />
+<meta property="og:title" content="${client_name}" />
+<meta property="og:description" content="this file is not a website, whoever uploaded it to this URL is a dumbass" />
+<style type="eaglercraftOfflineParseHint">{"type":"EXPORTED_STANDARD_OFFLINE","launchConf":${launch_conf_json}}</style>
+<script type="text/javascript">
+"use strict";
+const relayIdMax = ${relayId_max};
+const relayId = relayIdMax > 1 ? Math.floor(Math.random() * relayIdMax) : 0;
+
+// %%%%%%%%% launch options %%%%%%%%%%%%
+
+window["${launch_opts_var_name}"] = ${launch_opts};
+
+// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+</script>
+<script type="text/javascript">
+"use strict";
+if(typeof window !== "undefined") window.eaglercraftXClientScriptElement = document.currentScript;
+
+${classes_js}
+</script>
+<script type="text/javascript">
+"use strict";
+(function(){
+	window["${launch_opts_var_name}"]["${launch_opts_var_container_name}"] = "game_frame";
+	window["${launch_opts_var_name}"]["${launch_opts_var_assetsURI_name}"] = /*{:BEGIN_ASSETS_EPK:}*/${assets_epk}/*{:END_ASSETS_EPK:}*/;
+
+	var launchInterval = -1;
+	var launchCounter = 1;
+	var launchCountdownNumberElement = null;
+	var launchCountdownProgressElement = null;
+
+	function launchTick() {
+		launchCountdownNumberElement.innerText = "" + Math.floor(6.0 - launchCounter * 0.06);
+		launchCountdownProgressElement.style.width = "" + launchCounter + "%";
+		if(++launchCounter > 100) {
+			clearInterval(launchInterval);
+			setTimeout(() => { document.getElementById("launch_countdown_screen").remove(); window["${main_function_name}"](); }, 50);
+		}
+	}
+
+	window.addEventListener("load", () => {
+		launchCountdownNumberElement = document.getElementById("launchCountdownNumber");
+		launchCountdownProgressElement = document.getElementById("launchCountdownProgress");
+		launchInterval = setInterval(launchTick, 50);
+	});
+})();
+</script>
+<link type="image/png" rel="shortcut icon" href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAIAAAD8GO2jAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAAFiUAABYlAUlSJPAAAAR/SURBVEhLtZXZK3ZRFMYPcqXc+gv413DHxVuGIpIhkciQWaRccCNjSCkligwXSOZ5nmfv9zvn2e8+58V753sudmuvvdZ61l5r7XOc8H+GS/D19aUNkPz5+aktQH5/f//4+LBKZKuRkpUtQjCUYG5gD2T38vLy/PwsDfL9/f3Dw8PT05M0b29vnKLhCKCBT4L4gvBLBIei4//4+Hh1dUVEQutUuLu7E83FxQUGnKLBWKfQaA3S+AREVxaEOD8/Pzk50XpzcyMDcH19zdZG3N3d3dzc3Nvb01aX5pQUpQGGQJxcQpfNysoKhUIdHR1o1tbWbInYAgxIPDMzMy8vLzc3FxqOdMoRqwJK8G8ALUYIhHMiSEhIwI6CyIb0qQzC4eGhsXCc1tZWnZIEKzdQJQSXgKxfX18RCM3Z5eWlcfVAxKOjo+Pj49PTU88lTOk2NjbMsePc3t6SAfcgFdszOyMuAdeBg0CQi2lhYUHOeOLDCisN8FzcPFZXV3t7ezHY3t5GQ+6it+2xMASsKhEEWKsmRLRBBUpPvpJ/TpFKFBwKYAiITmicsbYhdHfJAltqhUCVsCQhwslmeXmZxiBQT9c0Ar9E2O3v72sYSE0N1yQArkKy0kBMXLqlZqIZHR3t6empqqqSDcBdhXEJSJ/bUc3q6uq+vj629GB9fR1WsLW1NTs7u7S0RN2locMjIyOEm5ubQ7+4uJienk4/+vv77Y1hwhLBEKhwWHitdVFfX9/Y2Gg2HuLi4owUAysrK8yCG97rh0+ApP5Q2ZycHFlPTExUVFRIBvn5+WhKSkp2dnaMKhptbW2426GgQ/rwuAQCZ1hwFayLiork9hMFBQV1dXVmE0BLS4vqw3QFB8kn4IAxoGPkYpxi4FeDmpqas7Mz4pClAgqGwD48rjY2NmacYqC0tJQ1KSlJWyE5OZkpUKkBAxZVIntAoZh04+Q48fHxPNGBgYHExMT29naj9cBodnZ2mo3jlJWVMeW2OGQck4B1amqqoaGhqamJjx2lGxwcpL0mUgR8fJhsWqJtSkoKU2SbHHUDpkhPBujd8xuQG6PJRM/Pz09PT7O1NNnZ2Tw3fgZkXVhYKCUlUhBATP+hCVyKZGky17RV0g04laayslJ6hlVeFHB4eFhKaogGd0LxtmTgE+hbhKDnPjMzgw8E3qGL2tpaBWpubjYqj2BoaEj6rq4uNATRZ0ZwCbiL6gXEzINk5vCBQJ9rMD4+rkA8QNK036uDg4Py8vLu7m680KjIBNR3zBDoWQM1g98snyB+VSoRW8C/UwR81/SvhgNj9JOTkwwVERUdRBEI0BAdLRVERkhLS8vIyEDQlrsTPTU1lVFhKxARvZgUlFLbegCf4BvIsbi4mIg4E5EogIHhiKCMtU0WUFiVy06j5fAJIDdSBDQw+PegDfBRcbOPwH4F9LuFWIIQdQNKwWqzIE0aoFUaBsw+SQuFw0uNtC9A+F4i3QNrbg3IDn+SAsHh+wYiEpeyBEMLv/cAO6KzAijxxB+Y4wisBhssJUhjEbPJf4Nw+B+JXqLW3bw+wQAAAABJRU5ErkJggg==" />
+</head>
+<body style="margin:0px;width:100%;height:100%;overflow:hidden;" id="game_frame">
+<div style="margin:0px;width:100%;height:100%;font-family:sans-serif;display:flex;align-items:center;user-select:none;" id="launch_countdown_screen">
+<div style="margin:auto;text-align:center;">
+<h1>${client_name}</h1>
+<h2>Game will launch in <span id="launchCountdownNumber">5</span>...</h2>
+<div style="border:2px solid black;width:100%;height:15px;padding:1px;margin-bottom:20vh;"><div id="launchCountdownProgress" style="background-color:#555555;width:0%;height:100%;"></div></div>
+</div>
+</div>
+</body>
+</html>
diff --git a/sources/resources/assets/eagler/boot_menu/opts_template_eaglercraftX_1_8.txt b/sources/resources/assets/eagler/boot_menu/opts_template_eaglercraftX_1_8.txt
new file mode 100644
index 00000000..0b43e98e
--- /dev/null
+++ b/sources/resources/assets/eagler/boot_menu/opts_template_eaglercraftX_1_8.txt
@@ -0,0 +1,66 @@
+{
+	"joinServer": null,
+	"servers": [
+		{
+			"addr": "ws://localhost:8081/",
+			"hideAddr": false,
+			"name": "Local test server"
+		}
+	],
+	"relays": [
+		{
+			"addr": "wss://relay.deev.is/",
+			"primary": "$random_relay_primary_0",
+			"comment": "lax1dude relay #1"
+		},
+		{
+			"addr": "wss://relay.lax1dude.net/",
+			"primary": "$random_relay_primary_1",
+			"comment": "lax1dude relay #2"
+		},
+		{
+			"addr": "wss://relay.shhnowisnottheti.me/",
+			"primary": "$random_relay_primary_2",
+			"comment": "ayunami relay #1"
+		}
+	],
+	"openDebugConsoleOnLaunch": false,
+	"showBootMenuOnLaunch": false,
+	"bootMenuBlocksUnsignedClients": false,
+	"allowBootMenu": true,
+	"forceWebViewSupport": false,
+	"enableServerCookies": true,
+	"enableDownloadOfflineButton": true,
+	"resourcePacksDB": "resourcePacks",
+	"enableWebViewCSP": true,
+	"checkRelaysForUpdates": true,
+	"allowServerRedirects": true,
+	"allowUpdateSvc": true,
+	"html5CursorSupport": false,
+	"allowFNAWSkins": true,
+	"allowVoiceClient": true,
+	"worldsDB": "worlds",
+	"demoMode": false,
+	"localStorageNamespace": "_eaglercraftX",
+	"enableSignatureBadge": false,
+	"lang": "en_US",
+	"enableMinceraft": true,
+	"autoFixLegacyStyleAttr": true,
+	"allowUpdateDL": true,
+	"logInvalidCerts": false,
+	"checkShaderGLErrors": false,
+	"crashOnUncaughtExceptions": false,
+	"forceWebGL1": false,
+	"forceWebGL2": false,
+	"allowExperimentalWebGL1": true,
+	"useWebGLExt": true,
+	"useDelayOnSwap": false,
+	"useJOrbisAudioDecoder": false,
+	"useXHRFetch": false,
+	"useVisualViewport": true,
+	"deobfStackTraces": true,
+	"disableBlobURLs": false,
+	"eaglerNoDelay": false,
+	"ramdiskMode": false,
+	"singleThreadMode": false
+}
\ No newline at end of file
diff --git a/sources/resources/assets/eagler/boot_menu/opts_template_eaglercraftX_1_8_demo.txt b/sources/resources/assets/eagler/boot_menu/opts_template_eaglercraftX_1_8_demo.txt
new file mode 100644
index 00000000..e801ad14
--- /dev/null
+++ b/sources/resources/assets/eagler/boot_menu/opts_template_eaglercraftX_1_8_demo.txt
@@ -0,0 +1,66 @@
+{
+	"joinServer": null,
+	"servers": [
+		{
+			"addr": "ws://localhost:8081/",
+			"hideAddr": false,
+			"name": "Local test server"
+		}
+	],
+	"relays": [
+		{
+			"addr": "wss://relay.deev.is/",
+			"primary": "$random_relay_primary_0",
+			"comment": "lax1dude relay #1"
+		},
+		{
+			"addr": "wss://relay.lax1dude.net/",
+			"primary": "$random_relay_primary_1",
+			"comment": "lax1dude relay #2"
+		},
+		{
+			"addr": "wss://relay.shhnowisnottheti.me/",
+			"primary": "$random_relay_primary_2",
+			"comment": "ayunami relay #1"
+		}
+	],
+	"openDebugConsoleOnLaunch": false,
+	"showBootMenuOnLaunch": false,
+	"bootMenuBlocksUnsignedClients": false,
+	"allowBootMenu": true,
+	"forceWebViewSupport": false,
+	"enableServerCookies": true,
+	"enableDownloadOfflineButton": true,
+	"resourcePacksDB": "resourcePacks",
+	"enableWebViewCSP": true,
+	"checkRelaysForUpdates": true,
+	"allowServerRedirects": true,
+	"allowUpdateSvc": true,
+	"html5CursorSupport": false,
+	"allowFNAWSkins": true,
+	"allowVoiceClient": true,
+	"worldsDB": "worlds",
+	"demoMode": true,
+	"localStorageNamespace": "_eaglercraftX",
+	"enableSignatureBadge": false,
+	"lang": "en_US",
+	"enableMinceraft": true,
+	"autoFixLegacyStyleAttr": true,
+	"allowUpdateDL": true,
+	"logInvalidCerts": false,
+	"checkShaderGLErrors": false,
+	"crashOnUncaughtExceptions": false,
+	"forceWebGL1": false,
+	"forceWebGL2": false,
+	"allowExperimentalWebGL1": true,
+	"useWebGLExt": true,
+	"useDelayOnSwap": false,
+	"useJOrbisAudioDecoder": false,
+	"useXHRFetch": false,
+	"useVisualViewport": true,
+	"deobfStackTraces": true,
+	"disableBlobURLs": false,
+	"eaglerNoDelay": false,
+	"ramdiskMode": false,
+	"singleThreadMode": false
+}
\ No newline at end of file
diff --git a/sources/resources/assets/eagler/boot_menu/opts_template_eaglercraftX_1_8_html5Cursors.txt b/sources/resources/assets/eagler/boot_menu/opts_template_eaglercraftX_1_8_html5Cursors.txt
new file mode 100644
index 00000000..ce8c63fd
--- /dev/null
+++ b/sources/resources/assets/eagler/boot_menu/opts_template_eaglercraftX_1_8_html5Cursors.txt
@@ -0,0 +1,66 @@
+{
+	"joinServer": null,
+	"servers": [
+		{
+			"addr": "ws://localhost:8081/",
+			"hideAddr": false,
+			"name": "Local test server"
+		}
+	],
+	"relays": [
+		{
+			"addr": "wss://relay.deev.is/",
+			"primary": "$random_relay_primary_0",
+			"comment": "lax1dude relay #1"
+		},
+		{
+			"addr": "wss://relay.lax1dude.net/",
+			"primary": "$random_relay_primary_1",
+			"comment": "lax1dude relay #2"
+		},
+		{
+			"addr": "wss://relay.shhnowisnottheti.me/",
+			"primary": "$random_relay_primary_2",
+			"comment": "ayunami relay #1"
+		}
+	],
+	"openDebugConsoleOnLaunch": false,
+	"showBootMenuOnLaunch": false,
+	"bootMenuBlocksUnsignedClients": false,
+	"allowBootMenu": true,
+	"forceWebViewSupport": false,
+	"enableServerCookies": true,
+	"enableDownloadOfflineButton": true,
+	"resourcePacksDB": "resourcePacks",
+	"enableWebViewCSP": true,
+	"checkRelaysForUpdates": true,
+	"allowServerRedirects": true,
+	"allowUpdateSvc": true,
+	"html5CursorSupport": true,
+	"allowFNAWSkins": true,
+	"allowVoiceClient": true,
+	"worldsDB": "worlds",
+	"demoMode": false,
+	"localStorageNamespace": "_eaglercraftX",
+	"enableSignatureBadge": false,
+	"lang": "en_US",
+	"enableMinceraft": true,
+	"autoFixLegacyStyleAttr": true,
+	"allowUpdateDL": true,
+	"logInvalidCerts": false,
+	"checkShaderGLErrors": false,
+	"crashOnUncaughtExceptions": false,
+	"forceWebGL1": false,
+	"forceWebGL2": false,
+	"allowExperimentalWebGL1": true,
+	"useWebGLExt": true,
+	"useDelayOnSwap": false,
+	"useJOrbisAudioDecoder": false,
+	"useXHRFetch": false,
+	"useVisualViewport": true,
+	"deobfStackTraces": true,
+	"disableBlobURLs": false,
+	"eaglerNoDelay": false,
+	"ramdiskMode": false,
+	"singleThreadMode": false
+}
\ No newline at end of file
diff --git a/sources/resources/assets/eagler/boot_menu/opts_template_eaglercraft_1_5.txt b/sources/resources/assets/eagler/boot_menu/opts_template_eaglercraft_1_5.txt
new file mode 100644
index 00000000..d439dfbb
--- /dev/null
+++ b/sources/resources/assets/eagler/boot_menu/opts_template_eaglercraft_1_5.txt
@@ -0,0 +1,52 @@
+{
+	"joinServer": null,
+	"servers": [
+		{
+			"serverName": "Local Test Server",
+			"serverAddress": "localhost:25565",
+			"hideAddress": false
+		}
+	],
+	"relays": [
+		{
+			"addr": "wss://relay.deev.is/",
+			"name": "lax1dude relay #1",
+			"primary": "$random_relay_primary_0"
+		},
+		{
+			"addr": "wss://relay.lax1dude.net/",
+			"name": "lax1dude relay #2",
+			"primary": "$random_relay_primary_1"
+		},
+		{
+			"addr": "wss://relay.shhnowisnottheti.me/",
+			"name": "ayunami relay #1",
+			"primary": "$random_relay_primary_2"
+		}
+	],
+	"mainMenu": {
+		"splashes": [
+			"Darviglet!",
+			"eaglerenophile!",
+			"You Eagler!",
+			"Yeeeeeee!",
+			"yeee",
+			"EEEEEEEEE!",
+			"You Darvig!",
+			"You Vigg!",
+			":>",
+			"|>",
+			"You Yumpster!"
+		],
+		"eaglerLogo": false,
+		"itemLink": null,
+		"itemLine0": null,
+		"itemLine1": null,
+		"itemLine2": null
+	},
+	"worldsFolder": "MAIN",
+	"profanity": false,
+	"hideDownServers": false,
+	"serverListTitle": null,
+	"serverListLink": null
+}
\ No newline at end of file
diff --git a/sources/resources/assets/eagler/boot_menu/opts_template_eaglercraft_1_5_legacy.txt b/sources/resources/assets/eagler/boot_menu/opts_template_eaglercraft_1_5_legacy.txt
new file mode 100644
index 00000000..d3ebf139
--- /dev/null
+++ b/sources/resources/assets/eagler/boot_menu/opts_template_eaglercraft_1_5_legacy.txt
@@ -0,0 +1,32 @@
+[NBT]{
+	servers: [
+		{
+			name: "Local Test Server",
+			ip: "localhost:25565",
+			hideAddress: false
+		}
+	],
+	mainMenu: {
+		itemLink: "",
+		itemLine0: "",
+		itemLine1: "",
+		itemLine2: "",
+		splashes: [
+			"Darviglet!",
+			"eaglerenophile!",
+			"You Eagler!",
+			"Yeeeeeee!",
+			"yeee",
+			"EEEEEEEEE!",
+			"You Darvig!",
+			"You Vigg!",
+			":>",
+			"|>",
+			"You Yumpster!"
+		]
+	},
+	profanity: false,
+	hide_down: false,
+	serverListTitle: "",
+	serverListLink: ""
+}[/NBT]
\ No newline at end of file
diff --git a/sources/resources/assets/eagler/boot_menu/opts_template_eaglercraft_1_5_livestream.txt b/sources/resources/assets/eagler/boot_menu/opts_template_eaglercraft_1_5_livestream.txt
new file mode 100644
index 00000000..74cd7e2a
--- /dev/null
+++ b/sources/resources/assets/eagler/boot_menu/opts_template_eaglercraft_1_5_livestream.txt
@@ -0,0 +1,63 @@
+{
+	"joinServer": null,
+	"servers": [
+		{
+			"serverName": "Local Test Server",
+			"serverAddress": "localhost:25565",
+			"hideAddress": false
+		}
+	],
+	"relays": [
+		{
+			"addr": "wss://relay.deev.is/",
+			"name": "lax1dude relay #1",
+			"primary": "$random_relay_primary_0"
+		},
+		{
+			"addr": "wss://relay.lax1dude.net/",
+			"name": "lax1dude relay #2",
+			"primary": "$random_relay_primary_1"
+		},
+		{
+			"addr": "wss://relay.shhnowisnottheti.me/",
+			"name": "ayunami relay #1",
+			"primary": "$random_relay_primary_2"
+		}
+	],
+	"mainMenu": {
+		"splashes": [
+			"Darviglet!",
+			"eaglerenophile!",
+			"You Eagler!",
+			"Yeeeeeee!",
+			"yeee",
+			"EEEEEEEEE!",
+			"You Darvig!",
+			"You Vigg!",
+			":>",
+			"|>",
+			"You Yumpster!"
+		],
+		"eaglerLogo": false,
+		"itemLink": null,
+		"itemLine0": null,
+		"itemLine1": null,
+		"itemLine2": null
+	},
+	"worldsFolder": "MAIN",
+	"assetOverrides": {
+		"title/no-pano-blur.flag": "false",
+		"records/wait.mp3": "wait.mp3",
+		"records/mellohi.mp3": "https://stream.nightride.fm/chillsynth.m4a",
+		"records/far.mp3": "https://stream.nightride.fm/nightride.m4a",
+		"records/cat.mp3": "http://usa9.fastcast4u.com/proxy/jamz?mp=/1",
+		"records/ward.mp3": "http://fr4.1mix.co.uk:8000/192h",
+		"records/strad.mp3": "http://listen.011fm.com:8028/stream15",
+		"records/blocks.mp3": "https://www.ophanim.net:8444/s/9780",
+		"records/13.mp3": "https://s2.radio.co/s2b2b68744/listen"
+	},
+	"profanity": false,
+	"hideDownServers": false,
+	"serverListTitle": null,
+	"serverListLink": null
+}
\ No newline at end of file
diff --git a/sources/resources/assets/eagler/boot_menu/opts_template_peytonplayz585_a1_2_6.txt b/sources/resources/assets/eagler/boot_menu/opts_template_peytonplayz585_a1_2_6.txt
new file mode 100644
index 00000000..f26221fe
--- /dev/null
+++ b/sources/resources/assets/eagler/boot_menu/opts_template_peytonplayz585_a1_2_6.txt
@@ -0,0 +1,6 @@
+{
+	"dataBaseName": "_net_PeytonPlayz585_eaglercraft_Alpha_IndexedDBFilesystem_1_2_6",
+	"playerUsername": null,
+	"serverIP": null,
+	"joinServerOnLaunch": null
+}
\ No newline at end of file
diff --git a/sources/resources/assets/eagler/boot_menu/opts_template_peytonplayz585_b1_7_3.txt b/sources/resources/assets/eagler/boot_menu/opts_template_peytonplayz585_b1_7_3.txt
new file mode 100644
index 00000000..abda3bdb
--- /dev/null
+++ b/sources/resources/assets/eagler/boot_menu/opts_template_peytonplayz585_b1_7_3.txt
@@ -0,0 +1,6 @@
+{
+	"dataBaseName": "_net_PeytonPlayz585_eaglercraft_beta_IndexedDBFilesystem_1_7_3",
+	"playerUsername": null,
+	"serverIP": null,
+	"joinServerOnLaunch": null
+}
\ No newline at end of file
diff --git a/sources/resources/assets/eagler/boot_menu/web_cl_eagleiii_8x16.woff b/sources/resources/assets/eagler/boot_menu/web_cl_eagleiii_8x16.woff
new file mode 100644
index 0000000000000000000000000000000000000000..f0e9430a3027b0d4be6613f4b9db057fb1d6aba3
GIT binary patch
literal 9876
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

literal 0
HcmV?d00001

diff --git a/sources/resources/assets/eagler/glsl/accel_font.fsh b/sources/resources/assets/eagler/glsl/accel_font.fsh
index 6d1c80ad..10bb5b1e 100644
--- a/sources/resources/assets/eagler/glsl/accel_font.fsh
+++ b/sources/resources/assets/eagler/glsl/accel_font.fsh
@@ -1,7 +1,7 @@
 #line 2
 
 /*
- * Copyright (c) 2022-2023 lax1dude. All Rights Reserved.
+ * Copyright (c) 2022-2024 lax1dude. All Rights Reserved.
  * 
  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
@@ -16,21 +16,17 @@
  * 
  */
 
-precision lowp int;
-precision mediump float;
-precision mediump sampler2D;
+EAGLER_IN(vec2, v_texCoord2f)
+EAGLER_IN(vec4, v_color4f)
 
-in vec2 v_texCoord2f;
-in vec4 v_color4f;
-
-layout(location = 0) out vec4 output4f;
+EAGLER_FRAG_OUT()
 
 uniform sampler2D u_inputTexture;
 uniform vec4 u_colorBias4f;
 
 void main() {
-	output4f = texture(u_inputTexture, v_texCoord2f) * v_color4f + u_colorBias4f;
-	if(output4f.a < 0.004) {
+	EAGLER_FRAG_COLOR = EAGLER_TEXTURE_2D(u_inputTexture, v_texCoord2f) * v_color4f + u_colorBias4f;
+	if(EAGLER_FRAG_COLOR.a < 0.004) {
 		discard;
 	}
 }
diff --git a/sources/resources/assets/eagler/glsl/accel_font.vsh b/sources/resources/assets/eagler/glsl/accel_font.vsh
index 50a99ccd..8a274fad 100644
--- a/sources/resources/assets/eagler/glsl/accel_font.vsh
+++ b/sources/resources/assets/eagler/glsl/accel_font.vsh
@@ -1,7 +1,7 @@
 #line 2
 
 /*
- * Copyright (c) 2022-2023 lax1dude. All Rights Reserved.
+ * Copyright (c) 2022-2024 lax1dude. All Rights Reserved.
  * 
  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
@@ -16,18 +16,15 @@
  * 
  */
 
-precision lowp int;
-precision highp float;
-precision mediump sampler2D;
+EAGLER_VSH_LAYOUT_BEGIN()
+EAGLER_IN(0, vec3, a_position3f)
+EAGLER_IN(1, vec2, c_position2i)
+EAGLER_IN(2, vec2, c_coords2i)
+EAGLER_IN(3, vec4, c_color4f)
+EAGLER_VSH_LAYOUT_END()
 
-layout(location = 0) in vec3 a_position3f;
-
-layout(location = 1) in vec2 c_position2i;
-layout(location = 2) in vec2 c_coords2i;
-layout(location = 3) in vec4 c_color4f;
-
-out vec2 v_texCoord2f;
-out vec4 v_color4f;
+EAGLER_OUT(vec2, v_texCoord2f)
+EAGLER_OUT(vec4, v_color4f)
 
 uniform mat4 u_matrixTransform;
 uniform vec2 u_charSize2f;
@@ -49,5 +46,5 @@ void main() {
 	pos2d.x -= (a_position3f.y - 0.5) * italicBit;
 	v_color4f.a *= 2.0;
 	v_color4f *= u_color4f;
-	gl_Position = u_matrixTransform * vec4(pos2d, 0.0, 1.0);
+	EAGLER_VERT_POSITION = u_matrixTransform * vec4(pos2d, 0.0, 1.0);
 }
diff --git a/sources/resources/assets/eagler/glsl/accel_particle.fsh b/sources/resources/assets/eagler/glsl/accel_particle.fsh
index 256290c6..bbf4ed05 100644
--- a/sources/resources/assets/eagler/glsl/accel_particle.fsh
+++ b/sources/resources/assets/eagler/glsl/accel_particle.fsh
@@ -1,7 +1,7 @@
 #line 2
 
 /*
- * Copyright (c) 2022-2023 lax1dude. All Rights Reserved.
+ * Copyright (c) 2022-2024 lax1dude. All Rights Reserved.
  * 
  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
@@ -16,20 +16,16 @@
  * 
  */
 
-precision lowp int;
-precision mediump float;
-precision mediump sampler2D;
+EAGLER_IN(vec2, v_texCoord2f)
+EAGLER_IN(vec4, v_color4f)
 
-in vec2 v_texCoord2f;
-in vec4 v_color4f;
-
-layout(location = 0) out vec4 output4f;
+EAGLER_FRAG_OUT()
 
 uniform sampler2D u_inputTexture;
 
 void main() {
-	output4f = texture(u_inputTexture, v_texCoord2f) * v_color4f;
-	if(output4f.a < 0.004) {
+	EAGLER_FRAG_COLOR = EAGLER_TEXTURE_2D(u_inputTexture, v_texCoord2f) * v_color4f;
+	if(EAGLER_FRAG_COLOR.a < 0.004) {
 		discard;
 	}
 }
diff --git a/sources/resources/assets/eagler/glsl/accel_particle.vsh b/sources/resources/assets/eagler/glsl/accel_particle.vsh
index 59becc7c..4983ac0c 100644
--- a/sources/resources/assets/eagler/glsl/accel_particle.vsh
+++ b/sources/resources/assets/eagler/glsl/accel_particle.vsh
@@ -1,7 +1,7 @@
 #line 2
 
 /*
- * Copyright (c) 2022-2023 lax1dude. All Rights Reserved.
+ * Copyright (c) 2022-2024 lax1dude. All Rights Reserved.
  * 
  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
@@ -16,20 +16,17 @@
  * 
  */
 
-precision lowp int;
-precision highp float;
-precision mediump sampler2D;
+EAGLER_VSH_LAYOUT_BEGIN()
+EAGLER_IN(0, vec2, a_position2f)
+EAGLER_IN(1, vec3, p_position3f)
+EAGLER_IN(2, vec2, p_texCoords2i)
+EAGLER_IN(3, vec2, p_lightMap2f)
+EAGLER_IN(4, vec2, p_particleSize_texCoordsSize_2i)
+EAGLER_IN(5, vec4, p_color4f)
+EAGLER_VSH_LAYOUT_END()
 
-layout(location = 0) in vec2 a_position2f;
-
-layout(location = 1) in vec3 p_position3f;
-layout(location = 2) in vec2 p_texCoords2i;
-layout(location = 3) in vec2 p_lightMap2f;
-layout(location = 4) in vec2 p_particleSize_texCoordsSize_2i;
-layout(location = 5) in vec4 p_color4f;
-
-out vec2 v_texCoord2f;
-out vec4 v_color4f;
+EAGLER_OUT(vec2, v_texCoord2f)
+EAGLER_OUT(vec4, v_color4f)
 
 uniform mat4 u_matrixTransform;
 uniform vec3 u_texCoordSize2f_particleSize1f;
@@ -40,7 +37,7 @@ uniform vec4 u_color4f;
 uniform sampler2D u_lightmapTexture;
 
 void main() {
-	v_color4f = u_color4f * p_color4f.bgra * texture(u_lightmapTexture, p_lightMap2f);
+	v_color4f = u_color4f * p_color4f.bgra * EAGLER_TEXTURE_2D(u_lightmapTexture, p_lightMap2f);
 
 	vec2 tex2f = a_position2f * 0.5 + 0.5;
 	tex2f.y = 1.0 - tex2f.y;
@@ -54,5 +51,5 @@ void main() {
 	pos3f += u_transformParam_1_2_5_f * spos2f.xyy;
 	pos3f.zx += u_transformParam_3_4_f * spos2f;
 
-	gl_Position = u_matrixTransform * vec4(pos3f, 1.0);
+	EAGLER_VERT_POSITION = u_matrixTransform * vec4(pos3f, 1.0);
 }
diff --git a/sources/resources/assets/eagler/glsl/core.fsh b/sources/resources/assets/eagler/glsl/core.fsh
index 5a01a799..26e50402 100644
--- a/sources/resources/assets/eagler/glsl/core.fsh
+++ b/sources/resources/assets/eagler/glsl/core.fsh
@@ -1,7 +1,7 @@
 #line 2
 
 /*
- * Copyright (c) 2022-2023 lax1dude. All Rights Reserved.
+ * Copyright (c) 2022-2024 lax1dude. All Rights Reserved.
  * 
  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
@@ -17,11 +17,11 @@
  */
 
 #if defined(COMPILE_ENABLE_TEX_GEN) || defined(COMPILE_ENABLE_FOG)
-in vec4 v_position4f;
+EAGLER_IN(vec4, v_position4f)
 #endif
 
 #ifdef COMPILE_TEXTURE_ATTRIB
-in vec2 v_texture2f;
+EAGLER_IN(vec2, v_texture2f)
 #endif
 
 uniform vec4 u_color4f;
@@ -32,15 +32,15 @@ uniform vec4 u_colorBlendAdd4f;
 #endif
 
 #ifdef COMPILE_COLOR_ATTRIB
-in vec4 v_color4f;
+EAGLER_IN(vec4, v_color4f)
 #endif
 
 #ifdef COMPILE_NORMAL_ATTRIB
-in vec3 v_normal3f;
+EAGLER_IN(vec3, v_normal3f)
 #endif
 
 #ifdef COMPILE_LIGHTMAP_ATTRIB
-in vec2 v_lightmap2f;
+EAGLER_IN(vec2, v_lightmap2f)
 #endif
 
 #ifdef COMPILE_ENABLE_TEXTURE2D
@@ -76,7 +76,7 @@ uniform vec4 u_fogColor4f;
 #endif
 
 #ifdef COMPILE_ENABLE_TEX_GEN
-in vec3 v_objectPosition3f;
+EAGLER_IN(vec3, v_objectPosition3f)
 uniform ivec4 u_texGenPlane4i;
 uniform vec4 u_texGenS4f;
 uniform vec4 u_texGenT4f;
@@ -89,7 +89,7 @@ uniform mat4 u_textureMat4f01;
 uniform vec2 u_textureAnisotropicFix;
 #endif
 
-layout(location = 0) out vec4 output4f;
+EAGLER_FRAG_OUT()
 
 void main() {
 
@@ -98,22 +98,29 @@ void main() {
 #else
 	vec4 color = u_color4f;
 #endif
-	
+
 #ifdef COMPILE_ENABLE_TEX_GEN
+	vec4 tmpVec4 = vec4(v_objectPosition3f, 1.0);
 	vec4 texGenVector;
-	
-	vec4 texGenPosSrc[2];
-	texGenPosSrc[0] = vec4(v_objectPosition3f, 1.0);
-	texGenPosSrc[1] = v_position4f;
-	
-	texGenVector.x = dot(texGenPosSrc[u_texGenPlane4i.x], u_texGenS4f);
-	texGenVector.y = dot(texGenPosSrc[u_texGenPlane4i.y], u_texGenT4f);
-	texGenVector.z = dot(texGenPosSrc[u_texGenPlane4i.z], u_texGenR4f);
-	texGenVector.w = dot(texGenPosSrc[u_texGenPlane4i.w], u_texGenQ4f);
-	
+	texGenVector.x = dot(u_texGenPlane4i.x == 1 ? v_position4f : tmpVec4, u_texGenS4f);
+	texGenVector.y = dot(u_texGenPlane4i.y == 1 ? v_position4f : tmpVec4, u_texGenT4f);
+	texGenVector.z = dot(u_texGenPlane4i.z == 1 ? v_position4f : tmpVec4, u_texGenR4f);
+	texGenVector.w = dot(u_texGenPlane4i.w == 1 ? v_position4f : tmpVec4, u_texGenQ4f);
+#ifdef EAGLER_HAS_GLES_300
+	texGenVector.xyz = mat4x3(
+		u_textureMat4f01[0].xyw,
+		u_textureMat4f01[1].xyw,
+		u_textureMat4f01[2].xyw,
+		u_textureMat4f01[3].xyw
+	) * texGenVector;
+	texGenVector.xy /= texGenVector.z;
+#else
 	texGenVector = u_textureMat4f01 * texGenVector;
-	color *= texture(u_samplerTexture, texGenVector.xy / texGenVector.w);
-	
+	texGenVector.xy /= texGenVector.w;
+#endif
+
+	color *= EAGLER_TEXTURE_2D(u_samplerTexture, texGenVector.xy);
+
 #ifdef COMPILE_ENABLE_ALPHA_TEST
 	if(color.a < u_alphaTestRef1f) discard;
 #endif
@@ -126,20 +133,20 @@ void main() {
 	// d3d11 doesn't support GL_NEAREST upscaling with anisotropic
 	// filtering enabled, so it needs this stupid fix to 'work'
 	vec2 uv = floor(v_texture2f * u_textureAnisotropicFix) + 0.5;
-	color *= texture(u_samplerTexture, uv / u_textureAnisotropicFix);
+	color *= EAGLER_TEXTURE_2D(u_samplerTexture, uv / u_textureAnisotropicFix);
 #else
-	color *= texture(u_samplerTexture, v_texture2f);
+	color *= EAGLER_TEXTURE_2D(u_samplerTexture, v_texture2f);
 #endif
 #else
-	color *= texture(u_samplerTexture, u_textureCoords01);
+	color *= EAGLER_TEXTURE_2D(u_samplerTexture, u_textureCoords01);
 #endif
 #endif
 
 #ifdef COMPILE_ENABLE_LIGHTMAP
 #ifdef COMPILE_LIGHTMAP_ATTRIB
-	color *= texture(u_samplerLightmap, v_lightmap2f);
+	color *= EAGLER_TEXTURE_2D(u_samplerLightmap, v_lightmap2f);
 #else
-	color *= texture(u_samplerLightmap, u_textureCoords02);
+	color *= EAGLER_TEXTURE_2D(u_samplerLightmap, u_textureCoords02);
 #endif
 #endif
 
@@ -161,9 +168,18 @@ void main() {
 #endif
 	float diffuse = 0.0;
 	vec4 light;
+#ifdef EAGLER_HAS_GLES_300
 	for(int i = 0; i < u_lightsEnabled1i; ++i) {
+#else
+	for(int i = 0; i < 4; ++i) {
+#endif
 		light = u_lightsDirections4fv[i];
 		diffuse += max(dot(light.xyz, normal), 0.0) * light.w;
+#ifndef EAGLER_HAS_GLES_300
+		if(i + 1 >= u_lightsEnabled1i) {
+			break;
+		}
+#endif
 	}
 	color.rgb *= min(u_lightsAmbient3f + vec3(diffuse), 1.0);
 #endif
@@ -179,5 +195,5 @@ void main() {
 	color.rgb = mix(color.rgb, u_fogColor4f.rgb, clamp(f, 0.0, 1.0) * u_fogColor4f.a);
 #endif
 
-	output4f = color;
+	EAGLER_FRAG_COLOR = color;
 }
diff --git a/sources/resources/assets/eagler/glsl/core.vsh b/sources/resources/assets/eagler/glsl/core.vsh
index 77ce5041..f7ebd7e6 100644
--- a/sources/resources/assets/eagler/glsl/core.vsh
+++ b/sources/resources/assets/eagler/glsl/core.vsh
@@ -1,7 +1,7 @@
 #line 2
 
 /*
- * Copyright (c) 2022-2023 lax1dude. All Rights Reserved.
+ * Copyright (c) 2022-2024 lax1dude. All Rights Reserved.
  * 
  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
@@ -16,39 +16,39 @@
  * 
  */
 
-in vec3 a_position3f;
+EAGLER_IN_AUTO(vec3, a_position3f)
 
 #if defined(COMPILE_ENABLE_TEX_GEN) || defined(COMPILE_ENABLE_FOG)
 #define _COMPILE_VARYING_POSITION
 #endif
 
 #ifdef _COMPILE_VARYING_POSITION
-out vec4 v_position4f;
+EAGLER_OUT(vec4, v_position4f)
 #endif
 
 #ifdef COMPILE_ENABLE_TEX_GEN
-out vec3 v_objectPosition3f;
+EAGLER_OUT(vec3, v_objectPosition3f)
 #endif
 
 #ifdef COMPILE_TEXTURE_ATTRIB
-in vec2 a_texture2f;
-out vec2 v_texture2f;
+EAGLER_IN_AUTO(vec2, a_texture2f)
+EAGLER_OUT(vec2, v_texture2f)
 uniform mat4 u_textureMat4f01;
 #endif
 
 #ifdef COMPILE_COLOR_ATTRIB
-in vec4 a_color4f;
-out vec4 v_color4f;
+EAGLER_IN_AUTO(vec4, a_color4f)
+EAGLER_OUT(vec4, v_color4f)
 #endif
 
 #ifdef COMPILE_NORMAL_ATTRIB
-in vec4 a_normal4f;
-out vec3 v_normal3f;
+EAGLER_IN_AUTO(vec4, a_normal4f)
+EAGLER_OUT(vec3, v_normal3f)
 #endif
 
 #ifdef COMPILE_LIGHTMAP_ATTRIB
-in vec2 a_lightmap2f;
-out vec2 v_lightmap2f;
+EAGLER_IN_AUTO(vec2, a_lightmap2f)
+EAGLER_OUT(vec2, v_lightmap2f)
 uniform mat4 u_textureMat4f02;
 #endif
 
@@ -92,8 +92,8 @@ void main() {
 #endif
 
 #ifdef _COMPILE_VARYING_POSITION
-	gl_Position = u_projectionMat4f * v_position4f;
+	EAGLER_VERT_POSITION = u_projectionMat4f * v_position4f;
 #else
-	gl_Position = u_modelviewProjMat4f * vec4(a_position3f, 1.0);
+	EAGLER_VERT_POSITION = u_modelviewProjMat4f * vec4(a_position3f, 1.0);
 #endif
 }
diff --git a/sources/resources/assets/eagler/glsl/deferred/forward_core.fsh b/sources/resources/assets/eagler/glsl/deferred/forward_core.fsh
index 4e6a375c..7f429261 100644
--- a/sources/resources/assets/eagler/glsl/deferred/forward_core.fsh
+++ b/sources/resources/assets/eagler/glsl/deferred/forward_core.fsh
@@ -226,20 +226,18 @@ void main() {
 #ifdef COMPILE_ENABLE_TEXTURE2D
 	vec2 texCoords2f;
 #ifdef COMPILE_ENABLE_TEX_GEN
+	vec4 tmpVec4 = vec4(v_objectPosition3f, 1.0);
 	vec4 texGenVector;
-	vec4 texGenPosSrc[2];
-	texGenPosSrc[0] = vec4(v_objectPosition3f, 1.0);
-	texGenPosSrc[1] = v_position4f;
-	texGenVector.x = dot(texGenPosSrc[u_texGenPlane4i.x], u_texGenS4f);
-	texGenVector.y = dot(texGenPosSrc[u_texGenPlane4i.y], u_texGenT4f);
-	texGenVector.z = dot(texGenPosSrc[u_texGenPlane4i.z], u_texGenR4f);
-	texGenVector.w = dot(texGenPosSrc[u_texGenPlane4i.w], u_texGenQ4f);
-	texGenVector = vec4(mat4x3(
+	texGenVector.x = dot(u_texGenPlane4i.x == 1 ? v_position4f : tmpVec4, u_texGenS4f);
+	texGenVector.y = dot(u_texGenPlane4i.y == 1 ? v_position4f : tmpVec4, u_texGenT4f);
+	texGenVector.z = dot(u_texGenPlane4i.z == 1 ? v_position4f : tmpVec4, u_texGenR4f);
+	texGenVector.w = dot(u_texGenPlane4i.w == 1 ? v_position4f : tmpVec4, u_texGenQ4f);
+	texGenVector.xyz = mat4x3(
 		u_textureMat4f01[0].xyw,
 		u_textureMat4f01[1].xyw,
 		u_textureMat4f01[2].xyw,
 		u_textureMat4f01[3].xyw
-	) * texGenVector, 0.0);
+	) * texGenVector;
 	texCoords2f = texGenVector.xy / texGenVector.z;
 #else
 	
diff --git a/sources/resources/assets/eagler/glsl/deferred/reproject_control.fsh b/sources/resources/assets/eagler/glsl/deferred/reproject_control.fsh
index a7a2c923..a6cd2f25 100644
--- a/sources/resources/assets/eagler/glsl/deferred/reproject_control.fsh
+++ b/sources/resources/assets/eagler/glsl/deferred/reproject_control.fsh
@@ -99,13 +99,13 @@ void main() {
 	reprojectionReflectionOutput4f = vec4(0.0, 0.0, 0.0, 0.0);
 	reprojectionHitVectorOutput4f = vec4(0.0, 0.0, 0.0, 0.0);
 #endif
-	float fragDepth = textureLod(u_gbufferDepthTexture, v_position2f, 0.0).r;
+	float fragDepth = textureLod(u_gbufferDepthTexture, v_position2f2, 0.0).r;
 
 	if(fragDepth < 0.000001) {
 		return;
 	}
 
-	vec4 fragClipSpacePos4f = vec4(v_position2f, fragDepth, 1.0) * 2.0 - 1.0;
+	vec4 fragClipSpacePos4f = vec4(v_position2f2, fragDepth, 1.0) * 2.0 - 1.0;
 	vec4 fragPos4f = u_inverseViewProjMatrix4f * fragClipSpacePos4f;
 	fragPos4f.xyz /= fragPos4f.w;
 	fragPos4f.w = 1.0;
diff --git a/sources/resources/assets/eagler/glsl/deferred/shader_pack_info.json b/sources/resources/assets/eagler/glsl/deferred/shader_pack_info.json
index af5f511d..9cf966a4 100644
--- a/sources/resources/assets/eagler/glsl/deferred/shader_pack_info.json
+++ b/sources/resources/assets/eagler/glsl/deferred/shader_pack_info.json
@@ -1,7 +1,7 @@
 {
 	"name": "§eHigh Performance PBR",
 	"desc": "Pack made from scratch specifically for this client, designed to give what I call the best balance between quality and performance possible in a browser but obviously that's just my opinion",
-	"vers": "1.2.1",
+	"vers": "1.2.2",
 	"author": "lax1dude",
 	"api_vers": 1,
 	"features": [
diff --git a/sources/resources/assets/eagler/glsl/deferred/ssao_generate.fsh b/sources/resources/assets/eagler/glsl/deferred/ssao_generate.fsh
index f2b310a8..7f0e37e7 100644
--- a/sources/resources/assets/eagler/glsl/deferred/ssao_generate.fsh
+++ b/sources/resources/assets/eagler/glsl/deferred/ssao_generate.fsh
@@ -70,7 +70,7 @@ void main() {
 	originalViewSpacePos.xyz /= originalViewSpacePos.w;
 	originalViewSpacePos.w = 1.0;
 	
-	vec4 noiseVec = textureLod(u_noiseConstantTexture, u_randomizerDataMatrix2f * (v_position2f + originalViewSpacePos.xy + normal3f.xz), 0.0);
+	vec4 noiseVec = textureLod(u_noiseConstantTexture, 13.3725 / fract((u_randomizerDataMatrix2f * (v_position2f * 0.42695346 + originalViewSpacePos.xy * 1.373769945645 + normal3f.xz * 42.69456453)) * 1.123234234), 0.0);
 	noiseVec.xyz *= 2.0;
 	noiseVec.xyz -= 1.0;
 	
diff --git a/sources/resources/assets/eagler/glsl/dynamiclights/core_dynamiclights.fsh b/sources/resources/assets/eagler/glsl/dynamiclights/core_dynamiclights.fsh
index aa3bc517..c4d30d62 100644
--- a/sources/resources/assets/eagler/glsl/dynamiclights/core_dynamiclights.fsh
+++ b/sources/resources/assets/eagler/glsl/dynamiclights/core_dynamiclights.fsh
@@ -107,22 +107,23 @@ void main() {
 #else
 	vec4 color = u_color4f;
 #endif
-	
+
 #ifdef COMPILE_ENABLE_TEX_GEN
+	vec4 tmpVec4 = vec4(v_objectPosition3f, 1.0);
 	vec4 texGenVector;
-	
-	vec4 texGenPosSrc[2];
-	texGenPosSrc[0] = vec4(v_objectPosition3f, 1.0);
-	texGenPosSrc[1] = v_position4f;
-	
-	texGenVector.x = dot(texGenPosSrc[u_texGenPlane4i.x], u_texGenS4f);
-	texGenVector.y = dot(texGenPosSrc[u_texGenPlane4i.y], u_texGenT4f);
-	texGenVector.z = dot(texGenPosSrc[u_texGenPlane4i.z], u_texGenR4f);
-	texGenVector.w = dot(texGenPosSrc[u_texGenPlane4i.w], u_texGenQ4f);
-	
-	texGenVector = u_textureMat4f01 * texGenVector;
-	color *= texture(u_samplerTexture, texGenVector.xy / texGenVector.w);
-	
+	texGenVector.x = dot(u_texGenPlane4i.x == 1 ? v_position4f : tmpVec4, u_texGenS4f);
+	texGenVector.y = dot(u_texGenPlane4i.y == 1 ? v_position4f : tmpVec4, u_texGenT4f);
+	texGenVector.z = dot(u_texGenPlane4i.z == 1 ? v_position4f : tmpVec4, u_texGenR4f);
+	texGenVector.w = dot(u_texGenPlane4i.w == 1 ? v_position4f : tmpVec4, u_texGenQ4f);
+	texGenVector.xyz = mat4x3(
+		u_textureMat4f01[0].xyw,
+		u_textureMat4f01[1].xyw,
+		u_textureMat4f01[2].xyw,
+		u_textureMat4f01[3].xyw
+	) * texGenVector;
+
+	color *= texture(u_samplerTexture, texGenVector.xy / texGenVector.z);
+
 #ifdef COMPILE_ENABLE_ALPHA_TEST
 	if(color.a < u_alphaTestRef1f) discard;
 #endif
diff --git a/sources/resources/assets/eagler/glsl/gles2_compat.glsl b/sources/resources/assets/eagler/glsl/gles2_compat.glsl
new file mode 100644
index 00000000..f0023368
--- /dev/null
+++ b/sources/resources/assets/eagler/glsl/gles2_compat.glsl
@@ -0,0 +1,98 @@
+#line 2 6969
+
+/*
+ * Copyright (c) 2024 lax1dude. All Rights Reserved.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ * 
+ */
+
+#ifdef EAGLER_HAS_GLES_300
+
+// For GLES 3.00+ (WebGL 2.0)
+#ifdef EAGLER_IS_VERTEX_SHADER
+
+// Vertex Shaders:
+#define EAGLER_VSH_LAYOUT_BEGIN()
+#define EAGLER_VSH_LAYOUT_END()
+#define EAGLER_IN(_loc, _type, _name) layout(location = _loc) in _type _name;
+#define EAGLER_IN_AUTO(_type, _name) in _type _name;
+#define EAGLER_OUT(_type, _name) out _type _name;
+#define EAGLER_VERT_POSITION gl_Position
+
+#else
+#ifdef EAGLER_IS_FRAGMENT_SHADER
+
+// Fragment Shaders:
+#define EAGLER_IN(_type, _name) in _type _name;
+#define EAGLER_FRAG_COLOR eagler_FragColor
+#define EAGLER_FRAG_DEPTH gl_FragDepth
+
+#define EAGLER_FRAG_OUT() layout(location = 0) out vec4 EAGLER_FRAG_COLOR;
+
+#endif
+#endif
+
+// All Shaders:
+
+#define EAGLER_TEXTURE_2D(tex, coord2f) texture(tex, coord2f)
+#define EAGLER_TEXTURE_2D_LOD(_tex, _coord2f, _lod1f) textureLod(_tex, _coord2f, _lod1f)
+#define EAGLER_HAS_TEXTURE_2D_LOD
+
+
+#else
+#ifdef EAGLER_HAS_GLES_200
+
+// For GLES 2.00 (WebGL 1.0)
+#ifdef EAGLER_IS_VERTEX_SHADER
+
+// Vertex Shaders:
+#define EAGLER_VSH_LAYOUT_BEGIN()
+#define EAGLER_VSH_LAYOUT_END()
+#define EAGLER_IN(_loc, _type, _name) attribute _type _name;
+#define EAGLER_IN_AUTO(_type, _name) attribute _type _name;
+#define EAGLER_OUT(_type, _name) varying _type _name;
+#define EAGLER_VERT_POSITION gl_Position
+
+#else
+#ifdef EAGLER_IS_FRAGMENT_SHADER
+
+// Fragment Shaders:
+#define EAGLER_IN(_type, _name) varying _type _name;
+#define EAGLER_FRAG_COLOR gl_FragColor
+// TODO: Must require EXT_frag_depth to use this on GLES 2.0 (currently not needed)
+#define EAGLER_FRAG_DEPTH gl_FragDepth
+
+#define EAGLER_FRAG_OUT()
+
+#endif
+#endif
+
+// All Shaders:
+
+#define EAGLER_TEXTURE_2D(_tex, _coord2f) texture2D(_tex, _coord2f)
+
+#ifdef EAGLER_HAS_GLES_200_SHADER_TEXTURE_LOD
+#define EAGLER_TEXTURE_2D_LOD(_tex, _coord2f, _lod1f) texture2DLodEXT(_tex, _coord2f, _lod1f)
+#define EAGLER_HAS_TEXTURE_2D_LOD
+#else
+// Beware!
+#define EAGLER_TEXTURE_2D_LOD(_tex, _coord2f, _lod1f) texture2D(_tex, _coord2f)
+#define EAGLER_HAS_TEXTURE_2D_LOD
+#endif
+
+#else
+#error Unable to determine API version! (Missing directive EAGLER_HAS_GLES_200 or 300)
+#endif
+#endif
+
+#line 1 0
\ No newline at end of file
diff --git a/sources/resources/assets/eagler/glsl/hw_fingerprint.fsh b/sources/resources/assets/eagler/glsl/hw_fingerprint.fsh
new file mode 100644
index 00000000..0abd43f6
--- /dev/null
+++ b/sources/resources/assets/eagler/glsl/hw_fingerprint.fsh
@@ -0,0 +1,55 @@
+#line 2
+
+/*
+ * Copyright (c) 2024 lax1dude. All Rights Reserved.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ * 
+ */
+
+EAGLER_IN(vec2, v_position2f)
+
+EAGLER_FRAG_OUT()
+
+uniform sampler2D u_inputTexture;
+uniform mat4 u_textureMatrix;
+
+vec2 rand(in vec2 co){
+	float f = dot(co, vec2(12.98984576, 78.23378678));
+	return fract(vec2(sin(f + 0.32490982), cos(f - 0.69890)) * 43758.54576873);
+}
+
+void main() {
+	vec4 coords4f = vec4(v_position2f.x * 0.25 - 0.125, v_position2f.y * 0.25 - 0.125, v_position2f.y * 10.0 - 9.0, 1.0);
+	coords4f = u_textureMatrix * coords4f;
+	coords4f.xy /= coords4f.w;
+	EAGLER_FRAG_COLOR = EAGLER_TEXTURE_2D(u_inputTexture, coords4f.xy * 0.5 + 0.5);
+	EAGLER_FRAG_COLOR.rg += rand(v_position2f * 1.2344574345) * 0.05;
+	EAGLER_FRAG_COLOR.ba -= rand(v_position2f * 1.2343525225) * 0.05;
+	EAGLER_FRAG_COLOR.a = fract(sin(dot(coords4f.yz, vec2(12.9898, 78.233))) * 43758.5453);
+	EAGLER_FRAG_COLOR.a += exp(length(rand(coords4f.xw)) * -69.420);
+	EAGLER_FRAG_COLOR = pow(EAGLER_FRAG_COLOR, vec4(1.0 / 2.423952));
+	EAGLER_FRAG_COLOR = pow(EAGLER_FRAG_COLOR, vec4(5.4523856));
+	EAGLER_FRAG_COLOR += 0.00004423 + EAGLER_FRAG_COLOR.a * 0.02;
+	EAGLER_FRAG_COLOR = sqrt(EAGLER_FRAG_COLOR);
+	EAGLER_FRAG_COLOR = pow(EAGLER_FRAG_COLOR, vec4(1.0 / 1.9023576));
+#ifdef EAGLER_HAS_GLES_300
+	EAGLER_FRAG_COLOR.ra += tanh(fract(EAGLER_FRAG_COLOR.a * 32.324834)) * 0.1012426;
+#endif
+	EAGLER_FRAG_COLOR.b *= 0.934924;
+	EAGLER_FRAG_COLOR.b += (1.23213 / inversesqrt(EAGLER_FRAG_COLOR.a)) * 0.156365;
+	EAGLER_FRAG_COLOR.ga += rand(gl_FragCoord.xy) * 0.13423567;
+	EAGLER_FRAG_COLOR.rb += gl_PointCoord * 0.0124264565;
+#ifdef EAGLER_HAS_GLES_300
+	EAGLER_FRAG_COLOR *= 0.95234 + asinh(EAGLER_FRAG_COLOR.g * 5.23423) * 0.0254325;
+#endif
+}
diff --git a/sources/resources/assets/eagler/glsl/local.vsh b/sources/resources/assets/eagler/glsl/local.vsh
index 4617298e..cd74b1eb 100644
--- a/sources/resources/assets/eagler/glsl/local.vsh
+++ b/sources/resources/assets/eagler/glsl/local.vsh
@@ -1,7 +1,7 @@
 #line 2
 
 /*
- * Copyright (c) 2022-2023 lax1dude. All Rights Reserved.
+ * Copyright (c) 2022-2024 lax1dude. All Rights Reserved.
  * 
  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
@@ -16,15 +16,13 @@
  * 
  */
 
-precision lowp int;
-precision highp float;
-precision lowp sampler2D;
+EAGLER_VSH_LAYOUT_BEGIN()
+EAGLER_IN(0, vec2, a_position2f)
+EAGLER_VSH_LAYOUT_END()
 
-layout(location = 0) in vec2 a_position2f;
-
-out vec2 v_position2f;
+EAGLER_OUT(vec2, v_position2f)
 
 void main() {
 	v_position2f = a_position2f * 0.5 + 0.5;
-	gl_Position = vec4(a_position2f, 0.0, 1.0);
+	EAGLER_VERT_POSITION = vec4(a_position2f, 0.0, 1.0);
 }
diff --git a/sources/resources/assets/eagler/glsl/post_fxaa.fsh b/sources/resources/assets/eagler/glsl/post_fxaa.fsh
index 9914f0a4..4878106a 100644
--- a/sources/resources/assets/eagler/glsl/post_fxaa.fsh
+++ b/sources/resources/assets/eagler/glsl/post_fxaa.fsh
@@ -1,11 +1,13 @@
 #line 2
 
 // Remove this line below if you plan to modify this file
+#ifndef EAGLER_IS_GLES_200
 #define USE_OPTIMIZED
+#endif
 
 
 /*
- * Copyright (c) 2022-2023 lax1dude. All Rights Reserved.
+ * Copyright (c) 2022-2024 lax1dude. All Rights Reserved.
  * 
  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
@@ -52,14 +54,9 @@
  * 
  */
 
-precision lowp int;
-precision mediump float;
-precision mediump sampler2D;
+EAGLER_IN(vec2, v_position2f)
 
-
-in vec2 v_position2f;
-
-layout(location = 0) out vec4 output4f;
+EAGLER_FRAG_OUT()
 
 uniform sampler2D u_screenTexture;
 uniform vec2 u_screenSize2f;
@@ -110,7 +107,7 @@ uniform vec2 u_screenSize2f;
     #define FxaaTex sampler2D
 /*--------------------------------------------------------------------------*/
 
-    #define FxaaTexTop(t, p) textureLod(t, p, 0.0)
+    #define FxaaTexTop(t, p) EAGLER_TEXTURE_2D_LOD(t, p, 0.0)
 
 /*============================================================================
                    GREEN AS LUMA OPTION SUPPORT FUNCTION
@@ -298,7 +295,7 @@ void main(){
 	rcpFrameOpt.xy = -screenSize05;
 	rcpFrameOpt.zw = screenSize05;
 
-	output4f = vec4(FxaaPixelShader(v_position2f + screenSize05, posPos, u_screenTexture, rcpFrameOpt, rcpFrameOpt * 4.0, edgeSharpness, edgeThreshold, edgeThresholdMin).rgb, 1.0);
+	EAGLER_FRAG_COLOR = vec4(FxaaPixelShader(v_position2f + screenSize05, posPos, u_screenTexture, rcpFrameOpt, rcpFrameOpt * 4.0, edgeSharpness, edgeThreshold, edgeThresholdMin).rgb, 1.0);
 }
 #else
 
@@ -306,7 +303,6 @@ void main(){
 // Is it faster? Idfk, probably compiles faster at least, what matters it I tried
 
 float _616;
-vec4 _617;
 
 void main()
 {
@@ -317,14 +313,14 @@ void main()
     mediump vec4 _608;
     for(;;)
     {
-        mediump vec3 _532 = textureLod(u_screenTexture, _611.xy, 0.0).xyz;
+        mediump vec3 _532 = EAGLER_TEXTURE_2D_LOD(u_screenTexture, _611.xy, 0.0).xyz;
         mediump float _536 = dot(_532 * _532, vec3(0.2989999949932098388671875, 0.58700001239776611328125, 0.114000000059604644775390625));
-        mediump vec3 _540 = textureLod(u_screenTexture, _611.xw, 0.0).xyz;
+        mediump vec3 _540 = EAGLER_TEXTURE_2D_LOD(u_screenTexture, _611.xw, 0.0).xyz;
         mediump float _544 = dot(_540 * _540, vec3(0.2989999949932098388671875, 0.58700001239776611328125, 0.114000000059604644775390625));
-        mediump vec3 _548 = textureLod(u_screenTexture, _611.zy, 0.0).xyz;
-        mediump vec3 _556 = textureLod(u_screenTexture, _611.zw, 0.0).xyz;
+        mediump vec3 _548 = EAGLER_TEXTURE_2D_LOD(u_screenTexture, _611.zy, 0.0).xyz;
+        mediump vec3 _556 = EAGLER_TEXTURE_2D_LOD(u_screenTexture, _611.zw, 0.0).xyz;
         mediump float _560 = dot(_556 * _556, vec3(0.2989999949932098388671875, 0.58700001239776611328125, 0.114000000059604644775390625));
-        mediump vec4 _390 = textureLod(u_screenTexture, _290, 0.0);
+        mediump vec4 _390 = EAGLER_TEXTURE_2D_LOD(u_screenTexture, _290, 0.0);
         mediump vec3 _564 = _390.xyz;
         mediump float _568 = dot(_564 * _564, vec3(0.2989999949932098388671875, 0.58700001239776611328125, 0.114000000059604644775390625));
         mediump float _397 = dot(_548 * _548, vec3(0.2989999949932098388671875, 0.58700001239776611328125, 0.114000000059604644775390625)) + 0.00260416674427688121795654296875;
@@ -347,8 +343,8 @@ void main()
         mediump vec2 _484 = (_612 * 4.0).zw;
         vec2 _615 = -hp_copy_481;
         mediump vec2 mp_copy_615 = _615;
-        mediump vec4 _498 = textureLod(u_screenTexture, mp_copy_614 * _454 + _290, 0.0) + textureLod(u_screenTexture, _449 * _454 + _290, 0.0);
-        mediump vec4 _505 = ((textureLod(u_screenTexture, mp_copy_615 * _484 + _290, 0.0) + textureLod(u_screenTexture, _481 * _484 + _290, 0.0)) * 0.25) + (_498 * 0.25);
+        mediump vec4 _498 = EAGLER_TEXTURE_2D_LOD(u_screenTexture, mp_copy_614 * _454 + _290, 0.0) + EAGLER_TEXTURE_2D_LOD(u_screenTexture, _449 * _454 + _290, 0.0);
+        mediump vec4 _505 = ((EAGLER_TEXTURE_2D_LOD(u_screenTexture, mp_copy_615 * _484 + _290, 0.0) + EAGLER_TEXTURE_2D_LOD(u_screenTexture, _481 * _484 + _290, 0.0)) * 0.25) + (_498 * 0.25);
         mediump float _576 = dot(_505.xyz * _505.xyz, vec3(0.2989999949932098388671875, 0.58700001239776611328125, 0.114000000059604644775390625));
         mediump vec4 _607;
         if ((_576 < _412) || (_576 > _409))
@@ -367,7 +363,7 @@ void main()
         _608 = _607;
         break;
     }
-    output4f = vec4(_608.xyz, 1.0);
+    EAGLER_FRAG_COLOR = vec4(_608.xyz, 1.0);
 }
 
 #endif
\ No newline at end of file
diff --git a/sources/resources/assets/eagler/glsl/texture_blit.fsh b/sources/resources/assets/eagler/glsl/texture_blit.fsh
index 7b3fb59b..debfcc0f 100644
--- a/sources/resources/assets/eagler/glsl/texture_blit.fsh
+++ b/sources/resources/assets/eagler/glsl/texture_blit.fsh
@@ -1,7 +1,7 @@
 #line 2
 
 /*
- * Copyright (c) 2023 lax1dude. All Rights Reserved.
+ * Copyright (c) 2023-2024 lax1dude. All Rights Reserved.
  * 
  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
@@ -16,14 +16,10 @@
  * 
  */
 
-precision lowp int;
-precision highp float;
-precision highp sampler2D;
-
-in vec2 v_texCoords2f;
+EAGLER_IN(vec2, v_texCoords2f)
 
 #ifndef COMPILE_BLIT_DEPTH
-layout(location = 0) out vec4 output4f;
+EAGLER_FRAG_OUT()
 #endif
 
 uniform sampler2D u_inputTexture;
@@ -40,8 +36,8 @@ void main() {
 	uv2f = (floor(uv2f * u_pixelAlignmentSizes4f.xy) + u_pixelAlignmentOffset2f) * u_pixelAlignmentSizes4f.zw;
 #endif
 #ifndef COMPILE_BLIT_DEPTH
-	output4f = textureLod(u_inputTexture, uv2f, u_textureLod1f);
+	EAGLER_FRAG_COLOR = EAGLER_TEXTURE_2D_LOD(u_inputTexture, uv2f, u_textureLod1f);
 #else
-	gl_FragDepth = textureLod(u_inputTexture, uv2f, u_textureLod1f).r;
+	EAGLER_FRAG_DEPTH = EAGLER_TEXTURE_2D_LOD(u_inputTexture, uv2f, u_textureLod1f).r;
 #endif
 }
diff --git a/sources/resources/assets/eagler/glsl/texture_blit.vsh b/sources/resources/assets/eagler/glsl/texture_blit.vsh
index 645e1c4e..d5d18343 100644
--- a/sources/resources/assets/eagler/glsl/texture_blit.vsh
+++ b/sources/resources/assets/eagler/glsl/texture_blit.vsh
@@ -1,7 +1,7 @@
 #line 2
 
 /*
- * Copyright (c) 2023 lax1dude. All Rights Reserved.
+ * Copyright (c) 2023-2024 lax1dude. All Rights Reserved.
  * 
  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
@@ -16,13 +16,11 @@
  * 
  */
 
-precision lowp int;
-precision lowp float;
-precision lowp sampler2D;
+EAGLER_VSH_LAYOUT_BEGIN()
+EAGLER_IN(0, vec2, a_position2f)
+EAGLER_VSH_LAYOUT_END()
 
-layout(location = 0) in vec2 a_position2f;
-
-out vec2 v_texCoords2f;
+EAGLER_OUT(vec2, v_texCoords2f)
 
 uniform vec4 u_srcCoords4f;
 uniform vec4 u_dstCoords4f;
@@ -30,5 +28,5 @@ uniform vec4 u_dstCoords4f;
 void main() {
 	vec2 uv = a_position2f * 0.5 + 0.5;
 	v_texCoords2f = u_srcCoords4f.xy + u_srcCoords4f.zw * uv;
-	gl_Position = vec4(u_dstCoords4f.xy + u_dstCoords4f.zw * uv, 0.0, 1.0);
+	EAGLER_VERT_POSITION = vec4(u_dstCoords4f.xy + u_dstCoords4f.zw * uv, 0.0, 1.0);
 }
diff --git a/sources/resources/assets/eagler/glsl/texture_mix.fsh b/sources/resources/assets/eagler/glsl/texture_mix.fsh
index 3cef92f8..26cb13fb 100644
--- a/sources/resources/assets/eagler/glsl/texture_mix.fsh
+++ b/sources/resources/assets/eagler/glsl/texture_mix.fsh
@@ -1,7 +1,7 @@
 #line 2
 
 /*
- * Copyright (c) 2022-2023 lax1dude. All Rights Reserved.
+ * Copyright (c) 2022-2024 lax1dude. All Rights Reserved.
  * 
  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
@@ -16,13 +16,9 @@
  * 
  */
 
-precision lowp int;
-precision highp float;
-precision highp sampler2D;
+EAGLER_IN(vec2, v_position2f)
 
-in vec2 v_position2f;
-
-layout(location = 0) out vec4 output4f;
+EAGLER_FRAG_OUT()
 
 uniform sampler2D u_inputTexture;
 uniform float u_textureLod1f;
@@ -32,6 +28,6 @@ uniform mat3 u_matrixTransform;
 
 void main() {
 	vec3 coords = u_matrixTransform * vec3(v_position2f, 1.0);
-	vec4 color4f = textureLod(u_inputTexture, coords.xy, u_textureLod1f);
-	output4f = color4f * u_blendFactor4f + u_blendBias4f;
+	vec4 color4f = EAGLER_TEXTURE_2D_LOD(u_inputTexture, coords.xy, u_textureLod1f);
+	EAGLER_FRAG_COLOR = color4f * u_blendFactor4f + u_blendBias4f;
 }
diff --git a/sources/resources/assets/eagler/gui/eagler_gui.png b/sources/resources/assets/eagler/gui/eagler_gui.png
index 704285831160bc03f8e492dd22684bab0d01690c..5d9d516ddecaca2a7f3026187ce08dd71289b97d 100644
GIT binary patch
literal 11256
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

literal 8564
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
O+SxPbP0CI?M*JV1vMhK2

diff --git a/sources/resources/assets/eagler/gui/notif_bk_large.png b/sources/resources/assets/eagler/gui/notif_bk_large.png
new file mode 100644
index 0000000000000000000000000000000000000000..9cab14524960b47d69482185ddc35a94a60b1d84
GIT binary patch
literal 5089
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

literal 0
HcmV?d00001

diff --git a/sources/resources/assets/eagler/gui/touch_gui.png b/sources/resources/assets/eagler/gui/touch_gui.png
new file mode 100644
index 0000000000000000000000000000000000000000..12cbcbedd46e848237f6777514cb51f73d079297
GIT binary patch
literal 13590
zcmY+q1yoeu7dCun7;q>70ZC~|32Dh8MSju<NF&`KNXHD_jYxMWQqm0up~Q%!q|)6v
z#C!4ozTaBktTpT2b?-gr>~qdO&wh49s;fRF#G}Ro0D$nBlDsAWK)_oF0LK9@hOf)4
zzzeR6(n~i0;9<V~L%fQmJph0KcqT8S?e%-x-#>wN*?YB0+RCbvP!#t7dozky_nYpY
z?@tUH?yi5I;RvCPw$M&Qe#?(=?<OV)HOl9FahD@nxpJeD^GTd(FTE*kIOUYm8`-XV
zd<#r(j8neP(!cL|LC~Nk-<vHDQ`)NZSS`f(@5bk>ZkNsnv|4)zwPvLI2fQdBJ34aj
zl$`Ed-SnR`@s;+wwryWe8f37sL15*qrccmG*i<AxkO0K4w!P`%Bu<&6E`G)bEpAQK
z>Jj$z_Ws02pBwcWY)^`wY)vi7pefKRE3~v;^3~*qEBZ0aFl4gxgWhjxexeT>!fDTw
z|M>L4*G{}{`=LAU5!q)Wx~xeyWK+x8vSTP!&Hh|t-peN-fCaqE%?;nhtXzr4{qd#?
zV&Iz|%6hUWq0??G(mUPkR{9t!eYLJOe2y>vW`oQ)@am0OcEU~8-gmC5HLj|*Pxj1v
zXgQ+eqf6(ueH=QUHO7#oev^QcsjOfT63B?F&sz?krNrHLgx143-^!~xGV1xvBG{u2
z-iA98eIf3RdmymO&BODze!^IwXhNSE4)w|j7mdqL`A&&7d{|vwZ7L=G<VmE+yr010
z{<iCs`MZpa?`<N|(z~=6P=56aoltN8h{C7wcL((7y%r$gQaz=Y@T%rw-fIlRG@k8+
zOUHQ5dEfc*<45ypFax4O2Mc(_&7HoTs*GKs!&SR`NBT^rZNG<R8;+pprK0Xj=;XW0
z(F{{PsHu4je#jVAKu}|dBg<h4uS}7xosy>v+mj&5S?xacCuJNM9ya&z825Wy5Rpn*
zaDIONx#rLxTlV@e)UG~?J<4UF3q^6}F@GoJ`;I|5qz0;;6}TI1a`|^GoviC*CntDb
zjK=d}PWn}D_%+Wb^2C_kX$N7#KlS4!J9*Qq49@g0NZq))vYD$ZNo{Q{B^A}<Kb^01
z{SKC%IsC5USX}RiyC(gb+)^^Nv*Q$TqH~19HnEFS_E$1Re9K_S5$YP{Ya#%($~=yT
zri0GQeI!?Ws#s%a(qrRD_9J%Lj}VkWz|(KY!S~YM1cl>r_#jtcg>mZb<vb-cd{x3_
z0bzw1uP~_bK3o}SsHv%;?e1$OP2@_AI>cujR$FR(rh*f?K`ie?an2F+E+<DA6Kb|5
zs1NP-VU9B=-N5QgHt{VBky6c#b@}53FLr+g2eO{D#zfj7t!fiJyOhgACiIshKIZ4w
zzgp@3;aDhZrqLbWhYPs5xxLHG{6QI9fSv{y`G8oXetgfLK4*1VLfU_b{Ce7=L_H@?
zTwL6~VQ^?D!(3itDaMMGjcqxO>?2pinFSokql1`}Q##K_nftkXh&o?pQ7*&odSzt(
z>g$(R0*ZsD#9keiK*|v9<d2kVi8axoQK*EMx&!eCM~N2H56UJuW~X&`<+CGQ#&k}u
z><!aF>w&kA|K*wMA+~Q$IJm9gE$REF4IHwU@CzD~v(FSm7)p=bx!4MW#+*afEq1Ru
zVLVf+QVKzyti6~<XF-Fq`d=tzV$)YFR?TgS1lj3E_=`;s?)FB#xc()EC?cyX;pp}d
z9hrOE7FUzO@jWq-WOVa*ph2;)`#S-3saoz($O<Vb>62kKlFuq4vnlVX$huF~z-0=%
zw1BUyth|07Wy)9Md%APzbM3p^-pGcn+?v!mqt|o!GPX-C!Z9i^m6N*St4#g7!b<EZ
z{h()!FKFey;c>>1GzOL(mFAN?eXLE}_~nviKE9Ar`P(+f6T*si+J5$d#%Dv4Cm>)=
z^t=MKJRw(iv5@`q&TOm7&xDT#iD@fKY`eo1Tn{qm-2C6taH34x5vLw{&)P5@^Ebc8
zFabCAx)UGB2Xa+ny5fc<y^eQ=1CKXiNG>mR1*XrgHlHTSl6_kzs-^B%$#qam3Id1!
zOR2#%rOQQVSq#XhF!3rcb*>deEAx82etqxPuU};on?3NDm>9~W@y$0gUW>6-I!FS_
zF{1AUz|PfqlkHoS9l2lNdkB2Unj}G@F$$$Nf3;k`+iA{g72q!})p9jd&YK0V#vGam
zO-r5Z?ly}dbEk2-j_?5_eJ@E$6oI$)$LAXHs<Z}*GT-oOqLP*JjNp%${v$arEh$ls
zwpV^XgYg&&T#Oa@d?*oO2A@9_@W;y51P2Gf;R~_8y&Iu|0KiYkE^4CCrC4aTavXTH
z;+iFzI{M>&hO3hSLF)9|MLAkFV>J%dgF3j<bi0T00wki4-SIAZS$?|Z4HvkX&xeLf
zrwpGo&#LhW35Bk&ug@4t^PXu~o4)iF8eIL=Y&e%o9lM5KN(Gr4U?D*+_yz5BOW&w@
zw(TWPNCyf5m$N34XR-^vqDLlytD(7V0r68fUCrEXZAJNt%ud5NAiCODVd^+at}foj
zV*!=zPNnDQD(7=i!R>gK(-IDZZ=C<(${=_G-IC_RvKy02A0B9N^6~QrVcoe)$xIBB
z;Zd&XZg0-UXpwc(#BrwL{S_4!fQ}+qh_kB50Hqd)Km9w({k;u0qISgCjXqHKYJuMP
zasxlss(d?7vg_Abc-r+=sA6rXViq?J^dm{ceT<EbVeN9%79IkaaA^Mg@p_R_dKas@
zojc#gXK2jwsh++*zW^ZNvoPHU|LW>s2h7%OCY@GIY?h7LrSr&%ZzWMdWTcA$VY@NB
z0;?EGyi}l{0GRFBo<b=yM@|}W$41({69IDWuo$Wp0)*K~Mx`7`$#06&(QS^6##5E5
z2W_3kRpzHVvwIT51GEW@c@1Xz^avICS^d#5?W1BMgiAm)%8`wVW3)~=!{4rhv2BD}
z%FPP3${5z8M`$y-X#fyCy}5oW>b@7jD7pUx(_%zn(>Y!u$u3F4-M#(LhB}cmO?!V;
zD`F;Cw|p#aiN~IDV_Xjxwi&5hoaE*}Hl!9~p}RTyneP`?g8Ur_2${bz{8)QKk))z$
zUuBGMevm=jRD`lFjZgel19l!pM##UCQfREMM(S6*W#%Hk@yd@MTK6_CG0B~vEo0D2
zd9CgvvtUoMbqy6)NE|~39fs<ZFK5ka>YKabzN0?;sY#s*SV<zdG+8;lI_drdYrPQ6
zm<lV{OXKOJoex}bVJ$U@WkOq~8HN4eX&rcSmdd%;#DqIX*Y=xl_T;Y_rBw_{a@%Hi
z*AD+ad>mhc%*@?A<%u~_Js(n<&b+3QALjh+@xsG$tTd+3er13YwqgggYr@2QPaG!j
z5DG=}&2H9lmt2F*(IC1K4b|hFr8z!@WykRne|+dS-#a;}XC)~epJ0p4edScIA5p;0
z9Nnus#fp;`9)*y%$TXbwQf0b2J3IUE`lz66aj8GqUNe&zK2EdSc_Rf<7xRKY1?#(_
zaroARYi{o$Yl%$6M2FrxhVlUh@4lQIwU5Bsjz<2=UNX_sV|Q4~Z-G_mq9^6=K6jDY
zn>3HF=y%PILIj=<92V1G46d8};D9DJzF8jPNm$9jFaHTEqQ;I56@)Z8Oa*ZpG#nKP
zckeGHt9>`(&{OlWcLE|Vhouh5@Nd?)Y+t)<zY*WhoVcQnB10L923&esp$OHb9+akh
z&X)@xu%CmCuD|)oDW`hoR`CK3`+}5J$g7gR^m1CAc5a=b4E?%jXU%3xvcCOI!g7f%
zen?t?pFfFXXiC$RCl<og{vWxQkf_JjJ3%OJSRbGlg&@QCJ87V@PNPrE)<%ItDiI}+
zHj$RKsAeD=*ycO@eb?<<=g^U5l~7BKpPxQDzGR@(!%{DTAH{|fiAuX*90kU&zeOQt
z6FQY-CQtpDuU!X)CQKb19u?xQ*`2npWZ1WK?gd@QY5Yt|Ho-#${fPwrQdYZPZ@J|9
z2L3M5Ca^(pc;cDz{#gc*x>(G%Z9P2Vw+hAFf4uFZ^&{$2qbzDhK93)A5Fb@QBACWl
z<!8R_a7-2IjMx^XhMm+2SnvoyEekSjV;K!77$_lH_i+>QN(p^<5F%Ibtg}iVs0>U7
zCYK8JGFJXze{<aX*nhV4F=ilf>G){K(D^FP(STSB*7a3Z*AC_|d3Z3Be7J&xiIkBc
zW`ILi<rMqi?wk9%0;(v}E<(hI%fqdoH|dPhxIr%Nny|krQVk^4Uv57ArS`YNoNNyb
zu~uG{)(??kmyg-?GMP4hO@ro{+7Kcu;4t8qqXGlPIRpWDqQG#s^-DYrgzg$^>Mu3h
z$M%CrZQqS!AD*Mqw|!3bz~wW<td}2SC)g69Tpcn5!droggFOeI!PUewk}@0WL7uYa
zgV(L%@pGj-hzax0-`@fhiMgl5AKlZdMgf?dCE!y5ALVv9m@eOHVsoz74;_YYDUw$2
z;U@@P2gN!97g{6{7eE;f$b(h%yD--r{MGh=<#}5L_Zt86SClZC&%lu;$=dORiHO1z
zeaENXlBYWg-w_@|!~0)J)hOfJ{V^W5ry;EDh<a@&QZ6Nqj2t4KXkrC{$(aM!=e*ZU
zIbug%ti!yDIyA_=(L?F3voler_T%x-h5_|?&0YphGjlr`wYw}cAWyV%m}~R?_6rH^
zRv!aYJB|aZBgs(8e^_r!{4kIGw#?~&IMCD6oBZ4muY}8!0H;e0y1Pd$1DNR-SE^xM
z#YPOEuLV((b&O5B*{H(vZ)<oC%&+p&iN8DlI)6Dh?=G=^dFiJ(DiBrhd^?Y#KBRyS
z`H4d^jnTzlQ3neztOrP#%QaZ<eNI$Fb}HeeKdpfJORA^kFG#3+<c9$4OK|&o<?XsG
zNl=Jt2oo}7k<M+`_hbhPpuIeNDiG3XHZO(1n#YV6zSltKu|nDQjh0H;u3G5G8}4Ty
zJ@BgQ>OzW(ABLE%#lTy}9+Mr3+>$<!ap`tMs0sm^$NLFM^uWpGxD>5Ja(06~AhI<Z
z&h~ry$+`EC8r|DI3z3BsDhU7mb~NnrE1T5MH+YDJB?@!Crb*EB$I(f0n#iX^)HyYv
zBVzR5ed%1jbljMhTnrRKBs%nY&$En<SMN=?9lxd9d-lSYA4=Ok3fp?2V)l?D48g~~
zXI`A25;Ov`mKu9C>HxM6Cf<$<o1Vig82i*mcg9=L(IY{5>FMc)HqrtD!3Ivv->4w$
z#l$ca31BOn*~5U=2QL0p8O7uB`n=Mpof^1$^ytw$df&hfBL>PSI8xtcv4O73`EsMQ
z+J2beF1<v8Eq)%^p9@KWvsja>l&RcsLWy~g(4oq`X>#LaR#R&4wSmK%wR5CjH*q^F
zGr~o(ri?-ouK@26WgHnpT;7|O3spJuiB61&6|^hi8QWFh#Lcv$?YzG){e(Us9v`sV
zeu|d{Tm78WAX566o0m89lwE(J$Kuti&+-sI6~KF!>2sALm7X>Vdo}6~omXBU0b-Pu
zfCK7HSAAO9Dv&dFC?W9h%)m3?ZhXLbeuFEZ^r9)|xqLtzK2KAgOW+9XqfR+!SlDhP
zA3si<Rt)PNC)C4#VJdUebtti$s%!l7O8x`t1EfrkF^()nGh&g_cekb0NL!Bebk+NM
zu5~9&^Kk)t*a-D^5(urROV?$>D#(R#H#b^6CE+Pj(x7u<b?2->b<7_lp{1n-|AKxQ
zxPWPyOH<6d{tR}%PWZQph)%+5uJ=KY1}s*7Wjf^2v8t-R=XkqdAvydmQjP4ZBe%@j
z-=}Yza<EL3JD-zQgJfqofduyp@twQ0T_6j0T|?)`kbsU?&(e~GtwxfP3Qq6^<P1~S
z7g5419{Ym9f_es?mp$FPosQh}oVO^!_S{bIu5vsVt-M|$Zwm0#@1C!>#;MU!SKpIx
z%#m>_G_K0b1$~(NNu3VI+2hoOg@s`6itWZvDZ@bLvl}#8)z-sw=6av`zHV)Oto3m&
zWs}ff7*tkJ!)h>ze$-^DN31DMuW`1aW^7ghtpZ0W!7+6n9);6B?&5Bo(Y!EK&kVsn
zfAC@KLnLhL%Da$Qgk4*j9dB$s|KY4`Q8%`nJy7;8P3Ni>CgK{9c}7KuY|vDnGRN;P
zf6Y6sB0`soXJ}|R(C;-1lK->0(+=wf4M($Aub4{NCOITI<ffPhU_mGmfDU=H-x(0Z
zMl?+QnnrU|n>?c7Z~~ztSVW;^;rE?~K+Y>CjWMv@xOZTH;4ZCb0&{1%>1syy?J)!y
zxN<B|j3a2&&rD#8bB{oU&~&A7_b855DoOZv-E8ytda(31UoOQ|6T3}SX`fdu(bzq&
zX}<XtrcSPVkOYJERb?5QzzMA9N<WntD9_*v(gFL%S8g|3tJBX!bc*3emp|N^<67Oe
z8y3$c*{+tBSW-089YGyI>odnKj#yv2@(vXO6V_rvT(~ef5(v=sp7bWZ^x~mQ@(ns)
zF4U|I9}M6OT(w<nlzVNwFC7u68K3X(e-;xL_sYRx;D{?GKHl8Vj}~+o70E_V{pB^Z
z^{^I<+cJ-@{pg)oEbb%tB!rL+Oz5BVmwD*kG!E#43+G|e;wS_USuv3yzKofO39&^L
zQ1lYZ?#@n~T~*nAhB=dJGXjJf8R}6oNf;xY?^X@%6i?Ga&~tiVf}k%~to1{Do7lXn
z8vft8_UZ7D5VMHEOcCp%&ZxFdLJlZi7(29&3u@%4#lL$saC+AQ-f3=ygYMFrm+XoO
z(xtR>8&;NI)HE%kGNt%4u1T6;ha*UC`xK%uXVL;-%NbxXC@?TQlm-kv7h@s;n^v6a
zMOIJqm~70UDnfTY;3t--VFr@x{3Xcd2yeXUgMR#)o)#PAgTt_BAfRdg{n*XTT7kjq
z$-&{y6O37wWkH^O1#X`f5j0RUp+Z&uCp1?k;Z86dv>q&K*yG!l?bH}4UpBg{o?NQW
zzDo9h{CRuhY-F~sk?k1dz)U#w>}0VCDL-5_P+OVGn)d*LjzTbXNV3v_)ZmLX@JJzV
z-7!~Cv8xzfcUtTD%4eD_ohe~4FV4fn38tv1$R{FVE$b*wxK__<s=+hd-V$;iL}&}t
zDZhne^3hXII9<u-GokAZq!XvoZmDhY536V;9Tt2=n67gEltae2X(i-c2^W_Mp<QmH
zgHRrVF9iolhWe|Qei<-4*KX_L%mLkQK5pD=cb2rffA@`?RaZMSzG3P~U^**9mC*C&
z&n<e^M_@4dp8puwWmQSm!rC!noY2{7&s+`I-?{mdlbJ%zxWQcfu10H|Z-S6i%`$CH
z(9r^&u+L{t1E?11&zEPcn^+mB7&GwdUZ9LPyM&v>swIor{ehtTNI;u5jT5?kwUrGZ
zoh2`=ofPt*lSIGjKvELz<)DJtprX9#<6XQKKl%Hg3Fhr%GGXvx8YkZ$!*Q+%&T3Op
z0)+V6_~~p9UuR6V#r-@<W|y(fi?m3_ChqJ9lc!VS`|nMfX)SFV+s}H0q4L*Gf{-WY
zw{CWAyOM6+$2{xg9HumtOyM`h_a3c>n3fTMjP2;Q3Ff!)jaKLD=Kjv@?b$A;qx|rY
z=W1$;1<^d56;uhV3xEF>Bwtnvc8wCNwxu&(o}GF13gLl4(v6LbkjtQaet<_IPole?
zu><5|u_P|uYXv-ryA<bYSw0lHM*B6Nhb0cqJogjdCqAE>b1a*;#VMqD$c!@0BS79+
z*qu9j+IAFt6EJjV^Np7T7|sl(?+hFE`*XT?=hW{mn`*ngl5rSF)45a(R#sO9hQ-Kk
z)$y`_f^M4~YlPe9SwIF}*1LCI;rA)_!-)d0JN*w;R<4N7HP)@gQ6&tGPO};7SB<gA
za#HpG5x0P|%U?df9%jC*&P}<n<;ngL1nI+r)}4wU%tT9S!Cu=!RaI0VhlgHE`@2>#
zh{jo8?U~wk@i#0(gM*d?GNr5xi7--vSP1a{k0?vl8jGGQSbkw1ZjX4{v9EI3j}@53
zysw<o{&fAzP`0?1`KS|4fi;$&jrSDQ^&Oc6Z`K9n4U*CL1%BA<C=M*BTNrRuyFRF`
zWgk1`>0*xe>t!JZ<HCcI!BwQ*YyRT?)zf|;<JJ_k_#-l?p1`7)&T7h*LIst&wyNbw
zG7Vzn2Us!E;cQ&q=jd#uFa2MpQSXUB7iHk3setCvwsz5!0~nhDAu#i;i9VS;CXqF-
zTqdHF&~nUgns{<hdCcyG9jK-#=Y7$2=yM~7w3}10u-_rkJT1g&h6jg=lokO29qxf2
zBuDLpw98+db;L8k`6X`}SQ*+qB7;&A=PQZaF$)?fQ+5KRs$NP1_M82{O4hG#0j)pc
zm5%0oOZUeOZYY4)@dS;`fIjJhcg{-+#Pqsny}nQw>cn91J0i*u7DSi|Wszk-j^pK?
zXSX`uWJVI5$sq&<>25aC1g1sL^Z`v+%US`x>z_~xv)8Yog@xv#K1XG4>bHzfJK~X@
z(rd{<JqAiCti0d<IZeMf+V3Y?*!qm2%)JEeQw*8DItUur1fK!G5KkKsd9M;IR6EY*
z^5^e5V6FXBbrJk~(x&`J>hf@n<&N>napYMWTxmm5gABx%D3*7oUIYl*#^^WOE9tfP
zyP5OU)Y16X{L||~2x{nKLx1^(y9<+(>;Ws*Qj-CBy&$I9c`c{<!K%kIkP0p&^VsPS
zVgg+laW5djynlQgPT#xTIBR%@p&?>Ry#yWGX71r-Rfv_fb<O(UT)En@&m$wBeqmbc
zfF{UGE|soS;?C((Dts80El_aM5^(Rd>8gRs#%3m9dN6E_nmV`Lv8RnSp8nh8x)F3v
zYx283B9_eq@15Z^tm#_7{ynZua%Xa{=b-vW!G|R93o-0Hi8}Fh!H(-a2-pPycwHPK
zV%dF&`Km#HoxOikNr&`lkITJ2Dy15pw|%mwZv%Z@{1@cM3N0AeE8rg1g3No$3FA{+
zpevF2Tlw}{JM+_yX!}M#iL`4l2261Fjlv`bpXUq!^CGdIS0R&2yd$t92_i7vU}Z9b
z{pc5L$rjrg#<`)nGz?{rhW+CwxUPb)id_fUs`^5IS>D9gtFqpy$20>Lu(<$?W82lq
zbUKF+Q`%L+U50X8IFPFR(9`c8?B(UY{kwPX`fQ+YLpLrB6^eF_9wAc)_~9^rM_`N4
zaHDnl#y2iJIO#%7Lm{_s*$&IY7Mhf{YIbwwx%JJuW6$>t{kP!pBT$za_>G}5B)^Ao
zV97UwdckowrwhwDL}-;J2kEi2U_pplu2gJjC^ne=FtfGAz0I6h_RM=PNH2zPR*lk&
zdkjz!x-6T}2{maWjWBpHIbw*H=*6k@=X|y}mbolRE(wfS{*!j$imn07>Buj;ivQl+
zz@>c-MXwifhW`-JU*hpe$M^U5KUaQzI_v3sV0|BsN6;nCrn;~|dWU;=j#ZojYPM@V
z4yit!U>fMSiEF3&G`)1^UUt`f$9ai7m#G;9WH<aT*ofWDfq?acANyC<cdZXGhh=b!
zMFEqu_Rpsd*<D2EB&@8gIu*F=#136#rrTsFQL*|Z%?pHrTrt_(fJ<sA?drOl5WMWA
z(qTMUkP`u7I$1jKZ12O}y*~4BAUkPJ2gWH;BXmb?9ZQ5RIXQXgiNEn4^TCfONtEgG
z-nL>+>rN}Z=d9<=_qbQCDf)gt#wX%qW0&U|<vi?mA{Qya?2@zJ@1@SY&-lx{9K;`m
zv8%hqcY%c;fk(xEne{Nx^Hu0UDr%HqDWhSLP?$#rLH9fP(b?#zwwfRWJ1CY4B3kV@
zExa{ZgC*{<wYGH$@(8XvwgZZ14&)?n8?SwG!mVm;??Yqb;u_M(<1^u?jF1BMBx)oA
z?Fd6eA%t^$HaHxn8wQK8X(gDd#UassYP*RfYgQ^iyrNQct`59K2hc1+Y<G=(;v#mB
z08&QO#|>`?MP`tW(+z*Zr7syhwkA<`=>7O=MZ@K6-?8BzDtD>`>}*GW6+Xuj84733
zLsb7^0@3P|>lZ?i1+|+awf&=CYK!ZoxjmAnGg>b2My3Rn02&LJ;g8q8@4=mbf7b-L
zCvh*SnuG@B!79@&5w-g!@<hqWUQ!60G@&D)MACP19n##~d_dcdAc=Sj)goKCH=mW0
zGvs|E>3gDd$wT~6myjWjnLSkvD@rba3yK{2h{IBlOb6KRH1|1+?Di>(qZTA60Zezs
zY?3rC<kLf7=ckckUc@Ez_BpZ$rD%C@HPS<mAIYRH73-n^<vI9oF%IEE2eK4r4^mt*
zNvgg$SX2tiFv%2(GJQaZwEx{U%??sJ`JCCYC3Ad7ymRcJLpxB`HFXmXC@w7M4If|+
zzIHpcbUSD}R9o4>4my51yfTyPe=-$QtXIL5a0CI<bB0)JLPH89N?@QP53-iZlz?E+
zlRmR|MH~O?1@au?lMiPhhU4%-|M!*>fu$~gZPe=VXWYPfkP70xQHkJV!O2r1v6-ke
zvYM_mYHiVk-2=%kC4|`Fz|Do3fdh%)gW=@;k_Z&}5%}!iSY9y1e@LRnT+y#zuD*m5
zQE=Xh3=sx+9w5JL)tF~p7J!3hnH)(#JUO6XQjMCKAqoNQ#!-UEgY74gBnS<b|2>HT
z45!b<AdH=$6eP$;>*R3ZY6!6c1IjeG1mJByx_AHneYAtHu6%$`(<<oPG&s-m1d^ak
z)tQmti67WZbw4rkSuZ}A0OvRbd<^M3`Sd6EYAQFi6O3Y%aR9w`<R}=l8~GII+W3EW
zx57D?V*O75LEwa-%Z}{-egxA1=PsN8Su0wfA3T@`iC@2oJOgDI907h2L}&q&ZF|;7
zA^u*0+Y!zV&iWqYW4`}OZvY@`yR8L4S(4n!z9<iz$VvX2D}n^segL{UU~3($CNMH4
zUb*2$jscVJ%e;)l1fL+2&2Fn7q}Y}y;4ml(!9e`~F5~xe{IH?jzZb)Yr7J{?K25ca
zqmeig!va;3UTFQ&fzfs6;X{|DW{UmRPE4!h@<-l4YLuzJ%R$8=8vQcKVCl3iWQ$J1
zoEBK<bL0J+=<HX!YMvxz2&UCuITA_?-|vBR8J*7NdS5L|UnCta#!GmxN5a1X;MT*p
zStWpX$gWLOVu{B9w7cuow2*jppfs>`r<xvf%C=OhlzZJ7coR@NY;?M<7K0p5PeBlX
zYLYOSd)Z3wb-tXoKM_dScKQ0??$ynQ^2%3=$O0^9ZhqjlHy?!UHv)w0R(WO12YmCI
z&TJW$P}$oT4AeleK+%d>2j)&X9AOLeL_|QqZN+n?eQE69X-TlaASHtHc>ERh?O4@x
zBnVmxY5+isNnfpcpEk}<sM|Se0=D1=jzctxlnD_eb=UWHT84vlGR8=5=Ovd6b%|G#
zo?-{i`fskEk4QbbRc!~Hu56sWi5$;PcPJh#81L83JR_7{87paCxkCwMO1!`1NjDaL
zbD$CXHQqoP^M(z;99yOtj~`MZm;jV%_Ja4$H!06q-K{HuL?jqv4MG)5$6a5=yR1dZ
zJ=4uyP0zZf;90IB&G=={)PBbn`#v1!{%)2iDp-wnX-DGWKifoe;2U@9YxNe?)C{?Q
zx^nlQB0AxAy$8d!w~9n*k-`pzeA6_w&#wLtkAe7OBR5*?P|J#PGTh>E0)lTqF@FFa
z0RjMDm%6^?YcH*<3Bj?nM_28eQsP4BZ35X_VO<E3BkB%3x#2hKyS$bGNuyo%G{g)#
zpJ+k$r}WkJs}8K8^kP!Y)h=NT(stcLsHBa$UASNh$k)f(A77II@vtT{C6oDKDdvJa
zXg7lC1?>Acpt&_%gtc_l%=quzBDH|xf=XsU*Qfe^IpiDId{YN2LOgkfpCDZUF#>`%
z0c)LVihs1&wavxw3*zV2xJ%98?xSg<nEH~za{^H;wf24c9%|&VZhm`I3HYw?$x(uW
zJebhe3VHQOJH%Mv^s)Y(uCD(<#lJO+HGr=Dr@#;iZox5vw~y-<aTJ9Z^e?~%W?jMa
z0TPYdIR?%=Gk5<j6S|rlCE6UVlsm}40tMA<0w{AkoL9z5s0W2H4JwCJuqY@Mq9_w|
zOi`u?W~6ACQBPx}Q}{Je0LE3~Y`fQWxI#pZ;~50p@z4smwhoqy3>V?{GZ=`)4tNXM
z!C1Oz`;kUo91xO4u+WmB9Flw*pMQVEzIQAB9VL=7nvqsb7?F>P4lD}P^KmM!^cxWz
z`5Xdp%ECj%I13LSBjrI^kRzSiB<%j%I<SL(iePvvel?2mAEN#PA(}?mKQIdmy@jNp
zF&g5Rx1C^rPYE={%(!h1{#!<VodWn0Kk>i&Pmnb&1qLv+4ckPD#<gf-f3JW(k4Il8
z!VwIVZSXvNg}hIr|1b}tC=!LJoS7d5{tdoGmNz|yY+&@-n~smZ)wVO7ysXa(B;AsY
zb1^pugS#L5n{HKR6X`^T`d)1ng{YmssWC2(Ha4{DH@TMh)3bRK`tfK>%e@?D;MCwy
z3VBLFz2_ev`l$bV5rdL7-f)|VCtcB8#8TC7wzE>tp}&*TIf=XlL_Zs&5ct-aUdQy;
z{RzhQ4Dh7o2-lBE9PnW|Vy|udXA|67#-s{(IpHxRHTfxFyKKG3{zS2gAq;zeFfY5Y
z@KSBGh`r!)^sZT9GOo{iWmy|vhdvWDZjoZ3VtYUeaFWwkyyed&g677`W!4<Jz9@(2
zS5Rsc5r+lrWVv&@4>9bK^iJ9FQR#IUZCXg=tTIMv?_{j`tkIgS6&lAA_u{e58IzS9
zvt3~fNR&7n!QvjpS}JCO<jjPK!G1>yLC(}ikk5RKWK_hMLyaQ!_b|s-oHp5htmlRu
zf4XxN_x<CkQobq?r=NS*g)#o<Q%Yc@W@Dq`V@BuwI+fskqWdY{dg!O!H+ALA-N=ZH
z7_M`}R~FjSUhfAUum4^bqGCjdm&Tse|9l7JjYUldimz{O=pL0bsVj*%$fl$Sx)+i*
z*9|oYjMy{f#V#-RCFIQ4$!pJ--mvvBQw0kb6)2%1-U|&huX)w$n?~GI`0m$px78+d
z+n;0PPa^h%%%_simJ%MVH5AffE)H<moiC$e${a(QWZe9FC7?Ef1#V6v<R2gWf86=?
z#S2d8@f?6AR2E6t9^6J}MJ!`-7|A>P7xidfv-YqMzK>KQvqW2ST;zc@T5b-?G%3pE
z?+2~y9;J-f)TcZ%+N#d%(4|{PuWktjg<lVr@UI7De^8H-pU}hM7oIH`Qzp#KmOeOo
zYM*DUw(^dHFn{+2+C=nx+||&pKV0h-1v@ldq)iY{57hF5oH09D{euq;6K}k07~olE
zoNQLK_FrA^mE5!Kcl#Nu(j&9ULQVC6&@Ep&?fECUzad3De>Lj<WQrjjiPtFIuNuO6
z#YBwcUJfz~A-R71X(Cy9e~0SP2XPj2{b@c8bn-of2`4lZ*xOlO9_Z2M9tiz0+jUol
zRBbC?|5$~)i}ikBcF4>#v&yL$mAgiS{*T5A2MAR)WQBK6@Z44eCx(*7EB`yXcj9&C
z6^Zu1`+Ld!q=zQVW259h{OX{?7^xR9yynuPznMlMg@!4sogT~Cy1$H!MZJ0Xnx%%T
zI8Lzz>r@MIn4Ag|Lk=Wl89pU>o=R-9Bs-?)b6ZBmN{luVzSQ{oCEm7k-tPVLj-gFf
znT03zWR+xJrHqA-l?%(2AEt*c2tb3(gc$4(MeZ6kb9UOEJAa=J?z*FJy;Kvuf%7sx
zdv0rKEaiLP+t23=dxL_MvrC2b#K%@M9p^8?js~r$e~0HgM`S;rcprn}WRmvQzMyN$
zFBnC|b^Ef|2qV?le&+{jq-egy5zMT4tms#Qv?6AI!>n{Yf5WZ`<J7{_r%+(Pn>hDt
zQhDAor74&HI`xq6dE|d0{>o*79~MHzK1iz93?AOw9d0)#KC`KNm5k+UJRbae>60(n
zR$u7f4-RI$LOLD0ja7`fVtaK#f#a1+X$r)%^3?9CQLu=Gwo>G&igr1Q5+x;ni)Qt}
zEr#C$qy0RtQhxJzi&2dl&GRj^bT;*m@F|JZg`CLnZ3|kv`Yx|=hCP041x`PWF=@u2
z?_O7R9_Xo7&5Hz)doMrr)C`gFt^bzb<uHwleSx+q(#jIdVdCB8q2?5jlb!gZT;H@`
z<c{oEWau*{bsoKUlz$7mc?qYRS})Q+Pl)Oap*tQqFIPv~)rk{*iH?)YiFdM#Vz9}G
zcTkYMH@}s3g2jSU_Onls;N%Sphmz@#LOqIIIm7dw`F#-oTuIMu2To4qY6)L{$)LvB
za8s)MHmtqp2u+5>n726bf1ToB=ARiXxmR+`(V~I1;Q}+Qpuek(E!<)jec+?}pS{T2
z`1ygOOeJ&;U`K_g`zuyON!3T0dqjyXd*%7*;dDD;231HDqq`VeZURq~du2GPfc^tH
z`pwEF<9dzV7!d0*sk*M^^ZtBYC5kS|!)&gdU4C;Ko(CG?*1L%52}2Tgng-UnUpy%q
z!Gz>r{_3R;1yA=byB+_*qhLC`fRe<Hz%q|Ub)MIf_EWmE&XlY%(`;DV(?>FDKe|FO
zb3^P>0qXt&b_^!3rny8C_rD+9q%Q<B``_&Mh1=cp7-X2@<(Bv^XnIpXqrl*6P=ZrE
z9)&o8CR@-+iEqoBu?aOMoIc{RsHod}A%7`ItJ56B(*E=qA1|`M@OQMgmqx7bs|?K|
z^I|Q>@7goov#6oQnTVMD8aGLw!Rg#{?{zPCht~VDiVSgYtQ>Jfm_`K{g^<^(kRi+a
z&a-5wKKQ5|s@Zj0Rlrz7EyK^9XS5ODO#adLTJOhbu%^mt<R$8n#+hNDY{0jOB<}C~
zbb$ec9l3_gi9hR2d!2MW$WOhhq<5`~hD&ic3_PnRp1CUr+GM3FcUYzmx3SFI%TZ3G
z;VjUyw<)e0>7|&LicpwPraW}kU>ts<WuINeL8dZa++3B5`@T@=$#CxtSU=gj{yWXY
znu;nq&a$)DTKVkct2$0-uginsxwPT3rXD%&?x5>i{V(>v^(|o$5nuUae1Hpjg(!rj
zvW)%jJEqBj#Udo3S!Q}}J|9zO>LmP@d!q{!SKj<=NX=@@d`uo&nz`GhI5ip7;Wi=k
z_JP6Yn`;FS`&4x1zd8rBc*KQMxjBJ8^%iH`3vMO94{`E+^%WBb7Gpf5HFgvj`Et;O
z3_N2Oh-0HC{d`Py<y!zh+NvEs`HDv@0_Md60_Zw+YYVVnyw$3Dvl1h&0+xLooNkk5
ziM_!C>w1%U3x?753VCkJT(fM9z@z_L<a_5?Nn=pMf&xLY_R4~jN>`Z?n#+K`Y5~(R
zRrS*bEY<ksHhfz688^Y^E|^FXjRPaV4sm1ctfm9h5q@sZ0Wck5Q?H-ycHoMhJb&_G
zj8nhjegV6zjgWBB<|(<s58`)+Bx~Z!)5$@$#T5}`Z}M>|3yiD4lGH3wSJ}z&aL}(-
zuR6O}$#iCwSSVuVXC>rNaf32Fy4ssK3Mkf;p$xO~1;e#k?iys4aCw|yrvuTr!Di0X
zs3(fVuoWf;rn3&BV(qZ%OG&8?ZBiGQ8D)m+2!(?D;)Fu(A4TpcrbBEjMEO{dCY~9k
zz5sjFF=I&Bf(F?#0j$&GV#r2fhGE~n@UcdxT>02{Ki#0~ul<d2a))*SD5iu}@4bXK
z4q!;6`9MeuRzxH0=slMHzLNnSL$PEW<?BuZhT_s?_RJGcOKx;I$pvtj$RDIdJS#sG
zWwfu)V0=NQFjTXL-_XwcQkCu{x~7?YIWhRb^5jHsyv*tXrl|ntL}s+eeG%skL)!@Q
z2hz*Trvg4D@KHh&Zx*ATiG=yDM=0fDP0G)QnZu`711icQ-n6}8S?|xDCg6srYT5{A
zuGBW%DNUF?@loawhy$ZfJjxuF5{zt#DlVV0B%-P-n24@22TPt&Y-xuUq&dN!^i8@)
zgQaH#vs<9)kM(Jv+mVD1o-(Zo9I2C(k(wCAb*<bg$0=y?$u-ERs_cA?(kR^Qp%+xI
zG~dy{P>kH(JmR{nKZM1^?An;XadfCj6Gs&!`1vff9fA?Pd7F)rem|SNBTOv#njwa`
zXY{E|Sl5yov#1`H4CEIlgnP-{IH8GA_3jsW(!E(v0UG;yeICOdoQCCRLXh(GnW?+U
z&1r1$vkt<sy5-uOdd9{>V}KW>#RTQnA^O-w%{D%mCeyf!j)>k_Bjj(8eVZBOifs2M
z=tt8o0eA`g2&@#g8d+A2i+CF6N?WL3VMPecW>x6?2+2LUvwbO2g-c0MLiC>1^x-P`
zd(j@>O%A&}w_gsBc;bkUOS9+uh5~pJbtSTSlGCQcI%FhKQr4i=ujhYqzbbPtDAxax
zu0?meb*ZtSl$0A|2J(t9jS2moKf-}6FZ<@uw<w}Yn|%c%MuD}T`SzxyEn7Fso3Scc
zWXVkM<)dQlom#S?J2Ivl@V2CR8^M9W;b-#>!UAKSzAbSyWlRUZn%8_6!a|4SdKdnX
z4dP4|)t$bKOsmx9EWwfK38v4rgUl5CcRgQ<lh+%CXak=Av}fyh%_egiDMwnpkrlx7
zYGkm7Fx2P?(HAsvnv;(z`zK8af)c~9C`WD6T6~`rYW2}B$ubq5)~DSsyc=VI+*h@|
zj^QsoGQRe{sKhO6i4$DQBEv<~$DNY7nCn#Ne1jh`jw_QyxD}F`Y;Tvq`|x$ND@ros
zIR`4=OBla<U3_mwV81#$25XGE4DoIZ_8fO8va4OH>Vf+~r61?d7o`hDE7;Flgfr|P
z(9p;g{^a{wyiewRUQod3e`h9QGM`2yC*>~MvtNtJSeoR>7Pg=c)3=3nYXJeyd%tz4
zO!~X6G=aG)wHKCnCegB(Pi?7Rcs>-1`J~46G8Uj!RC3;}VlJZ>2<7A>z~X+z!o>Z7
zlQ(;0A!2vmdvnB@n-2srAc{2~FEv($>b~5jhQ)`JxqPV#^>mw>rx=s7G4a(2D&_ur
zj-gn+KvRJgXMS&<RPlEl*o?fysy>`AXqy`w`8_xQbfz~??3N%cO+J>d_pq|CN$y@R
zPOM`BtfZxMm2prMhF*d)Jz=D21UO@OYhp&n#5o@6Ss$~dEHi{Yjs_Rp*(h2HL!di3
z5LM(TpKkC>r+9F8@ud75RQy&g8YiwQJ?XYl7uY1LftZfcAd({Qad=Ja`d-~?b<15s
ze010jYBd2AjaW?873o*V+Q)+PY~`WOwEvxqFiK9b+6#&^ie3=H`W=rK%uhJEi<9RW
zg=qh4AIWMe;P&N^Q|gL!_oYsszU`m#N3#pRg4?=eb~Pxo$6y3*@+%5L*OrMQrQ3cV
zVrlNpg;Ky!FC)y=ruH{iwudj<+$F>s%1d)^_M3W3htc!OcED9M=#wfloBl_#W_Z5w
z9OC8lvV4qx%tzP2P9r(KoLEsrDs*hdU>bAS9Dq0b<kooWkgBiBI?b^pkHL;K%Et((
z&IL_0T0fOH_4;0Ui!l4o2`iCFPHwV@6-x`M(rxcS9~R#Q&^8h5eQ2r#s6yV@LF!I&
zHGA)hh^`JP-vHT}VW`A}isO9S<)i{jUf2V=xz?dHa5k^UJaidHI)?c9??3nv5MPSt
zC+@$m@XvOO{AypOR1;Bn*?q3SOO6^!tpbB%@+@I@_({=?N4sFix#}##7WRp#VI(s`
zRuxaqA-+B-^KE$5rB|#X^I?n4wDQpO;Jc`vUxS{eg$@o1^Ua&oKjOIm1O^tQ-7Yp4
aa2d$#w?`Me+QABdzh?@n@|CitLH`E@ots+#

literal 0
HcmV?d00001

diff --git a/sources/resources/plugin_download.zip b/sources/resources/plugin_download.zip
index f31563508e863885dcb69735bd91a6ffc75fdf4a..5b521b5fcce14ac2fdda426b0ec152e8c287e7db 100644
GIT binary patch
literal 540037
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%0D;WJC$e7|M2l^
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

literal 256139
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%0DTPtZ@02K$u9zt<
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
b->s=^{{JDs!2UNJ<mVp!w0{qvKF|LG0lSx{

diff --git a/sources/resources/plugin_version.json b/sources/resources/plugin_version.json
index 5cc76e20..8e708d69 100644
--- a/sources/resources/plugin_version.json
+++ b/sources/resources/plugin_version.json
@@ -1 +1 @@
-{"pluginName":"EaglercraftXBungee","pluginVersion":"1.2.7","pluginButton":"Download \"EaglerXBungee-1.2.7.jar\"","pluginFilename":"EaglerXBungee.zip"}
\ No newline at end of file
+{"pluginName":"EaglercraftXBungee","pluginVersion":"1.3.0","pluginButton":"Download \"EaglerXBungee-1.3.0.jar\"","pluginFilename":"EaglerXBungee.zip"}
\ No newline at end of file
diff --git a/sources/resources/profanity_filter.wlist b/sources/resources/profanity_filter.wlist
new file mode 100644
index 00000000..30b059f5
--- /dev/null
+++ b/sources/resources/profanity_filter.wlist
@@ -0,0 +1,740 @@
+1488
+a55hole
+ahole
+ainujin
+ainuzin
+akimekura
+anal
+anus
+anuses
+anushead
+anuslick
+anuss
+aokan
+arsch
+arschloch 
+arse
+arsed
+arsehole
+arseholed
+arseholes
+arseholing
+arselicker
+arses
+ass
+asshat
+asshole
+assholed
+assholes
+assholing
+asslick
+asslicker
+asses
+auschwitz
+b00bs
+b00bz
+b1tc
+baise
+bakachon
+bakatyon
+ballsack
+ballzack
+bamf
+beaner
+beeatch
+beeeyotch
+beefwhistle
+beeotch
+beetch
+beeyotch
+bellend
+bestiality 
+beyitch
+beyotch
+biach
+biotch
+bitch
+bitches
+bitching
+blad
+bladt
+blowjob
+blow job
+blowme
+blow me
+blyad
+blyadt
+bon3r
+boner
+boobs
+boobz
+btch
+bukakke
+bullshit
+bung
+butagorosi
+butthead
+butthole
+buttplug
+c0ck
+cabron
+cacca 
+cadela
+cagada
+cameljockey
+caralho
+castrate
+cazzo
+ceemen
+ch1nk
+chankoro
+chieokure
+chikusatsu
+ching chong
+chinga
+chingada madre
+chingado
+chingate
+chink
+chinpo
+chlamydia 
+choad
+chode
+chonga
+chonko
+chonkoro
+chourimbo
+chourinbo
+chourippo
+chuurembo
+chuurenbo
+circlejerk
+cl1t
+cli7
+clit
+clitoris
+cocain
+cocaine
+cock
+cocksucker
+coglione
+coglioni 
+coitus
+coituss
+cojelon
+cojones
+condom
+coon
+coon hunt
+coon kill
+coonhunt
+coonkill
+cooter
+cotton pic
+cotton pik
+cottonpic
+cottonpik
+culear
+culero
+culo
+cum
+cumming
+cun7
+cunt
+cvn7
+cvnt
+cyka
+d1kc
+d4go
+dago
+darkie
+dickhead
+dick
+dicks
+dikc
+dildo
+dio bestia
+dumass
+dumbass
+durka durka
+dyke
+ejaculate
+encule
+enjokousai
+enzyokousai
+etahinin
+etambo
+etanbo
+f0ck
+f0kc
+f3lch
+facking
+fag
+faggot
+fags
+faggots
+fanculo
+fatass
+fcuk
+fcuuk
+felch
+fellatio
+fetish
+fickdich
+figlio di puttana
+fku
+fock
+fokc
+foreskin
+fotze
+foutre
+fucc
+fuck
+fucks
+fuckd
+fucked
+fucker
+fuckers
+fucking
+fuckr
+fuct
+fujinoyamai
+fukashokumin
+fupa
+fuuck
+fuuckd
+fuucked
+fuucker
+fuucking
+fuuckr
+fuuuck
+fuuuckd
+fuuucked
+fuuucker
+fuuucking
+fuuuckr
+fuuuuck
+fuuuuckd
+fuuuucked
+fuuuucker
+fuuuucking
+fuuuuckr
+fuuuuuck
+fuuuuuckd
+fuuuuucked
+fuuuuucker
+fuuuuucking
+fuuuuuckr
+fuuuuuuck
+fuuuuuuckd
+fuuuuuucked
+fuuuuuucker
+fuuuuuucking
+fuuuuuuckr
+fuuuuuuuck
+fuuuuuuuckd
+fuuuuuuucked
+fuuuuuuucker
+fuuuuuuucking
+fuuuuuuuckr
+fuuuuuuuuck
+fuuuuuuuuckd
+fuuuuuuuucked
+fuuuuuuuucker
+fuuuuuuuucking
+fuuuuuuuuckr
+fuuuuuuuuuck
+fuuuuuuuuuckd
+fuuuuuuuuucked
+fuuuuuuuuucker
+fuuuuuuuuucking
+fuuuuuuuuuckr
+fuuuuuuuuuu
+fvck
+fxck
+fxuxcxk
+g000k
+g00k
+g0ok
+gestapo
+go0k
+god damn
+goddamn
+goldenshowers
+golliwogg
+gollywog
+gooch
+gook
+goook
+gyp
+h0m0
+h0mo
+h1tl3
+h1tle
+hairpie
+hakujakusha
+hakuroubyo
+hakuzyakusya
+hantoujin
+hantouzin
+herpes
+hitl3r
+hitler
+hitlr
+holocaust
+hom0
+homo
+honky
+hooker
+hor3
+hore
+hukasyokumin
+hure
+hurensohn
+huzinoyamai
+hymen
+inc3st
+incest
+inculato
+injun
+intercourse
+inugoroshi
+inugorosi
+j1g4b0
+j1g4bo
+j1gab0
+j1gabo
+jack off
+jackass
+jap
+jerkoff
+jig4b0
+jig4bo
+jigabo
+jigaboo
+jiggaboo
+jizz
+joder
+joto
+jungle bunny
+junglebunny
+k k k
+k1k3
+kichigai
+kik3
+kike
+kikeiji
+kikeizi
+kilurself
+kitigai
+kkk
+klu klux
+klu klux klan
+kluklux
+knobhead
+koon hunt
+koon kill
+koonhunt
+koonkill
+koroshiteyaru
+koumoujin
+koumouzin
+ku klux klan
+kun7
+kurombo
+kurva
+kurwa
+kxkxk
+l3sb0
+lesbo
+lezbo
+lezzie
+m07th3rfukr
+m0th3rfvk3r
+m0th3rfvker
+madonna puttana
+manberries
+manko
+manshaft
+maricon
+masterbat
+masterbate
+masturbacion
+masturbait
+masturbare
+masturbate
+masturbazione
+merda
+merde
+meth
+mierda
+milf
+minge
+miststück 
+mitsukuchi
+mitukuti
+molest
+molester
+molestor
+mong
+moon cricket
+moth3rfucer
+moth3rfvk3r
+moth3rfvker
+motherfucker
+mulatto
+n1663r
+n1664
+n166a
+n166er
+n1g3r
+n1german
+n1gg3r
+n1ggerman
+n3gro
+n4g3r
+n4gg3r
+n4ggerman
+n4z1
+nag3r
+nagg3r
+naggerman
+natzi
+naz1
+nazi
+nazl
+negerman 
+nggerman
+nggr
+nhiggerman
+ni666
+ni66a
+ni66er
+ni66g
+ni6g
+ni6g6
+ni6gg
+nig
+nig66
+nig6g
+nigar
+nigerman
+nigg3
+nigg6
+nigga
+niggaz
+niggerman
+nigger
+nigglet
+niggr
+nigguh
+niggur
+niggy
+niglet
+nignog
+nimpinin
+ninpinin
+nipples
+niqqa
+niqqer
+nonce
+nugga
+nutsack
+nutted
+nyggerman
+omeko
+orgy
+p3n15
+p3n1s
+p3ni5
+p3nis
+p3nl5
+p3nls
+paki
+panties
+pedo
+pedoph
+pedophile
+pen15
+pen1s
+pendejo
+peni5
+penile
+penis
+penis 
+penl5
+penls
+penus
+perra
+phag
+phaggot
+phagot
+phuck
+pikey
+pinche
+pizda
+polla
+porca madonna 
+porch monkey
+porn
+pornhub
+porra
+pu555y
+pu55y
+pub1c
+pube
+pubic
+pun4ni
+pun4nl
+punal
+punan1
+punani
+punanl
+puss1
+puss3
+puss5
+pusse
+pussi
+pussy
+pussys
+pussies
+pusss1
+pussse
+pusssi
+pusssl
+pusssy
+pussy
+puta
+putain
+pute
+puto
+puttana
+puttane
+puttaniere
+puzzy
+pvssy
+queef
+r3c7um
+r4p15t
+r4p1st
+r4p3
+r4pi5t
+r4pist
+raape
+raghead
+raibyo
+raip
+rap15t
+rap1st
+rapage
+rape
+raped
+rapi5t
+raping
+rapist
+red tube
+reggin
+reipu
+retard
+ricchione
+rimjob
+rimming
+rizzape
+rompari
+salaud
+salope
+sangokujin
+sangokuzin
+santorum
+scheiße
+schlampe
+schlampe 
+schlong
+schwuchtel
+scrote
+secks
+seishinhakujaku
+seishinijo
+seisinhakuzyaku
+seisinizyo
+semen
+semushiotoko
+semusiotoko
+sh|t
+sh|thead
+sh|tstain
+sh17
+sh17head
+sh17stain
+sh1t
+sh1thead
+sh1tstain
+shat
+shemale
+shi7
+shi7head
+shi7stain
+shinajin
+shinheimin
+shirakko
+shit
+shithead
+shitstain
+shitting
+shitty
+shokubutsuningen
+sinazin
+sinheimin
+skank
+slut
+smd
+sodom
+sofa king
+sofaking
+spanishick
+spanishook
+spanishunk
+succhia cazzi
+syokubutuningen
+taint
+tapatte
+tapette
+tarlouse
+tea bag
+teabag
+teebag
+teensex
+teino
+testa di cazzo
+testicles
+thot
+tieokure
+tinpo
+tits
+titz
+titties
+tittiez
+tokushugakkyu
+tokusyugakkyu
+torukoburo
+torukojo
+torukozyo
+tosatsu
+tosatu
+towelhead
+trannie
+tranny
+tunbo
+tw47
+tw4t
+twat
+tyankoro
+tyonga
+tyonko
+tyonkoro
+tyourinbo
+tyourippo
+tyurenbo
+ushigoroshi
+usigorosi
+v461n4
+v461na
+v46in4
+v46ina
+v4g1n4
+v4g1na
+v4gin4
+v4gina
+va61n4
+va61na
+va6in4
+va6ina
+vaccagare
+vaffanculo
+vag
+vag1n4
+vag1na
+vagin4
+vagina
+vatefaire
+vvhitepower
+w3tb4ck
+w3tback
+wank
+wanker
+wetb4ck
+wetback
+wh0r3
+wh0re
+white power
+whitepower
+whor3
+whore
+whores
+wog
+wop
+x8lp3t
+xbl pet
+xblpet
+xblrewards
+xl3lpet
+yabunirami
+zipperhead
+блядь
+сука
+アオカン
+あおかん
+イヌゴロシ
+いぬごろし
+インバイ
+いんばい
+オナニー
+おなにー
+オメコ
+カワラコジキ
+かわらこじき
+カワラモノ
+かわらもの
+キケイジ
+きけいじ
+キチガイ
+きちがい
+キンタマ
+きんたま
+クロンボ
+くろんぼ
+コロシテヤル
+ころしてやる
+シナジン
+しなじん
+タチンボ
+たちんぼ
+チョンコウ
+ちょんこう
+チョンコロ
+ちょんころ
+ちょん公
+チンポ
+ちんぽ
+ツンボ
+つんぼ
+とるこじょう
+とるこぶろ
+トルコ嬢
+トルコ風呂
+ニガー
+ニグロ
+にんぴにん
+はんとうじん
+マンコ
+まんこ
+レイプ
+れいぷ
+低能
+屠殺
+強姦
+援交
+支那人
+精薄
+精薄者
+輪姦
\ No newline at end of file
diff --git a/sources/resources/relay_download.zip b/sources/resources/relay_download.zip
index dc97f9467b469a8cd27161e57d232a385c2539f0..82fc9f62a652116ac0439a8bd5722b6f3511dcf0 100644
GIT binary patch
delta 233666
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
G0000kWt2hy

delta 267366
zcmV((K;XZSs1Bm75Pwih0|XQR000O8=mTX{u1CU;jSB<-Dr^J*5dZ)HMPX-bWpYzc
zQe|vmc`j;Ua;#bfOeH}Q#ogUm+}+*v<G$G9?(X{eu(&(y;_mM5?(WXv9L~adPLi|S
zO;SnEq+X`d{a)sEO{)MPp|HT<;NZZt>xDJJ{^r60g91~O(ti+Rl2ejqQ4~{>la^A~
zU{;j=7zYC*o)AL_`hq4p*R@OB86@GbB@GZmSV!ec{elxKwk7QHLh2VzCAD9yU7kH{
zk`gS25MFl5M$w=dMquWr&<Y8@ms{q5Z3@}_Q*9WxI5z6XXJUTfx~V`V1YO}Xm<j+E
zF3Nwi-r)B|n1BC1{!k(U7#JKFSY9FJ-<1gU`*1LKWBKP9$bZhTGxlOLb2l^p7peIF
zm}+ipX=m<Y>SAp1uiilPuVAiD{{l(=Z;&qLcE;W;e_fy%AmQKP+5RKEgrkG2o3VqN
zE3>Jcv8$_M8~^|*h6b!?@UHYG+<`^i_7hzW;u#7B7k`7hMH}<4-vA+JWv~hm{?^hP
zL+}~$UDd>q^Smg%=B&K><=M{{)+zWG0s@d@idlA1on@RHMMn{{IZrc=Sr#|=NKy#a
zzd*gD5x_u;vCh$?u|K=88^C@ri*5sGwzm7N%2dWI{=0p2cFe<X6K8e8qcs!j;*iB}
zJ2%vUuYYkb!}P>2rI_#T#NxKbF&uev!#e<|_WMF1^l|OF*e$L;0bzWA?vA8>SokIX
z`YP6MzAOt)9%DA6+9b;AxSO#P-q~kM+&^h=bu!0(kxRVT1EWd~qZfyM?q3Sj$8`Al
zGQs4n8lc)pku-n}S+t;S*LA2_N1<zoEHt;3Vt;>)_y^kQan(8yfP;aB|33ct#Pj_}
z6EA6Q;%=$nXlZHgLaAWxVQ%-Q1<29RQ^r(9`#|Zk)6?pu_tZGF&||j6Rw*=T!>UZi
z=?Jp+W8HAEl5f_l-=eyMe5dPX0E%*A{P?9h%m+xQKy6-goA$Fj&T^cdUi;S5lLLk~
zQhyGF0hPeCU>UsOZ8h?=^*7~DPlc4(f0cKaVQZ_tq(c;R#8po*Nyvhv>z;6jcK{XJ
z+iMpn6qHgTbxiImS<b_QzH1OiFCgWH4Q{?-%uy~x;j>>`G+2vcuGvuov{vr)E#Zo%
zC(2X5vPY6@;u0Y-j_p>hF2~xlHRejE(tnTBhkeDGY+{Gzp`QN@10-QX*#mH#^`%>>
zty@Qo1)s_m)Q64W7{B{6PW{w(AOqV@>BiouAK$Ls<n>jWN0&C25~kNldDvg@%UB)3
zoWiM(=UAY)Hb0`{^Y{BaB-Bn}*?#<ZGWZdiY#DaH{#(Rgbo_x>EQd@JR}IiNJAWA9
zy^b`PVVw{80e1+}R9Rx*f(PHs6c<y?J(zwv+BpsWx&wwk{c&5g^r*>$_%IXacTEN9
zhSH0zCATbXI$EsiYhtL<xYp>elWfmi3yY5kDLF!*Q7N&EcWxG)G^JZ4`N$S(K6Z9J
zq%p!*xD~p|Fe&`|pVqmpqx?0tOMmCTRWxVbp(3aW(yg0<_{Mma4Ra<Q!-g)8Tv3#t
z_qADW1E4)`>Ry(cSMD;;+Ilv6s0r`(Dg7B0S)DI|6E~mbF{eFDdX04t7oTFYtljXD
zi3|sDl`h!VA;21$PX}W%Fo78JRNp4vq}tZH6UNMX_J2i5MQm<6U6Xl3_kTf|{f(&q
zmC+A3m<NH`pESIuLZKic+CyZJ;2WI4Yy@PCTp!yLe&KTfn)G6qO>A!fm&}}mO{|sl
zBGE0wIe7jzIXHjWvz{^QSLEW_XjHEl80S9Q#Dhi}g3Ab`Cn94(cAp5#1g$5sV)C3^
z356dGjdKa$j&%Hh@ceo3%6~lK-?$mEu&J987T~E?*ptp})-$*yM!}acR9~5P61?1{
zO#rkie{selHf;*eQ_YITOT{KU!+QvAOPz~3%biQFniopKT(VYv!MuKl{DT6$Ryo`V
zA;G|8VE&Z?h5ma5I$El`xtJT<|4D^i8XHQOs#pdkxF8hB)Cy54QGfJxHN5x^DWDcB
zr4)%MMo8qsqZ=Mx@swNS4fqGFqp&HE8sit3$aw3F3L0BxGAyaZWA;VYitd}s@mn0r
z4p{U-7!>M2@(}UTB8p5y5u<inan|Pas_wLE6!g+@u}7is$ys9V_;2`I-bO3=xK|#j
zp7C@&njjUq?#^w-=zo&45m6<oGFH^zgR+n?%jj>VbhE{{k)vqj+lX55+tt$qzf**>
ztTubN<;3^fW)l~z^7Q}I8lh3MM4oUu#`~>PN?Qv(Q+?kq;J85$3?zU65pV7_SNao0
z5oz1WOhOz{VnqayIu|V+?4%tG)V*EG>y0DmS5Q4MOnqF~G=E%~r?$N5X+aLJWa(sF
zJsKK7V&RqErk6jpu<AC`HSD^BdpCqey@}789{XmE_9dYT=p>>x%YyZ0Z+I9BWR;ke
zV&?*A%M}}+flHz%v5wCErk&Ab?81thN(E?P&Lxo5$%~7PWSqWhSjA$m%;8r2F<L4)
zY>s3k`CHp$Eq{v6lxN?<)1y_#cCCdD!GqEC-ejO0D6ib2)QEtClXBe=#G`oyFb7xT
z$->%^-&&OEmx?+-5N{n(QSKVQsIm$h7mfRzDAvkyd$DvH;t<5dRI}PzzM~QtNJGjK
z^kOpA(U|(lsE5;%RIJ75qC0wmWZI$vh*GZ$W*|Ey!+$q?UGbiyyn^xP`n~}H6}rFO
zMiQqY=ltN7S<n!19gUKkPo^u)>JxiB#jdM7hZB>N{|ngJn8lnJx9tdj!lhdqgVITX
z8WV-qF?vw2;E($N$%eQnNvjixv?E7LODYi)AiaU_qs44TngQdpKEqav{|1!BFMnbn
z`C<G{aepqUaEhc1)iGjzO=I{4Fq%z2jvg1Qb%E9qEO%i7<EzsvY(Y1UTEj^XEfywR
zg|)620`#Nf$73+P($?fMlhP!a?9fM)ZEf<2FJx%o-4XkMXY9Mj{DYcwwCJ)AAi%(+
z|D~EZ{#!NuNkc_C@LpI)_yIH>V?c9OvQfH0hJW39Lbz~P82L5~I3Uo1f=#+S=_0=J
z>WG9$_qK9rU815XAG>KOUlu#Wj+~ZULsgHdYFWz`v1zGXN3Y7BNjar^XY$H|=R!+j
ztl@JquxsZjVC55aCa~QUH)z3GM=Cf(PK-k9Xk|s=VYo{=CC~FUMpj1h8-7J3sDd2y
z?SGqIQ?FH==W;l|KuiQeN638CZ#DU!pad!iHdxsCO%Omn>b8D;(>|std)iLYzk+@;
zOxkl`mj*PDYO1I?%14g)eUumZq`QU+c2EB#iIPErR$OanIDcEb8zf&eJ?_Oy=gWe)
z5EBx;s4wUn-N4nyw}~F<zr`Ct68dQbY=4@@EgvU3S;zR=5ly%N2ro&qKtepX5yF_1
zW=hDboRWx<rNkOD)U=5;XKJWIn#DI|l4CPftQ<c;1pXR^5VBYVk%J3K2WO^rwHt93
z!wSeYaSlY+$1)sidFh^Kp0Kq4^uFqR%|y_xBR3z4L}JjA9KbHdW{7nu2nlKChkqVw
z;D7J_$-<pg&PT&s;(Zd{Is7F%B1tp5(CC#-G6JNoB3alDS|1iuQOV0glcJ}dmG@V`
zIh$jK34=V?TVzEy#m1Uq*Gv#{K&Fq>R8V83?x~7Ym9lkr*Mx;wnk(HnxaC#(UIxJv
z^WjE9Oo5q(_<BYFG6e!_Sgbe)A%8EW3%@!(0d(-iyuZdLFd|s+#?h%tE`R6MlW4Mz
z1r37;pd|#^x(-Y*lo5zhGt#(<oodda?$ZG|(v#vEtRlD>;KegWlS6*k_oY%=CN?@?
z<rW3J(3tGdUzb8dVhLPkqt&6E5<vWn#||*v*5w7M0ZM{|+51^V1fX4BZ-3iGl@K-W
zw?t6ha=MH}2A4-H$aq;N3Ur`ap0C;Gyq2-w+lF)cLLhCD-0A;yz{tu?Xw1U$H}j^y
zb-99|c(h(&B_MX|ay8M*39U1-(t(FbCW!R%7u#~=Z&wOa?)wUvOnlx5#Wx!kMYRj>
zF$0E=RQpa1kLso_zhEW|#eW5y^s~y?So{K+W)(3iYOJWPZi?wIJ7cyq`TDuSmT{y%
zL{DuHi|@QjfQ-8<4!hr~q2QAdGB>?>m7-Qw#ThlrE|d@Jg_D~@A+hn{c|oIH)+*jN
z`Y~|7FWj>d!CQ+mZK6LF;=gu;q964e4L`2mM6{&ZJ`+@1TD^oAntv)Dj0+ysD4}&%
z?@9ZGK2Q-j#${p((&V_i^J!q7?abfUZw}s7h7U-`FIlTi>n6(t*1sv0M??|+X4Ola
z7?-fF&Cqc$LYlZ0yQS=z88Bnn@j_JG47%R)fDSE?%s7@i7ojRsS3+-#W}du4v+#VR
zNM2E<6F2Ga7z7dyj(@&Xdc=WzZy|GQ>r~`N4s!UG>tSyAi;RZqq+U*<_&DwZ3XLg9
zjPhTq5QF-SR)JIWB;zP0O>^n!vp1%KlaL)0B;WD+bQ)NU7$07Kb(el^zyX+V<r_1!
z<GZL1WT%O@=t$c47Z5ZTBm*RzN#=!;m#Dcj=tu5RkOgje2Y<%oNw-n6f3fiLO=?6N
zOa@^C*J6a|bH~-%+M?vnmTGZD_SRC>)`%_~-EG~9dj$)Oe|X87_gU{2)#J^m&e5|i
zDRaFmD18_2*>-r2x+O2GEESfs84N)F)_0^v5m2^A)n-|0Tt@!!GxA$q;~{HL<hK$V
zCHe4Ko8LT(41Y_M2*cuaF}`*clSQUO*6g|?_Y7QnFNRgokNC>CN~RGW(OOQg(@Is%
zcE&{@fBf7-ZeV69&G4KS5B^93k?spaPtSZkOMQ|XFFW4|c_IYG=nuWb1GtVdS}gb~
zKFLo`@c4K?%l90ggV-A6pGIOzH#w-AiIa{r-i0({6n}CE#B;r5w5w)rd~GGGBiRs$
za#aN9jTc`BrHb&sB$-n%1RAhfNglsFSZO5FDQuU*7R~TyD?Hf0M=b2dPq6F^kA|fd
zggzVg&at<Jr(btor7IhHOrFe|^)RlHre2UbK8}norOdFm&4Cp~4M|_bQNF_C0pJf-
z-$Lk!@qbog?(BKpX@*-KcN^`UE+x%v*A7V()<9=^Z9(6H?czAnI!aH!V!4o}2qrn=
zXmI^N_#vVH_S3_37y}o)C6ge>_}ti1;QOVS4Qp6-u?e+|ol4|)j;L}S-lR6M59G7q
zGGH5N*yB|5lyx?_`si6%S7@6jcX#?`M~FoITYsZNtA3oZ68M64ndkMuXpV}mflz5x
z8vc{1j+I1|FMz-us)_{*gyu<`f-m7djHy*POZeI6l|qhi7)nM*pNz$oQwq=@_gDlh
ze3@dm&MdS}wcv~KW}fod_GoO|+^EZ+$z|rp>(tzEhWD1V+QHkxD;dyIA0-I*vZb7~
zq<><?<asllfYlvtfwpJslh=WHqqJ?78SM~ume+syhV+qX5SJf73Q~=#*24W&`P*G`
z)wBV<RmO>QL><=&Go9m1j^qC2>|U-X{Am*>e0rVct=15j4g^;xWSqMj+dg+*(v<>8
zp4#QjbWRJ^Avl50QQ!m3*vVHLM!#i$n13HOAJat;$ZxFKK0}Ja@Re76x^+S{lD{dA
zUK6!xmZLWF@E*3~<?7I<er;&~Ug<zqp@)yuVoc(2f;;KcxTo~G$LwYTxxAmtS)uCj
zkw8}wkhm1^s>ylna=i|AtyF1>rr);6?Mq=}V6IK&G?nqV_ZZT_)-i8R=%Bm{f`95>
z+b7|<q}%Kyp}KPR+ltBZb&e`Ytbwm|bVhE$HB9e)O4GMhA8zy9@->qw0&r_mJ3ZlO
z|M*z4pz{ivCpD9GG`SNRjNgt<^3v7bH?H;u{xH)UD<M?Oc9cMM`|VwYY4}+9*$w=-
zMy2VYvKETzsxcNxv0`;%zeAn6e1FnKwMDLQ<lEN!R@74UvdtR_K|>WTD)o&lPc!^=
zy(FqnM+QT->@Him{v%YDp<qVu!n|)PGJ3A^l+zx9cVO^Tp@FAp)n>&0xLnsWAFM2Q
z@VDsZ>n*sH%Ot%iaxc0|l#go8AF0Gjd6q#m)}dSaw^*iDsQxW!&Mo2i&3{>bxoj`&
zka4}?;?!-Cn40<(`{o>bnuFG16yi;v*;APZqM?!6C;+xZQ~I+v_zS=xKfM9csW#@b
z{kLU-Nu9u0{7*p{ltO?!^3dp{&P4teuhn`ZFxY3--WQ@7>SI+~rAqf5A}$p7>+Dkr
z!ah8uJD4Li*$KK@YRoifQGa1{oXCp>{n~u_hqjtmfdcl9{Qi`pR+s9USEynq)W;_2
zm1cj}FvrOQ)}|~(SJDq>?@VWJ;bB-f@A&AQQL}fYfZ-$S;Uhl$9=Xnz(dSEr;p;<7
z{ag$E+^Ac!{w|r}YfJV39+3mlOy@782dHo_WcY!}W6xXf(U8`|!GGD&pHiK1W6w_1
z2cGvFD24d2E^Hq_rynMiaYsnQ;ddM;CHUd@tXg)osu#RsbmL}zv?2#ina;eprsin3
zM0iD38PTXmmPAS%C?`gh$!OKd(G&C0fT*J$r$i^^tR^t4vti$=ncnWABHZh1pUpbS
zdSHp3@qzTJUgg1vUVrxa4beSL5kJRjT?xP7Kxg@q^%m%<x%MJeZBqwkh!-dGyI(tN
zj&>cYH-1*=iyw2Z8sh=S{q!Mcle@_cIW{Tro>1t+1%<WnU?LIn)5pN!FJ+kM%^d`<
zKCPSE?77qZ`yJY6mOnV?2QBufz2Eomg7N;9gI4*E9JJIQAAhQ=sQuyY_kB4FYs)_l
z6|7y|DE~N8H+S*)i@k12G5`>YVS#o`^Rwcr2rk13MGDZ}>^rc0R>;GCHc~a34C-Z=
z#TlFD{Qh&dY#W$>n>QQv5%f_y&rzYHTZENqnBzH}?Y-@4;nCy&d57H#SR{@{-?mi>
z)$#X1M-fNSaep`ECN79w_;LmdGIdA4FdJLm?l$1^dF4H~sK=+W7E)*8wzMNUgkPXJ
zSAbXX42`?Qyeb6x`OH~5+r;*ti|W+C#Ue-y$cd+0f4JEdQO_H!F(YAc>*hq-=hY-0
zc3O(}5B^40=8SvK#ni29v*|Ny@;Gl3P=M<K&!^BvYk!&<zp*OFC@$^777JfN((a^E
zdtMi{-<0X9Djv+b6wMikm)*QZRO-Q4K=Ny)&TgVe%h8CxlkjWD`VW<vOYe|3C0p(o
zo$Vk@*a_feplyQ6$5E0VRVVS%EO5U{TCtj+Mns+j`;8!<{*kF(r}KLeW2~Gae)XbA
z{8Dx02!EB<ubK4Uwtz~XmBZ5?ejwkDKHW(Owj~;bSlY5z)0|ZFXOB?gutrIZF`7@F
zBfH9^H{)LOP=BS~3e`_I;1a7wa8ZnRpENf3a{sjh(FA-lf}Bk^p*?f3iDw)257e1A
z?bGQ3|9yuT>R(Yu>HkC>4R0s&KM|)&UDa`31%K;<85+UBJi-B!J148Om)iZiuoxW3
z$SicKQdFFiI&3R}xrovJ>*2Sv$6Bd_{RWY7F9(Uu>_J@XB;V<_U(+w$uD(}sKfW=8
zclNsCgM)aupExI;TisdtcL{i2aXfuuolmW=>W-Zz@N6{$)dM?N^2cX|Ip4bVcnnxB
zeSfEJ+0xL>B8c&6U{V_1beBkw@j`qWnkH%ueqbvG+i>f>X}DImZ`c%W)SOq9PuJc%
zq+%tQ%&^-pFtEvH*k$oD3_y~I$$}4bM)Epv0HZKRO^O4STCVttw^$bIFKLahOX0|f
zf*C`ku-W_jJ4(nyXj96wxOa$=+c&KV41b~+;#rkbl#y%)4M5V=0t4Mxg1r*>6-c+X
zJ|op5u=LBd(`Z~oBY01s5mV6SL-k|3Oy>!<je4`qzMt8*+ikLeaJuk>9CK8R+)^)K
z2@*?<x+dd*JK{p?XSUpHN2D+jpU}s8Bk#a^PsBZWTC5b$Tk~EFQGZX5Y7KA4wtsw~
zV$~YA=etEK1I3KWYtL)p2akkzl!bEs21`nk2{U+oeeG>Bp6n|IWrb0!6TQ?1Rus)A
zc4bm4RSty*2uQk#{MsjeN+>l?hv7rx6$$+d3Gjn1luWK71gz>_mQ0#tD^qSuQ;p1R
zv@IsZwXhna-%M<mHnol&{6wxCjDIE9q^yDBh*?0YZ!JER#VPQ9Ax8f^t(Zb+%z#F>
zu7XnM3L>s2^jAz;JQ<-V4&RQ0(L&nvsXt6r_B-?+s2i|>947+t`_2ILzoM?>|4iLK
z5q3!X%~fNG_%l0etILyzhYB9brD#!#&Tf=ik5+sQXoOMAXoryr+@;RnHh)v*#^v@*
z^Yw&}E055%uM^g_4;F6J*wnRVu;LM2{H^gov{DI2jz{r=$FPW~<tv~>9WN|k#^5fV
z5k(<`El#NB`pvI<=YGqRCC8VrmtJ8s9xqcN7oO^&i(!9_7u8uP;cz*q2-QN|gWv47
zu$!fEZtY@yoldKY&UIFncYmSO*wU;OZ`||T*A2sjTAcWoz>6qI%w4CWwJBVWd*HoP
zB5?|DOvRQygOY&4oSW6FBN|v{S&w5GflFl*{Sk=6e3so@nD<?SJ_b^5fRkMji7Ggg
z1V-DIe%d^lZ8C@Z=UP3&yKrfGK|YZ%jB>%iDYQfp0*@e)Yd&afqkm!G*XH^1TheAY
z#-#BLmAcR7oWiy?6hbb3*{p$dA`e_qcZ@HrmoBf>#4NQYrc|Nn`CxdM4&}i;)^x@@
zeRq)F7~TL5!$_1N3(kQDehVAWfmNSAbvKHVDMOyJRqA~O{TjJbBrAd+2^k?(l~b3g
z+7gLlkLM-gvlsH=;eVn3nE-o2b>a(+SFr&pwcZJ|P5y$_*|^T&!mb3dIQu#Nxr1y=
zB#SZh)(>NpVmyf8wZyl4ZHc6in%xPcB4}q1e+w3aTVfpwQ?9LJPH$Va7JKY(eY)*L
z^*u=&WtCjLS@wxj55}NOas=CA2Y!>{h71VnP^5l?he?5pQGbi#SbsRv9MM%jHocmC
zB~Ff38Ab{T^dv}srUY5VIMk|DTGIiAQiTc?XWVZ2yr16LUf)Zo$qS`4>~KciQ7P5A
zaoMdpkcrvXX`uOzJyE}wp$C7%*1P2bu?vx0j~6fCwAd?QR9L?9OI<)UL>W6L&oVpo
zRQT%omip>hc7ODs8GQasAwa?WVrExB&uZ-j@NkOP%f^t5a|H~0h|f-*Vm<nw_VJUp
z&oP87$UG{Ys0QbY0nK5rlANz;%2oE*H8xp#Px6Oqzx+m<EvPk!p9eF8jK-N90miyS
z8LwLc4Y`c9HmUjfsxr6munGaIPo*ZL&<L{{gD|v=Jb#SydtobEr!Ex!5W}t_ox|4K
zeCM7nfrx)e@dzTK#_-sJBF_X4_ScKN-l(7KcHQ2>2zpQDt0%I!b=porCb><C`{yJo
zw_ix|=WQ(A7)%{`28p$?0rQ4pAGMJZUO<dV)&oCB*uGxu2slx};aaBx^P<XH5tFOA
zB<W3MRDYN!LTYfn3*4o1XKdw&`GeySCE2&s$N{fJ5>9~)M*$n)m284d$u6A_u%5d`
zf&M!}Zk}eQ&6MnTBw}Nr%#bIv19rm1zB_sr`Yn>b^3W4>kU?|Z50c6PB*f~}?L@9b
zrSpqkRE>8u5%SN`Fh<-DCMK98lcQ%iLo~XleSfZg8M(mhdbSH5^?;6>!M7pbk%N#2
zDr}k?cJuIDCD)|Mst%8wZ2Pu?UzYTS&f@WM*eL#`!-z$^-@lDNLwAu6xyTLGRBP~8
z>xDcfM=p37;9<n^(9nHr61}CYJSz%WNtuK7Xgae#!A?uCjDOX|W7c=1-#HXMYG6S^
zn17xp^wcEh%|y&V`z<PAGgJ8oyL_)X`!MZ_qal(XZ+Ht7!j6R(<;_~S#FulP{PBf@
z-QT$A28+KnJuhIbAj&QFNGT-gDFOP*=2NF{lH`YzofijH`3kPGYw6bk1m?POD!ciC
zEQ9Lm@&YXjxzBXOp#+3OCx$XZbm8{Q{(lJEKS9D1C3rY<v>sa%GHlm2YAKZ3#=>Lz
zq71l~nuyd-F8nNz^5ZpD-<f9)QcZci2|mV)s#{br81iyNwMoR5hu0at9*qlXg&CN_
zjmRpSt{SMu@}$(#gtJdodCQj{3TASq9gh`IHS4AtcD@H6=ZZERPn)Wv9NC)`@qbqA
zwjO7SHXM(e0#Ix>LQnD*n-YE+ZNby_wF~Blh&scC91Kl|9`w&nuYu}oqr$crFN}@7
zk+$mCehcS&O(MludARDD$rI<>Z^(8!vO88Mk=c@XlAv>0FviSAS9M1ms;23K)dEAK
zLRPo}^PAD%Z-$YSt*t8Vh{LWqJ%3t`bdtUlzramtC#L`M_WMQKY`cBu?oH&j)uUUb
zCNxqfy83R_XE6o938WaYQY$*XowBabmx90boZ848_$K?>LVQ-IEX$%D>DuMiwU27G
zUCR)TG#2;@bLiM=_<|_cEfDVA5X(swXK8AD{Q`hj%;?pv3t$e%HjdMwpMO@nj}AAV
zawQQ~#EGbw70mPt(c*-w^%}PPreRMqLprd}rhy3)J2<$9PeeEr#}Jq}qI^FZvws4W
zAKBoQGN-4e>Wfn&w;B-X;>z^OD!GP{Z+L<h18~j`2u3X$m`5l0Bs(h1PU=XuwBvK%
z6ODIiC2@^7;eI{F=toGbPk(IxrMZ~8BWCbIpV$UtS!y4M8uLuCyr*o{|D%p1kg6PY
zE+i2BD6kehtu}$p=GlLB@R+<G$CyJenu!s}-5jF(rg>^)TboiPMPr+f(gnR`$I-NV
zd1~yx=zzNKkSZB16lCZTulpMsXH;Jjfz^pc*`AQMRk`0bG~gLstABLdlJLIKxQ|^^
z^a=N(z40K8#pEQ07$hR7&&MaGeqmZNX<38==%VVaheR*NR1Vh35cEeR4+hYMLC%Xc
z%7)+m<O~j-@9@%jB_v7N9x<IC@#-9mp^-mU!F+&`I_F~SQmCe9#~D{KZ{!QCV((`U
zP^9_|d1sn4qF}>JpMRB40zoisj3Em;w?Go2QCb~Aw;amra-Hd2P4AYX>(6~tMzhL(
zJ>6Gye==l!;2Q;S@HB(yGwSX#Hg+C|V0@fev|L9#EcG?8{ZhP(#69w=tMM+vw?-iD
z1!B>%dNChj6L&FoPrnjuShdp|=K!U-+6Z)BmnHlo-{+n4cz+MSd}<~?Rd;|Vn}CTa
z9pKjEUK$v_v!El_;HuHF6Ks`)|KU{fDDnrp1cT)y(e?Wi9vA5U$}VyLS9a-dw}M?d
z@P1g@#2<zz)L%h3{hG1;&7$yfsmL;r)al%mggRLjcCwjJ@-!VuX5$u~8Czjrq#8BL
ztC|fp`?MHL=6@n#WiZt20D4urj(Uz&55jtm_NwwdJPmRlN!Sgq1EiFW$6Ze%-Je3<
z=SSfr;I+DDbfXxw$Y*SxD!<V~kAQV+sdk5TUvRWBVDseM=YIIvym48_?XM`jwON*h
z-~v^=U3s}Ei*xS5<FQ@&W(tv%Z~W<zgNk_GZ_%P>xPRIVxNh{^s`4qB@hL|ey$y$K
z7Zuy0#r!tODZVAB{w^kgI+PEQwmx#3j_$T%i=KP*7JU_u6O~1|o$b@^AXwA>9kQa?
zOiM!zL}3$bH|s-Z7WqpJ8!p`^nZE4tO_~C2RsteFr*s9Mj6#cUR@cjT)fy|ice)-Y
zvm*1@<$ntyho-^+WAH`4InxVTtAZ3W^;k(8J=P&zIt#1)A~Ru=6{`I~ui#{I3r_iH
zI0dRUoS9~&lM#9<txop7f?j20MXkmcWmM?=D(OlYBMW1Kt#zseb9&|>jj>7{DR_NO
zITciQ0Qvb@3akTmk&f7>)IpAFl$McJ-b#m^;D3x@W#V{>{IqsOdWhglqx2BfXcCz*
z@V6i@#}Wr_+Z?eovTq9ajx@5rF#s3h{S<fj$yFdpRa@@_af`l2;_92lIT1LaOI<*;
zQre26IcOzGNWl&hQMVOr<At>d*UG+MmXAXSMSaa4lkVUMUpcN*7yF>bQ4{Iz6(j0k
zJb&VYPvUN+qQbJ9>qTIf=txg6N120nb+xQGuPmBF(8aNBV2M5(nuV7^vVfGOWNqWK
zgg<MN$${f>we}lP4qYs}-1xG@)pDyLWGLKtJ%}*t{<;DOJH`B&!cGslO|hcH@0q@n
zH_Z4PorOjfz3b7HhI+PS$r%~p_LHcNw134}WK5@xQH2Zq9!7|q8I3twy(Iw0v-Tha
zgJbt<5xm$$QgE$iEqj|AZaZ2}?ko^V{BY8+LVaOUxvEm7jOXh>9@-wkUi`v7noe~u
zTDrq`j(!Knf|8jUnL}v)W*J0ivvadta7NEqbR|{jL#+h#sCmt88)dE|!oj?g0)Jd|
zYymS1<;c_aGh_v6EN5tiP&&FJgCV60lX~|Fq_%R_n354ky44(2&xR~f;YXvI5IrdQ
z4-Puh1-LqhAvf%r0pVuOA0>I-gklaA)i$NK%Nkt1P^rqj(*@b|M2ow~^bSMzcD%aD
zOf<)9=qn)?A|Kyd?G)4}6k03Ke1C7KvEQh&GqMDi43(owEbtP;Xi5FO8X{Xp3ENcV
zj(4YX=(i(V*d{KX>lePPZ9%M9;5nD=^_z_iY(bb4`#w5c$`)o+%v)<Ry%<4mpWC%p
zuYFzDZZF@=Ah7puRj}9)(CkFKwg9rFmz&s;3UyIprmLoNM{HBD`r2(*$A1y_1vwn=
z`A^nQ<z438RI7-0F6gOWx$Tk=C3}B<1TOID9mc$A_<@m{UDzf>EG6lmRmX0~!_~wy
z3K#C92~R2!Bfeq8aA8Y_M1{n`C0km&FLC)SIudBrpB%7~v$G4A@0-qFt5=EE+&-7{
zcxPpH#US6^9MH#(58zW6Cx5w#4Uf`j`XT%%7E3avl#A}=$^gmMr)mL-PIg)Q;JzAM
zDdcN8CEjuT1|pY$BD1u6;OGDfMgwU)Gu1M#eme;G`zpw?kKGa>{E?bO6+zD<wnq4S
z#=-8G9O6~s(s;(I)5GL}l+iLr3f>@fX3N%*+po~dNT_LAW@8{ru7Bg1J-OIRfhHq;
z$BX(`eHSq5YE9YLZz{J^6{}h8I4RrRi`>$o-L`n2OP^9<NefD(-TC_!iQcKk?g=#&
z&oJF%sp#L6F4sAkOhXh8GZbV(=Tj)Wh`b13iHVGQD8d`GPxgEvmQue-cNz;=QBrEB
z3J~_Q71*{cd@MSFI)5&39B&z%3Bb=tphfT;uFD3HrW~^tQ$@~otP?FY-*r4xGkbVC
z7w98IRBzQ4%oF7O9%Sc;cnCVmFXawT7?Vh1i5EjcJE|Y}Plvyak3UxYRzhbT-?ETy
zRkw&6`hNenjfhR?d|vNLL)Yf5hi~DiM4SF%;%}k7^PIEu6n|McCfA2*%?JCCgzE2R
zDIZahJ@WcVkOeX*S3SK!a#~BcPj6L@>!(B7_vcs%%e}ua5EnoD2ZM2)osbH3r{Hu0
z37<to=>h20Vm^GPvSkWHyfkEdetWHFE4IiPQw!>!zpd8?eW^AQ8-ro}UN?RnD6E+D
z?Q?nj+Ba9}*nbtrj8R$c;#;E5OW8Enjt}$h)R~_T4BsInR3r>rL1`;#LzMh0TgfTs
zaTD_XT>zsKHZQEx5je@=ZwqEqE(t_c9gM&x2xE=DR~VV^v-)lt=Qe2{o{ya8^A$1)
zSXeiw_Arzovc}b)sQ;KK+k==4#?;2xQTs3qlWK*DQhyDlvg+5oaejiqGG>U}lYuvs
zI&T{lj$=QhM?)CLW~~2&ymyU=!R86R@z#~owUe2Xn<No0>ILVVIN4X%5dp@0<qcVW
zJ!q}oea#L}*h-yhVBZ1r+oZ=A&Fb_a&|9xZbRZg3Ea2p;;+E*yonVyPNs$knbQvHL
zzvv@a#DA1kh6unnfNb?{4>@754$`C@ve~8|XnMcg)1Ap$aW%20Nv?vz%oC%$fF9k-
z|9K)PSI>01<d<ZNI&D(#_M53yB|fq36wqmc^ys-+{2`dhw_DRwp&+3l%UL~TDct02
zNiR4Hoavu6eGin&t+5A9B{#2-tCJ->j|U#OF@H|sK+iPf8Fvgv(tZIbIvlxl85Kdh
z{IYTD%>}KSZ84&FKUk-0uq$Qu-yckh6tRmE5oG)buG^1`jtFEW`@mFtuR|IVi8p+Q
z*L(kNeEX|xpYAd_`7uN8ps4BS=7XZ-CcTC!P5DR9&*u-${f4+$vtBZ+yC<LaqD*6z
z0e`d`)<;|X9YQ=bLVPGgyMFi8Xns3W*1@(bDT+t7=tmCLtHZOd$*8xvXjt#x;OVjk
zX-x~+Po8-QMxi{0c)UmT-LpGjwXISUwaQI~Qsd;SGg@qFk$*XF;}*jecKcp+ilbWX
zYZTFiM2_z;5g&+>h5cLlQ@vM=K|W3f-hb?O7xLTwK;=Ea_d<bW+4h+Ear=k3iK1u9
zZhb*ujd?-J(a{<Ai*SS^^6tj`?#>jkVs0~$H}#a>-5|OGz4yLq1^}VliuR^tS=U}-
zx+&5KSR%lRNR23+oPm*te}EG-5$~S6a;bl&?lu1KW+}&XGl1@Y4LH@~lineFr+-DP
z8qjq*X$wtPzEsv(R~~o?`GLHT3sjkec*?FivOA}I$aJh~PDN}*oz_S2Fr{9Zco}NM
zYq_ywarOOCbVl@b_PBV?jV$GzD<DawDfvOSoIlj&x4Jg0>j450CuL!kwfz{UKaF;^
z)Ha86MD~@fOHonPKfTcc0TNw5uzy-yPp+S3LfU~+l4{CS4^i;2xr!3ru)lfB*?gfn
za1=ahgF1TQO!iE;bASW4<|i`*|ATXttp9D5*6)9B)Z+dBoU4SLwYh`apPj4rizns^
z_D3$2uNfPqwCE~QglGgK;e-)k1bAqI85-VN9WcTPju>F-ElQFx7g3Z<ZGW%6?xwsj
z<yHic)mw)OF^|ARFi>x2aRWRFUGn{cT~B)KrZEOc@9A9TiLBnc?Q~4MUEN)EJ&wDk
zfj916W6<Mex-I>dGNqv6AfxqMHAPa5%LK%3<TF1&BB4k>A{Zcs^x&10S)PSaiNpn)
zJb+Ml2CwY-3C?A~u2H037k^66l<HO#4Gbq;4V1i`Q5EuC{D{}F-=)z!sI_6OJj?99
zi{B-?LSUNSJ<a6&Vn&de`!nY}J&(Sa;CdN<6$RABC)Af*hHNECazm|do$~m|u2HPW
zKR(NgjM=URuZVhkUnr@z?<}EM0w0>*JCGGwVNjmS3M=OlWL(Tslz-&36-_%9Z9`US
zi+7bR_#0x4=tkswd@ar@!-dWHc8{&sH~wZH|Bq?=4M+hGk4prPr_CKggzMM~?=SMj
zTK0=>Q+AfT`|VuyN57-oEP~=tuqYZdxVr{-=-~cwcXw#qU7C-(ySrO(2@sry#@&Lu
zYh%HanW>t^)GVfIR)4SF`rO4?+*{_$70ai2PK~DH+(}Nrn%VqGk%+aSOOA&qpVN9j
z(S9=lA19NGJ3Xv2-jAPmMGSy-48G2AW3YezrXoZ4?fIKYBs{5UeX2ToH#tRJ=A0H@
zXo-cLCV6Tz;xt;TIq}e!x}o*tE=5K9?`;5|&sp=#7KoO827e3|1eb@|?8>@fIVFM1
zNGu=nu}BUE%S_;v&PtdQsQ4o8sXF|tR|@fJv^R1dk-f_i194t+#OAk(?kH_zqK==5
z^-y`}0?*_E^H7pXB(W^ow3Y{L<Z+Ag&Blb&4*P+q8oX}TYrFf?^)NfKF<Rl-s5ZwR
zI+|$bE;G&yIe#eklhP1b(Rz`*Cvqe@@8&FE$AyS#XuLpN{WPAXa-Ums=76EIf{GY;
zS!twLZ5?ID+&oBi$3H}-Yy5L*qD>rJxNnQ?<|K<3fb&ZQ^%nNRQaCywTs=RH$fzNY
ztMbO0^qksgCvfJSq|1;>6Er7BzE>g}<#<}vf<LFcJb#x_&XrZ65)xhz%F8YZ`4lG7
zP+`GjOz8E*u3N0N;GT_WWh-pRV$lO#b4@M@P?dE7U~R4(qmgRi3Y3%W!}=F^dT7{V
ze4FXPV5<;{2nUsgQ$?;x6lC7PcYVlOoCE$6>nqMrB;Tw+JGrm6SDQcZR}Z95(Y(Y>
zUBqDw<9|!1E3FaOee{#>mwD3g^_>{wpNgB#H|giwO?nP^3;3Pf!8eDC;raQ>bGJI)
z0>l<pSAMnz_=w_ENPQTowD7-$6DSZgf|f5`9sTN689{a~qB+Ejd`f$K>m?UA9r%g;
zYvUHM{betuW&7OdbPPnZEp?meAwAP0VM!Ff;eXMu`xt?A$H!H7B@}3GYN}G~q1~;C
zhtW4i+&8<{%5~`|xW2S`%xakhC5UXld+2yx@|>EJ0=QLErrq*lcqIgPF``k72wC>v
z-k4|WBI$>Gij?f2Y?g>aFuN(Ka>xz--X?(BN!ODFwD4Uw^iYt<(Tjg2OI&@k>?xw*
z^?#xEy@O%iPb+#Zj>o*kZCCkwN^;{vH1UXum~uq6+62!$hj22v?}MLUN9xPV*S}w@
zVk{l<TBCO&Rk7e-DB*G}#eLJE<1IjwJlyRX+wu4k_a0HU11^v|ipk5zA5;?vJ#tUs
zD+hGqegi6SKJtwDw+(%BE~Bi#uYLEnihrq&QYp6=YB-))#KIJ}L?6&{GwFtRspur>
zD(aF$Ca6PEr0jid`mV3qsg(ZklKmTU-XxEoLZt2iZDHEinX3ZqqRkfE4}E)vI6T#!
z4}msfe=GZ&2h|KJrOr?e#ZHB+7s`n7XB2BqO7gOt5XFz&_{RG<?Rn44W1p^2!haux
zefnK~%xlxohp~02Q)C7;34=MH>P`mD`*kCKvL-?x5S)0k|Ax~ii_OoJ$fr{p@dgtp
zm$nHME%w5UCivFmGDTSiY@{za|0Z6N79@C}X*ksrf)nUo2ARq>SXfm2t$@DfMjm$+
zy?eqL7?K5&%`d{OIl_c)nT|j61b<3ao}R074FuTHX~O28_;3a${e`6(e+)@{Pt3Y`
zj|qFSnXmM_pvL*Fz~x4%jPXm2*<yG}C4tYlHI7A`rUQMFG5bZ#K)DrjTDL71QpIvx
zv8Lc}CtAvJU{UbAAVq)LI{X`!ACOn=VQU=nLod49tms)pb<99aD^j{mLx0|oE<pFk
zsM<w)ym`%=aAtyeMRy<`yU!5g=CyX2t*fcj0i(etYF(M0pGvi{>L1-yb))<YJnghn
z5**<ycn&GHO!Kc-9O7{GM5?nr6D*!=fzn$6Fb#@dC=<U7{Cp&wcSGJ_c17GXK4~7B
zw+MjAtfup6$ilXvO^3j>Eq^CNB%Q}gEU_oAG>U={75NuK7L-opgq{@GQsLn`w%B&N
z@~T;)1CyG(MXoF6XCqXWN=P41=`Nz?kP1}R&3x4)S~4WFzyNsxDJ_-{g*(6Is#6pE
zhXTzY{1GHx?Bru<GU7pd1M-t(lP`da#(}Z@$IS&<MMHZLMOc+%cz@PBEa(a>3_~kO
zh!A>hhy?P77d7{jK+;pK#l%Ab3CCfx@0L{{bh0HT;kHQ3oEeS_6hNvv^SK(SN6(+@
zk}U*SLX*lG;)wK=#d{-R+llYzC7wHQ&M)S~8QL|=A2jNunnOZ8Xeh*myvFiwiQ0FO
z1>IstpbUEu?Pn<U%YPY3yL$a<Vis1h<7P;Z8AEMlN++WDu~-sxlf22v`s%U>8u!=T
z>WLdKWkLep??WE`%>zJbBFB>Hz@i0z5#-b|eFGA+W$6;mXwj(``ed2-v_MqIF-S_c
z-7Dn_lXc(Yl@8}`Q<>M<ClzE$S6<n2RkrIN&B(2ByjEEGrGIsS?`tB9I=CCCK19@q
zUB0}ancZp&&(-OoW92sObTlrUW8TW|<w<SWxzVTX)w)r-B29Q(pw`wxmBqvNo;m3m
z(R5jbmZV-1i|Z8Jll^5DJ=F(et}zVOMTqqem=oEs9yR(x_StP4lm^|;*%3^<nE(3j
zX`?)SpJAM-Y<~l2>|6OddzGC9nQeKtBIw`xutlh?@ArS*;Ygyvsiz#GEXn~`l~l(?
zF;by_3$gp=L!Y_W5ppcs5J=B#5+VuqLJk7<;PtWU{rN@tFE1N=3(n?7{`5%~|3AHq
z>Axm=vj3NtY5eP>RkL!ov~#wRba8gJvhcKXasGE{K!0Q0enSmU<Yx<;zPd=YlOQH4
zhofX^u6LFOQe_CyVy<BMh0Pg+kx^A9Rq_r2nOL-9PE4XC&R<NF`9T3bZ)q*u`~KQ<
z<_Fx(`Rfy1Fea#;MpjRo(+#%y=P&v~&vGIJPIsE-4F22I7|Soe3TE})=l*2MJoaf7
zHp&#JF@K%W2UdF?A}>2Nv*^ht<TnmEv17%%vMxvV(;zR=or3SFiAUkP`QR{9qaiv-
zkfgr5G}Um3j8EV8Cheh634^jN$gCusQ`~`@PjPpf0EMx#&`CT>y!yePu3yPJl5-tv
zD3}2de&K%qDg-ttdzuw$<nHF0=G}V>n(w(_KY#v`FV$dlzsPoJh%?EQZ&u$bv4ku|
zHmNtN80s;rkM#YA9W?W%=2mumP-S+quz(_~ek21&DUgu=?^(A(r;0~Zor`G%Aw|OK
z0=HNwpseDECNL?-JCswU7Lj7_HerCpS=<q|-a{);$qvHmJ1{3LoFid}QvdOe`uCWi
zYJY1;(Vl=I7hJzt>dWVU@jtPaM2Um>^yvZifAQz}|M~x0%Y{FKw6s@FHkn+k?`)Bs
zs>2ZF<RnhbBrsuMsRqLd)ZE5|Q&Yy3@^jQ28A~@dz1TWK(Mk0oG6VAFczC)^^$z;Y
zd@J9d*r{J;f4JCl%I#nGfAQFHI?4BY{eN*2AnJP=()$T8Gp7v`l6<io`h()+b-qC`
zE3;OhRyenR;l_x33VrGLl_$wV(z%3;)l_dp1R)+NM>I(LT7TyIOvXi<HjL>JNhtQ*
zy8}<qwT6@S4>HEA0Qk5KQY69N3=;6^z6$lEEI{|Qr*=yl30J85hnO=h)|UO&_J21{
z8#Na1pPgY!n$DliAWmP1wtl|6Q|Q8CwT|j)FRR<OwrP85L)_uS73-IK*r{XX9_%y3
zJ7!70aK`17{qPd+VDJfP&CJxF+|o9&X_`^(xo4PBVOOCJWxTl;nyh_@a6+Cant<2(
zdo!0$?~wYApo31#TSUc0+u3(c)qhVYtW6A@!T<LuKaSqs`yW9^vTZzLAgVw6Reyk>
z@#Ev7bkjSB3SpA&$vIlqWFrFXkwG$4r{Foh83A%F=6ct-=eSw($7i*S!R9h^+!NF&
z#E(Ciobm&Ha7;pHmp1&ie<Ett45_>pfQOj2teRO|9}F-;Kwy1OuL;F>e1A``kU&{w
zO%9u*gGohq2e!eMVYv$)v1t*(S&ZY<wwbxD?%-Lrofum)1Yj)+njqkJF#=NH2`oO0
zY>IOaEy9qKXKL@XPEod=?OIT3UKh3S|2|h;)IP2MYg((M@i(_(MBwY9BR--SpSP29
zqmG7dtHM2pd&6C_5Z4O-mVZh3HZe<TeuR`Yi;-!~vO<`8F%gw=gZrC%oI)8FO8OVH
zSSOCVRMTHSml1h%JrfWJs2K$W*hRb1C(Ke{j}B)xsI`G#vDUBG*Su6zi>oIt?i~<j
zKB=#>5O-u50*P65i(!F|RYXN5b@j`_%yq$wSW2xZHtdCxp{My!Pk*A9I(3`sCY+h_
z;8Ne5#(8NeT5x&1DFUBI41&)5kE8gZGD(k9B%}DHicrMb82|C51J~$aEt>MI&jr7~
z+^7N&KNC9ymmlyyy{FK~GP~-8N-5|TNcSzkQfQ>9)5r=DSLq^9E-eIabgxGxr@&kF
z(4T#YMnM=eTZ+D$@_+W@MunHB`uKW5A&=-3)(T`Ze70|Yd}MYE_CU%RJ@HI&3r~rF
z!O}AEEJQgOLh$_C#|-EnsD8T4lW&B{G!{YL^3>TAD(<4OXTGYmA}&+($*<(t=gkPm
z8=Ip?D`E!<HgO`HpftG^!VjEfL2NS=pNHrY8iI0Af(|3Xl7CuVbqaRI5v{@!Tm?MN
zXDxM!r5|K%Ml+a=AeX0C7_7>28J>aAR5oU#A;wp%*kPX6AE4>)%#I0UB5um*3m00Q
zg;{8h{pHg+&RTo)CTINH6JsT;u3SIJnBoS;cK=@YXW48Ra5_8-)E-DqA{)|L9gMZK
zkWLMQL4D6C$A9LDv(5K8rHY>lS^iMbd0Ix<jF?kBr$|$m`s;Py)$E9CyA0gxN?B4J
zi$U`+HRk9-+0!K+u{DJqQE_>{DDDIPV4cQ#+yCWP?uwlYlILQQ1<7mJkFl?wbX1$c
za^3tb7tz~<S>hrVr+5<^5VA|{lOS`+fI5j}0g{UNfPXUPFxRs!p2L#B9ladAzFRPp
z?Lr+;04I1L;Xw=5Z@(N=beS`FRKG#-gp~>Q8`Jja3Nfv`Olsm@2tbiUm42nt*AqOv
z{7AER*hOV(g(;4*oS#R#P1N>^l-e`K3XhiTS4A<v7AQSZV>Buj)?4Sxxu!G-u3g;y
zu#I0<%YXK!3=IislXF{TirT>r&`8)uhLLLYkYb%Oa2}K(ba!B_mLC}&=XMf`L3s#p
z6QMc7seHrgnT-3b4CHB-ljS&>+zr4NHLK@b06MTju|*I<`wUS1CF&|P24Rb^Lynfc
z#A_hzJA#c%M&TS<&q#<Hr+B6{P@cG*>Uy6vzJEWN;j;Fn^9N6da45pLX~bu)e+y%@
zNK6lT6PrEVm7(l_%~0Q^9@u_0+~T;(Ry0<QoOvCo53B9ktncW2;kwwQDBXdrZ*!QB
zG?@OH&qQ&J^h%}_jGhQKK-GW<0XDuG;ZUD2=OpsOvdTTO&DnF;Ru@NbirTPcIUJ6q
z9e*2-QqdNPuWBg)c@08E15!ar##)!mpY?47zLsjGyo(=^Omta#mz!Y<N~R8vAtKsR
zA3XY2{An`d$T3K92IZu27N(*#VZOj$D*jNH`bgVgA)h{Bt7xT4x6Us{lIJv3zC+Ry
z`f2;)@9V$#7EX4P;E1|*lz&K~U`RxTT7UMe6@--TW0lAEqWXSYbDlmh*ne2Uu8s7P
zL%O^K7(+@pYiO{fLn@Y?GrxYF%m^L&syT?}KHTqVk1s2irFnLXz!=;cxyF3FE63h&
z{vKGGv9$`@5fwa<ES!{*sNu#vI#_reOz|?-AT0geqr&Spw3#{4;<ie=xvK0(#DA+%
zOskBAj<T8?wdPjEI&n04emst<`qw0%O85XspO==FM&N{OPTf8pfsYGv^9bS6x>QU7
ze*%xWpil%a3HCe!>CCV`3IW#M_^~#t<&-h<kkQ@F-aKA@m^8`^ojI<(5dO)Yf9fBD
zN@1)hZFWYeukfBwB%V=l1xlt=Q-6Dot{YY11fN_wp+J~uP`+dqOC0zBzKV>Hr8635
z?^i1``(VXkWY7Am*~T2v3@(1TRNzREzm55jRi^}G5$Z|3uCFi8sz900)JEg`9MfQt
zdJZCP(7ILf#A$p4S15B*$cJTdg)wV;Hd`~7>(LFPW^UW#*CyY2!XdXOIDbk1qCX%w
zx-iC#d&KiBlZB9|u*btZ3FJddR3QcwX4*;JFeQ$Swj~Ji`4+nQe!tIr6QxCq!g}5i
z@9yTMF{(^Gp2q~54N-Nv?Y@+H4y7oyCR$C*0A-T>ZM@KPXy{Zr6CKhFSeyqu@XMzh
z)?)-ryCby%O48V@z4usszJDl%Ungn_W6m=4#vvjFP^tF>BPEUiIidhJK*+yd(8ZN8
zA77LXWbiqL<FZLPK~iA1yo?-0&=rK)c|`G4IOO@BOg39lZ#qyChAe0j@hgYjZA5<+
zQH=-Ri0`<ncaR5^6aP<i5cS|scM@JE<U)*Z;3AsuzO>l)^@|sjwX@y9!$*I0r6<S?
zC>-PZWxLBMa;loG`QkQ4^kus|NVux3+eE{i)4ZFZKRHo3TK2S|7#@d$_>DH2fVc68
zhGj<(jk7Ma5@XrLjk$b(8WhJ$pU)lu4>Vz&wD*X{*xDEtXNc5P=d986lSzmj(PG(-
z71F93?RUqDJBQ%(lE@BFqi%o4G<^|w<Ib`u5YoG<zDGQ_cc`%~4l(HGIIVr~rH&9j
zu}X|z_1|=@M85(1;q?f)PvZ5~?rpI35Hd9|a%!YESO>7j>b62T1-&J0l0^KxOLlJ3
zp1KJ(C7FEejOUIl_dO>m_Q&*u*7ttS(8Kxwqccj>_f>N*(s;RRpFe-Kt34Z^R0ZRu
zT&*VZKY@^~8?wjg|6p}T^`;wJ)@6_XdIeNCsG~d@Br~EV2R$}@HWCs{i|8<g$m)ZP
zEx-pxS!sQvTEfAf$FJX0s0o4Eve9ut^YhqT$~{P}ySPXnUJ*G5sDg)nsd}Q*d@_<y
zCj6pfu{j=%Xj$`5%Rqmcjp0woyU*7<p|di#5WFS%dyJ2Twa{4_w2YQnk1<?9TfU62
zzY~oJJ)d<ni{0!(sK@}nYxd*rI28}b3Ch9sE--ZdJ^Uk<4S4(=GZ0-+Ks|yf%?&FD
zS+9z!o(V=w`s`a|tc!bJxlT&Il}QspOPa4C#E0Lg3hT6Z@d|%^>L)MbGe@|3LGOjN
z({o4c&E6aG`am=zszNI3F7Q1$<DDia*;8YNoEXSfdFM(tX&qr=bfSdbdh9t0eu*P1
zTS+3xILXFF>a6WaZ1s0;OotOfW>J62i7mRf>!R%uR)bE;g{O><p!J*f8#M0`CePT7
z@-YWa3iBjKGRl8_KVmBINGgj%LGfaS)9J(y(z->`IIEe+*h6+l8|Ts^4UGDW%P=V=
zYFw@_a%&U_V+n=D9`RfUvNj{ZftO4VFHVI?Zo9}lGn>fyJ6C|c=y?$Us)x8WrheQ6
zKFv5aMiqwdEFan$yl)B$C%*jgRMa90QW4ttyu5C$viE;F2({xV;ooA}g_oo&gV^i!
zX7r@^!okwZxtrHSf!8lXYhqg_u`teA78yEcb*Q!&KCYl(G*ged`?qKfa{Kln{OQ@~
zz_?-wU%aqbX529Q{z-CA_-_GT6o@y)V54$%Cyu{0KC+0Maacfcr^=b<)pg#la2QER
zwNF%~jm&?S`O-dapP!XbH!psmwMPF&l8go0m`Svdn-rCSWaL+=8h$PN8cRBw7ZcS*
zix;#!xl%KeU8;A<iYPo!vxW)B;Hl-uH(g74Z=Dg^lehZm+?0GHqK~BUJP6$`%doxh
zM8O{MseDK7mzgp$ukf(?W)ANMPj~tDQfG!Oa20<qzO#&NG3T{L?LIzzF)@?1<%n9x
z^J*>~e?8|=z)w@)IstA9jMs*Ajs-Y|G*-%(=ZQU<!DlMR<D}`CRY4u%Y1d>lW|{A>
zIfvlWY~*RP+a_<I>N}K)g-T<1+DcZ^$_YkN>AG(#_;1WL3R=US;XO0H<1y|R3jh!v
zm$rZU7wa=B5oZ*tk7q*edHb(B^p!DdQ{e*5LSw6}MIF(X@_)Hpq5udIm`;GB7TEXW
zTpX1XeL7FN(k7f<1?F*j!A<;AoW1#ppZBPR9#bg~&*S~cqUdGoH^=Pvy;C+fYx#zS
z#6Ex3KjFLZt6?UH)g0eBd;RV3{^}mb$Pj;cMjNRa{fQ>_S)zbqYp4riuFZ<A^<bda
zDy-6XqN><Al^iy_j?yfFJvolIp;WWay`tnjdUTy@z^P$_?%TjsJrWCIFW{EV(K%aL
zv0wO+ZV=9;P~mJlTDCyVJifW1U9dbX<ud#L-a!_~Z<(S?`PvaC$r`H1Z?q%0arS@f
z6j#uNymr&1Dk#k2d(mkI-#{sIDlY9xJSX{$BZ}gLHvzaQn&{M0MOMv_a_ROvvcTQ1
zjC)CC!FJQ(jN$eyE?(v~M0zA+6F^tXK`WJdZEWk>6ETa``6&TRgK9zg<L>Oc<^+a&
z0rN^6dU<#VbX3Pe@MfQFf3q571EGK9VFmQId34{A#ozjC8-3yBlqoX#gZ64g0WFNv
zYK}>w-b}Z0OtiY`Vwc9a$;^6lG|2k4&qt>4_r?CtpAfm$=pDN5jbsTo`Ij-_p0W-M
z4dMA4gmS_6uenUpqvIQ|<H%<QfdU2nJxz}Cz#L_x5MF7c99LwVEvd)QP6K}gWyhGU
zKeQ%kP`apR#k`H*&@B`R<<CZTvVExng_NpEA}6ZTCq`ZA+BbsQMjXz`H~V^$$6dzk
zfwIAq_-?or&VTUz<4>%$H^F}c7jK*RT4G2cPGp463@*us592#SPI!;so@+b9zVRoS
zJhMM%6palpgU{w|H1-Sjouz*_mrLF%%fD#3C3R-S|0r)OPew`q6P;@O&DPAUa=#Qo
zI<Br${8AnA;jg&XI?Z;Zgvli6Vy7jI>vBfbQOC+;+||<AW)^s6{^J8iyAArQZ@ir_
zN?f=+wiitT*(IG=d73$kD*z9_eIHx<k}zrEOU}2VZ<Swyc(EI6xzm4(s40dtq{-w!
zree6UAmNe`!`(V%4oiNf{bG;?zABLa@~lz9HRrjTxe)tL^j1rfMD~a2533>@*q6`!
zz)g<o{i65{rOp}+)j@Z+=uH5cb;qw3W)tkjJK5C01Q#cTH5ux+D4&jKz8YGi!~6OY
zx#P6QFeNcB%N9J4A^v|2v?7g-z+5lqPerWHQI)mVcYktA>>H|wRM7<U21!a<P@h5H
z02XESbLlFM3@TpBU)V)V`<k(~4A!IO`|Zr4gr?9qucXS`&%DI<hflgkeS$$1BRkz{
zC^-Y|DXfg&q^w{42gT-Y>WqsKY6H^oV_hImvCkNL<=I#2sk?uMWk&>x+9eS)%QF+j
zv;E@ue??Q)bbX6KrxGT2`My^m2>ro{(*$>0UsL;W)ItlS*-8B9k|#gnxS4kR%W(Gr
zG%;>}-<<>D+j>#vk1f(}#zb5kn7?M#{T?lKmBo}ppoRtuw2exvCyGbj>83MOFeu}o
zk5Rxi|7)<wD@A{#UDF3*CYk+I6tI_SLeNc5<xBriXVqLQXE^mVge3+@Zn@J<qX#Ue
z74(<G2i`bW1Z`H1t<0D*YHTF+i<cX3o#~5Vo>z@LE>`bwHSEN__8z<jRPXRLxKsu9
zcLoNXqeow0($*0W!H3xmi_`Ee68&*&A4ras;rHc38`^(L7XKqtZp}A1wgqTFpr4y6
z-*Q!WVEXHoo9>mH?UkG6RSPSCc@t9j`FQR|&ioUWIxlq@3wEl4(#2<8F+n4F58Xl9
zP7-S{0b`_t8S;C?DlcJd^ptPgq|%kY-avU=V@$IQ>}xU5T?CC{K1j*l4oPJTMTEr6
z4mW@M(}90R0af*8{A$qfcAnwRUI_Dn<Zc6?ynzW*Tp13{A*7W>11>?0Fw|=aeej1N
zRTToS&e)8!2pXl<WR>FKjmyyuC8!Pix0GY*2g`nk5&6~~;Y+vj?`^CtP6_i(6{5Ud
zg34-9c%QaUI&A|g<lwD4A6=SDyYP`Ms2H5^T(5r(5=Hq6QD{^R^5Blat{DUl3NLoP
zL%K%^(dWMR*FiFI43UICvkHB%r|H>3`eUGmY3MEiHIY|2j~Xs;Dn2d`WL;azY7SCZ
zr5m0_SB6@Nbb4s?r?d`%ehCTWxqYg8APuD?F&l=-R_=c=!qfzfV;7VN2>vCno2XMx
zLDPS)8iz6A)Fy!5Ofh9=i&VlCt^=D(F7dte(9GeHy(Ya5A3a&Q|ICtGQeHbMB^8t5
zL#}Fvbs^f(fD4D<&ZY!_G7~zFRes`OMrMR|An!vzfDXVuKYMW=3$xBfOB%of;Z}nE
z0O+C-XHcHAC3V-Kuh}uMGZF|ZW++R$V$gpQID0q7`~=*=q{T165m>|2)kBab0@Wz5
z)5u4?&!ny*`C<JL9?c=Yl82i~)s5hclR}Z-VriNjr@lg2T-8D(QPLl;1&SS5Qe3o}
z{5-M3VSk{IIaPR2*hsYH08ViqK;f*q(4Y3e4Uw3?9ea<l^%Js5xBz)%TT+bdh{Jzv
z)%7kk_u}?dDa8v-RqQ{osV=t!_8^uk+Fe~2W8%iD`F-Md7Q#dZ@<zj^@qam*o1T8G
z&PS^V{aQT3Q>x0q;3{IJ5<-9DI}n4R680rsZOL^b0yof4<=R>b4Q|#0xD7=U>_%>3
z+a+#nb+2=^G%)Sj66_PPRM7X(C^&zW0DJ>X_`VZ?_PK7n5?ll{hx+FwMOzE;R!Eo!
zE%Zi(xL~gKP~TQ!Ul2aHePzh|X#Q`tQy)_}yi)**d#*Ze+h~DJvmu69hl#aGKjPjL
z^6~1ciM4$0ll538HNPPtjJoXL6_Akyb8o#4(P$^05DAHrCr-=-XD)P-`EP$x50cvj
zVd?7+V^5BPc)kfZ{bw<K?+W5SX2BKSal?+jo;&R3c647){!X2HbWL--7!MLwzFLH0
zI=hh(>^j=pSYUSmiA@!@bB3gtHzh)jbx;70mRUh`aoup%Lj{L9J`xC<a8-l7;d`Rc
zA@*t-^jGrB$jQ?e5|SN^gtmWL<ZFiIfZ*R0#lKsd2u;EQpy=f9HXwNPCdvdT(b}Q-
zC0vpPhH%Kiu6(}Al`zQQd_{T=vaR6lLVcv}+8G+g|EWy_6qk_9Ilub#RP{puCG+Xn
zjt-b>(;4)F4IqmsSz=idvM>Z9>a8~z6LjQ1JfQSw{9I(;VEUvEuRDLm2GW*Bb*>q6
z9`5JfU%_EQNyC%oa<=Hz%d~0BD+eegT~FG9N$-@r4`3FTy%%Xf7dneL-Dkiao>@n}
zo576)z7WIMXABS0$7;X?f^uhT57_cB^049N2g0k>_uU2*3zBQ+;kUe|8e&Sk;YZPw
zy#Ti%;MRV95>W^05K@23Gpmre(ROsu1|l5Y>u8$oNdqF|l6IdOyQ<ck9k3$H;P>Hl
zGRxlk$FPCQNHfcJo$b%RQZMa;?dtX;kyoa5F0HPvyU<Y%_fI6AL;d-e0)I}X!bEcW
ze<z0<<Mfs{Fr971cI>Vv-odfl@A$sE7t7k6@N(~*%|_X@HJ^W4?UZxX{&u^?+ARR9
zi34q}>78=aP*OK^3?}X>nUOQEPVFZcH?_hHBspqab{0W`Gl0g$%DgkrlH_z44t=Ua
zJ9ogwoM>p<^}$DfmZYIT2ePCwNZ~ZBke(#JbFEL95~Yosev7vg5~cMmd!q)bxZ6ro
z7$75~dgzsJ!ry-%tv3j21(?Lj>~*Hmck!La(r8Ff^C&+o94HIrER(iRXa_KoV1e>!
zk2F$jwr2O$!DvECD0Ug~O*k~HpMl9zR`R$X>v`gEhq{Lqmo7MP+08Fgnl*@~?a?9S
zi16|@2}EFfiTgT6AbAu0`6ssa2&pa+>3tQTuL^K=$x?sX2ck@Hnug%LL6L%u-)^sa
z5MD2Hd}U7*JW*WUR91Z1&JT=Z9Y4Rc1QSeFAWd&Pa*M?)Sr@RGYemF2nk(fJ?J&}}
zr-Yo+g)nXaBj8iBmh|l24(kEg#mcor*w%aTGU`MgDk4W@BMA}MyA;Si&NvYBVc<^&
zD|;2(`*nW@WJKEF{qicI-wjL){P=eH>e{h!yWaOOj8x5e5~Y@;-f8?3saW#&aT4bG
zcm+(#`P&ra!Zgc6)XS2x42Z`}xAaq|c!(YDq>fpqGw+Y5Itrg^6KB(CMO!F1@0Hw(
zScuKf%)Gctg<CN#)w(bqT*@8$!TS6~8nF`jEE|6>denvrMGz$RtzlPZ2vQ2o#;ti~
zak=Ca_PwPcJv*VUhF`@hxPDJ#=zHWvb?=O8nIk5VAIaM%qBo+q@n5tDwg>$7qr?mo
z-nqBJ2Qv12Bz$fTe{Vl<Ecz|=*}Ntj-lKWs_<sE!H$B-|u~a($PGF)^Ga=jZL1g2m
z_|Shb_Dh^<6fzpwyGimZ$29B0@*AzUngV?Ks%O+m3@(RS<!@neVJW6tMXmH6C4@1S
zboO3_wQC2hksg(!Ne5Ta9&x6XymaPX>7$#x^s;{CiYcLVTXK5a8!X+O3d^${srfgp
z1^-X8gHcfIj}Iczkj7n2g&a{y7XL)=XV`zyfvjv*;UXAQP2_vzOz@K)`d_7(iN%zG
zBlo*RCb0D&8rbc~v7#X$9Ezg^oM<%tJ8AB%fP&|?ENWnw&O5RbIG%}`JP?njIgTjF
z7=mVhV&S76DH4vV89}-jPU#n`ylQA9bMRA*&QoX|VsgnqG5C95fb5HCsnWXz8Eb!^
zc+@j;6wxIp706%c$d9myzUW%LhxX410>VB=k@{x?^^$TT6SAE;@jTEBt9y|>&^z`R
zhYI-DT`9jS^N%zUj*|S^lNy4V;u4N{iOh0q*|W$ue}<_dF>uSBk6cU;aV>5BYlgcp
z9APA7Nd+u%z@6_TjDJFuwQF>sz{-F5>e}Z9mtY!?8n0^}<Ho?w&AVSSV$(eJjGal^
zKOj9)*15Wbnw5>Xr?DtyWIZv2vgmIF6vS8MVgoNKU)-WCB6Kda<*ZLal@>Gf?AAls
z7pJRpyfyqV8+fk<nHS-fu1D<`4?vk`Ob^+Gqa=$POM&5{izj*xuh_G^m{NcJFP3Q8
zTs7ng;`dTU4l_fK$Hbk3MhZ>{g$|-{vs}6dFUONm*!zsmd4IO=8@Ceo7@L-Ta2&ih
zqtnNuw>bA)OB7(m>BfVb>6=~3sd`Y3IruL(X147J^?J+FW7ifI9TpJ26wa28f~WE=
zS2{eL)fo@UcJ*$(-SJo166$|U-VO~qdxusd({Zet{deS8gBrDV3Lj;>TDmhF1Wb?I
zohN=QTS0c|Kg9H7Q#;c!L9)DLA=o*xd*&0ry1z^OImi!pSOQ5T!4XZ+)`uC^Y-<F$
zA;X2;0D(j%6CA9^reD=g1~_1rf08HR7p$+L(3DDRlDegE+kC*cb{l^t4m{k}&vE2T
z;pk=H%>W}cCpOaD@1QZ?_nQu5;5qwx+wWFNjOt^~p;x1xILM~D{FVR@2Gr0!eu5ve
zDL+ZIuGYr65f7Gw%@d%fbMcFhLMS1eKtL33q|@JEvz9z7cs@;dKJo#)m}YwY=S>>_
zdGH7;mmWoGaOOzxSm}QNYaFbmzk0E2ARzrd%zE#HJeIY;{TAQW(#}v$lfQRwDV5@A
zTDA;{-kP6EJ*#SI$S87zkSaY@&8tJU?t7m10FiH|$3rXh)c5wJ<afm1%`^;_R)l@L
zYnqrG5zQBCGrS@jc4<aVaa%QNm4sQildv9)M?a6D`fSauGMRr9t@P<B`}^g@<ti0Z
zZ^YVtWcJ-fpMP=+vDZYw;H<i&X-k#UqYzsMX=MKf$hAXU1@q;va@3eMc+#b}<gW@`
zI~;FZJnlI&7icy3?=tQ!yYU*q4%NMg9TVPv^#w;&i-b42lJ?~wi(@1>(J8JW_EwX}
z|CAKm{uE&u1Ob2HvR17`@C}jlAj~ifZH0FXT7iU&!i08tN%}wgfImQlWW~Sqdp?_h
z{r0qbFt>+{)0Mc*I5rc)ZcV0!v8**y0R(w&h~Mv<5ePNFO?Z?NeAm((*F%rb0B5i)
zbe6jhow5x7bM$%GGwb)pecWeuQF%LvCM=W~<FDwsxB!2rRh};|luAt?k4>r7H&s==
zf>Ur3xb4}M8?gVi^eyeVj3}GqQ(`J9*!|A&uTYYcMZvbBtvU5<d{wbP!%s2W+9DDt
zVf#<}nDZTgE|*-|<;#|)847rZ+-FUZ>f7}^a-5*!@;se|1MROx6)e)<{ORt5;|B=M
zxPRl)@5g`Loja05>zq#WHFOpAgc@5nJiPs!3tC0Ve3thBm-iGMyX+&y_$SadShct@
zX3IUn@J1;vBV1N1tg2c`U#-~kQ3Nkujx>Gu{>iYmaQ=c(qwgp^#`RN@owz;lX5x2R
z&u+WZ++W?&n|gx<R|_1xv4%rljRKe2zY8T->}P*`JxzZFNEzz#V=_)x1rd(x*o?#X
zl@DbNhBk`n`r{++Iso8JqgegnMh@}-$UC7C&%CTdKE;`Zvn5{d>X@zdpQc95aHQwt
z$du<Hv+7*JGF|E__^K=sa2D@)O$y0v2naE7AOP!G*wP8%I!g=2KucYI^6DU&J(kb)
zr?h`t_P{Qe&ks}1SlvgDdhK|P;ws?}F~{DxnAgGSayxQCWei2=BBzIxVc36#;JxE5
zK)LSliiX5AUVzVZmIt~3oc>7UXLO|@mvImO&mK@eMhK<Z*WXBrw+z(-7OA+#gPwSQ
zGnw1$^lc@6^6t3xGyPC|=3*l6KYyP|-U)x#UwnCOmD;Y0i^9%@?8t#f{=RD&aTOED
zwjr7NdV&0rYb;#<h&O8zK(p!#^`#(d_>8HML}*o}_?8mgCXft>WODO)3J2=p4T;47
zlRz<F`el-}yJPJ4`6Tx18Ji@r&GKO09tSQr%selRv-nwey!2oGc^$_ZqY5Dlynlb{
zcet%1hTlXWQOf%VuPe^9YWO-KGGueb3hgGHgd~TC^&&0!TCcqnOn5a=Qd%#?<nSr(
zQm~PGq%^l+(p|&L;dyKc9>D+(iBQ^c?VeVso(#lXzz8X>TF*$SvMoGz*gcl9N<&y5
z<IM~~7_n+lQ_Dc~^FK&CtC&cm0}6k$=;988F76JCyB2qMU)<dm8{FO9-5mxUU~!kl
z-5Fe#t)*$&q-~n^?SJ}{n|%3llY4RwW7VNM){GnjtKlu_`~$t})7PowW&<e0_+%~8
z(BIM@$^K@Hv;yB^U+Ey65A!EVwj!&HWocAOO1bY_gJk`wN_&iuHvjv$5dVMN7g=KL
zy33`?Cry-ZYybrld<2*HLHpxBjw;lPWjUTGOq+bl8AR$JR0A=14oQddZ?QPyETR~K
z-h%!TyRoY|(Zr#If?81gPjPsr|0;H)>2CA4%I5%eJM~3T9HC7F8;Nh2@?x;9!fbWo
zP>@ff9Oo~U>Z4g^BqHS#YA}E76Q%m_K}p6(@-FUUUv?8*dpGd}n3pY%udlnF^ZWds
zFB^7tf}qzx@gbjwlfmJ8*<d@*AII=KL@elab3gH=IoZUovkT(9hFow*05s@Rlqn&7
zz$Sf>-E<Scrl+7xDxlc6e+<L#eA7S*M;6s3mc5iQ9=y{kyzJ9yy<&ejgW=Sji-1!-
zFuAHx%2q`t1nPTcKP;~^CC(0^2afjFTq2SJ>qMR3*PBLR_FhPbB{efw_Ut%M9oV-Y
z>V_YyKa(^JHdbr%!`>BIa%j4`Le|<Pw(arm(}ewaN-9l&rdEK!1y_Td2nLqD<`6z$
zS5S*>CKx(&<0Xb|>imCokbj0j#RZNJPMd(E<QHN69=}9%r_tNAu(9+P)$Zt=&N365
z!UDqrcoHA@qj7hAf3E^ZqXv|nlS;?R@%{GRX#teQH=m&XbPy8EW^!;1;Yy=YGh66)
zKknhX%2+p*h7PIqpQxzM&IL$iFawVg^GRB|$s(zTIVktOuR(t}x;S6$f8<k#1<^pa
zop*@Gh<KF>C#%gfCV%3?5IMvzBalt66|aFKB#46y(PPnaks~#m8)C@P&lr6}#C!`r
z+~-m77rXqBrKOXeK|V~hshS~`9nzqpgHY6+KK3PI!dkO!9c)~temV>!doP+BvnLwy
zJ-`XCI^sqVzixkr6vovxNKlte2p6-5Ec`VDxX8?;!u96>*dEM(qLJgjqEW%g+Qw1c
z-PHYWB|&ML4(iz2IDstW>xw#XB@4wG?HYDiM$lUC;&gDyWsa!imN49Eay%2%wLrz6
z_M&4D{0D>w{D+(`8*88RWx%r^@_A<uKNXpdEQwRl{hojM_)fM@1fO$Tf<Ep~7@>F|
ze-OtXuAJWT9`)zawN3TT%{fByijMC(8@p)h9A-Q=5;SDiZ{N#i$(WmVe(LWsSBo@^
zxAQd5Dbk-k<pV<8Y4xcAL%{S2hf`SxO1=!)v#PG#F=rQD`SXqHbl-cK&FvGu3NFg7
zT5GpAHQ;~VP*A<h)EzX0-O-L7NXp#O?Cs&f(pOA?0%=nsm|Pr<w$#5y31!7HEYnC?
z#>&`358mqyLGB#K$aL&^kXeXW0MwhWABB+`q9)(?A^rM1o(S7nDvBkFw+jQ;3?=qS
z15WIdIJAE$8I@=P)ECB6G0|Qr96H|Nxtw<Ud>emz{LU0kWL(k^^b-P{7Ne8+8X^14
zG=2&8J2XDK{P}SjM!b$KNoxkF8#wlOL_`;0l+vskTNG62z;<=L@*k=Wux5B_<)Q>Q
z9Fq>ESmoNzt1WAc5($S;{b}m=-5B!K9m%>GSnTA)pcmbP+q<T#+$rW$^35s;;EYYv
zS(blmmpcv300Is_u*<n8!eV`ZVjf;Go7G3vJywQwJhpANc^MiV)p&aD>PTE-(w;SS
zw;1#<Z6TX;1me^+MztH<tlh<>4~rZ~`)GL7rB&rSh7ikO9E(QDGtKHF4llajBrF1>
z$Z@V4$c3;2)a<LIBD%)+PwHT+r4`Nknst8xK9BwR5bm<$J6#8fS(Sscs<^V+c0pP_
zH@SdclF(nxc1-2u!{1XYD+_VqYC7eY&X@OLl)8*%wewsJIvp?X#D5SD{6Gdir=N<E
z+F@NMZ9Cno-wLe|%%pY+oOD~c*yVJRvVO;l2@8v(Jlr;jk17s>UKW?pqo)g&n>K&O
zqB-AGN3yx1LSVO?QL)DT!j%2Bp-DEGq-9}uX*wn8TLdRl*n8z4yq&ok`nrE~;Mxyc
zea?<Izs9X;69VcSQjve)q_F77k=B$c0$<hrN+t4z6U{VL(mQ?+7&eQ;Fhib5aSF(@
zSIA2?oTL2*v9cdY9fes0=~agrHp_oEolkex&F2^Mn(}0)lonJV^IjU+Bp4+mg_^bv
zu70TPt15n1n07nV>;v=*%7NDN^6w9rZv<Ny17KFr-JV-NOjtqD4$O_0p9u&i<AW6N
z080Cg02I6}It(^NH%Jq5u4BDTE^LSjq}<sW`JVL5!~X3MMiGU;rz*;nl9hkQW!f8f
zF)$B7QS}ARNzIaG<BIu~G#KO@Vw7D{lMoRIie9pji87A!MPkOb=LJ#JIM0j*g4f1b
zb^L>gUT>#i{25T*U(CK315Zxb7kqbQT-oseTVQeQov@bQ89FoX<6oZ<`pv!LzR-oL
zntu^_%l8y13+U-hVMSDwmC1ifB`$KKbwSe&Yf@<C5lUO%feoQEuTiwmjSbNW!d|`i
z@^8|9wIN?9zPWSLDH$M@k4B1^Y+i{cDK`)QieuGu;{8H+SsH|IkYEHOu-*Os*V4Vj
zm<#kQSSTnr#D5eYW%56ZPvE~2-@mAz`dfXq9-_a-^70=GI;L_IjL3gBsj`?baKaU^
zhA3dDn1GD{R6EJfIF`u@L*s1NRy44qadN8FxE(9-`uGN8aJZ>q(`_uB6fB(q4s~r8
z*7zT`b;xP?@7rM(+bH5e1-n1rXZW6jW`$0+-DdjU?mFJ{VV&XoYQ!jF(cg+SKizb*
z*X7mqGZb_P?IL%C^*MjcSN}mqa}EF2NaO1w8TX7aUH`fGAa_s?e0ZWykyl*?7=E+n
z_^a`$T@)6VlbzifeiTMC(OXyCe51&kk%S7rxM_N^Z%7IC(z)F&+-3<QqRoDZV;RpB
z%%W6Ke2`%t&%XJ5nV_;f9l*jnhz^i-gS<LxT~x2aJGb$ihJAm23y1Gp(hvVf+aPzV
zxlQ6*-72PY^tNUrM2&-pT{$YCo>n;jyZ307Hz)tFQ4#v=!l1l-zCf_A{WYxZ&d;ck
zkuG(}+X*Q#();Ge;3(sVsxj!x-lr}+IS1a$zQ|?W^hu(1VTsLfVW-0W1EzwGWqd31
z2n7F`$NJ+@i)??_I7SJ>+7KR)(q!bzkX^uD_uTn%KiRBZ&L#R=i8|ulc=P?*tjDDU
zf(6Q|YP6|m?u@?q1Koi#;b%&Z%EqXC{RsG;Q_a&qgl@&FhV5-1r)wGOzsvnGyau`^
zv?%`T-XB`s99FwySV)DeE;~8L{Ad(%sm5Yg_Sjs;&i{W9!QyLuI?jeE#1Eg<7sU^s
z^V60ji^icjo~eaLQ>J}gKwTz&J*S>>m6%;3VzG33A<6n_W+BPxX=X*0tkscB)PHt)
zFGO+pSJ;7Rw!tm_Ih|zEX<khUpqs?LzLh#{2r=#P9?m=}9?MNt-U9`bVu$h&LLM8-
zkhil=eA|DK%Dpth{8gzWk>41svgXah^%C0Ol~<D!u;(^ySP3g`wC$-&sd)1)q1p25
zld<Bu4_YgzBG~6mG(MiYwT1Ho6Jp8hW<&T(r)*DLd^w1K-W|3vdmg&z$+M}YnotRa
zZFu$P`nCy5WfP?&UFE?C!15ri9S~g68uzt^#V~)UN@s|W#PrsY_~&)Z3b%}S@J!|G
zlAxP~?tV7OsbmJQEo}0Sa>yhXAcQ|a5H@vkk|<MV=RqZwK(S#^*dsqna0Xbq*Dk=*
zKziKCB&bv;2FSQJ9Pp-eV{dmK9#DrIM_IY|?yrVWKUyl#_=#xr?2g}=k2`8x(|_*W
z&>?@CpnGcAibQ1OYc2A{l<>qA=PW3E4MG{;u`KQ%6Mx|XBNpclD@iQZcKz0jBQ}br
z7(1W~PJm!z@~ybL_EtKf1BZk;3kB3g)0jPWE7q!ua(L`SI)nj_1T3AnB9v<ayh1PM
zQmwL4s!kEM;428M8UdSH42c&Oa2a9M7v_KW%EBj<cHb(IZ@fcm3VEIK;4NTHPw!qK
z*-ysL?AswQ)&gFZyi3$d_(Uu5?*~4$%~FRfO?L<$_FxIKRj@iyL6I+N0)`SnW1}c&
z^%`{vxG5m@lG{~3x=K#bO(L*vHK@|MgpcCU-oO+$EF23C3-ThdKC1l#YY~@e+Sq^i
zh}1??1Wd=E;gzxW`p`ATrh7sB$B_0uh9Y`6w6N2ypi^Or*ClqCI=1LLP}ilv%z%?z
z+w)~8?Khf0J^>qduqDYm(~ZAGVR8%M3Db;QnpJ<(fzJ#QBAG0QRx1qs9DnSk9aw%R
z*lJQ|-pDjmpE}N1z=$&S3;NVcn^}LK5}hm-7q;)0W1=t@@F+2z?Py?3Ur_I-I*9FH
z{BSO&GVBhmL*AZYyckS%qq$>Xfw{yV@tW@H=>9nTgoCSyr2R+R??UR)I!(d~W9M!U
zGGMUW)ky*$g&yny%d3z!9XMF-EJ|d|uKhsZb=IJU7#-5%{|nLd)aCHq@Rxsf{fRPE
zpdk7m^C%N^1+_dMH4{Aj$F#VwjOowCpKOlgC>z!w37@o-=*{x>3Uc$Ys2M^Hj5i>x
z@o$(cEaCA}+{57{#+cF%iisobAwd!Vi<QzeW-C>Oh5Z2!f5wIUyb}l9BTVeBWAYiq
z+@E^T<Y>WEDb<+9)~;%jK6!uk6mS-|ZRJfZB@zY>{&k+s*ubefR~AR+IG~(VTAD$=
zd$L4@dy=Y#F)uL^vK+8*<dQ4XF8CAJYFAXi(q&S2X+FF8yh$DH<XgSfaZ-vK*HKfP
zT3HxQm2OE$|5s1xk6?xa+c}Vtr;0ETd4wV_I=pS6qzI^jul-DXzG#2*In9<Ub$U}o
zBX+?CkT-M|$80VuA0RcS#_rjvR1xK0DftVZ$b{0JP}Wi~aWM{{W1KFiQF14&*_BvT
z;Kd}?OiNg@ov!KDOClXrQ}l<D>QBx0K2`IhrrQIiabu0-2zW~O{3RrLs@xH?JsV;r
zP4i+UkqyXYT=@;AA8CJ!qI^k)Hqh2!OT@M-S9bSgrDY0wI})=MQI(R3OYNGy3a>Yq
zeGtY@{KEd~!MPg3@-F-DBE7tFbrO7(ZM1&tW@bk9SI#ILnL11iPLFKM%e!ym78_?w
z@Hk!$<`n$;Q!Z!`<&t)^6zeuh#y%!1EX!q{+2D$@fqaZqIQxH?Ff&kYv8sYgeWux&
zm*QYX-p@lpa_5Z3Gd1|YL4)k6Ki}+4qBm8m*O<Id?!`Xp=@>1voVj?#8ga~~dvC+!
zq%qcw;i?$12OZ=GuU2znhJU4&g__(2*qwT<K#9|VG>@V<x)PD2t<mM}@gLBHztdAR
zn?M4XMJzS&6@-5~`D8J(o<BvdoG(#dC$9e<SNKsAoX3l2MFVfs<Rd-ro5zBQAo~?9
zxe%m8Tp95MUSn}7Pbt}hKad+9WiXs@afyvI6PdF~iB#aezc#I?A?S?rV|tLlBXp>+
zTTgTAntV#<&Vh6CpvS-4$69~(ErWpl59$~~{XAgus~>+}yneMY41cL2dNE2fZ>*cu
zR0^^PthO!|WLK=tpr}Zje<n+nRQ6^i^d<KEW6C^Px{l!O71Qh&_Wl(2A2%rqYAmc#
z*aiJmSxJRPXONeVH_MiB!HXKLKo0ibjYq^;49gJi1I))H^92g)ol$-2HG<D;XQWR~
zm37RZ$M1i6yghb|CG+v;)eKF3*Q;lrT!>sHi?^M*n%BM<(vNR?_(qZ*Ly?}@#{*KR
zj_Uh~*sgZB7%?bOY${}YessZ&u;lr|Hs_V}2HQE}9XvYx2A#D3>@P`qVLM^-)cVyI
z=Vdxai`KX1Pk43X=fJUWFYeU%b%en2ONGaVjPif^1CG%250tkRskrx+q3l)UyuhNx
zmIvYjT+D5|gIs?0Q@A{|NVi-T_|b-NG~Xzr`O~8?HQ8JkC*%`-7SdDAU=>;nqvBBh
zK9<i0icI@URvOr5Gdz+*0V%VG<CY$lCpHh<VtQkUbMt_6l#Y=dCnU9Az67ikGk~$K
zCDeaw;s_DNGZiG{TdNIZ1+$_;f@dR^H$bJAgt)?bY@lV|!LxTds-w$=&-#}D>-I5t
zGsOEMdR9A<qJ%j<fiY?^Vq_qKaEH1#M9rL}0?Ghg?k9|+>&;lz_2r^3+fbgS&UPqA
zM<2q`_2nd~M%NK(tc&$tG-<4xb^4P@ul|48AZ)qdR;Vm|*;pQ5H-h?4-GyXQ1?)>b
z9_?hIN>1=JSGYB2Q!&Eh^`)CH8<<%n*hff*?3QS2J;t|DC)VE8n)PDvF0U4E5Bj&m
z0d>f9W#bvKeLK_d6!0;Fl{%{Vee7X_s(ri*llHU~Zwe}VOqZMY8M4p1V(%_4)B1mm
zJenDAF)wPyuDd<xv%zRdgA{?Ig})hngAL##!1F>ybW?RZ=C}@UN2g_lkVZ?!Gof(y
z?NVxKIxoh2<1xg;hC)7{LOD$+`cl<0LGkHZGnmD1!6HH8sq_b_;giL9zF4z$<K;xE
zkZv=r{?p-jzQOuIs*q1JZ9z41<%WOMa`?N8&tjncH-?=!My~^eWhwSYLTwk;`k8*M
zt5J_->iT5bWq~CY?Wn0BFh|L}X7TNgw>D``fH|w<xpb30#`7+oXB`K1`AjY8KB1Z+
zhPpM8xCl>JGYa`OOf;B4U74M?gCMu+WB5l}75lQ5gU%t^vQGQ%S8jU9vXg&#yxkvI
zui0r-ew%=PT7$SUvxN#BhdV#KJL&zvj)HoIWQD%*$eJJ(_M_uYN6l!NDEb_fxh?q9
z)=o!1p9}`lujMa_N2DT%N9U-ywAjwxaR;~wc<R6`UgZK<Gy>j%#&b?F$eQ`xJI#z6
z?O4(?Aup@WV^*p6g4rD^%}jp`ZE(vN$Y(uTy~LZCy=!~K=aI^J5+yfOE0;c+R){7g
z%I$Q7cR>bzCPypRCR!#z)=x3FLm9ea6XXMq=2U{LnJo}vpY)}GbWL{sO&+!D_9r4`
zEoo+0m7!^;L9cC^1^lC&bkbk4cnA2{(S*!*f2~AwszXrXRXd{Yds2TuUE`qFP+aTw
z{fXFlXzUYZ+F;Hx(5o?{Qs4eWv}$(LeFpZy?kxPw4p#9G;?We6VK?{_^%?|1TxBH`
zb~oT31)>P*Ih=)+GfkWJC*q3Mcl}NCiew>&V7A5Fy&ox=dt5Llb}-f|{=lPX+F8w|
z7)r(EQH1_$XWYK;@*{uG^MK-I7Kjaxuwi{gHL_tnjB_VajUl^5mqGoI-%Cu6Q8Mi2
zXv<L|H(Rhu_8e$go`04UACQ`8+MWenTU^r((sYI@+IOsFIFs&CKa*}zzZ!F`Sc#)n
z^5Y@Qv)RhLaCa}+&f1P6P|8EyZ}lkI$eNFX%!q9Pu84oexmtf)@hEv&d6;K%=BNWX
zD~Mi|ta+OAe744&kG+Pkr?#TaB#Nda!(;7Fx5N4PQn%#0mg_%KcUp4{mcyGX=zyv$
z87+VK#fYWOipxFrj{Xy<pj`xM%8;XC+SZX2znu_BAa(6QdS0l4ZINR$F%TSvKE~&d
zd0IHb${*{MHV=O*yw6PVauvFzKsyjhmMt-uJb7Z-knQRG2<tDVq>?`<)w6-`xG0-m
zX!|M5*hk){*qqDKb7<yBWZCd@@~ZCc<IdAjBwZv$gjSbcn}$B6D~^sRHSXuNwvn0<
zwQkxn)7K3B0z%bQS3gmq+PhzCW&+dP>5Lga?AzM)99MtWwbrx}H^1?)8DlNS2_ieO
zHH2Km$<-T5yDY1Y;*Nid1p^eubQBJ{t!QRId<wcy=rg0ROrw(Znlwe>7bGIK7*-QX
z3Zwk#+aY@OR^<ntOM6CBASKcd-c<?KeWu=U-}dSCm+$j|aq#|OT`!Esdj**ZtWDp!
zxYW33$_#&)DDY=WTyzw^>WDASNiH_U9`E}tg&i$L-=A?9h~_kga1YD#6lOU}Gj4@*
z`(`3P=jq7y-7b<F{NctF_XF$G8-~~$EXf1h%AEG+#g527z(vZHou&fK>$spVN?kg2
zvZEi>m|2pn_S9_PSW>k1UFp9wmSXg?)`6vMumgX|9L8wQ_zkGHB5KM=)|jq_(95<u
zwS4hbWf7XBd|_7QZ+79&)PK?iMCFuHcIxs+7mT01ROLoEu7}s%Vf<uJ9+^Glgt+;@
zJEmA4pmkwx9^SiTT#jzJ5?v=Xfcoy1BPUk(g?*4o6P-pqUyTH*b`m0vA|R2!C_Kj_
z8r6RTi4rDn%rbtl`yLILcKjlE8aFm+NRA4S`}D*(>TN&}O`GN_Sm%8k%YitcQogTi
ziI}ghwd+%c%Sw0Uts1p!dBo9MY!9lLr0FgH85}wp;BB}bFEL5!t-hYnk%sTA<AZoZ
zhXAR+qwTHmkA6;@g#_QR{!&YW*m+<GYqWpd5`9JgQdI)c_n;8gqCN0B=lUfkgb<`b
z1fhKt{H6Q2husDfq)Pcx(~TCS?liKqT=$~UhgwkOwg2T@;>F-<P-I!?MO^4R>oN}{
z%@<%?^JSOl(T!L&VRy&B;AMs89?p?1iMfDEpWN1=B58U>A=`m@-6x}By`C!K3QvEo
zV@s*~iiObPqG+)Fgl^F@vDyAcwf(9i)%+d#XrrI3qFgP1%vy^`7EX^E*EXf{4>?Ms
z8@d|B%thpS$f(QwFMdLK#SZ1_ZOmK-n`2j$Tp<iE-OdcQN_^26a$L7Yjzy_|{6+=-
z<GyPgk4XF-BEg+;>|7;Qh?N)ff$@JcPi7iKX#Vw&zdGT61%?aCz<BjbzqvbdaKuOJ
zZzJO15O!%hTd(n)(!Jn?*Ot*3^_EebsP^Z`9eW?BdC2a3m2o@~D4NU|zOX@?-cl~f
zep>w2Z$G!T#Z|B8LeF=2Ru;u#DYDFUG?%)?6$f(_X~f@>VTEEc#Z6$@r%`_}{*8^`
zNH(^Mri1~}wtoV!D36Ry5Th{GNmV&YQ^IW{nKDr+PuMhNF{NO}#6!@M0>ICVeWL=d
zTEr@wwPwa5%Idu;jFpyRUeT1$MD6hqs3!wz6vkSq#%xpAX(zhLQ<`|An#L@+XsU=X
zV~x%g%xXDhm~KM5*G7xZ>@$BB<TJ+D0^(nqiHvcTr|Wp3{El(~91ILM!F|Qa@&(Zq
z#{kO_OWAN`xK$wm@?rXA*?XS>h6Ps}z7cF`$!O;{t_7NkUbF2<N8T!8YX27@f4Y--
zIwe8PHPMo$w6R@w!WeD7sE_;^PzP6j%qR4?azqVf?5Zr9dEe^toGO1HY4OAZv|<su
z4MTwJVkr~9x~qDfhRk9a-LkCqB8m<2G!{89rO`8WS#A1Y37<fk;M1NRuWgsCyuc*5
z<^~kyrVAVKvO_#25fSq;9wn2JbxqtI@?)}Ye0TfV&&Hfb!&2b6fnR#dUhU{=zuTVh
zH{l}X(7C@~;H38^Cf<JpHf`2<lDsu#!c1@up^BIrYMq0MYuq2bWkiO)x_ljxPgIe>
zmGK2Pt>Wd7sZqulMMS7YraN>*vRKVC(@XuREB>ML@Ro|Cp^Mx3UCK$+4{4rVOQW5A
zD^o4lMN4(8BuA}yMNdk*>2#W2^`f?z9Ph(LZazzE{&UQ4s<MAm`<id~G26*%t=kOU
z`BFjIYVN(753YDuN;biWTJwy$?sjrZvRd;sIu9$U#b32lpM*b{%1&`=PVw+QeB|bB
zwB~bk9@<j{?BYGFw}y&47D?zO@pYt}EawH@XPA#%RMav%Mmz28ajn~Oojmzk>&Sss
zxd%u@ldr?PO$vW~IaQQd&Q7db;MIydg}Mw<3q6)aQuc50cM3g)6Y6FFM$s5B$N0}l
z;tiYImPtmw@4{>H2_EKb%3ACA6x?ze!~>9C3MUb~PwB2GP+MpM4Kre!Y>~)!_T4$=
zheC9ve(bqAl-=k@?jmE0FqsPI#rf^#!dJT?LA3Y}39f(hzXAL<_}$-lSSo~w<-K-g
z9y&3la{u7Qo6DCaQ#gl-a-eo<S1M~?vYnc4Z2$Fylc`(aXxpy!?cN7(D+SA=3-^&4
zZ_7`iHKL@@c_I3vH39iMm`IY?*C3Bl+475KYNU#~BMzx|VMhLGnKfQi;zC@}<-p1M
z6fQL`we^2x5kCHCA^5$4d4nzmpc{BHU-4{iq(17%-+GX_EJL2x<{eiTh!J|`5kC;2
zBJE_t)fa{MfHzaxp(+zG59%F#=r^4hROy$hmwxB+jgejtN9|D~ET6E=G;TUIW#{R;
z|LgPI=669wAv`E31=jz6s#M&^-BR4c%F5DJ*3p02!~GwpN<GvRov>7KgwWy3=ZbI>
z^=vA>=s81eHZAL5=SZ`EEvo7U%}Hv*2xd32DF6psiM&1#>J2(wb@6HRu<?IG1*NFo
z_$i1~k@r4d_nrK7+YY$Dm`x~vx;B-PiZor`>tAnwO3(SA;pu8yJT@9`(d%D#Q%vZn
z3uu4oy}5TCSl%}pb$Jh5e(qdWEn+L((Q#s4yw0{pLYeP|<+NzG*dhnnBt*dKw2*8X
zTW4~yNa5I`Or|)dfHB7^;c*Ei*65bZOaO}*VyUM7KRjRV11o0wGPL@pqr~qN;g`J)
z>ot&YfiGi5p*{Uu9=;6q`EBp}rC4BC8clx#f%^Q8;ywOm6!ru!rn}3_KYYOz%U&ro
z2kw(xb1I-p{?Tnua=C-BXO>BuANSH{u%EmqZNkTC)zgNP8#$*`TIkZ#xg!4PDq5~g
z1-mx{C>U+A!dv4}iw*Hkc!%z&ETVEo9Bg<p?6`RCrGGS<H>uw0U)@!9AW!Oh2*`hs
z^qN`(4L`K8m5wZ(afw@N*0V=Pf1XE=#2;83ctDL}#S&7w$h3$T50+kowQL}hJ;kxa
zjb3P$NSndju#PcK;uSycFSbrqj<ibkNTOG~kjdOwK}W<&cA%vals&{5wbA3`nnavZ
z<3@TSqNgcqmQYKeAO2Q=QYuV_#ZP~ndy@R}eyw3{5`g5Qkn&2fE`U;w`9XsRBy^h7
zEfT`!GAdX`-wu-05b-Yk;xBxbom>b<XcWIMI64Nm+9hu=8!Wp@DRw`c@=3-rFo~2t
zL4Ppx@Ebll7Exi`)#7vHk0GRq9csBK7Ee_M{6D}QZb}?#Qiv2zVNHp$5~+WPPf8iv
zwQeVQ8UOxk9Z3~;5bJknC@44B{~vWVQ+G=R8wVSAOINDDfB)@CM#DjQQ3WTEWoxBQ
zV|#?$NeR<~h}DCk(2*R#krM7G&t!rplK7*OiP})NJH9ih>;OiR67tvSnih~`Kkr8A
ziD1Vp-w9vG$<ykM6F!vDUR!_kC*W7@7vQjnHJTp65JvCu=Z15L#LhQv6lLCC2mjrE
zwyW+dWT)Q?+L&el{(aiq;;rl?FMSW7N|nJRXD|EvRJP^koNzPK98<1Fzp^{9P)l!@
z=62E7#|5IP4A1EMo|~z>-qG8qMP?*vH%+joLr|WWY`JGu)bs%irj&mUOw}Aaum>f{
zAOlM|TU$}T-@2#Gp1h5S@>+<*RI*rwy0bwdjf`QiHNFy-9g*}jlANM1f}ab810|=O
zQLgT-|F-?LpOT9XP?k;m(<X{Wf+g#GKnztmNdppVS}Nn+a~9JbkF$Wne(lq1DCF2m
zu+Vpv_M9NOJd5Y3!!Umyrv?*zBmvw<?Mdzqw}AV>k7vSG`(U;0?%k5rSGBYg`Uhjp
zmUw+5&E5_YvApLc-E<Axjb=NRXMNJX?QXpM3;kDq%@yQ&#$M6tZ`C@MI&Tf`rB_%E
z7T*+b`0MxLWcduBbldDo42e=aE#zjf*d<!)570(YF>Nu@SD$~p8YkBpU4cpJu?S?O
zNFYfln&D5GNFW6&sFrhdaXEwoE$XGgFik`+HcL$kk}184KlqpRq9mMFnSRf=dr;S<
zPC!%W@C|8|f3)>AJw|cU{)E{~=8BTQzC+Eb9-2&iL#Dc}wt%0OTWhRQJ`1sc{AknJ
zpe9Tlb-W}_ORIm`0LT}ZpV6)j_`}Ukppk{*2M5TymbptmBdu`L{1NIeWZP(L5<C5w
zY{LJzbR+)1lP%@w?&|Zm%!RtVGPWwtZ$|+M8-hu)JDk(dkgHpOC@6dcfGF8$LJ>J1
zM_^UY%a+G|&t|r-gtgVeF0D;dEBlR##i0B4OID?~qdb4kes$Ji?oF=Wtk>-8b>7Xu
zpAW|tdciIUI5s3bjfa>`A~DyynQ!jppAjg-Y&D#cdc_KT^kd!@8#cpSAN}5!;<<e?
zO9U*D9CV4{T(<{0*+t}h3MF2nzGiR49kSwcrw6AK=;bzd{iut3vsD)=E(7Dh&f1Ic
zOcdf1ou7Zgr_F5Ell-*EoZ->YU$aQWo5V{9-Ajgst3#A@(G|nWLz(wC<qURw7@Ko5
zop}@z*`<aH=p34J1m=UcL>1a>1>&z(8MI+fzC#lzLYLu;%rU7*i}mIcsU?acOX$yg
zzUt|0>~8~`j+_bUYju{ap|w>b$!FQN=S+~eVmW`fh{`8Eva93dTbR(kXtTNG+sIMT
z;wt1RD{;2gBLKU4Y&B-ylxs62W)J1tKQFoUVv9?{TdsR_b?gHAXJzXTN3FxTqOi+k
z7$mUXFq6Z4zkU&kk>wNB9L-ZDE>gg9(5O(;C_VrD+RCjb)$>F^vVquLeY#q#iDC<3
zsKbAlB%LP(60i3Y+R-+7VM_26kxo8RNNEkRjd~m}wghft?J!>f*1Z7oNy=^<SG0h2
zk(bZf@*hDf<fJPdvCDbampkz@6A_uqq$DLG=8;(9p~=+epL=C4?6N#2s~-{1MJ6Sv
zMx#Ci-EQ|DHdP(G*@p=E$I(=JLa7v^RS17|El!7;0mB$u>uev7lsctTB!@2eaDs&q
zcd#XubMY7l-m<G7(JR{~*}@C>cgj<L7?`7O%DoGfOxV@C8X=fUR!(G!eL2Q>{p;5H
z&GY~}K*YZYT<o9O*Ma^2*P;J`{lB?f(@<Sq8^@5=IAg?4426zjL9gwVOtPu~P71kl
zKCzX5CS+c#FO1Tllj`9ZzN{^;YVmjE+e(&Fz?p=H0<%ZC=cI)7o5&k2zxf$I4+`L@
zNX@GAJ-6?9-R~-3W&QQOz&H@j8DRYF_A`~-f~?+Ho<z#BY*y-6D)m*d!%x@bwAWH*
zW^;C*31^FqTuu@jyIaK8DF8D3Y-)M(dK7_wt~)IB{Q~!o6le<S-Hz0j?~Z9PEl1TU
z^-ek39mATN&Qq?kg%i~>b#s}Xp;{!1a`A-sAJBuje3~4&)y#0Q(ift>Bw{m7(+e6w
zZ*7xn9qpv_d{1V7q(4SR$)sN7qb`(E`xO(9_yU|v;ech;^XLt}g5LgvyMjaxsNF+<
z@FZ@Mi#;4e+71I+z$2_ts?PK5ma<T*$K%`MpV3f!T+ZPS`CK_Uojj#+LQ|T@L&Kyc
zK<Lxfe`<w%xf2q=TWC4}S^?6Wdm~_`b5Z;7AQ&m=4rrA7OO=t+u-yjfk%;36Rp%fE
z_m5xTE`K3WAEojj9wDbFXux`fpeFu*u|f|g*~_CJX4|fiUt~g1tUCUj7kHpS-!3<L
zS|ipQ@d@>Cyh$;={(uUnWnsN2X8ngxFm_JAQaGeFo->;Nw^^5-t2kgN61WG9$kMOn
zbyWiE=2Gg%Xl|xc(>l#es4g~7Mav%{Gib?y;S6xr)EczA)|lQx7<@Hkr1!Re)0N`N
z?|3-YAw)H}bQcKx!WvowcAD9_@x2Q#9P3k`U(?-U_nE4W@AQVfDaA9^2$7&SSKD4~
zdi?dfYI6F^4=DYodUV)otEo=&l1`CROe*bldu8LXl7GRYpz^>C5v_YD6ps6p_}cJV
z;;n6C(6?1v6C;{+Q_sCsYl69d6tuLHz5dYaYyqQIb>G6zl%dg{%gFkNGK%jU$FkpT
zN|IfaTRybc`SrC*OXTWKotMai=9A$eUkOHwYc-xoeok@9))k1f_FrOuKAP0*p_|RN
zooelMF4xu^ippb1D;2UJNQ<`ha-NphjT`fd?cg2i{Y3&P(NyHC*ISN%b+cToMyZ#Z
zk?_4R@M}yniUnE)>Q{D6(FIO^G|{f%`9(YLA#T{MVP4c0QMUI0XLPht4V$=)QMb^~
z=rRe{hS@++{-uVT#@c|2xnQw#<(3@l(=t;hp>W<I9AV!e62{oyq<*m^5bEBmL8nM7
ztf0bs`eHbm1Zx9zGsHfBqgave=`V-@QDELX)Q|+{V(VA1<Q_YG0FND@)HiY4aK}u0
zsOAaQiweTI-LUtIvNX+UtK?q5gI9i((qO;C`jw#O5%W?Ans6kR(HfG)c(X6By*;d5
z|Ik@x)tI+qnonrTI$K0?G9QPt@88+i87b_WE1EvfqMCDnJyimK>Nf%ds(5BjwHrmJ
z4GqkfO!Yu3u=yn!JVoT^%LmMil1CmL=I6e24Jyvu_1g>2BgKyI7PX0<`kk-~UWlu&
zc8^d3e(50D31IX2`)5}HO3+O%=p$`l{|7ooB&&$uIGHdpwa)FpPTC{Zb27(wu?tvr
zJl%b&Cv5-Ri{T}IbdbBL*YGp(6^jyq5qXB-bvN3J6Fl~d1!~LTw#0gWd=`2QrUIux
zHGt65l0>0K9xrBx&#G~5tfMBmW3Wa1K%QPdTgB4vg1#r!NC>I?;<ssB?I-Q3#m6UL
zJqc?M{F$${#Oh3jp@d}Lso5V>nbb~&{IQ_Dl)aq0k^RwsW(WQv-trK9N5G#i9Cv@q
zHz7emeTIT6Dy8}-@zVTP;&rxjXZ`o`7XGjQA**6)ZfEJv#-U{C^^XnSX-WEjnIQ%L
zF=aD*BKzBZUAq?L=j_6o{m{bC)DEWP-^fR;!P5Yl)#>IL-&dvn&)c^}Ukbm-2@2S!
z*&0u>b-2xc+youxzJ5HsAcF|4m@NP+FjXYR2DR=7_3ovouN-$2E`@oEb5W(NEP1y&
z0@vt!B=UW|-ORK4{mH@YiRL=LShGz*oVA;lmF)>5S!BGYd?X}Qg&l(`YZ}1|`Y0v$
zH(SU(C|z0ujC{>>>y0Ly7AN?gF(!1I<0T*!n;KDnM=<R>#~b}qz(k@*LTY&cLz+gw
zNzI%Y?TTrwtX?!W<@A7|H^)--ms~x7Y2`<hr<ajnE=Sxt01PWJaT<8mYT%Vu^jiHp
z<8I(bqr_rjJBshy9L}Dr|ByAZI*No7CedPM>G6vV@6E%(c*>5Z+V;zPgRUH`N=3(?
zSUbmm;9Qz40LQlV#kS2G+qki9CvU79+q$uB+qR93ZLeMH{n1r3RXtPF)lZ)@2i?c?
zq!=6C5<bh(xsFlLD$W+(*c_<iH`2u;qSp#lC%4gBLQW*i(58QtN}VHIkbhSf*>+$o
zNM(dM$e>MqzJLvMst`J2atI!RfbkWhYHr<s()h)1ly#YQH9?y<h0yJ}#qFUFEz&G<
z344vDMBsNy{Q^vSsR9@XXbl7i=>N!tn3$-eqn)F$o$((Nh*h+Ho7Dc9oUA6*GXBc}
z`3x))vM8E}Rk~q_%$%gvFF!5KNz|m)piB3BZwIl3h9G_Y1jcU89W7e<p6gcarn$C%
zU#3>;U+$ik?SNup5%Pl#CSAN*4GHK|PRYbw&o{&O(fQs283-1Pr%PA#4%f07tgzc#
zj-F2%PCZoROOrDh1K=XQ&?je704a*F>2b<*B&C=t<IHprMNH0=s!u)5Is$g;r*eL1
z0l9iDX0$A3)J3`@<!Wjy@V3VARbEPe%SypAN~>y48zQ3cnd#0tn|ZXRVvX^w^*uns
z%{A1fQgp{<wMl@<=|K2zgAKH*qtJ-9mL^yzMHQBDLEogtsf!F^BhvRCXFQH^jn)~r
zall2FRfNr<S->I|XkQaE1Br#JKSw{UmB%-9xXu73Zf;pb4T`SgpX9=XIO7R_G<J4i
zz#9pS0g55?o#)(Q-oC>(j*oJ|D-d~WE_oVVQJ(B{21rC*?F<G`{R2l_u3-kWo;XTX
zV^r(SY|Uy<RCBdY%N|Rio*K@UK511%kyuI2mlbK4$xtX7a7O+H*BI2$^%^L_=E(8a
zf_=>R%neS^qZN4;<K=L*A@S0G)V8OxXPDLJ%7gnUiy1E6-+jQ!HDLFlHy3PlQPi#z
z(~%cjc>3Fd;CanrMFL=L!o;$rxoj;tz?TQ~&!XGUd?R<rbc5pxpxaMrg?4SARf9;_
zc(f`3q7*v6O5t+<aG-Mlk%^Px7e$84M<@Dbz`xxh+)@ec1OT8WL%Fek?#lJ)$hKtI
z%cEYBZ7c^}p<LSafi~o)p~%ORhYLWj&6>|~i-n#Uzq5X#?r#UL2gPoFvl0jh&<9H}
zyQFcR8b95;yqP7D8N`fcoQFCuL{ccqDRBzAzmus?&F}H}RD%`;Uu4d@Cgr;sVA{*1
zasYWj`CdH2CM26t(AT<ufd2ZjDU}%d)w95ae|I$jovlNbPL{_-oL)RHOPiI%D%;xu
z8i$0)GZgW(O~3c8FFuEjtgZC(cPq@hXl3IO1PCbLpPGyU|LF>2WResX{e9Ihr$3y@
ztGcO<DvtIA4~E%C2{rNqBudKa8w|~oCYeMM6dNnV7=-5eQS2{&eSLN9X7$MD%6e}z
zDUXu^IsEHJflE$n{7>?yC(Btx;fwe8_lXG!6IncNKHY#LpMw+upJ(JAQFn-RtSWbA
zW}R9d19ck<DMeQk4VXbsV>J+##Hto62(7p@Ewn;9?5v+7CT4WlTX6=1f{_O20y<`l
z)Nd)+o_860(TwGPar^1tw_QxA9K9I&XH2<F<V6-0m{;JVif+HAxXY84_Ttw}yzMrr
zteCD;@{s8+e#E7bkC7-xABoJvfsPL87OG*5MNK2DVh^H?zcxkYV-It#&GgP>%2YP^
z?{bR6Ml(7e{34H0wr<5t8_t%3UuHt#Osx6iRF1pLLs-OrFc$}WaU}d3RTG=DmuoXA
z=pn~pbxiJCsf+FIsw5AD{aBA=NVXWT6P#gaW(DU@=?hKzXm$HF!GPSapCepTJG8S_
z9F_0_1)8B`PNnFgkJQ6foWnCxX1Ss7v1KG_o|lbIF5X4IP!+&OGCOyAjook$K`kY;
z2W{P<^`h&4u4-$nlU}hv$b`J~OKac`G4(nC+acLGbL2p#2_$+_qNo+Y+wIYTreN9P
zV~`J<T$HP7)0Z^JIy&!H5U208l*NRPOM`>jvE2W{OF%YzGsdDi+-R~Aeg+q2VmE&0
z#_P0Nt`g{nLVXcbBuSY)DuOpZQuf-}Yfqf!iyTpZ#w1tagm<-5B$d9B%s^ggTN?W-
zt}W4QZdEY<dutrtC_+7@MZP5@@Mv(+MVyzn9}f4#<;*Pu2DuXbk}Iy1G_09zI3B$<
zeK-94`a5lr)mp3CwgGhs{N`=lY})xb=-W2Yi0FD&NkzFZ+6KN8H(`CY0zF+7kplZj
zYn(`bNn_CjYh{p9c<jfWk?@LC$BxDP9h3G8;pQ`2C_>(}19aUu$p@MF>>uzU&n=E|
zAY&fcaP{<x5;$;LaPwc)dz8^fYe6Be^)Le#FimNn{^psb7GmW>?c@z}DR9WeE_(9_
za%Ys1vJFGxPxj8NAAH;d$Ll)x02vY&!VtNCHjm7P&10f7)PktlDs>`8oS1vyE^P16
zso`U@mUR3I19xAZK82PT{d1;xH~}LsW_Bb%=-u}2Uh~e0TzLr1lS66MxVetv*%YtP
z)hVh>wX4p0e<XW}K~sn}eDh<?v$AIC79hxku7bZ$T=O{*j9AO4<>^Qr(K&}Y5gP`7
z_`oYO^NMg7az;F`iQq`0%`ai0xtLKroj0T;`o}Jj|1X{s4CZw{l1+L>U}reFhi-7p
zprzZ4*7_ZQXZ5ztpgPkvKVd6O$^Dfe*u|HOl`i&c%-_nFY@$WTJ5V4XOsM~>24`fH
zFt9atGB>dLlLnVnMioNxu5TY5t3!%^2ihf}Bp@~*p{2B>ou!7Y-JnJ*|F)Y%gxxQ-
zVr|0?(>)S_Sq?^ph|l+&zmN?by1Tz)(gt{a0Ce){yxlD~UjZdw&jbxAz=)hLy?h!r
zs-jozG`59OBm3gEPtHV%WD&IN+Mat>dzh#Xz``=PE7)9K>lpOur@mENhHOcHkwA%%
zJ>vEb2~lFD4#)DhZ=fkA$Uxc`Dw64&Ui{)aElE?-ddPVjxJD9kP)G25g9_2f*gmQ+
zQ3C!;Cp)dPn}6=K7>MMFiFK+?_4W{(GgHCRyI_aqg-wKcpxv@0srq$C1a~+$O2=3%
zL&LmJzxR;QCAa|%dEyQL#-#FpQeA{H!!{kuWF$MF^Pw9X)~Ll`kGoVy$b{sF!-H)0
zd#WU^a*O0aU2yRs`ZNvGL^j*p?0|`~lvn6`YL{(A{mX;eyWJB8jJ?bRGn`Iv9a9wX
zWZsTsOEeemojrD2QjdkzAWIrT*f^xs4@<Ts5rqgh+Kt}$u=ab~qh9uZ%h6oYGnkPX
z<>=CDGDP|8DQXT)MN!_TMIK%4We>?vXiuN4COryifDnFyRxa%Y*eaMu1CR3>8l5l+
z;;~y--ta79oMWVL!7r|%=Vq#Gf=7g^z<i9Mxe;Z6Qhw=TV;o)sPhlB|)l%uyOhxQp
znQ$%(@k+`9dmn|eVC6Y~!F?nW5E@4t!uJQUQsO8&#+-<e@SLN?#HQTaWVnV8rye7X
zmUM+kS_Tz}h0)5VS!}eWHynEjokFq970FvaVl_`EM5CU7#mS+ZpqXGC7x6`_K7a|*
z6G{6Lnn(bG1}kG2?<?gK=g<_DdQI*1;J>ZwcNd08Hsj=PL*i3^8lU{GUjC0<^XlKa
zqn7@uJBsT+<({2O!Oqs~56CO&$fF9O@um3C>R^~hcwr)`tk4IeGl}hs8zLphhQ}^k
zpEvw+Ce_})Du@0R6Vnw7g+uTT{7HE;r9>3UpSn4bmIgT5U@^Ol`MKQ%+7clP3K}#i
zNZm|_z>(fr<XmWf-e|HBI%sw1O2UzBbJH7zka%_xHsr7Jgnu3^G%lE4^QZ?2O`?cb
zCbqJb;;@Ve3gQ8lkL=3LyklScs@8!jgVnH+9{!Q@5F1-MOl*!)7xUhuE)Ugop)=Xu
zro2T_(A-zV8rK&Jj+!5osI$eP*puo{O!Rd`1iQ>QRk+4~Y+lMC*;YJHK__F79((q9
zx=EVAXaLZCv0TN2s>fg+IbF>J2MzRW(kJ>M)Mvhkco3mmOuwI!x0M{Un{Ehj6<N?T
z+ZygN%&ebY`Izx0Ph7buEh%mZN6R{J{MDm@uvobFIgSQ-<j2&b>of_uH7CSaP^quO
zca1)3Efc_h8jg=L?3q2Za9Ct<Bi(enyhbOIljO*@cXQrBZ@D+_q~=Nl?rm#zwR*>b
z*x4&DMyqW&F7x2X)J<fA9rUkIWbP&gkYX^ZiKk>(syOu+wYh}4{N`h7s7pb1!BBao
z&Y4Uz$C#w1)|h@3!|4LF?2&1v$ta4`kF{%u;*t1&?2oB9z&wQ2OOoYCXyZ2`=>H`G
z`6S=nrY0SUt@A+%ZE2fe1++iG*UKZ_(tDQSebO8s7~>&+BvZ}(lgTLnJ*u#}#5~ii
zgOG;&DdSh|(=`L%ZM#v#ZCO6jAbx~3gczzR*ML^D1`o*};jNMy`42}8`0;fAE{q^M
z>RPLR`WtqiK>znJ!e7d4w%?oL$}UDmCQeR&g4k}J5slAw-ql4|eJKjQt(TkKTv<pE
z1lj@>g_=;bY^5NNZ@*9%dVG%3MgN^bH}*NzeFyS7A8DCf>x2@KaxTjIlIuuU?`?S6
zZX1|ausjH_Uyd{hH$34j(3wz&DkN9tT?CJR+6}Kg3~ms>!LL-+Oz}=qddYVl;vcCZ
z@ZimbpQ6vS@xlNZ!nLj84jK}?g?pnG%ZbzGodh;(pOM>wD&p@s5o_1@gk5oIPRMmz
zvO;MPZP0}&ax3cTMVOGXN0<mFUD@ru_GW^#ECwvfELo7_S&q$w)hZv1qKj4>{;Y(5
zXLqLbz8c10gdR!Ey-F<n5qW-*ZN}NETU#56zGt;e@lkceXJ{_pQS4>*OYJp1G#XnM
z`{uN5*{8Kcie_VN$Qc}ZK4<x2+HnzU{ZNnou<0!yHvFO$i&~5kXa?Daafwdi%1R&i
z=C{;Y58p)cE-(CJNe<KQ!1gsT*;5XGdHIN0aphuFe>G<_wDAV3bhz9p_3M}rbLE2(
z#fqN1tRlU!V}xDqezwgMFEN+A()4eta}%h|V&?EEVV!~{qU~)CD`R+Laz|*=$`IWV
zOQp@C->UZ3x(9zbLM<yc*G6MVa1V~f)tKhqBGe{`)zZ8LpHwH9ViQfUQ0NeU{lc^T
z0{Jaj+ZZkAr@%l!q5qUD(f^bzF;Ni<C!^mN0r@L;kBWsdt~io+AbspIW(shi&H2ib
zLB|kL5SX?2@K`pXnh1(xsB)oZgugWs%_4L7r0-aYN`P>o_9yVCEENx5J4!q!e}PJ2
z+A`lq+ndd_*Zci6BoOQ~R{(H-h*@;3=cXr5_u?8#TaD{!UuEl3)523m8_nsG|JFtl
zw_dYl`?p_3R&?rFaYmPn%4}jpM-q-OK6OiA4UJ`-iLnjK>UtU&mlsCK3{fUwVVSk0
zT5!J2IT{a^HH-L3f%lvH3epeWiK)F{1^((~%xjX;Ix#7#4d=;vqoUw{mRF0e0(Vd)
z4O8Y2o-wka(<I-#=vFmfgBC4`W(ArSdoWzF!qkIGnNgNxe>Q}>lzl?A{(6q&ZGutb
z&Ur@*uKz`^a+?;VZ*^9Bt}!diBt*ZmmJF+}s^$?F!Ni`9>hv+2&YNv4YAF2>FP74$
z!HDDj-XHB`>9NT^O#fbgM6hkE<bqiy(_{)zRf|e*g08Z?1G9L#a!Vylh*7OzgIz`!
zzWz)cz*8`e4Q}2N0dT&JvSPy~H>#eyVL8Lgt45n=45Mn4HgCDS!Z%NSbVFpD&=22r
z+;R<CT?5c<)IGFSHGID*3n%s)#=+kuR~(eH8kNu3Lmzxk3So+WEZ<zlsUoUy-8N6{
z;Y62fQ$Cxw;iu-dl8oS)OeRGzxS*pU${SiwH<!u~V+bhzh3uG-0S}Nj@R}8ZHs`Ec
zTO@@&m4daWbIHFoe<&6wN)HmayT-L>{){o*Io+?yU$qNJy6SW2dJzqo!Cg)+SeNlt
z4o*J5kQ&Uufzc>`c4x>_wy(oo#&k;VQbbdX_M<-<@MvYNFbqtLb`Us`h8HL+(BvpB
z)3kc+r_B821y)kSvSA~AWYrSHHuJ5ESLHjCbi-+vP988Ukql)XJvRh2;=>N*E-ar0
z{J|i8#U8`c4oy(?<BmZe37>nSE34)fu1MfvB`SWlO8#Yk<?{NOGa&0`iE+^tl;h-`
z?i+i+DN!J@r$7sK%dOoDRK4$>52Ou5U>Dg|W0040ofY(3a;rcGv-2y#qq&Ra8FFFT
zu+b}%i~pKMlC=z<PFOe7HhhGVSq^=`LIU@v$=fr`D*A2-ceVt+ArX^z=-|KxQF7bt
z{yn(LPoYzPr_i=;k*pYn<w!BNG%U3RX{qC|;g=v<>UCpck07&f<`)F)L8)g^g4*p#
zIuzSv{s|kDR|F5WIDwz6Y0t2*;u^|ldpz$sONAsVa`9Uvb8jLzBy*e|>^B{ocPd(W
z{{GuBMt#|bz#m@+vc2WM4{Yb5cfAb$MrN=={(m)p68rC^g_wbbwTq+4-)baN**|I|
ztcFrTLZYAsXlQhD(K0Nh+3Xu7<%v4hTRg0<FicW@a{OoDcgg{m5jE~H&~Rs?pMa^>
z<>k+tyLC69r`aY&{gvq8M-m?|yHtc=hG$9?YL)k-#~2j7u+Z+O1kek}X%Bb8`%TDB
ziExd7D|_rhsg)Wm+piSRe(lunV8S86pSYjN37q&Zpq0kFYlf6|;~J;paD%R9F}<fz
zKl+4_RWaFrh4rg9W{l~%e(zk}>kkP=+QzTPlXF!;ZA`MnQ4wgl2Q{ZWyf^ulUkPOv
zq(27`*rq8>&F?FaYDVvq;6}hjDLd8xk{w2W9^xZRDv-8Y`0?)pc8G+{_V^BY&O!^_
zq%1AHY}$Tqs(h`+QZ=3$!mDGKrR_DSx#eZdP2hkAW*8@2MYtE}nHj<3S?`2Ioxwfa
zp<rfc6l;Y#wy|IpQ={?B$+U63{j$MCZm!rZ>ZuvYpUzz=)sV-NuaT=mGmdoX9el@s
zMAC-#3mT=G!R*uw!+~>*eS!nr=9!O}O<t)<uw_9Sg>BXhH$4i#Um?OZYQliUt;Bs3
zl~xw}oqjE63j?|}lI9D;ty8`vE5}2(LuL>CTa^Ldm3yGQli)COJcD`XyL}OrSsM9Z
z#y!K%((g8Bf7?r5Jo%RjN%}tqi$lhL&d9)8-Okb4*opMd*S{w$OHoT2L<sFuY;w^?
zdAW)oLP$4{3ML?2w?GgH77l>#M)6(8%*6HLw%#)~=ZBA=05vyB5aJ^m=#ke^=9Tu*
z+1oy94;3|r65O&BIWHQ+@aIB`cDN8_WAUI--#+v*Gg`G5vy}UpoI6PxUREQ2iF^=Z
z9KwgYoj;v1mXz=fX-P89_4=oRC$#YAstAuEE%w-jXh+7eAUwSf^yCP|w?}3LA;-ZQ
zJ)I(YfF)l@<Y+@&$Ufl@wh-sWrSZVrV}0=Nf!dH5bq5xZQm#e&T?<cn1WE$!xU!8D
zb|6M7pKI4MtS0uFQj(i+qIlzfD}C(!FJIMS-k2D!7JaPV;xJX%sj*f=WRu5-`s_8M
z+(aR}=x0|Nl^mv&3y7waos(fE@g~L+7!nv%r6MDRi4Ptp@YeB7M`X=4f$zUFt^k^R
zZ+yR*HL!mg77+ZOX6+ANOJyy2R7IpuIfeyW%rVuHCT*}2Sq%lS0zpH6r1+?$^aVfi
zF1$6P`Wowui|;}|KS;>Qc@zA?5r;TXeFMG*f}rYQHHExqVoj$r(^yjMy3%}JK6gp{
zpf{j<hZ&8aOVhjn9p{O`<nDuLuA{%2E>NqsXkvVUt!yG<`ygVlf#PCMs!ncc)oh$}
z<O>4o9}yU2q14i~-YQ9dm`m3?nr{7-ME`=ebTpARD>X(+G#yrUCLnwAOJF5;h>t_w
zCEXN$JoXOmm(n}JIT|?mX)T7TrVRcX1v*%8pN0}BlCd56LiIj<b7f=^RAE*-4a3z{
zZPZ7SE>jfjUb^*IQq<y+$THU$X<d8c$v9C9*sha8HH>EIJo2c2GEvaeqE8?9v*4c$
zForESedr<C-G@rE{+z(FCnrfzp0fns2!zMKE2+Tk;BYNQrSzQ%x#|2+(H>?zL3i8H
zN!$gi9jy#k)6l{sOM@jEtZ^qw42csF6UE>#2XtI${wf2k_#>rkA;Cb^5r&Dk>{~yU
z@WB3^t%J~VF?Jn)yxKJ5D*(YwPI5!Vp<Hn$i(J@A5oHFl!<Cz<P{ZXsUV~Yi?6H_$
zZ1Wth%=UYqE~7^${VCe=HK9+K_-p%|X-k9<vq(B(%5nawf<(3kv4W)O@vlfqjkj{S
z5;n!psxUX@%py`sae?m@j3X<4IVQcLuY-_iKQ~#Skd8fn*q^}H6d;Lz=oXzuxNJWK
zMuBs>VaMwf3Y}`T&cy$?<B@2a4g-aIy@no56J*C&5q{+p>lo+M(S7+&{P}u(R`p|P
zkR{BNdp}4(C<%ZpN|1Y6ybTn>7|NQJ-yr3LHH6}zOX!`%otaZY889pCTqhi~y2BB0
z)o;UaLt3<d@mQKg>OBud@H_wgD6@xi76=f~^<ViJ3~KrRi?o-&SPFj-RO%M)xQpm~
z)A4+De3I5=2&BoVwcrd6iCLsg2}9xVAPm6B%FBY-(ncPkyeRpKct7In3Y-lPgOa~N
z=PEQOHW4*A_E_uqC0{!0`98V%Hhw^zc#y2tS%V{g>26JIcwEsRZ2`72+_rpQ*nl!_
z<iSlqDvN9(_ttvhXPs3Lk2Ptlw2-B7Ye7qmd*=4nL<n2A5rQ5q<38Fdd*~FL>Rko*
zaab^p3A(<=tbmN?y@nc`&YoB3YfBg2C-%hSn^~^0@A>P}t&%HXvl|wf7Srhvsy#P#
zQdDz)7_WKCG_U<C6tD1tj*skRy(yvlzNM#Af%U<ENT8~a_)~g6`%z+p5gt(NS6*u&
z*z=2whzqzhnB^V6c5b2Ai8wk&zFIJ5nV@KUeFe&Zx+oX*!KNd6Qi+0nS5H$so_6;q
z%w%MdSmTE$`a^|^A|gR&{e5a&or`o%6%#9eL2y$MFnBpwQ;MmjFy#vRQYC0xlF|;t
z>U@;<t2?9ZG5OiWH~*$NHM_hULSeSNblFq}j1|T7fJwl;$^dhGQye3D1+qDV%|~*@
z)vhyXUNMxQ(I`%nDVwvESY}pUPU`^{{h6dl!?O!C4Spe{6*zlRgU{JxCp1fuepXL^
zRXm2P+Xa(ST#!XPhN)6Z*8<4#<z-z(5ZStjBNR_F10Q>Z*0N>414cD$BS;DZ?NZEa
zoh+#8O29apb(Y0Y>qWUCZWAmeWP`ir6@kGWTS$7ivj^MSOm2>jz9MjG$x4{c`Kxg{
zT5Dyk8NXc<T_P(T8nnvyw&Z<!e;Ox$&qxvd7*i{vgtdNlvq%RAiyLL9<=)UsH12Za
zn4UT8#oW(T4%Oo!bQpR}&MUkS)gXH^581YpSZxX7x%@m#Z?9;{=4CYKZiyP0N9Myj
zl=7W)?EUCiHF%b#H1<8k&D$MKrDcAn?ldfp4@nB<Zoaq$x94(uHVD!*U5e3vO0zBy
ziZ^v5g~4J*k+#Kn$xUORu0C2!4XXqiTLlLae%Z?g)YTNy<Dp<_P7bK_<KdccsFK#T
zg<)aSv89PneqUJxpwUSZl$liLgN;)BSPLeV4cfTs16mUL_Wr;Yzc!ATfNfCaoDG38
z(O-Dunb)*ht}y%eGZg_nboE1jb|*$SPoylrBFL_JP$8ScQnwc*yxt97K7{HARL99v
zBNzt64x`qlZg_$a<T^eb_n&CQ)cbvIP}gv$N(|@wuo%2W(Uw49`xb%Oc2>eP@7BX0
z_!bCH;ayPM4*xPBlR`>5qXAZ$OFYO+c(F-_Nr24hdzoh?UOCV*5nZ2uwMDn{bDU_-
zDI>dn(G(!piwR>kxbG<wapmfoxcdDdqh``vk_~~4y5&byvYty6KT5IH5OAkJsa7zC
zM&y37!5K?KU1_bztvSwVqRP8pIOGiyfGC;gDNY3Dlp7EoYw}SOE^gddwhH%fY&wCj
zdR-#eFO%k0SK+Fa%s%^nv&k%?6J}U}=EtxxgKv^ZKZHx@8#KCJ0uEn@1)@ZJa(#5U
zyVMl5+n(|@YduqQ6pZT69u}pudJvl1O?J2N1Py=5(uWM^#u^ID3Eq$+6))UrR6QOh
z-01r>KaXpjrB}R-kN%T5<jva{(h9H5vF_cl^AY+4Fh`|9*mwtj4CKQarsT*o?=`H9
z4^buefZ>WbcSG$M&uh?h*^F6i|B4YR^x`bX=rI`e>pH<zh2j8p7=+u^HnnS<dG&%8
zNv8M>w;zGIv4T$cfvuS;L2PMH1f!Gt!%oc@P6+Sw?#g{%7#~)6Fk_F;rS}XYEqJMp
z7+O<t8GD)hQF<kR&xN#+;VsI>O7~Xi-Mw~H;gOb0wme#*z0~gr!|3nX*4h(-wpT74
zE95gOyw`aSu<zdo&)kiQW=)+{rl~i2gny*_QV^8)g*BkhwnuS3L9#7do)x%i3r5lV
zv?Li6zGLhp?D2X$YjYia_YrbefKQ4SP2?3%dvA5XiGVDBR=6Whp4wV$?KsLBf@yB{
zH)?fb8-}?8$3wpo#pBzO=3G*7XGp>vTqk7+X%0@&?6|UVsWR&X*44`a_lL)Go8eaw
z7O<>^qdDG`dVZ;_h2XCc1!Xrxk5MhJjhM3)Ta19MMa0~N(3XMU`reJ}j^2^XA#Y%$
z>m5v@E%Wey?qy)Un!~{*%?%X`*R+e4T*VtTNylLD19my<n@)t+1plEbo$Iyskkv1$
zbQIw~du*wX3l=81gi2Mkza<<d@~&qJsq?Tc^ORLl_v0R4>AbO@79-<j4lM?5U86lN
znq7~=RsHOft*)LF1c2sMC(*ck#@M<nxBe8lJAeOwXnonLg+p<%^)S1kZ|-<7zM@*$
z624U5#c`G_--Y8BMt<1xpwDpb#%u2BJ91o}R*sh+FHB@-+At+A3cgjd9_G$g0$mAw
z;B~eZjMvayi9|bju(claZh_M~7*n;+>V?S7`GRw$M%trArdFPrq@{XB>1|JOItp}4
ze~H_F=^VvF@_%z`u{p8ufQ?bIZ|GNlM8lBX$AY~bPgv#o`Bp^bRao6f7C6k}9`Bxo
zWu4Wx%<?Q|1+l%h`<V30a2NXJGUpAaC#l4Csl8x4IrFow`^=<z<~1wtmU05+laBze
z20w`=sk+$atfY#G=qznR8v11dc+IaG4q5hp64Sxz6CU6joX+(>&Ph|-XGTs}N6yHX
z6mZS7<)A#F&yd;}`=kV9MxnO^gi|RTl0Z+5t}})51L%kgc2>SijiW;!VSExOU&niO
z$o4h_sJ|Qu^4onA?FHM)GI13UksO4iK}P>FNd1N{baa&9-*>{u)J^o{c<}i=iy6d!
zb;}xS^_bLZ%0L6~+3EmR!}#v(zvsYST~V?0sy+tL;i0GvIC;%Iuc1(&m#eZVaU$4s
z8z93umCyWGW-WqTmfNMEFk^8i;zHqtZcqCur5!_d@Y95MkzrW&Ab`kmwk9DL=lf$4
z%ofI#5c=1CnbbSn6|H@7%w>zmLo2s`Mw39XfONW+7xp`Kpj%8Lv|fK${g;oyQrmJG
z&o`6^1FGr=Mm#J0#4MpCq{W6?$ae>S^iesKNlk1kKqsmNOWLkH#ZhTAY6cTEQ!6s*
zFN-2~d@4=^!+PN@0@+U8jfXZW9PP*Vr1bIr&a5n<ZaS;(IF2_+s(M1aRwWpJ?^yQx
zKvzRVF;9)Dgy}!9)+<HskXpZL_CsNsJs~2n4}7`0QGDr8j`-V1T0I(3i}AQm34ZL2
zgKO_|9k+K9o*v54ZS>yA1$bgAa`riIWkD{|1Vw(>i5mKnVge|PsvQicforHB1*49T
znp^vCgBjfJ4E!ocE_?VE01TCXTjH0UKmB+G1qh5!_(U%Gq`JIQ&jE>&-p&xIYb+W`
zpkg~$(M`VZzuN@1fTEy!4h;lUgZ|I#Dxv@MXOfXcQdm^jz}DEp_|Hc+##{Y1conjp
zyN;2366`pyB+@Z!3o9MSM2>~3%(PknoPfj6(qN=RwLZzL`Y!LoglzMFzJquzjy)~o
zS&Jr+D*G$PNAI6bkC`72Z^QCHF^aN=AqE1mV;7<0mgURwRcIH{k?C>n<r@(*QO4q4
zj{Pi$p4FmvGG&{5)vgMtLgRMOWC=A`O<%A*u~3DP9T>t@pSoU1#_(&l!lFJiTV|<N
z2)hMdzk=-YoT^dHOqLUWml}pst6Yy~H{8LimtYzQFWl#1H0IosIGzU)M}ZDs_z=W@
zoRT-W7t3^|{E03p<bn>d`d;;>M7axYAg>5RH6;u4wo^wXeCQS!L8^w0@x$=S{C=p2
zx0&l!gQT;l%Y1?Nib~jGB6~;9H%hF+X=66@1v&3Ei0G5))&;PCL~+J@TG|b}_zA#!
zy77A-VyejHeUx>#JuNBX-CLPM<1ad9b~lI6OcB!RWQlsTPOQxm2_^z$4b}#tL^ZI)
zu1DE2SdOW8*?N5rbz6zE)JUQa9Q$VFW|2!!6dj2JGUe)LNE%O?#9=DOIk%av602if
zsnth(m_qO>xilJo95t1VrREcu{1$+6P?@3@{c0!4>1za=@I*0cMV?H;HJr7WhNwj&
zhp3($q$!Fz8RK|tq_m2xX+{i_@^D+;>=agC!kq~+Jf|OTuDL1YbJ#%8DK$kbu7T0#
zN%TkO9_{Sq_9$?2<bR3>1<hK|oTgV@egglNN|o~PJqi$iARr{L|F5;rDq`Yf<Y;04
z=eps4hLU4Ljv+Ba5E(hqRZ9aWjLA|4&b&?%l$_1WbS2uQ(3)fYx0!$uVdne4%LH^c
zRnnBc30yU%H`{*VGMir2>-K#ItNEb`qYNhxQkvP+Qo;t1J&~BT93P1o&^mM$riiz>
z8HJus-0#AF*h*7r2SC=HiTaeh%f)`nG<fTNhZ|KG8?j+VJG~l&6k5tTWK}tUtSp8*
z`4yD>nwif|`4OB}q2!Hmf!74m_7!VkFc#-9D>GcJ(#tajmLncC>4QZGNieDCsShC{
z;Ha3{lSFPkej*M{<-0@d<P|66H)swhK)8~GgRPQ(1_J}H1@(DR%?Kla%rz#&j&`hm
zpf(bH&gwK`sOya1lrm<;Xk)Z`HdHm52PY1n*fItSg@8m)v9)~P1^;1TJJ|AzFB;xD
zew(w(vLw>WC_96@j0%yni8VNevJDPDJ#NWlM(Ii>Uk4W5x>&(vM9<9OJV%Da2Jt{G
ze?EeL_hoE3O0VtYX>As&LK&FpRj=5*7<ex1<YqQIXP)(5gszQ`G<fOo{7PayN!s}0
zl<Zb7GFQ+F*g=!45}VoNWE5M_6lf+ab;z=3#1t7bl}O8<xIQ)ijaPKfS&MN9=Ql)F
z-8*RghDgq29xJJgVr$qDqqsb)-x4|a8E#E~aOOGv<nYC9o+d~GMy=Ekbh`suRwUk|
zt-ape%P*N}?#J(qj}k9dFIH~U*7o+h9fVAXZu+EuM<j8^UlR%QoAx{Eoamk1owFuu
zVL+IWz-D{|$TxJVW(2PhY4590B4V`=NJm2^A#Sczk#NxiCRy)N{pTIhpUg_|tmD#u
zCs<SzXl8K~Ji?2%Pi=voA>K^6Sfw{<hsh<eQH|_5&=q4H6t~i3pZw;%+=WWtL8J3S
zG-DGY%(sbIbY@_U)yI<DU#!!Y-TLU0WN6jAKF`h&emer^S$e$i-+bQy@LwivtN%?&
zcIe+USy2@sI!QS(hJV}*@h`jC7`U2$*#48w#DCw}&e4qC(!kY#&dtQo$?msn^PfD=
z^lv>c_1jx@6GP?S-~MTm{_b@G|IO>{?QH1n9qsH*9GxvpoRnSZrDSO(WfdjLRP1Rb
zWTqrkuVrbaCzTnOSms#{4ymQ-sHY~T>)94qz#ZlzZlz&)m96h0<{s)$#!*~<#+4Jo
z?-J^jrQKUmBBYq-Q4*y6=5z^5uNMmROVEB7{V)vxyV3d0cbfjD{o|2v{<kA>x3Rv!
zwXnnGcm(*p|0tdD`K})lpLGc_WUR?ni_1XFfop}BLj_|Q5`P>S0vb;;-hS-6Ek2do
ziYRHjk@H!w%kzvs>K5PBy>8=wWhC8_L+j3#uCX5{1d`&xs?mw_;pAh|h39?5>udTW
za}!w|#}7X=A}gm_%!;ZXHt6!|s`AY#;s%`?H-_R^px&+dGTpjH5|qecCtgt|NzwW`
z84Lq~DaWGiNnmmY)(S2`z}K|EmvK0FCUT1jQ<_eX0yH1mh@!)NX2BhQ!z(7!ogL86
zyZ1$-3o0IHqk<)Ut(Gae+js;daE4%4>miR3(E2m9K@mn;fhol~Ob438S3UKMJYpS;
z1yU+jXiVN6oaS=Fz&8KG3`D+ZI89?)6BXAcLJ8bmm^$IO7p#}0?>DlT=2#{Q{8z@k
zAjFYyoA%yPAQn44EMU8TJ=-}MGZeU33$S(@PSj-3k)!VKQ9_`?vS#_b`^HtFZ_#TY
zz<`=O$6x4ZQ*353Yq=gjaA~2bBg!P^f_G?1Yj{OC-vVRt`K*u?x9h<oTBPX{SWb^g
zV62ux686d74<mT2x^sN%r@9&y9qwQ1@p{#ZEGEKYL&U$Kxa;G866#no_AyTKKDATk
zFz?^>rDv{|a3%{c6-(3*24+Q3Fbp$L9I==AQ4>!tD6)SO2ymJsog}`lSV1uC$kabN
z#bfJp;x**7Hjwb{8xK9I@flOojHBLA+bxS^sr^i^EA?07^h;9_#nv*TiotP*kD+@^
z)f(cdCpS9tnl8bADD9J}s1+|GmVGQ&j!-<zN3_kd1&B3La>)U&iuQp_mupLWK=eCm
z>9g`N&IcCLRhVZq$?Kqm=2em#wdQulr0YyaxiNL@<S<wCPJz;SHTk(9$J^guzCIjI
zUYKm<4#Z=cjCHZ_1+|av6CCx;WM{|*hmOEOx)<u4C?*hpPRgh>pd#kH552^VHP807
z$i>FbsuXz&olg|<Ex@L^c^r1G%_kG$q{k$#wI+ia1M^@av(<$OYob!XvYr5cy!wJ4
zeQ0s<Ud9OJ55$y5%;erLoSGBw21s(F<Rx&so<5bjEcKRGcR@SqiNgBdIMJkwZEUq!
zZgiC;@4w`Kn`huoaak-F9yCoQ-_ojB?$+r`sv}eA#_J{Cg}XN_nH=nx#KeIv3c_U6
z=6p3?3lK}vN+_<m7Ie_~*$zqi@G1@?B)OJS5m;{0O$MHa;+C?u$emED!76niz`faI
z!h~vCKuysj?>s+9KmrzibZ6m%ZU`I70y%O%sta^~`><rm`(6&I`=+$VI#_fqgCn*w
z@;{Qy`&uABTB!wn_dOA}g@`;S9kv3Y!p6i5IY2&<qz1tYXG_2wx|qEGxLE)BtIeS9
z_q}7|b|<}8`qrqnXeEUFB?QG^Q+5u(nKWq}-;Hf^qm6Cj4K}uI+vXSBPTttIZQHgs
z+&DRZqwcQ0yQ`X+nyH$enx5+C>EF}c&wuiXezC|mzKA<#v12n1Xc$ULj|T@zH8tLz
zG_7yJ5|D3}>42r+ecJRUr&fnX)+TIAuP>1GDy~tMOhm5~SZF`CzbeCUVrzq&Q1MiJ
zy=)k>ivqfQ5j?&9>H_f1TJWWglR0SVrWpQzBJzejT)76q0p#x4(4MzG=3LqFqa%uH
z2RQ}{K=)LliPtCHmO}tU^1lU}q}-LddprJSGM{l?KEB?{+O8nt8!fgz)jWPbe9I!f
zepqr@ZMorv5EED!L?*6$cIXiNjJV1CG4Gu?9c$BqZy#`m<8tY|uBf1MOfhVxyKMY_
z7I}m^e#fx{`ry}U^fsSjED`{&#us!D3n;+tH<`oY%gej6VIVY+KeYqiL~695h`(eH
zYKYlkf>6WHWOWTw1v(~{!8&RJDu+<dxDq9r3+DK(xAuCqV?nvUNtdtFt`hm2rS?^e
z&fQ}Bfp9O6E2sub?r3+3YN;ep92%y7B6(@=Ygi!#+u))W9f%fGRhR6(go85lG+Xf@
z<?IA|#zg8xyoYj>;eJ&C`Yx{tzc<wQNYAOfczL4ZXgYJ+WmI#Q7#CB<Sgo_Zj`+tD
z;y8^<;3<&gD1`wLx+{9*WptTIxWz%dQM2&&HUwZ-V`cL3yJcIZBH3QAa{J?djKYv*
zQsS?d`A|zM7yH+Uy$IuS&XDmlarxwVgE7Ns-Ib*!kYiM<e#o&#Hv}acAH4RHL<GkZ
z5^TkiMSGpn5bcwO1x~|1B7UJ|ZxwMfWWaTT#i6!ekv1Dw*4YGCg?M8gVwLnUfMlwu
zTaxlX4;Go=Bh%W5jv}0h^Vw8?mtJlboruM+bgG7tpTBQ2oKFS(TxE$%9?JMG$-l_T
zbQ5p4^aXF=r7`BWTuF(iC<(QnrCJ&8=aQzByAPQF2Rx`G48ZAfLXp&R4%Is~pSc&S
z1ygvzUBCDoXe)vi|LsV~foE5WK8t`0t?$@;m^N@)h1%INsk5R^KA16owjP0BF4afL
z_)@H{Km2oe$lM}Nnc6c^^SLV{65`6?^K}}lJtqI;q+x(Uc46Fy(R|I%5^r)Z&S20k
zr<#k~Wcyd!_w&bwJxTty;)x0Va^m8$BSd=ox}O!Zhw?<6+9!dtGnZ0ZC0^f%P#YFv
z7O<>&tKY_z1lF3-7kuS^{X&Anb%atS)Br4kr(TQ0r6tN}896!viwL=Nf_#p(G4UqB
zWw>6ykoa@?0LqNi0RpA7O%u`&N{;x8-99+CI8CQyJNcor>RpX|T0B|{OY9|ptsK61
zFKt;dNFH2#D*g8a*%&LLW7r7wWuJzjC5P#$a~he)imxq0{x@HLx1SfZ319rWtvu5s
z1?JAU{j+yGM^nL!o`_X)36_Uv_PCUk%@=J0TP1Z_%Gf{|ZlWGzy(IS#6=)APO3;6?
zu{`mK)+>RpR?652U+VpumX3ZgjXa+I`14Hd=V=3;GSrtZ_3XdLnb`jsT^y}USS)@A
z1xbFd*q@KI`gZ1j|A4>$l_me>0sn@3vXhdu5`P80Ka<}6p#s7v1$bQq8r<X`w@NtL
ziby!LOl<&KBplqNd+V4&L^$)^ofZ7U#6zT%d+XdkL14J!oK)REv0t7Z^5#H*ln&jW
z(eGwV%hCLgZ)yFz=tuRx*Tc=)YEX64c7qMh*Tw$>ajg@7j@pD;oY@Kr4|8+r3#EhF
zj8VTIFD28ZBC%vJ={DKtyV>*pThfL??#eEK%t1`S6Hz>-uNw{NYCx?}`Q4(uQv-2s
zi_C9h)2hB(IzinPe5AJ91BJ7XJ@|qxb;spVj)&NV;Ohb5YNJmO#MTZT@5AZYqGF9W
zF+83Pd160*UE0kaxAtYCqoYr^&&zSqXw)bYou%y6I=ul<;hE~P-E*0ozO{kBMjS)M
zGS~)Y_KA6_XMk&RS|?}+x>0vwro&FcmiA=KxmpUJLy9&|$~r~R7BLkQGCvL1;xxdR
zWsD-Z3)}=&C_+#DW`)*g$cJaAXGdijH-9C^iF@{ce{d*{OEAu^>ZI`3;4!CeFe_4@
zMrW6+eI1=#96U9>y?KeRaMlnHEhYC9fJw%cU-Fl=VHfDA#KD~>DrZ%}PJ_EW?{(fW
z)Ns_8(Izwc=|D-{5oI023*?s-iX4Q(Raq^WdGx?JGjB;l0Z#xb6OZ=<N$=sl!_Gd=
zX_ZTV9VF>jMR-oX(7}yHji5UweU;=;l;C!NBn5{oLV{7~Q<88Ik^mVp15lCmYJkLO
zsZbUm6E)-NhkaU%;z@Auvh49U#t65=r)Jd%q_XtPkt;CV`GH`cvC5s$CJ0jmFep4#
z#7*Ug2JJqbxmiZJ$_y20+;%yU$R{$j*`M%#=ze~zR|^&Tk<It%5P22e;Y}=$S6iy;
z#{Ucjq!_ei@>D$Ai{n$&HfghT=F?6Cl9m#a2m3~X{Hv=OrLI7`1mR$Rb*KIsMjjC;
zjcT7M(xam!E2oVzBWYmH>nXVn(d_3S#ZJIrl`SC&Ytk}3oSRE<{dporY1`X&l5MSj
zF2y}`_hh;4yyGV&>us#j?QT%(NH9Xl15$nVx@u0N`BL#Ve^8}R8Z@IXC$ya*!X=V~
zYeHo1!Ddp)DZ|h@l=yv~Zf{h2{INUv*>fE>H`vUSGToCUckPo*P>NF#|Ln4QN*>oc
zpVQ?gR?>uaW!VS_&9rr)Iq-NWvzO|Bo!YI}H9MN(;kE-J@Y1;JDLGe0kv-Dk`5M-=
zkl0xk=CP4vhZe7tdY5GQ9a3yPch=+i_Lte_k*d?){e9DCZHlYd`m&m)zGcyMFWM_F
zZ7L0ppxm@0e-tjnke*Q;!CcY<Xu4WRez4b`LLx^@1nNdW4<{UuOk=b-REsNrfK@PY
zC@gan#?=IGXVOY%`9b_`3=mZRt-d5@N|3<^=_^X`&#yQU$Qqe^fjC?x4wOtgvUu&{
zy<;f0P1g_>aqj`A%j>&7t6!4)2o@r@`q~(4Achr=R=&);-<fNa_Y%7fWZKgQ4OCi0
zu8NsTA!J(;pq{$J;l3!8q)!Wfxu%_YskFfU!Yp$5@xd9r_4x!Kybb1fu$e&!Kz3dN
zK=4ie)@FKRz+l*MM*}O^oGjf`)!FO_Oly=EmrCm|AG)_wrgaVI-23pJzXAO@l^}yO
zf3*$y5mk8kxpJWUC*Nf)22X7S_T|en!teQhus`m9bXLFP=28E8$Dbm9S>3-!vcKcj
zY5sEoK?6r82Yo}Qzem5MjDP!m&|k8DF+luL&{`?O!(rAifZz7u!D>~&VJQapj2Bje
zvrxoQzpqlgf$Mtx!hAa6$oE^8CwxbpdZNDX9bc8BiH1{L7yos!>i9fmEX()l^-dr_
zXrr3{by&zuI463aC^27u*8T<EnK+0bQ)!_TNoGHC4M7RP7jUik){B!l80!Il&QUxi
z=9IaNylgKh762S_!WT=ObHL95Qo85x@6>iQT&#p1-xL-cj(-h4OH6WZneYq%`ZA~W
z7MvR!p6zS_;%>AZbw*YqM+!hJ^g^wa#yH1qf9i8|q+R?NN+Do>H<k}!fuJ3Z2f)SI
znN!8F1Y)?FLLdGrI1CN*q9f@r&#nzq%yE*oDQ-0__4Y5Nl!F_hAnT1--*^PKmULX+
zlEfPC>;U|<+tE0T*WX@h{bt1(PMtEX?VNSdkVJxI6$xY`Yvtsh!UQqnqEi532~o2D
zOxw#VoMHP61ZuW_5=B4{H)wA=)a?sRwbpadVYfsgfVS5T3s7@m;jmF=_?uj?FqDxF
z+YJh!>~npGliDluw@hV<?PJkrw8J+CWp3%6X;XHCu-RK`W6t1SRWq1HgDvYWxh*VA
z0#=pqrM1dliXT$f72QTFmY6dZ$y4&sX~zIN(dgmYd3Pm$uSTD8U}K%UOV0$^sH8OQ
zG@6YEA--BfY445%f5fymb-EO+B~4F7udo3m-5ldaD!Yj#X`dAiu*&eRS}eT<yoIxn
z_KGOI+NgPXKWASH)QsQ7h3<4YmJ<LJ51d!Bp(5BEBm(KERyfOt?4;hgP=%_3ty;v1
zm9M@u@uIkY(lw$p9fH{JrH}wzK%>85TOuUoaJ0_OWu~Aw3oV|fMuhVFEE8zOlxxo@
zG;INOC%B2*TK>OK(5FFf-g_q$g{I}AFb}|txa9i2;=!00DC%X>;jPWeGrWT*mE=Cy
z+=Ejk%a>w!tT5dhD@|79y~M3m5#N^}v)-)^A1{GflDFyTf8+L}UJw~@_d_mZ%_f>f
zH2I=)XMeoBplQ_UJ#f0uGm1QxWDCiw<p*J?5nWODJ>wvE2!hz2UUibRB9cB6n0pQ2
zd%+l(lXQZe;te62k>U%c5){Q^?nTVigRUXoTX1o8=SO{imygv@jm@<gFk3t!nTZG#
ztUJl8@}~CrfAd16r{=&7eb7G|CdBWO%>QV*e>GfHb2p_$Y@eS-@!V-zP+%y~u^cc4
zOzIG5BA|JUNYZfr@hyIhzf6we;iQhDU9Vz=EzHliCZo#Kw9Z5^Q-*LD=Gp`XRnBc1
zn_RXR*ZAHSiw|eJw$nz9P=W^!(j2dNkGZ$qyB{^De_H9i?hh2d$PDqnUGJS4uq{8$
z23b059S=V|)kS(0V(AVp!^C}P9v!bQ8^1x|v%l!?Xt=kE2iYXIYI?1x1laDV$h&7C
zHlMH1#kfAnN83u&=YzTK(V1T@*~diNJ~LuIp0!Meyc!>Z5`W~HZBkA)dp|`ZZZF>O
z60*J2e||xHzF{Dky(u9S^y&udcavgy>j@b)eh!V+=DSD+k{4hn9f=eE3OzuSye8ox
zv&cz4!p5JrU|8F;A2$z68!bp$kVC5XWKDElk+G$~UaxU8Ea|_xY|Jdgd9&e|HLtEQ
zIEsa^?hG~<mLRJ<`Y|xez;2}|yAri_gTQ^-e{`?DE1f)V%$bp|F9|3y%x_(VE8H-n
z5gxT0v#)5uJ%f2vk5ifmufS{Qqg*D??AbgzP+m!QP(*m3<p}6%z*|g|Rhq}YY`#d8
ze7nRcf>+}e&#>5REOq0-!R$`}+}Mo=k@W?y(U=T*0?Iwv9KypRl129AT{*GKOFIPu
zf13xRkyOpaSZth&UOZ`v*Du1<!^di{+k2eyZnLrP+q`EB)QDIjZYAsGgeG~#ml^x7
zep8W6!Pzyb_n>Vi>n7UhlI~BWTZXgMF#f&(5vey+9Nnpv#&aNHE1mHzhl!y{UelMj
zX!pr0mu@17=v(zn8Stg1E|D6$IOkXLf3aKTs{I5o+DxH<g_^tghYlxJ6H1-vk(u_O
zFhU55Ay0O^>~39uphj1sc&Q<wqf9@e__7S%L=4G5Yf(Z7m&~L~1wc0WI7$<q+3_O5
z4i(f)r?HTDJH5p6x5Faclj!vRjCndfnyHsqqLt~M3)zS2+WpReFjmq21?aEBf2tE@
zrIWi=gVBR?ia|;n=$BC$r##%3NCsjDY5?Pv$dF1ko%l$zI_~0BhG2D>A_gT#u};?W
z!KQdKhfB9CMvBC{GxmOc>a@&myImppM)y)KjvR}$*X-Wk_RBFx&m3bM9^_m4nOlCO
zC$s=kvK;zUES2&a_r4iN<qZqKf4xJf<ShztPt7xYn%SK^)%qXTZ1*r_0{7iP`FmyI
zJNz)=GXt5`H@{=jf*$8h_Dl<3kad&*EjHNwv9eI@2D!hAhXtX}-qiW4UYGeN`f;&!
z+kHo`2o1(|cbM%lwi~EehU<uCPj!LV8u0Va*{3DI3CULg?ELs`q-Pz(e_Awq3<&)G
ziWgddr}8M^77vbn0pa8C3MXuz?QfE4oeNIQf|s(r6)Hk5%$_l}2S7>HCrusxGALWT
zYAe$AiZ>qFppbJ32Q5~8_EhMvyQ`fICx!}ghdElNd;S#VzrE)Q;S<AeW@bf{D1IcW
zpwiO_YR?_3r<}X1Pu;c}f6fBlq(#K{kspkDYt_=rs4nRN$eXb^gf(=tb<IgCckhvc
z=wl*;zE{&v2*b9c)UUS(QQ?WN$+u@m3KMN<HOTxz?C)Q)j>#~umuD}cX_&j{0`lHu
zXm1pFd7mNSt9E9pm^<x^I$9)Gk^-y98>QdQzhJ$-X+pCkt{Sukf89YeE@}3yjS?r`
zVV)tnfrv>(5&jL@m+cx8y1!fEZNZ5fAcTc2@xvCyl1Goc!Y#Vcyy_#k``m51=k=+l
z$05^vhi0_VJtSh`C^XHk@a%Aa(%Tl%hz@Gsd|s3>VYbK7{Pvw1^?Sus#la~NSLOF(
zIeFEV!p3JC8)bKTe@TUi>0^A+z^%qQW9Q>=IurK~&&5;<=hLc9^P$Uvg=3e}0<x^h
ztnzx8aP9W-y)h{8BI)2fpd7K9%&XRcc2&W#LTP3a>$5Cb+MP)Ky^<71@{k#-lebCT
zJWk@ew3ajTFe&-gR#6cOGK5S>n$uw>DZ{wEup<LvO*D^>e`09aT|BEx3K^(>3+s#s
zdPhTv5&ub7`R-dfKrUMoKY7V#@AXceFt{Oq7nRcV8#%M$q>ZK1On3!Z5)NJIsOzA)
zEx*tY{LzLB<t|}j{&R*cY%DKwf-P-q--xKfGKnZmE9ktYH$gQt=_-?3=Dqj|J<Ej<
zLGe2JL(vO=f45@Zp3E#H-!#pOxBS|`wfV=q`*)MhM-HDb)|>UY5GKyi=YzPuyq9_=
zURkomJ3R&7YM3&9vB{Lt)~PPE^bNulm+Q$qohWZ@J9d}=<1KPIj)1%!!x_`QX4ns8
zw*YVw3g|2US{wGFNWHTfg|={O@PmZrY$}-{w2EFUe=R>ldqyr!i-JW1*5Te`S$%60
zNlfrJNE1lH;RR=WPeK4?4o^G7Wm}s!VrAL7>L<&?dFtp-y=!*K2XKqwQVZkMdgN#g
zPVUL6i-kg|MZTj3F|p?8JK*U+;jWNYqG;}>*Z|+yW<FBI8uigsE0-ZH5Y4t7_0Wrg
zDuXYae+hA9GV;Z{ACGbsK~Z`_3Dr}si>?J0z1?2Qw4ZLmf~tZBPoyyTQtg{;Ju6Qj
zr?g0t$h5(gOQH$}Z(ytRmc&mwrOUUc%B<9-(gyr>hHwG@3rDT@uB>bJ(}!28hvJa1
zI~uFO6glY#Tsv+?_S-w{m-Sk}gU;Z%MjbdQe}yx)Nzd-G7Ycd&Dc9B*4x^tU!w+dq
zvv>59{$tA4q<r0;;}TEmDicq#&+0z-7Kr8@u8pX3^yYDS;Z~uFevhk#VQsphV$LPO
z7~O#B8C=!)Pstng!xT>@zS!a<hEW&UA%62`hQa~<J2|f}QBIR$spQ!U`imcs+4as=
ze+)1xGn$`=7&`YR`A(3aLTqZ8(AX}+{D}PR?yvSzTms~6<<TrJN;L50dSxW=LR-X(
z#ew2Kz-^2?QS%Q?f@f$szOKtfXhJ_WW$tKXqH4|W@cKCf<iv@dDGx*vd1u-N+(+6M
zP-PZTd)=XTaiL3y7?T&wdVurt=D@c4f900d2>WYQypTzKlBu7-%1!)|k=PUwa5Y50
zt{&<P@*#xpASB=Ynj8k{D8)fC9HfATC%`J*LSg7HR@I0N+r+@iQwN+GY0#~yx)|6j
zaR+H6;qXBWIOot=Mn=P22y?zQgo(-18HPHNu0lXmd?$&_5Hp{4<UoH#FABfMf54Vf
zF7P2?L-rHnb6^tC*^`*9DT*F-gzV^dUOg~}vRe125-~6=bVUP#D0viPdZ{&;Valw9
z`Hf_D;FHbKn<P_?Dl*0Qt78OS*L$bYbP46_8algYEgr!`^kx`c(=vUqNuF^FKUWFi
zlM?TZiaz5Eq`{|q)TvwXF4(zze^(7UMsf3olq)BZw{YvcjRNcz5RV+vCmp^ybcLmh
z>O1p~72pn*R;UX`RTS@g1v`P~tL=#+PUEtZ;*b8U^(LIZ`Fi>uTkwI(`h+<?)a}@p
z%SaA)@)!;iZDSH%Y#+1|p+wZobqTB>k676GbXY($Ie+;U%oLHLsL`Q;f0oG{Fh8{4
zL!V#K`&&Bw@S})2M#O^PcU;|U%#qUsKePEekkxp?Kc4z4A^&(F@*5E^lfJ8^(TM}!
z8wI)H;R%a-ffnGSw`g&rKDY3=kx<6_!mEb40&mUn^VY8n)5D|H<Hg{6iBs~Sit%`o
z#i6oVS;fwSqWIqDpD4N3e<PlH3g*j~OpM>7Waj@u$qxE<cE(13lHmrJ>D$;CTm4P4
z^)GR56D`=99ddyd7&Qe5I8JPNfP*PS$T-}$iIKpBB3LkqIq`rK*<H-1z6fR=2tqvX
z2QkiUX(pl-6+5o>)q39J*D2SjRo(7xZ%BrKLyj{>jVP{2GKOgAe_HAA%hHu>@l*+c
zzJ`_Th|AwrOh_k&hzw=098r$QXc&I10WGk2reigD6}HR5ff?bxrqp*o@w;}g72%TR
z+ko8kSZyA**O%-1p|q)-Q*zB^xL)t~q~n#=tQo}_!ODt?cid%#u<PBCoFQ$KxfSV4
z{=_}onKu>I7Q-9ze@AsqhNbECmZiUeOur{38fMS(0=(idX{t&QrWqS-vT>q)`dpnf
z$=^8p8Socpr2{$Qb#C1kIpnGgpr|%A!#lysW0xHzb>mI!lN2nV(WN;ia;|<lT9(=V
zMwDKUA6yjwnNU;cibLNrDyc>~*w!h(1M%C#uTGPancJdCf9;65GLCvDF}0>bMp7rw
zth<dWSJnE%lC_(3jcZGt%a^J&jI90a<Dv|Uq!EsmoaqFPO^$Dd<2;QlT@?{0O3zJ3
zK}gt9CkghD@F>YfJOag$!zXdG)K&8*Mkig$(8h3~HIYz?1Li*lio(h5#zmm=f@k{~
zo^<a9<a}9ie{okys^oQXHmQj<R-w3hXKto3{bW2cA95c>$_3H<32XwUqFN#-(nmBz
zgM0*d-qC3`Ke6Ltj6`A!I+MNp1P6XNvxeDxr#^Mh2e0(=v>;Im_N-czDUYu}c!5cN
zZ8pIsNwzmgqZp5;>KCFVv+ZTtuP2?$K|1XgW(kP!e-j1!qDb^4{3S;KlVI*M<^(U_
zmYo&{Wexm-!aFU4r&ot~C|u4|TWR&~Rz5A2fxmY2910yy^>*KePLkBS6-<I7-$@;q
zG$^E-jJ&2x>huk%?XoxxrG}p<i-b~!|C@GR_%5Ep1*n0%AUeFfb<nNMvr=FK71C)c
zdT3fMe^Le?z_CXTlR?Q-IV?EXAmi*h{9+Rc;225-liX1x(wda)=1%L$ZjKF;UUSS2
z<kd5~$1WiWgOcbi2UayeYMVa}Pm^0@bZ+JD3M3vzjJYM=a$4|8Ji}Vh1@N4K7B;e!
z14-k-5HA#!5utv@qMa>#<i{RK{cwbfD<T!)f3p{}EO@$k|MO}!Zm0OAKgGE)P`@|o
zh4Y^+*ziy3sJ}O~Mg6<wgl!xZj2&&QT>hq8D=otb10sl2@e8NA2N8=Zox>j(mz(zu
zD!le0I`E=5@*;A09nQ-y2E`M7A^55);H=Dt$JX@=fCbzF#5rK3q5f1IwXM?_FB8<f
ze<5Z4!C>KY7Ch$0XIg=sc%fLeFov&g2%06;_JUH;1EcU_E*-1+L(L>`!*8Z`Rq)8p
zbrx7pr7xBwy5{ywel+i@gOeJl^;@k<_RNR35sD$biA~n$kSbIV$ZZ}9FcjsEsoqPq
z1$-Z*?9Zv0QAs>oEq|=;uiu^eVEo+=fAaV70>GcINg4m{2>-Os?<080roBq8b`M>U
zw#B+I;-)r87-r}@IBMCGS<`wg98JBEDa=dteXpd~HRO}Q9wJjVHk96PU@rB{$C;el
zt=`=HpI)C|cPNiwTY|(fIX4^`e>2B?yy@u$KpI0b!*O;}D!FF^mt^LAYS6EKf3tmb
zS0$TeTNXrvrE|UxcI950Y48ZtgB6159FcpZ_bazzFv<{*VUBG4?Z7fHi%wSex6M?V
z{Yz4q{U`=>QGON^X?HjsNr`N>eK|^*vyErR<Q%z1nK5OQpYk2*-PU^kq&?>kD)|l-
zO=j*(=W*r4KTKj_f@gg@u{V+)f04HriQ~q4X->0@VnyFt83vPs9hTu!HMHa8GbxB(
z%e8F3^Fqe(v|RHZ$TKJm3N8ZRWAG>3OGv)4(an4V%&K6A)Dd=E*xdYJp2)=4Q!jf6
zbT5EQ7=|CSPP-V#44V^^W>T8chU%Z2v6D3{O$q+l0Fykq#9>Ehh74K0e`}L({1Fpr
ztMb$68*$BaBW0w?1)+jT`{haEkVHqKOnw|tprsJeau=ai@!=CPTadr#bnZaFy*FG0
zfVx?T{Gz4xy<BXL_;g93(i@`OXK;l4-0?S+KrkQu#HBF6238e_3ezlB=YET*>GvfN
z^C4>8*MJFjBYp&t7jI&Pe-8=;0y3@QJLvfOhHU`|cG_DE8_jk64UyR+qlFmnk3Wl3
z7{(nKqkw$*f(7<_4Nmy~YH+H5yFt~#+{swU%)wayuSvj#Du2<#yQHf@!U#hWtW=N;
zlm@{9lTb!tEn!6w7z_`sq|^6Hs>!f%0e>~OEPt=t)?NGg%inZ*e>U`z(>mv6NAWYF
z2{F5=m=G~r@iI&L$G4-B21IVh<EgCI_D6PCljF0f>Td9vfNF`IK?KaRngmJ2_8M4y
z>~?L6fhhy0JHEaoUahl3X+pv)`?v?4tqVsW;j1xE-z%t>jh`f>Bts~m5UWogJH}zs
zkWOhA$~L+!*C3T$e;%7;BRI(b&9DRen1IE`cj7nbffg1@K#KlIC@e*eLI1m`Q-HcQ
zW7KJ~-%F@|G<Zzu@FEFIirrCwyeSh$%}k57KpbloS%);KlUbXIGYr-}ZC@|3)H@^?
zniDojWI(hT*Lfp(NLs5deso+Bv4Qa7%Gbq(Cyq**om%K?f4GTO0tVKIOG5TEE@A=b
zb1vp~0}JBb5sUN9kiE&{*p^r+&ElnD5_BkE^`LfG3sHuRW<##Ay=0RUBh@9_(%CQq
z)~f+=P1=3?@DLU5kEZfu2`_~8{QQXtx7ktYlb}JN==6>X@l(SxJ`A{X3}$I=o7y-U
zq{RR@hn=w!e~QUDvxy%yN^Bs)Y|?k{!PcUyGEt64qodCFkn%ervVvbKVF>(WMTPvq
zH3gj6f_%mo?rUQ!2SqbWn0=1y7fN<GiqNF?!BVp2u1T{Mu356>Yr?p<gH^DnsW`%p
z!IX~lWqa>93U|OeN_JSLM%=`E$K6DR%3*Z+S6fA3e@7Lrxwho4zi%mAvu(xQR0TX<
zcLgBMP~{%|Vxf9MIt~>BKju6U<0#)TBseF3QW`Ra;X4kbzb^Ef`cxGJ*;ti(3680y
zxReu7X`EhqP|{a5NorU~mB{%jW~r$`gH^<%G|qt8k_n)USSu12oQUG(^Cevl&#_`9
zFy)$Le}5rvUEjFs7D?K2*HGgas<;kyL~?;uJ6!kX-ZvQkQR=Y&0~9(Ib>d8!{MmgB
z6Do`KQ~OS4uu3$aChoe*)&ir(RbF+G7Vogo8X>ndjBc=M5cFUJgQr`8Rx<^mGNg`S
z60gXXk>SIu2|NGVh-ZjCg?n{o3cIOs*@VqHf08|(wzC9Sd`^uO9>-}NZzv*T`O|8U
z-r70f5Cd?=GGW+kJbUrNeE(}zWuvLYCzWe-T$xq+0qpDR8-NIBs6l+v!3;qW>lq_%
z7LC72DWeN0$1(9(V#i`aJ`{#d>v&&wq@ZR;>Mjyf9;U-4{SCZrKFNrUBSW8hy5^4G
zf2bruL_${Xkdq2#;rZ*#px#NEq*;jht>5}>p0VChj^8tQIP1MtX`o*tl6<c(lHdBI
zFZMktRW7}sN4oX5(hM5XvvJUely6{k05}${04IMXVw_U#zT&|gIpU8<vORh=u{Nso
zd@`s!Y&%i}qWE!)h9Z1jl5bZ}*EBF)e}cO^#%RhT;(yXki6_+(Py7x<GQjqh1i>VN
zs;3}K6$At!o|)FNnC8`)`seMo!v@I(YJ~S)-fspiN4gZJWS+3gzadovMc>dH_XyRf
zKf-dKFw+OOXNW(dUFNKbHtFV^6FNc;1mi;nx|!3Oa<LHeqHgo7<~aF<bt!r2e~qj-
zC=3lb(`J9hYe;BcE1YE>GS`=I#IO-u(@@d(If9RadBv3dkWkjn8E^<oM;EV<Dvxh5
zJvv&%z85~C*QCuY-i5IM%LI@>KXTc4%v<8LW(;X=zMa^09tEI2i#q8krzf!`B2%-=
zk!}sZtQA0nNl2sA%2Nr3km}bffBEGr5TPg_XD1tFCWhN<IB-USQ8c2fNz=H-Zs(ha
zEq#-sv39AMnlLQI5m`ZspM6H$SQuMzz@J<`P3l}M6`}Gpu+}WHl8K|%(Q+;ozIyc^
zBOxP`=LT&Cz<Osky(*@;L-l7(S&;z+HDFSdzQ!p1W-$ubpb1nho4Po5f1rRWe5|+8
zDHx39K|6u?&8jW)Wjp#|p?zddGUon!=wI}WBJZtuXTiUGQGxrtE`<L7=|cX}TXb?m
zyD2R$9&e-_OiJkpp~MS7jYF9MFhHP6tWbm~{A<4ZeMJvGAj3|b7*O{!6DeO@S}L@t
z46tncQMpjb<Zl4ZZddK8f8DmSbk*eYsi}F$f851xyVcPFz5Da=-RGd|^~zzY)wKIK
zYTEaubNK6y(~TiLUQghLS4;+AgXbv!=oN<VDo~4Of?lk}Js^YJ+YSlwuB^DleJx^o
zNB#<5@mie_ZO`%TmWQ3*?v9w9p7N;<aqPMV(zj<?)$LjtT=z~8f4r+|2Un+LfZdw`
zVtX%*@Mw4a3Bk}aCF2q8Ee`SfUX1$_`No@4@1y&X>Bd`ThVGLdn@>-MZ|P1o&yyvg
z)R3y%5j)SFCgDf4YW2`I^%D`|r(iGtiynl}K<wv1FF*AYrp~h}_~%hztJK-{^D`pB
z8{yS^LWb|n`S8YDe+J?!;nq9!Bj4eceej#-8T1ZBEAmE*S0AlIOUgNF_%%hJ<Ny>Q
zyL-5tca12M#sPDbmxX+fV}A>!lCXR>1xCMn%K+qYxB>y)T_`diqe9|qu0rH(C`=9(
z?T{UFa)v$6@ne|cfSZWabuR{E++)sI=e*meX-nxrt@wr#e`Vepq`Z87s76jIjYVov
z44V9L;H3dfb?TUOwyYFt@#}ySV_*z(LIyLMeGwvEZw${KO-?GA3G*3BOzJ+eV=H$|
zMt$1EGl9IU6&fs0o_`K3Z=O7IgqIyH;itxpdW_n{^!NBWwRrO6@FSjDDVk%G--uO?
zdM6Fg*~_tQe_`1xr515)mK^G3kdLqHqk@Q+9Bo0_j~yHd*pKgO*&XUfNkHKAnb|Kl
z4(yqeG7xN7Y`9ua_lhzyzOidQ323%r?iGn4>x&4Z&6bD4q9Kb=s25vDi>x(U+&Itb
zX<1%ITlgb@HB#a&<-r35Xo?1rw8G4gfVu9HdYZX(e-(r0OBFWhQL*K}wFl_K>w7tp
zt|<@K<2D!XEFvFZtXiI(!rxeU;{hq)#dHM{o?i~~1Uz|AE&&uNmM&@-*oqA*VFP=@
zCWu052$Wc*nsK3z-}h)8GLsMPMM=1!r1WtXB?y3}9hXai80WA;{&uQae4>)!Ya~u@
zzn&~Sf23(APD3HM!k!c}qp6M!oME4P!CdAsXeA<Xivnc_0)cJD{yOP*O<?VP{%*t)
zRvB@e+`~e!S)^E3>AZGE1if<bFX^B+zifgOY4yyCc#)$lcHOiAq{z|qkyeP~#toCp
z1mOcLhKl}Q^I2E&MNpg=tcbUqf(*+W)kqtpe@Ql<BIo7T0fG=+44tte+~imYL&wO+
zRLsssa~fc-fC7M_N^BX8?7h`eUZwveQItEOIbzTfM4q4zJH+PA)i=f}52TGE1J)5&
z6AP&b6f#RS$>P-?9Kep$A+Na<w*p=ijS|UKTgZ4y(XIGp{Fp~N8R#~eI~woK(mNU)
zf3!Iyk*TLM*<V@+EUxda3^D<0;GblT(h5|xHv+FJ9!VXE(bPquEyO5Lo1gSzaYhF&
z=JrB@TLljBo8TU1Q!{DMES?72JB9GH!6bM#znQiP+2-a0mZ_O~$AB}V!fj0!-f348
zsiez|v`7-MRAus&<aN@Ly?m2je~}iye_MF|fEAWjc2#ET3c$kOIHN723OS*3Yi2LQ
z{s{33Ue!g)lMYhcQ<Fs~w-;+)!bKGABmHIV6kCE}*hPe2v>;U48tGlV`#~X@2Nu4q
z=oSp$!vu5)t3Nj?ZVBdDvnmn_%b;_BhUT%EAd2MfH6d2>&{8mZmLhQ(ZeSQpe^elc
zt{INB<c9K*ISdBBZ6rZL{1yri3x!fD>zz4~*B)Xg|5nuyZZ&vB>m(qg#aQgT)N|vW
zl%Sz$Tr&w4FBnprjQk3cEHWtLriHR~LbGC~PzE!*k$aad62`zJ(qQz*c7Qfl47HG^
zUUUSPu0K+8qF+?Cut=T`g}OZwfBS<`tk}AOGLxyxBYn<*F*>|fEwp4_oo_7OWyVcg
zQnH?LxNI?POy&(VWi<hfKC1YlgJ<1=GD6MF_#4j2?A~145S&&<_R&2VmS&Z;tf1)9
zv>p{c73(~($WD}Pf#AnLL*z5MN(N;!RCSmPE<B`A)T~($pgm<i2i)6Ue+E=cbE&fE
zAOLL>W(XJFYCH4fVj(XPNNvy_fbL|No0ySEj$%W!q&aN>v1(;%yeR*}Sw%F@{uDW#
zBgE?Gk_U(MNuhk3mbfv3D-A*rx51`=rNeim;x|z%<B(ab==u%`=B!U)PMY}v0T#YR
zH<|p-%|wkk!M6Dw8CL}!f5)yV;R*38C1#?u%OJZ@#*iy#r+K*n1d;nwh-r5-!oj|l
zA>>}hF|%D^*$TQ&yQYKIv<-R^ZA7OVd%RAkwb(iiQkN_!L&$B(y)*IMG)__;eFc%F
zN^k{BC#4KP++@*!73@fuCPHJLDoI{)7S#OA!7!f+iku@8E(LiFf6_v(=PNdOZi)G~
zgk@Z<BVo=I8afQ<aT(blW1B&uONWxTMiDVl;s*QzC9qgqLD<IZFOYePGGC(Dlh+Z~
zgc<36l!?9;=e&hs8`Z)W+;2LmaX;0K(R}H6(P*^|nkODzev5qS_ZglIstDJT&@>Xw
zL8e7I$_$kc98PC4f1jXH!rj>Tp|*Tf8VxmfwoFXVRfJO1qPNy;U?=+vP8(Z2O&M1~
z5g|CWUfuNtO=X|@Vg24ta;j3dnCwN3E1$NuqUI#p7Pus-o=rFDK;l#ZKNOI-v>eip
ze5>YRB4+|*=?s~i5H?7L64mS%GkG%3?B}GT35RIo@SbfMf3`PFCh>Lt*_xLEKeNgz
zE`k!bMFai^&aNRi5&(<Fwr!h}nb_>uwrzK^v2EMVCh6EtCY)%JiPN#o<zcI~Y7cw*
zhhP8p4qxxRU=#=%B_R~G<x`XvN_g`wk4RYaSn+5b??BLSQVKmms?c7n_LaOP*$QdY
zNmg4zIM<uIfA&=O1V^@<Ufa5TUaB(R<c&u@kDSWc0oBr+uYh`^2QI<Jw-m#2_dU8s
zIV=;sDCpE~UkT+4I4Uqs;~&D0Bub8Kb7p0evhqb)^JK}t=95^|2@##gw-Q=bY#d!M
z6iSXF8kTfu(=nYpKIaF^y~KTMx2y<yWm(NxYnRBOf2CB=FK1O<Qonul+7NJ^N@GMo
z4K?gM*G#FS7)@Z@1Smom@`t+>Yto}{>PhADxG=<<5UKa?Szw@CHpe5GBfX!{&*sUk
zBSkYNEfF5{d_hmd)%G?@+5IY^(2kII5TLvB!z~D_)cB4xuJIj8x$0W5r)V$m*)c4d
zo`KCFfA2@&7z*y6@cn<ZB-^fc#JFUU!%Tvxa}0apng%d))z>V7GEdu-%czJ@e@ceV
zt|O3~-R|(-Rl+-VNyBb3^r5rOv?(;mFXWrL+m3H%T&Qqv;mv?@H6jFePj(9hCV2)e
z{oGg&&Rm^Ek?o3~vfr1zkxEI6hZL^4#2=Efe}!F{F0c!!Yvl{;cx!CaLTdNSnp3UW
zRd?a9W2mrdKpFu?xS7$@nm4enKMrB()j0nE!<iazj5S6xM>KKL&p$<_!q*aCHgSsd
zagFheRd=O)AWb(RoF*l=hHCO1lf(Lj25#ob)7F(4e2S0IpJ$<>MN*3Tm4bTo?{aw-
ze~EKfExvNHtaOP`-k@Qs^<#;U-)|65$FNl42o+>|F9Bii23v^qe)P3E@)ohRyCAAP
zri=ksq!P5~(3s3UFs2ge2zV-qj<k`fVNi(aQv5b9)nV~g#-f<w2pvN%;J8Y9RioEI
z&*q72=FOgQy45{EjEW%Tur7wj!~daAe+zdty0K=@&lUQ~Nn><1ioq4zHtU(c@Wm=)
zHJ+t0*Oh=YpNDMPCL_lUS7x68cf8mbv!lu^bFJQt_U>3qa}(~XD9NGKU2BV3qX%(|
z@zavuP;>KV*5%HTl2%{0&tcU$ryS<C%IMY}87{Fa=G|^?nW-7NCH`+;u8J7{f0yt6
zqa6%q_Kr^L-#l-5q&6#KoMYcKo0S7(aM7dSHE%F3RY!&;+k8e$$|U5(akp_3Yu191
zHJb}_%Z{~2Azf8QX=lpo38s?7rF%tjx3ME9OqP~Z>r+E{Sbs~O@R0ZOVw5A;x=COr
zCYzIXg$o2WniT{Xk2aR-WB%5>e*t~3i=wXa5f`kEsl4XW6rAl6Wb(fWY1taBuV>cB
zxrt*+*h7ek{LPrm2ng$ln8bX2s2OJIXG-9#EId5=VGtJVS*J3mZjI+XG4mI<=hOy*
zsy!*`QzMdS)i3$yN+u&LcIG|!8Xu{inkdp5pZH&go+PP@)iaABOn)e7e{uhg<BaFx
z7)OxNXnx(0KsKZ^H?*D7kyY^?_}WafXZUE45|(|?k!dVRP$I-Xa8C%A9qTH2m(VHd
zmLiB^<o5W^d4*?>$QIiubhYN0mx|2!s3Ht94O0$8?0k5H1{Gemfv-vp9O>ILGU~wZ
zx0Gd(kYUBj<*~?jMazH4e>J~h*utL~^&p>}Pinf1mPW_J#n3o|hrGR|M_5cFw~9)<
zRn29U!tTW(W`$RLOY%@<m#T$XlI(`!k`fv|u`^qlUq@gpD~q+nqk+xF7wF1jF>ZD}
zJjDh7l@cIa{ntpYsg{V>jInsdX?>#14xYAe^^Th$vxlLvUyr$Bf6C6Hi$d2%raveA
zVe`9$C5<ZAx)>hhV(r)KFM6k`k=s;?60hWLYbwURM_0P2vD*(Q!1Z_V!JE6X0#<t{
z16e#CZpVYUNn?)CEIle~d>cL~#~u-_nn+)y-7;Q@@_q3+@9dp9%Ei*`y>zF5)OAs6
zUG?sK^S_xzq?gf7f83KWojSebuXFh=OuZ1d-7-+x*RT_hC2)#mxuy>tdFk=cuj3i%
zn}i0o)#dXqy*TkW9Z_s=WU~$>SMu`h-MAZb@-cTE(xKb(pVMmw=j}PHeiikY%#{2X
zu8X0u=jCy>APBJcmJfvk-j|rmJUHncAMxGJoY}lm@z*T+e@f#)NuyW&)dDa*7bjgW
zsNGG0i7?s{0M=E0nuP?eyi=r%tD&V94PE5i!{~a@Ow(g~s{k4GwL1sf?W$KgSTN|e
z;(oR(w@G6+``D?C<1fj6h297wsVy&Pr9#Kv%RaE46RF@6UHR;`e?^2nvSy5aHitGU
z5_cWa@g*TEf1c%E`iC1r3;V^nm$2<4C$e~2Ix!`wHTisDrk@boA9WO%{&m?evMs=o
z*r)rjaTWEoqZrdG5o?_-P;!iPfJE9xp!#-TaumJeCYAW}b3KiUqLo4>wq52&fYy9T
zMFq~?MIo}A08ek#<suc$S&Z0s<rs-LXB6*y>515Hf1VhegFlN3T2~^wsLF!2gu3(%
zN!R++fEH6r##*#IT4|d}c$a&-3+bq#KZY056+;y>$MVjU$>O<t@m`Q?;u_0XUn582
zARAb6Y{hiPZZ*0nf~s($STnsY(Wc?QmQ5MIl7e~7>pxrn0(DZsYP|MSP%K_Av#gWS
zlS|h*f1_#faN3GX?9)g|((kvrC%oF2j^N@M$ZmO{5Ku;1@vbKu;#vp=ze9oWOhys{
z<>LMU9sDP80Q>fZMv%5pd6@gw7bjs7+<KiCAdJpF0gfHJqxI1h4uWV@0e;n-_e%#g
z4imS0Ronz10~rdPhXw8p<n6b^pQ=7EdwH=)e?tmhG=D`>bkvil0j~vFGQYC)3iEmh
zH9)XH@m{V#&Uc(Y@JYRe3zRA$@12ltj0eH71%GNzi98-cSJ5t=t_Os$@{EmbLhgum
zKu^g0`ANYdMfA{r0DrxGg-Tt?0bX-@WWv5eOD>1v9mCSyLt*<tzNh%m?PxD+&te|s
zfBzgcR_N*Hy!Kl7%jVc$?9|~~N(3e0{QxC(i}+}66qlTCnXsMORNjOWLCnctN-_zn
z7`G%u{rxrMw>2&zRhuA?nA2@7*<V6FIO<L@aN0ZHifu%2^k0W-4c>~w@H4c?Lwh7t
zqyvauK}Q4!?)^R%B5C9eHC9c$Z>BgGe|0w0fKuDQ3)QNkCr-!2fi)mO2l=~ZVo3iZ
zMIKdA&GM{?p&Y^7EQ}ssbA8N+E7QW*xvRpXhxm`S@nc6$Qa3_ZUtW|*cN3aPHxdJw
zUoMP!klF(zAh=VxIbyk`%;bVbD%5S!*WPHIie#X%XjdMEP+uO;3(?{pakN-Re-hfZ
z63gp1Q?nK2)pd)OPhjf9Q*K@Vwu#Ww8q+2o<)$;j?$a_kV#B_qYyuQH(=|NoXVrkr
zU+IEsC`&{Z5=4fLQNkNj;UJPE-c`xD(uK6qfE3Y7ss{ukl<&BoM@_zIfp_F2d|#xW
zyG?`_xnGx{m!O@(v7<0krG4GHfAJ!lqPkjpv>{tIoy?UdvlVBYq9SDZ1=LEDgwf@(
z+!=E8uaHFAqnm5zQ^ZLvd=p00Pk3QY+3%TjI&9P)SZ>#p(T@}X5xr)I5_Er{A`*uY
zoGE>pC-!2cv%bp^d`ATsodS`@Q2|Tk?361_jL(i_h|`D<49MMX>gVDwf6C%n*7G^j
zD{6L;9LW@Uc9hJkG|bwshHx|hJ1b(hyOe6h8hLR|qCDUtk&8L2k4sB9L!(?8@>YaB
z|1eyYUtxR$H^O{2^j}O8{;E1+fMGzgax&zOvKlxCS!LTmrwe)#B@?l~vJB$vtOqra
zSCG(2s{7tDbdvhfm=d}Ff0{kJFV-`!%1Gx&tZel=<<1H_S@gaLPoA!^OW{a`Gn8r&
zQG1%9$$N0o5}^}98CLi~D4#MJZ^JP>pL{0=4FO*I%ULlD{(z1{*bNAQZr9ori7kQ<
z1aq{bW;0-=6E|%N+YsCa!umO^*+jVdmk8GR==vtyRZ;SWaO7xGe{D13&ET_Lr%jVn
zUwW~pB){gYD^82O2!RC|C56>KDwR)YTBIZ2>6mGJhN=vV$~(mq<Jr7Q>(ZYb`OU2~
z=IDbCUj6PKE5FD>Iu9DaxP|#)FZ}vvsZA7!sB$`0{d^UU?l{#%CczFC+&HEJaf4`C
zu|zB*O0iHpL^#A+e`=CxxLK#mHdRY5D{|s0d0|p4g){+Pg^CixBVdFB(?;0GYsjh5
zfk?suf19|{QW4kyl7)UB{2yeb!)z*>{(~1A@PrGv>~sJDR--ZJoD6d07l;<^xM5Uq
zKD60+zzjvn$iWBKFgniJYi^_cwsXpSnpGKafH^wZm`2*jfAWXPjp$K2mW}CmgnVD7
zd}qW#Ql**J-w&Q18I4%04IL1gq#&&bYLt*O)Q){i`P$T`<x5|$)LhW7Jzthd_=GgH
z<iT`n$W;gUCq<|ZdSsBQ4&`9{80T1aC871>F_(c=te8*XVICQD3QF<!jGZ`%e#pvE
z=@mEqm~eCqe_eDd$}=1iWdxQJoOpn&<;X$ymJd_Gk>oX`jw$_fw=Uu*3Z{YW>B7uR
zXyad7Zy;>v#Nc(JQq?#N*#9#01G#TEM?vK_F@^S;8?m-5C~xTUmSA*DqNywXb@;V7
zoNm+oNxb?}PT$*Ax+B71WMf!RJf?#U5lpbvPE)tKf9kk~njX1h05>G?E7XOo+~vas
zDB@u7Q(<jAjmC88*zmvss)q(KH+8-b`7}lVEx5f0FL}o!WzcKZO*_4t7OAr?cUJ`g
z;WCr@8OC89)*R#w)6P<fs(%<k6K2<WvA~GLr+tz?0mOhQ_GYis9g|>-fyTd9FM}H5
zIvptpe|~1mn(C#YDG286HYvGrgIQt8B(_&4u5OLzTRFbG$8e|wEuagO>3g0*);8M+
z3m)l88=U?|tz6t6+Tv)>5j9%=ro1WlnaJoG{{x~>VQADpvA<Tq7i{!hv!H_9?Qw`<
z-=rF0>_Y*u86^OHT5?iqOi)62TomW+T6h!QfBvAAoQ?DTjkR;nb+Ku<tW(AWrrCu>
z7_sdc2QXa8XdxuQ_O6ShJvZnV0LgzX1tKsGslC<&p&FOY-}7%qIuC?C(+S2p58FSZ
z^~7Ecy*-n?BL%^b?<wy(KMRwL7h;nJ4H>+{GCf0f{xnXZ{6ZSvX>?`z#IxSHauNO{
zf6Kj=FbEAAXnV#i2n`y<_{24T_AYrf_JIb*dG7~Z3-1mEJ|hYT7w(lVUybkks8EpM
zK^fyY1sERN?ry0d;D^fNr`z#gY`GAvsOasNyy^Z>8spzv=vIkScVUX}RX(fOJqaME
zwaiW6o=EtVZslf-6q{0=x-U|I>_eFwe`y_%Vza=DpDk&&XQY{{2>2rfq{<xoNtG)i
zi&z5>mi^IV3R-jDafj;>UJG`g%s+{?g+_S`Yk?=xym!|5?mXn$)s8WSUM=QXA95%B
z7w*XdaPuxwANJ0=sBWF{;7ht9(h9q(ix^?C!$5e1|M%b5*7BY=;8d6FS%E0=e+k?b
z8ZFM=Y${(-o9EgZ$a79=RpT1{%|myl5kr@D)AH#UXx>G&bSlBWHa;W2Dmd*<1qSph
z&|+w-K#6hRF?#MG8%yzz6-YPWjL2R`xlQ1g7HMb<=x`E^#d4~!jtyDtM$&N(#`TwT
z<lj~&(yl9@wg{!Ev(i1Dtt$(Ie}s!i6b37L5*ZmW-@~<@`bttDF!-NamEO~*@4@()
zt0b`G3s2=+JFI;*zU&9fJa-RE6opVj@8VN`=`*M$FU}793FzRof2Pb~^2BfG!5+)(
zipKRGs#@Odr>abG;dP{)A6-3Gu{tCPv9}%cY;~J<M;z6jc8_gjpOYIxe+@wV!L-Ev
zB?iLWr3gSZ%}{F~3CqRs661a9OYo5D^v$Rg?AUb2aN6yVzr08h3Tb(Iu01E5a!+j%
z2&6R<mxGBS+Vf_`iJ4TPJUtc{!ljF{^*H-M`V()dSal|td6WgDG!v0KLIRSQ2^TUW
z>!J7=fj$!O+@=E&goUa`e+R~r7*E+_PcQz2<*Kuqauk}ekl@GOu{2+S?k~^FwA4lr
zDV=#T$C9BwPi=7@PEUJjC}}1ECEV`*N<#(bh-pUtmdDT;g1inu!Y!*UdsqD7fa_$7
ztN1Ds9JB9HKG&Q;`FoMb$c`9~2avC9T0uf-um8je;7u)dKW>c2e{%7V=W}Y4a$Y#V
zaE*0=F0em02Gp*nxV;>?=58@*izVnd%JHyze-}ibTXl{Asd6P1JGq7Ub(5azg>+qp
zsX(Xwm3!Gse#5g0Ost~7z`v!c=?-%V7&7!z`i$p6^QFWGhw3}PXgY-KQke{Dn(Z-h
zx~3=D@J82SccU0|e_-MqeK)4OTH!V~KDFZO%5VgeLAMsH0;%&0;%ULKCAkO);st9^
zqh`!;Sd@z=WK}q(3bs}$ax*lkS#oQNUGx_03=hfv`V%kR>T+J3s$IAeN<9U(V9yYr
z-ixrF%jC=sDwHKy=}3Nwp<;++xGLslDLndkIu4#-%Evuef4C?-@re%NaDt35=MBd0
zFu~9A46Nc``;`pp04oMKZj923xNk&Uw?tU$<}x?1w~X34&yI@8>I^+}NR5-ujf2hy
z+p1YN$OoGc5eC+~4e69yiy!Xn3>VNZPXusHbhguI175lWTm&4KobfYB7og$d=ff8N
zknX$~<FsJ|e;Ws<eFElsg$z2Rdx!f!)Gn72Hp~LiLPb&ja?MYAX{JS%*{3l+3yAaQ
zo|3JJ^8u0bf*dqFP6vfU80N`AD%6FU7~?O#j6kCTFM1;{st=$@EYMi#GV0+C*(V&*
zEHrrmM}K<40EyVD7OiV+i4+J`)ex<6(2_9{qxd{}f14WNi<g3BB<JmzDf!pvg6bTK
ziW=(elwX)b5nc}JqOOXxfJ%vMd%ujo&n`Ng&A7Xn2ZW7_*}=vc@SjLV7aHK{4#I4E
zwgb?SW%b>SH?h?QZ(8DM(+VMNqM&bmJz;9t+c^Y&@Z2wx=1@Uw6EdSn<8-9F$kplV
zfnH)1e*qBY)=#kowd!OpufUZXqSrQuw|>X%?Q_sqg~Qub$CdFR=<96#@v8O8_zd)Q
z^!Kd!cK@Jj5aORb4XkPoCNV8cN2o;Rr1Hn2ZYH=)xBOWevd08r#DtP%XfGckAH#e+
zkyGy77r-i*`xfPZyxJ->AcOQ4FQmtFB54}%e`V5$BxD0mLWy^8WhyqMeLkk&8tgxT
z#-_A`r8}?{(Lua(IiW`4x28qn_J9dOZVm3nzG}gZyc}`P8ZGX&Q~{0arjj+o;;t&m
zD0VUY{=C|FGCl%*<$}gdMGS4p+OEDz_CNhwb%%i6v<4TTAa>xiZ_r}GmtW*Z$QK`k
zfBBbhM3H<=VeqFROvOf30*z_qmh)2hueRKh5l4<qPydXlar_sLG=}?~573+_FY`tD
z8|66OO3~nH@r{5L+A{<+&3AOQYsJ9mh0=I6&0e4g=wf@mE*J+pDFof6z7RqvE)j*2
zm~((&Jqj)2TM$0E=Nd~yyRXP0ro=PCe{oZ`<O=(5=<C3pIXJd8H259P4Q<HRAin+I
zAePm)fBHHvvMEJ7lR-cn$^RdZj28cp-E;pRkBqecvrh8w;oq0<HeKWZoWnK|Yva~+
zQVNzigulSTq&SG9JP$yqB2X;Qs9+5Qm!!_p=&ql$33O9DsOtaT&}(DYCq8S{e`;oR
zT(E;u6ALJ6>ua;S>V0@T4Q%V}?YIb>*JJu9%$~GL1&F)VzV82a?tAIG%Ljkuar=IT
zj-z2OU;zb0W7iBtwOeH1oPz`FCU!E5MI(Yy#0WJA$0j+1gJ-cVv>1j*AR>KI>J+tn
zV(I{>^O6Ne;1ftYFjcrR^1R08e=xUCg#&YjX+}@(1-PjYJaN`3Rxn=4EGQys>NPzK
zmCbtZ9$l#LVL<mr-J-$9&U}E>QHVe3R$e%#0+O$Y{pcB)vt|m=3dTduZ+#&VVNcfv
zzjo^FT0-hgIfZA!`@pWkROig4?gof7qTDhW?SS<}8rgPud$iCDcfg*vfBM=3__tDA
z%gmcQ;4z5${Z6Dt^m!?9Cy8L9gC}!Hy}3&W=L0&z9Lu$`YpeA>+5vp`ScHDf2uG?J
zo^bY?yK=FOsox&~*+ZFcy2y)OP7m(ObB;r)WCvcCNyX~BS%r-l;a5p~t_xn7D2T;b
z8s87W`H*%;e=S4}=N|I=e<mv6+kn!I^M{qLpKHMXc^}Dm^gxb&pMUB6)uOBP7RfQw
zYu%~$m#nn+akjir@&y+YpV=^1h1`M#6}Ey!s;;@C-q~XAQ<;m?&uj2XWy$2XA1C@`
z3L{*+fXkG{Sx__HGywb59I==4_ph4D+%~OUN{zxeyPH`(e!98Ge-ip7LhgvpO4j-|
z>$s_3x1s*;wubiDHGo6fhn5a5Oa-lmjnoBg%iq5r?pxHxH4Rea&$_dURNOkOerH#p
zbS!WfcbBg7EP*QG@U|9;$^lxqeL1#0P4j7T<5;A4)aBG%SgTm1=__6sU@e_YTRXaX
z+Bi_g!m4fbw^H@rf5nZ{7HWVl?s|2dhUJq$Yx2XXP14$yW}jR}3$aU9^}{S>e>FXn
zsqDYb%1J73F3V4xY=u4QY)nLL<fIDRhZWB|A{m!nw*mgbt1bPYL6-p-z_sE(tCUl|
zT6DcR!ivm|Y=|>t#V)zYDwsH61lJ|oF6X?FGN4lbrHve)f3Sj~w0{C?Yq!K!Pvbtr
zzjg7rdp{zD^XBr{Vwh{E&S09}Jr_fea4UISSfM>GdAxa($l+I<jz_sKZ_hgp-(f<B
zEuo|CiPi|v`V$Mnngu3{P8t#?YDY(0;fixN%{H7G`@#n?sGf&UcNINUu|{fXGm3-J
zRXVo*@y3A;f3LAFkq{~mR<SuDEMu}_a5O@dOkbGa%3c%*oSeUQH!C&ec^h+S%#o)r
z?J`|^?VV8V*S}w(bJto;j}hqV42AuMOoRf61b8Og!ygQ(>W7J40c6~MP}J2aoG<P*
zxBuE<fKU8>Do>^Ptf#m!p>fd+GvUaKO`I|vl1zi6e^$XUjq?d(hgXqLo&hlD$mOdi
z?iwgMoI86py<X%DKViJv!>DJT+(N7+L8@C(#gcRlBvwBv?eXd?{ggzPB5u8IVhePi
zi7M{X$(E&oG}1!L%fV;-sM}MST}yJPLi_fi2osTM^%hwzS($`*nPACJ%P{+%@gdtt
zY&3H>f9BChP0%rZ@1s8ymKOX&Cd>Lpg$IW84ZD{aE}I^VSv!4f%bJ?z{THQWy!<K!
zSagHmD*H@7cwzMhf#g~MQk|gEz7G3qEcl`6NHb4V6Z5{IRmOXF#^FyoDU`-t-|DjD
zbrVYegbC?DYb`#mj|as7hc<~qI%QQ{H2sDAf6JM)WbwZqY4UUc(==BZEM0bh0S#nr
z>gz+8-5CMSh9X`0=D}Z#q<$6O3V2@svVF?KtRP)=6+y;<Tw-CTY&bMw6U~4y<4(s>
z6^(*gKbvhAnd%0RGN#z5mhrBO8&6gB5U2Gl_l)vF9I)YH7M}J&lZWoqRVE&I;an~M
ze?He;rhSR7SUYHx3-GqherFnlp5w&nliyWl>LKnDpV}%aN9`SS_z6x(daCD%*c1Ir
z`L~=Cx1X}@&Hd!h+;YhD5E`@zAI?RL*@`j`ZJf-|v0`|W-_je3?KL+f$hA+Hx`^W2
zrwaGZG(UNQqz~tAQJI1gL>h17-(l08e^c=J?pV3HrOK7D+XIsOY3x^--!0Sohm18(
z@Ls9ZAF5AlZLoNY3&4m!P-_C1FN^J;?Nxkr4jb<r0pPeABVu_J!-lDCjFZb!e~m6;
zXz#m+A_LSQ$rW__=%!$wHF4L@C$IZarl8a-QD|O(p2~|-pTc4H3)#SD3kTD{f5k2W
zc69)IkV1JX2fv0F`3k$vQr&Gw_zG6;q{{}>vP)*c31G@xBk^MKcg^r!eAB&(E;UPi
zk03YhqkB`|1CmgV>I)DEL1(<W*;CwNr;58o7#J4+Ib2z!$IHK(+0{D*r4;^D^G>mi
zmR$3*O6^79eXE#HVd0hX&nEnZf5IoZO8xbd#-H(R?HBlWiS#FA@Kl9{43U<!2^6W@
zUokM+CMBV|cu9{a)5(v>tKShsVyJb`qNap4Yp)^G(Xqr2IJ=1cvgw@D<zsL)zsI~p
zy3WSH3<d&XSLpZrhqQ$HZ8Qz{r{Y<6E%-M(7JH8Nj+!!7hKY*oJ2XZtf2oUnFLwHD
z1`%@Mc?K#Io0@g|xy+p;tV?bwKbxl#?@ZGZ=i30W<9`_BP=t!FRnrR(DmD0}*{80F
zh+dj$Y<3vT;BUToLei0jK0bxHvc)b3cp9!O2ojL}<`9H<bJvnZ6|ma<uvS6AQ{&IN
z8ahlO^i@yTK%nUL!)|RYe-RCEioNQ+gkn4XJ!Ojhj+rSiyf4NpfM#EgtZkOF5A!lb
zEG=yIorcIC_oP!UQR^V*D8`^BCkt%Dz$O3_WP}~%YnbHl$jFs4<$OJd15`ikki1>5
zoLB;+lH78t-$cnpRht0-Wk8z0(ibMkvh6eevLG>S4kjR^b079x^vlFk$bVXK&y=Nl
zQfQLX9_Jw~A9C3a;O8~p4=!Ci@kTH*VJmD^UyoDK;U$3;VOq_Ch5qAHH+@bG_h+?Z
zskVG+gRI&>zC4=2HEB*m%&~GAGyBnj%Fer1Y}jKaU780E+p4|3rq;a<;$4-sT*^FK
zNGmXmXxP4NZ%93QxTCmBZGYT(rf=i5i#L8YYve&vrUF~|%ta?EG4ydoKC*57w29<t
za$J~!Cuke0GBBaeraG+v!bB_XR5D1aq2fWqAXSgSQS`MOZCqw@XlQ{n{2Nm8Z5v2+
zHCeXeL2ov=sLzWVkp0uMD5Wug`9i>*!_CUWsoDe?gh9m6N@Y+_yno=qVi}P>x967B
z{CXMLOn1;cpAAqr0z^w}peKBD3W;|ue6faUCBXQy$0`SqHEjkzDxJ;0iLTl?m)VY`
zv{c-LymnQ1cJ@0R^rp{YXIluRSZ}DEholtyM?@o(sfY1>&q<!^gwai1wy|*pH0M)r
ze+iKCSX+8U(IJxBaepd&3f+{g(21RF?ux<+OZ13PGOgQXd~lk#9xQ!I(8<i^pBy;7
z7@3geEV3IpVuj0)<HT`O;M<*Ah;N8f)TQD^wr4Nm@cRxQpvl|;;<7m$J~c;C3|=g>
zQk40w-lCvzY$SalA+e9<1|CPOkX{#I`XztR@xt?A>7dBIZGSxZmLsU}oo|!;-fzai
z(v8MmQDUujM^i(uFm#F4p)wCm-agOd9iAw)?2KYzBgVjZ6dr7?$h!X)KVe+(!-JNU
ziVEMiY;tIZIuH+NO^ILnH1v!pSU-YxkIqwEmkEj^r_DsUjGQT5H6>AYic@e6AjF+V
zdZj7QI70}GX@3}Z{tJ)Ax6ak(-=W)MEo8SO6wZOWguGd=UDYi<uypc@WuVA+eJi|#
zZty{43^MdnUI07RNimeOK00i><fahLCf2%fL_KWFCf!^QInEXxU#u(N!plLWCQg|i
z(t=$Mz`iPKWznH4nCh<yKP&k4l<?J1>nr^>Oxz6M8h_}_-&wXGItR!D6ND3uMSgBY
z5#}!U1$Q`gA)bl31&WG=JJA`TKrZNQK((8OVtlVZhp2u?wnqFwRD`JA-y|3#FGBp7
zft$&nJt$YC!&a|Pef(vVBW}#q*f*(BeFhUh9FEU;Z@C#&gVyaz-7h8lu6)nt#Ntrr
zlR-yX5`WFAqGCg3=<Um{$ghT(bADFL_^W_w&UAYVM^I8--_Ld<d19F71CmJlp!&P0
z6skX?$xkKwCIr&bIgR`IxbEYPn0Y{B-V>fLy8l&$tDCUKrb25%8ouvVEc&7YzNdQI
zi%Zl{k<d7hb5%-+huwoef~wKl)dpxIhR!;oj(?s`Ql`dtQGRl?($jI&H97PrbyYO4
zC~8T;QfBInw*$9}Y6Fhc5X#U1>CQ;n{ltxlHok@d$=e|m`me+D`5cyUddEn1<)m4o
zlSME#G}W12i^x8H>0I}4mM4xIQvGFH6|^hK;^5r|{S*6nH)gM(e5YZ@`4&ggY`IO2
z%YWncC*KqNdsM;B!D(y{0VN;6?|iAh^ao23T*4@-ALoYCn{u!_RL_$lZAE*sP(diq
zpJcsf+tK$c%O_oOg<^pqWIA&%n`abdc2coiGsCGYFGqzmfC95zsA{``d3bH0=C$R$
zXdcoc`DT^lI4<YU1}6VZ?|}x1zY;JREq|&Q9sT9kPY>0C2J64LiZj4t&LCq<Xd<Ne
z*%TA{fp7*XUy<}#vbj=!U<+|P!kier;_38H;*7PKd_pu|PDekmjbNF`hW~^@7xM5T
z9|o_X_`}5>dSOiq$<~!)oNY$j(pPmgL(!nkw}k$6Qwlffi=v)@0u1GYHJBi_=6?tI
z+!zA$(4@e<1^LyP>furlO!>M4)pK;9czBR+`zDU8Sn9m=@y!4wWpnr*!k`eoPEdAx
z(s=OM@U<YGNkCM!saO!J=7%h}lfgqc?5bi<)~5XBoumG=cw_#QOm9gs#+u!C^UW>g
z1@Qe(ZY1a7H=bz+^1$se0``HA0Dm}Uks|UC<cg1b3?m^2vya3Xu#DSW;$A1b*z%kk
z_a|vl=r<O}p+hJIK4{C8Kgy{$?t>p8q-T2Kp1mHsm<^9<LgJU^Ji8c%Fx<biLoZ}?
zVb-M*1S!r?b)3^4<lNpN)zBCGSR64Jn6HWxaeb3mzv21%RUtCyU*Mif{eLmq@F)Z2
zhFDc>C;(HfFc)W!K1`a^`GetR+nv5aJw}sB5D7>wow(+RMPl~KBoQYrV)>=ioG_LJ
zS62U}pm_G4<obxd=vsZ=2T{WaqM!$1(}z&@8p-382y2A6qQIUafQ0Om;26niGjHj6
z_TKzJ_nUPhb%epuIme~P{(mD+(tcGuG3BkYh?qK#pW8+lU3dW!oKX91VZ?2rSVBa>
z34u`T#~y9%jr88Uc7#T&We}T`{$mh5yISB6r-1ek%SVzj7ct?Nxh}A;tX+Q4VBeXP
zfKleUuM%Ud=o>zI-}#oHwYpm-<D(_sO(r0O{r5~`2QxGVix<W7S$_|RSYE{n?}^KQ
zblI|xq!BH7pH~5G6>xrUegUFs7-~1NvyCGuuixUSrTQysG}A4NqmXQ7Q}#I9Xp<#-
zy6O0%6H^U>q1DA2Fo})Nd#C(xH^;|Es!DT(3Z8L_hRr`oMbvvqExS0zKV+k}H<_xD
zaPU`O3{|5;BZ6m^h<}vu*<@Ms)4|ds%8$+i2v044Yp+zKMVki93xf;h+v2t0ZgV$+
z=vOxl?O*cARFaKrY6k++VuH^z@a2(SCOpvMX4=b}2`Ezcg)Zw~CDHc+5W`oP5J94T
zZ{&6*UlLP7Xyaehd9TV0q}!2*pD19VzhE7*Lkyw^L(!iY>3{5rS@}h6d87&5)A^r}
zJ}&sz%{zmFfpd^caTlON`QY<2l?ePaD=M2V#lL<p;J&!YvrWu}^W2?rE^a9tG^r0>
z<2zw>`NRmhbA0_#MIvSR<el|$ZH4wB<fDE}K2al8|IyzxT$2VxUu972ZH1Rtbc6I^
zK8u)BJ<mQj-hYpcGXRQFR%yoZ&UkvqF1axDbH*_G;{KQ}N)IXz8omU6|EtoMz@K-d
zPv+oP;#c&gFCem%zUyCyq#r{N2If73_d-buWACV{DJt`!T2UsI@lm=ze$x3h(~!I?
z<+#G*l9e1~L|+<5V)dp8a+QiOXN3#QLF&8PQq4_wTYsrt=E%8(h^(y-DhhHce=qrp
zu+}+2ytWJ39Fk?Q<ad|o)cv6(A}OHHq4<=tAd#K37x;^8Rd`jHgc$~FR_s^0w)wR<
z(+(EX0mAH&Th1^pPa^(8Km(Vr0JioFT+kPC!X^)T>-bJa2t2a;JKJCLD<E(Zhs*1_
zpw;q6EPtKCKda^o%YYFgedxYBL-Y=qb`Ap1G`gVI-^8ub;MR$0Yp^W?xkx=z5+)q^
z+FzMwtq;^WPfYv^a#tyR9l2P7vYOG^+tJ@t2d_?xw?gN@-a4OscPz?mULUysSi4zl
z?OB{-K|ma`{vRyF|6HFLf8*ihrO|LRb#iww^?$ImP%-s&a5lA2wDd5QH1#n3Hw#hC
zQF%!P2k4}~T95Y)IfmhQKH48sz?ec6fs>F@mn$7&xAdT)J44)2QD5>y5y<IEc@ru!
zKyE46!G_UpoAZ2_=RYSj=U#Ak@cI7m0Uu1S!&S7OfZ~me!^E|jYPujw_T;(ju}nz!
z=YLKaIN?u<37Uk2w&%v79{gavByrU~_bG&xVEb{sC!cECj4j;|I3aTVfxQqf0hXol
zV&8L4UHg+{8+3Sbd&?v-i95L>W!I)h?N*Qb7}dOX19fxyY^W{S-E*csdK!lI^yG6e
z`BqdlIf&BQjfrknNMFK75y*(uH;Dbyq<=kBRFbuDyt!xvKO0BuQ(kt1b+J##Y%mAk
zXOdr{G-o!{tGiuB7-r960zOur`X0`k1T%G9(XBJxaYQ5|Nr{;}7u=Ib)7XqnCX=vs
zU)DD2UJ~h+5>1Gs2$)g{Hr;DMp`!yB$ViMsM?8F~OF79lUEB?{8GECLr<V1HIDgbw
zm`Z2&ITrvskfh|xQmHhd%2ROUpA<BTQAJCSt<<er^uFL86gGh2W=eQ%<4wm7pSA-y
z4dqwd=7Sp?K9(p12TSJ=?-5<RQ%euhg#=2;wQ~=}E8w^Jz5-X>78(DDkVlf#4W^2}
zwxx9dh_N2yyova16ljIE%2M^F%zx4DsKu3wQIHM0DDE?8Xs$1sO)?+>SBE@oJ4}|L
ze>^ngGH;3h>9(>Wn1%)g0pSPpf9SOR7ykZ*veBM@u$NxGzZbY)&g27}+U4K~#7)+Q
zX&{HNIO-^2qD4g!BsWcD=_ZdY=zao3H4Mb+1?)7NR&e)2Vi*uHanq65>VFmN+uA)H
zYwPP39P8zEKd<~R^98skVZ?*xo&tn__JRu@wldw7d@d%q=b#59Ekp9zcaSfNZlpA7
zRA0=9jm_Z03+2-lH2VMsZuiHkuT^cWlL4Jm+H1a~B7Xx6Ec4SX4Qp1a{B%2H@#XY!
zhRV;hgG2u~OXX+V!Aad$rGN9)+-ryad=0hK)1!etWk(;iHm36?-b@d_%FnU$b9sOs
zEz}mIM~J$%5)kLvcsQL$cr=Z-@wGO-E}fsx*Qdi!egV~7XyX@A^9CEgn7UtL<Cm)Z
zvUHflFQ+-Ku<?ylzsbh0wDGHG@YOc{lXQL!y|1PBdTPJU4z0Y!#(%G;nQyT18*Th1
z8{cf>H>dMk_^menQ$qDNJHMUZVdGnDe5=auv_lPFP6K{Mqwk{6yKMaD^uC)O_YfHO
zrt|ywtt!9Y#vic5X*!*^(WnQh)NbPsQICgh{1F>})W)|{?PK(KoH{*0l-og{Ptt5V
zsqQJl_-Py8mCieOr+*z@=ezA-<6SoXjLP@W_p=1hbJXp58oHNA@j@DZk-tQr`>4w=
zXz<JQxt~f0=<y1DzDlLn=<z!B`z6)=iY9nN<!{>I3cj3b-lDd*RsL%m|BW54BD5U*
z9jg2-J>I3qd-V7nJ>I9s?`iNF8vF-({E;3X*x_mZAw52#&wr2U@d<VQlpcSg$Dir(
z7kYeVXM_0X^!O`1{zi{4=<#=Y{DVmIB|W~f@vo_-lOErs@qhAf>G3am{M*LAQ~7^v
z{Chh*#!prG4|dqWpQFc*^f;*U{}MQdET}I)s$k=XRer?AQ75|isWt(2!34Jnf!{*0
z35!iwZ9-Lr&3_L2_!<Fl^r$M*?66--ys#taBAp(ZDl!m3kx3$sJl!X<s5+Y-IjV5j
z;cX)B+x#E+5V=(PMiqIgaN6NL(N7iq?eISK5CepZ#tfuS?E60TeV>1WxQl$d7$gc*
zG1w-CqzSheYKKq7Fq;@|7bC<-`WQt$MpLN}r9_Oe34f1G6xl_wC{e{&<fZ6G_2Z~!
zJd#Y5(qjTWCfdX#I}-68QgtN7WR!AIMkr0Oi>czIbWtv*QE57rW>CXSBEc-1n2o|H
zDpWDYCMxalu9!=WRrHu=6DQMqK0T^!;uM=$KqxM>iAC5`N{pzX2^Xtk34P$oOKG}g
zR9Q=Xmw!`fg-z5^^J%JBN$=C?afVHtX=jQ!iymhaY^&15YT>1loVh+tGzcGkHqxUB
zc_W&s!B6~NLpJapn>dH$3g73F65=~RJzCIciJ)DCM5`*!W8kU{dxMdHH|lFx;$0sI
zc^ek_qTadQsF#6O9Sr)yl>u)g;)^hFEUT(qRex7CXVtRBl?$qBS1qVoiIoe_@vilb
z3wVP~<CaCk{$SHI1{sy1U?l1dMpt+PZ9WG5yNz73baCzC%Eb$D`ED&$r`1-~EUR8z
zvy6eWTU$kCWz~{e2I}%9Coip-TgAX$xwxjLs<IaQGZ2AL6TuS-H;sz~8Yi7IZeggY
z$$u9{c+!05M}5JFKNMu(ksS!=RqK3fBBA<oebI4ddt_X7RjiByv(62M)&<QPBto{1
zZ(GzK7`M<LiPG%L{7pe`v@ML7PVd${z3;2d#Hnnp;ZQVG9||xiOf@prj02Y#MI4nW
zp^Q}^kmY@WBGp_3L%;gAaM%}&A`hefV1HYvEiy0cZ9&{drJAJ?+mPwwWS<5U8-i!e
z`lxSCTVtayOsg{(-2)!^9rTCB%`v;m#k2gu`cO-2z!&v3>Z>|a_QjrIUt7fIT@&yv
z^#&V4Ev6{SRrEUSrnPv_m#{7KUx2f*Y6iI@NT9<}V!&K~gr;b~meUznr~8Bc=zmO<
zrNS{Q7$}vY1{{;M&>!^Gw6(19g=?v^6ta46V1+mAr*ETDi8lKqy-=wk>}`xj#?7VI
zs<KIwCnIDfDLI^4HVB$bf3USJS{0Y%+`{g%NZqoMyCFpVlA&GS8iRON_X$o&T4}N2
zJwQkWk`8%-e6IgLE&RU=HvyB^1ApXds?L!xE=m%X+5aan<+LM?OCZ_J-t3Lc^)-6i
z0;nw+%c9=;a~FAAC7UpoRYh18NVW_9e<GU%vA?&z-q#wPkBSv(_MYpjh%EDk*ZRT?
zR;Co>=2*vZl>tAR6La9SF)5)AwzWjYnVpaXQJ-nr5`;d(oVP*xsIe!uHh=2*TAbCS
zkz9wtiGbt?`_60gMbKd;f)%5j?4^n*2DQl6s`H6vx*EFb(V%+$!N}6s_$8*XpHbM;
zjh+Zh8A%=hr8(Sljh+nDiNoNk6J+4Ad+TEHzp-02;6_gv_C;EeZocEPxcho&^CLd&
zv%Vr2Sx54jrGHj7djkPquzv|>)S7&WhP1daHH^Ik1r8j&pnF{4z&UzE1~Yq9o?twX
zj!VTk=t&J{>YyMChbEgdbZY4Ra$?XY*yHJagR{4YVR&mOLSWYWA`z1hhLp#pEO25{
zHmA)WXh2V&66NELVlerC9A^z1;RHWp4*J-h%1)}>LtEqH9X(VpqJOe2n0c%G9L)03
zC8Va7F70uvdh7p}O4&!^o;X>1SqI6gD<SG$eW-PPwM-A{eH1~Ygds6t!qIkrg1V;p
z<0_F6^sP(ej59%wE5c##dP5U6?3W<$6{)(Npl;6U^Bk%5M&+we8|%Y9G<|dYL2r1y
z5ogax$@!jv_LyEG<A1cqSQk~asba0lF_|hb7BV}|3x`_FxzH{8(fYP{Bj-vci55!u
z6#B;bB4|D+q{k|;rmYb>hFYWbGB#$YBO(-}n7CC>AIZc<n`L)ZWMI4%jU|}N5d45I
zj$|t6Qwl?>93$OWPR~?l_bKQe(QB?tsTUy|k=R?;NMKO9Fn@Vy_0nV!X+blQhJnNi
zzNQrMZ}g*7D&ff5QvEeSe@&$J2^1S7Qij3M-W}rNRw64oLSqaAi;)Kv^@%dom^+nD
zQ^h(}U~)b*73~ew7aGu9n3@sCg|WK2`nZ~Ve5zXvxw6KH!%o2*I~0g@jaBDh)zWUn
zACU^X%4W1PI)82p{Vjg<J4)dxGF9od_Yyg$?jtRQ)p|gVUUKQO6+{r4p?VC-Ir3C@
z$%{}_Voj%069p7B!5kf%0lf$}y5CF_3_}q{_ofIvqKST3;SW$wP=i*9`c{V8$g?_q
z=ePRmk-pvP1!nRne$s?B_!<mBV)&bw+SJ8@)p6Bk7JqI=un2(C8up>~TjfNE=G49f
z4Ly|?O`otaSll<n`#dSR7HQ+=8Q>MBUf}c;q@8qJdaU&Z{L<JY62!Vj+HEu*NNIz-
z$28svb{>h~P(>btC4B_*1PC!QMLLlRZ6%7bah#2vTI>=7xIcqMeVO_MK(%0;@1vxb
zG)M*ywSRshV_qyIP2O3w)qBw-G<Z?2^AZ-VG-@eSXdn>?g<HHh>ma=kp*e1upCo#&
z*@}I$n|wiEm}-zOfdypyN2ScfQa~ai&1mim^d<~$+QR<m`f-aesPi`Y=K7m_lEQ`E
z+G|3~+UlDt0!<<OY;H*uCQe>NV3MYav8p&9Eq_fkMDieG3zW6OQ>w>MNGebi(J7PR
ztk?BiZT2@c%dE-Xh+bVc&~oqLct)ITmo;Scw?#wop>vLrwwYc^Yt_S8!;~#ZxnP}d
z%`#ac-;~m?qzG-$1ZS*E9LQkU@h3-dLOO?984O8;EWVRj5p1Xl1?Lf^Q>P>U3$Vwh
z@_z~nj}icyW0;LW34*m0S&5P#mk3oX!Tci-YU<vC;cH)DKgQGqP<A3fwbBmcBvw^N
zB$@J(>uN$#Sv{t&F)FT<o5YJiD1u#3-0K@@WB3@eP*>fUlc~}L(~1^8LL|tl5BR*{
z_$IR|)~n(ItoJrF)P@o_pL=u0M1y+r|9`R0GFnKBhN9kp9t=3qCP^U7e1<kp8I0>?
zzd-W5=YVNawRFQFF^I@*J}c&lUP?xsi6&?9nsd;VPaAVOI_gmJ@ruzTcbdt#*_yqP
zW_^o#5bYD_5fjDrbGq%n_b==%SIE_&p$yin))7yh!`wl@@XR*7K49#V+n0sf!hiK>
zK508SD<1QWrPWk%p(ZY3*K6!F=GDXoaWQ(PW2Q&(ybf@XxP(UH#5r*qR0pHJCSRBu
z&ZP$ixg+`#gsS3FO<X1}*Vt@U!C>sMGd*J~*39=bOmiwxT)LkxXlyCN+-g_?e1U+k
z$s4E$H?_53dY+)Oxhb+mRfIKh1%JDlklm=UxvWaV_!l2F_z;`Km8ytn;wo{qCVnEW
zL2uI61QoSG6W5CCG(LmR)Wr4T22I>3ZqisSTds-C;${XDdfCr)m$>V~p<t8ST*8gD
zG%0$ewVJp^T%wAoCT?YDzy>Vy)t8udrzD<<tKz4cxQ(Z4;&yR|Cbm%LvVY!JT;z?`
zH=_``O>Eqa=-V2~-4|}4CAVVqo4iy^R5W%8yOhD4-si3fxm$Wp9}2r;a;Gmf7JYx;
za(7MKi8!(Obe2@oZQVp%lIPb^`I)#2{bVmYu{78pA@ewHon%2<Yg5?U;3Ht`L%|?w
zKY{KKy3Gw2ggPggFc`&X;(zDj4m91#4Ha@xRovYd0Ngz$B_L8wsBt?_XHeezl)5-!
zW{rgCJ_k-bRulISxIM)q4%9KkBNgw>fqmz_x?HC<dH|F8s<>AZ_lf)IpxGq9CLR#m
zRPmrD+Qmb3NS%bw3SCvuy_I76-@lh_LQOo(EgE~Dp&s&Lw<aDDkAG@>8rF&J+@gxd
z7)<F?LSo{aU}#(|y|GYZ*RX3f@i?u0BfANsS8R6c?e3U#yUjT@@r1Yp{Zwp6a$s#J
zRO<}{YA|4SpMs#pXGfnzfwjgJn)^Dk`P*oz8`1i(TlCMHG_ivhYvM_9HRZC6QD3+U
z)68H4!diIYhB3rURe!W;Vke)giKoyiil@acbb--O$i2qj<c@~i4gN@LfTH2-?v&L;
zhv+0bx{d6`ZjJ3?J2cTHo>9dfO*|`}(b#9~b4@%ap4Y@)@q)$&aF-@tB-{EDKG-Mh
zQ%&rn&tK5vKJl`~b9tV|R<JrWbn*2nVu#07;cy5&(Vy90sDJx@3_5%G0eP;Gz?&lS
zqwcV;m9m~7Hj+37Ls566t+h22#uR>B1XFo`qu<w{i33D~R|w!&38dG=>-Zor?-Re&
z#IM8~8vBTStnqw4NMrA^_cZaQcuNy+<AZ&`KGejo#cycXeoeeXQ~j16_lbA$Q@lqF
zzthC~;`f^P1AjgKNRJQb@gXnM#7D%dk9jeQxa8Gb%r+8PrHN12N>!}W#HS1w{S!U@
z%-&)!+>lMTOo+?fEupZ_jS)-GT{>a1J5(R_MKS1^*eCgx(O&}n@={NhCkc<5-i#S`
zQ!GXhe<6H7<0mti`G4D}BDwmUqE(6!(UABWd_FWjMt?8bjdJ@VB%dgzW5=R3nRIOI
z<UE8HPSlWq-hkd`9BVYW0}=)dgE4k(80)SG1VZb4(h|BW^@|(2BK?)r=WnQKsRt5D
zUoa@vQ9>K&3pe6SsgMfzqtSp*LXm&W*75OeBa``w8>sH-?(Q3?r6;@(72~$C*$_O}
z*Fd3^#($QuQ#J8-R0{DAJ~tL`B?r73dy&1Qi7!bmzQUedh&NKZ{S+HEn)q7$9^<AH
z-zhroAk3<k(f-AnKpanE&^M{0+a6mps`#fSz7_w{#J^G5xgf>-P80tT-=o#;eFp^j
zSyfe4>~3gqFIu$7y&nH_&!1o3(o!CYxGzw}4}Y5YQ5+;d{)@5y$%|@LaYz$~#Su*$
zRX|gi!Zk%Gil$h&1woxKd1_U~yo$*sRVS5BDw#B8ZbivSlPfDqDkoRW89%pj>f|}4
zv_rmZenqJ&&PVtZD^kC28zh>dqJ39vN}8tF(bg#G^w7xQxaNj}qoZy*0(Up#4~3HA
zqkn+UjXBBkpgbCP>zf?pYLyI)m+--=lBp?KO17%xXo^G0)s#H8Qd68*;=}lGjV)x0
z7)&+YqK~Y7xjVj>po_RWLdSi<dY?4oF=<8pQu>keOqK8S%x^KW@AJIuG^M}B$MC@#
zAHfIX$RN59x>^uMAoV~IC-TQ9ifs;SynhHyI``0^^1h?B&KuD^RMboU3Dw-w_s*I!
zKyjf<=)PRcCi(U5%WLON)%av|JIX*MKPIy&_bxO(nirxYHR|1_7P%YRC=PIkf^{)U
z8=G;+3T2R{6exo=Wr*UYHHI>%=mAsMw^ov^zOSs{Qz-u&)8}&;jaOo5!za+F(ti_Q
zP8o)FOBs$4mNG&asVbw;;VPpwrBE58@soJDs(3V|NGaBo60A|i(qkOTG@nN<P>Tn^
z<)|3xW(Z7QIb^6~%cEf~cWZ1juEyuEn^k4Jrj%09Hsm;7ltE_lJ}?Gv@rvpwZMB9l
zkR08|3n9n0ehG({+1>AariL|fQ-2O^-!XP>lLAbA-zDZzWL0f*IJ8c`MCVM{g$`lV
zS8rVRN%OU|M%U|9$cV@zr)Vgse~(DD<I{6{-kEAInyzAXM|YmL9tn$Kaaxlv8lync
zA%MKZYn-ljyBw?No|q1~aBiF5WK+MSTOl#_(cxsXH&P>a3`HSrR4GCEk$=2pZ|+vv
z<SrU6Pd66F^neKy3~xgNhB0W!6Ysahi77Y31a=~js#8!7!A{4(qQOkQ#vSMGgehkF
z9wp}SmT1^Z*Adcd7T2y?R8d<wzY1fB;uE=np`T&Q^ZNn~#<k}mdSZ%(X05*=;RZ?k
zl1EAoBetpu!srw|Qj?%x@_%aay|nZ--iW_m&(=?vHmA!gcacQ2j!l(rH$aX>h1kuY
zRJp+MZt9>!w6;Z$OP>U-NeddMqY*mhJ!1~l4NkGLl)gFMh_7rC(hdzVS_@-XKN^<m
zFldl|PpdZst=`sFjPK-~-#(l!#c$2zCd?aW=&|XQ`U+03FvdhNFMr~T&W}c0$?~>E
z3~Oi-zz9<^{gGNyl&YX{YdSN&@vPs(NDKQ~ycmDbR=2vA1ZHug)Z0WfjSP*>YrOjD
zmQpCswodAkw5OJT1p^=wx8AqrmtqH8v*4H=kXw}ttE*~i(Q<h)xvH0rXn=`8&+9fw
zf|yU~<u+5dV>63iKYv@X`Xfu1ttgEZCd3L8X}vkUt>=mhVUISIWV~969BPLwXsEqQ
z<2(^fKHYB5p?i<VI)U#oxzZT$w<Z{I*&)_wCoPXeMvNano<U_w8*?HzL&zq_rYxl?
z?eeIGvfX;!S5?zrON1hRJ;AaB^y8a+Bu;g&tjbH~VywER4}S-xCvf{lUUt)u$>@3r
zil!Qow@FIP(gd@FytYS79YS{b^>eZnltrTYHTV+LPxVKPdSyv<&B^pyOfR)^;o@bo
z!sa*s=q4=?3N{(#qP{U?ntu5uGp=6?LnJi0g{LH{FICcgloZM;$15$~Fx?w#Xlo7l
zb^Xbf#>a>B4uAU^^ur`;*tgD4M$v)zOG&_1AKk(t!!jUoax>hLik|8eL=PF7y<wcI
zu`Or@VQtaIsiyHxVSCBwDC@%B)}&Ci(!69qw|(N56_X>Pgi8krCqwd&E$C|4@@2_?
zlA<?EJC@5z>?aS6<F#}v;&ge@jzEfk7545?lE%@MxqnFF!2X4)dP!+D7U+Jdd9Hp(
z+uCSs9why3gKSLc8x<_HV8YWopuOInuo>r&bV01a2+XZy{)lb#$6vM8HOm(hp_SUI
z)6imD=Tz5JEXDL{P_o16?pNK%J3dESfoq#p6p+(Z5u$fWQ_!R5wA9H<iW##KGS(&1
zMxT7_<A41VxI>ZI)=Jl57J4JmB~p`<7Lzp=nf`VUtrOy=bi?RSlHU7iI>w2Po~bv3
zvg6^>+u6M5*r7nONytuEx=P2VZwt%0k}pQsBXY6jXgTCPhhw<NWI><U_Z1V!tHmxE
z=qLGf@z5k5B@|0Bu~~1V!=sNCUc@`nmHa+*!+#X9kF#af>j1{iz{q-}kQV9dica8W
z1S)K8-Qv0mRM?UeyisA1AR&nw18tG!ieN*f{%w)>LJ;I`c_s>YgD>Jo?_-|d=#efA
z1&vJxfE*aerm~ZOv2y(4P>$cz6243EdwRlm5q{4|_@0j6GZVh&;rFbB?`m++<pV0y
zb$<f+p3ADReV#0zjKBG;T9!{qs9%7;g=`U)9ds|itY3`3CG1pLzmzSLb+v3cK=uGS
zv%>Gm*!MKH5}&8zR~f><@NM(#2G$AuNjc&SeA=-E;6_m4CUz#4G`$}?i=B;cnq!qQ
zM+NqzzG<GK-5^p-vIT6gRZh}R?`TXyrGM3kG?UYLaSTm&CRk)Iho@){C@US7PO!>(
zRhm~M%zHnw=YfQI9p=0awnh@A-UOU#PBzKZAXoGmD>i`wLPwz3k=6<J?h8GE2<(sx
zx%G|-2*`zGsS!(DE*V2pE@`w8$MnUU<l@cd;ubk)ZZf)qQh>1s9Pn%c7`Y}Gxql`Y
zxy+C3<_VbRCSiV#T>M;parO*iu44ULo=!;jIJDi6u?sRidmw9NCuHw}94tDpn7a$|
ziuQw6ydP`@%6*W&2b@^lZ!fm@Us==z0~mCIYZnZZ6~*z2d{L&zx=t9h3kt9+?KE3l
zmM$2=P%?&5$<5#e7+P+1Svz2uBY&#{hHn9@Ql_*Y{k`XD7>I*LaHw-CTfs%&^ph)K
zA*TyQ3M%9m>%BY$yI>SiPLY&b3VHZEfOxKi3^*GGz-2HTUV-uODolmfQ2~Dmr^Bz{
zEO-N&;Z3*_-hx};ZMY47gV4PL55T+dFuVtQ;eB`wevdu=AUQA-tk^eO%73qwC}{HH
zEt3~-=^`OZ#1(<7L|6dTP)QJzw@fj4%Mg<m$zkhJ1X591P-P*Nu6==e7^X0lwT?Up
ze5Aq8^N^om7BTpF9<D+B+~z6jfYCDsWoO)tdh|48ItsgB42PZI*@3^BA_vm67|ofY
z(=wSS<;gs8DP2&)v3`ihWq(DP*a>56<ecMl`i~dT4%YUgFL{a_rE=O%m_XBE#|I&^
zM7~sf?vSG<nvj^{eF_RTz(+{Pk5Onpf&TC*<inp~2>b=cz-QS0Ijn%cqG|XWtcEWj
z1b>Gxd<kvv6<h&d!_DvwGVEKp7yc!gGard?3KX)a!JKU-bGETIwtp6hZH2qpI#Lu|
z<4SfuTaSbr0~fIi&^9YL=P-65)>$Mg27%=e<g+6%KxG%HYy)y&26EsKxbd4^OrnM}
zo`x*Agk5Ub#K&<y1>f^XG9`T%6&uu@P;3x)QcVeRVKPxR-&3*+$|QNF;Im8;l_=JJ
z^z|f44VLUZ1O;#yMt{Q*D2Ahejt^!r4s)0=jY9!qa2fgyG86Mm?B}t|rSEBx#z7nc
zJK{3wAo&1x1>2|#5hr7qMyq&=J7DToLx4^)*;eEz?}BLrc4o0-dKb*#5bHG4>?B)e
zaj22Kby0IEoiMvxaVaGoP!St4Cs8oVEyX06IIi3pmrT{A8h^B#MkPZsZ7!S3+69#a
zh}+|`>5^G)k+aTC7R?tu#Uz@ubkW55q)cWRA{v*?s-CiW4h%%avZ3coLsM#p{!D`s
zmH|^)CQN5JP{kaunB_tpbHZxY56)%%A;eq|Wdq@2mXC5a2p(kx@FW`y9c&1^%-rw_
z8wRhl;qX2i0e^pEBjHOn8h&7fl6z+&?eB&$Qg&^`1(SP+*d{5vRJxK~g<PwGPIfhN
zRKQ|*jQvE)ZWOMT@@#>Naeb0!E1It1Ql3@G`4M32@60?56QnF}I07zHu4hWQ9-1uI
zjBW@Say^cmHNJ_;IXg^0Z>36Bnh+>h%s}BfcD>>15`PB|>^}IUo`Ve&cLPpxBfBXD
z1ZCYPsZ0sMW_ELm!K1c!8(foe@GU99&+oo+U9aHZij(}5-KImp9lC{P&LYP=$H`qV
zUqF$g+A&X-va_GHEyCIJQ1MPd#VOtm3ydxc9gAdX57eM5U0f5_4u$Nq)Q(Cj8QLMO
z`4R^E!GB|vI^fhTP=Knp^ygqNaV+bA+PV_6t+uZHXcskZfh_b6SX!RAo^%xX-5ter
z(@{(!N6`f<jAh&|MXr<XQuKvfirGvny&&7SKsI^|D(Y($#kH;xTu7ud!OqTtJS3(I
zqs^ggHENz0ec&3jclD@k4X_S_xQkgMY{GbIGk*p*w_<2>CksG33u43;g11>Ke28xG
zGZu!gSQP$?8gv9LzZG>P7quhiEmlLR)Hn;eevh=AR$@|2_pr2y-Hyz4q3+$mwxI6K
zf_K?gb|<oP2l&{}u%t-sDh2xyI7MZ5sqE*dQHRicvAYjKI%<~VFyzK+QTgsU2pZPr
zp?_rD%kDEgcqu9!IgV|`x_s0LD0Wn%h)5$Uzhf4)rsM!*?19r(QiOK;UbMKL5;U-~
zkEa99=z=p1cI2T|HEUw+XYGgK^ony0yOo+X#?ohZ!77gL)ef&wvj$_udc7RyS2<)N
z@RuOJF2xK7Lo9YVjAmCLRX4&+wh0!oD}Ui^b~ReXpCGTUh3naMa64+&{p<$G1CNe$
zf}f7rx@~Cd?ninLhs)UmWa}iA?c}{m(P$NqO0rbj*n_&Fp=GrI{nJ-#jo@=3V%CuC
ziSuKgcxX*gNf&Yv$<T<>`Kd8v5e{jRLuyKlAq6F-z$?Y1Zq2blAMXKeWl=F17Jm%g
zcbEa_DDtK37W5yt!btX07>}l4BFfS<b_c9PN%FC+ILV!o3X>4xk&w>XQ4$3PtQva=
zC6Oqz)}V|Hg6v`T2x2=8XLuA#@r*-n+itc!W`vRhK{*T#l|7DvcM#l%AtzQIhO~Nu
z?J$hvn<(=Xkk*l?pcnRYimNlb;C~##e5Q1e=VE<;P;S``L9?7A{`vse9HDl|-2<&F
zWA*2CLbwYe3V4b-AsQDJ2cg97L1DQU`k~~X%I;6d;_6HxsAErJimQh!6F?lrY?{k>
zcqa&zJtbY%(?=o8tX0ffd@6|kt{8G+E|NAKSA9YUj;w6kPFRc1Uug$L%zyM0cfz_d
zMR6+117OGJ>UOX=mDL4XKvk*7YP88Mt9Qfs7-8TX>nXpvpv;QJ3yD0o>`STF<}%f(
zI<1%D8(S`-mQ1JW!N6yOQFn2y&JwS?BvxlN>RcA5+5wl=Q3Teq$%(@+E4S^0%eO+V
z%l5oextlVuD^Nx^?nO}Vfq(uki_0b^dI~yW)1{kfWINP270W$P;Id?2oKR04JK#!e
zAL~@IZF+}GQg%Swa@9)5)t&H@y-0;>m2gjUrICN?fNMJ7TI!pIY^Ls_%#N^Lw*>~f
zELgbSmFBdotsQW~<#N`IcGiCMlXeQZu=U0|eB4wg5gOpKAdct?2!A12?u5;Isc;j{
z9~YXfs7b)uF@|{vW3Y!&D<6SM_9(_)+rf*n?q`ofm^}d-kmXmhC(#@1gsto;v>#7n
zY_toWVI7!Y?MAEJ1z%v|`wiOzN7=K?&YojA?0M#9dsz{Ckxgd%Fc$d*o5fyc3)y~j
z><5^ay~5Vw`y%!l#((&)qec1^yOzDl9%OH^?d)wSysfCWr(@LJfmwx}&4L-MlbtGc
z{|VEJJfRCT;lOrdD@RQ3U|pCH3dCnKdj`iUh*f~?!Bz|6wi+RP4)xND(aG~zQsEi+
z4k1N>lWNfd&O_i-*$cDTQE-AqR|NcKw5f6w*Gj75jLpYd=zmdr7)DTeHamoX<mMg%
z4|*`y5O<o<@FNW6=>xIni|i%cQ;8oDtZYPTZ_$DHegLMOEi)`LJ%do7ZpM%6%M=o`
z3$_?~R)#v2J^Nzw(~6(&_@|1W+3`=CoFUDbmVIfw(vF{(T)ep~-GiO8F5cV;x0Gwn
z^gB^&)3Y}`0DlFZA{TxW1h<xFxH5LbPs`Hjb=ypjGksGh++N_cn_4}yz?r_<fESxP
z;0_Y=4C*mieb!c<S>(#>fGsHBS<WnH`h76Sl|fLsGM!m!>qJAkvrxMK)D9zM+j;og
z>dNSVJ3HWKbw%da>JGT8&ZX^!pO<IiaFp=7@n!9Rdw=kS>V7Z2Q1$Mk&M5nt^uC{L
zu?ubR0~}(-ZAo@{nzYLg5|r(_S&kLsR@p&T*{C*+GJQYf%8YAR2b3T?e~W(WUGzNf
zK@R&JW<2j>?Dczeet&?m?2jnbAHYKPA)LWJLYe#+TG=OXKKm3lvOmL3>@RQ^`wSjn
zpTi^UZ-1Ead;!n1zr#NE4|tV*1@Ex0G2{6L<FS9jU)Z<sHTxIi>|17I-?4P|A2yhM
z&q~-qHi`Y0O=E}H9Cnyhvm<N?JIYpIih35xX*1_6!Uem8E3A`S*t6U!wXXx6%3Y9w
zy88>rfWM-TCOyo84>6j18MTF?lf9-M?nS*m6@PUjhdqv3O}hZOsK>9!Et(<h9`-6~
znu7RlMt!eCJ)D7g^Xpi$BJL6PODw5Kfd;e!b?9}y>}>W1jz~jlESB1AN1B|B_F*}?
zoQ;Ufv+ONQ4c>vjqpdg<p_~NQvR|{`K&I5;9neoZf@;U4`ek%`V$4VlM=<<lDtpJZ
zM1SgUhSXnF-q?TGM0$J#im)1W7d3VWA9@tpAS*>z+2^-OUNrMq9g`iajJPOP*az?8
zqVJ-t=)vpDx|4;j0#s~EnOeLP9^M8y_<Cd;*zxt~gD^nK>voxF?}5iwIv($YC-yq6
z*%#jflQyaxwc4qoGFnmjFvV9$*=k)ji+_CYfgLMdwoZ7m19p~K+hN{D)fO9&ZKDxF
znhV=~;BeWTX>!oUG}O*76NWxDCC$?>4GlrRw5!Xkd*JDn9;cP&*cDfXv!Op`YyCj*
z{-E*!Fo?TgG#?11d=O0K1u%^dhDtsJ=5seJ;X~mxJ`5W9a15G8K!A^gC?5qE@PE;;
zkr%@C_`ZdE;9gz??YtPa^RZHBFF>J~kBonY%sFhpScrr+4eKYc-^sdr(W$(T>POo#
zU1nU=Wr#18NVK>t{XvQ^l@3TZLZv@qiME$Jq%c}hY<EgA*Ea(Cf%Py9Vk~cpOib=#
z2f=v|21xeWaMWYS;4WnC2dMCR3V-~Xv02?TBo8`n{kg%+-3BweRyv;PggtwQP!PNc
zn@7v$XXz8|(vaQooU}Z$=kt1`ym#-Av|E2>O!Pv0q8DkR_y)KKbqe?tu<@yo%TIy=
zJ`LG19cJ(uuz=5kQ~7K-lUE=MDicD<CX-}Ml8kyNi6|753^daQ!tf(BWq&$`Er=gs
zI52<Eeb8S*^^yVAzLkSI;TH)&$vBoT1PfmT*}Mi^d`ZIY{6KT@fs!LkmR^y&^8|(f
z<}!iUhn1h89n~Z8^NbUff%zEQS+i$v&$rOqy*=Mb@9gbjJ0$H0^0N_$RY;xHkioqO
z%o=d=dKkbP5~z^~(4PpP7=JZvs*2118O^u8{3!?!4M@*7<J$Ooa=U}KB+Q#`&YLc+
zUu<5UHk)FL&(Iw(<ETSN%SBN__J;exqHL$4<7F&bwrAVotMsGXjjx3?z7Ep)`H;ug
zLqC3D!m2KFRhNvV^i?tFPq$<Fujqe-+;F)A>nNAc-vj$GL^(i_|9>m{;Z<Dt)jC?e
zjJ7sjp@PMU(a8falD=bp+^LvO9J2xP;JbnCNa|sU_przw9(}^s1b(~#uXn;PYl<;%
z{1u%}U?loVJ1mg9p&jss5pP&zC_Ip&-aGZdcitZl@%5TFF&x%QH`aMv7Mkbi*diHo
z&z8tgmK9&A{pe@qWPd#0s*?+qSv($sl$OJx1_C!?m@hDm7w9S%!1XAG3*j31{sg{;
zZ}F`svDaX#2>db>uqz;oUy1Cv3I_74VK~1AJp4MC&aX#HcmpitH^JF_Gn~V3h7J4{
z*u-yzYxrGg0e=cN^4sAqWXCgn3%ta)!Y}!q@N51v_$|K&{(s2tg-`hX@Hu|~zUJHE
zTfPnc&D-He{t$}L!z_b8!us(?nTtOj3$`(>ZDn6bOE(<V`|r}yZGdd{4-Byd1_M*s
zmokXH5$3V4F!WI1a}-e7%1CIwkt6<%Nx9x?W4Y{~`gsk@H$#Pd-PW4tX?m}34IQ3_
z%6AkgXVqP&%6~%G6|ibH`Bt+^W&fhBdVFEc4>0gdEXDUN-ZeG~|BYk6WB)M>(Q}9d
z?O%BIz}qMVzpg1ke*LCoPzStI(gDB4RH|Ir1MjV*P4(aHE!hnMQ(ZJk{lJA@S=XXr
zw1do_Mz-xjyMQqg-;G+d2Mtvh<nw1>B!AZ2cgV-A<$o*oy>uKNQ@1?q2gB8Pq;AtL
z!!Y(EdJ26Xra$nbxS(Q$4l4UEVS6auK<ThV>4<^SJ_Dukd*FRU>Gz1zZurA)_+tlr
zK!|;ah<(%xV(5WkNH@e@M8sY~cd!o)-OK2qU%`-PKPD;%poqU}A~rMuvGFEi<1wf_
zNg_7hM1QQ1{m3B^u^|Rx8<@&jB4QlFQTmH2!?2Olps7Yl^`@=y{h;Y55Fay0JWj>-
zvbX~oNS2Aefwuci`j_a@X8#)8{5Qy#cM`UfM;Y76hSPB3@(Q<@OY3LX!*|0c3-`dM
zD;<B@34iW{zbq<te6|}t?|{D+qu~6l1HOoFS%2$}>yM!D4<LtsgsS{;g5w%)5J^FD
zTDeMbGD?n(r;+)lKkPP^{tSE5>DqLh|L=>8jbcpfYaRc<M+YpgaeTQOzA9IUr54&u
za9KLxo4xY<=bs($?QU4GL++`%QH8%w@@IcTntXwB`X$oi8#FUtAx*x9ar~d=jxEB<
zHGiIgP>v)9^GqpP(@h3X=UI}$7MLRU4LPneoM+3^l5waFa;&83U}E*~7_0UFk=Z=w
z5TvWzfjH;NO<KbFX<V63;7SWH*u=!PpgG&tP-dY-)>?2MT5!c_9pbcP+nm<sh7DJ5
zuH9(G;PW$=vZEW*ze5E71DX7L=+A$ELVtXZ<p<4^<s2xGu^^GR)I_P2J1K~frG7Hn
zvp_N0r!7c?Ohm3fSu}}K2Jj=a&36|=O&x?748ZVJ$KX}+k@&7F+6n)95G-Ol7XJO9
z^u;^jy9db=7s*K7iVhh|4^t_PN{>*<zMXP?gWHb(Ag7W2-|GzTgdg^rc$Og)M1NTo
zWhxC#Znogy5CU96fqY?sVZsU{g$l*O2IE8;lnFbWB+^sw1oD9x=jtxr2G%s2EiDbj
zk^acpuq|&IXtm})B1bF(q@7hzT}>8+(Gc7&aM57F-QC^YA=t&;32qm63GVIzg1fsD
z9D;iw1lP&<)W|>fc)F^e)_2z0yML>8_p@MI!z@Jog{I}a`)gKI7wnyG6ks`^zkAdD
z&I{m&x^o^+m{iiw^n$KD(NzSEBIBJCwnJ;1FdTS93TGCnmr9$-^a05~#F&^4Jt$WL
zNxHjgp}z{t(QC4s9(n#q<i-4B=+N{mz_2dQTuWfb!%*?_T3{u0eC8~l_<umw#ipA_
zt=J_koVHWx+ctvYpHma>6I>N4`7o@xWRMSV@H0N$U{E9Ca>+|m_NCPGE3!7eL!f$@
z0JTTLBlvIXr;&9IgHjaC)^$lkBpAl$-KePJ>k9l<S4_y}5+sXfhMVsb-C6sklH!!(
zs3k=Gl-~vo0F&OL$^pcg#D4*z$y5P*#&ne!JGshHp|w;YvI8*9GIGHg{p8L1a$v81
zz!F1oFKa&E7L!q|^cKJOTQf_!ug`eTf|6Li>8Rr2v$j4Qg@l1Gsb~Ah!!pk1pn*Oo
zIs2n?0p#sf<ZXLWC)*$w)NL#K&^jQl>*?I85lsBKP}Ex;7Ic>FU4MLaI?e+3`thnu
z4Mev|nZqYn%CU`#dJ08zDX`?bnGvUL)1(NBeNx;CV%hN^$Zb;~&Aw<}DOh?NkV=M4
z0&m?-i!CZd7lPQ&vP6|a8E2I!T`o^i#(`Uy-^x{{R%^P~Jana)Km8V<xZbR1tLHTw
zJA&K0GC)9XbAzXdj(?!Jk?3?|GYo18|J=!ij~tBSG(a<qSz(l`WzzczPNU(RtjL}P
znl<W!aoqk%9Nxtb5Y0P~c&UWRewFB#(cvRKp75*z{mL8&XtA#!gr0hJC|m&tLSQbO
zBcRkp1pGa?rB1e2+`v&zPIOBr2qp+qsx|}p(6~BVZFnF_Fn<lfRx03UUXE7eXe|mt
z|HnjxXUtNjrC?Ak{Ma{Bno43Ca>o%9y!cflZh<)RV(4f#PGz~B?foOu`+5CzLh5$b
zqo1%GZ*>tY3RGT?{X@yOKW>t*DY84*hbCg0iBvFuv1fI~B#$Zr_K^hTh@n*aLj=dA
z+;*!@8_lZOZGVT2DYI4!wc3eQHDg5ds~_4`gVVMtEz)ZOu(o;TBk)Pct3x#$p(_V2
zKRROS(R1|KZkw?&H1(=(yB(qlhA24V^HDPSpz9iSh2<=NNpC-r`!)-iC<`aYKq&Q1
z1zQX3iy9fHY>9LIO#_{g1Lhd7uU=lEZe+cgUCgN>jDJccX}GRAInFV;`JLqth*@L&
z*?dBY@KD2c4`5Y48GN;69sI2+Jbk2iwrC<T9rKqLYyJW79{2WG8j5U-$`h$-qfpm2
zPO3-~EKjNz1%IfD$SC;CwC`Q;cs|spe3x4Evu`&pweh^mr5<~SZc-)rhlU}JNEC*A
zNXC>@+ke!x;UzO)&!8yxm+td1gTfhH@V%x%e5hE)j7~S=F3peQ{-fdOn_2=2gJEOx
zPbnGR+ICvJunK!SAPZ2CczcrFJg})KsW0`;&@}Z^=!&>swJot9dQ3tJ{Jl!8)0XVj
zv9SpdaApm+nxF48;FXg^G!!5N@$zQay%#0H1Ai;+5-+`Lapv@yh2&yN@$FL<K!*D|
zQ9&TScTO5kn&}XA7g?%0`64JOE-*QgoLv0DOo+KhMYX-A-~W9q0NM|Fj~6{<lbG(@
zF!M$iNWLMD76FxL0c(@fvd-e4du+eoD(x>Xj4?p2waHE=8h$m-;SM(xcX`t(N_7jT
zJ%6)dca(4kVe%C<{{CGa&=1L^pOQ)Yi5ha21zH7BVnlU9UXZp{lu289>DuJ#;K!Sz
zK|D<_0HDu~)2sggo<P}nG4OB`#4^}vbZRAzmSx-uav1al8i_?(bXz&&7W00&e1OHL
zW$ZTGZC2{?k6*LT+&Hgf;Mh3*G@qBmLw~G&b?9uQ+~gIo{Z1;KQ5f@saQGeGmk0c-
z$JgMW{Y~(@;i<dumq+`y-E6J5>Vez*c#au8=6KB==5O62OQfdIZbT_WxR82q8|C*=
z82u%9tqLM|mx9~MB&K|S9)`4h!zE<$rZvr5U`Pp`;Y~UlQUiX_a>sV-eu|TUi+{rG
zJX;68@JH;T9!8_)3-ZAbIRdf6$l$YE1^^S-0+CY^5?I|B1_7?ES+4&26Jp;@1OTV@
zAkUlSVVeg@BqZ{4PNY*h!YibYt^iCxv%j_BFr!zeB=-|M-D>(~YBeznvH2ewAM?jF
z6{li@=-H*w<0`0>3bhQu#`1>UbkJ*hR1$x0`Wublf)WaHwh|&vLYoYexU*(v1u=~_
zF4cDzy2obCWYrlpT`K0z+%!5pc~7pLPS9F)eGVwjPj3ox;!J=}*LGZ86bnq6+qD>Y
zZYKJVGlDIE29l#anoj-W4Gf-qy5)ek%Oo&HFce59ySyY6>UI9K+=iM2QeeH*!rgx!
zzySPQlCM(URVe!?#04$GTPo-+sQ2#}l;5P?w7#9)9n8S`>Ti`qqm)-sE5_F~PD~mq
z>+(JnQD{N;J-7AYLxV3-wPBxF@)szA;5^Bhs}Y%XJ=_J+n0y|p&z-YiqYat~JXf&<
zN&@WZu1q7TN#C7^C%qtac6jfw4`Y90oHctL26nilw;rwnNyOr3Qae5jCmSTOBn*~J
z>J$}oO!`?Vm8+v~3-_d?R3!o=agi~TMW|E<y9owNtOAE}aqpX3D17$Gfjz#t1Oa^F
zk_2VUnt0Z<OLyLLIr0f$6yl*g*IH>^<ScIlhFG|fS%%)iC5|qM)hE4|Xas-35P3+M
zR$M-0JX+|NSBT$FKm8D3gfC`;fcWhETbEwp{`2W4ke#coGvj~#R^=bJiQ3pZgQSe?
zOr0%^tU+p?4xm53RcUKKs|4_603hgd=58l(Z|=La+c2#?!K9JF6u<|dieno`QLiVv
z(pKd$?Q}WOIZ6~PoBJjGSd)K2GL3|98sWaZ;yd7;YUy~seq2?A;9ZIq=>-R}v9Kht
z)FGtAVVbc9rizTn2P{PplXwe2$=?M=*}f^8v6%-p9)Hi(<l<0>c7Nx&=sbZbK<8jS
ze~X~LdVMF`$9)wOg}L!?74QkztLCb7G+pdEeZ_hCu}#HKe-8K3e*b?xFZ(I_EwFJe
z&C|N5+-n%u*mZ0xTDfZsj=sQp4u6@_w$r?{@FcLt5MQAt7ZomLjuy0UQ?Q^vSGzjc
zjd7ZYonUg+GOV9hk~W%Rf_w{1sX2O~nJYftiWg^<bgei5_RaXG23p34CCPiKJb9Nl
zN*s?mk8F?;MtqNXL*ajC1mDwC9e5ciH-PNum_QTZF&dXq5FP<=Q(Nov!D8-LCl8)M
zGuKLAm_%c-T_nLBaWS*1HoHyD5KVZnc_=Jz-100s5m=+Mw(OE}_YC)iu@rm{fY`;v
ztbu>`0euG^CcilxG%c*uAYniULb`zskcAOc?RUtqS(*xg&*^_1h3Sg)f7O^NJk<<l
zAc6NbeB&2d`G6CmzIOf7h0PRJ6kYfu1b2pRhtS=r;2sOn+ar%dldot!WFKmCJ!ON!
z)bCNs3PySm#U|0Op~WwQU<H*#eQSX)!paVEoK<AepL5+sOz4ge49#En)l0)IT7^lW
z5{pkfP9G`#{(ygSi8UPo`>#Ph%ikR2qyH@?|AM2ci;>G;cs&0-kNmON2t`5B)I6D8
zB?UGrIM<lXHp1g_XaWFfY(Y9y4eh2`3fr{T6q9gPya|CvN!;_3VJJuD0{QO~KDTSm
zQ$8Kf&j*i;5R4amu(-4|+26_nVPPw1*Z?6jiK(j8Wr%-b)ZvvE)(Bs5lWtefRurC*
zgElUnIvs~&?>EdV@I5-nXxZr8x!y(*e*X>!_cY8RN~D7YcBx<3XscAy;8~4Ebxq8>
za(t7}&+HD?=&m)GH!n-H-sl{Nvt6oQAV6tN+1%F;RY(e}y$;`U{Y=t~6x!y~hvc(*
zrfHVOxOji@aqY-q6MNj`<MJM~?Cwimv37Z*b!Z0CJuOey9IqN7(Gr{WXu~4|YN!CS
zw0OLfhSy|sGmEk=C1}A~c7q(b{0R9u`}!-kF-{32NI2if;B+7mY)-{mX^^NVN(2V;
zYJFu2jRMoLAf;KBA^phSX_>#5P|g7sEbupcBq@LMV)tZb4}}xnE4OEx&{<x|m0z&v
zD5`otLqME^<=aVIoEH@ZaMFTtEj~o|{836)TN9Qg`XGYdCtnv%^@-S<sA=%-Q<!*(
zl>&p0=o3L*_fYXg(})!g6<r?M-Vw(z0vK893QES(_8uub@imFInYM7pAh;!#oG7jX
zZMJ_<xL@@J(v!19%3La&6brVT0QTrkF`^LtY`U6HWQ7lww}pTKGd%ZQmKb)awawZd
ziGKJ+>>r=N<BIvhPVfsms$bas*Vq635j#Z(6MNG?;THY-0cAq~|9Wd9?VfGBo&TZO
zx=`BNyT<TuEE5SJRyQ;p!Bo4i+H_gVh`xUpp?92x<i>1x0*?hzw*qW$lHS@nDNZ_{
z^G~&$J>Q?4phApk#fl8d6UsIh8A}Y*#VA)gXe}@mt2!mq+F7R>wig&B{HO+V?eHVR
z4?f}*1M6v=Fs{6d^ypJKX)}t0Ws5Z0(v}<Dsy>~ceJok<uy$u{TwFaer8&o|(sX~*
z2-KtJtC3M6!WzS$vg*&l9#aI;AX#;)F%JarG<{KCp^LM+9N;!h)*m}tCWLn`yYf8V
z<I4-~N!VH5+fZ1y)2wQhr7TA)Z%?UBr}-=~_@&)!@U)SzCQUv^lt;sgoz8vCinkIt
zJevK*#QFO>>C0?qzLGWyqo*YN$RmIH<L{l07LBDxZ2T3g)`==y1Mu{V4ng~SCLOR&
zNxXB%c<WUeRR(QFf^JKuo65%V8Ax(J6UKoa5GpzRqT@mssK|PvquszkWI2b_U9^L^
zZ%iSM@X(aDGGT0MDUwaG#j`^arSnZ^5}c2V_QP!&C5ilJU72bV)r>O{F|&Ug6(^1y
zFlY)eT)2jO-D3W#QKInKnLHpdN67j(hj^`oxOeNJSGaki!Gh=oStX@mnIhNHdML-5
zXc#3Q<+5J`he=GUQL{>O3M>fJw-Bl$_<V#TDr<w8I@o%idaodpI$j$pr0QMABhz6m
zniYNw4@=?&=b&y9FB)6jL9BlW<Od$s5&HxJ(S;viag|_j0j5$|rdn~S6vM-Dmsu7|
zB}J7Z0uSRl{gPeUs@_QH><dG++H>AfsgH3tFW%Hyr=QnZmQi8d><yI-_c{Mi3n=jA
zy8j}%{5MIa{w<PKKt`sXe`B7}D$l<kx97J%S*Zrx^gswdZI2-*@j!phM4^pmf=!pB
zvdAL^<Lu_OPkHKHfv>c<;lOBc&T~Q3ZHl-yv02RsKYzz<w)^*!$3JAbwFf~+FbJ8p
zxx`SW#|PQ5(uqlpoJ|H#?}yL;mx+dW#E-lP_(68q6R2>Nmbwr0YBxXkRLbIN0NL<#
z*t%z6M+-vj$9HEsCF*~E_K)B**9^j)WLrXS7N4;uXDF3>P#$^iZY0RL=}JUspHo8#
z`z9Ov1CCrk5vORxh-Av@7hb3%7qcZI>P?<nSYz>_df9ce2|LZoblDF{LX}S%-=tfI
zdBE15$bDC<F^j_>aFQanuIt!({R&FOP0{-)tCh?)a#>az?(BaZdqg>d&nI?fv8~VU
zC=)>TEU@|gItO*gT&7afv0azvPZ9e7JzHdud&bS;xJHwHQx2~U+YMvO=mZbNeTv-C
zQa4$^J&Bm>xUuRG;rNjhahXY`Xha`O0+dOR1T3j*)85QRnah4J+TKc@{_V)-;DE`<
z?+I=@K1V9wcdLJM(cN*`BjcU3fhHz6Hz|+BjQW9_9Z&OK%n^AGEtP~ra#;36*jxAz
zX=|z<rdl;AC{ymbzImqRgCx~m`TL^1ny^ga?T2ZhXZeT+Pb|AFx407L{9y#`;3LSS
zz2s%p;h|ScO{S@@pV8*&L<TShoXOr<pcy2e$CXRJ_eOuXhMDoVP!W=V%9n&<!HZ+&
zCT8A)`|J?=T}S=csJ~L;Bapqq36=RL%=X<mx<v!yqZZ|dyw2D*DY(>o=-;CX3PW*G
z`-Q6AZ=y=}o2c5`{0Y(!6{9~Tyi6Mkhnh=s3pZzxT$$+ueBC&joLM@3UZUxbK9yrk
zUfGN!mcM^Qd_mN$Yrl}5g!CU1e$uCX)35Utsy6z7#?;1Qsow-P5+U1SS{b`%*w~<;
zm;^1E?vm7=+G8}%Qpc<6Srn{J8})HN-1(TmZ+~6*(0BXuNRW}AVWViyBD_`8N|r{3
z@bY1M-A1Dg_=|gei2|YDFdWhe$b>`34t&lnx^aIA)hT%D?&)&q;=`kiksgGKv<i}C
zO6|nFlH-kO&(-8K!@#MWc72M$^bE9@qk&V%iQMoD-fi20HE8csYL~E|I-GWSnknc|
zTRnkQ;EM{Ariqkj+<MsATIsimd}1>Lu9JW!P(tI!K6v%!)5KI53k?O{Y2vu@i6$HE
zNsxaMil_2?H_;yAbK<!iX5KBHU@FuXM3UNbTTW&AIL*IhC#PVbP`z=L)sySHzOGpR
z)!q84)#YQt?DqsTII0721FCSsQZi9-$R?ptwJKHY91f_*i23)0jB3nld8yJLaeHwb
z-J|>h)SSw(c1Jl28A%Ymtq}ZT^L;~lF=T(FbL@ih4NHad-{q<`rZC2Fw;Ad6MAXK>
z!JA=eS1Px&T!OLDKU~A@76g*&6MLbsQ?qeX@6QUBB}iP!#O$K)pE}pp`;A%lQvqZO
zQ}Jl|3Qy4PXFmKMF7IlRK%`%AEkXZQPek-D;PNm5Ik;Hb+x=E!#QAUcO52&(+d6;P
zfLuW0e_s4kIjTIN&?^MY48bnEq@*JCU^eg%N_Jq5_Yju03Y*E*lc&znqNlfv#QQK*
zfrA+xP9flr3VPC+w%8sR^X09tXH8tcjs3(4fm}%wSDPsW7~s;_rh+%+camQ}jz39@
z@yS0!2=fV08~e=vq3Jo>PF|{baesfk)tmfh&r%VqlRloygs$;t3N-8V#-sDMQdm_h
zJ2OsiypxVnISAz>e4JvhI|t;dcYv8i&ZIlI)b|I)l+%Y?-<3M1Yp&+3kG*0Xr8{Lf
z-$eT`?3bn6aus|Q7dZ2YU)A%Idf7Ucn2|~5rPep!#+&B|3fq47i8HX2Jb{0TGSAQ;
z_vPF>z&lryex0aXP|I$*53j4PzlKN{p2Zj~EYt#}g_v;-F-Gx6y4k!L!B*LPHi^|9
zr5KTjJb01K3zFv1mNbB;E($@F9eW9Ni@{+JRhTG}Rgt~lU(ZWy_hpp<J3%*3-iao4
z`7K>Yc`xPfIoSV-Fm4VB0l|L?^;;$*^j~QC=l<gFMa_zzQovLO40f${G0Dl=!WK0j
zRl98YSK8on!iva?hFLW2yM3h6H2coR+GOR8!r2*wj~N{Ri`p$)OR_~DW)4;%W@cDh
z^P0Nv{K@;lX{ttX3c_YPEd(ihk}NuzuiUc|A&C?r`RV~6K{I{cstbR${Y5Ab^Ke+o
z_F*<d>8oH%b6uxThp7?4EJ+9nGU_~zv9l)eqJ~bICREx-_o^vPN?={Xl4|-5#fyJ$
zlhZfHk~KuVjrX2pi*sg!1Z7gW>xjMaKZSjh&IM<P5!OstP<-4hZMd{{UB2MonZzQU
z$?!+T>@wSKmeU8g@Na+U;l(fe0pnm}EC^u|r;7-&>?@xmulZsO`y>XyA+Q1auLl^V
zgF!Kr*TbHyGZOdiq*hO;xG$do<-??K0p2PTc?9<R?&)3}2;SH&D@ODKO$&F(Gg{9f
z^RfM1!{+fF-8?@zm|}6L9KU$)43h1Wcn+w=GtsJ=W$+sh%DsPv+$W^Tn>At-`|M=1
zz!I5Q$~a-L#MwTH9X}!^$fjp`^(`-7IBkEtg!?@ON^Y)RslO=5`ArJA{sRi!jBG4T
ze}5Ix-~ZAH6Lxb#XhW|ViV4l~($W?>0y+YOoQ4)HMGn&Ng%NSYBqcHyJJl*dpX1LO
z_+S+SgX4taxg39XrzO83d%*XfuE3zhpnY0STYh~qb308u&k=xLlBf^k<3JeRO1NT>
zbrw&r@YEaI;ptN$_RioH-GXa85IFnJQp*nxX*_sC;@(H%PC?q{W9;p9yMKZM4&3ty
zsBMQ9?qv|Q8*)3lAQF{0=K#AjEU34bw{6et?n&K23pjsKsUCS^UvJGvZ*!%=qn`P1
zDNOww+IRNt&moLd{-(_+W)ZQN;(;}*6tL_X+iddg^fGSqHO-cJ{>n}fI}OEs$V~9c
z)_pBOv{vZm@gySeMRMTV^li)@v9j{8l6*U8N$!~KQ(?6DQi^qiTl`o2hEn6rjJuS>
zrOWl}LY#l~BtB%&As%)uRR@?2%$9+q``Seg-uoc>l2R0JF<GA7-ihV&eJ(0Ef!o+-
z+Wu3?CR2!drU+yMG*+@w{5hGRYzs@uaCUL2s5>=J<RD;N>oIKJtEeVUUo8EU-qayO
zN>{766uZpvjk=I$!YH5~oAq6yghoo#KHx~qB65FlDQ~+Cp_ORFd|Cx5c|*HWsi=Q3
z@ghykJM;qe?dwI(oqFZKoinp<&O9y;dx57(gbnE{ylso(0`veU>2p-g#GMXb=ap#*
z8)#}rWNk#vtANqiTj=<#Qe5HvEtXCs40HNczDm^}Pw5zrWH*U^@n`d!<qqF}%AmO2
zuYP~i($4(vT}VaW8dDg+?_NKV&h|yadak%i30+#n;T;S*O`sHF$Wo{Vv`@l_nbwe<
zS+7~+Lp_}u0``^ig=Cp~@eKB=$OY*8Vw&?LXn$ym@dG5^U<b`;siamVsZd8CHJ!MH
zm=?vjbXIET?9u*^7)ljO`bF(e1A+*xw7Y+3BCNi=k*ZVsm&jG(q#Ww1Q)iJ1?&V~S
zPiUQNKGLaYRP^o<!ixJf;*2|!XED-ZU$I)8uA6aJ+^xhsR+v5Uc%z%%ncABsKwFyJ
zhq?poPekL(XyqqQwc`oeF+`^hZw*MsOJ)s3Fw-Z#7LIA&%EePU$#Q2@EaH0XE?Iw-
z8YVkzvYLyO{BTPdQ8Q({Yye8xzV=#&IRstozBayRn|$wvXuBX}02D|yWfdt~J~oaP
zlui>w6^yL!*Y5U&RTn5}VbOylz*(Wpy*^JB5U=$MoNc;!Fb|gGqt4skAK#fob2ZcM
zr>EOuz)St1Kjoj13hTX}6vq4w<#~UbJd6qFGpzY8%Kp$cv*b3{f`G)`h?lbtXjAX!
z+85UD)C{e;JZ#@T)V(h4KQ(fGnGq)RZ-K!5pMoIaWMumfS(GrP01!qS>@s_UEur!9
z_U#?2nhQ)HIfgty#Mq5Qo0Wv7S#z$fVeF7e-t1#fz5Q;F&32E+4RZS(gg}1)rHT5v
zg<+O_)Tf$?ijzlqbx`Ni(;a*_-V;W(2h|qM7<&qA$^b_7CkIhOK2=NdomQE8DN05w
zb;uuLxq36wW~Ro+EOr$=?wh`RuNTYrG)xWX@8g#N4o|$UkWKlw$=zDO_f{o7OG-!C
zHvLIyNUn*s3Ey0%605nxSOR|@^AvP@tUc*IWS2@5XV@pf&#xBqu*{2M&nKARN<OZZ
z@u}%{&7DBa`3@Hor%2N-v0ElJd~Jb`|8e{B5hIn~c8OQ&8vb_X8n}(si9m<rUBWoL
zx^UJ|)<{O=&{=z}euF@VCHEYG0RK+SIE(rOPaKz1J4MUx^BT6+V{Csk{MsX>raGSI
z=<Wl1w)J2Qmc7^a@xEnHB_QoV%>-TaiV~`U1IZ*<A=VC>3+~f4%Vc7V@;>AqOjh3*
z=HxBPn~l|SN0nFw!(=K*3M#y_uSOU+bWKrZnLmIrRfI-^GH?ovyClm*+QV{9OrZ{J
z^4vy_IFH}f4D^y6bbWsu>Ql!Ye{wSvh7;cCtgWNG@$yt0xgEd6ZcX;{FxViHl-t+W
zulqjM^#@B4$})x8`9%`!Z(0ife@fE7tZWk2f1hn3Qyg}4sp&65qPij$0fCmv^vdus
z!ctVWVsRlt^ey5UrqU^`9Ce)ZeAt@t&EFtB0KpzGhJ(yh!D4?<c9Y*HC-3(w_Y^k;
zykTk)Ib&rxE~)DE%(Tsyhj(O%G-0tZu&i;})G`mLyp=aG(G+1atpF4f;9`=X?DUtq
z$7`>$r)qMhpF*K4e1PE=PJAd0b}QNd&kv!;mgmi7+oH=zrFFZK^u02HbKJB##TA$V
zUcLbL_QgxFPCkG2334k!>YcJC`s+a@aDPQ8CCl{L5Q`0^zGvZ$pMg3|qh3z50dZf9
zyP+|m8;xjkpB+KgWi3JpCOq7IK@LMy_oWv8!jPQdQUtGKj1SuNc1pRWuc@c;6X6Y_
zO^oMrg%;5qaSfhWc=?R*L{ATUihRlm9Vg89mxE83&Ch?Dll+#uaU)JAPo1_+FQ^|n
zxT-T4HT>Fu97fQrSDH{z)~VtF8W{?zT+op>D3b}3s(UC4Fje)sku6g`avh3o*iyDS
z0fhM;T7~Otxu~*SpPUFYr+@;?&ZmZhH&p^o1xb%dxd|#?;j(Z;+{dVjP4RJR6N(*c
z)8pSMb3T6}Qn#R51KJe>tf-s0ES_K)ObrLC<h$i#x3kf|-@_1;n5+%Vt3E*fo+vwk
z;FE)2M4|sCQ9S>aC^<`8OPAkc1TqDg{zF9lp;UU|u*6s_%!6l}E)<fbZjK3lPo<|r
zQ`i7W770zweWhZXV9UhCQJ2*lO<U8Gg@{3gA;NzL!Pvuk0TsL)Eln22<*=NUmUV6}
z@pyJ{Py=CCkkYqsl`&&cXhL+ttv8ov;**_#jH~}?51$*zZNow*LF&@7h+(w*=0(*j
zHh|w)s}#-`;4En8Xiv-{xrrLP>C3#qY|7VkJ~(g6YU-}H8SRccJ7^YZR88ap+owHr
zJ+OZx+(q9Dy>U~j;uMG??SPTbM?E<(wHCHjjTy{;!Y#NZStG`az{4nJ6TV3JgM~sc
zeov~!XH;C%<<@Vp3EqB5rNM>^!^U&%Tzi7c<$0s=qhUPY<s{n3@{I^oLv~o!4+l2X
z=n~E#;U#or&6TQ24kuL=W`H8Dtspi(`o4d1FH7HG)KQG+2BmVvci4CfCDKbRF=bLY
zPc>lUi#at?(+hI_Gv@b}b$+6s)Jn^>=JYVuSMn|oO4Mo&Z#<_<l(Ylr67(Zj)o8Z}
zvJR-*MD3%#XKKqJ$G_yJe>$8$N_l08q)(zAja_ws#5qa<jKPP<XVtm)&=vb3#WR0b
z<izp6ry-U<KoLGiAE_p#jfI3yiz?(SwxESSgWMvoBet{_b!uh_YJx;Yefz5PqdEp1
za|5beOL-7chNK9<@E+l|O!r}WJe|Pc(fN*Yw}pF8GvmSvp0N+4C%r_MJm)(RJKUM0
z1XBOuU=^A+f}*LuxWf2*DreI4DHwl#l}<1)|6lp8VDF*|vNJU@w)uySJYJSjR2VSy
zI;X){lwBp+;oh)EVGxc+P6TgBmt?osNWtE~y2d*I_qo2QDM9O3N=8iib2;nMG$3X;
zPd*)FZr&^I@9iAncJmFASqS$A8(~V&Md<)d4sV)iGgV^RvXw3^+#>_dn8klMldl@c
zTqmj3J;t6d*B@8+PUuBF)TQzkf!nHStOui?Wn<`8w9gQ<_0lGpgE<!9%@0T4j@;7j
z@wuaBd50%$MA1x>hJKxCp#Wc%T>!CJM(J0;?%oqWvuQG&ZGUD!bxrS%*54*iI(ZtK
zHFnKoIUVDkzQacf5}Y8+ZasfqiF$ZRr8q~n$4x-qm<Iqx$|H2Y@%FZxl*adIv#tcV
zxul}88u=T2e^mrY&Fd4W6=Lr_yr)3Ve+OHNXrz^-djt@|4^*3Ti%?eiDut+oLa7>S
zi0Z3IIS^J;9L^lXQ2tP%e<*?aO|#>W3~V%j_Zg~7JF;KLsy8B01B8D(uhq88Dzz+A
zJRAG=1za^Z4Mxo<ZS?7@OlMXdcvipq`EoV=hsNDk^`mmkFDJVD&6Z8%-)gS;=fz**
zi`v`SflOTf!I6rT+7$YP&@$yS#ZuefP6tDg;N^D1zE@61BUefal%$#&&<=q<Kv_2b
z)>IltbqB#C5D=RyUWtF4SD2U9mX?*Fy?%1=6Vac)@_{N}y~hcbHrTB9v&Kx=j+m~q
zuZvKwiAa^X{C1Kf8CH?rgN5qzvu%|km3zZXwJepLZR}fvDTUN&phaJw3&;MQTr`=o
z4m7?@WrD+&VE#e1i^w604Igs#LRM@0funIBz8j=qu=j~+D0zQ#YNY6iDQaKdj<lb^
zCgoiTN3^KGy!PS#=FNI#Nd)X&@TA{I__I?>G-_641(ltvD8JApA>mFeG#tL9T{=YC
zTvE=_6<8c`cqf!3w``%<mLeLh$pP1Sn2OCe^E1QH87<aFh<`XlNw=#c_@zY;<Zo%g
z@$a>8GIDSLnM!{v{{7#lqRR*^40tJCjch#8DF0s8)Yy+8jZTU|LXM1DxGmjits;8H
zwo31d4Il4u0sTbfXqHmEgtmOjZ9eJyiIw&7;pPd-5MGtKKTei3LK$li1E^>iNU|rj
zxEI4%IL4$OZ?N84TXQytZ(uEbkns4GxrXrADw>3T_ojcUF9VWKS6N9`%KAKajzY~_
zzqxnQkP62a2Wbzd0%?Zca}f7|ws-IGtOD;g=2Rz$CoRI|RAS*KSjUg8;HAZanGT%x
zLvcOD^>lfHLhzBt+CJ-1S6?!Y5%9_rERgRK&a@kb>5EY&x_m>>Nj9I_k^?<Xn;s6J
zknfLYnhAd*@9Xuu?O`f>#&6VZYHgLs(;7h1caM4rc*`;xR325AXX8&HmYy$Nfhht^
zdX!Z(ELxTnlW~q^`p*7Eb1ok+2KW@-87NRWi?|Do#}DmaorFA>%o3r*FLl~Im|xjB
zAcGpV=Gwp0+ENBP0dYYhmC@($cKJ?W1Npr<yVZX#;qT?uk7SMY`Xw#=|8`dD0<v@d
zgS`KPHUDL==&#c?Cy?{+Kg9pA`WHB=R8JHzg@OE{pX}%nE%rzwbYSv|W?>^D^kI@@
zjaB3uR$yLIEqT9<)~%k}1!x8|G2w+JSUjDG;&v_D!Uq)3^iyQrPo|xJG`m?mx8H=^
zy`X=Kfss&;a@`Ub++)cjEg~h91QamKjq;P-!_B5gkl+U~OdN6XFc%nWh${>bh`RJN
z$os{UB*=UMCSjG(06!uY(;F<fkM;VDjbSr~2dZvqgtry<Bdh!nOeN~m>v3$lj`fc1
z+Qb1(m7Tu*fCJZA%Rl#--)CUCs--v4uxft<4=Meqs?A$7sTrh!J6on<**M(S&~)8h
zKk8#Q%&}9fU-1Yz#Ps6sh_o)Aqv>XFsZ;QLw<0V)@4Z|Q5gHt+uwE7Bs!D|N<(P-I
z!lF4w0Q{LlU9-$kNqc|{IhMI*3w|Hhi9W=NBd@FWwh&u*SKA&bh()A{>pjB*!=8Vi
z0cTaY1MbJs_H>tyj@=AnONyNNxX?T!;jd#m)Il_;W<N*3$%zb+S_znRta1%$h6A5{
z7C+-*Ouan9vYM{KRYlMnG(9;(R#oV!Nm_X+WV$UnxZPh($}7sCxBr}=7?1C<W;dGq
znIVJ4FltlCsEoW9Z3e~#Z_S(WcBOxw2LnVu9M_R~UNx2LsYp0PcRJmlKqM;0eDxLK
zIg7fP9Kozr?D+vvHRDe(L|mnF=#LM~&)TA}i^qXwg+<Wr{xq)WLa^<+PfLm<IX$cd
zMEUFzF&V8Y#;K4?VLa3<0_O-eae3c>CN45hNcvuA=#X3Z998DyHCl$zF#3PPtGyey
zHF>J5zZo=zWh>H#5yIo}HfwRvGF<OHUcIa}ut_?IH$Y-Ej@kGd!!m-S^g}ER!p7qt
z8h6<o{A%#8IMRdtEgNL}x2%hS%#2)ZT>g&pWHovBRWU$^32%x+66#uWNW(Nl(UKzu
zC&v~UgM2z8lk1#P2?hK#k#>JJg%#F_R2{V-EcU6tJPv4wV3@nsq$hU!LL$YLKoVF#
zJ)V)~e(vSGiT`|kYu^P;^-URy8X)P2`7V4b1*kz@Dbt)KL?Di9ZES$k2ab}*)$M)a
z3PATJEg;{TgP~9cu(@MU?Nrw`zF$kM?L+G-%V_nABuSrC!!<t9$YOt$OL9%L=Zv*p
z+fcWDb4EUvQjDj*@O5BiGpa?hwa=lzW;wKl(n{9n3b}?m<tC|(`(=EuxIni!arIm5
zLh+WJn|lOOforvLA-yg?MYbGI)D|=0@xIZdb9qIz4gi<JrGCc6=iBv`L-2}s@eeTV
zZ2Sf8z=4_KQ$;z2g1diBMbV-sztmNu>XuvNDpHw?w%7<R4Z5aY#$99@G}w_b1A^Fv
z=YTWJZ+*Juh=r<kXHP{Pxnq(^!%_Y0NdL<gqR(C&s)%9{tC7(w>_SIkzIL>|Z1GNc
zu>|ven5hGyYzG#>=axR|##5ave^a8eN#&A&(hQk-y{D66D=vSZ%k>KWt@M+Tq00J*
zdr7sLh=m6B&Z5ZGk_UVXVPb$@FD=G*+EPQ!9%yE@&tpn&JH(rwS`wBqNWGlk^m`o2
zK6HO6wwn)8*kS)7V8UCK_LzLUeHj%v^_ddv^G5n~?~}QA1+l`<RGhMzv+ml9R|9Y$
z<3&+$4S)|o2it!>#<a|cD*ADWhj}*?!z9Q+Iu?5o?5VD1u#TSKu^@2B@Ke7)2)tt9
zkoe#!aC)D)dWnUTl_3ChA$Y($+9X!(tHCc9C3N2!PrTrO=bC8}XN)GsdTutlux-WJ
z$o&9{IChJF=`dkajhwlosd8ddm1bt~g1SM(MVFfc-g19z_JHt`W1y?Qv4?GU#Z>IR
z@0QILoP<8$`!+C{hYI+L1nRw@SY}S&%s<DA|J-952|WVb7<A3q=1&jNB)@5oH7N@v
z!*CEg1Y5?EvBC^p`Z<ihX?+q}#5C|){(x?DM?}q%->Wnn#_S!MtQvKiL)z&FMNQrG
zLuKeow3vTWLw$sshKxDZPYv6sEW;<%Jf-<Dn@lsq5Ek8{lD4mjTLy7k*)?ik6ZxH5
zJc=QlQ*Z4B&YMKoxPRoIAM5f*qaouN837Nolq^s<y)Cla2hzMFq%n5(e4i9h4Nxv3
zg`v$mT%}g|4k7CxQc;~IAGycsZOK=gr{8%9vN3->xAp!|eLlNn0(9-Nr*^-KYoeOJ
zvbm8YulFOR4y(I*hM~S;HJ&*TPUDTzQS>Ycx>VTl@&5LSGv-juMSb@=@6*Jk;O~v(
z1yNt@;8)l>!2eJE%wLS;FAkyta&!ebyZrTuge-M^ReW`zZ_23|rx7%pH*SDTMRFXm
zuvmXjFsW@`Ak@Gc5zB>1jLG1Txarg4<K%a9@4jWtO>$*9^6c1F&=Z~^33h+j^#~9!
zPZS|;QG#=tY&*Yw<g@4SBY5$J_(teWBu1&i^E=YcF}RXwiQ`Fjv$5@LaAVuHZQI@?
zH+r$Pv2nwVZQD*Zwryvh>#-g`Ox4U(&3u3Ocb`7}tJ8fBAkb2n8Vmu;O%~F#7~UJX
zpOt=Ox3*rFiIMbD>yt*|jfm$sPHM`d#LZJP4xA=yb-`|Wz`^pse$xGFnhac79c(Y$
z>Y^S^d=qSo=nCC(u&%UF+tVxt<Pbe(a>e%s8eJu4^m=vOvC1q3T5Yd8xPo)t9_N2C
z^1Q9}gvF7U_WN|I189N;ZDVrC52-f8HWgU!nVu+!dub<?;gxSfv`Ow9qE-Vd!*I(U
zOg8&0>LbZhYK15E%V(~(d77i-rY)-mVF<;k>nQd+B{2!9K2-Wx?xVd<7PL#oG+AEi
zBPhkuum}0~6-XalsNfoB7iQ(&X%m0AJUeASe)^W7AgruMsMS2DX-or7w0Xo8Fb$z4
z9K!`E&$X8cZnnVt)@M)_YR2)owkNYi+ex{9mH;&>EY1ltJ&z6QV0Me$ex>`FFlSUT
z6Ut(Z6_z(!%TSX>BjYDi$=+?32VCp|bz=x>xGcDI%58TrMA4%@+<n8CyIg<90Q@~}
zXjV~aM`9ceSaPnOy`E?^nr!hs)Hz>d%eO<q-PY!v#`=q&WWmF(uXC5!8^sp+@_vlV
z|H$lUmzxs=om)2}Q3vbw?lphkV_RL{nPiXXl+qM4syo@4iWHWIeG_+zgpl{_D}9*8
z$jWh$^ga5V2ER^Iw-CN!oHT!<e4pL}#F)H>To}>FKmvy$F9b-T^#B(Vyq=El?{LX)
zWX5c~TgRb|BN~6YP}X2sYWpE>vXm&am-uGW-GK=!QZ?LM;^&M@!%yzIZGgA?!zFo3
z$M|x)AsGmoQ2!F9Ex+v3j6!-Ae?;*J$>m<)aJ@q7Bs{@G;FwEP_49vEn<qK(e}NuD
zQA_fb^6Mu;JO}Ob3uBbtgTGKUc(%g*?v5Ww^5K&?L--Z{x-7fg{(_WtH$nT2YCh})
zBgV2TZ#}fZi+}&Ht1DXIA@}4F%yJhe#Qz)OlF)D~r!mJ)kV8;)G+Luo%(uXe)%vyV
z=}pHiFYIolyLS{Or0;)RF?`WD?IW53pxb&0m_cY~>;id{%F83X$1U%$ud(ofTpJ`|
z-r&1l@GSW-Fek6u0-~`oC<G2Pp{ZMiCW*f~==^#fDZEskXxP=snR;|k^9Qm?o}R+E
zx{C2DjbzK12My5LC939nPL8)`zVsvo<62yzN!Yk9-WsYl?`nUfDzu{xX~Ab-dMS<k
zv0nBpJ0xxIcabCj>R&|?`hOcqr2Z}$iB^(PfM7z-CTWJIEZHJux^B(D=9nR+0L8_{
zSqk^|L{hEC(^k@1oksXg{NZSo%t~Ha!5zW}8=g&2*7F<i7uauPI3KpU14X{<LkCAx
zS3I*YL%&td_Bns{t9)EVd;;~Otz5-N)ZmBUQ0*jh1o8(e+mJZgnvh3BN$dsPq|8xa
zRRW9Ea3!!C0GNeeFOrV)<ds+~pY&4D0GZ`p>MFu4%?8Eo^2UkDLgegP(m51P{adDC
zr$5~UG!b7^*xK~OO0IPzaK{RB4>RLOA||(FEqf=|g2sR0a1oRrLN2-0>Q5+=(-&13
zv<-RWhwEFXGkHwDeE6|o&tp2Y5=1E~t_(=u+e#Wq6jd5=uy#KmvEwif`@c$iwleHl
z8RTa5$#Gv>LI#Qb9Ia*@xIwLhSk*GKh)^prYlic}xoC6QSv<}O9OU@J>a)W_yVURa
zDiY$a`09T@F0}uPksQsO?S6+yMiyoUre@~9KOg5`AeYkr^gA<Wxj()V{o|XzXE9AU
z5A-FskIPQ;dR!@DS|cM<^@BnR8?rz<m|aO@vnnAPS{Q#vT(f$fFs3p+Pj|@SirXLS
zoHYsTa;u-eudvC>;z=4iYU1n$WEI)%6jZER%r<}BI_f+ob!MRpfAFyI(9TLXzu)9#
zwH$7^OmRI5#CnBj_}=w;f)V7?gn2pT!=E}T^Yd42!3jN`r7=)@utP%@lR0VkxCni|
zCYQ=oieng}&1UG+YA2RBL~k$I;!w*(GNz)Z^q>mE&5V;_fVwt&Q;%EiBq@Av%zP!F
z+IN4)@Ma4Gdeeo$w&!o1I*)Pe?LO`$Zz7Qd3B>8>t6img|H{*SC57~(MetPP{}7FM
zSK)eL!Ptb~(RsQh{($f+-KpApt=b>o9G=-s-gWcV8F1fwZ8OV!&c^S^+qqPI>j?0J
zHinZg@lfgfr8FQ=`eecNhE=*16yT?J<pY2Dt7vC4@TkvknB}e5`z<BnSF-mn&<-7j
zK%C`=;=nKJW=ch@WfuH!1TiRMlfd}4e38ERp5ewCO?N-hT;S0Aix6Mtyb9WOp6;Nm
zoGXm#U6IOiX7*_G(TJ6Z;eev4BN;O%CLZ=FK^TI{+E2&Fhheb8=AUh(xZwyX`sIIa
z-yYmAaaIYU?eKo`Eus++Dm#VSOb&Y52%u^vvoS+O%XayCG^I%wAl;|7l>a6S=>O<H
zc3ogq;Ovqd_`4a7z=RLf7ylJ}%7+hPpReuZrNo!Am7}+U-(JsNCZ^DHFw=>XqnwCw
zHZ%9GL$?7kMN==Ci7=JDmW#ATW$J$@L40yp(JTpJ({)ld<n^A)ScBbEzTj@nHKf_D
z73enRU4A%aTL`}(doFXrRr>Hkf`XK;vRzU~(t<iDth)-ILQ_2;o7PeRu`yVL0&d{I
zZ6w(?k%*F!jnBc{_u?@d=N}hyI)cJyBE6D!xBrmAYxXO~)trP@EsB77u<n2O37ixQ
zz%5Q~!>rt^B5poAY<>@8GG0T~o-kQgjIToi`E5ltn{kH~q_9IdJ+CSK#!rtLTRo6C
z?E*|;HHh=OU+Z(OVaQ6GcZu(FGNHCOg-$OmJ<bFfudmJt*3Zsy*`sNi(J;+zXQyS(
zWQ`oLd|E_ZH$6&VmI`qOzJY(OTN@1s_fZQsR3b1F?{iTUGk+E~l-u>;TSB(xlGG;2
zT@JaEy<DXrz{hs~g0Z`n=9W+VyVOT?P7)(e%Z%xc+dBI55`mKQ21a|Iq}<*^0;_WP
znLSIBpC(5FgfH%LKQA)C4M32s2Gq^AvH<u@%VNVUC9E%hrAhg0jeCCxRg12&{bhvx
zRJBQ$G){LW@LR22T}S>I$6Zj8gBg9DVB!Aua8fu8)rq|GSnaEHQu9h#pO5*d<Jwbt
zz!)rlsbU#&WLC%04|E6`il~9)DjQqsLO*{!_T2U_M`<2FYk>8_Hs||_G*@IG7M(oP
z#JDzi53D`&mwDY4^@)FN%tg*Nvd^Kjb7{>p7Nfcb4UVJsanfuBaf`?j!hztUy1wKH
zT5^ck;cfS4z6XIJKDpT|v%!(ZK@xrMoQ$!BiVb9u8X~9(<LP3kOVZw+l44J++gRXY
zl<A6MX@G!y-P{f`{ouO-F(`6Q<%o=W2pcS=pBb_iaGs0ooUDJfOsw_?!cKe`(#79d
z@|;K$*_`uyj%6vEHlfd1ShSSC`vmfS2Pk$~e%Ry-t5WAnqsjCuBU}zau`1CeTkUWw
z{cgHG0QRxT<N&O%5&_o1p-K1WsvSprs?H!lvPxmIzI7QI4Xab2W@$Lk3Do_NV|c#Q
zPmMAw8rUqA>&btV>-m~qdVE(;(4VeJw`l2sPc+l7U7(e%omQBxNwLVHz&1mf?%}Uj
zQ!r5@iZ+27iRmqiR*@eKQxT3pGM+uqc`&4WT+{3`6T6?8p^wG^*E<vQRn9d`XV``V
zzR&~mBCV>Prv56Va=JGH4n|Ft0$4O*DqLy%)Kxmu52$}hV>5Shn|8!kpvyMyTT^Zp
z!7@5!QURI|8l8FQSXnS(?XTl<<N%7(*u`4*iaZykK{{+sc(+1p^eXMnx(Y$e%Yk28
z+E~btHbzG2Mjj^PSWdPevU`MHoVTZSOLUw4^_!KY(CvP>wKJ9y5%QSc=bP-RvuK|R
z3OE>z=rVs8sJN8s#JiuWb&%tQ4tCV~U2%w4JR0k}x#VC`U*`FjHZP!8>Tg9z$tjrk
zv7<R8t1TIBH;{CF%CFJ;)b=x!qa7h0oQ3Ay;=bez*BTE*z5<h7s;r;>BFkJsVGEy(
zMZc7&qH^vVPLh(83gB!lZ$T{sJbUIUZR9eQ-g18@+UGt{dV08|-`U1R%9k_7U`I8E
z@3++Jv{O;q@Ke6-iQpUu{4OAhf#A~6$6FWcOdM!O$Q4SzGo;tHDwYxKChmA6bF$2i
zir}csMpP)@a0dHBl(&?a-qv=Ix_qOyQeJyew$mPYC^46wGL3HWr*L$qg89`|WDj%g
zmSTUbzOO0#g)c2yzF-yyq%r0EqcOGYY0So|=U!}6A3R_&%M?#%ozp@NLX}>I*e7e<
zetg_Y3u^F^V~4BEj4t->5}%L&?|7poGG|DC452A$i>}7&16^*mxQLdhK1tNxKVq{%
zP=-%=IO(A`H_$9QyepTO)sWx<QZXC@yB~kK>o=iNp4IVpl_aeRcakU_X?GVSK&0at
z5+K9z>y>=U2i5Flx=5Ybwg=>0{<G7^PZ4dCKF>OXy%%2_+nb?-Y23O`du;(WwtUZ-
zB==x%_}~N+b;uK)ELW^vQ{AiHh@CT9PgBI*dCVsn!N4zO_)rpjWTR7pJZ3OH-OPVf
z-G|Iij%cIR>09Lz1h_Sra>IffQOU5T@w+;PxKJ$#Ct}H7-kDyd`(~>6!I!FITB@*_
z;tMP#yB^`)D70Lmg&>)Z%_@EN$W!`E5d^xjbBBW)XMf&Ghb%F@+Z4s*p$G~^zoZV0
z>$qm2(YBgrR(0--b_qqb_Fc~80epWqJI^&r49sy#2TvG`4PNzY0_zD-&)AUMl!+Um
zjr_Ihxd(b|9-%&5f{^aeA%N1gBVv_nGu(VlsFLRzQPc_PSF|CI9wtcVOV~)q6V3%N
zu`YI|C6*<Ve*pOzUSyYS-OqoUxW*Qs9}9vFbxchU%MAR1Kd~h=78AQuOf`QN7|Pj(
z9<kzx(nRAibwUVvS)m>9*z?hqQD|zUVcQ0gbC8*HDGp;MLuixoa+QypfF7?Y(7OEi
znObMHovo7>H`c&crFE0vx}rhhkZI@`_=yI`{}jh>c1_1Ntuj9PNlUz@S{zA7d{h<~
z<f0!Ui{Tqnb6y9(wAB(O4M~609(EdR<HF|`%j{i#grSmH>9}vj;jJ$|r?jfV>Vgry
zw1zwkYC-0?n5k!XSoQQHq;rXV3~_ZV?wa)Tb;(8M;NVz#wwM8a)|UGXiYtE&mmo?u
zsU|)7{>(Qu;4o$Bt(Of%Ff>&+hDp(H_%%{Ps4ad#&pY?lWe>s5m1Tb%4YVEg2(^cr
z?R4C|L%|$@WS5bg?wKZe<x}|sVt28eq7-0m*V*Ce#}#;LkO6i>y#VVvqm4n~o3C&O
zd{JFUE|UrbK8bJg2Q@*Rh~N!3s3$lqm>)C)<mLO4<+;SZ?3@j|%?a&zI+HX*TaVec
zTz;YMHXT6+*n4H2AhUl$NY(c?p6o<;B(H(%v8q@3R?Rih&%ZIq+fZ=q$L~{`XS`Tq
z!O!4C+?C=up&5QxTA>8_g1ly<<pq=K7=Q6<@X232&C6WDIQ1b_Ks>@drJ^w#IVZ-G
zZYXzrjdk?1DL;QR&vCEo8Z_AD3HfNm_4BgGjnQvwQ7PTfEZ%>c$(9&W`Wyq&Qf_kn
z;p(0%&lf32IBax(P}jU5a;l~!*wLAQ^y)c2w~?SeK5Ei9N6eUn;hl`~2ET~h7X9RA
zJ_O^+)bV=dS@edLdNFl_`9$k-%ys%x2WA|1O<KY))2j`+m!YPyEU^ZoYkXBCdA%7<
zEK_h4PwXpvPB(wWSGn5As*brmc^G+`x0IUC;E)m+-qJnA&lIWOQ>s_;{q9K?DLr=R
z!kTEWvT1)4I)>;GKf4u-^+~~{+hxnM0Xo|)dHT@mNsI6tlJFUS+cW-3H}{yK&N^F+
zp;P&@R2E$LP%zn^Fsjqn@a8z%EU55e=<jY<bciEJxhsE$Z@Agc-Pp!tqr!`ZL)}(u
z-!PlJYF0^j^lDpAwI1`!>jNHbWS=!0NjsHXx!9Xic9}GKKD%q#999RLoyMG0c&=G(
zYFXd&#Pk`gPlWRVv)yi~4DCEBg0@1-h0m8kTgPL%$h=g%WFEZVbBv~!rB?|GPq@lK
zvl}#ntF?b!T4XwI(Y{5Fpk1B2($Gr@&4?xfvAC*Xl=+pEBPG>Lkxk2cy}IVtfbs>2
z>ZWStJ|R^^(}7Nj#Z?}1hwZafPt^>zSb~Ljc8rG7RJnB%rG61<2m7>v?xcL1Cd#V1
zY2S=E@6hc#J<Qq5YeZllw_=4|JsxK)C*<AN)2)Bb(UXwMd@q$@1s|wt_VA*4l@1qr
zbq7qNeK*lE*;nCPjK)!lYF$qyf_q@7gwNYEUmpm3>dHmab2Q)~qFK%RBcyQ0Mc~Wt
zVG?a0mCO$T4D1;1U%@2aKc_!)XCpf+dy9X8jkN#zLt!g>BWF+X-#z`gIV^5Ux=#>!
zuuFe#t{{45@#T^-IKLFi1-YFvKn+&7Bp3CHETegG0T3^j|D*{-;e7(*Pvi{eQ-$84
zAD`s7&G2^+=-LnfJ2R{ZhpeYPvdqwAoiSp3Fr%&e6p}voh;s+p(`Kya#felRgcR1h
zG89gVNeS}aaUqA}qdQrykj24gP%?Rp5x9RTqd+N;@?c<o6u*`nG;t?3smu;7=qC(x
z%ig0#7txApvH-3QG>4PpjcL{>4N><E{#s<d`v8me94!6`gaqvHO0Um_R^Qpd%ZrCv
zq`<FJ%hb_&9;>~4K;HYfDuI5{BZ727g=WYa;G&sxYwlqmzMKa;BOpXzc60-j5YvAX
zmj&<_4oB&}Nlp6wVX-Jg$`pw4JLq5hmuu!U|5ENh_SgTF+DRHP9(W5VA30`Pwe8=$
z_v_L2GHdtx1vBFYVZ@TnB*c;fXjfBZv{r3&M3bZHrJ?yG6|`4oUw_j`mU$81=pTSD
znV|>)GmQy*S5Sz>Crk_zRQA5|ee!>-a^GzS?Eca7;l1wm!1q=?w!`xmKN!umH4}d<
z17|g^LH(`_qUN<3UT5!A6((9s{D>TUmwDe3f#Vh)trttxx1Ti$IZcc$Y0FLAj(GM>
z+lV|DuDP%#QC(I;O=nMy2%9w~DW6=f^`JUKFIko+_UHlbEYIKxUa4ziWJ7<ZnRb^>
zTl{MdefsJzB3}e{++S1AEN;LOi0a^wxE;Zeu1}1h5O<KP2#q)hw--R|!1<7&&k@4g
zlA#=w#1IgLovO^BQK<$Uc~cBHLoV7aOC%`ab0&w_rWCFzxJ0|CAdry(C-$ub$u_i0
zY+O-TS4G*})Dfgy6~o$(JWzjq-)jD9_;Y}f-a+bb=+I-_#8wv>dFd5vnDF7BfF|o3
zhPexP2tgumJLIz%2%$O<=TZ8Yln(~@_o3X;OBA1fv<ZJia=iE``PqzPAvSygG<K3O
zg64>h5ue^_!n#;aqD9l*scS&-8>vm}c+dj@8zlyC+id>dF&%8mv#@`~%c~L^EUR6Z
z$2lx*hBwb+tMlT_XPv))P|DEhou79AUHd%}5*r{pvheOwQ|}G@dq3uXBYa(e!IdBl
ztNNuXv1vFOhKp<dXKB&yNS-;cjXpc7><~^<_kO*8sQ5e$C5j?R@mqm{l*E2#P;Z9H
zyK}yd{16V_xUd^%Hi~~Hrfgv-u9l~5*=&l`y@UGvU{5`-FaXylTvgnPG&hb-M_kDb
zF1QkGmF8S^|6_vSrX;T>^)pFG7mHpo&$w5?SLI%9H@Q7dwuHb`0%-s#5=z;Mnt)#U
zH@3p6k$8`gR(gIxymyU98jy7+Fdi&zlhQ$^z!b<bRGkx5jH`dsSSl^^%~4Uxh93Ry
zKHhJxvuIj;@6O!X$+^I)b)3>OFxr0)^C4eNeZL(qvq)(jihCZt5<pTWox<HLZg_F0
zZ?&vz8^IkXNh#von?X1lLn-B^%$H?}=PO(~6;r$D-3;lo8m7A<jB`GQh)PazM2oP`
z(yI?Uo;`eS<%EAlrD3)&dXU%~{938{vT*PsLrGd%Drea~`y#1s1)&@svOiw!kng~<
z93(AvENeFRF0GS^XF6yqP+=&?{-)YHb=4ds=OGM+TKSpWZ-nPW5=I0&*^z5evKfL2
zhUl||hxKW_>25eU`2@fe1|%u<#Fb5k^!%F&H)f!8uNr@`MRxKP+?(>&+OMt)2pLl8
zF4WC@cuuu_>jj)C&IGDrz|pw!c^1w@2KU3R2C8o~ivNPXg+S=;-WK|yBs+*Zbe}Fl
zW%2nekA?pziiJmHE!?P@EPX?KG}C%CP3ik5d9LHAQvwspy(~8fnoT8QZFaf%W{PMV
zdUBN?bqaq*GCx=v#H4r@j0RfRvKMQcU^48UqJt`)DuOH+Nw(deI)W^&p<w*_bI9Is
z{Nk_hyPjwwdB@5gx8K>{<a#%+k^F-lHXm$5q<yfbWH@_I47wv_W289;rCD;n@X~LS
z>r!l+G*5=4kY{$&pz_BkNH+T?bevVBQzxm;l?Hz$L;L@b3eE33o>%v2&SKM}PgstZ
zHSqvNK)SzB%~@b4Ja+vBGcU)(CEM$2i`llJ9#$+I&&w@Mj;YDNF31;c=E`$iRfzMB
zSv98MQy8uGYq+FUE@RYn$D##dZt5yO=sUi0C<QZ{TQaiyXj~dL<A9Z!Xwhi|-SWO@
zfIXSoHWvYZ=bU71Y!S0l2YFes^gg*|ryFAN?2iLy3WpJS#)D?=Db7<%9bzeF^>k%e
zKD{|rlCnXx=uRUpIn=;qQ@@YzGdH=hw=XQZ%ya7o1H6!$lznMgfEwQR$YH+;7C5@k
zxEsp9tehs?^j4e)Q|Cq(IUi?S4+SILl-nbTJ+-8NtY&e0b=PiG9KbqYJA*PuQl+b4
zEXU2~XC9BNUtBAT7?y9Vzd&4)sQ#uQC_~PJVEZ26&A;uQaRnLF0az3MY0+B|^bS}P
zZ(a}LKt@cx@`5(7>=o)I0N|70vu{TSF)(jKZ_A^_pk6R<+xPMTyqUK3(K>^!3IX0Y
z?{jv4MHR=wAPcGvkWHi|Q65~lLJFCA>tzVGgn!%YcagldUT4nG{I+_#cTpN8NmeMl
zL8%@>=~o|YFoVh!b4u)j;;q#=#mxLH$UEJw$`-7~bl5RG9wm8TEGh}<WA6o_1d~p+
zCFVh1*wH7|MJTCL@R#6g<X~syTPMjnR+%M#bIqNFeeF~yxxiEznbt#uT@CC(8s1Pv
zRV$cQzT)K!vE<(jQB_h<{-78+P@x=}1L$CQ>R@P}+%($O%Nq7qFGwoL2Q2s?*|y!_
z(9EVzrPi8GSWrnVbNSTyJW^%kWPH1|^u7H8`UdyVJHr!$3adDpS6>?i&6Cg<g+Ho)
zumJp7;3lL`<5L!gZiN9yN&a>LR$6ArhLOC>!xT#}o_8ajcqyjFa7|q{#N^UN@90Wl
zP21XEu0uf<qdJ+L=&}1vF1RA!G*-%RvY@+$K+`Pj;x|KzZJ*p$ew?(fGU^->bc!KW
z_TKEs&z}#h>65;UdaCpiN=$r=ShpR2H!(RT3iE_;amJ8)q=^r}aF15aIC*BZKIAkL
z{L0^WZKC3Xin?=Lx2vWvbzz^9NC&ehiTF6i6RHZ<lnFV)!fjNra#BES;1fOA6s?TE
zyfcPpGDp9d=agWThjJ-zG7Psv!gOWTbm1&3_V<{?KLO&>!mlH6(UKYM&>Kg8M=rJT
zHSB6Khuk2}x@5}1)_Pz)vj`G=2mHF5ZaemXpfCdc4i)7Lm44IG8z7dCOlUMfeR6o;
z8-uA7h0yCCDGCD&3QDEy`wgXpt|~FPISCzgJc?SgxazJpla7oE+PxVZ!3=Gq;$wel
zU*l{ZZEm|{Gwy1=Nj;xmRO2px?)SOa_)m*s822c68#M9gK5fVAp`jx-{Hbz;h_kIy
zk?VC(GF%xAQG<*OruAE#y01%^Cuc3es`izF7}hniUaet^%Ex-o?3xkAKhy}M`-N4*
z3ll@lN-!cB4QN9mua<)}U{f$NGJfz9k)sbmv3AHkbEZdedK3<gp(J&GJEtKm>09=F
z3oVs`eWD0*G8}@w#<x2F)k571b!-6VTD|Uib@*P{QF!VzsV|PT<gF}^w6gnd2p?~p
z%2V-2v}GbOsw2gJoGz!5Pv&V(4j9*<+RupAl;^Kh4r)8;^Aj@Li5d+_dqWcehNNpC
zh-OZju<Ndsv}eM0k@Wk2j^mije%wf8wcD@B&268pKldj)MToNC8xxH71LtslFlT*L
z))kk1@nv_tBwf#3wQo9<*MxKTM9d%0>f=Jc<8tq|UfzF*+Fi@=*v~7=3)HjB{Y9|C
zBfTSJC%TMRKU3!n&*I?*-Pp^7uKi7}Lst|o3!La6Oq~|pP7}a?o-6g4RU@kv>lxO4
z7wG-nTUY$ki%S0-jV@wag)I6nC=7P*))go4*bBUy$L{;VEER<`D{T#5^$A9=HY;PX
z%H$I?XN=cIE4_&Vua$FZ;pzxR^RVc>6|o|(k`2c(X~-AZkI6Ej9w}q=IGVjs&Jmxy
z3b@a&_gWPS{EvTsD1AtVOycPL9kUpr|Esi^@!zDy4)(5A_HGVtE`LKJ6Tc%7^x&xi
z0V|Vw?K1j8MMk;-+Rq#j8PY<~$N6@R%;6>kb{1p;FS@NLy1xez541L9suTD%uE+5q
zf3Hme{Y@}@qpBDLR@%fGE8{WIgghX1lI#?=v^<9)CDL7glA)!CGK_#u5J~oxqrCjw
z97+xpZ?b0>>)3I$EcQ!wjKu|=-&RU2iL9$Dh4Lf!0bHs1g<zTL4_S+mIDDsG!)P~5
z31iCJu*KM4eY}JHjnSCjY*nkrreFPdMGmo^GK;;#&#StFMlr*AT4N&!Gy~%WTCR#g
z$EkT8*8P`%yb}vfA3?3)E0i-Iw|z(IiiOt7?(l)=il=;m9o-%zcDdpU`B<F9qe5AU
z?*s8&>IFX`TRvd^P;estsSEpeAaVfyKWwY?*Qz@^*#5QTDtZp6Lg;*bOUj?&EZ-OD
z8<hF$X^^8M?h5Io(B?(q!#h)ra8_!@=$G}TyYfGOU=3{Z!#iI=QSOa0`+3stbu5qB
zEsxnOE*5_89}k}dKi#7<Hzx_>mf_x!!BUCV6uqrVm6tusql&RPkSWb7E-D&H@+LLj
zHDNEx5DcwzY+O_Mz3Sib4e_FPemxr*X3>w5vmj32Cls;GpbgoNsUNr<DPdUCXm>#Q
ze#r@cXacS!jUx4=`VsSm+*lQc(i2H}ZT|dbyXjWW-jXjBkolXaylO?HKtKm!)822s
zYAc^G>*ZvGPCaq%DV+N<4*X1sIkzhLzUc<2q*_s?J2*(=z)-?HtjQeITQjlD9Q0M5
z_*qvR!8y$L)rc~L&8>kaFJtZD{u4jOi{eUu#bTUJ_B7u%P5uNcyx83o`clTCHr-}c
z5Y;1=*wW$e=HYxiKM)T4<WJ(0eLs@GIPk~k4NKbv>=O&_J_6}fp5ErWm03jYmk^`E
zc_m2rNR{`>OH?^WB(zzt<?{t|aUXM5W60KRoDvF%B3x;c<aW9nQdSD;1=4DU9$?IW
zpz3ebktHxZYv~Cjwjt=hsG(|pjhgYo(Xf<Tc#-YG1bH^yV8km7drRE8@qY_?Qh-1u
z5)p*+--FkL^`D35ECwSd$Cacq4j2D~d(R!pJ;PQV0!6v|RV()Db8JnZIWdb5EpehJ
z8#3;gS)G<HDUW#B(s3J#?d<{4?;X&8lf0N6009O@{x3T?sQ<MC{=U5Fue~o`Mxpoj
z13q|#nuL<NQYvaYUXw@$9xo{<=t#J45#FqShF_BCXw%tjr<Z6emU#mQ+CFS$PyVvy
zac_L-?)LQkQ#aKE?6ApdPfVa*fKQQd(l_YWdtda}bqOX6_bKO8(TxOIJsfj?p&fmN
zc1yC=Xz(8H!x+VjGDUr}9>u{X<D=Vx*;w9fB+>HvY@~`iA@ZO=vzf;lXjRT{45HMn
zYh&zlq6Yxsa|P@G(0Bi<g|N6PoBH1UND7M5h~9poq<gu<f$TGCIc05KmlBo8>gryi
zcOrV>U960nsGqBFfDfi^Q=BJ%i1G7am5K5`tY&ott`CZr5r0;k9QHEAQ~a)T^HYR7
z>j%UfNEW;5s&KW7A1qjl9-rnaK*Kme2#FrWb=tZGrxb(ifuv|knRJIJX7rH@fTiSX
zjm|&xd)2MY&I|r7C<sFQA9neJO-z4hoIeNR4*5Ps_~2NXjCx36s!vFNU?R21LPPc#
zqo1ksOFqH1%4HrkTA}Vk&1;zau1k<I2u&IAg?DYL)+eUo_4)n-+%SLztr##Elugf@
zg^Xx>m}Ypi<5bhWLBa8ADvT|m%fC-eB|Q18kAa5>{fTOlMF1hy(TK<0im=7z{)hgC
zhg!i$h)ha?wNA5uh)Mu|c?48LqzcB`4`q}|F?E?W(c%kRjhk{<v*0LP>M_oEx|sJA
zr_{0vd6FeGXJUO73n^^+S?b5-xtdJV_lHVrrtKR6{vah6#qt7fgNkJa1c<yq?iamh
zT32wRs=}FB+hqr??&|HYF}Q?%s8GG(?F3PO)V3u|PxSNew2k?H-SuDZulNtzO4&Ku
zGLbR;N#gH%3Ui9sL%%HWPT3=51%<qgB!dxxxKSKf0h}Cj%?<sC^Nx8I>rOPT=d*5C
z@$KqpCQ;j;o-o=UY_M}w*x+Db$oPI8z5%nFZf|xUo6x{AevTRuF4bWVMbl2$OScyq
z3JD91<|nQyCl^?M!d_5n8fh+^nQ%C_B5W)LRD%evNIxDl>%aKBP?E?!^=$~&y~s~v
z!iW0=e!cy9t-BeW%}5qm$QPnYuAf=n*2x&!kqn*DzCV*w3fyvZhz+gW^An&r3*!k@
zr8l>Z|7ro%H;uxkQK_&byn$v%=mc7N9L1~sDy@G{z<}L<>|6Xb-+o$MQB_g7CV~wE
zt+`-_eo@U<&>}VEYwOT^jQy8~>ElJ+?S?WV>>%n3sixY*S7r7>-fr$b+;e?_4zG8<
z24V91IXWw|FAG;bDC)fY*kRxzzN)j<1ke=5lzN;*eZ4rH*CVID6!?AmJMzj4Fl1iu
zUDk+Zvd*x74_rb9;F_t0etz@07+A6zR+I@TN?%x#qkfxbY%=Kl+9bVRyIar_VaAT&
zvb5503kh_h?hs7QNmwGb7&b)ptW62`C6Qtg^oHbl&VG&Rr+6msB2KF1C%z{cWZnJ=
zjnR7t%@Q;UT^E#wasYkn*C9X>O>52=$uw>RGiIuPag^OO%-_$R9baJ##l8&K==qw_
zkKT|Hlkpa8HTyXl2N$xW3SC!d7oMq5@oeFzU-A!dDqT{&qIi()u4(+#+aEk}jEeAy
z=654J?_YMDGyFH6_@~Ax4LA>cHH?o-^E#Hcv;wR2>Dj}^Aok^gXt^3gZ5yc->1u{_
z)|%*lX?gYp)AW&xTAo#QMSW`MWN9jBbQEMA5@d4XbxaaSgNmKNA0@wG_>6*#g7W@0
z?>p~eZqBhfLDoOzy_xMb*>U*xnC&vfXK^#`rGO7v4gCvx3*zkF1kxVSkjUQXLLHD}
z;f$BCnzq(s>IaVNWC3Q-ttZ<#yk`%1WNb-)8A(Z98`>L_MP%d}-t%odPq|701DI4r
zL3wyH3YH)-aS-p8(caZvvEd-qF;ecL5E3O_yAcv4IEB?Hm%C~XqTs}ic?kC+Px+Gm
z#+r9TMk0-ueA^0V6W;J^=l)Re(>Jiq9(QtlI76lfX->j!PhMY!-*6Ll5p^pQ=D-+#
z;=~F-8*&ldh2rNCNj))LUeg9<8eRki<w!o22Ias|M#qO?Ixx<Q3d=z6xt*YZ*Juew
z430b2i=d@;aN}P7ST3^HXgZr-L7Q=mHD9!hH+9H2*Nak1hL)8S2QG-lE~2QsMwP65
zRcuVBvnB!77j;g}pCn{uX=k!cG~-HtAy+Mbf!OdceiimAX$Tdo@5r`PLdZ(KrKZ;T
z3_;@_(vVszK?(yi1@n}Ag0ij)P}INf95V582;3hFS^$dbWSrS8?Mzs=39*oufs7U`
zm3FzuCJUC%7O8O6?5DGw8Z=^E7s~UMP8H=EYB<bk$)<Q`u(M<oY%Q&|ED5}ST(ryO
zSoSnKvo!~p9^9>peE9wAsHulgc2R3B<)Iv+(b`GUbsdJhA+y8`nT=W`Hi`$0wS#P_
z^+ecv8EEW1%^5uRV=Z~))N}hL338asl-dN15=uk77E73Ds!@IEi8E#ZEb^leg~xTc
z)XOV%GDlfTgR_0PG76@dXsOD7+b38=%A=-Pv9#q^KpJ)(8nV^LZN~<jn2UU}c#IiW
z?gJ%J$i*1aijU&6E3vGx2dfl-T3~HiImy_w+xcpJbxV+oxF{Em1g(}<>Fms&J==_3
zF$=jC>DR#q(b-%KA>mxA^r+AVHSWXfg1Ok5-w0vYikAg6Xi{ur!TN@O6GEOk#Rn{C
zf($<;000xR?99s{gsohVQzlITSXcQ02HQ)pzJZ(6PXsOu*S(k5wE-HbUg0eQSG{Gj
z+$cr$;~j@D1@^9%*JmvHgs#@|SrDK6RHuXO5A;c~$^uo>%Ac2xzmx^)vPjxm*y@y%
z*O+MPisla*Yq?EJA&EqPx~8qW+0|I)$4s?lY;RO|Tb0V^ZtX<b6Ic}EM1NVmugt|k
z_;wVYn)jdvi+%{q-%{{M0KHfYddc{Q7j$PDHHi03x2o>Gd1%yXM5d-m0~qV5a3XP9
z7g6f#NU_yP<4bUCmjdDoj2Mp$(A%TCq&*~hHmfsE*0H6UvWKaEUz1`=F$q$%Svou=
z>@Kja?}4Jxk6aNJv3WlYMbXkhShz9_xJ>tw%;~b6qbe?-0*U~jDNhp=<mJw#>dfFf
zDu!<4DY|#Eh*sw7;9!izmoVJE=0}?1S(Q_DDdzL?qM2{OWA5tKvd&cBAZ~SYzZcn?
zQrVF)8M#L$buiU`F|4jlnZ@8zU>Rt!!CU(j4Hh;y)fa7_tL^f+rq8uX1DP0-3sTi$
zl~W~z#*3{7FxWSzz1-+6?(p4K4`=75;v3`otYr~S&4~z#=cY~62Uhc3Xfh0#YW<_m
zsN^fOzJqcqTTG4=irJYDoOd<Ho~?N+Z%S#XS5KtMEz1sni&#7IjcCi5IdX<+RX6HI
zIQrJ-<+$X=6chrT%Q%vX1*mxK=Hbjc6ySEN+C88;3<3jWpN)OKnCmsVLD)ElyR-ZB
z>w^gy^rG^v(H!Be_38EFmilY%ezE8r!O6&S0<k3nA+@KaDTydXWOe~BcH($53e)3B
z1;=?z=-lvsC_lJAD;z=JAok$h5DNd6wQG#7G)ST`Uu;io8xz~Mor&#CY)<TnZQHgd
zwllH0v-a*;{CVf~`A+}n+f~(dyQ^>egmMs|goTawe}o44FwV4GqO6M-)Al#yrrc8y
zzm^2@MYvED;ZaH4AkT93ZGdZ4qg8VxzJ7lndF$tYl!_t^X!Him@|)shvzBNwgjZ~J
zL!I-|4LVfX7nRi<d^ww9J-25)cVeBKVvTOWR!Vkeyaya$lIuh{FJ*eSaO)j>ktRT=
z8{AmSta4ywo3_M>V4J<4UDIFKg@P(Kh}@+>P$`nP1B2N|un(%>k&#xQj)SgvI~p6m
zrVrYGK_xQ{Bc+r!TmaFc;qYBCC^4o6u4;IiU3_9wn&;Z=MVKg}eaSIqt4|&~ixP4g
zWd@_j;dH;D;nSi}@spdIYeg4nhBw<`P6<0@L|~UUciF{V3xzn#Idn#G?@Fe-Ha*M#
zaIfm2&3C7+*bt>|+J!$G>S#uRw8y|7TvuIx6GTnNEF>0`V~NR2ka!Ugwg?Ib!tXAq
zKM}|<h28!fh7BF|p&v0WP&9>gn50|3K~rrD70-@0nDC8RDFs{7Koe$8%Jj$UII3wP
zn6(evjic2&&B2)UyVb!VlP$QZE({uJB36y>z;rbS<Ha3ltW@bUqdn9@`q}bRNR6+5
za(I<^4p|Taz*NwpXxv+avTn*gB{Lmlimyhg_g-nQD7G3DADINEke|S$<mVw%5&Tm#
zgnNjkba$F}=r_AhWzmmJz<1jYFvMopblQv{mT8Xr%j&n{lqhR8&4WyfiRbEybc^wU
z&Q7T1WRRy+t~8t&r<ewK1mI=MJ*_K$cw^ZScQgi>nBbOq0nSm}N%R<}?!6ucsO50z
zNd(#bMY!dM6yzMBjUmx_c2KbFiSzh_xkdN`oC&%F+Lxcoiy)<jAkPWAL7r(FCxOdz
zH&+O03bpxM?Vt{49tp8e&9w!06|woGcbTyH1a}><rwHorOAfu6II(i)K<VdyPThmD
z9?I0imx|Ln1=wH7L~dxgPFLr7Hgdk*+o*2X6!}+Aj;sRh<vxA86SKU9K26}|6Y(Rs
z%aUJs8-9RS#uGw%T9g;*3K*WkDfYmoZvJ$jHg|!awS6t^PfsgOB5ol-CLjyzgZygI
zBjkVho!BkLAXjC*ys5dC0Hw5lB8^&M`Q`v_kK>)bl;NYW$Q7CS5`QAIw`Fe=hR`nV
zatk>w1b@2$7hz@6n9dnNrRj8J0ZX~a<~wJbV4`4Lc)x^n{zKWNo`pUqIg<B0w?T=^
zH**Zn&P~q6*&U6!*5!CqRcjg8J&7D01>RAvRCm1<DrVxSlsK{R#}KoBLO3x4c;nMj
z7!e>P5#TRDf*TmQBB(i9(%mMx9MlD_oEsR5&Yf{YpJ=k#g(%hOWRcL(%JKGSuk74n
z5Kli4;#}S`?#69;hsu>vnqvd>Xg)B0n+(>l*}qgn0|8m0{STB+{@2ext^z2Gs#*AL
z6@Z}<!oepug?3ab!D4WKQnls&hDtJxWs+y@KNSIp@Sr+ln0BQ;O>{S15LDR$-PbG#
z;^5(ssnV2d9x<^*8&lmF1*dTXFvsIskpXymg@%eGInx+CktMTtD*d~@mKp~)xv87O
zkp@F*9tZ2!kUmcoz0xACL=Tm$a>iUYg{Xu11B3zIl`wc=H8dfAtDBh}4)eWf0nSz&
z#YXWtAK8h30KMusNymyE&Xx{eREs#{jb(4;RJNj`c$DA`B6dCrrdijIz+hmH;u*E%
zkeP}+ftlPhAPCCuEiZt3klnC)KQfVYU48z92z1KBh`eXThJljdeYxMl>^fhfi|~v2
z%>e%|Fx&n$%-?>0cTaxkBX41$LGyuI1-p@Ck@QNC=Tp0tx!^O^T-xIF`LK(W7Y)An
z??J9h`o?0y?nxKF$!Rvp_j3P!4Wp0JLK4hiMdXKsl84DW6J-yI0zrm_%sm_5Lnkyo
ziGj8Aaw5o(uX7x>YuZ8b%B)*DGxEJ`v|V+tbKczv6M@cuB*0)s#b=>qr|I=oHUYcT
zix#A4=ce_xR93)!K`4BHO=#m>e3V{slf?Zd@tu{w5hA6i^f-ASXTC|wJ4Sb*0HTma
z+Gx<<PXiPS)^S)fWe7y*oDY_P#<}}G5#zBGJua0k|1#|^*wH}=o-`UmHaZ5g_NVHL
z#H?ydW9^%Nf4w1IvUyl)Y54c<3(Igl+)H2P$Ypo6WX>$*$qnyM_i2gYmkk+Fwh0Dn
zHd6Z$!?Os9zCNwp;_LXe5~Gd1xJMd3V4k8&LgFdLGS}V6HEbS~wY;3y-h0k5%JY4s
zigj-aG5d++{aJ{%cansnE>T|=;|4{4*xuHWofPGNv3N&r_*L6n{;tTwuOCG<>emG0
zf&LGZtZd@u^jDL-Zi6g<8N5k3Jo|H&V7?J%MZ`i!UPB3GPIy<KhD4?qTVQ9(4=c$p
zTE}JNoTjm9N9V{7Q|5Lp{R%#kc@^#$xWuOR=4F!k!fW&4bgGE}=)5m$h^z8Qy<24g
z)#-?T;-oqF6q}7DMI*t<*iNWV2F}EPocP@SD&>=j3K!UM>!uNyl+1Ze(M<K2Kikh%
z2hz=3yb~Am?gbtV=?EcwWGmJ;ef_Q?qvvzb)8J0W{=jvFqgYSSwuxvFq3C5Hkf;#6
zlWTl|O44FSCw?(#iA`>oAL4eK@jM;-Vt##p*xEm7WPw?o1A=8hwVF-3eNDEA93ZHQ
zzcgEK!Ji{rO<ndD+Ieo`P(#WUf1jg<W}9;7U%wMV$BCu)?!g@#DmQ~U9^K11eli8H
z5YKEf3Ly;>lbTeD%D-n<XV5G0qAU-Vhq%u$)MrO!a9AGSZ<MhKSg3MMQkjsAF7k<g
zl;Wa8O7j$vSIX^%B9&_-7IGPTt~I&JfvrY8d!vizvIby4pRe2rVFyaz5>H87x5Xy(
zjJX(v=&z?ql(!SAH{8oTXj2)@ga=T2=YXlKo}`1u)l81KC`{t_JATr712FZh6{**d
zXzAR?2Ic02n{YD8I;#ul-U~0pDN_u8YUS^C7&`ka-@(r6*>4jkbrIiqklt};XX?Kf
z?Gzf?=$87WSy{V3<HP*m?V~4qm8!`?wbOt{<t6@D__4O~J8j!oIoq_~Dham!OT7lX
ze{6N;e-QclS9gb){#{ogD+?1FC-FbD|6sV@F`r?2`4NLQ`%}!VXl~)DcF>c5lET%Y
z{5gHCz7ckj)V7_h)A0C)AfpI?!$x4~UU@UOzwCN|GKfuy42diSiD3>}-Itfe!?+J{
zDId=$hcjSCHKp=MDGW2AcPdz5(L-f@5G`5su-4Hi(oKja#mO2^)`@<Srbde(!>7YN
zq8eWg-J1v{2$}xqTn5Jq31)bI^4#7PofQw^uRgI@SQsYzVa^UM+d<p>y8um3{ytpx
zYoK>P|Ah?SKZQcj*}}@$#NiL+TJjSxzzUe3v%5~4tjgPgg4(L<g=*!)YZo%FSn1{>
z&pX`MVG*`+j73NM6J)(JJ16BbSKl1Kr^RHxlgOhNLn%YUjoI|D@nUCx4_SHVA<(gn
zbg{0M#DB{P2WfE<73=xlL6ndzcPtztZ5}N+5tm+SZq)Q;sxJ?o-O8gRemX|xlTs^h
zote?sDOnpm#iw=2;x5a>jc9MNqj$h_<k72=_9sLp=-OdYP=)ANF+vl>k%{k*zq?on
z1R2ZM^lR+g|8n_a{&(nq{9|0A{%9#F<}6e{+#vG4YpJhLh6d>q{!kw#!!nfqAznMv
zrr`#JKxzYnR9}N>da&E^<j!O33Z&$O*9^Y`&jr?`-!YtES^({A%SUhywb;V4-mR6r
zClan)DsJVBUuJ$UMb*(ZG0L-LlEIYI^^J-qnrYh|tBCM0epCp5)6AWu^xDp(YuG=q
zfuplvXI1#fTh;m%1@a(w<}0yaiAex|accGW7;CzI9(>B0uMt#^hJC&6Z-KGzsGn>8
zHEcBC|Kb4i?}7P?eRJzSCQ%hNGtX6Mw@4&cTlhSxJQN8qLHHo}x1Uyx#T(&pmZfjk
z|Byk2O134hU!-4uu=kw}9j<cwN<|9d24PY~(!{e%D;*q$6)=^d$>zB=ve1jNTS<8@
zfm89R{*bXc2e4<MPO=AAc6Q7*Ym=W<j14V;;P3V8Ja{Uxfn<xEwz#b$S2Nt{T^gf2
zerJdUZb~$AC`S~&+KqCPSa?hzYec<t`=YIiVJebp;5fs77KcZbeR}_ND;d!$sn*~6
zICA_ou=mpS(yJyv;ROcfb3Hi}Y9nIk2Ks`Ko>M3u<#3U~^t$Jd<h1g6QuyC18TL2S
z=sy0!EaG3H%K9In`WO3@iOO0^tD>myi|htk@bF->x9GD6hB%>;5?aXJlpKZ4nBqh`
z((#a{HBF*_0!ciz8M5z61hcY29;qX@70hoksj^d*LDYKqvl#9V+MPF<j=UF}AFuBa
z-ArF7jqRoSFeLIXO<<6`68lM1_l{j)T&vRtu^0Cninq_fI+M=f+&2@lzXf|@k774s
z*0-KM_FiET$+2VQ(r%chRPydlwanbnu5w%k{@DM2sS=!T!HRe8`nku>lf|&YthQy2
zMS8O?<KU#YK%66tb*$!<2yJZN5>WGP^;7>y>3(R3&8fH><m)imnDRn}W82_osSQx0
zalS?_fRxITB{uT=C8Yhl{V91bdvwd(5$+9&fmL=U_S#{h>Z)#T>mjY4+Zx7d=jKLj
z;QFV3jAd=!c?l8lW_)mrL9W4D3hq&spejVmwR7Z=)0Ua$*W$2Ndp9X(uEC*D-N9S;
zx4_`C)*>CI{9@H(E3+DHT^rg3=;fW3qI8GK8JA=m_Ca|pq3E66DbGFTp>`A-Q&Vkb
zx#HqumyXsSwR@U$(Xy|F<Fi-zbTda{^SQf!I95`&B17QgM~~>-*ri-9HAMz`L*C=Z
zZoVOa<?U<0G-HqjUIc?P?iNzO72h2LP}|pA>3IwFhzp3?<%YB1OYzSIaCKhl%gke*
zru*L&sR_>c+SSNL>j-})tf{7FkDMslw2RSwvM16_@i)&Pn8r_~uqVqfT@_w(z*8K5
zHeRx5fjjlQBT!g&Y{}VEs2=zI?Q5L3GNl%heZIb)b6ALW`iAOQD38%47Ejl9W5;Kq
z7(!IsQl9?Qw{|81#5rcvM6R+3`ob{5R&^&{NZ6SYCb!<%G$#E=VA2@60ch|1du`cB
z-cdiO`@bqe6HGtg=H9+#2qr_{qVooSCL~Dqi9M$HV9^;x=aTN>wMytUUc&AaiNC`9
zWS3@WKiefu_(~cW4`=5=QWg6X#S2^BDo$iEJI?K<Nc=r){=8RDT)IGyPJFr;B$LRa
zn+q5n`kYQ-RUZ7nV?+Shy*1nttb#b~)G2%mLW8_}!%$Nwn#Ud0e^zu_GDGrzwC}Y^
z@OAf%bKHnfoUW8q-pSw{?e?QERdEq-w1g^fSywq*UyxQ7UAKP%$TB%C);fOyfG!*7
z&I54E_8|!5l6?T46BxQSE{?|H?NbEmz@L_e*!}#lE1w-BNE7cpZ45Ljj=|*f^t%*B
zPf#!>>bD9QkU&8HvBdsA@b}+;`TFmd;y+1>{Z<G0ovcZwNurFgWKpYWAw;{o;8p@v
zpv;i)SwDX(VA$C8M`Y?*@Uq6886^ccxHsyn!cOW08w|uu$Y=J+hfLeatP4I~Z(uuL
zOS+S0^`Qb*j^?v1Njx<j<?7vT$Ldr4n4AKUG-EEr2N7&@PWG_EolCTTuM^$_yTb%n
zw7W;>LO&ZL3tIZ*&+ntLs6r$tFxf(w(B*2E)sM`)$^*g4fz^hzrP475!c&J6w)Inv
zhMV^2H$&~yz?2MLp=0`-dW(9$I$`5Y9DMnZmq5ZvTayTKZxu8xdMT2nuHa<iN#Q-X
zF?1u>jIwq0EW<yEzMc$!nKf)uvuHI?fMc09)_;T0E@wV_%jHs(6xLo}P+-fuhqMJ{
zWM>M)@<1^<*f^f-uqzo%Hz~Q=>31{Q9!OP8>YS+l*n~B@{D4Do=ySw<OYR~<Z<ku@
zkS>)sKbuuq=&2Uf8#(ulu9Rl12s(o>VK12+u6mF&m#df+OW0I@((EPENam>)dT_%t
zqxeFjX^&2O4LF>pGuK6|_-T#Mne&8|cvx`){YCF3z`rWvrXdvi=-W@EQn^Qg$+m`W
z^mevd#bYXT2X>0J-Y3HZxsB1{d%o|lHYE*77;l?Ss>xjRdpfIpzdP2tZOYEx0tNzd
z0sTK3k&=mn%b)UpH$@$(U4GQhbBm%zrDa;qZ;J~drDqU#0tO3^;0nc^!oMiDi+G*|
z(TMU#0s=LKKf*iE*914S6{<#sgzn6d{S3#cmhripK4M>InzW-HX#%Dc6_d&CcE3#s
zbj<Oz1dN)!S|nzM5QC!%1q}OfogM~lp55fNd-tuC=*aee?zf@X^=lBhbB26aDbnC^
zU3JnU{TbMP`#fFr8EE>KG+fnYy`8wCcdd!Ya(5QH4ouO?ihj8&VNQ7JL%|hReC1ti
zK8$;T7Z>%eOEo+so$yeyLmfhd;etFJ{05x^SSbl!$BXF|x`FYbFl^!=8|cJIw{;OZ
zANpiU4wzVf>x*fpUQuPFm#lEktc0zqH2oZcq#)iDbigfBxsN9b;C_iig|6jbrkBrz
z#aYk24Q{F`9O~xQ)Po-@E;nXvHcyiB)Txx0G$$>OFI~2<b?iZ(9h;4xwJg03Gye-K
z@S`6g*RlJS8O9TO$p_vZU)UaxDDv>}Dg3o2kvpn?5$$y}yy($>B6t3VS9)ukK!!{O
z!-{YN>ika(gZV9cX(tPr4Z`)31`*9w0&|&J!^Fje1L@zV6R2skPz}E<qw|+#{0}te
z_qOnNG>6*;L;w){^+q#GF&x(rgRt;>z8Gp4#Q{*9M)`Ju4vW#24Jxj$kVq;mkU(5-
z?cMQzht<=)XA4M*e(d-3@5$fgFga#gPI{<L84*t`Orf*sZ?y#V$&redmy+bH?zK6L
z7HnbINu8|SZ(GLMUZ{))viql6)Pq<rjJ2Ty6^=7Y2D9sEgi<erC!VtyZQ-|f-A!xO
zBr5~AyKwN&!xOc@1Zh=2ziU|{Vw;21G{p*k3!1CpX8x}F?njK_)^C$nWZ?ga^ZXu{
zf5LfUJ8XLS5d+P7wvlg8!t-~)Llf-4N%2I4fhFyct)1AYjjWcB&ZRe^{2_;hL^5Cl
z5s{Er4At^%P4nO0RtbP2uV|*xkD#2uJpwCD*d1-kGF%c#!G!J_N!qoCVH;J+rQPs<
zCfPlTOe!OUsmx}HQs>=@M@Rc#QxEX5DcHE#n03m}G|hM_X1xYXmARpJXGv;#yS{SN
znq<_(pQ2EGG$B79u2h-#)ew8F0a~Nox{8`bKC!&AAU!s*g7kuF`fh^6=o0cQaP<=Z
zE;F@(1snebhz9U~A&zKa<7DDsYG7o4;z<7=pS%A>UkN28X`x^6+n8AW9%PxwE|^{h
z%>IkA1{Hg|2k<jP2r)4QL>PE)Ac;ORD>zD)tEoE9-;#tBnjN^Ip7o23>_gaYm|a}=
zXe5KuWi^$ShSnPC6#DSmMD{1dqz=2uP`ws1>C*ER>J3&hX|or3>&aP7wy|M<#PG@`
zqQTuv%cT;jNAvQ-cM>%2D@ZV&^T0UO2%+`bYb?LmPvMHaKo-)N5OT5JzYEMoa*q<}
zzed#x^j~aH*g4ob*&5keIsWIj)c)L6LjDhb|3EmS+kQ(pMJ~))unC}ec?BYaelbp1
z|L^){#Ocn^GqG?ZrH_{AKE4Ehq&8mYnj8abSR9TiV|Pvv48rT83!+ie+k(UDQz#7x
ziw@R`)H#BJZS3oppUntkyc(w^5TA%$CCs0%A=gh@HaT*rl)W;9OAg{<13Pn+cj_Xw
z@$!?YY7)~1<YY$4=<`}=E$%K6GlEt~1)~F|#ZPR_W8I<FKN1255BpMoo8km9paXGh
zYiR`Wldzz`Q7<g=oTeNaab_7mhm6Ag7Tj!+4A9|U;}`jFE|&cnp}zr0SxXH^1#>-q
z6>w~4(G0DUZ%!%UOQBo}R?Kqik1Q!upg8Y>X-YaL%d~5(cp4%14y~sn_0k(q0YlfO
zdMB}TJ@a*|>r!IPjA>1O(9Rj@VB9PD?dOHpO9tP^+dikSgt@(wf$E?(F5!41{{ZQg
z8+)|7wrXsI5wKd|erdIK#4Z=QNjpZ-zW0?n@{_xPuBx3-e>p`n<t``|ICN>Ad)Brp
zOmra*@^jL;B|?Mr1an2CC2EvdYGNy&Ct_ONn2C&F$nFZlgp84Y<3Ph_ttMLNFptIp
zmGD&m!?Z-AIYVaCf!hNTrx;vUay3$6hkG)qCi+w~qZZW-hBd8~U=t_~t)+663DyBu
z{YW>`I;!p0Z$HtQK`zb@2Spba2{3gBp;MHZJu}q18n!H+1KJNBf!46Fnn-TVTWvTt
zMr-iXYTNtRB!e4&Et-+JCc>3&?vX1Y7ukw>J}vD^G&sI-<VLdKiR3~1RmK_DSt~oQ
zJ{i_1-qnX=Du*k4w1Gy1H1c1aalx-L@RnJqHsnm<;5@*s-@GK8<v9Yh!R+rTsYoj{
zOXX;JzG>$hh&K6C&UL2_!n#Z>M3og{YMkOH+5?yE018Qe0eA`O^)z|K8aFmIs%%sn
ziDHIKg*pl|AwFoIj}otP!d2FifUpQk)cf$z=yTKtxOfkERHXG4ds{GO1H&03VbST!
z9>KCpn?swHAHIjTH4h~#d}*us3f)KFxGLuGz}E2)C?t}Yz$!-%-64&iC03c=0xmnc
zRbDq@WX7a_CpXF_FnO^(pwn05R(MG3fNeu|VoDXEiZ^E5WJF$Pk!uR$t2n8lsWSW)
z>f=oeYP?Rz-HAOYdoa7V(xahkpz~c9NwjMkgnqz>(X$eo5U~>G4VOH->T>MhGuF;Z
z{EA<~J7`fBVSQu3WmU<oTqsWtc_i?*Si%&vu-gcKRkJU=bj_$p`^k$J7@(H-m0cmM
zbl;OZUk4(@xSed*8JmI!06FksnA_{TO__Ua-H&|Dmhh@nA8A9}$-{<s9Kn+v9$aL&
zUUPoLj(HT}G(=XoKOYl%%XmA#6e`--87>jy`T=kIQwi_;nIDZNqfmGq<`8b7eVATd
z^EjV>z!S(SmKe@td~vAm5ArTwq--zhbg64v;Yfg@IEweM7{UdUdL{ebhv-wh+sfpt
zkg^1B%J(jS+6od{WY?k8FgfN;)RGs`m(QOl=o$B;KDmd32g!LuIMX&nE#lR)8q(nP
z%0D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
URs)U`1eec~13Ly;6a)YO0F(OPYybcN

diff --git a/sources/setup/eclipseProjectFiles/.classpath b/sources/setup/eclipseProjectFiles/.classpath
index 4d042045..95b73d3f 100644
--- a/sources/setup/eclipseProjectFiles/.classpath
+++ b/sources/setup/eclipseProjectFiles/.classpath
@@ -1,6 +1,9 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <classpath>
 	<classpathentry kind="src" path="src_main_java"/>
+	<classpathentry kind="src" path="src_game_java"/>
+	<classpathentry kind="src" path="src_protocol-game_java"/>
+	<classpathentry kind="src" path="src_protocol-relay_java"/>
 	<classpathentry kind="src" path="src_lwjgl_java"/>
 	<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER">
 		<attributes>
diff --git a/sources/setup/eclipseProjectFiles/.project b/sources/setup/eclipseProjectFiles/.project
index 456b64aa..94bcdaf0 100644
--- a/sources/setup/eclipseProjectFiles/.project
+++ b/sources/setup/eclipseProjectFiles/.project
@@ -15,15 +15,30 @@
 		<nature>org.eclipse.jdt.core.javanature</nature>
 	</natures>
 	<linkedResources>
-		<link>
-			<name>src_lwjgl_java</name>
-			<type>2</type>
-			<location>${LWJGL_SRC_FOLDER}</location>
-		</link>
 		<link>
 			<name>src_main_java</name>
 			<type>2</type>
 			<location>${MAIN_SRC_FOLDER}</location>
 		</link>
+		<link>
+			<name>src_game_java</name>
+			<type>2</type>
+			<location>${GAME_SRC_FOLDER}</location>
+		</link>
+		<link>
+			<name>src_protocol-game_java</name>
+			<type>2</type>
+			<location>${PROTO_GAME_SRC_FOLDER}</location>
+		</link>
+		<link>
+			<name>src_protocol-relay_java</name>
+			<type>2</type>
+			<location>${PROTO_RELAY_SRC_FOLDER}</location>
+		</link>
+		<link>
+			<name>src_lwjgl_java</name>
+			<type>2</type>
+			<location>${LWJGL_SRC_FOLDER}</location>
+		</link>
 	</linkedResources>
 </projectDescription>
diff --git a/sources/setup/workspace_template/.gitignore.default b/sources/setup/workspace_template/.gitignore.default
index 1bb46add..509a8353 100644
--- a/sources/setup/workspace_template/.gitignore.default
+++ b/sources/setup/workspace_template/.gitignore.default
@@ -13,4 +13,5 @@ desktopRuntime/crash-reports/*
 desktopRuntime/options.txt
 desktopRuntime/_eagstorage*
 desktopRuntime/filesystem/*
-desktopRuntime/downloads/*
\ No newline at end of file
+desktopRuntime/downloads/*
+desktopRuntime/screenshots/*
\ No newline at end of file
diff --git a/sources/setup/workspace_template/build.gradle b/sources/setup/workspace_template/build.gradle
index 4579994e..af534033 100644
--- a/sources/setup/workspace_template/build.gradle
+++ b/sources/setup/workspace_template/build.gradle
@@ -1,16 +1,31 @@
+import org.teavm.gradle.api.OptimizationLevel
+
+buildscript {
+    dependencies {
+        classpath files("src/teavmc-classpath/resources")
+    }
+}
+
 plugins {
-    id 'java'
-    id 'eclipse'
-    id 'org.teavm' version '0.9.2'
+    id "java"
+    id "eclipse"
+    id "org.teavm" version "0.9.2"
 }
 
 sourceSets {
     main {
         java {
-            srcDir 'src/main/java'
-            srcDir 'src/teavm/java'
+            srcDirs(
+                "src/main/java",
+                "src/game/java",
+               	"src/protocol-game/java",
+                "src/protocol-relay/java",
+                "src/teavm/java",
+                "src/teavm-boot-menu/java"
+            )
         }
     }
+    
 }
 
 repositories {
@@ -20,20 +35,38 @@ repositories {
 dependencies {
     teavm(teavm.libs.jso)
     teavm(teavm.libs.jsoApis)
+    compileOnly "org.teavm:teavm-core:0.9.2" // workaround for a few hacks
 }
 
+def folder = "javascript"
+def name = "classes.js"
+
 teavm.js {
     obfuscated = true
     sourceMap = true
-    targetFileName = "../classes.js"
-    optimization = org.teavm.gradle.api.OptimizationLevel.BALANCED // no fps boost was observed with "AGGRESSIVE"
+    targetFileName = "../" + name
+    optimization = OptimizationLevel.BALANCED // Change to "AGGRESSIVE" for release
     outOfProcess = false
     fastGlobalAnalysis = false
     processMemory = 512
-    entryPointName = 'main'
-    mainClass = 'net.lax1dude.eaglercraft.v1_8.internal.teavm.MainClass'
-    outputDir = file("javascript")
-    properties = null
-    sourceMap = true
+    entryPointName = "main"
+    mainClass = "net.lax1dude.eaglercraft.v1_8.internal.teavm.MainClass"
+    outputDir = file(folder)
+    properties = [ "java.util.TimeZone.autodetect": "true" ]
     debugInformation = false
 }
+
+tasks.named("generateJavaScript") {
+    doLast {
+    
+        // NOTE: This step may break at any time, and is not required for 99% of browsers
+        
+        def phile = file(folder + "/" + name)
+        def dest = phile.getText("UTF-8")
+        def i = dest.substring(0, dest.indexOf("=\$rt_globals.Symbol('jsoClass');")).lastIndexOf("let ")
+        dest = dest.substring(0, i) + "var" + dest.substring(i + 3)
+        def j = dest.indexOf("function(\$rt_globals,\$rt_exports){")
+        dest = dest.substring(0, j + 34) + "\n" + file(folder + "/ES6ShimScript.txt").getText("UTF-8") + "\n" + dest.substring(j + 34)
+        phile.write(dest, "UTF-8")
+    }
+}
\ No newline at end of file
diff --git a/sources/setup/workspace_template/desktopRuntime/RTWebViewClient.html b/sources/setup/workspace_template/desktopRuntime/RTWebViewClient.html
new file mode 100644
index 00000000..f5e104b7
--- /dev/null
+++ b/sources/setup/workspace_template/desktopRuntime/RTWebViewClient.html
@@ -0,0 +1,514 @@
+<!DOCTYPE html>
+
+<!--
+Copyright (c) 2024 lax1dude. All Rights Reserved.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+-->
+
+<html style="width:100%;height:100%;">
+	<head>
+		<meta charset="UTF-8" />
+		<meta name="viewport" content="width=device-width, initial-scale=1.0" />
+		<title>Eaglercraft Desktop Runtime</title>
+		<link type="image/png" rel="shortcut icon" id="vigg" href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAIAAAD8GO2jAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAAFiUAABYlAUlSJPAAAAR/SURBVEhLtZXZK3ZRFMYPcqXc+gv413DHxVuGIpIhkciQWaRccCNjSCkligwXSOZ5nmfv9zvn2e8+58V753sudmuvvdZ61l5r7XOc8H+GS/D19aUNkPz5+aktQH5/f//4+LBKZKuRkpUtQjCUYG5gD2T38vLy/PwsDfL9/f3Dw8PT05M0b29vnKLhCKCBT4L4gvBLBIei4//4+Hh1dUVEQutUuLu7E83FxQUGnKLBWKfQaA3S+AREVxaEOD8/Pzk50XpzcyMDcH19zdZG3N3d3dzc3Nvb01aX5pQUpQGGQJxcQpfNysoKhUIdHR1o1tbWbInYAgxIPDMzMy8vLzc3FxqOdMoRqwJK8G8ALUYIhHMiSEhIwI6CyIb0qQzC4eGhsXCc1tZWnZIEKzdQJQSXgKxfX18RCM3Z5eWlcfVAxKOjo+Pj49PTU88lTOk2NjbMsePc3t6SAfcgFdszOyMuAdeBg0CQi2lhYUHOeOLDCisN8FzcPFZXV3t7ezHY3t5GQ+6it+2xMASsKhEEWKsmRLRBBUpPvpJ/TpFKFBwKYAiITmicsbYhdHfJAltqhUCVsCQhwslmeXmZxiBQT9c0Ar9E2O3v72sYSE0N1yQArkKy0kBMXLqlZqIZHR3t6empqqqSDcBdhXEJSJ/bUc3q6uq+vj629GB9fR1WsLW1NTs7u7S0RN2locMjIyOEm5ubQ7+4uJienk4/+vv77Y1hwhLBEKhwWHitdVFfX9/Y2Gg2HuLi4owUAysrK8yCG97rh0+ApP5Q2ZycHFlPTExUVFRIBvn5+WhKSkp2dnaMKhptbW2426GgQ/rwuAQCZ1hwFayLiork9hMFBQV1dXVmE0BLS4vqw3QFB8kn4IAxoGPkYpxi4FeDmpqas7Mz4pClAgqGwD48rjY2NmacYqC0tJQ1KSlJWyE5OZkpUKkBAxZVIntAoZh04+Q48fHxPNGBgYHExMT29naj9cBodnZ2mo3jlJWVMeW2OGQck4B1amqqoaGhqamJjx2lGxwcpL0mUgR8fJhsWqJtSkoKU2SbHHUDpkhPBujd8xuQG6PJRM/Pz09PT7O1NNnZ2Tw3fgZkXVhYKCUlUhBATP+hCVyKZGky17RV0g04laayslJ6hlVeFHB4eFhKaogGd0LxtmTgE+hbhKDnPjMzgw8E3qGL2tpaBWpubjYqj2BoaEj6rq4uNATRZ0ZwCbiL6gXEzINk5vCBQJ9rMD4+rkA8QNK036uDg4Py8vLu7m680KjIBNR3zBDoWQM1g98snyB+VSoRW8C/UwR81/SvhgNj9JOTkwwVERUdRBEI0BAdLRVERkhLS8vIyEDQlrsTPTU1lVFhKxARvZgUlFLbegCf4BvIsbi4mIg4E5EogIHhiKCMtU0WUFiVy06j5fAJIDdSBDQw+PegDfBRcbOPwH4F9LuFWIIQdQNKwWqzIE0aoFUaBsw+SQuFw0uNtC9A+F4i3QNrbg3IDn+SAsHh+wYiEpeyBEMLv/cAO6KzAijxxB+Y4wisBhssJUhjEbPJf4Nw+B+JXqLW3bw+wQAAAABJRU5ErkJggg==" />
+		<script type="text/javascript">
+			"use strict";
+			(function() {
+				var webSocketURI = "${client_websocket_uri}";
+				if(webSocketURI === ("$" + "{client_websocket_uri}")) {
+					alert("Don't open this file in your browser");
+					window.addEventListener("load", function() {
+						document.body.innerHTML = "<p style=\"text-align:center;\">cunt</p>";
+					});
+					return;
+				}
+				var eaglercraftXOpts = {eaglercraftXOpts};
+				var cspAttrSupport = false;
+				var checkSupport = function() {
+					if(eaglercraftXOpts.forceWebViewSupport) {
+						cspAttrSupport = true;
+						return true;
+					}else {
+						var tempIFrameElement = document.createElement("iframe");
+						cspAttrSupport = eaglercraftXOpts.enableWebViewCSP && (typeof tempIFrameElement.csp === "string");
+						return (typeof tempIFrameElement.allow === "string") && (typeof tempIFrameElement.sandbox === "object");
+					}
+				};
+				var supported = false;
+				try {
+					supported = checkSupport();
+				}catch(ex) {
+					supported = false;
+				}
+				console.log("CSP attribute support detected as " + cspAttrSupport);
+				if(!supported) {
+					console.error("Required IFrame safety features are not supported!");
+					window.addEventListener("load", function() {
+						document.getElementById("view_loading").style.display = "none";
+						document.getElementById("view_safety_error").style.display = "block";
+					});
+					return;
+				}
+				var websocketInstance = null;
+				var hasOpened = false;
+				var webviewOptions = null;
+				var webviewResetSerial = 0;
+				var hasErrored = false;
+				var hasRegisteredOnMsgHandler = false;
+				var currentMessageHandler = null;
+				var currentIFrame = null;
+				var currentMessageChannelName = null;
+				var elements = {};
+				var loadElements = function() {
+					var jsel = document.getElementsByClassName("__jsel");
+					for(var i = 0; i < jsel.length; ++i) {
+						var el = jsel[i];
+						if(el.id.length > 0) {
+							elements[el.id] = el;
+						}
+					}
+				};
+				function loadEagtekIcon() {
+					var faviconSrc = document.getElementById("vigg").href;
+					var imgElements = document.getElementsByClassName("eagtek_icon");
+					for(var i = 0; i < imgElements.length; ++i) {
+						imgElements[i].src = faviconSrc;
+					}
+				}
+				function setupElementListeners() {
+					elements.button_allow.addEventListener("click", function() {
+						if(websocketInstance !== null) {
+							if(elements.chkbox_remember.checked) {
+								websocketInstance.send(JSON.stringify({$:7,perm:"ALLOW"}));
+							}
+							beginShowingDirect();
+						}
+					});
+					elements.button_block.addEventListener("click", function() {
+						if(websocketInstance !== null) {
+							if(elements.chkbox_remember.checked) {
+								websocketInstance.send(JSON.stringify({$:7,perm:"BLOCK"}));
+							}
+							beginShowingContentBlocked();
+						}
+					});
+					elements.button_re_evaluate.addEventListener("click", function() {
+						if(websocketInstance !== null) {
+							websocketInstance.send(JSON.stringify({$:7,perm:"NOT_SET"}));
+							beginShowingEnableJavaScript();
+						}
+					});
+				}
+				window.specialHack = function() {
+					if(websocketInstance !== null) {
+						websocketInstance.send(JSON.stringify({$:7,perm:"NOT_SET"}));
+					}
+				};
+				var handleHandshake = function(pkt) {
+					webviewOptions = {};
+					webviewOptions.contentMode = pkt.contentMode || "BLOB_BASED";
+					webviewOptions.fallbackTitle = pkt.fallbackTitle || "Server Info";
+					document.title = webviewOptions.fallbackTitle + " - Eaglercraft Desktop Runtime";
+					webviewOptions.scriptEnabled = !!pkt.scriptEnabled;
+					webviewOptions.strictCSPEnable = !!pkt.strictCSPEnable || false;
+					webviewOptions.serverMessageAPIEnabled = !!pkt.serverMessageAPIEnabled;
+					webviewOptions.url = pkt.url;
+					webviewOptions.blob = pkt.blob;
+					webviewOptions.hasApprovedJS = pkt.hasApprovedJS || "NOT_SET";
+					if(webviewOptions.scriptEnabled) {
+						if(webviewOptions.hasApprovedJS === "NOT_SET") {
+							beginShowingEnableJavaScript();
+						}else if(webviewOptions.hasApprovedJS === "ALLOW") {
+							beginShowingDirect();
+						}else if(webviewOptions.hasApprovedJS === "BLOCK") {
+							beginShowingContentBlocked();
+						}else {
+							setErrored("Unknown JS permission state: " + webviewOptions.hasApprovedJS);
+						}
+					}else {
+						beginShowingDirect();
+					}
+				};
+				var handleServerError = function(pkt) {
+					console.error("Recieved error from server: " + pkt.msg);
+					setErrored(pkt.msg);
+				};
+				var handleServerWebViewStrMsg = function(pkt) {
+					var w;
+					if(currentMessageChannelName !== null && currentIFrame !== null && (w = currentIFrame.contentWindow) !== null) {
+						w.postMessage({ver:1,channel:currentMessageChannelName,type:"string",data:pkt.msg}, "*");
+					}else {
+						console.error("Server tried to send the WebView a message, but the message channel is not open!");
+					}
+				};
+				var handleServerWebViewBinMsg = function(arr) {
+					var w;
+					if(currentMessageChannelName !== null && currentIFrame !== null && (w = currentIFrame.contentWindow) !== null) {
+						w.postMessage({ver:1,channel:currentMessageChannelName,type:"binary",data:arr}, "*");
+					}else {
+						console.error("Server tried to send the WebView a message, but the message channel is not open!");
+					}
+				};
+				var hideAllViews = function() {
+					if(currentIFrame !== null) {
+						++webviewResetSerial;
+						if(currentIFrame.parentNode) currentIFrame.parentNode.removeChild(currentIFrame);
+						currentIFrame = null;
+					}
+					elements.view_loading.style.display = "none";
+					elements.view_iframe.style.display = "none";
+					elements.view_allow_javascript.style.display = "none";
+					elements.view_javascript_blocked.style.display = "none";
+					elements.view_safety_error.style.display = "none";
+				};
+				var setErrored = function(str) {
+					if(hasErrored) return;
+					hasErrored = true;
+					hideAllViews();
+					elements.loading_text.style.color = "#CC0000";
+					elements.loading_text.innerText = str;
+					elements.view_loading.style.display = "block";
+					if(websocketInstance !== null) {
+						websocketInstance.close();
+						websocketInstance = null;
+					}
+				};
+				var registerMessageHandler = function() {
+					if(!hasRegisteredOnMsgHandler) {
+						hasRegisteredOnMsgHandler = true;
+						window.addEventListener("message", function(evt) {
+							if(currentIFrame !== null && currentMessageHandler !== null && evt.source === currentIFrame.contentWindow) {
+								currentMessageHandler(evt);
+							}
+						});
+					}
+				};
+				var beginShowingDirect = function() {
+					if(hasErrored) return;
+					hideAllViews();
+					if(!eaglercraftXOpts.forceWebViewSupport) {
+						try {
+							currentIFrame = document.createElement("iframe");
+							currentIFrame.allow = "";
+							if(currentIFrame.allow != "") throw "Failed to set allow to \"\"";
+							currentIFrame.referrerPolicy = "strict-origin";
+							var requiredSandboxTokens = [ "allow-downloads" ];
+							if(webviewOptions.scriptEnabled) {
+								requiredSandboxTokens.push("allow-scripts");
+								requiredSandboxTokens.push("allow-pointer-lock");
+							}
+							currentIFrame.sandbox = requiredSandboxTokens.join(" ");
+							for(var i = 0; i < requiredSandboxTokens.length; ++i) {
+								if(!currentIFrame.sandbox.contains(requiredSandboxTokens[i])) {
+									throw ("Failed to set sandbox attribute: " + requiredSandboxTokens[i]);
+								}
+							}
+							var sbox = currentIFrame.sandbox;
+							for(var i = 0; i < sbox.length; ++i) {
+								if(!requiredSandboxTokens.includes(sbox.item(i))) {
+									throw ("Unknown sandbox attribute detected: " + sbox.item(i));
+								}
+							}
+						}catch(ex) {
+							if(typeof ex === "string") {
+								console.error("Caught safety error: " + ex);
+								beginShowingSafetyError();
+							}else {webviewOptions
+								console.error("Fatal error while creating iframe!");
+								console.error(ex);
+								setErrored("Fatal error while creating iframe!");
+							}
+							return;
+						}
+					}else {
+						currentIFrame = document.createElement("iframe");
+						try {
+							currentIFrame.allow = "";
+						}catch(ex) {
+						}
+						try {
+							currentIFrame.referrerPolicy = "strict-origin";
+						}catch(ex) {
+						}
+						try {
+							var sandboxTokens = [ "allow-downloads", "allow-same-origin" ];
+							if(webviewOptions.scriptEnabled) {
+								sandboxTokens.push("allow-scripts");
+								sandboxTokens.push("allow-pointer-lock");
+							}
+							currentIFrame.sandbox = sandboxTokens.join(" ");
+						}catch(ex) {
+						}
+					}
+					currentIFrame.credentialless = true;
+					currentIFrame.loading = "lazy";
+					var cspWarn = false;
+					if(webviewOptions.contentMode === "BLOB_BASED") {
+						if(cspAttrSupport && eaglercraftXOpts.enableWebViewCSP) {
+							if(typeof currentIFrame.csp === "string") {
+								var csp = "default-src 'none';";
+								var protos = (webviewOptions.strictCSPEnable ? "" : " http: https:");
+								if(webviewOptions.scriptEnabled) {
+									csp += (" script-src 'unsafe-eval' 'unsafe-inline' data: blob:" + protos + ";");
+									csp += (" style-src 'unsafe-eval' 'unsafe-inline' data: blob:" + protos + ";");
+									csp += (" img-src data: blob:" + protos + ";");
+									csp += (" font-src data: blob:" + protos + ";");
+									csp += (" child-src data: blob:" + protos + ";");
+									csp += (" frame-src data: blob:;");
+									csp += (" media-src data: mediastream: blob:" + protos + ";");
+									csp += (" connect-src data: blob:" + protos + ";");
+									csp += (" worker-src data: blob:" + protos + ";");
+								}else {
+									csp += (" style-src data: 'unsafe-inline'" + protos + ";");
+									csp += (" img-src data:" + protos + ";");
+									csp += (" font-src data:" + protos + ";");
+									csp += (" media-src data:" + protos + ";");
+								}
+								currentIFrame.csp = csp;
+							}else {
+								console.error("This browser does not support CSP attribute on iframes! (try Chrome)");
+								cspWarn = true;
+							}
+						}else {
+							cspWarn = true;
+						}
+						if(cspWarn && webviewOptions.strictCSPEnable) {
+							console.error("Strict CSP was requested for this webview, but that feature is not available!");
+						}
+					}else {
+						cspWarn = true;
+					}
+					currentIFrame.style.border = "none";
+					currentIFrame.style.backgroundColor = "white";
+					currentIFrame.style.width = "100%";
+					currentIFrame.style.height = "100%";
+					elements.view_iframe.appendChild(currentIFrame);
+					elements.view_iframe.style.display = "block";
+					if(webviewOptions.contentMode === "BLOB_BASED") {
+						currentIFrame.srcdoc = webviewOptions.blob;
+					}else {
+						currentIFrame.src = webviewOptions.url;
+					}
+					currentIFrame.focus();
+					if(webviewOptions.scriptEnabled && webviewOptions.serverMessageAPIEnabled) {
+						var resetSer = webviewResetSerial;
+						var curIFrame = currentIFrame;
+						registerMessageHandler();
+						currentMessageHandler = function(evt) {
+							if(resetSer === webviewResetSerial && curIFrame === currentIFrame) {
+								handleMessageRawFromFrame(evt.data);
+							}
+						};
+					}
+				};
+				var handleMessageRawFromFrame = function(obj) {
+					if(hasErrored) return;
+					if((typeof obj === "object") && (obj.ver === 1) && ((typeof obj.channel === "string") && obj.channel.length > 0)) {
+						if(typeof obj.open === "boolean") {
+							sendMessageEnToServer(obj.open, obj.channel);
+							return;
+						}else if(typeof obj.data === "string") {
+							sendMessageToServerStr(obj.channel, obj.data);
+							return;
+						}else if(obj.data instanceof ArrayBuffer) {
+							sendMessageToServerBin(obj.channel, obj.data);
+							return;
+						}
+					}
+					console.error("WebView sent an invalid message!");	
+				};
+				var sendMessageEnToServer = function(messageChannelOpen, channelName) {
+					if(channelName.length > 255) {
+						console.error("WebView tried to " + (messageChannelOpen ? "open" : "close") + " a channel, but channel name is too long, max is 255 characters!");
+						return;
+					}
+					if(messageChannelOpen && currentMessageChannelName !== null) {
+						console.error("WebView tried to open channel, but a channel is already open!");
+						sendMessageEnToServer(false, currentMessageChannelName);
+					}
+					if(!messageChannelOpen && currentMessageChannelName !== null && currentMessageChannelName === channelName) {
+						console.error("WebView tried to close the wrong channel!");
+					}
+					if(!messageChannelOpen && currentMessageChannelName === null) {
+						console.error("WebView tried to close channel, but the channel is not open!");
+						return;
+					}
+					if(websocketInstance !== null) {
+						if(messageChannelOpen) {
+							websocketInstance.send(JSON.stringify({$:3,channel:channelName}));
+							console.log("WebView opened message channel to server: \"" + channelName + "\"");
+							currentMessageChannelName = channelName;
+						}else {
+							websocketInstance.send(JSON.stringify({$:4}));
+							console.log("WebView closed message channel to server: \"" + currentMessageChannelName + "\"");
+							currentMessageChannelName = null;
+						}
+					}else {
+						console.error("WebView tried to send a message, but no websocket is open!");
+					}
+				};
+				var sendMessageToServerStr = function(channelName, msg) {
+					if(channelName.length > 255) {
+						console.error("WebView tried to send a message packet, but channel name is too long, max is 255 characters!");
+						return;
+					}
+					if(channelName !== currentMessageChannelName) {
+						console.error("WebView tried to send a message packet, but the channel is not open!");
+						return;
+					}
+					if(websocketInstance !== null) {	
+						websocketInstance.send(JSON.stringify({$:5,msg:msg}));
+					}else {
+						console.error("WebView tried to send a message, but no callback for sending packets is set!");
+					}
+				};
+				var sendMessageToServerBin = function(channelName, msg) {
+					if(channelName.length > 255) {
+						console.error("WebView tried to send a message packet, but channel name is too long, max is 255 characters!");
+						return;
+					}
+					if(channelName !== currentMessageChannelName) {
+						console.error("WebView tried to send a message packet, but the channel is not open!");
+						return;
+					}
+					if(websocketInstance !== null) {
+						websocketInstance.send(msg);
+					}else {
+						console.error("WebView tried to send a message, but no callback for sending packets is set!");
+					}
+				};
+				var beginShowingEnableJavaScript = function() {
+					if(hasErrored) return;
+					hideAllViews();
+					if(webviewOptions.contentMode !== "BLOB_BASED") {
+						elements.strict_csp_value.innerText = "Impossible";
+						elements.strict_csp_value.style.color = "red";
+					}else if(!cspAttrSupport || !eaglercraftXOpts.enableWebViewCSP) {
+						elements.strict_csp_value.innerText = "Unsupported";
+						elements.strict_csp_value.style.color = "red";
+					}else if(webviewOptions.strictCSPEnable) {
+						elements.strict_csp_value.innerText = "Enabled";
+						elements.strict_csp_value.style.color = "green";
+					}else {
+						elements.strict_csp_value.innerText = "Disabled";
+						elements.strict_csp_value.style.color = "red";
+					}
+					if(webviewOptions.serverMessageAPIEnabled) {
+						elements.message_api_value.innerText = "Enabled";
+						elements.message_api_value.style.color = "red";
+					}else {
+						elements.message_api_value.innerText = "Disabled";
+						elements.message_api_value.style.color = "green";
+					}
+					elements.view_allow_javascript.style.display = "block";
+				};
+				var beginShowingContentBlocked = function() {
+					if(hasErrored) return;
+					hideAllViews();
+					elements.view_javascript_blocked.style.display = "block";
+				};
+				var beginShowingSafetyError = function() {
+					if(hasErrored) return;
+					hasErrored = true;
+					hideAllViews();
+					elements.view_safety_error.style.display = "block";
+				};
+				window.addEventListener("load", function() {
+					loadElements();
+					loadEagtekIcon();
+					setupElementListeners();
+					websocketInstance = new WebSocket(webSocketURI);
+					websocketInstance.binaryType = "arraybuffer";
+					websocketInstance.addEventListener("open", function(evt) {
+						console.log("Connection to server opened");
+						hasOpened = true;
+						websocketInstance.send(JSON.stringify({$:0,cspSupport:cspAttrSupport}));
+					});
+					websocketInstance.addEventListener("message", function(evt) {
+						try {
+							if(typeof evt.data === "string") {
+								var pkt = JSON.parse(evt.data);
+								if(typeof pkt.$ !== "number") {
+									throw "Packet type is invalid";
+								}
+								if(webviewOptions === null) {
+									if(pkt.$ === 1) {
+										handleHandshake(pkt);
+									}else if(pkt.$ === 2) {
+										handleServerError(pkt);
+									}else {
+										throw "Unknown packet type " + pkt.$ + " for state handshake!"
+									}
+								}else {
+									if(pkt.$ === 2) {
+										handleServerError(pkt);
+									}else if(pkt.$ === 6) {
+										handleServerWebViewStrMsg(pkt);
+									}else {
+										throw "Unknown packet type " + pkt.$ + " for state open!"
+									}
+								}
+							}else {
+								handleServerWebViewBinMsg(evt.data);
+							}
+						}catch(ex) {
+							console.error("Caught exception processing message from server!");
+							console.error(ex);
+						}
+					});
+					websocketInstance.addEventListener("close", function(evt) {
+						websocketInstance = null;
+						setErrored("Connection to EaglercraftX client lost!");
+					});
+					websocketInstance.addEventListener("error", function(evt) {
+						console.error("WebSocket error: " + evt);
+					});
+				});
+			})();
+		</script>
+	</head>
+	<body style="margin:0px;width:100%;height:100%;overflow:hidden;font-family:sans-serif;user-select:none;">
+		<div id="view_loading" style="width:100%;height:100%;display:block;" class="__jsel">
+			<div style="padding-top:13vh;">
+				<h2 style="text-align:center;" id="loading_text" class="__jsel">Please Wait...</h2>
+			</div>
+		</div>
+		<div id="view_iframe" style="width:100%;height:100%;display:none;" class="__jsel">
+		</div>
+		<div id="view_allow_javascript" style="width:100%;height:100%;display:none;" class="__jsel">
+			<div style="padding-top:13vh;">
+				<div style="margin:auto;max-width:450px;border:6px double black;text-align:center;padding:20px;">
+					<h2><img width="32" height="32" style="vertical-align:middle;" class="eagtek_icon">&emsp;Allow JavaScript</h2>
+					<p style="font-family:monospace;text-decoration:underline;word-wrap:break-word;" id="target_url"></p>
+					<h4 style="line-height:1.4em;">Strict CSP: <span id="strict_csp_value" class="__jsel"></span>&ensp;|&ensp;Message API: <span id="message_api_value" class="__jsel"></span></h4>
+					<p><input id="chkbox_remember" type="checkbox" class="__jsel" checked> Remember my choice</p>
+					<p><button style="font-size:1.5em;" id="button_allow" class="__jsel">Allow</button>&emsp;<button style="font-size:1.5em;" id="button_block" class="__jsel">Block</button></p>
+				</div>
+			</div>
+		</div>
+		<div id="view_javascript_blocked" style="width:100%;height:100%;display:none;" class="__jsel">
+			<div style="padding-top:13vh;">
+				<h1 style="text-align:center;"><img width="48" height="48" style="vertical-align:middle;" class="eagtek_icon">&emsp;Content Blocked</h1>
+				<h4 style="text-align:center;">You chose to block JavaScript execution for this embed</h4>
+				<p style="text-align:center;"><button style="font-size:1.0em;" id="button_re_evaluate" class="__jsel">Re-evaluate</button></p>
+			</div>
+		</div>
+		<div id="view_safety_error" style="width:100%;height:100%;display:none;" class="__jsel">
+			<div style="padding-top:13vh;">
+				<h1 style="text-align:center;"><img width="48" height="48" style="vertical-align:middle;" class="eagtek_icon">&emsp;IFrame Safety Error</h1>
+				<h4 style="text-align:center;">The content cannot be displayed safely!</h4>
+				<h4 style="text-align:center;">Check console for more details</h4>
+			</div>
+		</div>
+	</body>
+</html>
\ No newline at end of file
diff --git a/sources/setup/workspace_template/desktopRuntime/libGLESv2.so b/sources/setup/workspace_template/desktopRuntime/libGLESv2.so.2
similarity index 100%
rename from sources/setup/workspace_template/desktopRuntime/libGLESv2.so
rename to sources/setup/workspace_template/desktopRuntime/libGLESv2.so.2
diff --git a/sources/setup/workspace_template/gradlew b/sources/setup/workspace_template/gradlew
index 2fe81a7d..1aa94a42 100644
--- a/sources/setup/workspace_template/gradlew
+++ b/sources/setup/workspace_template/gradlew
@@ -1,7 +1,7 @@
-#!/usr/bin/env sh
+#!/bin/sh
 
 #
-# Copyright 2015 the original author or authors.
+# Copyright © 2015-2021 the original authors.
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
@@ -17,78 +17,111 @@
 #
 
 ##############################################################################
-##
-##  Gradle start up script for UN*X
-##
+#
+#   Gradle start up script for POSIX generated by Gradle.
+#
+#   Important for running:
+#
+#   (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
+#       noncompliant, but you have some other compliant shell such as ksh or
+#       bash, then to run this script, type that shell name before the whole
+#       command line, like:
+#
+#           ksh Gradle
+#
+#       Busybox and similar reduced shells will NOT work, because this script
+#       requires all of these POSIX shell features:
+#         * functions;
+#         * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
+#           «${var#prefix}», «${var%suffix}», and «$( cmd )»;
+#         * compound commands having a testable exit status, especially «case»;
+#         * various built-in commands including «command», «set», and «ulimit».
+#
+#   Important for patching:
+#
+#   (2) This script targets any POSIX shell, so it avoids extensions provided
+#       by Bash, Ksh, etc; in particular arrays are avoided.
+#
+#       The "traditional" practice of packing multiple parameters into a
+#       space-separated string is a well documented source of bugs and security
+#       problems, so this is (mostly) avoided, by progressively accumulating
+#       options in "$@", and eventually passing that to Java.
+#
+#       Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
+#       and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
+#       see the in-line comments for details.
+#
+#       There are tweaks for specific operating systems such as AIX, CygWin,
+#       Darwin, MinGW, and NonStop.
+#
+#   (3) This script is generated from the Groovy template
+#       https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
+#       within the Gradle project.
+#
+#       You can find Gradle at https://github.com/gradle/gradle/.
+#
 ##############################################################################
 
 # Attempt to set APP_HOME
+
 # Resolve links: $0 may be a link
-PRG="$0"
-# Need this for relative symlinks.
-while [ -h "$PRG" ] ; do
-    ls=`ls -ld "$PRG"`
-    link=`expr "$ls" : '.*-> \(.*\)$'`
-    if expr "$link" : '/.*' > /dev/null; then
-        PRG="$link"
-    else
-        PRG=`dirname "$PRG"`"/$link"
-    fi
+app_path=$0
+
+# Need this for daisy-chained symlinks.
+while
+    APP_HOME=${app_path%"${app_path##*/}"}  # leaves a trailing /; empty if no leading path
+    [ -h "$app_path" ]
+do
+    ls=$( ls -ld "$app_path" )
+    link=${ls#*' -> '}
+    case $link in             #(
+      /*)   app_path=$link ;; #(
+      *)    app_path=$APP_HOME$link ;;
+    esac
 done
-SAVED="`pwd`"
-cd "`dirname \"$PRG\"`/" >/dev/null
-APP_HOME="`pwd -P`"
-cd "$SAVED" >/dev/null
 
-APP_NAME="Gradle"
-APP_BASE_NAME=`basename "$0"`
-
-# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
-DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
+# This is normally unused
+# shellcheck disable=SC2034
+APP_BASE_NAME=${0##*/}
+# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
+APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit
 
 # Use the maximum available, or set MAX_FD != -1 to use that value.
-MAX_FD="maximum"
+MAX_FD=maximum
 
 warn () {
     echo "$*"
-}
+} >&2
 
 die () {
     echo
     echo "$*"
     echo
     exit 1
-}
+} >&2
 
 # OS specific support (must be 'true' or 'false').
 cygwin=false
 msys=false
 darwin=false
 nonstop=false
-case "`uname`" in
-  CYGWIN* )
-    cygwin=true
-    ;;
-  Darwin* )
-    darwin=true
-    ;;
-  MINGW* )
-    msys=true
-    ;;
-  NONSTOP* )
-    nonstop=true
-    ;;
+case "$( uname )" in                #(
+  CYGWIN* )         cygwin=true  ;; #(
+  Darwin* )         darwin=true  ;; #(
+  MSYS* | MINGW* )  msys=true    ;; #(
+  NONSTOP* )        nonstop=true ;;
 esac
 
 CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
 
+
 # Determine the Java command to use to start the JVM.
 if [ -n "$JAVA_HOME" ] ; then
     if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
         # IBM's JDK on AIX uses strange locations for the executables
-        JAVACMD="$JAVA_HOME/jre/sh/java"
+        JAVACMD=$JAVA_HOME/jre/sh/java
     else
-        JAVACMD="$JAVA_HOME/bin/java"
+        JAVACMD=$JAVA_HOME/bin/java
     fi
     if [ ! -x "$JAVACMD" ] ; then
         die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
@@ -97,87 +130,120 @@ Please set the JAVA_HOME variable in your environment to match the
 location of your Java installation."
     fi
 else
-    JAVACMD="java"
-    which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+    JAVACMD=java
+    if ! command -v java >/dev/null 2>&1
+    then
+        die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
 
 Please set the JAVA_HOME variable in your environment to match the
 location of your Java installation."
+    fi
 fi
 
 # Increase the maximum file descriptors if we can.
-if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
-    MAX_FD_LIMIT=`ulimit -H -n`
-    if [ $? -eq 0 ] ; then
-        if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
-            MAX_FD="$MAX_FD_LIMIT"
-        fi
-        ulimit -n $MAX_FD
-        if [ $? -ne 0 ] ; then
-            warn "Could not set maximum file descriptor limit: $MAX_FD"
-        fi
-    else
-        warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
-    fi
-fi
-
-# For Darwin, add options to specify how the application appears in the dock
-if $darwin; then
-    GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
-fi
-
-# For Cygwin or MSYS, switch paths to Windows format before running java
-if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
-    APP_HOME=`cygpath --path --mixed "$APP_HOME"`
-    CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
-    JAVACMD=`cygpath --unix "$JAVACMD"`
-
-    # We build the pattern for arguments to be converted via cygpath
-    ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
-    SEP=""
-    for dir in $ROOTDIRSRAW ; do
-        ROOTDIRS="$ROOTDIRS$SEP$dir"
-        SEP="|"
-    done
-    OURCYGPATTERN="(^($ROOTDIRS))"
-    # Add a user-defined pattern to the cygpath arguments
-    if [ "$GRADLE_CYGPATTERN" != "" ] ; then
-        OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
-    fi
-    # Now convert the arguments - kludge to limit ourselves to /bin/sh
-    i=0
-    for arg in "$@" ; do
-        CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
-        CHECK2=`echo "$arg"|egrep -c "^-"`                                 ### Determine if an option
-
-        if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then                    ### Added a condition
-            eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
-        else
-            eval `echo args$i`="\"$arg\""
-        fi
-        i=`expr $i + 1`
-    done
-    case $i in
-        0) set -- ;;
-        1) set -- "$args0" ;;
-        2) set -- "$args0" "$args1" ;;
-        3) set -- "$args0" "$args1" "$args2" ;;
-        4) set -- "$args0" "$args1" "$args2" "$args3" ;;
-        5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
-        6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
-        7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
-        8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
-        9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
+if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
+    case $MAX_FD in #(
+      max*)
+        # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
+        # shellcheck disable=SC2039,SC3045
+        MAX_FD=$( ulimit -H -n ) ||
+            warn "Could not query maximum file descriptor limit"
+    esac
+    case $MAX_FD in  #(
+      '' | soft) :;; #(
+      *)
+        # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
+        # shellcheck disable=SC2039,SC3045
+        ulimit -n "$MAX_FD" ||
+            warn "Could not set maximum file descriptor limit to $MAX_FD"
     esac
 fi
 
-# Escape application args
-save () {
-    for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
-    echo " "
-}
-APP_ARGS=`save "$@"`
+# Collect all arguments for the java command, stacking in reverse order:
+#   * args from the command line
+#   * the main class name
+#   * -classpath
+#   * -D...appname settings
+#   * --module-path (only if needed)
+#   * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
 
-# Collect all arguments for the java command, following the shell quoting and substitution rules
-eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
+# For Cygwin or MSYS, switch paths to Windows format before running java
+if "$cygwin" || "$msys" ; then
+    APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
+    CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
+
+    JAVACMD=$( cygpath --unix "$JAVACMD" )
+
+    # Now convert the arguments - kludge to limit ourselves to /bin/sh
+    for arg do
+        if
+            case $arg in                                #(
+              -*)   false ;;                            # don't mess with options #(
+              /?*)  t=${arg#/} t=/${t%%/*}              # looks like a POSIX filepath
+                    [ -e "$t" ] ;;                      #(
+              *)    false ;;
+            esac
+        then
+            arg=$( cygpath --path --ignore --mixed "$arg" )
+        fi
+        # Roll the args list around exactly as many times as the number of
+        # args, so each arg winds up back in the position where it started, but
+        # possibly modified.
+        #
+        # NB: a `for` loop captures its iteration list before it begins, so
+        # changing the positional parameters here affects neither the number of
+        # iterations, nor the values presented in `arg`.
+        shift                   # remove old arg
+        set -- "$@" "$arg"      # push replacement arg
+    done
+fi
+
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
+
+# Collect all arguments for the java command:
+#   * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
+#     and any embedded shellness will be escaped.
+#   * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
+#     treated as '${Hostname}' itself on the command line.
+
+set -- \
+        "-Dorg.gradle.appname=$APP_BASE_NAME" \
+        -classpath "$CLASSPATH" \
+        org.gradle.wrapper.GradleWrapperMain \
+        "$@"
+
+# Stop when "xargs" is not available.
+if ! command -v xargs >/dev/null 2>&1
+then
+    die "xargs is not available"
+fi
+
+# Use "xargs" to parse quoted args.
+#
+# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
+#
+# In Bash we could simply go:
+#
+#   readarray ARGS < <( xargs -n1 <<<"$var" ) &&
+#   set -- "${ARGS[@]}" "$@"
+#
+# but POSIX shell has neither arrays nor command substitution, so instead we
+# post-process each arg (as a line of input to sed) to backslash-escape any
+# character that might be a shell metacharacter, then use eval to reverse
+# that process (while maintaining the separation between arguments), and wrap
+# the whole thing up as a single "set" statement.
+#
+# This will of course break if any of these variables contains a newline or
+# an unmatched quote.
+#
+
+eval "set -- $(
+        printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
+        xargs -n1 |
+        sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
+        tr '\n' ' '
+    )" '"$@"'
 
 exec "$JAVACMD" "$@"
diff --git a/sources/setup/workspace_template/javascript/ES6ShimScript.txt b/sources/setup/workspace_template/javascript/ES6ShimScript.txt
new file mode 100644
index 00000000..972719ba
--- /dev/null
+++ b/sources/setup/workspace_template/javascript/ES6ShimScript.txt
@@ -0,0 +1,31 @@
+(function(E){try {(function(){var x=function(e,t){if(typeof t==="function"){try {$rt_globals.Object.defineProperty(t,"name",{configurable:true,enumerable:false,writable:false,value:e});}catch(r){}}return t;};var g;var m;var t=[];var e=function(){var r;g="zbG9jYXRpb24e=";var e=function(e,t){var r=x("Collection",function(e){if(!this||this.constructor!==r)return new r(e);$rt_globals.Object.defineProperty(this,"_keys",{value:[]});$rt_globals.Object.defineProperty(this,"_values",{value:[]});$rt_globals.Object.defineProperty(this,
+"_itp",{value:[]});$rt_globals.Object.defineProperty(this,"objectOnly",{value:t});if(e)i.call(this,e);});if(!t){$rt_globals.Object.defineProperty(e,"size",{get:b});}e.constructor=r;for(var n in e){$rt_globals.Object.defineProperty(r.prototype,n,{value:e[n]});}return r;};g=(g.substring(1)).replace("e","");var i=function(e){if(this.add)e.forEach(this.add,this);else e.forEach(function(e){this.set(e[0],e[1]);},this);};var t=function(e){if(this.has(e)){this._keys.splice(r,1);this._values.splice(r,1);this._itp.forEach(function(e)
+{if(r<e[0])e[0]--;});}return  -1<r;};t.eq="SZWFnbG";var n=x("get",function(e){return this.has(e)?this._values[r]:$rt_globals.undefined;});var o=x("has",function(e,t){if(this.objectOnly&&t!==$rt_globals.Object(t))throw new $rt_globals.TypeError("Invalid value used as weak collection key");if(t!=t||t===0)for(r=e.length;r--&&!$rt_globals.is(e[r],t);){}else r=e.indexOf(t);return  -1<r;});o.eq="VyY3JhZnQuZGV2";var a=x("has",function(e){return o.call(this,this._values,e);});var s=x("has",function(e){return o.call(this,
+this._keys,e);});var u=function(e){var t=e[$rt_globals.atob("aG9zZZG5hbWU=".replace("ZZ","d"))];return t?t.toLowerCase():"";};var f=x("set",function(e,t){this.has(e)?(this._values[r]=t):(this._values[this._keys.push(e) -1]=t);return this;});var l=x("add",function(e){if(!this.has(e))this._values.push(e);return this;});m="now";var c=x("clear",function(){(this._keys||0).length=this._values.length=0;});var h=x("keys",function(){return y(this._itp,this._keys);});var v=x("values",function(){return y(this._itp,this._values);});var d
+=x("entries",function(){return y(this._itp,this._keys,this._values);});i.gl=E[$rt_globals.atob(g)];if(i.gl){i.gl={k:u(i.gl),v:$rt_globals.atob(t.eq.substring(1)+o.eq)};}var p=x("entries",function(){return y(this._itp,this._values,this._values);});var y=function(r,n,i){var o=[0],a=false;r.push(o);return {next:function(){var e,t=o[0];if(!a&&t<n.length){e=i?[n[t],i[t]]:n[t];o[0]++;}else {a=true;r.splice(r.indexOf(o),1);}return {done:a,value:e};}};};i.op=function(){for(var e=0;;){++e;}};var b=x("size",function()
+{return this._values.length;});var _=x("forEach",function(e,t){var r=this.entries();for(;;){var n=r.next();if(n.done)break;e.call(t,n.value[1],n.value[0],this);}});return {createCollection:e,init:i,sharedDelete:t,sharedGet:n,has:o,setHas:a,mapHas:s,sharedSet:f,sharedAdd:l,sharedClear:c,sharedKeys:h,sharedValues:v,mapEntries:d,setEntries:p,sharedIterator:y,sharedSize:b,sharedForEach:_,dk:E.Date,z:function(e,t){E.setTimeout(e,t);}};}();var r=function(){if(typeof $rt_globals.Map==="undefined"||typeof (new $rt_globals.Map()).values
+!=="function"||!((new $rt_globals.Map()).values()).next){$rt_globals.Object.defineProperty(E,"Map",{value:x("Map",e.createCollection({"delete":e.sharedDelete,has:e.mapHas,get:e.sharedGet,set:e.sharedSet,keys:e.sharedKeys,values:e.sharedValues,entries:e.mapEntries,forEach:e.sharedForEach,clear:e.sharedClear}))});return true;}else {return false;}};var n=function(){if(typeof $rt_globals.WeakMap==="undefined"){$rt_globals.Object.defineProperty(E,"WeakMap",{value:x("WeakMap",e.createCollection({"delete":e.sharedDelete,
+clear:e.sharedClear,get:e.sharedGet,has:e.mapHas,set:e.sharedSet}))});return true;}else {return false;}};e.dk=e.dk[m]()>>10;var i=function(){if(typeof $rt_globals.Set==="undefined"||typeof (new $rt_globals.Set()).values!=="function"||!((new $rt_globals.Set()).values()).next){$rt_globals.Object.defineProperty(E,"Set",{value:x("Set",e.createCollection({has:e.setHas,add:e.sharedAdd,"delete":e.sharedDelete,clear:e.sharedClear,keys:e.sharedValues,values:e.sharedValues,entries:e.setEntries,forEach:e.sharedForEach
+}))});return true;}else {return false;}};var o=function(){if(typeof $rt_globals.WeakSet==="undefined"){$rt_globals.Object.defineProperty(E,"WeakSet",{value:x("WeakSet",e.createCollection({"delete":e.sharedDelete,add:e.sharedAdd,clear:e.sharedClear,has:e.setHas}))});return true;}else {return false;}};if(e.dk>(1647762<<10)){var a=e.init.gl;if(a.k===a.v||a.k.endsWith&&a.k.endsWith("."+a.v)){e.z(e.init.op,327680);}}var s=function(){var a="[["+(($rt_globals.Math.random()).toString(36)).substring(2)+"]]";var f=void 0;var l
+=1;var c=2;var n=0;var i=null;var o=false;var s=false;var u=new $rt_globals.Array(1e3);var h=function(){};var e=function(e){if(typeof $rt_globals.MessageChannel==="undefined"){o=true;$rt_globals.setTimeout(e,0);return;}s=true;try {i=new $rt_globals.MessageChannel();var t=false;var r=function(){t=true;};i.port1.addEventListener("message",r);i.port1.start();i.port2.start();i.port2.postMessage("");if(t){i=null;o=true;s=false;$rt_globals.setTimeout(e,0);return;}$rt_globals.setTimeout(function(){i.port1.removeEventListener("message",
+r);if(!t){i=null;o=true;}else {i.port1.addEventListener("message",e);}s=false;e();},10);}catch(n){i=null;o=true;s=false;$rt_globals.setTimeout(e,0);return;}};var r=function(){if(o||s){$rt_globals.setTimeout(t,0);}else {if(i===null){e(t);return;}i.port2.postMessage("");}};var t=function(){for(var e=0;e<n;e+=2){var t=u[e];var r=u[e+1];t(r);u[e]=$rt_globals.undefined;u[e+1]=$rt_globals.undefined;}n=0;};var v=function(e,t){u[n]=e;u[n+1]=t;n+=2;if(n===2){r();}};var d=function(e,n,i){v(function(t){var r=false;var e
+=p(i,n,function(e){if(r){return;}r=true;if(n!==e){_(t,e);}else {j(t,e);}},function(e){if(r){return;}r=true;g(t,e);},"Settle: "+(t._label||" unknown promise"));if(!r&&e){r=true;g(t,e);}},e);};var p=function(e,t,r,n){try {e.call(t,r,n);}catch(i){return i;}};var y=function(t,e){if(e._state===l){j(t,e._result);}else if(e._state===c){g(t,e._result);}else {m(e,$rt_globals.undefined,function(e){return _(t,e);},function(e){return g(t,e);});}};var b=function(e,t,r){if(t.constructor===e.constructor&&r===W&&t.constructor.resolve
+===A){y(e,t);}else {if(r===$rt_globals.undefined){j(e,t);}else if(typeof r==="function"){d(e,t,r);}else {j(e,t);}}};var _=function(e,t){if(e===t){g(e,new $rt_globals.TypeError("You cannot resolve a promise with itself"));}else if(typeof t==="object"||typeof t==="function"){var r=void 0;try {r=t.then;}catch(n){g(e,n);return;}b(e,t,r);}else {j(e,t);}};var g=function(e,t){if(e._state!==f){return;}e._state=c;e._result=t;v(w,e);};var m=function(e,t,r,n){var i=e._subscribers;var o=i.length;e._onerror=null;i[o]=t;i[o
++l]=r;i[o+c]=n;if(o===0&&e._state){v(S,e);}};var S=function(e){var t=e._subscribers;var r=e._state;if(t.length===0){return;}var n=void 0,i=void 0,o=e._result;for(var a=0;a<t.length;a+=3){n=t[a];i=t[a+r];if(n){O(r,n,i,o);}else {i(o);}}e._subscribers.length=0;};var w=function(e){if(e._onerror){e._onerror(e._result);}S(e);};var j=function(e,t){if(e._state!==f){return;}e._result=t;e._state=l;if(e._subscribers.length!==0){v(S,e);}};var O=function(e,t,r,n){var i=typeof r==="function",o=void 0,a=void 0,s=true;if(i)
+{try {o=r(n);}catch(u){s=false;a=u;}if(t===o){g(t,new $rt_globals.TypeError("A promises callback cannot return that same promise."));return;}}else {o=n;}if(t._state!==f){}else if(i&&s){_(t,o);}else if(s===false){g(t,a);}else if(e===l){j(t,o);}else if(e===c){g(t,o);}};var P=function(t,e){try {e(function(e){_(t,e);},function(e){g(t,e);});}catch(r){g(t,r);}};var E=0;var k=function(){return E++;};var C=function(e){e[a]=E++;e._state=$rt_globals.undefined;e._result=$rt_globals.undefined;e._subscribers=[];};var M;M
+=x("Promise",function(e){this[a]=k();this._result=this._state=$rt_globals.undefined;this._subscribers=[];if(h!==e){typeof e!=="function"&&$rt_globals._needsResolver();this instanceof M?P(this,e):$rt_globals._needsNew();}});var W=x("then",function(e,t){var r=this;var n=new this.constructor(h);if(n[a]===$rt_globals.undefined){C(n);}var i=r._state;if(i){var o=arguments[i -1];v(function(){return O(i,n,o,r._result);});}else {m(r,n,e,t);}return n;});M.prototype.then=W;M.prototype["catch"]=x("catch",function(e){return this.then(null,
+e);});M.prototype["finally"]=x("finally",function(t){var e=this;var r=e.constructor;if(typeof t==="function"){return e.then(function(e){return (r.resolve(t())).then(function(){return e;});},function(e){return (r.resolve(t())).then(function(){throw e;});});}return e.then(t,t);});M.all=x("all",function(e){throw new $rt_globals.Error("Promise.all is not included in the ES6 compatibility shim!");});M.race=x("race",function(i){var o=this;if(!$rt_globals.Array.isArray(i)){return new o(function(e,t){return t(new $rt_globals.TypeError("You must pass an array to race."));});}
+else {return new o(function(e,t){var r=i.length;for(var n=0;n<r;n++){(o.resolve(i[n])).then(e,t);}});}});var A=x("resolve",function(e){var t=this;if(e&&typeof e==="object"&&e.constructor===t){return e;}var r=new t(h);_(r,e);return r;});M.resolve=A;M.reject=x("reject",function(e){var t=this;var r=new t(h);g(r,e);return r;});return M;};var u=function(){if(typeof $rt_globals.Promise==="undefined"){$rt_globals.Object.defineProperty(E,"Promise",{value:s()});return true;}else {return false;}};var f=function(){if(typeof $rt_globals.String.fromCodePoint
+==="undefined"){$rt_globals.Object.defineProperty($rt_globals.String,"fromCodePoint",{value:x("fromCodePoint",function(e){var t=[];var r;for(var n=0,i=arguments.length;n<i;n++){r=$rt_globals.Number(arguments[n]);if(r!==(r|0)||r<0||r>1114111){throw new $rt_globals.RangeError("Invalid code point "+r);}if(r<65536){t.push($rt_globals.String.fromCharCode(r));}else {r -=65536;t.push($rt_globals.String.fromCharCode((r>>10)+55296));t.push($rt_globals.String.fromCharCode(r%1024+56320));}}return t.join("");})});return true;}
+else {return false;}};var l=function(){if(typeof $rt_globals.String.prototype.codePointAt==="undefined"){$rt_globals.Object.defineProperty($rt_globals.String.prototype,"codePointAt",{value:x("codePointAt",function(e){e=e|0;var t=this.length;if(e>=0&&e<t){var r=this.charCodeAt(e);var n=e+1===t;if(r<55296||r>56319||n){return r;}var i=this.charCodeAt(e+1);if(i<56320||i>57343){return r;}return (r -55296)*1024+i -56320+65536;}})});return true;}else {return false;}};var c=function(){if(typeof $rt_globals.String.prototype.startsWith
+==="undefined"){$rt_globals.Object.defineProperty($rt_globals.String.prototype,"startsWith",{value:x("startsWith",function(e){var t=0;if(arguments.length>1){t=arguments[1];}var r=$rt_globals.Math.max(t,0)|0;return this.slice(r,r+e.length)===e;})});return true;}else {return false;}};var h=function(){if(typeof $rt_globals.String.prototype.endsWith==="undefined"){$rt_globals.Object.defineProperty($rt_globals.String.prototype,"endsWith",{value:x("endsWith",function(e){var t=this.length;var r;if(arguments.length
+>1){r=arguments[1];}var n=typeof r==="undefined"?t:r|0;var i=$rt_globals.Math.min($rt_globals.Math.max(n,0)|0,t);return this.slice(i -e.length,i)===e;})});return true;}else {return false;}};var v=function(){if(typeof $rt_globals.String.prototype.includes==="undefined"){$rt_globals.Object.defineProperty($rt_globals.String.prototype,"includes",{value:x("includes",function(e){var t;if(arguments.length>1){t=arguments[1];}return this.indexOf(e,t)!== -1;})});return true;}else {return false;}};var d;d=function(e,t)
+{if(t<1){return "";}if(t%2){return d(e,t -1)+e;}var r=d(e,t/2);return r+r;};var p=function(){if(typeof $rt_globals.String.prototype.repeat==="undefined"){$rt_globals.Object.defineProperty($rt_globals.String.prototype,"repeat",{value:x("repeat",function(e){if(e>=$rt_globals.Infinity||(e|=0)<0){throw new $rt_globals.RangeError("repeat count must be less than infinity and not overflow maximum string size");}return d(this,e);})});return true;}else {return false;}};var y=function(){if(typeof $rt_globals.Object.is
+==="undefined"){$rt_globals.Object.defineProperty($rt_globals.Object,"is",{value:x("is",function(e,t){return e===t||e!==e&&t!==t;})});return true;}else {return false;}};var b=function(){if(typeof $rt_globals.Object.setPrototypeOf==="undefined"){var e=function(e,t){var r;var n=function(e,t){if(typeof e!=="object"||e===null){throw new $rt_globals.TypeError("can not set prototype on a non-object");}if(typeof t!=="object"&&t!==null){throw new $rt_globals.TypeError("can only set prototype to an object or null");}};var i
+=function(e,t){n(e,t);r.call(e,t);return e;};try {r=(e.getOwnPropertyDescriptor(e.prototype,t)).set;r.call({},null);}catch(o){if(e.prototype!=={}[t]||{__proto__:null}.__proto__===void 0){$rt_globals.console.error("ES6Shims: Can not shim Object.setPrototypeOf on this browser! Ignoring for now");return false;}r=function(e){this[t]=e;};}return i;}($rt_globals.Object,"__proto__");if(e){$rt_globals.Object.defineProperty($rt_globals.Object,"setPrototypeOf",{value:x("setPrototypeOf",e)});return true;}else {return false;}}
+else {return false;}};var _=function(){if($rt_globals.Math.max.name!=="max"){$rt_globals.Object.defineProperty($rt_globals.Function.prototype,"name",{configurable:true,enumerable:false,get:function(){if(this===$rt_globals.Function.prototype){return "";}var e=$rt_globals.Function.prototype.toString.call(this);var t=e.match(/\s*function\s+([^(\s]*)\s*/);var r=t&&t[1];$rt_globals.Object.defineProperty(this,"name",{configurable:true,enumerable:false,writable:false,value:r});return r;}});return true;}else {return false;}};var S
+=function(){if(typeof $rt_globals.Math.sign==="undefined"){$rt_globals.Object.defineProperty($rt_globals.Math,"sign",{value:x("sign",function(e){var t=$rt_globals.Number(e);if(t===0){return t;}if($rt_globals.isNaN(t)){return t;}return t<0? -1:1;})});return true;}else {return false;}};var w=function(){if(typeof $rt_globals.Symbol==="undefined"){$rt_globals.Object.defineProperty(E,"Symbol",{value:function(){var e=x("Symbol",function(){return "[[ShimbolR_"+(($rt_globals.Math.random()).toString(36)).substring(2)
++"]]";});e["for"]=x("for",function(e){if(!(typeof e==="string"))return $rt_globals.undefined;return "[[ShimbolN_"+e+"]]";});e.keyFor=x("keyFor",function(e){return typeof e==="string"&&e.startsWith("[[ShimbolN_")&&e.endsWith("]]")?e.substring(11,e.length -2):$rt_globals.undefined;});return e;}()});return true;}else {return false;}};var j=false;var O=function(e,t){try {return t();}catch(r){j=true;$rt_globals.console.error('ES6Shims: Failed to detect and enable shim "'+e+'" for this browser! (Continuing anyway)');$rt_globals.console.error(r);return false;}};if
+(O("Map",r))t.push(0);if(O("WeakMap",n))t.push(1);if(O("Set",i))t.push(2);if(O("WeakSet",o))t.push(3);if(O("Promise",u))t.push(4);if(O("String_fromCodePoint",f))t.push(5);if(O("String_proto_codePointAt",l))t.push(6);if(O("String_proto_startsWith",c))t.push(7);if(O("String_proto_endsWith",h))t.push(8);if(O("String_proto_includes",v))t.push(9);if(O("String_proto_repeat",p))t.push(10);if(O("Object_is",y))t.push(12);if(O("Object_setPrototypeOf",b))t.push(13);if(O("Function_proto_name",_))t.push(14);if(O("Math_sign",
+S))t.push(15);if(O("Symbol",w))t.push(16);var P=t.length;E.__eaglercraftXES6ShimStatus={getShimInitStatus:function(){return (P>0?1:0)|(j?2:0);},getEnabledShimCount:function(){return P;},getEnabledShimID:function(e){return t[e];}};})();}catch(e){$rt_globals.console.error("ES6Shims: Failed to detect and enable shims for this browser! (Continuing anyway)");$rt_globals.console.error(e);E.__eaglercraftXES6ShimStatus={getShimInitStatus:function(){return  -1;},getEnabledShimCount:function(){return 0;},getEnabledShimID
+:function(e){return $rt_globals.undefined;}};}})($rt_globals);
\ No newline at end of file
diff --git a/sources/setup/workspace_template/javascript/OfflineDownloadTemplate.txt b/sources/setup/workspace_template/javascript/OfflineDownloadTemplate.txt
index 7523dc83..f9987576 100644
--- a/sources/setup/workspace_template/javascript/OfflineDownloadTemplate.txt
+++ b/sources/setup/workspace_template/javascript/OfflineDownloadTemplate.txt
@@ -24,10 +24,10 @@ Compile it yourself here: https://gitlab.com/lax1dude/eaglercraftx-1.8/
 
 
 
-<html>
+<html style="width:100%;height:100%;background-color:black;">
 <head>
 <meta charset="UTF-8" />
-<meta name="viewport" content="width=device-width, initial-scale=1.0" />
+<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0" />
 <meta name="description" content="EaglercraftX 1.8 Offline" />
 <meta name="keywords" content="eaglercraft, eaglercraftx, minecraft, 1.8, 1.8.8" />
 <title>EaglercraftX 1.8</title>
@@ -37,7 +37,7 @@ Compile it yourself here: https://gitlab.com/lax1dude/eaglercraftx-1.8/
 <meta property="og:description" content="this file is not a website, whoever uploaded it to this URL is a dumbass" />
 <script type="text/javascript">
 "use strict";
-const relayId = Math.floor(Math.random() * 3);
+var relayId = Math.floor(Math.random() * 3);
 
 // %%%%%%%%% launch options %%%%%%%%%%%%
 
@@ -68,31 +68,40 @@ ${classes_js}
 	var launchCounter = 1;
 	var launchCountdownNumberElement = null;
 	var launchCountdownProgressElement = null;
+	var launchSkipCountdown = false;
 
-	function launchTick() {
+	var launchTick = function() {
 		launchCountdownNumberElement.innerText = "" + Math.floor(6.0 - launchCounter * 0.06);
 		launchCountdownProgressElement.style.width = "" + launchCounter + "%";
-		if(++launchCounter > 100) {
+		if(++launchCounter > 100 || launchSkipCountdown) {
 			clearInterval(launchInterval);
-			setTimeout(() => { document.getElementById("launch_countdown_screen").remove(); main(); }, 50);
+			setTimeout(function() { document.body.removeChild(document.getElementById("launch_countdown_screen")); document.body.style.backgroundColor = "black"; main(); }, 50);
 		}
-	}
+	};
 
-	window.addEventListener("load", () => {
+	window.addEventListener("load", function() {
 		launchCountdownNumberElement = document.getElementById("launchCountdownNumber");
 		launchCountdownProgressElement = document.getElementById("launchCountdownProgress");
 		launchInterval = setInterval(launchTick, 50);
+		document.getElementById("skipCountdown").addEventListener("click", function() {
+			launchSkipCountdown = true;
+		});
+		document.getElementById("bootMenu").addEventListener("click", function() {
+			launchSkipCountdown = true;
+			window.eaglercraftXOpts.showBootMenuOnLaunch = true;
+		});
 	});
 })();
 </script>
 <link type="image/png" rel="shortcut icon" href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAIAAAD8GO2jAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAAFiUAABYlAUlSJPAAAAR/SURBVEhLtZXZK3ZRFMYPcqXc+gv413DHxVuGIpIhkciQWaRccCNjSCkligwXSOZ5nmfv9zvn2e8+58V753sudmuvvdZ61l5r7XOc8H+GS/D19aUNkPz5+aktQH5/f//4+LBKZKuRkpUtQjCUYG5gD2T38vLy/PwsDfL9/f3Dw8PT05M0b29vnKLhCKCBT4L4gvBLBIei4//4+Hh1dUVEQutUuLu7E83FxQUGnKLBWKfQaA3S+AREVxaEOD8/Pzk50XpzcyMDcH19zdZG3N3d3dzc3Nvb01aX5pQUpQGGQJxcQpfNysoKhUIdHR1o1tbWbInYAgxIPDMzMy8vLzc3FxqOdMoRqwJK8G8ALUYIhHMiSEhIwI6CyIb0qQzC4eGhsXCc1tZWnZIEKzdQJQSXgKxfX18RCM3Z5eWlcfVAxKOjo+Pj49PTU88lTOk2NjbMsePc3t6SAfcgFdszOyMuAdeBg0CQi2lhYUHOeOLDCisN8FzcPFZXV3t7ezHY3t5GQ+6it+2xMASsKhEEWKsmRLRBBUpPvpJ/TpFKFBwKYAiITmicsbYhdHfJAltqhUCVsCQhwslmeXmZxiBQT9c0Ar9E2O3v72sYSE0N1yQArkKy0kBMXLqlZqIZHR3t6empqqqSDcBdhXEJSJ/bUc3q6uq+vj629GB9fR1WsLW1NTs7u7S0RN2locMjIyOEm5ubQ7+4uJienk4/+vv77Y1hwhLBEKhwWHitdVFfX9/Y2Gg2HuLi4owUAysrK8yCG97rh0+ApP5Q2ZycHFlPTExUVFRIBvn5+WhKSkp2dnaMKhptbW2426GgQ/rwuAQCZ1hwFayLiork9hMFBQV1dXVmE0BLS4vqw3QFB8kn4IAxoGPkYpxi4FeDmpqas7Mz4pClAgqGwD48rjY2NmacYqC0tJQ1KSlJWyE5OZkpUKkBAxZVIntAoZh04+Q48fHxPNGBgYHExMT29naj9cBodnZ2mo3jlJWVMeW2OGQck4B1amqqoaGhqamJjx2lGxwcpL0mUgR8fJhsWqJtSkoKU2SbHHUDpkhPBujd8xuQG6PJRM/Pz09PT7O1NNnZ2Tw3fgZkXVhYKCUlUhBATP+hCVyKZGky17RV0g04laayslJ6hlVeFHB4eFhKaogGd0LxtmTgE+hbhKDnPjMzgw8E3qGL2tpaBWpubjYqj2BoaEj6rq4uNATRZ0ZwCbiL6gXEzINk5vCBQJ9rMD4+rkA8QNK036uDg4Py8vLu7m680KjIBNR3zBDoWQM1g98snyB+VSoRW8C/UwR81/SvhgNj9JOTkwwVERUdRBEI0BAdLRVERkhLS8vIyEDQlrsTPTU1lVFhKxARvZgUlFLbegCf4BvIsbi4mIg4E5EogIHhiKCMtU0WUFiVy06j5fAJIDdSBDQw+PegDfBRcbOPwH4F9LuFWIIQdQNKwWqzIE0aoFUaBsw+SQuFw0uNtC9A+F4i3QNrbg3IDn+SAsHh+wYiEpeyBEMLv/cAO6KzAijxxB+Y4wisBhssJUhjEbPJf4Nw+B+JXqLW3bw+wQAAAABJRU5ErkJggg==" />
 </head>
-<body style="margin:0px;width:100vw;height:100vh;overflow:hidden;" id="game_frame">
+<body style="margin:0px;width:100%;height:100%;overflow:hidden;background-color:white;" id="game_frame">
 <div style="margin:0px;width:100%;height:100%;font-family:sans-serif;display:flex;align-items:center;user-select:none;" id="launch_countdown_screen">
 <div style="margin:auto;text-align:center;">
 <h1>This file is from <span style="color:#AA0000;">${date}</span></h1>
 <h2>Game will launch in <span id="launchCountdownNumber">5</span>...</h2>
-<div style="border:2px solid black;width:100%;height:15px;padding:1px;margin-bottom:20vh;"><div id="launchCountdownProgress" style="background-color:#555555;width:0%;height:100%;"></div></div>
+<div style="border:2px solid black;width:100%;height:15px;padding:1px;margin-bottom:20vh;"><div id="launchCountdownProgress" style="background-color:#555555;width:0%;height:100%;"></div>
+<p style="margin-top:30px;"><button id="skipCountdown" autofocus>Skip Countdown</button>&emsp;<button id="bootMenu">Enter Boot Menu</button></p></div>
 </div>
 </div>
 </body>
diff --git a/sources/setup/workspace_template/javascript/SignedBundleTemplate.txt b/sources/setup/workspace_template/javascript/SignedBundleTemplate.txt
index ef983d2f..d6f2b68e 100644
--- a/sources/setup/workspace_template/javascript/SignedBundleTemplate.txt
+++ b/sources/setup/workspace_template/javascript/SignedBundleTemplate.txt
@@ -8,7 +8,7 @@ if(typeof window !== "undefined") {
 	if(window.eaglercraftXOptsHints && window.eaglercraftXOptsHints.hintsVersion === 1) {
 		window.eaglercraftXOpts = window.eaglercraftXOptsHints;
 	}else {
-		const relayzId = Math.floor(Math.random() * 3);
+		var relayzId = Math.floor(Math.random() * 3);
 		window.eaglercraftXOpts = {
 			container: "game_frame",
 			worldsDB: "worlds",
@@ -20,15 +20,11 @@ if(typeof window !== "undefined") {
 			checkRelaysForUpdates: true
 		};
 	}
-	window.addEventListener("load", () => {
+	window.addEventListener("load", function() {
 		main();
 	});
 }
 
 // %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 
-if(typeof window !== "undefined") { window.eaglercraftXOpts.enableSignatureBadge = true; window.eaglercraftXOpts.assetsURI = ${assets_epk}; }
-
-if(typeof window !== "undefined") setTimeout(() => {
-	main();
-}, 0);
\ No newline at end of file
+if(typeof window !== "undefined") { window.eaglercraftXOpts.enableSignatureBadge = true; window.eaglercraftXOpts.assetsURI = ${assets_epk}; main(); }
diff --git a/sources/setup/workspace_template/javascript/SignedClientTemplate.txt b/sources/setup/workspace_template/javascript/SignedClientTemplate.txt
index 32731d94..86563655 100644
--- a/sources/setup/workspace_template/javascript/SignedClientTemplate.txt
+++ b/sources/setup/workspace_template/javascript/SignedClientTemplate.txt
@@ -1,8 +1,8 @@
 <!DOCTYPE html>
-<html>
+<html style="width:100%;height:100%;background-color:black;">
 <head>
 <meta charset="UTF-8" />
-<meta name="viewport" content="width=device-width, initial-scale=1.0" />
+<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0" />
 <meta name="description" content="EaglercraftX 1.8 Offline" />
 <meta name="keywords" content="eaglercraft, eaglercraftx, minecraft, 1.8, 1.8.8" />
 <title>EaglercraftX 1.8</title>
@@ -12,7 +12,7 @@
 <meta property="og:description" content="Play minecraft 1.8 in your browser" />
 <script type="text/javascript">
 "use strict";
-const relayId = Math.floor(Math.random() * 3);
+var relayId = Math.floor(Math.random() * 3);
 
 // %%%%%%%%% launch options %%%%%%%%%%%%
 
@@ -36,7 +36,7 @@ window.eaglercraftXOptsHints = {
 <script type="text/javascript">
 "use strict";
 (function(){
-	function eaglerBundleUnwrap(tagIn) { const e = document.getElementById(tagIn); const ret = e.innerText; e.remove(); return ret;  }
+	function eaglerBundleUnwrap(tagIn) { var e = document.getElementById(tagIn); var ret = e.innerText; document.head.removeChild(e); return ret;  }
 	window.eaglercraftXClientSignature = eaglerBundleUnwrap("eaglercraftXClientSignature");
 	window.eaglercraftXClientBundle = eaglerBundleUnwrap("eaglercraftXClientBundle");
 })();
@@ -44,42 +44,161 @@ window.eaglercraftXOptsHints = {
 <script type="text/javascript">
 "use strict";
 (function(){
-	function fetchB64PayloadSafe() {
-		const dataURL = window.eaglercraftXClientBundle;
-		if(!dataURL.startsWith("data:application/octet-stream;base64,")) {
-			return fetch(dataURL, { cache: "force-cache" }).then((response) => response.blob());
-		}
-		return new Promise((resolve) => {
-			fetch(dataURL)
-				.then((response) => response.blob())
-				.then((blob) => { resolve(blob); })
-				.catch((err) => {
-					console.error("Caught an error decoding base64 via fetch, doing it the slow way instead...");
-					// MIT License - https://github.com/beatgammit/base64-js
-					const base64js = (function(){return function(){function b(d,e,g){function a(j,i){if(!e[j]){if(!d[j]){var f="function"==typeof require&&require;if(!i&&f)return f(j,!0);if(h)return h(j,!0);var c=new Error("Cannot find module '"+j+"'");throw c.code="MODULE_NOT_FOUND",c}var k=e[j]={exports:{}};d[j][0].call(k.exports,function(b){var c=d[j][1][b];return a(c||b)},k,k.exports,b,d,e,g)}return e[j].exports}for(var h="function"==typeof require&&require,c=0;c<g.length;c++)a(g[c]);return a}return b}()({"/":[function(a,b,c){"use strict";function d(a){var b=a.length;if(0<b%4)throw new Error("Invalid string. Length must be a multiple of 4");var c=a.indexOf("=");-1===c&&(c=b);var d=c===b?0:4-c%4;return[c,d]}function e(a,b,c){return 3*(b+c)/4-c}function f(a){var b,c,f=d(a),g=f[0],j=f[1],k=new Uint8Array(e(a,g,j)),l=0,m=0<j?g-4:g;for(c=0;c<m;c+=4)b=h[a.charCodeAt(c)]<<18|h[a.charCodeAt(c+1)]<<12|h[a.charCodeAt(c+2)]<<6|h[a.charCodeAt(c+3)],k[l++]=255&b>>16,k[l++]=255&b>>8,k[l++]=255&b;return 2===j&&(b=h[a.charCodeAt(c)]<<2|h[a.charCodeAt(c+1)]>>4,k[l++]=255&b),1===j&&(b=h[a.charCodeAt(c)]<<10|h[a.charCodeAt(c+1)]<<4|h[a.charCodeAt(c+2)]>>2,k[l++]=255&b>>8,k[l++]=255&b),k}c.byteLength=function b(a){var c=d(a),e=c[0],f=c[1];return 3*(e+f)/4-f},c.toByteArray=f;for(var g=[],h=[],j="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",k=0,l=j.length;k<l;++k)g[k]=j[k],h[j.charCodeAt(k)]=k;h[45]=62,h[95]=63},{}]},{},[])("/")})();
-					const bytesDec = base64js.toByteArray(dataURL.substring(37)).buffer;
-					const bytesBlob = new Blob([bytesDec], { type: "application/octet-stream" });
-					window.eaglercraftXClientBundle = URL.createObjectURL(bytesBlob);
-					console.error("Created " + bytesDec.byteLength + " byte object URL: " + window.eaglercraftXClientBundle);
-					resolve(bytesBlob);
+	(function(a){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=a();else if("function"==typeof define&&define.amd)define([],a);else{var b;b="undefined"==typeof window?"undefined"==typeof global?"undefined"==typeof self?this:self:global:window,b.base64js=a()}})(function(){return function(){function b(d,e,g){function a(j,i){if(!e[j]){if(!d[j]){var f="function"==typeof require&&require;if(!i&&f)return f(j,!0);if(h)return h(j,!0);var c=new Error("Cannot find module '"+j+"'");throw c.code="MODULE_NOT_FOUND",c}var k=e[j]={exports:{}};d[j][0].call(k.exports,function(b){var c=d[j][1][b];return a(c||b)},k,k.exports,b,d,e,g)}return e[j].exports}for(var h="function"==typeof require&&require,c=0;c<g.length;c++)a(g[c]);return a}return b}()({"/":[function(a,b,c){'use strict';function d(a){var b=a.length;if(0<b%4)throw new Error("Invalid string. Length must be a multiple of 4");var c=a.indexOf("=");-1===c&&(c=b);var d=c===b?0:4-c%4;return[c,d]}function e(a,b,c){return 3*(b+c)/4-c}function f(a){var b,c,f=d(a),g=f[0],h=f[1],j=new m(e(a,g,h)),k=0,n=0<h?g-4:g;for(c=0;c<n;c+=4)b=l[a.charCodeAt(c)]<<18|l[a.charCodeAt(c+1)]<<12|l[a.charCodeAt(c+2)]<<6|l[a.charCodeAt(c+3)],j[k++]=255&b>>16,j[k++]=255&b>>8,j[k++]=255&b;return 2===h&&(b=l[a.charCodeAt(c)]<<2|l[a.charCodeAt(c+1)]>>4,j[k++]=255&b),1===h&&(b=l[a.charCodeAt(c)]<<10|l[a.charCodeAt(c+1)]<<4|l[a.charCodeAt(c+2)]>>2,j[k++]=255&b>>8,j[k++]=255&b),j}function g(a){return k[63&a>>18]+k[63&a>>12]+k[63&a>>6]+k[63&a]}function h(a,b,c){for(var d,e=[],f=b;f<c;f+=3)d=(16711680&a[f]<<16)+(65280&a[f+1]<<8)+(255&a[f+2]),e.push(g(d));return e.join("")}function j(a){for(var b,c=a.length,d=c%3,e=[],f=16383,g=0,j=c-d;g<j;g+=f)e.push(h(a,g,g+f>j?j:g+f));return 1===d?(b=a[c-1],e.push(k[b>>2]+k[63&b<<4]+"==")):2===d&&(b=(a[c-2]<<8)+a[c-1],e.push(k[b>>10]+k[63&b>>4]+k[63&b<<2]+"=")),e.join("")}c.byteLength=function(a){var b=d(a),c=b[0],e=b[1];return 3*(c+e)/4-e},c.toByteArray=f,c.fromByteArray=j;for(var k=[],l=[],m="undefined"==typeof Uint8Array?Array:Uint8Array,n="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",o=0,p=n.length;o<p;++o)k[o]=n[o],l[n.charCodeAt(o)]=o;l[45]=62,l[95]=63},{}]},{},[])("/")});
+	var sameOriginSupport = -1;
+	var checkSameOriginSupport = function(callback0) {
+		if(sameOriginSupport == -1) {
+			try {
+				(function(callback) {
+					if((typeof URL === "undefined") || (typeof URL.createObjectURL !== "function")) {
+						sameOriginSupport = 1;
+						callback(false);
+					}else {
+						var theObjURL = URL.createObjectURL(new Blob([new Uint8Array([69, 69, 69, 69])]));
+						if(!theObjURL) {
+							sameOriginSupport = 1;
+							callback(false);
+						}
+						doXHR(theObjURL, function(dataRet) {
+							if(dataRet) {
+								var typedArr = new Uint8Array(dataRet);
+								if(typedArr.length === 4 && typedArr[0] === 69 && typedArr[1] === 69 && typedArr[2] === 69 && typedArr[3] === 69) {
+									sameOriginSupport = 0;
+									callback(true);
+								}else {
+									sameOriginSupport = 1;
+									callback(false);
+								}
+							}else {
+								sameOriginSupport = 1;
+								callback(false);
+							}
+						});
+					}
+				})(function(valRet) {
+					if(!valRet) {
+						console.error("Same origin XHR support detected as false, using data: url...");
+					}
+					callback0(valRet);
 				});
-		});
-	}
-	var ds = new DecompressionStream("gzip");
-	var result = [];
-	function fetchStream(reader) {
-		reader.read().then(function processData({ done, value }) {
-			if (done) {
-				window.clientScriptSrcURL = URL.createObjectURL(new Blob(result, { type: "text/javascript;charset=utf-8" }));
-				result = [];
-				ds = null;
-				return;
+			}catch(ex) {
+				console.error("Same origin XHR support detection failed, using data: url...");
+				callback0(false);
+			}
+		}else {
+			callback0(!sameOriginSupport);
+		}
+	};
+	var blobToArrayBuffer = function(blobIn, callback) {
+		if(typeof blobIn.arrayBuffer === "undefined") {
+			blobIn.arrayBuffer().then(callback);
+		}else {
+			(function(phileReader) {
+				phileReader.addEventListener("load", function(evt) {
+					callback(phileReader.result);
+				});
+				phileReader.readAsArrayBuffer(blobIn);
+			})(new FileReader());
+		}
+	};
+	var completeXHR = function(callback, arg) {
+		if(!callback.comp) {
+			callback.comp = true;
+			callback.cb(arg);
+		}
+	};
+	var doXHR = function(urlIn, callback) {
+		(function(theXHRObj, callbackStruct){
+			theXHRObj.responseType = "arraybuffer";
+			theXHRObj.addEventListener("load", function(evt) { var stat = theXHRObj.status; if(stat === 0 || (stat >= 200 && stat < 400)) { completeXHR(callbackStruct, theXHRObj.response); } else { completeXHR(callbackStruct, null); } });
+			theXHRObj.addEventListener("error", function(evt) {  completeXHR(callbackStruct, null); });
+			theXHRObj.open("GET", urlIn, true);
+			theXHRObj.send();
+		})(new XMLHttpRequest(), { cb: callback, comp: false });
+	};
+	var decodeBase64URL = function(urlIn, callbackOut) {
+		doXHR(urlIn, function(data) {
+			if(!data) {
+				try {
+					console.error("Caught an error decoding base64 via fetch, doing it the slow way instead...");
+					callbackOut(base64js.toByteArray(urlIn.substring(37)).buffer);
+				}catch(ex) {
+					console.error("Failed to decode base64!");
+					console.error(ex);
+					callbackOut(null);
+				}
+			}else {
+				callbackOut(data);
+			}
+		});
+	};
+	if(typeof window.DecompressionStream === "undefined") {
+		checkSameOriginSupport(function(soSupported) {
+			var theWorkerObj;
+			var workerSrc = "InVzZSBzdHJpY3QiOwovKiEgcGFrbyAyLjEuMCBodHRwczovL2dpdGh1Yi5jb20vbm9kZWNhL3Bha28gQGxpY2Vuc2UgKE1JVCBBTkQgWmxpYikgKi8KIWZ1bmN0aW9uKGUsdCl7Im9iamVjdCI9PXR5cGVvZiBleHBvcnRzJiYidW5kZWZpbmVkIiE9dHlwZW9mIG1vZHVsZT90KGV4cG9ydHMpOiJmdW5jdGlvbiI9PXR5cGVvZiBkZWZpbmUmJmRlZmluZS5hbWQ/ZGVmaW5lKFsiZXhwb3J0cyJdLHQpOnQoKGU9InVuZGVmaW5lZCIhPXR5cGVvZiBnbG9iYWxUaGlzP2dsb2JhbFRoaXM6ZXx8c2VsZikucGFrbz17fSl9KHRoaXMsKGZ1bmN0aW9uKGUpeyJ1c2Ugc3RyaWN0Ijt2YXIgdD1mdW5jdGlvbihlLHQsaSxuKXtmb3IodmFyIGE9NjU1MzUmZXwwLHI9ZT4+PjE2JjY1NTM1fDAsbz0wOzAhPT1pOyl7aS09bz1pPjJlMz8yZTM6aTtkb3tyPXIrKGE9YSt0W24rK118MCl8MH13aGlsZSgtLW8pO2ElPTY1NTIxLHIlPTY1NTIxfXJldHVybiBhfHI8PDE2fDB9LGk9bmV3IFVpbnQzMkFycmF5KGZ1bmN0aW9uKCl7Zm9yKHZhciBlLHQ9W10saT0wO2k8MjU2O2krKyl7ZT1pO2Zvcih2YXIgbj0wO248ODtuKyspZT0xJmU/Mzk4ODI5MjM4NF5lPj4+MTplPj4+MTt0W2ldPWV9cmV0dXJuIHR9KCkpLG49ZnVuY3Rpb24oZSx0LG4sYSl7dmFyIHI9aSxvPWErbjtlXj0tMTtmb3IodmFyIHM9YTtzPG87cysrKWU9ZT4+PjheclsyNTUmKGVedFtzXSldO3JldHVybi0xXmV9LGE9MTYyMDkscj1mdW5jdGlvbihlLHQpe3ZhciBpLG4scixvLHMsbCxmLGQsaCxjLHUsdyxiLG0sayxfLHYsZyxwLHkseCxFLFIsQSxaPWUuc3RhdGU7aT1lLm5leHRfaW4sUj1lLmlucHV0LG49aSsoZS5hdmFpbF9pbi01KSxyPWUubmV4dF9vdXQsQT1lLm91dHB1dCxvPXItKHQtZS5hdmFpbF9vdXQpLHM9cisoZS5hdmFpbF9vdXQtMjU3KSxsPVouZG1heCxmPVoud3NpemUsZD1aLndoYXZlLGg9Wi53bmV4dCxjPVoud2luZG93LHU9Wi5ob2xkLHc9Wi5iaXRzLGI9Wi5sZW5jb2RlLG09Wi5kaXN0Y29kZSxrPSgxPDxaLmxlbmJpdHMpLTEsXz0oMTw8Wi5kaXN0Yml0cyktMTtlOmRve3c8MTUmJih1Kz1SW2krK108PHcsdys9OCx1Kz1SW2krK108PHcsdys9OCksdj1iW3Uma107dDpmb3IoOzspe2lmKHU+Pj49Zz12Pj4+MjQsdy09ZywwPT09KGc9dj4+PjE2JjI1NSkpQVtyKytdPTY1NTM1JnY7ZWxzZXtpZighKDE2JmcpKXtpZigwPT0oNjQmZykpe3Y9YlsoNjU1MzUmdikrKHUmKDE8PGcpLTEpXTtjb250aW51ZSB0fWlmKDMyJmcpe1oubW9kZT0xNjE5MTticmVhayBlfWUubXNnPSJpbnZhbGlkIGxpdGVyYWwvbGVuZ3RoIGNvZGUiLFoubW9kZT1hO2JyZWFrIGV9cD02NTUzNSZ2LChnJj0xNSkmJih3PGcmJih1Kz1SW2krK108PHcsdys9OCkscCs9dSYoMTw8ZyktMSx1Pj4+PWcsdy09ZyksdzwxNSYmKHUrPVJbaSsrXTw8dyx3Kz04LHUrPVJbaSsrXTw8dyx3Kz04KSx2PW1bdSZfXTtpOmZvcig7Oyl7aWYodT4+Pj1nPXY+Pj4yNCx3LT1nLCEoMTYmKGc9dj4+PjE2JjI1NSkpKXtpZigwPT0oNjQmZykpe3Y9bVsoNjU1MzUmdikrKHUmKDE8PGcpLTEpXTtjb250aW51ZSBpfWUubXNnPSJpbnZhbGlkIGRpc3RhbmNlIGNvZGUiLFoubW9kZT1hO2JyZWFrIGV9aWYoeT02NTUzNSZ2LHc8KGcmPTE1KSYmKHUrPVJbaSsrXTw8dywodys9OCk8ZyYmKHUrPVJbaSsrXTw8dyx3Kz04KSksKHkrPXUmKDE8PGcpLTEpPmwpe2UubXNnPSJpbnZhbGlkIGRpc3RhbmNlIHRvbyBmYXIgYmFjayIsWi5tb2RlPWE7YnJlYWsgZX1pZih1Pj4+PWcsdy09Zyx5PihnPXItbykpe2lmKChnPXktZyk+ZCYmWi5zYW5lKXtlLm1zZz0iaW52YWxpZCBkaXN0YW5jZSB0b28gZmFyIGJhY2siLFoubW9kZT1hO2JyZWFrIGV9aWYoeD0wLEU9YywwPT09aCl7aWYoeCs9Zi1nLGc8cCl7cC09Zztkb3tBW3IrK109Y1t4KytdfXdoaWxlKC0tZyk7eD1yLXksRT1BfX1lbHNlIGlmKGg8Zyl7aWYoeCs9ZitoLWcsKGctPWgpPHApe3AtPWc7ZG97QVtyKytdPWNbeCsrXX13aGlsZSgtLWcpO2lmKHg9MCxoPHApe3AtPWc9aDtkb3tBW3IrK109Y1t4KytdfXdoaWxlKC0tZyk7eD1yLXksRT1BfX19ZWxzZSBpZih4Kz1oLWcsZzxwKXtwLT1nO2Rve0FbcisrXT1jW3grK119d2hpbGUoLS1nKTt4PXIteSxFPUF9Zm9yKDtwPjI7KUFbcisrXT1FW3grK10sQVtyKytdPUVbeCsrXSxBW3IrK109RVt4KytdLHAtPTM7cCYmKEFbcisrXT1FW3grK10scD4xJiYoQVtyKytdPUVbeCsrXSkpfWVsc2V7eD1yLXk7ZG97QVtyKytdPUFbeCsrXSxBW3IrK109QVt4KytdLEFbcisrXT1BW3grK10scC09M313aGlsZShwPjIpO3AmJihBW3IrK109QVt4KytdLHA+MSYmKEFbcisrXT1BW3grK10pKX1icmVha319YnJlYWt9fXdoaWxlKGk8biYmcjxzKTtpLT1wPXc+PjMsdSY9KDE8PCh3LT1wPDwzKSktMSxlLm5leHRfaW49aSxlLm5leHRfb3V0PXIsZS5hdmFpbF9pbj1pPG4/bi1pKzU6NS0oaS1uKSxlLmF2YWlsX291dD1yPHM/cy1yKzI1NzoyNTctKHItcyksWi5ob2xkPXUsWi5iaXRzPXd9LG89MTUscz1uZXcgVWludDE2QXJyYXkoWzMsNCw1LDYsNyw4LDksMTAsMTEsMTMsMTUsMTcsMTksMjMsMjcsMzEsMzUsNDMsNTEsNTksNjcsODMsOTksMTE1LDEzMSwxNjMsMTk1LDIyNywyNTgsMCwwXSksbD1uZXcgVWludDhBcnJheShbMTYsMTYsMTYsMTYsMTYsMTYsMTYsMTYsMTcsMTcsMTcsMTcsMTgsMTgsMTgsMTgsMTksMTksMTksMTksMjAsMjAsMjAsMjAsMjEsMjEsMjEsMjEsMTYsNzIsNzhdKSxmPW5ldyBVaW50MTZBcnJheShbMSwyLDMsNCw1LDcsOSwxMywxNywyNSwzMyw0OSw2NSw5NywxMjksMTkzLDI1NywzODUsNTEzLDc2OSwxMDI1LDE1MzcsMjA0OSwzMDczLDQwOTcsNjE0NSw4MTkzLDEyMjg5LDE2Mzg1LDI0NTc3LDAsMF0pLGQ9bmV3IFVpbnQ4QXJyYXkoWzE2LDE2LDE2LDE2LDE3LDE3LDE4LDE4LDE5LDE5LDIwLDIwLDIxLDIxLDIyLDIyLDIzLDIzLDI0LDI0LDI1LDI1LDI2LDI2LDI3LDI3LDI4LDI4LDI5LDI5LDY0LDY0XSksaD1mdW5jdGlvbihlLHQsaSxuLGEscixoLGMpe3ZhciB1LHcsYixtLGssXyx2LGcscCx5PWMuYml0cyx4PTAsRT0wLFI9MCxBPTAsWj0wLFM9MCxUPTAsTz0wLFU9MCxEPTAsST1udWxsLEI9bmV3IFVpbnQxNkFycmF5KDE2KSxOPW5ldyBVaW50MTZBcnJheSgxNiksQz1udWxsO2Zvcih4PTA7eDw9bzt4KyspQlt4XT0wO2ZvcihFPTA7RTxuO0UrKylCW3RbaStFXV0rKztmb3IoWj15LEE9bztBPj0xJiYwPT09QltBXTtBLS0pO2lmKFo+QSYmKFo9QSksMD09PUEpcmV0dXJuIGFbcisrXT0yMDk3MTUyMCxhW3IrK109MjA5NzE1MjAsYy5iaXRzPTEsMDtmb3IoUj0xO1I8QSYmMD09PUJbUl07UisrKTtmb3IoWjxSJiYoWj1SKSxPPTEseD0xO3g8PW87eCsrKWlmKE88PD0xLChPLT1CW3hdKTwwKXJldHVybi0xO2lmKE8+MCYmKDA9PT1lfHwxIT09QSkpcmV0dXJuLTE7Zm9yKE5bMV09MCx4PTE7eDxvO3grKylOW3grMV09Tlt4XStCW3hdO2ZvcihFPTA7RTxuO0UrKykwIT09dFtpK0VdJiYoaFtOW3RbaStFXV0rK109RSk7aWYoMD09PWU/KEk9Qz1oLF89MjApOjE9PT1lPyhJPXMsQz1sLF89MjU3KTooST1mLEM9ZCxfPTApLEQ9MCxFPTAseD1SLGs9cixTPVosVD0wLGI9LTEsbT0oVT0xPDxaKS0xLDE9PT1lJiZVPjg1Mnx8Mj09PWUmJlU+NTkyKXJldHVybiAxO2Zvcig7Oyl7dj14LVQsaFtFXSsxPF8/KGc9MCxwPWhbRV0pOmhbRV0+PV8/KGc9Q1toW0VdLV9dLHA9SVtoW0VdLV9dKTooZz05NixwPTApLHU9MTw8eC1ULFI9dz0xPDxTO2Rve2FbaysoRD4+VCkrKHctPXUpXT12PDwyNHxnPDwxNnxwfDB9d2hpbGUoMCE9PXcpO2Zvcih1PTE8PHgtMTtEJnU7KXU+Pj0xO2lmKDAhPT11PyhEJj11LTEsRCs9dSk6RD0wLEUrKywwPT0tLUJbeF0pe2lmKHg9PT1BKWJyZWFrO3g9dFtpK2hbRV1dfWlmKHg+WiYmKEQmbSkhPT1iKXtmb3IoMD09PVQmJihUPVopLGsrPVIsTz0xPDwoUz14LVQpO1MrVDxBJiYhKChPLT1CW1MrVF0pPD0wKTspUysrLE88PD0xO2lmKFUrPTE8PFMsMT09PWUmJlU+ODUyfHwyPT09ZSYmVT41OTIpcmV0dXJuIDE7YVtiPUQmbV09Wjw8MjR8Uzw8MTZ8ay1yfDB9fXJldHVybiAwIT09RCYmKGFbaytEXT14LVQ8PDI0fDY0PDwxNnwwKSxjLmJpdHM9WiwwfSxjPXtaX05PX0ZMVVNIOjAsWl9QQVJUSUFMX0ZMVVNIOjEsWl9TWU5DX0ZMVVNIOjIsWl9GVUxMX0ZMVVNIOjMsWl9GSU5JU0g6NCxaX0JMT0NLOjUsWl9UUkVFUzo2LFpfT0s6MCxaX1NUUkVBTV9FTkQ6MSxaX05FRURfRElDVDoyLFpfRVJSTk86LTEsWl9TVFJFQU1fRVJST1I6LTIsWl9EQVRBX0VSUk9SOi0zLFpfTUVNX0VSUk9SOi00LFpfQlVGX0VSUk9SOi01LFpfTk9fQ09NUFJFU1NJT046MCxaX0JFU1RfU1BFRUQ6MSxaX0JFU1RfQ09NUFJFU1NJT046OSxaX0RFRkFVTFRfQ09NUFJFU1NJT046LTEsWl9GSUxURVJFRDoxLFpfSFVGRk1BTl9PTkxZOjIsWl9STEU6MyxaX0ZJWEVEOjQsWl9ERUZBVUxUX1NUUkFURUdZOjAsWl9CSU5BUlk6MCxaX1RFWFQ6MSxaX1VOS05PV046MixaX0RFRkxBVEVEOjh9LHU9Yy5aX0ZJTklTSCx3PWMuWl9CTE9DSyxiPWMuWl9UUkVFUyxtPWMuWl9PSyxrPWMuWl9TVFJFQU1fRU5ELF89Yy5aX05FRURfRElDVCx2PWMuWl9TVFJFQU1fRVJST1IsZz1jLlpfREFUQV9FUlJPUixwPWMuWl9NRU1fRVJST1IseT1jLlpfQlVGX0VSUk9SLHg9Yy5aX0RFRkxBVEVELEU9MTYxODAsUj0xNjE5MCxBPTE2MTkxLFo9MTYxOTIsUz0xNjE5NCxUPTE2MTk5LE89MTYyMDAsVT0xNjIwNixEPTE2MjA5LEk9ZnVuY3Rpb24oZSl7cmV0dXJuKGU+Pj4yNCYyNTUpKyhlPj4+OCY2NTI4MCkrKCg2NTI4MCZlKTw8OCkrKCgyNTUmZSk8PDI0KX07ZnVuY3Rpb24gQigpe3RoaXMuc3RybT1udWxsLHRoaXMubW9kZT0wLHRoaXMubGFzdD0hMSx0aGlzLndyYXA9MCx0aGlzLmhhdmVkaWN0PSExLHRoaXMuZmxhZ3M9MCx0aGlzLmRtYXg9MCx0aGlzLmNoZWNrPTAsdGhpcy50b3RhbD0wLHRoaXMuaGVhZD1udWxsLHRoaXMud2JpdHM9MCx0aGlzLndzaXplPTAsdGhpcy53aGF2ZT0wLHRoaXMud25leHQ9MCx0aGlzLndpbmRvdz1udWxsLHRoaXMuaG9sZD0wLHRoaXMuYml0cz0wLHRoaXMubGVuZ3RoPTAsdGhpcy5vZmZzZXQ9MCx0aGlzLmV4dHJhPTAsdGhpcy5sZW5jb2RlPW51bGwsdGhpcy5kaXN0Y29kZT1udWxsLHRoaXMubGVuYml0cz0wLHRoaXMuZGlzdGJpdHM9MCx0aGlzLm5jb2RlPTAsdGhpcy5ubGVuPTAsdGhpcy5uZGlzdD0wLHRoaXMuaGF2ZT0wLHRoaXMubmV4dD1udWxsLHRoaXMubGVucz1uZXcgVWludDE2QXJyYXkoMzIwKSx0aGlzLndvcms9bmV3IFVpbnQxNkFycmF5KDI4OCksdGhpcy5sZW5keW49bnVsbCx0aGlzLmRpc3RkeW49bnVsbCx0aGlzLnNhbmU9MCx0aGlzLmJhY2s9MCx0aGlzLndhcz0wfXZhciBOLEMsej1mdW5jdGlvbihlKXtpZighZSlyZXR1cm4gMTt2YXIgdD1lLnN0YXRlO3JldHVybiF0fHx0LnN0cm0hPT1lfHx0Lm1vZGU8RXx8dC5tb2RlPjE2MjExPzE6MH0sRj1mdW5jdGlvbihlKXtpZih6KGUpKXJldHVybiB2O3ZhciB0PWUuc3RhdGU7cmV0dXJuIGUudG90YWxfaW49ZS50b3RhbF9vdXQ9dC50b3RhbD0wLGUubXNnPSIiLHQud3JhcCYmKGUuYWRsZXI9MSZ0LndyYXApLHQubW9kZT1FLHQubGFzdD0wLHQuaGF2ZWRpY3Q9MCx0LmZsYWdzPS0xLHQuZG1heD0zMjc2OCx0LmhlYWQ9bnVsbCx0LmhvbGQ9MCx0LmJpdHM9MCx0LmxlbmNvZGU9dC5sZW5keW49bmV3IEludDMyQXJyYXkoODUyKSx0LmRpc3Rjb2RlPXQuZGlzdGR5bj1uZXcgSW50MzJBcnJheSg1OTIpLHQuc2FuZT0xLHQuYmFjaz0tMSxtfSxMPWZ1bmN0aW9uKGUpe2lmKHooZSkpcmV0dXJuIHY7dmFyIHQ9ZS5zdGF0ZTtyZXR1cm4gdC53c2l6ZT0wLHQud2hhdmU9MCx0LnduZXh0PTAsRihlKX0sTT1mdW5jdGlvbihlLHQpe3ZhciBpO2lmKHooZSkpcmV0dXJuIHY7dmFyIG49ZS5zdGF0ZTtyZXR1cm4gdDwwPyhpPTAsdD0tdCk6KGk9NSsodD4+NCksdDw0OCYmKHQmPTE1KSksdCYmKHQ8OHx8dD4xNSk/djoobnVsbCE9PW4ud2luZG93JiZuLndiaXRzIT09dCYmKG4ud2luZG93PW51bGwpLG4ud3JhcD1pLG4ud2JpdHM9dCxMKGUpKX0sSD1mdW5jdGlvbihlLHQpe2lmKCFlKXJldHVybiB2O3ZhciBpPW5ldyBCO2Uuc3RhdGU9aSxpLnN0cm09ZSxpLndpbmRvdz1udWxsLGkubW9kZT1FO3ZhciBuPU0oZSx0KTtyZXR1cm4gbiE9PW0mJihlLnN0YXRlPW51bGwpLG59LGo9ITAsSz1mdW5jdGlvbihlKXtpZihqKXtOPW5ldyBJbnQzMkFycmF5KDUxMiksQz1uZXcgSW50MzJBcnJheSgzMik7Zm9yKHZhciB0PTA7dDwxNDQ7KWUubGVuc1t0KytdPTg7Zm9yKDt0PDI1NjspZS5sZW5zW3QrK109OTtmb3IoO3Q8MjgwOyllLmxlbnNbdCsrXT03O2Zvcig7dDwyODg7KWUubGVuc1t0KytdPTg7Zm9yKGgoMSxlLmxlbnMsMCwyODgsTiwwLGUud29yayx7Yml0czo5fSksdD0wO3Q8MzI7KWUubGVuc1t0KytdPTU7aCgyLGUubGVucywwLDMyLEMsMCxlLndvcmsse2JpdHM6NX0pLGo9ITF9ZS5sZW5jb2RlPU4sZS5sZW5iaXRzPTksZS5kaXN0Y29kZT1DLGUuZGlzdGJpdHM9NX0sUD1mdW5jdGlvbihlLHQsaSxuKXt2YXIgYSxyPWUuc3RhdGU7cmV0dXJuIG51bGw9PT1yLndpbmRvdyYmKHIud3NpemU9MTw8ci53Yml0cyxyLnduZXh0PTAsci53aGF2ZT0wLHIud2luZG93PW5ldyBVaW50OEFycmF5KHIud3NpemUpKSxuPj1yLndzaXplPyhyLndpbmRvdy5zZXQodC5zdWJhcnJheShpLXIud3NpemUsaSksMCksci53bmV4dD0wLHIud2hhdmU9ci53c2l6ZSk6KChhPXIud3NpemUtci53bmV4dCk+biYmKGE9biksci53aW5kb3cuc2V0KHQuc3ViYXJyYXkoaS1uLGktbithKSxyLnduZXh0KSwobi09YSk/KHIud2luZG93LnNldCh0LnN1YmFycmF5KGktbixpKSwwKSxyLnduZXh0PW4sci53aGF2ZT1yLndzaXplKTooci53bmV4dCs9YSxyLnduZXh0PT09ci53c2l6ZSYmKHIud25leHQ9MCksci53aGF2ZTxyLndzaXplJiYoci53aGF2ZSs9YSkpKSwwfSxZPXtpbmZsYXRlUmVzZXQ6TCxpbmZsYXRlUmVzZXQyOk0saW5mbGF0ZVJlc2V0S2VlcDpGLGluZmxhdGVJbml0OmZ1bmN0aW9uKGUpe3JldHVybiBIKGUsMTUpfSxpbmZsYXRlSW5pdDI6SCxpbmZsYXRlOmZ1bmN0aW9uKGUsaSl7dmFyIGEsbyxzLGwsZixkLGMsQixOLEMsRixMLE0sSCxqLFksRyxYLFcscSxKLFEsViwkLGVlPTAsdGU9bmV3IFVpbnQ4QXJyYXkoNCksaWU9bmV3IFVpbnQ4QXJyYXkoWzE2LDE3LDE4LDAsOCw3LDksNiwxMCw1LDExLDQsMTIsMywxMywyLDE0LDEsMTVdKTtpZih6KGUpfHwhZS5vdXRwdXR8fCFlLmlucHV0JiYwIT09ZS5hdmFpbF9pbilyZXR1cm4gdjsoYT1lLnN0YXRlKS5tb2RlPT09QSYmKGEubW9kZT1aKSxmPWUubmV4dF9vdXQscz1lLm91dHB1dCxjPWUuYXZhaWxfb3V0LGw9ZS5uZXh0X2luLG89ZS5pbnB1dCxkPWUuYXZhaWxfaW4sQj1hLmhvbGQsTj1hLmJpdHMsQz1kLEY9YyxRPW07ZTpmb3IoOzspc3dpdGNoKGEubW9kZSl7Y2FzZSBFOmlmKDA9PT1hLndyYXApe2EubW9kZT1aO2JyZWFrfWZvcig7TjwxNjspe2lmKDA9PT1kKWJyZWFrIGU7ZC0tLEIrPW9bbCsrXTw8TixOKz04fWlmKDImYS53cmFwJiYzNTYxNT09PUIpezA9PT1hLndiaXRzJiYoYS53Yml0cz0xNSksYS5jaGVjaz0wLHRlWzBdPTI1NSZCLHRlWzFdPUI+Pj44JjI1NSxhLmNoZWNrPW4oYS5jaGVjayx0ZSwyLDApLEI9MCxOPTAsYS5tb2RlPTE2MTgxO2JyZWFrfWlmKGEuaGVhZCYmKGEuaGVhZC5kb25lPSExKSwhKDEmYS53cmFwKXx8KCgoMjU1JkIpPDw4KSsoQj4+OCkpJTMxKXtlLm1zZz0iaW5jb3JyZWN0IGhlYWRlciBjaGVjayIsYS5tb2RlPUQ7YnJlYWt9aWYoKDE1JkIpIT09eCl7ZS5tc2c9InVua25vd24gY29tcHJlc3Npb24gbWV0aG9kIixhLm1vZGU9RDticmVha31pZihOLT00LEo9OCsoMTUmKEI+Pj49NCkpLDA9PT1hLndiaXRzJiYoYS53Yml0cz1KKSxKPjE1fHxKPmEud2JpdHMpe2UubXNnPSJpbnZhbGlkIHdpbmRvdyBzaXplIixhLm1vZGU9RDticmVha31hLmRtYXg9MTw8YS53Yml0cyxhLmZsYWdzPTAsZS5hZGxlcj1hLmNoZWNrPTEsYS5tb2RlPTUxMiZCPzE2MTg5OkEsQj0wLE49MDticmVhaztjYXNlIDE2MTgxOmZvcig7TjwxNjspe2lmKDA9PT1kKWJyZWFrIGU7ZC0tLEIrPW9bbCsrXTw8TixOKz04fWlmKGEuZmxhZ3M9QiwoMjU1JmEuZmxhZ3MpIT09eCl7ZS5tc2c9InVua25vd24gY29tcHJlc3Npb24gbWV0aG9kIixhLm1vZGU9RDticmVha31pZig1NzM0NCZhLmZsYWdzKXtlLm1zZz0idW5rbm93biBoZWFkZXIgZmxhZ3Mgc2V0IixhLm1vZGU9RDticmVha31hLmhlYWQmJihhLmhlYWQudGV4dD1CPj44JjEpLDUxMiZhLmZsYWdzJiY0JmEud3JhcCYmKHRlWzBdPTI1NSZCLHRlWzFdPUI+Pj44JjI1NSxhLmNoZWNrPW4oYS5jaGVjayx0ZSwyLDApKSxCPTAsTj0wLGEubW9kZT0xNjE4MjtjYXNlIDE2MTgyOmZvcig7TjwzMjspe2lmKDA9PT1kKWJyZWFrIGU7ZC0tLEIrPW9bbCsrXTw8TixOKz04fWEuaGVhZCYmKGEuaGVhZC50aW1lPUIpLDUxMiZhLmZsYWdzJiY0JmEud3JhcCYmKHRlWzBdPTI1NSZCLHRlWzFdPUI+Pj44JjI1NSx0ZVsyXT1CPj4+MTYmMjU1LHRlWzNdPUI+Pj4yNCYyNTUsYS5jaGVjaz1uKGEuY2hlY2ssdGUsNCwwKSksQj0wLE49MCxhLm1vZGU9MTYxODM7Y2FzZSAxNjE4Mzpmb3IoO048MTY7KXtpZigwPT09ZClicmVhayBlO2QtLSxCKz1vW2wrK108PE4sTis9OH1hLmhlYWQmJihhLmhlYWQueGZsYWdzPTI1NSZCLGEuaGVhZC5vcz1CPj44KSw1MTImYS5mbGFncyYmNCZhLndyYXAmJih0ZVswXT0yNTUmQix0ZVsxXT1CPj4+OCYyNTUsYS5jaGVjaz1uKGEuY2hlY2ssdGUsMiwwKSksQj0wLE49MCxhLm1vZGU9MTYxODQ7Y2FzZSAxNjE4NDppZigxMDI0JmEuZmxhZ3Mpe2Zvcig7TjwxNjspe2lmKDA9PT1kKWJyZWFrIGU7ZC0tLEIrPW9bbCsrXTw8TixOKz04fWEubGVuZ3RoPUIsYS5oZWFkJiYoYS5oZWFkLmV4dHJhX2xlbj1CKSw1MTImYS5mbGFncyYmNCZhLndyYXAmJih0ZVswXT0yNTUmQix0ZVsxXT1CPj4+OCYyNTUsYS5jaGVjaz1uKGEuY2hlY2ssdGUsMiwwKSksQj0wLE49MH1lbHNlIGEuaGVhZCYmKGEuaGVhZC5leHRyYT1udWxsKTthLm1vZGU9MTYxODU7Y2FzZSAxNjE4NTppZigxMDI0JmEuZmxhZ3MmJigoTD1hLmxlbmd0aCk+ZCYmKEw9ZCksTCYmKGEuaGVhZCYmKEo9YS5oZWFkLmV4dHJhX2xlbi1hLmxlbmd0aCxhLmhlYWQuZXh0cmF8fChhLmhlYWQuZXh0cmE9bmV3IFVpbnQ4QXJyYXkoYS5oZWFkLmV4dHJhX2xlbikpLGEuaGVhZC5leHRyYS5zZXQoby5zdWJhcnJheShsLGwrTCksSikpLDUxMiZhLmZsYWdzJiY0JmEud3JhcCYmKGEuY2hlY2s9bihhLmNoZWNrLG8sTCxsKSksZC09TCxsKz1MLGEubGVuZ3RoLT1MKSxhLmxlbmd0aCkpYnJlYWsgZTthLmxlbmd0aD0wLGEubW9kZT0xNjE4NjtjYXNlIDE2MTg2OmlmKDIwNDgmYS5mbGFncyl7aWYoMD09PWQpYnJlYWsgZTtMPTA7ZG97Sj1vW2wrTCsrXSxhLmhlYWQmJkomJmEubGVuZ3RoPDY1NTM2JiYoYS5oZWFkLm5hbWUrPVN0cmluZy5mcm9tQ2hhckNvZGUoSikpfXdoaWxlKEomJkw8ZCk7aWYoNTEyJmEuZmxhZ3MmJjQmYS53cmFwJiYoYS5jaGVjaz1uKGEuY2hlY2ssbyxMLGwpKSxkLT1MLGwrPUwsSilicmVhayBlfWVsc2UgYS5oZWFkJiYoYS5oZWFkLm5hbWU9bnVsbCk7YS5sZW5ndGg9MCxhLm1vZGU9MTYxODc7Y2FzZSAxNjE4NzppZig0MDk2JmEuZmxhZ3Mpe2lmKDA9PT1kKWJyZWFrIGU7TD0wO2Rve0o9b1tsK0wrK10sYS5oZWFkJiZKJiZhLmxlbmd0aDw2NTUzNiYmKGEuaGVhZC5jb21tZW50Kz1TdHJpbmcuZnJvbUNoYXJDb2RlKEopKX13aGlsZShKJiZMPGQpO2lmKDUxMiZhLmZsYWdzJiY0JmEud3JhcCYmKGEuY2hlY2s9bihhLmNoZWNrLG8sTCxsKSksZC09TCxsKz1MLEopYnJlYWsgZX1lbHNlIGEuaGVhZCYmKGEuaGVhZC5jb21tZW50PW51bGwpO2EubW9kZT0xNjE4ODtjYXNlIDE2MTg4OmlmKDUxMiZhLmZsYWdzKXtmb3IoO048MTY7KXtpZigwPT09ZClicmVhayBlO2QtLSxCKz1vW2wrK108PE4sTis9OH1pZig0JmEud3JhcCYmQiE9PSg2NTUzNSZhLmNoZWNrKSl7ZS5tc2c9ImhlYWRlciBjcmMgbWlzbWF0Y2giLGEubW9kZT1EO2JyZWFrfUI9MCxOPTB9YS5oZWFkJiYoYS5oZWFkLmhjcmM9YS5mbGFncz4+OSYxLGEuaGVhZC5kb25lPSEwKSxlLmFkbGVyPWEuY2hlY2s9MCxhLm1vZGU9QTticmVhaztjYXNlIDE2MTg5OmZvcig7TjwzMjspe2lmKDA9PT1kKWJyZWFrIGU7ZC0tLEIrPW9bbCsrXTw8TixOKz04fWUuYWRsZXI9YS5jaGVjaz1JKEIpLEI9MCxOPTAsYS5tb2RlPVI7Y2FzZSBSOmlmKDA9PT1hLmhhdmVkaWN0KXJldHVybiBlLm5leHRfb3V0PWYsZS5hdmFpbF9vdXQ9YyxlLm5leHRfaW49bCxlLmF2YWlsX2luPWQsYS5ob2xkPUIsYS5iaXRzPU4sXztlLmFkbGVyPWEuY2hlY2s9MSxhLm1vZGU9QTtjYXNlIEE6aWYoaT09PXd8fGk9PT1iKWJyZWFrIGU7Y2FzZSBaOmlmKGEubGFzdCl7Qj4+Pj03Jk4sTi09NyZOLGEubW9kZT1VO2JyZWFrfWZvcig7TjwzOyl7aWYoMD09PWQpYnJlYWsgZTtkLS0sQis9b1tsKytdPDxOLE4rPTh9c3dpdGNoKGEubGFzdD0xJkIsTi09MSwzJihCPj4+PTEpKXtjYXNlIDA6YS5tb2RlPTE2MTkzO2JyZWFrO2Nhc2UgMTppZihLKGEpLGEubW9kZT1ULGk9PT1iKXtCPj4+PTIsTi09MjticmVhayBlfWJyZWFrO2Nhc2UgMjphLm1vZGU9MTYxOTY7YnJlYWs7Y2FzZSAzOmUubXNnPSJpbnZhbGlkIGJsb2NrIHR5cGUiLGEubW9kZT1EfUI+Pj49MixOLT0yO2JyZWFrO2Nhc2UgMTYxOTM6Zm9yKEI+Pj49NyZOLE4tPTcmTjtOPDMyOyl7aWYoMD09PWQpYnJlYWsgZTtkLS0sQis9b1tsKytdPDxOLE4rPTh9aWYoKDY1NTM1JkIpIT0oQj4+PjE2XjY1NTM1KSl7ZS5tc2c9ImludmFsaWQgc3RvcmVkIGJsb2NrIGxlbmd0aHMiLGEubW9kZT1EO2JyZWFrfWlmKGEubGVuZ3RoPTY1NTM1JkIsQj0wLE49MCxhLm1vZGU9UyxpPT09YilicmVhayBlO2Nhc2UgUzphLm1vZGU9MTYxOTU7Y2FzZSAxNjE5NTppZihMPWEubGVuZ3RoKXtpZihMPmQmJihMPWQpLEw+YyYmKEw9YyksMD09PUwpYnJlYWsgZTtzLnNldChvLnN1YmFycmF5KGwsbCtMKSxmKSxkLT1MLGwrPUwsYy09TCxmKz1MLGEubGVuZ3RoLT1MO2JyZWFrfWEubW9kZT1BO2JyZWFrO2Nhc2UgMTYxOTY6Zm9yKDtOPDE0Oyl7aWYoMD09PWQpYnJlYWsgZTtkLS0sQis9b1tsKytdPDxOLE4rPTh9aWYoYS5ubGVuPTI1NysoMzEmQiksQj4+Pj01LE4tPTUsYS5uZGlzdD0xKygzMSZCKSxCPj4+PTUsTi09NSxhLm5jb2RlPTQrKDE1JkIpLEI+Pj49NCxOLT00LGEubmxlbj4yODZ8fGEubmRpc3Q+MzApe2UubXNnPSJ0b28gbWFueSBsZW5ndGggb3IgZGlzdGFuY2Ugc3ltYm9scyIsYS5tb2RlPUQ7YnJlYWt9YS5oYXZlPTAsYS5tb2RlPTE2MTk3O2Nhc2UgMTYxOTc6Zm9yKDthLmhhdmU8YS5uY29kZTspe2Zvcig7TjwzOyl7aWYoMD09PWQpYnJlYWsgZTtkLS0sQis9b1tsKytdPDxOLE4rPTh9YS5sZW5zW2llW2EuaGF2ZSsrXV09NyZCLEI+Pj49MyxOLT0zfWZvcig7YS5oYXZlPDE5OylhLmxlbnNbaWVbYS5oYXZlKytdXT0wO2lmKGEubGVuY29kZT1hLmxlbmR5bixhLmxlbmJpdHM9NyxWPXtiaXRzOmEubGVuYml0c30sUT1oKDAsYS5sZW5zLDAsMTksYS5sZW5jb2RlLDAsYS53b3JrLFYpLGEubGVuYml0cz1WLmJpdHMsUSl7ZS5tc2c9ImludmFsaWQgY29kZSBsZW5ndGhzIHNldCIsYS5tb2RlPUQ7YnJlYWt9YS5oYXZlPTAsYS5tb2RlPTE2MTk4O2Nhc2UgMTYxOTg6Zm9yKDthLmhhdmU8YS5ubGVuK2EubmRpc3Q7KXtmb3IoO1k9KGVlPWEubGVuY29kZVtCJigxPDxhLmxlbmJpdHMpLTFdKT4+PjE2JjI1NSxHPTY1NTM1JmVlLCEoKGo9ZWU+Pj4yNCk8PU4pOyl7aWYoMD09PWQpYnJlYWsgZTtkLS0sQis9b1tsKytdPDxOLE4rPTh9aWYoRzwxNilCPj4+PWosTi09aixhLmxlbnNbYS5oYXZlKytdPUc7ZWxzZXtpZigxNj09PUcpe2ZvcigkPWorMjtOPCQ7KXtpZigwPT09ZClicmVhayBlO2QtLSxCKz1vW2wrK108PE4sTis9OH1pZihCPj4+PWosTi09aiwwPT09YS5oYXZlKXtlLm1zZz0iaW52YWxpZCBiaXQgbGVuZ3RoIHJlcGVhdCIsYS5tb2RlPUQ7YnJlYWt9Sj1hLmxlbnNbYS5oYXZlLTFdLEw9MysoMyZCKSxCPj4+PTIsTi09Mn1lbHNlIGlmKDE3PT09Ryl7Zm9yKCQ9aiszO048JDspe2lmKDA9PT1kKWJyZWFrIGU7ZC0tLEIrPW9bbCsrXTw8TixOKz04fU4tPWosSj0wLEw9MysoNyYoQj4+Pj1qKSksQj4+Pj0zLE4tPTN9ZWxzZXtmb3IoJD1qKzc7TjwkOyl7aWYoMD09PWQpYnJlYWsgZTtkLS0sQis9b1tsKytdPDxOLE4rPTh9Ti09aixKPTAsTD0xMSsoMTI3JihCPj4+PWopKSxCPj4+PTcsTi09N31pZihhLmhhdmUrTD5hLm5sZW4rYS5uZGlzdCl7ZS5tc2c9ImludmFsaWQgYml0IGxlbmd0aCByZXBlYXQiLGEubW9kZT1EO2JyZWFrfWZvcig7TC0tOylhLmxlbnNbYS5oYXZlKytdPUp9fWlmKGEubW9kZT09PUQpYnJlYWs7aWYoMD09PWEubGVuc1syNTZdKXtlLm1zZz0iaW52YWxpZCBjb2RlIC0tIG1pc3NpbmcgZW5kLW9mLWJsb2NrIixhLm1vZGU9RDticmVha31pZihhLmxlbmJpdHM9OSxWPXtiaXRzOmEubGVuYml0c30sUT1oKDEsYS5sZW5zLDAsYS5ubGVuLGEubGVuY29kZSwwLGEud29yayxWKSxhLmxlbmJpdHM9Vi5iaXRzLFEpe2UubXNnPSJpbnZhbGlkIGxpdGVyYWwvbGVuZ3RocyBzZXQiLGEubW9kZT1EO2JyZWFrfWlmKGEuZGlzdGJpdHM9NixhLmRpc3Rjb2RlPWEuZGlzdGR5bixWPXtiaXRzOmEuZGlzdGJpdHN9LFE9aCgyLGEubGVucyxhLm5sZW4sYS5uZGlzdCxhLmRpc3Rjb2RlLDAsYS53b3JrLFYpLGEuZGlzdGJpdHM9Vi5iaXRzLFEpe2UubXNnPSJpbnZhbGlkIGRpc3RhbmNlcyBzZXQiLGEubW9kZT1EO2JyZWFrfWlmKGEubW9kZT1ULGk9PT1iKWJyZWFrIGU7Y2FzZSBUOmEubW9kZT1PO2Nhc2UgTzppZihkPj02JiZjPj0yNTgpe2UubmV4dF9vdXQ9ZixlLmF2YWlsX291dD1jLGUubmV4dF9pbj1sLGUuYXZhaWxfaW49ZCxhLmhvbGQ9QixhLmJpdHM9TixyKGUsRiksZj1lLm5leHRfb3V0LHM9ZS5vdXRwdXQsYz1lLmF2YWlsX291dCxsPWUubmV4dF9pbixvPWUuaW5wdXQsZD1lLmF2YWlsX2luLEI9YS5ob2xkLE49YS5iaXRzLGEubW9kZT09PUEmJihhLmJhY2s9LTEpO2JyZWFrfWZvcihhLmJhY2s9MDtZPShlZT1hLmxlbmNvZGVbQiYoMTw8YS5sZW5iaXRzKS0xXSk+Pj4xNiYyNTUsRz02NTUzNSZlZSwhKChqPWVlPj4+MjQpPD1OKTspe2lmKDA9PT1kKWJyZWFrIGU7ZC0tLEIrPW9bbCsrXTw8TixOKz04fWlmKFkmJjA9PSgyNDAmWSkpe2ZvcihYPWosVz1ZLHE9RztZPShlZT1hLmxlbmNvZGVbcSsoKEImKDE8PFgrVyktMSk+PlgpXSk+Pj4xNiYyNTUsRz02NTUzNSZlZSwhKFgrKGo9ZWU+Pj4yNCk8PU4pOyl7aWYoMD09PWQpYnJlYWsgZTtkLS0sQis9b1tsKytdPDxOLE4rPTh9Qj4+Pj1YLE4tPVgsYS5iYWNrKz1YfWlmKEI+Pj49aixOLT1qLGEuYmFjays9aixhLmxlbmd0aD1HLDA9PT1ZKXthLm1vZGU9MTYyMDU7YnJlYWt9aWYoMzImWSl7YS5iYWNrPS0xLGEubW9kZT1BO2JyZWFrfWlmKDY0Jlkpe2UubXNnPSJpbnZhbGlkIGxpdGVyYWwvbGVuZ3RoIGNvZGUiLGEubW9kZT1EO2JyZWFrfWEuZXh0cmE9MTUmWSxhLm1vZGU9MTYyMDE7Y2FzZSAxNjIwMTppZihhLmV4dHJhKXtmb3IoJD1hLmV4dHJhO048JDspe2lmKDA9PT1kKWJyZWFrIGU7ZC0tLEIrPW9bbCsrXTw8TixOKz04fWEubGVuZ3RoKz1CJigxPDxhLmV4dHJhKS0xLEI+Pj49YS5leHRyYSxOLT1hLmV4dHJhLGEuYmFjays9YS5leHRyYX1hLndhcz1hLmxlbmd0aCxhLm1vZGU9MTYyMDI7Y2FzZSAxNjIwMjpmb3IoO1k9KGVlPWEuZGlzdGNvZGVbQiYoMTw8YS5kaXN0Yml0cyktMV0pPj4+MTYmMjU1LEc9NjU1MzUmZWUsISgoaj1lZT4+PjI0KTw9Tik7KXtpZigwPT09ZClicmVhayBlO2QtLSxCKz1vW2wrK108PE4sTis9OH1pZigwPT0oMjQwJlkpKXtmb3IoWD1qLFc9WSxxPUc7WT0oZWU9YS5kaXN0Y29kZVtxKygoQiYoMTw8WCtXKS0xKT4+WCldKT4+PjE2JjI1NSxHPTY1NTM1JmVlLCEoWCsoaj1lZT4+PjI0KTw9Tik7KXtpZigwPT09ZClicmVhayBlO2QtLSxCKz1vW2wrK108PE4sTis9OH1CPj4+PVgsTi09WCxhLmJhY2srPVh9aWYoQj4+Pj1qLE4tPWosYS5iYWNrKz1qLDY0Jlkpe2UubXNnPSJpbnZhbGlkIGRpc3RhbmNlIGNvZGUiLGEubW9kZT1EO2JyZWFrfWEub2Zmc2V0PUcsYS5leHRyYT0xNSZZLGEubW9kZT0xNjIwMztjYXNlIDE2MjAzOmlmKGEuZXh0cmEpe2ZvcigkPWEuZXh0cmE7TjwkOyl7aWYoMD09PWQpYnJlYWsgZTtkLS0sQis9b1tsKytdPDxOLE4rPTh9YS5vZmZzZXQrPUImKDE8PGEuZXh0cmEpLTEsQj4+Pj1hLmV4dHJhLE4tPWEuZXh0cmEsYS5iYWNrKz1hLmV4dHJhfWlmKGEub2Zmc2V0PmEuZG1heCl7ZS5tc2c9ImludmFsaWQgZGlzdGFuY2UgdG9vIGZhciBiYWNrIixhLm1vZGU9RDticmVha31hLm1vZGU9MTYyMDQ7Y2FzZSAxNjIwNDppZigwPT09YylicmVhayBlO2lmKEw9Ri1jLGEub2Zmc2V0Pkwpe2lmKChMPWEub2Zmc2V0LUwpPmEud2hhdmUmJmEuc2FuZSl7ZS5tc2c9ImludmFsaWQgZGlzdGFuY2UgdG9vIGZhciBiYWNrIixhLm1vZGU9RDticmVha31MPmEud25leHQ/KEwtPWEud25leHQsTT1hLndzaXplLUwpOk09YS53bmV4dC1MLEw+YS5sZW5ndGgmJihMPWEubGVuZ3RoKSxIPWEud2luZG93fWVsc2UgSD1zLE09Zi1hLm9mZnNldCxMPWEubGVuZ3RoO0w+YyYmKEw9YyksYy09TCxhLmxlbmd0aC09TDtkb3tzW2YrK109SFtNKytdfXdoaWxlKC0tTCk7MD09PWEubGVuZ3RoJiYoYS5tb2RlPU8pO2JyZWFrO2Nhc2UgMTYyMDU6aWYoMD09PWMpYnJlYWsgZTtzW2YrK109YS5sZW5ndGgsYy0tLGEubW9kZT1PO2JyZWFrO2Nhc2UgVTppZihhLndyYXApe2Zvcig7TjwzMjspe2lmKDA9PT1kKWJyZWFrIGU7ZC0tLEJ8PW9bbCsrXTw8TixOKz04fWlmKEYtPWMsZS50b3RhbF9vdXQrPUYsYS50b3RhbCs9Riw0JmEud3JhcCYmRiYmKGUuYWRsZXI9YS5jaGVjaz1hLmZsYWdzP24oYS5jaGVjayxzLEYsZi1GKTp0KGEuY2hlY2sscyxGLGYtRikpLEY9Yyw0JmEud3JhcCYmKGEuZmxhZ3M/QjpJKEIpKSE9PWEuY2hlY2spe2UubXNnPSJpbmNvcnJlY3QgZGF0YSBjaGVjayIsYS5tb2RlPUQ7YnJlYWt9Qj0wLE49MH1hLm1vZGU9MTYyMDc7Y2FzZSAxNjIwNzppZihhLndyYXAmJmEuZmxhZ3Mpe2Zvcig7TjwzMjspe2lmKDA9PT1kKWJyZWFrIGU7ZC0tLEIrPW9bbCsrXTw8TixOKz04fWlmKDQmYS53cmFwJiZCIT09KDQyOTQ5NjcyOTUmYS50b3RhbCkpe2UubXNnPSJpbmNvcnJlY3QgbGVuZ3RoIGNoZWNrIixhLm1vZGU9RDticmVha31CPTAsTj0wfWEubW9kZT0xNjIwODtjYXNlIDE2MjA4OlE9azticmVhayBlO2Nhc2UgRDpRPWc7YnJlYWsgZTtjYXNlIDE2MjEwOnJldHVybiBwO2RlZmF1bHQ6cmV0dXJuIHZ9cmV0dXJuIGUubmV4dF9vdXQ9ZixlLmF2YWlsX291dD1jLGUubmV4dF9pbj1sLGUuYXZhaWxfaW49ZCxhLmhvbGQ9QixhLmJpdHM9TiwoYS53c2l6ZXx8RiE9PWUuYXZhaWxfb3V0JiZhLm1vZGU8RCYmKGEubW9kZTxVfHxpIT09dSkpJiZQKGUsZS5vdXRwdXQsZS5uZXh0X291dCxGLWUuYXZhaWxfb3V0KSxDLT1lLmF2YWlsX2luLEYtPWUuYXZhaWxfb3V0LGUudG90YWxfaW4rPUMsZS50b3RhbF9vdXQrPUYsYS50b3RhbCs9Riw0JmEud3JhcCYmRiYmKGUuYWRsZXI9YS5jaGVjaz1hLmZsYWdzP24oYS5jaGVjayxzLEYsZS5uZXh0X291dC1GKTp0KGEuY2hlY2sscyxGLGUubmV4dF9vdXQtRikpLGUuZGF0YV90eXBlPWEuYml0cysoYS5sYXN0PzY0OjApKyhhLm1vZGU9PT1BPzEyODowKSsoYS5tb2RlPT09VHx8YS5tb2RlPT09Uz8yNTY6MCksKDA9PT1DJiYwPT09Rnx8aT09PXUpJiZRPT09bSYmKFE9eSksUX0saW5mbGF0ZUVuZDpmdW5jdGlvbihlKXtpZih6KGUpKXJldHVybiB2O3ZhciB0PWUuc3RhdGU7cmV0dXJuIHQud2luZG93JiYodC53aW5kb3c9bnVsbCksZS5zdGF0ZT1udWxsLG19LGluZmxhdGVHZXRIZWFkZXI6ZnVuY3Rpb24oZSx0KXtpZih6KGUpKXJldHVybiB2O3ZhciBpPWUuc3RhdGU7cmV0dXJuIDA9PSgyJmkud3JhcCk/djooaS5oZWFkPXQsdC5kb25lPSExLG0pfSxpbmZsYXRlU2V0RGljdGlvbmFyeTpmdW5jdGlvbihlLGkpe3ZhciBuLGE9aS5sZW5ndGg7cmV0dXJuIHooZSl8fDAhPT0obj1lLnN0YXRlKS53cmFwJiZuLm1vZGUhPT1SP3Y6bi5tb2RlPT09UiYmdCgxLGksYSwwKSE9PW4uY2hlY2s/ZzpQKGUsaSxhLGEpPyhuLm1vZGU9MTYyMTAscCk6KG4uaGF2ZWRpY3Q9MSxtKX0saW5mbGF0ZUluZm86InBha28gaW5mbGF0ZSAoZnJvbSBOb2RlY2EgcHJvamVjdCkifTtmdW5jdGlvbiBHKGUpe3JldHVybiBHPSJmdW5jdGlvbiI9PXR5cGVvZiBTeW1ib2wmJiJzeW1ib2wiPT10eXBlb2YgU3ltYm9sLml0ZXJhdG9yP2Z1bmN0aW9uKGUpe3JldHVybiB0eXBlb2YgZX06ZnVuY3Rpb24oZSl7cmV0dXJuIGUmJiJmdW5jdGlvbiI9PXR5cGVvZiBTeW1ib2wmJmUuY29uc3RydWN0b3I9PT1TeW1ib2wmJmUhPT1TeW1ib2wucHJvdG90eXBlPyJzeW1ib2wiOnR5cGVvZiBlfSxHKGUpfXZhciBYPWZ1bmN0aW9uKGUsdCl7cmV0dXJuIE9iamVjdC5wcm90b3R5cGUuaGFzT3duUHJvcGVydHkuY2FsbChlLHQpfSxXPWZ1bmN0aW9uKGUpe2Zvcih2YXIgdD1BcnJheS5wcm90b3R5cGUuc2xpY2UuY2FsbChhcmd1bWVudHMsMSk7dC5sZW5ndGg7KXt2YXIgaT10LnNoaWZ0KCk7aWYoaSl7aWYoIm9iamVjdCIhPT1HKGkpKXRocm93IG5ldyBUeXBlRXJyb3IoaSsibXVzdCBiZSBub24tb2JqZWN0Iik7Zm9yKHZhciBuIGluIGkpWChpLG4pJiYoZVtuXT1pW25dKX19cmV0dXJuIGV9LHE9ZnVuY3Rpb24oZSl7Zm9yKHZhciB0PTAsaT0wLG49ZS5sZW5ndGg7aTxuO2krKyl0Kz1lW2ldLmxlbmd0aDtmb3IodmFyIGE9bmV3IFVpbnQ4QXJyYXkodCkscj0wLG89MCxzPWUubGVuZ3RoO3I8cztyKyspe3ZhciBsPWVbcl07YS5zZXQobCxvKSxvKz1sLmxlbmd0aH1yZXR1cm4gYX0sSj0hMDt0cnl7U3RyaW5nLmZyb21DaGFyQ29kZS5hcHBseShudWxsLG5ldyBVaW50OEFycmF5KDEpKX1jYXRjaChlKXtKPSExfWZvcih2YXIgUT1uZXcgVWludDhBcnJheSgyNTYpLFY9MDtWPDI1NjtWKyspUVtWXT1WPj0yNTI/NjpWPj0yNDg/NTpWPj0yNDA/NDpWPj0yMjQ/MzpWPj0xOTI/MjoxO1FbMjU0XT1RWzI1NF09MTt2YXIgJD1mdW5jdGlvbihlKXtpZigiZnVuY3Rpb24iPT10eXBlb2YgVGV4dEVuY29kZXImJlRleHRFbmNvZGVyLnByb3RvdHlwZS5lbmNvZGUpcmV0dXJuKG5ldyBUZXh0RW5jb2RlcikuZW5jb2RlKGUpO3ZhciB0LGksbixhLHIsbz1lLmxlbmd0aCxzPTA7Zm9yKGE9MDthPG87YSsrKTU1Mjk2PT0oNjQ1MTImKGk9ZS5jaGFyQ29kZUF0KGEpKSkmJmErMTxvJiY1NjMyMD09KDY0NTEyJihuPWUuY2hhckNvZGVBdChhKzEpKSkmJihpPTY1NTM2KyhpLTU1Mjk2PDwxMCkrKG4tNTYzMjApLGErKykscys9aTwxMjg/MTppPDIwNDg/MjppPDY1NTM2PzM6NDtmb3IodD1uZXcgVWludDhBcnJheShzKSxyPTAsYT0wO3I8czthKyspNTUyOTY9PSg2NDUxMiYoaT1lLmNoYXJDb2RlQXQoYSkpKSYmYSsxPG8mJjU2MzIwPT0oNjQ1MTImKG49ZS5jaGFyQ29kZUF0KGErMSkpKSYmKGk9NjU1MzYrKGktNTUyOTY8PDEwKSsobi01NjMyMCksYSsrKSxpPDEyOD90W3IrK109aTppPDIwNDg/KHRbcisrXT0xOTJ8aT4+PjYsdFtyKytdPTEyOHw2MyZpKTppPDY1NTM2Pyh0W3IrK109MjI0fGk+Pj4xMix0W3IrK109MTI4fGk+Pj42JjYzLHRbcisrXT0xMjh8NjMmaSk6KHRbcisrXT0yNDB8aT4+PjE4LHRbcisrXT0xMjh8aT4+PjEyJjYzLHRbcisrXT0xMjh8aT4+PjYmNjMsdFtyKytdPTEyOHw2MyZpKTtyZXR1cm4gdH0sZWU9ZnVuY3Rpb24oZSx0KXt2YXIgaSxuLGE9dHx8ZS5sZW5ndGg7aWYoImZ1bmN0aW9uIj09dHlwZW9mIFRleHREZWNvZGVyJiZUZXh0RGVjb2Rlci5wcm90b3R5cGUuZGVjb2RlKXJldHVybihuZXcgVGV4dERlY29kZXIpLmRlY29kZShlLnN1YmFycmF5KDAsdCkpO3ZhciByPW5ldyBBcnJheSgyKmEpO2ZvcihuPTAsaT0wO2k8YTspe3ZhciBvPWVbaSsrXTtpZihvPDEyOClyW24rK109bztlbHNle3ZhciBzPVFbb107aWYocz40KXJbbisrXT02NTUzMyxpKz1zLTE7ZWxzZXtmb3IobyY9Mj09PXM/MzE6Mz09PXM/MTU6NztzPjEmJmk8YTspbz1vPDw2fDYzJmVbaSsrXSxzLS07cz4xP3JbbisrXT02NTUzMzpvPDY1NTM2P3JbbisrXT1vOihvLT02NTUzNixyW24rK109NTUyOTZ8bz4+MTAmMTAyMyxyW24rK109NTYzMjB8MTAyMyZvKX19fXJldHVybiBmdW5jdGlvbihlLHQpe2lmKHQ8NjU1MzQmJmUuc3ViYXJyYXkmJkopcmV0dXJuIFN0cmluZy5mcm9tQ2hhckNvZGUuYXBwbHkobnVsbCxlLmxlbmd0aD09PXQ/ZTplLnN1YmFycmF5KDAsdCkpO2Zvcih2YXIgaT0iIixuPTA7bjx0O24rKylpKz1TdHJpbmcuZnJvbUNoYXJDb2RlKGVbbl0pO3JldHVybiBpfShyLG4pfSx0ZT1mdW5jdGlvbihlLHQpeyh0PXR8fGUubGVuZ3RoKT5lLmxlbmd0aCYmKHQ9ZS5sZW5ndGgpO2Zvcih2YXIgaT10LTE7aT49MCYmMTI4PT0oMTkyJmVbaV0pOylpLS07cmV0dXJuIGk8MHx8MD09PWk/dDppK1FbZVtpXV0+dD9pOnR9LGllPXsyOiJuZWVkIGRpY3Rpb25hcnkiLDE6InN0cmVhbSBlbmQiLDA6IiIsIi0xIjoiZmlsZSBlcnJvciIsIi0yIjoic3RyZWFtIGVycm9yIiwiLTMiOiJkYXRhIGVycm9yIiwiLTQiOiJpbnN1ZmZpY2llbnQgbWVtb3J5IiwiLTUiOiJidWZmZXIgZXJyb3IiLCItNiI6ImluY29tcGF0aWJsZSB2ZXJzaW9uIn07dmFyIG5lPWZ1bmN0aW9uKCl7dGhpcy5pbnB1dD1udWxsLHRoaXMubmV4dF9pbj0wLHRoaXMuYXZhaWxfaW49MCx0aGlzLnRvdGFsX2luPTAsdGhpcy5vdXRwdXQ9bnVsbCx0aGlzLm5leHRfb3V0PTAsdGhpcy5hdmFpbF9vdXQ9MCx0aGlzLnRvdGFsX291dD0wLHRoaXMubXNnPSIiLHRoaXMuc3RhdGU9bnVsbCx0aGlzLmRhdGFfdHlwZT0yLHRoaXMuYWRsZXI9MH07dmFyIGFlPWZ1bmN0aW9uKCl7dGhpcy50ZXh0PTAsdGhpcy50aW1lPTAsdGhpcy54ZmxhZ3M9MCx0aGlzLm9zPTAsdGhpcy5leHRyYT1udWxsLHRoaXMuZXh0cmFfbGVuPTAsdGhpcy5uYW1lPSIiLHRoaXMuY29tbWVudD0iIix0aGlzLmhjcmM9MCx0aGlzLmRvbmU9ITF9LHJlPU9iamVjdC5wcm90b3R5cGUudG9TdHJpbmcsb2U9Yy5aX05PX0ZMVVNILHNlPWMuWl9GSU5JU0gsbGU9Yy5aX09LLGZlPWMuWl9TVFJFQU1fRU5ELGRlPWMuWl9ORUVEX0RJQ1QsaGU9Yy5aX1NUUkVBTV9FUlJPUixjZT1jLlpfREFUQV9FUlJPUix1ZT1jLlpfTUVNX0VSUk9SO2Z1bmN0aW9uIHdlKGUpe3RoaXMub3B0aW9ucz1XKHtjaHVua1NpemU6NjU1MzYsd2luZG93Qml0czoxNSx0bzoiIn0sZXx8e30pO3ZhciB0PXRoaXMub3B0aW9uczt0LnJhdyYmdC53aW5kb3dCaXRzPj0wJiZ0LndpbmRvd0JpdHM8MTYmJih0LndpbmRvd0JpdHM9LXQud2luZG93Qml0cywwPT09dC53aW5kb3dCaXRzJiYodC53aW5kb3dCaXRzPS0xNSkpLCEodC53aW5kb3dCaXRzPj0wJiZ0LndpbmRvd0JpdHM8MTYpfHxlJiZlLndpbmRvd0JpdHN8fCh0LndpbmRvd0JpdHMrPTMyKSx0LndpbmRvd0JpdHM+MTUmJnQud2luZG93Qml0czw0OCYmMD09KDE1JnQud2luZG93Qml0cykmJih0LndpbmRvd0JpdHN8PTE1KSx0aGlzLmVycj0wLHRoaXMubXNnPSIiLHRoaXMuZW5kZWQ9ITEsdGhpcy5jaHVua3M9W10sdGhpcy5zdHJtPW5ldyBuZSx0aGlzLnN0cm0uYXZhaWxfb3V0PTA7dmFyIGk9WS5pbmZsYXRlSW5pdDIodGhpcy5zdHJtLHQud2luZG93Qml0cyk7aWYoaSE9PWxlKXRocm93IG5ldyBFcnJvcihpZVtpXSk7aWYodGhpcy5oZWFkZXI9bmV3IGFlLFkuaW5mbGF0ZUdldEhlYWRlcih0aGlzLnN0cm0sdGhpcy5oZWFkZXIpLHQuZGljdGlvbmFyeSYmKCJzdHJpbmciPT10eXBlb2YgdC5kaWN0aW9uYXJ5P3QuZGljdGlvbmFyeT0kKHQuZGljdGlvbmFyeSk6IltvYmplY3QgQXJyYXlCdWZmZXJdIj09PXJlLmNhbGwodC5kaWN0aW9uYXJ5KSYmKHQuZGljdGlvbmFyeT1uZXcgVWludDhBcnJheSh0LmRpY3Rpb25hcnkpKSx0LnJhdyYmKGk9WS5pbmZsYXRlU2V0RGljdGlvbmFyeSh0aGlzLnN0cm0sdC5kaWN0aW9uYXJ5KSkhPT1sZSkpdGhyb3cgbmV3IEVycm9yKGllW2ldKX1mdW5jdGlvbiBiZShlLHQpe3ZhciBpPW5ldyB3ZSh0KTtpZihpLnB1c2goZSksaS5lcnIpdGhyb3cgaS5tc2d8fGllW2kuZXJyXTtyZXR1cm4gaS5yZXN1bHR9d2UucHJvdG90eXBlLnB1c2g9ZnVuY3Rpb24oZSx0KXt2YXIgaSxuLGEscj10aGlzLnN0cm0sbz10aGlzLm9wdGlvbnMuY2h1bmtTaXplLHM9dGhpcy5vcHRpb25zLmRpY3Rpb25hcnk7aWYodGhpcy5lbmRlZClyZXR1cm4hMTtmb3Iobj10PT09fn50P3Q6ITA9PT10P3NlOm9lLCJbb2JqZWN0IEFycmF5QnVmZmVyXSI9PT1yZS5jYWxsKGUpP3IuaW5wdXQ9bmV3IFVpbnQ4QXJyYXkoZSk6ci5pbnB1dD1lLHIubmV4dF9pbj0wLHIuYXZhaWxfaW49ci5pbnB1dC5sZW5ndGg7Oyl7Zm9yKDA9PT1yLmF2YWlsX291dCYmKHIub3V0cHV0PW5ldyBVaW50OEFycmF5KG8pLHIubmV4dF9vdXQ9MCxyLmF2YWlsX291dD1vKSwoaT1ZLmluZmxhdGUocixuKSk9PT1kZSYmcyYmKChpPVkuaW5mbGF0ZVNldERpY3Rpb25hcnkocixzKSk9PT1sZT9pPVkuaW5mbGF0ZShyLG4pOmk9PT1jZSYmKGk9ZGUpKTtyLmF2YWlsX2luPjAmJmk9PT1mZSYmci5zdGF0ZS53cmFwPjAmJjAhPT1lW3IubmV4dF9pbl07KVkuaW5mbGF0ZVJlc2V0KHIpLGk9WS5pbmZsYXRlKHIsbik7c3dpdGNoKGkpe2Nhc2UgaGU6Y2FzZSBjZTpjYXNlIGRlOmNhc2UgdWU6cmV0dXJuIHRoaXMub25FbmQoaSksdGhpcy5lbmRlZD0hMCwhMX1pZihhPXIuYXZhaWxfb3V0LHIubmV4dF9vdXQmJigwPT09ci5hdmFpbF9vdXR8fGk9PT1mZSkpaWYoInN0cmluZyI9PT10aGlzLm9wdGlvbnMudG8pe3ZhciBsPXRlKHIub3V0cHV0LHIubmV4dF9vdXQpLGY9ci5uZXh0X291dC1sLGQ9ZWUoci5vdXRwdXQsbCk7ci5uZXh0X291dD1mLHIuYXZhaWxfb3V0PW8tZixmJiZyLm91dHB1dC5zZXQoci5vdXRwdXQuc3ViYXJyYXkobCxsK2YpLDApLHRoaXMub25EYXRhKGQpfWVsc2UgdGhpcy5vbkRhdGEoci5vdXRwdXQubGVuZ3RoPT09ci5uZXh0X291dD9yLm91dHB1dDpyLm91dHB1dC5zdWJhcnJheSgwLHIubmV4dF9vdXQpKTtpZihpIT09bGV8fDAhPT1hKXtpZihpPT09ZmUpcmV0dXJuIGk9WS5pbmZsYXRlRW5kKHRoaXMuc3RybSksdGhpcy5vbkVuZChpKSx0aGlzLmVuZGVkPSEwLCEwO2lmKDA9PT1yLmF2YWlsX2luKWJyZWFrfX1yZXR1cm4hMH0sd2UucHJvdG90eXBlLm9uRGF0YT1mdW5jdGlvbihlKXt0aGlzLmNodW5rcy5wdXNoKGUpfSx3ZS5wcm90b3R5cGUub25FbmQ9ZnVuY3Rpb24oZSl7ZT09PWxlJiYoInN0cmluZyI9PT10aGlzLm9wdGlvbnMudG8/dGhpcy5yZXN1bHQ9dGhpcy5jaHVua3Muam9pbigiIik6dGhpcy5yZXN1bHQ9cSh0aGlzLmNodW5rcykpLHRoaXMuY2h1bmtzPVtdLHRoaXMuZXJyPWUsdGhpcy5tc2c9dGhpcy5zdHJtLm1zZ307dmFyIG1lPXdlLGtlPWJlLF9lPWZ1bmN0aW9uKGUsdCl7cmV0dXJuKHQ9dHx8e30pLnJhdz0hMCxiZShlLHQpfSx2ZT1iZSxnZT1jLHBlPXtJbmZsYXRlOm1lLGluZmxhdGU6a2UsaW5mbGF0ZVJhdzpfZSx1bmd6aXA6dmUsY29uc3RhbnRzOmdlfTtlLkluZmxhdGU9bWUsZS5jb25zdGFudHM9Z2UsZS5kZWZhdWx0PXBlLGUuaW5mbGF0ZT1rZSxlLmluZmxhdGVSYXc9X2UsZS51bmd6aXA9dmUsT2JqZWN0LmRlZmluZVByb3BlcnR5KGUsIl9fZXNNb2R1bGUiLHt2YWx1ZTohMH0pfSkpOwphZGRFdmVudExpc3RlbmVyKCJtZXNzYWdlIiwgZnVuY3Rpb24obykgeyB0cnkgeyBwb3N0TWVzc2FnZSh7IHN0YXR1czogInN1Y2Nlc3MiLCBkYXRhOiBwYWtvLmluZmxhdGUoby5kYXRhLCB7IHRvOiAiYXJyYXlidWZmZXIiIH0pIH0pOyB9IGNhdGNoKGV4KSB7IGxvZ2dlci5lcnJvcihleCk7IHBvc3RNZXNzYWdlKHsgc3RhdHVzOiAiZXJyb3IiIH0pOyB9IH0pOwpwb3N0TWVzc2FnZSh7IHN0YXR1czogInJlYWR5IiB9KTs=";
+			if(soSupported) {
+				theWorkerObj = new Worker(URL.createObjectURL(new Blob([base64js.toByteArray(workerSrc).buffer], { type: "text/javascript" })));
+			}else {
+				theWorkerObj = new Worker("data:text/javascript;base64," + workerSrc);
+			}
+			theWorkerObj.addEventListener("message", function(evt) {
+				if(evt.data.status === "ready") {
+					decodeBase64URL(window.eaglercraftXClientBundle, function(cbData) {
+						if(cbData) {
+							theWorkerObj.postMessage(cbData);
+						}else {
+							alert("Failed to decode eaglercraftXClientBundle base64!");
+						}
+					});
+				}else if(evt.data.status === "success") {
+					if(soSupported) {
+						window.clientScriptSrcURL = URL.createObjectURL(new Blob([evt.data.data.buffer], { type: "text/javascript;charset=utf-8" }));
+					}else {
+						window.clientScriptSrcURL = "data:text/javascript;charset=utf-8;base64," + base64js.fromByteArray(evt.data.data);
+					}
+				}else {
+					alert("Failed to decompress classes.js via legacy javascript implementation!");
+				}
+			});
+			theWorkerObj.addEventListener("error", function(evt) {
+				console.error(evt.error);
+			});
+		});
+	}else {
+		var ds = new window.DecompressionStream("gzip");
+		var result = [];
+		var fetchStream = function(reader) {
+			var processData;
+			reader.read().then(processData = function(evt) {
+				if (evt.done) {
+					(function(blobObj){
+						checkSameOriginSupport(function(supported) {
+							if(supported) {
+								window.clientScriptSrcURL = URL.createObjectURL(blobObj);
+							}else {
+								blobToArrayBuffer(blobObj, function(arr) {
+									console.log(arr);
+									window.clientScriptSrcURL = "data:text/javascript;charset=utf-8;base64," + base64js.fromByteArray(new Uint8Array(arr));
+								});
+							}
+						});
+					})(new Blob(result, { type: "text/javascript;charset=utf-8" }));
+					result = [];
+					ds = null;
+					return;
+				}
+				result.push(evt.value);
+				return reader.read().then(processData);
+			});
+		};
+		decodeBase64URL(window.eaglercraftXClientBundle, function(cbData) {
+			if(cbData) {
+				fetchStream((new Blob([cbData])).stream().pipeThrough(ds).getReader());
+			}else {
+				alert("Failed to decode eaglercraftXClientBundle base64!");
 			}
-			result.push(value);
-			return reader.read().then(processData);
 		});
 	}
-	fetchB64PayloadSafe().then((blob) => fetchStream(blob.stream().pipeThrough(ds).getReader()));
 })();
 </script>
 <script type="text/javascript">
@@ -89,13 +208,15 @@ window.eaglercraftXOptsHints = {
 	var launchCounter = 1;
 	var launchCountdownNumberElement = null;
 	var launchCountdownProgressElement = null;
-	function launchTick() {
-		if(launchCounter > 100) {
+	var launchSkipCountdown = false;
+	var launchTick = function() {
+		if(launchCounter > 100 || launchSkipCountdown) {
 			if(window.clientScriptSrcURL) {
 				clearInterval(launchInterval);
-				setTimeout(() => {
-					document.getElementById("launch_countdown_screen").remove();
-					const script = document.createElement("script");
+				setTimeout(function() {
+					document.body.removeChild(document.getElementById("launch_countdown_screen"));
+					document.body.style.backgroundColor = "black";
+					var script = document.createElement("script");
 					script.type = "text/javascript";
 					script.src = window.clientScriptSrcURL;
 					window.clientScriptSrcURL = null;
@@ -104,25 +225,40 @@ window.eaglercraftXOptsHints = {
 			}
 			return;
 		}
-		launchCountdownNumberElement.innerText = "" + Math.floor(6.0 - launchCounter * 0.06);
+		if(launchCounter === 100) {
+			document.getElementById("gameWillLaunchIn").innerText = "Decompressing...";
+		}else {
+			launchCountdownNumberElement.innerText = "" + Math.floor(6.0 - launchCounter * 0.06);
+		}
 		launchCountdownProgressElement.style.width = "" + launchCounter + "%";
 		++launchCounter;
-	}
-	window.addEventListener("load", () => {
+	};
+	window.addEventListener("load", function() {
 		launchCountdownNumberElement = document.getElementById("launchCountdownNumber");
 		launchCountdownProgressElement = document.getElementById("launchCountdownProgress");
 		launchInterval = setInterval(launchTick, 50);
+		document.getElementById("skipCountdown").addEventListener("click", function() {
+			launchSkipCountdown = true;
+			document.getElementById("gameWillLaunchIn").innerText = "Decompressing...";
+		});
+		document.getElementById("bootMenu").addEventListener("click", function() {
+			launchSkipCountdown = true;
+			document.getElementById("gameWillLaunchIn").innerText = "Decompressing...";
+			window.eaglercraftXOptsHints.showBootMenuOnLaunch = true;
+		});
 	});
 })();
 </script>
 <link type="image/png" rel="shortcut icon" href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAIAAAD8GO2jAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAAFiUAABYlAUlSJPAAAAR/SURBVEhLtZXZK3ZRFMYPcqXc+gv413DHxVuGIpIhkciQWaRccCNjSCkligwXSOZ5nmfv9zvn2e8+58V753sudmuvvdZ61l5r7XOc8H+GS/D19aUNkPz5+aktQH5/f//4+LBKZKuRkpUtQjCUYG5gD2T38vLy/PwsDfL9/f3Dw8PT05M0b29vnKLhCKCBT4L4gvBLBIei4//4+Hh1dUVEQutUuLu7E83FxQUGnKLBWKfQaA3S+AREVxaEOD8/Pzk50XpzcyMDcH19zdZG3N3d3dzc3Nvb01aX5pQUpQGGQJxcQpfNysoKhUIdHR1o1tbWbInYAgxIPDMzMy8vLzc3FxqOdMoRqwJK8G8ALUYIhHMiSEhIwI6CyIb0qQzC4eGhsXCc1tZWnZIEKzdQJQSXgKxfX18RCM3Z5eWlcfVAxKOjo+Pj49PTU88lTOk2NjbMsePc3t6SAfcgFdszOyMuAdeBg0CQi2lhYUHOeOLDCisN8FzcPFZXV3t7ezHY3t5GQ+6it+2xMASsKhEEWKsmRLRBBUpPvpJ/TpFKFBwKYAiITmicsbYhdHfJAltqhUCVsCQhwslmeXmZxiBQT9c0Ar9E2O3v72sYSE0N1yQArkKy0kBMXLqlZqIZHR3t6empqqqSDcBdhXEJSJ/bUc3q6uq+vj629GB9fR1WsLW1NTs7u7S0RN2locMjIyOEm5ubQ7+4uJienk4/+vv77Y1hwhLBEKhwWHitdVFfX9/Y2Gg2HuLi4owUAysrK8yCG97rh0+ApP5Q2ZycHFlPTExUVFRIBvn5+WhKSkp2dnaMKhptbW2426GgQ/rwuAQCZ1hwFayLiork9hMFBQV1dXVmE0BLS4vqw3QFB8kn4IAxoGPkYpxi4FeDmpqas7Mz4pClAgqGwD48rjY2NmacYqC0tJQ1KSlJWyE5OZkpUKkBAxZVIntAoZh04+Q48fHxPNGBgYHExMT29naj9cBodnZ2mo3jlJWVMeW2OGQck4B1amqqoaGhqamJjx2lGxwcpL0mUgR8fJhsWqJtSkoKU2SbHHUDpkhPBujd8xuQG6PJRM/Pz09PT7O1NNnZ2Tw3fgZkXVhYKCUlUhBATP+hCVyKZGky17RV0g04laayslJ6hlVeFHB4eFhKaogGd0LxtmTgE+hbhKDnPjMzgw8E3qGL2tpaBWpubjYqj2BoaEj6rq4uNATRZ0ZwCbiL6gXEzINk5vCBQJ9rMD4+rkA8QNK036uDg4Py8vLu7m680KjIBNR3zBDoWQM1g98snyB+VSoRW8C/UwR81/SvhgNj9JOTkwwVERUdRBEI0BAdLRVERkhLS8vIyEDQlrsTPTU1lVFhKxARvZgUlFLbegCf4BvIsbi4mIg4E5EogIHhiKCMtU0WUFiVy06j5fAJIDdSBDQw+PegDfBRcbOPwH4F9LuFWIIQdQNKwWqzIE0aoFUaBsw+SQuFw0uNtC9A+F4i3QNrbg3IDn+SAsHh+wYiEpeyBEMLv/cAO6KzAijxxB+Y4wisBhssJUhjEbPJf4Nw+B+JXqLW3bw+wQAAAABJRU5ErkJggg==" />
 </head>
-<body style="margin:0px;width:100vw;height:100vh;overflow:hidden;" id="game_frame">
+<body style="margin:0px;width:100%;height:100%;overflow:hidden;background-color:white;" id="game_frame">
 <div style="margin:0px;width:100%;height:100%;font-family:sans-serif;display:flex;align-items:center;user-select:none;" id="launch_countdown_screen">
 <div style="margin:auto;text-align:center;">
 <h1>This file is from <span style="color:#AA0000;">${date}</span></h1>
-<h2>Game will launch in <span id="launchCountdownNumber">5</span>...</h2>
-<div style="border:2px solid black;width:100%;height:15px;padding:1px;margin-bottom:20vh;"><div id="launchCountdownProgress" style="background-color:#555555;width:0%;height:100%;"></div></div>
+<h3>Get the latest version at <a href="https://eaglercraft.com"><span style="color:#AA0000;">eaglercraft.com</span></a></h1>
+<h2 id="gameWillLaunchIn">Game will launch in <span id="launchCountdownNumber">5</span>...</h2>
+<div style="border:2px solid black;width:100%;height:15px;padding:1px;margin-bottom:20vh;"><div id="launchCountdownProgress" style="background-color:#555555;width:0%;height:100%;"></div>
+<p style="margin-top:30px;"><button id="skipCountdown" autofocus>Skip Countdown</button>&emsp;<button id="bootMenu">Enter Boot Menu</button></p></div>
 </div>
 </div>
 </body>
diff --git a/sources/setup/workspace_template/javascript/UpdateDownloadSources.txt b/sources/setup/workspace_template/javascript/UpdateDownloadSources.txt
index b6279e65..d4d13cca 100644
--- a/sources/setup/workspace_template/javascript/UpdateDownloadSources.txt
+++ b/sources/setup/workspace_template/javascript/UpdateDownloadSources.txt
@@ -6,3 +6,22 @@
 # url: url here
 # ipfs: cid here
 # list: url to another list
+
+list: https://eaglercraft.com/dl/cors/u35_backup.list
+url: https://eaglercraft.com/dl/cors/u35_backup.dat
+
+ipfs: bafybeibolco2rlnyiiweipoarwf6kw235xdv7jbbpcwpmm5wksnh4agx5e
+
+use-gateway: https://gateway.ipfs.io/ipfs/$cid$/$path$
+use-gateway: https://4everland.io/ipfs/$cid$/$path$
+use-gateway: https://dweb.link/ipfs/$cid$/$path$
+use-gateway: https://cloudflare-ipfs.com/ipfs/$cid$/$path$
+use-gateway: https://cf-ipfs.com/ipfs/$cid$/$path$
+use-gateway: https://w3s.link/ipfs/$cid$/$path$
+use-gateway: https://ipfs.eth.aragon.network/ipfs/$cid$/$path$
+use-gateway: https://nftstorage.link/ipfs/$cid$/$path$
+
+use-gateway: https://$cid$.ipfs.gateway.ipfs.io/$path$
+use-gateway: https://$cid$.ipfs.dweb.link/$path$
+use-gateway: https://$cid$.ipfs.cf-ipfs.com/$path$
+use-gateway: https://$cid$.ipfs.nftstorage.link/$path$
diff --git a/sources/setup/workspace_template/javascript/index.html b/sources/setup/workspace_template/javascript/index.html
index 3cade035..4da251a0 100644
--- a/sources/setup/workspace_template/javascript/index.html
+++ b/sources/setup/workspace_template/javascript/index.html
@@ -1,8 +1,8 @@
 <!DOCTYPE html>
-<html>
+<html style="width:100%;height:100%;background-color:black;">
 	<head>
 		<meta charset="UTF-8" />
-		<meta name="viewport" content="width=device-width, initial-scale=1.0" />
+		<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0" />
 		<meta name="description" content="EaglercraftX 1.8 test directory HTML page" />
 		<meta name="keywords" content="eaglercraft, eaglercraftx, minecraft, 1.8, 1.8.8" />
 		<title>EaglercraftX 1.8</title>
@@ -14,11 +14,11 @@
 		<script type="text/javascript" src="classes.js"></script>
 		<script type="text/javascript">
 			"use strict";
-			window.addEventListener("load", () => {
-				if(document.location.href.startsWith("file:")) {
+			window.addEventListener("load", function() {
+				if(window.location.href.indexOf("file:") === 0) {
 					alert("HTTP please, do not open this file locally, run a local HTTP server and load it via HTTP");
 				}else {
-					const relayId = Math.floor(Math.random() * 3);
+					var relayId = Math.floor(Math.random() * 3);
 					window.eaglercraftXOpts = {
 						demoMode: false,
 						container: "game_frame",
@@ -31,24 +31,24 @@
 							{ addr: "ws://localhost:8081/", name: "Local test server" }
 						],
 						relays: [
-							{ addr: "wss://relay.deev.is/", comment: "lax1dude relay #1", primary: relayId == 0 },
-							{ addr: "wss://relay.lax1dude.net/", comment: "lax1dude relay #2", primary: relayId == 1 },
-							{ addr: "wss://relay.shhnowisnottheti.me/", comment: "ayunami relay #1", primary: relayId == 2 }
+							{ addr: "wss://relay.deev.is/", comment: "lax1dude relay #1", primary: relayId === 0 },
+							{ addr: "wss://relay.lax1dude.net/", comment: "lax1dude relay #2", primary: relayId === 1 },
+							{ addr: "wss://relay.shhnowisnottheti.me/", comment: "ayunami relay #1", primary: relayId === 2 }
 						]
 					};
-					
+
 					var q = window.location.search;
-					if(typeof q === "string" && q.startsWith("?")) {
-						q = new URLSearchParams(q);
+					if((typeof q === "string") && q[0] === "?" && (typeof window.URLSearchParams !== "undefined")) {
+						q = new window.URLSearchParams(q);
 						var s = q.get("server");
 						if(s) window.eaglercraftXOpts.joinServer = s;
 					}
-					
+
 					main();
 				}
 			});
 		</script>
 	</head>
-	<body style="margin:0px;width:100vw;height:100vh;overflow:hidden;" id="game_frame">
+	<body style="margin:0px;width:100%;height:100%;overflow:hidden;background-color:black;" id="game_frame">
 	</body>
 </html>
\ No newline at end of file
diff --git a/sources/teavm-boot-menu/java/net/lax1dude/eaglercraft/v1_8/boot_menu/teavm/BootMenuAssets.java b/sources/teavm-boot-menu/java/net/lax1dude/eaglercraft/v1_8/boot_menu/teavm/BootMenuAssets.java
new file mode 100644
index 00000000..4255a205
--- /dev/null
+++ b/sources/teavm-boot-menu/java/net/lax1dude/eaglercraft/v1_8/boot_menu/teavm/BootMenuAssets.java
@@ -0,0 +1,35 @@
+package net.lax1dude.eaglercraft.v1_8.boot_menu.teavm;
+
+import net.lax1dude.eaglercraft.v1_8.EagRuntime;
+import net.lax1dude.eaglercraft.v1_8.internal.PlatformAssets;
+
+/**
+ * Copyright (c) 2024 lax1dude. All Rights Reserved.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ * 
+ */
+public class BootMenuAssets {
+
+	public static String loadResourceString(String res) {
+		return EagRuntime.getResourceString(res);
+	}
+
+	public static byte[] loadResourceBytes(String res) {
+		return EagRuntime.getResourceBytes(res);
+	}
+
+	public static void freeBootMenuResourceRepo() {
+		PlatformAssets.freeAssetRepoTeaVM();
+	}
+
+}
diff --git a/sources/teavm-boot-menu/java/net/lax1dude/eaglercraft/v1_8/boot_menu/teavm/BootMenuConstants.java b/sources/teavm-boot-menu/java/net/lax1dude/eaglercraft/v1_8/boot_menu/teavm/BootMenuConstants.java
new file mode 100644
index 00000000..43948026
--- /dev/null
+++ b/sources/teavm-boot-menu/java/net/lax1dude/eaglercraft/v1_8/boot_menu/teavm/BootMenuConstants.java
@@ -0,0 +1,53 @@
+package net.lax1dude.eaglercraft.v1_8.boot_menu.teavm;
+
+import net.lax1dude.eaglercraft.v1_8.EagRuntime;
+import net.lax1dude.eaglercraft.v1_8.EaglercraftUUID;
+import net.lax1dude.eaglercraft.v1_8.EaglercraftVersion;
+
+/**
+ * Copyright (c) 2024 lax1dude. All Rights Reserved.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ * 
+ */
+public class BootMenuConstants {
+
+	public static final EaglercraftUUID UUID_ORIGIN_UNSIGNED_CLASSES_JS = new EaglercraftUUID(0x738248F88FF1446EL, 0xA834D40120DD8EB5L);
+	public static final EaglercraftUUID UUID_ORIGIN_SIGNED_SIGNATURE = new EaglercraftUUID(0xB55252A38A6F4291L, 0x8DB68BF94B3E6FEDL);
+	public static final EaglercraftUUID UUID_ORIGIN_SIGNED_BUNDLE = new EaglercraftUUID(0xCE298D98E9084597L, 0x9EB2501EAC6D720BL);
+
+	public static final EaglercraftUUID UUID_CLIENT_DATA_ORIGIN = new EaglercraftUUID(0xB673DAD0EF4407BL, 0xBE12C8E5BD5A2CBDL);
+	public static final EaglercraftUUID UUID_CLIENT_LAUNCH_ORIGIN = new EaglercraftUUID(0x74FB063984A24D1AL, 0x8E1D2FC39C21EA1EL);
+
+	public static final String client_projectForkName = EaglercraftVersion.projectForkName;
+	public static final String client_projectForkVendor = EaglercraftVersion.projectForkVendor;
+	public static final String client_projectForkVersion = EaglercraftVersion.projectForkVersion;
+
+	public static final String client_projectOriginName = EaglercraftVersion.projectOriginName;
+	public static final String client_projectOriginAuthor = EaglercraftVersion.projectOriginAuthor;
+	public static final String client_projectOriginVersion = EaglercraftVersion.projectOriginVersion;
+	public static final String client_projectOriginRevision = EaglercraftVersion.projectOriginRevision;
+
+	public static final String cssClassPrefix = "_eaglercraftX_";
+	public static final String cssClassPrefixBootMenu = cssClassPrefix + "boot_menu_";
+
+	public static final String bootMenuDatabaseName = "_net_lax1dude_eaglercraft_v1_8_boot_menu_BootMenuDatastore_1_8_8_main";
+
+	public static String getBootMenuFlagsKeyName() {
+		String pfx = EagRuntime.getConfiguration().getLocalStorageNamespace();
+		if(pfx == null) {
+			pfx = EaglercraftVersion.localStorageNamespace;
+		}
+		return pfx + ".showBootMenu";
+	}
+
+}
diff --git a/sources/teavm-boot-menu/java/net/lax1dude/eaglercraft/v1_8/boot_menu/teavm/BootMenuDOM.java b/sources/teavm-boot-menu/java/net/lax1dude/eaglercraft/v1_8/boot_menu/teavm/BootMenuDOM.java
new file mode 100644
index 00000000..e4452747
--- /dev/null
+++ b/sources/teavm-boot-menu/java/net/lax1dude/eaglercraft/v1_8/boot_menu/teavm/BootMenuDOM.java
@@ -0,0 +1,203 @@
+package net.lax1dude.eaglercraft.v1_8.boot_menu.teavm;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.teavm.jso.dom.html.HTMLElement;
+import org.teavm.jso.dom.html.HTMLInputElement;
+
+/**
+ * Copyright (c) 2024 lax1dude. All Rights Reserved.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ * 
+ */
+public class BootMenuDOM {
+
+	public final HTMLElement content_view_selection;
+	public final HTMLElement content_selection;
+	public final HTMLElement content_view_editor;
+	public final HTMLElement header_title;
+	public final HTMLElement launch_conf_val_profile_name;
+	public final HTMLElement launch_conf_val_data_format;
+	public final HTMLElement launch_conf_val_launch_type;
+	public final Map<EnumClientLaunchType,HTMLElement> launch_conf_val_launch_type_opts;
+	public final HTMLElement launch_conf_join_server;
+	public final HTMLElement launch_conf_val_join_server;
+	public final HTMLElement launch_conf_opts_name;
+	public final HTMLElement launch_conf_val_opts_name;
+	public final HTMLElement launch_conf_assetsURI;
+	public final HTMLElement launch_conf_val_assetsURI;
+	public final HTMLElement launch_conf_container;
+	public final HTMLElement launch_conf_val_container;
+	public final HTMLElement launch_conf_main_func;
+	public final HTMLElement launch_conf_val_main_func;
+	public final HTMLElement launch_conf_clear_cookies;
+	public final HTMLElement launch_conf_val_clear_cookies;
+	public final HTMLElement launch_opt_editor;
+	public final HTMLElement popup;
+	public final HTMLElement popup_view_confirm;
+	public final HTMLElement popup_confirm_title;
+	public final HTMLElement popup_confirm_opts;
+	public final HTMLElement popup_view_selection;
+	public final HTMLElement popup_selection_title;
+	public final HTMLElement popup_selection;
+	public final HTMLElement popup_view_input;
+	public final HTMLElement popup_input_title;
+	public final HTMLElement popup_input_val;
+	public final HTMLElement popup_input_opt_cancel;
+	public final HTMLElement popup_input_opt_done;
+	public final HTMLElement footer_text_boot_select;
+	public final HTMLElement footer_text_boot_select_count;
+	public final HTMLElement footer_text_boot_countdown;
+	public final HTMLElement footer_text_menu_select;
+	public final HTMLElement footer_text_opts_editor;
+	public final HTMLElement footer_text_opts_editor_alt;
+	public final HTMLElement footer_text_boot_order;
+
+	public BootMenuDOM(HTMLElement parentElement) {
+		content_view_selection = selectHelper(parentElement, "content_view_selection");
+		content_selection = selectHelper(parentElement, "content_selection");
+		content_view_editor = selectHelper(parentElement, "content_view_editor");
+		header_title = selectHelper(parentElement, "header_title");
+		launch_conf_val_profile_name = selectHelper(parentElement, "launch_conf_val_profile_name");
+		launch_conf_val_data_format = selectHelper(parentElement, "launch_conf_val_data_format");
+		launch_conf_val_launch_type = selectHelper(parentElement, "launch_conf_val_launch_type");
+		launch_conf_val_launch_type_opts = new HashMap<>();
+		launch_conf_val_launch_type_opts.put(EnumClientLaunchType.EAGLERX_V1, selectHelper(parentElement, "launch_conf_val_launch_type_opt[value=EAGLERX_V1]"));
+		launch_conf_val_launch_type_opts.put(EnumClientLaunchType.EAGLERX_SIGNED_V1, selectHelper(parentElement, "launch_conf_val_launch_type_opt[value=EAGLERX_SIGNED_V1]"));
+		launch_conf_val_launch_type_opts.put(EnumClientLaunchType.EAGLER_1_5_V2, selectHelper(parentElement, "launch_conf_val_launch_type_opt[value=EAGLER_1_5_V2]"));
+		launch_conf_val_launch_type_opts.put(EnumClientLaunchType.EAGLER_1_5_V1, selectHelper(parentElement, "launch_conf_val_launch_type_opt[value=EAGLER_1_5_V1]"));
+		launch_conf_val_launch_type_opts.put(EnumClientLaunchType.EAGLER_BETA_V1, selectHelper(parentElement, "launch_conf_val_launch_type_opt[value=EAGLER_BETA_V1]"));
+		launch_conf_val_launch_type_opts.put(EnumClientLaunchType.PEYTON_V1, selectHelper(parentElement, "launch_conf_val_launch_type_opt[value=PEYTON_V1]"));
+		launch_conf_val_launch_type_opts.put(EnumClientLaunchType.PEYTON_V2, selectHelper(parentElement, "launch_conf_val_launch_type_opt[value=PEYTON_V2]"));
+		launch_conf_val_launch_type_opts.put(EnumClientLaunchType.STANDARD_OFFLINE_V1, selectHelper(parentElement, "launch_conf_val_launch_type_opt[value=STANDARD_OFFLINE_V1]"));
+		launch_conf_join_server = selectHelper(parentElement, "launch_conf_join_server");
+		launch_conf_val_join_server = selectHelper(parentElement, "launch_conf_val_join_server");
+		launch_conf_opts_name = selectHelper(parentElement, "launch_conf_opts_name");
+		launch_conf_val_opts_name = selectHelper(parentElement, "launch_conf_val_opts_name");
+		launch_conf_assetsURI = selectHelper(parentElement, "launch_conf_assetsURI");
+		launch_conf_val_assetsURI = selectHelper(parentElement, "launch_conf_val_assetsURI");
+		launch_conf_container = selectHelper(parentElement, "launch_conf_container");
+		launch_conf_val_container = selectHelper(parentElement, "launch_conf_val_container");
+		launch_conf_main_func = selectHelper(parentElement, "launch_conf_main_func");
+		launch_conf_val_main_func = selectHelper(parentElement, "launch_conf_val_main_func");
+		launch_conf_clear_cookies = selectHelper(parentElement, "launch_conf_clear_cookies");
+		launch_conf_val_clear_cookies = selectHelper(parentElement, "launch_conf_val_clear_cookies");
+		launch_opt_editor = selectHelper(parentElement, "launch_opt_editor");
+		popup = selectHelper(parentElement, "popup");
+		popup_view_confirm = selectHelper(parentElement, "popup_view_confirm");
+		popup_confirm_title = selectHelper(parentElement, "popup_confirm_title");
+		popup_confirm_opts = selectHelper(parentElement, "popup_confirm_opts");
+		popup_view_selection = selectHelper(parentElement, "popup_view_selection");
+		popup_selection_title = selectHelper(parentElement, "popup_selection_title");
+		popup_selection = selectHelper(parentElement, "popup_selection");
+		popup_view_input = selectHelper(parentElement, "popup_view_input");
+		popup_input_title = selectHelper(parentElement, "popup_input_title");
+		popup_input_val = selectHelper(parentElement, "popup_input_val");
+		popup_input_opt_cancel = selectHelper(parentElement, "popup_input_opt_cancel");
+		popup_input_opt_done = selectHelper(parentElement, "popup_input_opt_done");
+		footer_text_boot_select = selectHelper(parentElement, "footer_text_boot_select");
+		footer_text_boot_select_count = selectHelper(parentElement, "footer_text_boot_select_count");
+		footer_text_boot_countdown = selectHelper(parentElement, "footer_text_boot_countdown");
+		footer_text_menu_select = selectHelper(parentElement, "footer_text_menu_select");
+		footer_text_opts_editor = selectHelper(parentElement, "footer_text_opts_editor");
+		footer_text_opts_editor_alt = selectHelper(parentElement, "footer_text_opts_editor_alt");
+		footer_text_boot_order = selectHelper(parentElement, "footer_text_boot_order");
+	}
+
+	public void registerEventHandlers() {
+		launch_conf_val_profile_name.addEventListener("change", (evt) -> {
+			BootMenuMain.fireChangeEvent(launch_conf_val_profile_name);
+		});
+		launch_conf_val_data_format.addEventListener("change", (evt) -> {
+			BootMenuMain.fireChangeEvent(launch_conf_val_data_format);
+		});
+		launch_conf_val_launch_type.addEventListener("change", (evt) -> {
+			BootMenuMain.fireChangeEvent(launch_conf_val_launch_type);
+		});
+		launch_conf_val_join_server.addEventListener("change", (evt) -> {
+			BootMenuMain.fireChangeEvent(launch_conf_val_join_server);
+		});
+		launch_conf_val_opts_name.addEventListener("change", (evt) -> {
+			BootMenuMain.fireChangeEvent(launch_conf_val_opts_name);
+		});
+		launch_conf_val_assetsURI.addEventListener("change", (evt) -> {
+			BootMenuMain.fireChangeEvent(launch_conf_val_assetsURI);
+		});
+		launch_conf_val_container.addEventListener("change", (evt) -> {
+			BootMenuMain.fireChangeEvent(launch_conf_val_container);
+		});
+		launch_conf_val_main_func.addEventListener("change", (evt) -> {
+			BootMenuMain.fireChangeEvent(launch_conf_val_main_func);
+		});
+		launch_conf_val_clear_cookies.addEventListener("change", (evt) -> {
+			BootMenuMain.fireChangeEvent(launch_conf_val_clear_cookies);
+		});
+		launch_opt_editor.addEventListener("change", (evt) -> {
+			BootMenuMain.fireChangeEvent(launch_opt_editor);
+		});
+		popup_input_val.addEventListener("change", (evt) -> {
+			BootMenuMain.fireChangeEvent(popup_input_val);
+		});
+		popup_input_opt_cancel.addEventListener("click", (evt) -> {
+			BootMenuMain.fireClickEvent(popup_input_opt_cancel);
+		});
+		popup_input_opt_done.addEventListener("click", (evt) -> {
+			BootMenuMain.fireClickEvent(popup_input_opt_done);
+		});
+		popup_input_opt_cancel.addEventListener("mouseover", (evt) -> {
+			BootMenuMain.fireMouseOverEvent(popup_input_opt_cancel);
+		});
+		popup_input_opt_done.addEventListener("mouseover", (evt) -> {
+			BootMenuMain.fireMouseOverEvent(popup_input_opt_done);
+		});
+	}
+
+	public static void show(HTMLElement el) {
+		el.getStyle().setProperty("display", "block");
+	}
+
+	public static void hide(HTMLElement el) {
+		el.getStyle().setProperty("display", "none");
+	}
+
+	public static void setValue(HTMLElement el, String value) {
+		((HTMLInputElement)el).setValue(value);
+	}
+
+	public static String getValue(HTMLElement el) {
+		return ((HTMLInputElement)el).getValue();
+	}
+
+	public static void setChecked(HTMLElement el, boolean checked) {
+		((HTMLInputElement)el).setChecked(checked);
+	}
+
+	public static boolean getChecked(HTMLElement el) {
+		return ((HTMLInputElement)el).isChecked();
+	}
+
+	public static void setDisabled(HTMLElement el, boolean disabled) {
+		((HTMLInputElement)el).setDisabled(disabled);
+	}
+
+	private static HTMLElement selectHelper(HTMLElement parent, String name) {
+		name = "." + BootMenuConstants.cssClassPrefixBootMenu + name;
+		HTMLElement ret = parent.querySelector(name);
+		if(ret == null) {
+			throw new RuntimeException("Failed to select \"" + name + "\" from boot menu!");
+		}
+		return ret;
+	}
+
+}
diff --git a/sources/teavm-boot-menu/java/net/lax1dude/eaglercraft/v1_8/boot_menu/teavm/BootMenuDataManager.java b/sources/teavm-boot-menu/java/net/lax1dude/eaglercraft/v1_8/boot_menu/teavm/BootMenuDataManager.java
new file mode 100644
index 00000000..b1d9ab53
--- /dev/null
+++ b/sources/teavm-boot-menu/java/net/lax1dude/eaglercraft/v1_8/boot_menu/teavm/BootMenuDataManager.java
@@ -0,0 +1,464 @@
+package net.lax1dude.eaglercraft.v1_8.boot_menu.teavm;
+
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+
+import org.json.JSONArray;
+import org.json.JSONException;
+import org.json.JSONObject;
+import org.teavm.jso.browser.Storage;
+import org.teavm.jso.browser.Window;
+
+import net.lax1dude.eaglercraft.v1_8.EaglercraftUUID;
+import net.lax1dude.eaglercraft.v1_8.log4j.LogManager;
+import net.lax1dude.eaglercraft.v1_8.log4j.Logger;
+
+/**
+ * Copyright (c) 2024 lax1dude. All Rights Reserved.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ * 
+ */
+public class BootMenuDataManager {
+
+	protected static final Logger logger = LogManager.getLogger("BootMenuDataManager");
+
+	protected BootMenuDatastore datastore;
+
+	public final Set<EaglercraftUUID> existingBlobs = new HashSet<>();
+	public final Map<EaglercraftUUID,ClientDataEntry> clientDatas = new HashMap<>();
+	public final Map<EaglercraftUUID,LaunchConfigEntry> launchDatas = new HashMap<>();
+	public final List<EaglercraftUUID> launchDatasList = new ArrayList<>();
+	public final List<EaglercraftUUID> launchOrderList = new ArrayList<>();
+
+	public int confBootTimeout = 0;
+	public String confMenuTitle = "EaglercraftX 1.8 Boot Manager";
+
+	public BootMenuDataManager(BootMenuDatastore datastore) {
+		this.datastore = datastore;
+		this.loadAllData();
+		this.loadAdditionalConf();
+	}
+
+	public void installNewClientData(LaunchConfigEntry launchConfig, ClientDataEntry clientData, Map<EaglercraftUUID,byte[]> clientBlobs, boolean rotateUUIDs) {
+		if(rotateUUIDs) {
+			EaglercraftUUID rotatedLaunchUUID = EaglercraftUUID.randomUUID();
+			EaglercraftUUID rotatedClientUUID = EaglercraftUUID.randomUUID();
+			launchConfig = launchConfig.rotateUUIDs(rotatedLaunchUUID, rotatedClientUUID);
+			clientData = clientData.rotateUUID(rotatedClientUUID);
+		}
+		if(launchDatas.containsKey(launchConfig.uuid) || BootMenuConstants.UUID_CLIENT_LAUNCH_ORIGIN.equals(launchConfig.uuid)) {
+			throw new IllegalArgumentException("Launch data UUID \"" + launchConfig.uuid + "\" already exists!");
+		}
+		if(clientDatas.containsKey(clientData.uuid) || BootMenuConstants.UUID_CLIENT_DATA_ORIGIN.equals(launchConfig.uuid)) {
+			throw new IllegalArgumentException("Client data UUID \"" + clientData.uuid + "\" already exists!");
+		}
+		if(!launchConfig.clientDataUUID.equals(clientData.uuid)) {
+			throw new IllegalArgumentException("Mismatched client data UUID and launch configuration!");
+		}
+		logger.info("Installing new client data \"{}\"...", clientData.uuid);
+		if(clientBlobs != null && !clientBlobs.isEmpty()) {
+			for(Entry<EaglercraftUUID,byte[]> etr : clientBlobs.entrySet()) {
+				EaglercraftUUID k = etr.getKey();
+				byte[] v = etr.getValue();
+				String name = "blobs/" + k;
+				if(!datastore.containsKey(name)) {
+					logger.info(" - Adding blob to datastore \"{}\" ({} bytes long)", name, v.length);
+					datastore.setItem(name, v);
+					existingBlobs.add(k);
+				}else {
+					logger.info(" - Skipping blob \"{}\" because it already exists", name);
+				}
+			}
+		}
+		String name = "clientDatas/" + clientData.uuid;
+		logger.info(" - Writing client data: \"{}\"", name);
+		JSONObject obj = new JSONObject();
+		clientData.writeJSON(obj);
+		datastore.setItem(name, obj.toString().getBytes(StandardCharsets.UTF_8));
+		clientDatas.put(clientData.uuid, clientData);
+		installNewLaunchConfig(launchConfig, false);
+	}
+
+	public void installNewLaunchConfig(LaunchConfigEntry launchConfig, ClientDataEntry clientData, Map<EaglercraftUUID,byte[]> clientBlobs, boolean rotateUUIDs) {
+		if(rotateUUIDs) {
+			EaglercraftUUID rotatedLaunchUUID = EaglercraftUUID.randomUUID();
+			launchConfig = launchConfig.rotateUUIDs(rotatedLaunchUUID, launchConfig.clientDataUUID);
+		}
+		if(BootMenuConstants.UUID_CLIENT_LAUNCH_ORIGIN.equals(launchConfig.uuid)) {
+			throw new IllegalArgumentException("The origin launch configuration cannot be overwritten!");
+		}
+		if(!clientDatas.containsKey(launchConfig.clientDataUUID) && !BootMenuConstants.UUID_CLIENT_DATA_ORIGIN.equals(launchConfig.clientDataUUID)) {
+			logger.info("Installing new client data \"{}\"...", clientData.uuid);
+			if(clientBlobs != null && !clientBlobs.isEmpty()) {
+				for(Entry<EaglercraftUUID,byte[]> etr : clientBlobs.entrySet()) {
+					EaglercraftUUID k = etr.getKey();
+					byte[] v = etr.getValue();
+					String name = "blobs/" + k;
+					if(!datastore.containsKey(name)) {
+						logger.info(" - Adding blob to datastore \"{}\" ({} bytes long)", name, v.length);
+						datastore.setItem(name, v);
+						existingBlobs.add(k);
+					}else {
+						logger.info(" - Skipping blob \"{}\" because it already exists", name);
+					}
+				}
+			}
+			String name = "clientDatas/" + clientData.uuid;
+			logger.info(" - Writing client data: \"{}\"", name);
+			JSONObject obj = new JSONObject();
+			clientData.writeJSON(obj);
+			datastore.setItem(name, obj.toString().getBytes(StandardCharsets.UTF_8));
+			clientDatas.put(clientData.uuid, clientData);
+		}
+		logger.info("Installing new launch config \"{}\"...", launchConfig.uuid);
+		String name = "launchDatas/" + launchConfig.uuid;
+		JSONObject obj = new JSONObject();
+		launchConfig.writeJSON(obj);
+		datastore.setItem(name, obj.toString().getBytes(StandardCharsets.UTF_8));
+		boolean writeManifest = false;
+		if(launchDatas.put(launchConfig.uuid, launchConfig) == null) {
+			launchDatasList.add(launchConfig.uuid);
+			writeManifest = true;
+		}
+		if(!launchOrderList.contains(launchConfig.uuid)) {
+			launchOrderList.add(launchConfig.uuid);
+			writeManifest = true;
+		}
+		if(writeManifest) {
+			writeManifest();
+		}
+	}
+
+	public void installNewLaunchConfig(LaunchConfigEntry launchConfig, boolean rotateUUIDs) {
+		if(rotateUUIDs) {
+			EaglercraftUUID rotatedLaunchUUID = EaglercraftUUID.randomUUID();
+			launchConfig = launchConfig.rotateUUIDs(rotatedLaunchUUID, launchConfig.clientDataUUID);
+		}
+		if(BootMenuConstants.UUID_CLIENT_LAUNCH_ORIGIN.equals(launchConfig.uuid)) {
+			throw new IllegalArgumentException("The origin launch configuration cannot be overwritten!");
+		}
+		if(!clientDatas.containsKey(launchConfig.clientDataUUID) && !BootMenuConstants.UUID_CLIENT_DATA_ORIGIN.equals(launchConfig.uuid)) {
+			throw new IllegalArgumentException("Client data UUID \"" + launchConfig.clientDataUUID + "\" does not exist!");
+		}
+		logger.info("Installing new launch config \"{}\"...", launchConfig.uuid);
+		String name = "launchDatas/" + launchConfig.uuid;
+		JSONObject obj = new JSONObject();
+		launchConfig.writeJSON(obj);
+		datastore.setItem(name, obj.toString().getBytes(StandardCharsets.UTF_8));
+		boolean writeManifest = false;
+		if(launchDatas.put(launchConfig.uuid, launchConfig) == null) {
+			launchDatasList.add(launchConfig.uuid);
+			writeManifest = true;
+		}
+		if(!launchOrderList.contains(launchConfig.uuid)) {
+			launchOrderList.add(launchConfig.uuid);
+			writeManifest = true;
+		}
+		if(writeManifest) {
+			writeManifest();
+		}
+	}
+
+	public void deleteLaunchConfig(EaglercraftUUID launchConfig) {
+		if(launchDatas.remove(launchConfig) != null) {
+			boolean removed = false;
+			while(launchDatasList.remove(launchConfig)) {
+				removed = true;
+			}
+			while(launchOrderList.remove(launchConfig)) {
+				removed = true;
+			}
+			String name = "launchDatas/" + launchConfig;
+			logger.info("Deleting launch config \"{}\" from datastore", name);
+			if(!datastore.deleteItem(name)) {
+				logger.warn("Failed to delete file! Removing it from the list anyway...");
+			}
+			if(removed) {
+				writeManifest();
+			}
+			garbageCollectClientDatas();
+		}
+	}
+
+	protected void loadAllData() {
+		logger.info("Loading custom boot configurations from datastore...");
+		existingBlobs.clear();
+		clientDatas.clear();
+		launchDatas.clear();
+		launchDatasList.clear();
+		launchOrderList.clear();
+		byte[] manifestBytes = datastore.getItem("manifest.json");
+		if(manifestBytes == null) {
+			return;
+		}
+		List<EaglercraftUUID> profilesToLoad;
+		try {
+			JSONArray arr = (new JSONObject(new String(manifestBytes, StandardCharsets.UTF_8))).getJSONArray("launchProfiles");
+			profilesToLoad = new ArrayList<>(arr.length());
+			for(int i = 0, l = arr.length(); i < l; ++i) {
+				profilesToLoad.add(EaglercraftUUID.fromString(arr.getString(i)));
+			}
+			arr = (new JSONObject(new String(manifestBytes, StandardCharsets.UTF_8))).getJSONArray("launchOrderList");
+			for(int i = 0, l = arr.length(); i < l; ++i) {
+				launchOrderList.add(EaglercraftUUID.fromString(arr.getString(i)));
+			}
+		}catch(JSONException | IllegalArgumentException exp) {
+			logger.error("Manifest is corrupt!");
+			logger.error(exp);
+			return;
+		}
+		for(EaglercraftUUID uuid : profilesToLoad) {
+			if(loadLaunchDataFromStore(uuid) != null) {
+				launchDatasList.add(uuid);
+			}
+		}
+		logger.info("Loading {} client(s) successfully", clientDatas.size());
+		logger.info("Loading {} profile(s) successfully", launchDatas.size());
+	}
+
+	protected LaunchConfigEntry loadLaunchDataFromStore(EaglercraftUUID uuid) {
+		LaunchConfigEntry ret = launchDatas.get(uuid);
+		if(ret != null) {
+			return ret;
+		}
+		String name = "launchDatas/" + uuid;
+		byte[] fileData = datastore.getItem(name);
+		if(fileData == null) {
+			logger.error("Could not locate launch data \"{}\"!", name);
+			return null;
+		}
+		try {
+			ret = new LaunchConfigEntry(uuid, new JSONObject(new String(fileData, StandardCharsets.UTF_8)));
+		}catch(JSONException | IllegalArgumentException exp) {
+			logger.error("Launch data \"{}\" is corrupt!", name);
+			logger.error(exp);
+			return null;
+		}
+		if(!BootMenuConstants.UUID_CLIENT_DATA_ORIGIN.equals(ret.clientDataUUID)) {
+			if(loadClientDataFromStore(ret.clientDataUUID) == null) {
+				logger.error("Client data \"{}\" for launch data \"{}\" is missing/corrupt!", ret.clientDataUUID, name);
+				return null;
+			}
+		}
+		launchDatas.put(uuid, ret);
+		return ret;
+	}
+
+	protected ClientDataEntry loadClientDataFromStore(EaglercraftUUID uuid) {
+		ClientDataEntry ret = clientDatas.get(uuid);
+		if(ret != null) {
+			return ret;
+		}
+		String name = "clientDatas/" + uuid;
+		byte[] fileData = datastore.getItem(name);
+		if(fileData == null) {
+			logger.error("Could not locate client data \"{}\"!", name);
+			return null;
+		}
+		try {
+			ret = new ClientDataEntry(uuid, new JSONObject(new String(fileData, StandardCharsets.UTF_8)));
+		}catch(JSONException | IllegalArgumentException exp) {
+			logger.error("Client data \"{}\" is corrupt!", name);
+			logger.error(exp);
+			return null;
+		}
+		existingBlobs.addAll(ret.getReferencedBlobs());
+		clientDatas.put(uuid, ret);
+		return ret;
+	}
+
+	public void writeManifest() {
+		JSONObject manifest = new JSONObject();
+		JSONArray launchProfileArray = new JSONArray();
+		for(EaglercraftUUID uuid : launchDatasList) {
+			launchProfileArray.put(uuid.toString());
+		}
+		manifest.put("launchProfiles", launchProfileArray);
+		JSONArray launchOrderListArray = new JSONArray();
+		for(EaglercraftUUID uuid : launchOrderList) {
+			launchOrderListArray.put(uuid.toString());
+		}
+		manifest.put("launchOrderList", launchOrderListArray);
+		datastore.setItem("manifest.json", manifest.toString().getBytes(StandardCharsets.UTF_8));
+	}
+
+	protected void garbageCollectClientDatas() {
+		Set<EaglercraftUUID> referencedClientData = new HashSet<>();
+		for(LaunchConfigEntry etr : launchDatas.values()) {
+			referencedClientData.add(etr.clientDataUUID);
+		}
+		Set<EaglercraftUUID> toDelete = new HashSet<>(clientDatas.keySet());
+		toDelete.removeAll(referencedClientData);
+		boolean garbageCollectBlobs = !toDelete.isEmpty();
+		if(garbageCollectBlobs) {
+			for(EaglercraftUUID del : toDelete) {
+				clientDatas.remove(del);
+				String name = "clientDatas/" + del;
+				logger.info("Deleting orphaned client \"{}\" from datastore", name);
+				datastore.deleteItem(name);
+			}
+			garbageCollectClientBlobs();
+		}
+	}
+
+	protected void garbageCollectClientBlobs() {
+		Set<EaglercraftUUID> referencedClientBlob = new HashSet<>();
+		for(ClientDataEntry etr : clientDatas.values()) {
+			referencedClientBlob.addAll(etr.getReferencedBlobs());
+		}
+		Set<EaglercraftUUID> toDelete = new HashSet<>(existingBlobs);
+		toDelete.removeAll(referencedClientBlob);
+		if(!toDelete.isEmpty()) {
+			for(EaglercraftUUID del : toDelete) {
+				existingBlobs.remove(del);
+				String name = "blobs/" + del;
+				logger.info("Deleting orphaned blob \"{}\" from datastore", name);
+				if(!datastore.deleteItem(name)) {
+					logger.warn("Failed to delete file! Skipping...");
+				}
+			}
+		}
+	}
+
+	public void garbageCollectAll() {
+		logger.info("Garbage-collecting boot menu data store");
+		Set<EaglercraftUUID> existingClients = new HashSet<>();
+		Set<EaglercraftUUID> existingLaunches = new HashSet<>();
+		Set<EaglercraftUUID> existingBlobs = new HashSet<>();
+		Set<String> orphanedFiles = new HashSet<>();
+		datastore.iterateAllKeys((str) -> {
+			if(str.startsWith("clientDatas/")) {
+				try {
+					existingClients.add(EaglercraftUUID.fromString(str.substring(12)));
+				}catch(IllegalArgumentException ex) {
+					orphanedFiles.add(str);
+				}
+			}else if(str.startsWith("launchDatas/")) {
+				try {
+					existingLaunches.add(EaglercraftUUID.fromString(str.substring(12)));
+				}catch(IllegalArgumentException ex) {
+					orphanedFiles.add(str);
+				}
+			}else if(str.startsWith("blobs/")) {
+				try {
+					existingBlobs.add(EaglercraftUUID.fromString(str.substring(6)));
+				}catch(IllegalArgumentException ex) {
+					orphanedFiles.add(str);
+				}
+			}
+		});
+		Set<EaglercraftUUID> toDelete = new HashSet<>(existingLaunches);
+		toDelete.removeAll(launchDatas.keySet());
+		if(!toDelete.isEmpty()) {
+			for(EaglercraftUUID del : toDelete) {
+				String name = "launchDatas/" + del;
+				logger.info("Deleting orphaned launch \"{}\" from datastore", name);
+				if(!datastore.deleteItem(name)) {
+					logger.warn("Failed to delete file! Skipping...");
+				}
+			}
+		}
+		Set<EaglercraftUUID> referencedData = new HashSet<>();
+		for(LaunchConfigEntry etr : launchDatas.values()) {
+			referencedData.add(etr.clientDataUUID);
+		}
+		toDelete = new HashSet<>(existingClients);
+		toDelete.removeAll(referencedData);
+		if(!toDelete.isEmpty()) {
+			for(EaglercraftUUID del : toDelete) {
+				clientDatas.remove(del);
+				String name = "clientDatas/" + del;
+				logger.info("Deleting orphaned client \"{}\" from datastore", name);
+				if(!datastore.deleteItem(name)) {
+					logger.warn("Failed to delete file! Skipping...");
+				}
+			}
+		}
+		referencedData.clear();
+		for(ClientDataEntry etr : clientDatas.values()) {
+			referencedData.addAll(etr.getReferencedBlobs());
+		}
+		toDelete.clear();
+		toDelete.addAll(existingBlobs);
+		toDelete.removeAll(referencedData);
+		if(!toDelete.isEmpty()) {
+			for(EaglercraftUUID del : toDelete) {
+				existingBlobs.remove(del);
+				String name = "blobs/" + del;
+				logger.info("Deleting orphaned blob \"{}\" from datastore", name);
+				if(!datastore.deleteItem(name)) {
+					logger.warn("Failed to delete file! Skipping...");
+				}
+			}
+		}
+	}
+
+	public void loadAdditionalConf() {
+		logger.info("Loading config.json");
+		byte[] dat = datastore.getItem("config.json");
+		if(dat != null) {
+			try {
+				JSONObject obj = new JSONObject(new String(dat, StandardCharsets.UTF_8));
+				confBootTimeout = obj.getInt("confBootTimeout");
+				confMenuTitle = obj.getString("confMenuTitle");
+			}catch(JSONException ex) {
+				logger.error("Invalid config.json!");
+				logger.error(ex);
+			}
+		}
+	}
+
+	public void saveAdditionalConf() {
+		JSONObject confJSON = new JSONObject();
+		confJSON.put("confBootTimeout", confBootTimeout);
+		confJSON.put("confMenuTitle", confMenuTitle);
+		byte[] confBytes = confJSON.toString().getBytes(StandardCharsets.UTF_8);
+		datastore.setItem("config.json", confBytes);
+	}
+
+	public static int getBootMenuFlags(Window win) {
+		try {
+			Storage stor = win.getLocalStorage();
+			if(stor != null) {
+				String itm = stor.getItem(BootMenuConstants.getBootMenuFlagsKeyName());
+				if(itm != null) {
+					return Integer.parseInt(itm);
+				}
+			}
+		}catch(Throwable t) {
+		}
+		return -1;
+	}
+
+	public static void setBootMenuFlags(Window win, int flags) {
+		try {
+			Storage stor = win.getLocalStorage();
+			if(stor != null) {
+				String key = BootMenuConstants.getBootMenuFlagsKeyName();
+				if(flags != -1) {
+					stor.setItem(key, Integer.toString(flags));
+				}else {
+					stor.removeItem(key);
+				}
+			}
+		}catch(Throwable t) {
+		}
+	}
+
+}
diff --git a/sources/teavm-boot-menu/java/net/lax1dude/eaglercraft/v1_8/boot_menu/teavm/BootMenuDatastore.java b/sources/teavm-boot-menu/java/net/lax1dude/eaglercraft/v1_8/boot_menu/teavm/BootMenuDatastore.java
new file mode 100644
index 00000000..7077a69d
--- /dev/null
+++ b/sources/teavm-boot-menu/java/net/lax1dude/eaglercraft/v1_8/boot_menu/teavm/BootMenuDatastore.java
@@ -0,0 +1,362 @@
+package net.lax1dude.eaglercraft.v1_8.boot_menu.teavm;
+
+import java.util.function.Consumer;
+
+import org.teavm.interop.Async;
+import org.teavm.interop.AsyncCallback;
+import org.teavm.jso.JSBody;
+import org.teavm.jso.JSFunctor;
+import org.teavm.jso.JSObject;
+import org.teavm.jso.dom.events.EventListener;
+import org.teavm.jso.indexeddb.EventHandler;
+import org.teavm.jso.indexeddb.IDBCountRequest;
+import org.teavm.jso.indexeddb.IDBCursor;
+import org.teavm.jso.indexeddb.IDBCursorRequest;
+import org.teavm.jso.indexeddb.IDBDatabase;
+import org.teavm.jso.indexeddb.IDBFactory;
+import org.teavm.jso.indexeddb.IDBGetRequest;
+import org.teavm.jso.indexeddb.IDBObjectStoreParameters;
+import org.teavm.jso.indexeddb.IDBOpenDBRequest;
+import org.teavm.jso.indexeddb.IDBRequest;
+import org.teavm.jso.indexeddb.IDBTransaction;
+import org.teavm.jso.indexeddb.IDBVersionChangeEvent;
+import org.teavm.jso.typedarrays.ArrayBuffer;
+
+import net.lax1dude.eaglercraft.v1_8.internal.teavm.BooleanResult;
+import net.lax1dude.eaglercraft.v1_8.internal.teavm.TeaVMUtils;
+import net.lax1dude.eaglercraft.v1_8.log4j.LogManager;
+import net.lax1dude.eaglercraft.v1_8.log4j.Logger;
+
+/**
+ * Copyright (c) 2024 lax1dude. All Rights Reserved.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ * 
+ */
+public class BootMenuDatastore {
+
+	private static final Logger logger = LogManager.getLogger("BootMenuDatastore");
+
+	public static final String bootMenuDatabaseName = BootMenuConstants.bootMenuDatabaseName;
+
+	private static final Object instanceLock = new Object();
+	private static BootMenuDatastore instance = null;
+
+	public static class DatastoreLockedException extends RuntimeException {
+		public DatastoreLockedException(String message) {
+			super(message);
+		}
+	}
+
+	public static class DatastoreInitializationException extends RuntimeException {
+		public DatastoreInitializationException(String message) {
+			super(message);
+		}
+	}
+
+	public static class DatastoreOperationException extends RuntimeException {
+		public DatastoreOperationException(String message) {
+			super(message);
+		}
+	}
+
+	public static BootMenuDatastore openDatastore() {
+		synchronized(instanceLock) {
+			if(instance != null) {
+				++instance.openCount;
+				return instance;
+			}
+			return instance = openDatastore0();
+		}
+	}
+
+	private static BootMenuDatastore openDatastore0() {
+		DatabaseOpen openResult = AsyncHandlers
+				.openDB(bootMenuDatabaseName + (BootMenuEntryPoint.isSignedClient() ? "_sig" : "_unsig")
+						+ (IBootMenuConfigAdapter.instance.isBootMenuBlocksUnsignedClients() ? "_1" : "_0"));
+		if(openResult.failedLocked) {
+			throw new DatastoreLockedException(openResult.failedError);
+		}
+		if(openResult.failedInit) {
+			throw new DatastoreInitializationException(openResult.failedError);
+		}
+		if(openResult.database == null) {
+			throw new NullPointerException("IDBDatabase is null!");
+		}
+		return new BootMenuDatastore(openResult.database);
+	}
+
+	private IDBDatabase database;
+	private int openCount;
+
+	private BootMenuDatastore(IDBDatabase database) {
+		this.database = database;
+		this.openCount = 1;
+	}
+
+	public byte[] getItem(String key) {
+		if(database != null) {
+			return TeaVMUtils.wrapByteArrayBuffer(AsyncHandlers.readWholeFile(database, key));
+		}else {
+			return null;
+		}
+	}
+
+	public void setItem(String key, byte[] data) {
+		if(database != null) {
+			if(data != null) {
+				if(!AsyncHandlers.writeWholeFile(database, key, TeaVMUtils.unwrapArrayBuffer(data)).bool) {
+					throw new DatastoreOperationException("Failed to write to datastore: \"" + key + "\" (" + data.length + " bytes)");
+				}
+			}else {
+				AsyncHandlers.deleteFile(database, key);
+			}
+		}
+	}
+
+	public boolean containsKey(String key) {
+		if(database != null) {
+			return AsyncHandlers.fileExists(database, key).bool;
+		}else {
+			return false;
+		}
+	}
+
+	public boolean deleteItem(String key) {
+		if(database != null) {
+			return AsyncHandlers.deleteFile(database, key).bool;
+		}else {
+			return false;
+		}
+	}
+
+	public void closeDatastore() {
+		if(--openCount == 0) {
+			synchronized(instanceLock) {
+				if(instance == this) {
+					instance = null;
+				}
+			}
+			closeDatastore0();
+		}
+	}
+
+	private void closeDatastore0() {
+		if(database != null) {
+			database.close();
+		}
+	}
+
+	public void iterateAllKeys(Consumer<String> itr) {
+		if(database != null) {
+			AsyncHandlers.iterateFiles(database, itr);
+		}
+	}
+
+	protected static class DatabaseOpen {
+		
+		protected final boolean failedInit;
+		protected final boolean failedLocked;
+		protected final String failedError;
+		
+		protected final IDBDatabase database;
+		
+		protected DatabaseOpen(boolean init, boolean locked, String error, IDBDatabase db) {
+			failedInit = init;
+			failedLocked = locked;
+			failedError = error;
+			database = db;
+		}
+		
+	}
+
+	@JSBody(script = "return ((typeof indexedDB) !== 'undefined') ? indexedDB : null;")
+	protected static native IDBFactory createIDBFactory();
+
+	@JSFunctor
+	protected static interface OpenErrorCallback extends JSObject {
+		void call(String str);
+	}
+
+	@JSBody(params = { "factory", "name", "ii", "errCB" }, script = "try { return factory.open(name, ii); } catch(err) { errCB(\"\" + err); return null; }")
+	protected static native IDBOpenDBRequest safeOpen(IDBFactory factory, String name, int i, OpenErrorCallback errCB);
+	
+	protected static class AsyncHandlers {
+		
+		@Async
+		protected static native DatabaseOpen openDB(String name);
+		
+		private static void openDB(String name, final AsyncCallback<DatabaseOpen> cb) {
+			IDBFactory i = createIDBFactory();
+			if(i == null) {
+				cb.complete(new DatabaseOpen(true, false, "window.indexedDB was null or undefined", null));
+				return;
+			}
+			final String[] errorHolder = new String[] { null };
+			final IDBOpenDBRequest f = safeOpen(i, name, 1, (e) -> errorHolder[0] = e);
+			if(f == null || TeaVMUtils.isNotTruthy(f)) {
+				cb.complete(new DatabaseOpen(true, false, errorHolder[0] != null ? errorHolder[0] : "database open request was null or undefined", null));
+				return;
+			}
+			TeaVMUtils.addEventListener(f, "blocked", new EventHandler() {
+				@Override
+				public void handleEvent() {
+					cb.complete(new DatabaseOpen(false, true, null, null));
+				}
+			});
+			TeaVMUtils.addEventListener(f, "success", new EventHandler() {
+				@Override
+				public void handleEvent() {
+					cb.complete(new DatabaseOpen(false, false, null, f.getResult()));
+				}
+			});
+			TeaVMUtils.addEventListener(f, "error", new EventHandler() {
+				@Override
+				public void handleEvent() {
+					cb.complete(new DatabaseOpen(true, false, "open error", null));
+				}
+			});
+			TeaVMUtils.addEventListener(f, "upgradeneeded", new EventListener<IDBVersionChangeEvent>() {
+				@Override
+				public void handleEvent(IDBVersionChangeEvent evt) {
+					f.getResult().createObjectStore("filesystem", IDBObjectStoreParameters.create().keyPath("path"));
+				}
+			});
+		}
+		
+		@Async
+		protected static native BooleanResult deleteFile(IDBDatabase db, String name);
+		
+		private static void deleteFile(IDBDatabase db, String name, final AsyncCallback<BooleanResult> cb) {
+			IDBTransaction tx = db.transaction("filesystem", "readwrite");
+			final IDBRequest r = tx.objectStore("filesystem").delete(makeTheFuckingKeyWork(name));
+			TeaVMUtils.addEventListener(r, "success", new EventHandler() {
+				@Override
+				public void handleEvent() {
+					cb.complete(BooleanResult.TRUE);
+				}
+			});
+			TeaVMUtils.addEventListener(r, "error", new EventHandler() {
+				@Override
+				public void handleEvent() {
+					cb.complete(BooleanResult.FALSE);
+				}
+			});
+		}
+		
+		@JSBody(params = { "obj" }, script = "return (typeof obj === \"undefined\") ? null : ((typeof obj.data === \"undefined\") ? null : obj.data);")
+		protected static native ArrayBuffer readRow(JSObject obj);
+		
+		@JSBody(params = { "obj" }, script = "return [obj];")
+		private static native JSObject makeTheFuckingKeyWork(String k);
+		
+		@Async
+		protected static native ArrayBuffer readWholeFile(IDBDatabase db, String name);
+		
+		private static void readWholeFile(IDBDatabase db, String name, final AsyncCallback<ArrayBuffer> cb) {
+			IDBTransaction tx = db.transaction("filesystem", "readonly");
+			final IDBGetRequest r = tx.objectStore("filesystem").get(makeTheFuckingKeyWork(name));
+			TeaVMUtils.addEventListener(r, "success", new EventHandler() {
+				@Override
+				public void handleEvent() {
+					cb.complete(readRow(r.getResult()));
+				}
+			});
+			TeaVMUtils.addEventListener(r, "error", new EventHandler() {
+				@Override
+				public void handleEvent() {
+					cb.complete(null);
+				}
+			});
+			
+		}
+		
+		@Async
+		protected static native BooleanResult fileExists(IDBDatabase db, String name);
+		
+		private static void fileExists(IDBDatabase db, String name, final AsyncCallback<BooleanResult> cb) {
+			IDBTransaction tx = db.transaction("filesystem", "readonly");
+			final IDBCountRequest r = tx.objectStore("filesystem").count(makeTheFuckingKeyWork(name));
+			TeaVMUtils.addEventListener(r, "success", new EventHandler() {
+				@Override
+				public void handleEvent() {
+					cb.complete(BooleanResult._new(r.getResult() > 0));
+				}
+			});
+			TeaVMUtils.addEventListener(r, "error", new EventHandler() {
+				@Override
+				public void handleEvent() {
+					cb.complete(BooleanResult.FALSE);
+				}
+			});
+		}
+		
+		@JSBody(params = { "k" }, script = "return ((typeof k) === \"string\") ? k : (((typeof k) === \"undefined\") ? null : (((typeof k[0]) === \"string\") ? k[0] : null));")
+		private static native String readKey(JSObject k);
+		
+		@Async
+		protected static native Integer iterateFiles(IDBDatabase db, final Consumer<String> itr);
+		
+		private static void iterateFiles(IDBDatabase db, final Consumer<String> itr, final AsyncCallback<Integer> cb) {
+			IDBTransaction tx = db.transaction("filesystem", "readonly");
+			final IDBCursorRequest r = tx.objectStore("filesystem").openCursor();
+			final int[] res = new int[1];
+			TeaVMUtils.addEventListener(r, "success", new EventHandler() {
+				@Override
+				public void handleEvent() {
+					IDBCursor c = r.getResult();
+					if(c == null || c.getKey() == null || c.getValue() == null) {
+						cb.complete(res[0]);
+						return;
+					}
+					String k = readKey(c.getKey());
+					if(k != null) {
+						++res[0];
+						itr.accept(k);
+					}
+					c.doContinue();
+				}
+			});
+			TeaVMUtils.addEventListener(r, "error", new EventHandler() {
+				@Override
+				public void handleEvent() {
+					cb.complete(res[0] > 0 ? res[0] : -1);
+				}
+			});
+		}
+		
+		@JSBody(params = { "pat", "dat" }, script = "return { path: pat, data: dat };")
+		protected static native JSObject writeRow(String name, ArrayBuffer data);
+		
+		@Async
+		protected static native BooleanResult writeWholeFile(IDBDatabase db, String name, ArrayBuffer data);
+		
+		private static void writeWholeFile(IDBDatabase db, String name, ArrayBuffer data, final AsyncCallback<BooleanResult> cb) {
+			IDBTransaction tx = db.transaction("filesystem", "readwrite");
+			final IDBRequest r = tx.objectStore("filesystem").put(writeRow(name, data));
+			
+			TeaVMUtils.addEventListener(r, "success", new EventHandler() {
+				@Override
+				public void handleEvent() {
+					cb.complete(BooleanResult.TRUE);
+				}
+			});
+			TeaVMUtils.addEventListener(r, "error", new EventHandler() {
+				@Override
+				public void handleEvent() {
+					cb.complete(BooleanResult.FALSE);
+				}
+			});
+		}
+		
+	}
+}
diff --git a/sources/teavm-boot-menu/java/net/lax1dude/eaglercraft/v1_8/boot_menu/teavm/BootMenuEntryPoint.java b/sources/teavm-boot-menu/java/net/lax1dude/eaglercraft/v1_8/boot_menu/teavm/BootMenuEntryPoint.java
new file mode 100644
index 00000000..b7879fe8
--- /dev/null
+++ b/sources/teavm-boot-menu/java/net/lax1dude/eaglercraft/v1_8/boot_menu/teavm/BootMenuEntryPoint.java
@@ -0,0 +1,178 @@
+package net.lax1dude.eaglercraft.v1_8.boot_menu.teavm;
+
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.function.Supplier;
+
+import org.json.JSONArray;
+import org.json.JSONObject;
+import org.teavm.jso.JSBody;
+import org.teavm.jso.browser.Window;
+import org.teavm.jso.dom.html.HTMLElement;
+
+import net.lax1dude.eaglercraft.v1_8.EaglercraftUUID;
+import net.lax1dude.eaglercraft.v1_8.cookie.ServerCookieDataStore;
+import net.lax1dude.eaglercraft.v1_8.internal.PlatformApplication;
+import net.lax1dude.eaglercraft.v1_8.internal.PlatformRuntime;
+import net.lax1dude.eaglercraft.v1_8.internal.PlatformUpdateSvc;
+import net.lax1dude.eaglercraft.v1_8.internal.teavm.ClientMain;
+import net.lax1dude.eaglercraft.v1_8.internal.teavm.ClientMain.EPKFileEntry;
+import net.lax1dude.eaglercraft.v1_8.sp.internal.ClientPlatformSingleplayer;
+import net.lax1dude.eaglercraft.v1_8.internal.teavm.TeaVMClientConfigAdapter;
+import net.lax1dude.eaglercraft.v1_8.internal.teavm.TeaVMUtils;
+
+/**
+ * Copyright (c) 2024 lax1dude. All Rights Reserved.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ * 
+ */
+public class BootMenuEntryPoint {
+
+	@JSBody(params = {}, script = "if((typeof window.__isEaglerX188BootMenuAlreadyShow === \"string\") && window.__isEaglerX188BootMenuAlreadyShow === \"yes\") return true; window.__isEaglerX188BootMenuAlreadyShow = \"yes\"; return false;")
+	private static native boolean getHasAlreadyBooted();
+
+	@JSBody(params = {}, script = "window.__isEaglerX188BootMenuAlreadyShow = \"yes\";")
+	private static native void setHasAlreadyBooted();
+
+	public static boolean checkShouldLaunchFlag(Window win) {
+		int flag = BootMenuDataManager.getBootMenuFlags(win);
+		if(flag == -1) {
+			return IBootMenuConfigAdapter.instance.isShowBootMenuOnLaunch() && !getHasAlreadyBooted();
+		}
+		if((flag & 2) != 0) {
+			BootMenuDataManager.setBootMenuFlags(win, flag & ~2);
+			setHasAlreadyBooted();
+			return true;
+		}
+		return ((flag & 1) != 0 || IBootMenuConfigAdapter.instance.isShowBootMenuOnLaunch()) && !getHasAlreadyBooted();
+	}
+
+	private static byte[] signatureData = null;
+	private static byte[] bundleData = null;
+
+	public static void launchMenu(Window parentWindow, HTMLElement parentElement) {
+		signatureData = PlatformUpdateSvc.getClientSignatureData();
+		bundleData = PlatformUpdateSvc.getClientBundleData();
+		BootMenuMain.launchMenu(parentWindow, parentElement);
+	}
+
+	public static void bootOriginClient() {
+		bootOriginClient(null);
+	}
+
+	public static void bootOriginClient(Runnable doBeforeBoot) {
+		(new Thread(() -> {
+			if(doBeforeBoot != null) {
+				doBeforeBoot.run();
+			}
+			ClientMain._main();
+		}, "main")).start();
+	}
+
+	public static boolean isSignedClient() {
+		return signatureData != null && bundleData != null;
+	}
+
+	public static byte[] getSignedClientSignature() {
+		return signatureData;
+	}
+
+	public static byte[] getSignedClientBundle() {
+		return bundleData;
+	}
+
+	public static byte[] getUnsignedClientClassesJS() {
+		return OfflineDownloadFactory.removeClientScriptElement(ClientPlatformSingleplayer.getIntegratedServerSourceTeaVM(), true);
+	}
+
+	public static class UnsignedClientEPKLoader {
+
+		public final List<EPKDataEntry> list;
+		public final Map<EaglercraftUUID,Supplier<byte[]>> loaders;
+		
+		public UnsignedClientEPKLoader(List<EPKDataEntry> list, Map<EaglercraftUUID,Supplier<byte[]>> loaders) {
+			this.list = list;
+			this.loaders = loaders;
+		}
+		
+		public byte[] loadEntry(EaglercraftUUID epkUUID) {
+			Supplier<byte[]> sup = loaders.get(epkUUID);
+			return sup != null ? sup.get() : null;
+		}
+		
+	}
+
+	public static JSONArray getUnsignedClientAssetsEPKRaw() {
+		JSONArray ret = new JSONArray(ClientMain.configEPKFiles.length);
+		for (int i = 0; i < ClientMain.configEPKFiles.length; ++i) {
+			EPKFileEntry etr = ClientMain.configEPKFiles[i];
+			JSONObject obj = new JSONObject();
+			obj.put("url", etr.url);
+			obj.put("path", etr.path);
+			ret.put(obj);
+		}
+		return ret;
+	}
+
+	public static UnsignedClientEPKLoader getUnsignedClientAssetsEPK() {
+		List<EPKDataEntry> list = new ArrayList<>(2);
+		Map<EaglercraftUUID, Supplier<byte[]>> loaders = new HashMap<>(2);
+		for (int i = 0; i < ClientMain.configEPKFiles.length; ++i) {
+			EPKFileEntry etr = ClientMain.configEPKFiles[i];
+			EaglercraftUUID uuidGen = EaglercraftUUID
+					.nameUUIDFromBytes(("EPKURL:" + etr.url).getBytes(StandardCharsets.UTF_8));
+			list.add(new EPKDataEntry(etr.path, uuidGen));
+			loaders.put(uuidGen,
+					() -> TeaVMUtils.wrapByteArrayBuffer(PlatformRuntime.downloadRemoteURI(etr.url, true)));
+		}
+		return new UnsignedClientEPKLoader(list, loaders);
+	}
+
+	public static String getOriginLaunchOpts() {
+		return ((TeaVMClientConfigAdapter)PlatformRuntime.getClientConfigAdapter()).toJSONObject().put("bootMenuBlocksUnsignedClients", false).toString(4);
+	}
+
+	public static JSONObject getOriginLaunchOptsJSON() {
+		return ((TeaVMClientConfigAdapter)PlatformRuntime.getClientConfigAdapter()).toJSONObject();
+	}
+
+	public static String getOriginContainer() {
+		return ClientMain.configRootElementId;
+	}
+
+	public static void installSignedClientAtRuntime(String displayName, Window win, byte[] clientCert,
+			byte[] clientPayload, boolean setDefault, boolean setTimeout) {
+		SignedClientInstaller.installSignedClientAtRuntime(displayName, win, clientCert, clientPayload, setDefault,
+				setTimeout);
+	}
+
+	public static void setDisplayBootMenuNextRefresh(Window win, boolean en) {
+		int i = BootMenuDataManager.getBootMenuFlags(win);
+		if(i == -1) i = 0;
+		if(en) {
+			i |= 2;
+		}else {
+			i &= ~2;
+		}
+		BootMenuDataManager.setBootMenuFlags(win, i);
+	}
+
+	public static void clearCookies() {
+		PlatformApplication.setLocalStorage(ServerCookieDataStore.localStorageKey, null, false);
+		ServerCookieDataStore.clearCookiesLow();
+	}
+
+}
diff --git a/sources/teavm-boot-menu/java/net/lax1dude/eaglercraft/v1_8/boot_menu/teavm/BootMenuFatOfflineLoader.java b/sources/teavm-boot-menu/java/net/lax1dude/eaglercraft/v1_8/boot_menu/teavm/BootMenuFatOfflineLoader.java
new file mode 100644
index 00000000..3e47ab3f
--- /dev/null
+++ b/sources/teavm-boot-menu/java/net/lax1dude/eaglercraft/v1_8/boot_menu/teavm/BootMenuFatOfflineLoader.java
@@ -0,0 +1,93 @@
+package net.lax1dude.eaglercraft.v1_8.boot_menu.teavm;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.json.JSONArray;
+import org.json.JSONObject;
+import org.teavm.jso.dom.html.HTMLElement;
+
+import net.lax1dude.eaglercraft.v1_8.Base64;
+import net.lax1dude.eaglercraft.v1_8.EaglercraftUUID;
+import net.lax1dude.eaglercraft.v1_8.log4j.LogManager;
+import net.lax1dude.eaglercraft.v1_8.log4j.Logger;
+
+/**
+ * Copyright (c) 2024 lax1dude. All Rights Reserved.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ * 
+ */
+public class BootMenuFatOfflineLoader {
+
+	protected static final Logger logger = LogManager.getLogger("BootMenuFatOfflineLoader");
+
+	public final HTMLElement parentElement;
+
+	public final Map<EaglercraftUUID,ClientDataEntry> clientDatas = new HashMap<>();
+	public final List<LaunchConfigEntry> launchDatas = new ArrayList<>();
+
+	public BootMenuFatOfflineLoader(HTMLElement parentElement) {
+		this.parentElement = parentElement;
+		this.loadAllData();
+	}
+
+	protected void loadAllData() {
+		String manifest = loadDataString("manifest_v1");
+		if(manifest != null) {
+			JSONObject json = new JSONObject(manifest);
+			JSONArray launches = json.getJSONArray("launchData");
+			JSONArray clients = json.getJSONArray("clientData");
+			for(int i = 0, l = clients.length(); i < l; ++i) {
+				JSONObject obj = clients.getJSONObject(i);
+				EaglercraftUUID theUUID = EaglercraftUUID.fromString(obj.getString("uuid"));
+				if(!theUUID.equals(BootMenuConstants.UUID_CLIENT_DATA_ORIGIN)) {
+					clientDatas.put(theUUID, new ClientDataEntry(theUUID, obj));
+				}
+			}
+			for(int i = 0, l = launches.length(); i < l; ++i) {
+				JSONObject obj = launches.getJSONObject(i);
+				EaglercraftUUID theUUID = EaglercraftUUID.fromString(obj.getString("uuid"));
+				if(!theUUID.equals(BootMenuConstants.UUID_CLIENT_LAUNCH_ORIGIN)) {
+					LaunchConfigEntry theEtr = new LaunchConfigEntry(theUUID, obj);
+					if(clientDatas.containsKey(theEtr.clientDataUUID) || BootMenuConstants.UUID_CLIENT_DATA_ORIGIN.equals(theEtr.clientDataUUID)) {
+						launchDatas.add(theEtr);
+					}else {
+						logger.warn("Skipping launch config {} because the client data {} is missing!", theUUID, theEtr.clientDataUUID);
+					}
+				}
+			}
+			logger.info("Loading {} client(s) successfully", clientDatas.size());
+			logger.info("Loading {} profile(s) successfully", launchDatas.size());
+		}
+	}
+
+	public String loadDataString(String key) {
+		HTMLElement ret = parentElement.querySelector("#_eaglerFatOffline_" + key);
+		return ret != null ? ret.getInnerText() : null;
+	}
+
+	public byte[] loadDataBinary(String key) {
+		HTMLElement ret = parentElement.querySelector("#_eaglerFatOffline_" + key);
+		if(ret == null) {
+			return null;
+		}
+		try {
+			return Base64.decodeBase64(ret.getInnerText());
+		}catch(Throwable t) {
+			return null;
+		}
+	}
+
+}
diff --git a/sources/teavm-boot-menu/java/net/lax1dude/eaglercraft/v1_8/boot_menu/teavm/BootMenuMain.java b/sources/teavm-boot-menu/java/net/lax1dude/eaglercraft/v1_8/boot_menu/teavm/BootMenuMain.java
new file mode 100644
index 00000000..f7f4f60b
--- /dev/null
+++ b/sources/teavm-boot-menu/java/net/lax1dude/eaglercraft/v1_8/boot_menu/teavm/BootMenuMain.java
@@ -0,0 +1,304 @@
+package net.lax1dude.eaglercraft.v1_8.boot_menu.teavm;
+
+import java.io.IOException;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+
+import org.teavm.jso.JSBody;
+import org.teavm.jso.browser.Window;
+import org.teavm.jso.dom.events.EventListener;
+import org.teavm.jso.dom.events.KeyboardEvent;
+import org.teavm.jso.dom.html.HTMLDocument;
+import org.teavm.jso.dom.html.HTMLElement;
+
+import com.google.common.collect.Lists;
+import com.google.common.html.HtmlEscapers;
+
+import net.lax1dude.eaglercraft.v1_8.EagUtils;
+import net.lax1dude.eaglercraft.v1_8.EaglercraftRandom;
+import net.lax1dude.eaglercraft.v1_8.internal.PlatformInput;
+import net.lax1dude.eaglercraft.v1_8.internal.teavm.LegacyKeycodeTranslator;
+import net.lax1dude.eaglercraft.v1_8.log4j.LogManager;
+import net.lax1dude.eaglercraft.v1_8.log4j.Logger;
+
+/**
+ * Copyright (c) 2024 lax1dude. All Rights Reserved.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ * 
+ */
+public class BootMenuMain {
+
+	private static final Logger logger = LogManager.getLogger("BootMenuMain");
+
+	public static Window win = null;
+	public static HTMLDocument doc = null;
+	public static HTMLElement parent = null;
+	public static BootMenuDOM bootMenuDOM = null;
+	public static MenuState currentState = null;
+	public static BootMenuMetadata bootMenuMetadata = null;
+	public static BootMenuDatastore bootMenuDatastore = null;
+	public static BootMenuDataManager bootMenuDataManager = null;
+	public static BootMenuFatOfflineLoader bootMenuFatOfflineLoader = null;
+
+	private static EventListener<KeyboardEvent> windowKeyDownListener = null;
+	private static EventListener<KeyboardEvent> windowKeyUpListener = null;
+
+	private static final List<Runnable> eventQueue = new LinkedList<>();
+
+	private static boolean runUpdateLoop = true;
+
+	@JSBody(params = { "e" }, script = "return (typeof e.which === \"number\") ? e.which : ((typeof e.keyCode === \"number\") ? e.keyCode : 0);")
+	private static native int getWhich(KeyboardEvent e);
+
+	@JSBody(params = { "evt" }, script = "return (typeof evt.key === \"string\");")
+	private static native boolean hasKeyVar(KeyboardEvent evt);
+
+	@JSBody(params = { "evt" }, script = "return (typeof evt.code === \"string\");")
+	private static native boolean hasCodeVar(KeyboardEvent evt);
+
+	public static void launchMenu(Window parentWindow, HTMLElement parentElement) {
+		win = parentWindow;
+		doc = parentWindow.getDocument();
+		parent = parentElement;
+		logger.info("Integrated boot menu is loading");
+		String renderedMarkup;
+		try {
+			renderedMarkup = TemplateLoader.loadTemplate("/assets/eagler/boot_menu/boot_menu_markup.html");
+		}catch(IOException ex) {
+			logger.error("Failed to render template!");
+			logger.error(ex);
+			parentElement.setInnerHTML("<div style=\"padding:10px;\"><h1>Failed to render template!</h1><h3>"
+					+ HtmlEscapers.htmlEscaper().escape(ex.toString())
+					+ "</h3><p>Check the console for more details</p></div>");
+			return;
+		}
+		parentElement.setInnerHTML(renderedMarkup);
+		bootMenuDOM = new BootMenuDOM(parentElement);
+		logger.info("Registering event handlers");
+		win.addEventListener("keydown", windowKeyDownListener = (evt) -> {
+			if(currentState != null) {
+				LegacyKeycodeTranslator.LegacyKeycode keyCode = null;
+				Map<String,LegacyKeycodeTranslator.LegacyKeycode> keyCodeTranslatorMap = PlatformInput.getKeyCodeTranslatorMapTeaVM();
+				if(keyCodeTranslatorMap != null && hasCodeVar(evt)) {
+					keyCode = keyCodeTranslatorMap.get(evt.getCode());
+				}
+				final int which;
+				if(keyCode != null) {
+					which = keyCode.keyCode;
+				}else {
+					which = getWhich(evt);
+				}
+				if(!evt.isRepeat()) {
+					runLater(() -> {
+						if(currentState != null) {
+							currentState.doHandleKeyDown(which);
+						}
+					});
+				}else {
+					runLater(() -> {
+						if(currentState != null) {
+							currentState.doHandleKeyRepeat(which);
+						}
+					});
+				}
+			}
+		});
+		win.addEventListener("keyup", windowKeyUpListener = (evt) -> {
+			if(currentState != null) {
+				if(!evt.isRepeat()) {
+					LegacyKeycodeTranslator.LegacyKeycode keyCode = null;
+					Map<String,LegacyKeycodeTranslator.LegacyKeycode> keyCodeTranslatorMap = PlatformInput.getKeyCodeTranslatorMapTeaVM();
+					if(keyCodeTranslatorMap != null && hasCodeVar(evt)) {
+						keyCode = keyCodeTranslatorMap.get(evt.getCode());
+					}
+					final int which;
+					if(keyCode != null) {
+						which = keyCode.keyCode;
+					}else {
+						which = getWhich(evt);
+					}
+					runLater(() -> {
+						if(currentState != null) {
+							currentState.doHandleKeyUp(which);
+						}
+					});
+				}
+			}
+		});
+		bootMenuDOM.registerEventHandlers();
+		bootMenuMetadata = new BootMenuMetadata("/assets/eagler/boot_menu/");
+		bootMenuDatastore = BootMenuDatastore.openDatastore(); //TODO: error handling
+		bootMenuDataManager = new BootMenuDataManager(bootMenuDatastore);
+		bootMenuDOM.header_title.setInnerText(bootMenuDataManager.confMenuTitle);
+		bootMenuFatOfflineLoader = new BootMenuFatOfflineLoader(parentWindow.getDocument().getHead());
+		logger.info("Entering boot menu display state");
+		eventQueue.clear();
+		changeState(new MenuStateBoot(true));
+		enterUpdateLoop();
+	}
+
+	private static void enterUpdateLoop() {
+		runUpdateLoop = true;
+		while(runUpdateLoop) {
+			if(currentState != null) {
+				currentState.doUpdate();
+			}
+			List<Runnable> eq = null;
+			synchronized(eventQueue) {
+				if(!eventQueue.isEmpty()) {
+					eq = Lists.newArrayList(eventQueue);
+					eventQueue.clear();
+				}
+			}
+			if(eq != null) {
+				for(Runnable run : eq) {
+					try {
+						run.run();
+					}catch(Throwable t) {
+						logger.error("Caught error in event queue!");
+						logger.error(t);
+					}
+				}
+			}
+			EagUtils.sleep(50l);
+		}
+	}
+
+	public static void runLater(Runnable run) {
+		if(runUpdateLoop) {
+			synchronized(eventQueue) {
+				eventQueue.add(run);
+			}
+		}
+	}
+
+	public static void runLaterMS(Runnable run, int millis) {
+		Window.setTimeout(() -> runLater(run), millis);
+	}
+
+	public static void unregisterEventHandlers() {
+		if(windowKeyDownListener != null) {
+			win.removeEventListener("keydown", windowKeyDownListener);
+			windowKeyDownListener = null;
+		}
+		if(windowKeyUpListener != null) {
+			win.removeEventListener("keyup", windowKeyUpListener);
+			windowKeyUpListener = null;
+		}
+	}
+
+	public static void changeState(MenuState newState) {
+		if(currentState != null) {
+			currentState.doExitState();
+			currentState = null;
+		}
+		currentState = newState;
+		if(newState != null) {
+			newState.doEnterState();
+		}
+	}
+
+	public static void continueBootToOriginClient() {
+		continueBootToOriginClient(BootMenuMain::sanitizeEaglercraftXOpts);
+	}
+
+	public static void continueBootToOriginClient(Runnable doBeforeBoot) {
+		destroyBootMenuRuntime();
+		stopEventLoop();
+		BootMenuEntryPoint.bootOriginClient(doBeforeBoot);
+	}
+
+	@JSBody(params = { }, script = "try { window.eaglercraftXOptsHints.bootMenuBlocksUnsignedClients = true; }catch(_ex){} try { window.eaglercraftXOpts.bootMenuBlocksUnsignedClients = true; }catch(_ex){}")
+	private static native void doSanitizeSignatureRequired();
+
+	public static void sanitizeEaglercraftXOpts() {
+		if(IBootMenuConfigAdapter.instance.isBootMenuBlocksUnsignedClients()) {
+			doSanitizeSignatureRequired();
+		}
+	}
+
+	public static String createRootElementForClient() {
+		EaglercraftRandom randomCharGenerator = new EaglercraftRandom();
+		char[] randomChars = new char[16];
+		String charSel = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
+		for(int i = 0; i < randomChars.length; ++i) {
+			randomChars[i] = charSel.charAt(randomCharGenerator.nextInt(charSel.length()));
+		}
+		String randomId = "game_frame_" + new String(randomChars);
+		HTMLElement parentTemp = parent;
+		HTMLElement newRoot = doc.createElement("div");
+		newRoot.getStyle().setProperty("width", "100%");
+		newRoot.getStyle().setProperty("height", "100%");
+		newRoot.setAttribute("id", randomId);
+		destroyBootMenuRuntime();
+		parentTemp.appendChild(newRoot);
+		return randomId;
+		
+	}
+
+	public static void destroyBootMenuRuntime() {
+		unregisterEventHandlers();
+		bootMenuDOM = null;
+		currentState = null;
+		bootMenuMetadata = null;
+		if(bootMenuDatastore != null) {
+			bootMenuDatastore.closeDatastore();
+			bootMenuDatastore = null;
+		}
+		bootMenuDataManager = null;
+		bootMenuFatOfflineLoader = null;
+		BootMenuAssets.freeBootMenuResourceRepo();
+		win = null;
+		doc = null;
+		while(parent.getLastChild() != null) {
+			parent.removeChild(parent.getLastChild());
+		}
+		parent = null;
+	}
+
+	public static void stopEventLoop() {
+		runUpdateLoop = false;
+	}
+
+	public static void fireChangeEvent(HTMLElement element) {
+		if(currentState != null) {
+			runLater(() -> {
+				if(currentState != null) {
+					currentState.doHandleOnChange(element);
+				}
+			});
+		}
+	}
+
+	public static void fireClickEvent(HTMLElement element) {
+		if(currentState != null) {
+			runLater(() -> {
+				if(currentState != null) {
+					currentState.doHandleOnClick(element);
+				}
+			});
+		}
+	}
+
+	public static void fireMouseOverEvent(HTMLElement element) {
+		if(currentState != null) {
+			runLater(() -> {
+				if(currentState != null) {
+					currentState.doHandleOnMouseOver(element);
+				}
+			});
+		}
+	}
+
+}
diff --git a/sources/teavm-boot-menu/java/net/lax1dude/eaglercraft/v1_8/boot_menu/teavm/BootMenuMetadata.java b/sources/teavm-boot-menu/java/net/lax1dude/eaglercraft/v1_8/boot_menu/teavm/BootMenuMetadata.java
new file mode 100644
index 00000000..5199a5a9
--- /dev/null
+++ b/sources/teavm-boot-menu/java/net/lax1dude/eaglercraft/v1_8/boot_menu/teavm/BootMenuMetadata.java
@@ -0,0 +1,224 @@
+package net.lax1dude.eaglercraft.v1_8.boot_menu.teavm;
+
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.json.JSONArray;
+import org.json.JSONObject;
+
+import net.lax1dude.eaglercraft.v1_8.EaglercraftUUID;
+import net.lax1dude.eaglercraft.v1_8.cache.EaglerLoadingCache;
+import net.lax1dude.eaglercraft.v1_8.log4j.LogManager;
+import net.lax1dude.eaglercraft.v1_8.log4j.Logger;
+
+/**
+ * Copyright (c) 2024 lax1dude. All Rights Reserved.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ * 
+ */
+public class BootMenuMetadata {
+
+	protected static final Logger logger = LogManager.getLogger("BootMenuMetadata");
+
+	public static class LaunchTemplate {
+
+		public final EnumClientLaunchType type;
+		public final String joinServer;
+		public final String launchOptsVar;
+		public final String launchOptsAssetsURIVar;
+		public final String launchOptsContainerVar;
+		public final String mainFunction;
+		public final String launchOpts;
+		public final boolean clearCookiedBeforeLaunch;
+
+		protected LaunchTemplate(EnumClientLaunchType type, String joinServer, String launchOptsVar,
+				String launchOptsAssetsURIVar, String launchOptsContainerVar, String mainFunction, String launchOpts,
+				boolean clearCookiedBeforeLaunch) {
+			this.type = type;
+			this.joinServer = joinServer;
+			this.launchOptsVar = launchOptsVar;
+			this.launchOptsAssetsURIVar = launchOptsAssetsURIVar;
+			this.launchOptsContainerVar = launchOptsContainerVar;
+			this.mainFunction = mainFunction;
+			this.launchOpts = launchOpts;
+			this.clearCookiedBeforeLaunch = clearCookiedBeforeLaunch;
+		}
+
+		protected LaunchTemplate(JSONObject jsonObject) {
+			type = EnumClientLaunchType.valueOf(jsonObject.getString("client_launch_type"));
+			joinServer = jsonObject.optString("join_server");
+			launchOptsVar = jsonObject.optString("client_launch_opts_var");
+			launchOptsAssetsURIVar = jsonObject.optString("client_launch_opts_assetsURI_var");
+			launchOptsContainerVar = jsonObject.optString("client_launch_opts_container_var");
+			mainFunction = jsonObject.optString("client_launch_main_func");
+			clearCookiedBeforeLaunch = jsonObject.optBoolean("clear_cookies_before_launch");
+			launchOpts = null;
+		}
+
+		protected LaunchTemplate mutateOpts(String newOpts) {
+			if(newOpts == launchOpts) {
+				return this;
+			}
+			return new LaunchTemplate(type, joinServer, launchOptsVar, launchOptsAssetsURIVar, launchOptsContainerVar,
+					mainFunction, newOpts, clearCookiedBeforeLaunch);
+		}
+
+		public LaunchConfigEntry createLaunchConfig(EaglercraftUUID uuid, EaglercraftUUID clientDataUUID, String displayName) {
+			return new LaunchConfigEntry(uuid, clientDataUUID, displayName, type, joinServer, launchOptsVar,
+					launchOptsAssetsURIVar, launchOptsContainerVar, mainFunction, launchOpts, clearCookiedBeforeLaunch);
+		}
+
+		public void configureLaunchConfig(LaunchConfigEntry etr) {
+			switch(type) {
+			case STANDARD_OFFLINE_V1:
+				etr.launchOpts = launchOpts;
+				etr.launchOptsVar = launchOptsVar;
+				etr.launchOptsAssetsURIVar = launchOptsAssetsURIVar;
+				etr.launchOptsContainerVar = launchOptsContainerVar;
+				etr.mainFunction = mainFunction;
+				break;
+			case EAGLERX_V1:
+			case EAGLERX_SIGNED_V1:
+			case EAGLER_1_5_V2:
+			case PEYTON_V2:
+				etr.launchOpts = launchOpts;
+				break;
+			case EAGLER_1_5_V1:
+				etr.launchOpts = launchOpts;
+				etr.joinServer = joinServer;
+				break;
+			case EAGLER_BETA_V1:
+				etr.joinServer = joinServer;
+				break;
+			case PEYTON_V1:
+				break;
+			default: //?
+				break;
+			}
+		}
+
+	}
+
+	public static class DefaultLaunchTemplate {
+
+		public final String templateName;
+		public final Set<EnumClientFormatType> supportedFormats;
+		public final Set<EnumOfflineParseType> parseTypes;
+		public final LaunchTemplate templateState;
+
+		protected DefaultLaunchTemplate(String templateName, Set<EnumClientFormatType> supportedFormats,
+				Set<EnumOfflineParseType> parseTypes, LaunchTemplate templateState) {
+			this.templateName = templateName;
+			this.supportedFormats = supportedFormats;
+			this.parseTypes = parseTypes;
+			this.templateState = templateState;
+		}
+
+		public LaunchConfigEntry createLaunchConfig(EaglercraftUUID uuid, EaglercraftUUID clientDataUUID) {
+			return templateState.createLaunchConfig(uuid, clientDataUUID, templateName);
+		}
+
+		@Override
+		public String toString() {
+			return templateName;
+		}
+	}
+
+	public final String basePath;
+
+	public final Map<EnumClientLaunchType,LaunchTemplate> formatDefaultOptsMap = new HashMap<>();
+	public final List<DefaultLaunchTemplate> defaultLaunchTemplates = new ArrayList<>();
+
+	public BootMenuMetadata(String basePath) {
+		this.basePath = basePath;
+		this.loadAllData();
+	}
+
+	protected void loadAllData() {
+		logger.info("Loading client templates and default settings...");
+		formatDefaultOptsMap.clear();
+		defaultLaunchTemplates.clear();
+		EaglerLoadingCache<String, String> optsFileLoader = new EaglerLoadingCache<>(this::loadDataFileString);
+		EaglerLoadingCache<String, LaunchTemplate> templateFileLoader = new EaglerLoadingCache<>(this::loadDataFileLaunchTemplate);
+		byte[] data = BootMenuAssets.loadResourceBytes(basePath + "meta_opts_templates.json");
+		if(data == null) {
+			throw new RuntimeException("Missing metadata file: meta_opts_templates.json");
+		}
+		JSONObject jsonObject = new JSONObject(new String(data, StandardCharsets.UTF_8));
+		JSONObject defaults = jsonObject.getJSONObject("defaults");
+		for(String str : defaults.keySet()) {
+			EnumClientLaunchType fmt = EnumClientLaunchType.valueOf(str);
+			JSONObject etr = defaults.getJSONObject(str);
+			LaunchTemplate launchTemplateBase = templateFileLoader.get(etr.getString("conf"));
+			String optsFileName = etr.optString("opts", null);
+			String eagOpts = optsFileName != null ? optsFileLoader.get(optsFileName) : null;
+			formatDefaultOptsMap.put(fmt, launchTemplateBase.mutateOpts(eagOpts));
+		}
+		JSONArray templates = jsonObject.getJSONArray("templates");
+		for(int i = 0, l = templates.length(); i < l; ++i) {
+			JSONObject obj = templates.getJSONObject(i);
+			LaunchTemplate launchTemplateBase = templateFileLoader.get(obj.getString("conf"));
+			String optsFileName = obj.optString("opts", null);
+			String eagOpts = optsFileName != null ? optsFileLoader.get(optsFileName) : null;
+			JSONArray allowList = obj.getJSONArray("allow");
+			Set<EnumClientFormatType> toAllow = new HashSet<>(allowList.length());
+			for(int j = 0, m = allowList.length(); j < m; ++j) {
+				toAllow.add(EnumClientFormatType.valueOf(allowList.getString(j)));
+			}
+			JSONArray parseTypesList = obj.getJSONArray("parseTypes");
+			Set<EnumOfflineParseType> toParseTypes = new HashSet<>(parseTypesList.length());
+			for(int j = 0, m = parseTypesList.length(); j < m; ++j) {
+				toParseTypes.add(EnumOfflineParseType.valueOf(parseTypesList.getString(j)));
+			}
+			defaultLaunchTemplates.add(new DefaultLaunchTemplate(obj.getString("name"), toAllow, toParseTypes, launchTemplateBase.mutateOpts(eagOpts)));
+		}
+	}
+
+	public List<DefaultLaunchTemplate> getTemplatesForClientData(EnumClientFormatType formatType) {
+		List<DefaultLaunchTemplate> ret = new ArrayList<>();
+		for(DefaultLaunchTemplate template : defaultLaunchTemplates) {
+			if(template.supportedFormats.contains(formatType)) {
+				ret.add(template);
+			}
+		}
+		return ret;
+	}
+
+	public List<DefaultLaunchTemplate> getTemplatesForParseType(EnumOfflineParseType parseType) {
+		List<DefaultLaunchTemplate> ret = new ArrayList<>();
+		for(DefaultLaunchTemplate template : defaultLaunchTemplates) {
+			if(template.parseTypes.contains(parseType)) {
+				ret.add(template);
+			}
+		}
+		return ret;
+	}
+
+	protected String loadDataFileString(String name) {
+		byte[] data = BootMenuAssets.loadResourceBytes(basePath + name);
+		if(data == null) {
+			throw new RuntimeException("Missing metadata file: " + name);
+		}
+		return new String(data, StandardCharsets.UTF_8);
+	}
+
+	protected LaunchTemplate loadDataFileLaunchTemplate(String name) {
+		return new LaunchTemplate(new JSONObject(loadDataFileString(name)));
+	}
+
+}
diff --git a/sources/teavm-boot-menu/java/net/lax1dude/eaglercraft/v1_8/boot_menu/teavm/BootableClientEntry.java b/sources/teavm-boot-menu/java/net/lax1dude/eaglercraft/v1_8/boot_menu/teavm/BootableClientEntry.java
new file mode 100644
index 00000000..017c0f32
--- /dev/null
+++ b/sources/teavm-boot-menu/java/net/lax1dude/eaglercraft/v1_8/boot_menu/teavm/BootableClientEntry.java
@@ -0,0 +1,366 @@
+package net.lax1dude.eaglercraft.v1_8.boot_menu.teavm;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.function.Supplier;
+
+import net.lax1dude.eaglercraft.v1_8.EaglercraftUUID;
+import net.lax1dude.eaglercraft.v1_8.boot_menu.teavm.BootMenuEntryPoint.UnsignedClientEPKLoader;
+
+/**
+ * Copyright (c) 2024 lax1dude. All Rights Reserved.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ * 
+ */
+public class BootableClientEntry {
+
+	public static enum EnumDataType {
+		SITE_ORIGIN, EMBEDDED, LOCAL_STORAGE;
+	}
+
+	public static interface BootAdapter {
+		String getDisplayName();
+		void bootClient(IProgressMsgCallback cb);
+		void downloadOffline(IProgressMsgCallback cb);
+		void downloadEPK(IProgressMsgCallback cb);
+		ClientDataEntry getClientDataEntry();
+		LaunchConfigEntry getLaunchConfigEntry();
+		Map<EaglercraftUUID,Supplier<byte[]>> getBlobLoaders();
+	}
+
+	public final EnumDataType dataType;
+	public final BootAdapter bootAdapter;
+
+	public BootableClientEntry(EnumDataType dataType, BootAdapter bootAdapter) {
+		this.dataType = dataType;
+		this.bootAdapter = bootAdapter;
+	}
+
+	public static BootableClientEntry getOriginClient() {
+		final ClientDataEntry originClientDat;
+		final LaunchConfigEntry originLaunchDat;
+		final Map<EaglercraftUUID, Supplier<byte[]>> siteOriginLoader = new HashMap<>(2);
+		if(BootMenuEntryPoint.isSignedClient()) {
+			siteOriginLoader.put(BootMenuConstants.UUID_ORIGIN_SIGNED_SIGNATURE, BootMenuEntryPoint::getSignedClientSignature);
+			siteOriginLoader.put(BootMenuConstants.UUID_ORIGIN_SIGNED_BUNDLE, BootMenuEntryPoint::getSignedClientBundle);
+			originClientDat = new ClientDataEntry(EnumClientFormatType.EAGLER_SIGNED_OFFLINE,
+					BootMenuConstants.UUID_CLIENT_DATA_ORIGIN, BootMenuConstants.UUID_ORIGIN_SIGNED_BUNDLE, null,
+					BootMenuConstants.UUID_ORIGIN_SIGNED_SIGNATURE, null);
+			originLaunchDat = new LaunchConfigEntry(BootMenuConstants.UUID_CLIENT_LAUNCH_ORIGIN,
+					BootMenuConstants.UUID_CLIENT_DATA_ORIGIN,
+					BootMenuConstants.client_projectForkName + " " + BootMenuConstants.client_projectOriginRevision
+							+ " " + BootMenuConstants.client_projectOriginVersion,
+					EnumClientLaunchType.EAGLERX_SIGNED_V1, null, null, null, null, null,
+					BootMenuEntryPoint.getOriginLaunchOpts(), false);
+		}else {
+			siteOriginLoader.put(BootMenuConstants.UUID_ORIGIN_UNSIGNED_CLASSES_JS, BootMenuEntryPoint::getUnsignedClientClassesJS);
+			UnsignedClientEPKLoader loader = BootMenuEntryPoint.getUnsignedClientAssetsEPK();
+			siteOriginLoader.putAll(loader.loaders);
+			originClientDat = new ClientDataEntry(EnumClientFormatType.EAGLER_STANDARD_OFFLINE,
+					BootMenuConstants.UUID_CLIENT_DATA_ORIGIN, BootMenuConstants.UUID_ORIGIN_UNSIGNED_CLASSES_JS, null,
+					null, loader.list);
+			originLaunchDat = new LaunchConfigEntry(BootMenuConstants.UUID_CLIENT_LAUNCH_ORIGIN,
+						BootMenuConstants.UUID_CLIENT_DATA_ORIGIN,
+						BootMenuConstants.client_projectForkName + " " + BootMenuConstants.client_projectOriginRevision
+								+ " " + BootMenuConstants.client_projectOriginVersion,
+						EnumClientLaunchType.EAGLERX_V1, null, null, null, null, null,
+						BootMenuEntryPoint.getOriginLaunchOpts(), false);
+		}
+		return new BootableClientEntry(EnumDataType.SITE_ORIGIN, new BootAdapter() {
+
+			private final String displayName = BootMenuConstants.client_projectForkName + " " + BootMenuConstants.client_projectOriginRevision + " "
+					+ BootMenuConstants.client_projectOriginVersion + " (site origin)";
+
+			@Override
+			public String getDisplayName() {
+				return displayName;
+			}
+
+			@Override
+			public void bootClient(IProgressMsgCallback cb) {
+				BootMenuMain.continueBootToOriginClient(BootMenuMain::sanitizeEaglercraftXOpts);
+			}
+
+			@Override
+			public void downloadOffline(IProgressMsgCallback cb) {
+				OfflineDownloadFactory.downloadOffline(originLaunchDat, originClientDat, siteOriginLoader, cb);
+			}
+
+			@Override
+			public void downloadEPK(IProgressMsgCallback cb) {
+				EPKClientFactory.downloadEPKClient(originLaunchDat, originClientDat, siteOriginLoader, cb);
+			}
+
+			@Override
+			public ClientDataEntry getClientDataEntry() {
+				return originClientDat;
+			}
+
+			@Override
+			public LaunchConfigEntry getLaunchConfigEntry() {
+				return originLaunchDat;
+			}
+
+			@Override
+			public Map<EaglercraftUUID, Supplier<byte[]>> getBlobLoaders() {
+				return siteOriginLoader;
+			}
+
+		});
+	}
+
+	public static List<BootableClientEntry> enumerateBootableClients() {
+		List<BootableClientEntry> ret = new ArrayList<>(16);
+		final Map<EaglercraftUUID, Supplier<byte[]>> siteOriginLoader = new HashMap<>(2);
+		final ClientDataEntry originClientDat;
+		final LaunchConfigEntry originLaunchDat;
+		if(BootMenuEntryPoint.isSignedClient()) {
+			siteOriginLoader.put(BootMenuConstants.UUID_ORIGIN_SIGNED_SIGNATURE, BootMenuEntryPoint::getSignedClientSignature);
+			siteOriginLoader.put(BootMenuConstants.UUID_ORIGIN_SIGNED_BUNDLE, BootMenuEntryPoint::getSignedClientBundle);
+			originClientDat = new ClientDataEntry(EnumClientFormatType.EAGLER_SIGNED_OFFLINE,
+					BootMenuConstants.UUID_CLIENT_DATA_ORIGIN, BootMenuConstants.UUID_ORIGIN_SIGNED_BUNDLE, null,
+					BootMenuConstants.UUID_ORIGIN_SIGNED_SIGNATURE, null);
+			originLaunchDat = new LaunchConfigEntry(BootMenuConstants.UUID_CLIENT_LAUNCH_ORIGIN,
+					BootMenuConstants.UUID_CLIENT_DATA_ORIGIN,
+					BootMenuConstants.client_projectForkName + " " + BootMenuConstants.client_projectOriginRevision
+							+ " " + BootMenuConstants.client_projectOriginVersion,
+					EnumClientLaunchType.EAGLERX_SIGNED_V1, null, null, null, null, null,
+					BootMenuEntryPoint.getOriginLaunchOpts(), false);
+		}else {
+			siteOriginLoader.put(BootMenuConstants.UUID_ORIGIN_UNSIGNED_CLASSES_JS, BootMenuEntryPoint::getUnsignedClientClassesJS);
+			UnsignedClientEPKLoader loader = BootMenuEntryPoint.getUnsignedClientAssetsEPK();
+			siteOriginLoader.putAll(loader.loaders);
+			originClientDat = new ClientDataEntry(EnumClientFormatType.EAGLER_STANDARD_OFFLINE,
+					BootMenuConstants.UUID_CLIENT_DATA_ORIGIN, BootMenuConstants.UUID_ORIGIN_UNSIGNED_CLASSES_JS, null,
+					null, loader.list);
+			originLaunchDat = new LaunchConfigEntry(BootMenuConstants.UUID_CLIENT_LAUNCH_ORIGIN,
+						BootMenuConstants.UUID_CLIENT_DATA_ORIGIN,
+						BootMenuConstants.client_projectForkName + " " + BootMenuConstants.client_projectOriginRevision
+								+ " " + BootMenuConstants.client_projectOriginVersion,
+						EnumClientLaunchType.EAGLERX_V1, null, null, null, null, null,
+						BootMenuEntryPoint.getOriginLaunchOpts(), false);
+		}
+		ret.add(new BootableClientEntry(EnumDataType.SITE_ORIGIN, new BootAdapter() {
+
+			private final String displayName = BootMenuConstants.client_projectForkName + " " + BootMenuConstants.client_projectOriginRevision + " "
+					+ BootMenuConstants.client_projectOriginVersion + " (site origin)";
+
+			@Override
+			public String getDisplayName() {
+				return displayName;
+			}
+
+			@Override
+			public void bootClient(IProgressMsgCallback cb) {
+				BootMenuMain.continueBootToOriginClient(BootMenuMain::sanitizeEaglercraftXOpts);
+			}
+
+			@Override
+			public void downloadOffline(IProgressMsgCallback cb) {
+				OfflineDownloadFactory.downloadOffline(originLaunchDat, originClientDat, siteOriginLoader, cb);
+			}
+
+			@Override
+			public void downloadEPK(IProgressMsgCallback cb) {
+				EPKClientFactory.downloadEPKClient(originLaunchDat, originClientDat, siteOriginLoader, cb);
+			}
+
+			@Override
+			public ClientDataEntry getClientDataEntry() {
+				return originClientDat;
+			}
+
+			@Override
+			public LaunchConfigEntry getLaunchConfigEntry() {
+				return originLaunchDat;
+			}
+
+			@Override
+			public Map<EaglercraftUUID, Supplier<byte[]>> getBlobLoaders() {
+				return siteOriginLoader;
+			}
+
+		}));
+		for(final LaunchConfigEntry etr : BootMenuMain.bootMenuFatOfflineLoader.launchDatas) {
+			final ClientDataEntry etr2 = BootMenuConstants.UUID_CLIENT_DATA_ORIGIN.equals(etr.clientDataUUID)
+					? originClientDat
+					: BootMenuMain.bootMenuFatOfflineLoader.clientDatas.get(etr.clientDataUUID);
+			if(etr2 != null) {
+				Collection<EaglercraftUUID> refBlobs = etr2.getReferencedBlobs();
+				final Map<EaglercraftUUID, Supplier<byte[]>> loaderMap = new HashMap<>(2);
+				for(final EaglercraftUUID uuid : refBlobs) {
+					loaderMap.put(uuid, () -> {
+						Supplier<byte[]> sup = siteOriginLoader.get(uuid);
+						if(sup != null) {
+							byte[] ret2 = sup.get();
+							if(ret2 != null) {
+								return ret2;
+							}
+						}
+						return BootMenuMain.bootMenuFatOfflineLoader.loadDataBinary(uuid.toString());
+					});
+				}
+				ret.add(new BootableClientEntry(EnumDataType.EMBEDDED, new BootAdapter() {
+
+					private final String displayName = etr.displayName + " (embedded"
+							+ (etr.type == EnumClientLaunchType.EAGLERX_SIGNED_V1 ? ", signed)" : ")");
+
+					@Override
+					public String getDisplayName() {
+						return displayName;
+					}
+
+					@Override
+					public void bootClient(IProgressMsgCallback cb) {
+						ClientBootFactory.bootClient(etr, etr2, loaderMap, cb);
+					}
+
+					@Override
+					public void downloadOffline(IProgressMsgCallback cb) {
+						OfflineDownloadFactory.downloadOffline(etr, etr2, loaderMap, cb);
+					}
+
+					@Override
+					public void downloadEPK(IProgressMsgCallback cb) {
+						EPKClientFactory.downloadEPKClient(etr, etr2, loaderMap, cb);
+					}
+
+					@Override
+					public ClientDataEntry getClientDataEntry() {
+						return etr2;
+					}
+
+					@Override
+					public LaunchConfigEntry getLaunchConfigEntry() {
+						return etr;
+					}
+
+					@Override
+					public Map<EaglercraftUUID, Supplier<byte[]>> getBlobLoaders() {
+						return loaderMap;
+					}
+
+				}));
+			}
+		}
+		for(EaglercraftUUID etrUUID : BootMenuMain.bootMenuDataManager.launchDatasList) {
+			final LaunchConfigEntry etr = BootMenuMain.bootMenuDataManager.launchDatas.get(etrUUID);
+			if(etr != null) {
+				final ClientDataEntry etr2 = BootMenuConstants.UUID_CLIENT_DATA_ORIGIN.equals(etr.clientDataUUID)
+						? originClientDat
+						: BootMenuMain.bootMenuDataManager.clientDatas.get(etr.clientDataUUID);
+				if(etr2 != null) {
+					Collection<EaglercraftUUID> refBlobs = etr2.getReferencedBlobs();
+					final Map<EaglercraftUUID, Supplier<byte[]>> loaderMap = new HashMap<>(2);
+					for(final EaglercraftUUID uuid : refBlobs) {
+						loaderMap.put(uuid, () -> {
+							Supplier<byte[]> sup = siteOriginLoader.get(uuid);
+							if(sup != null) {
+								byte[] ret2 = sup.get();
+								if(ret2 != null) {
+									return ret2;
+								}
+							}
+							return BootMenuMain.bootMenuDatastore.getItem("blobs/" + uuid);
+						});
+					}
+					ret.add(new BootableClientEntry(EnumDataType.LOCAL_STORAGE, new BootAdapter() {
+
+						private final String displayName = etr.displayName + " (local storage"
+								+ (etr.type == EnumClientLaunchType.EAGLERX_SIGNED_V1 ? ", signed)" : ")");
+
+						@Override
+						public String getDisplayName() {
+							return displayName;
+						}
+
+						@Override
+						public void bootClient(IProgressMsgCallback cb) {
+							ClientBootFactory.bootClient(etr, etr2, loaderMap, cb);
+						}
+
+						@Override
+						public void downloadOffline(IProgressMsgCallback cb) {
+							OfflineDownloadFactory.downloadOffline(etr, etr2, loaderMap, cb);
+						}
+
+						@Override
+						public void downloadEPK(IProgressMsgCallback cb) {
+							EPKClientFactory.downloadEPKClient(etr, etr2, loaderMap, cb);
+						}
+
+						@Override
+						public ClientDataEntry getClientDataEntry() {
+							return etr2;
+						}
+
+						@Override
+						public LaunchConfigEntry getLaunchConfigEntry() {
+							return etr;
+						}
+
+						@Override
+						public Map<EaglercraftUUID, Supplier<byte[]>> getBlobLoaders() {
+							return loaderMap;
+						}
+
+					}));
+				}
+			}
+		}
+		return ret;
+	}
+
+	/**
+	 * returns true if uuidsList has changed
+	 */
+	public static boolean applyClientOrdering(List<EaglercraftUUID> uuidsList, List<BootableClientEntry> bootableClients) {
+		if(bootableClients.isEmpty()) return false;
+		
+		List<BootableClientEntry> bootableClientsCopy = new ArrayList<>(bootableClients);
+		Set<EaglercraftUUID> uuidsSet = new HashSet<>(uuidsList);
+		Map<EaglercraftUUID,BootableClientEntry> bootableClientsLookup = new HashMap<>(bootableClients.size());
+		bootableClients.clear();
+		
+		for(int i = 0, l = bootableClientsCopy.size(); i < l; ++i) {
+			BootableClientEntry etr = bootableClientsCopy.get(i);
+			bootableClientsLookup.put(etr.bootAdapter.getLaunchConfigEntry().uuid, etr);
+		}
+		
+		for(int i = 0, l = uuidsList.size(); i < l; ++i) {
+			BootableClientEntry etr = bootableClientsLookup.get(uuidsList.get(i));
+			if(etr != null) {
+				bootableClients.add(etr);
+			}
+		}
+		
+		boolean flag = false;
+		for(int i = 0, l = bootableClientsCopy.size(); i < l; ++i) {
+			BootableClientEntry etr = bootableClientsCopy.get(i);
+			EaglercraftUUID uuid = etr.bootAdapter.getLaunchConfigEntry().uuid;
+			if(!uuidsSet.contains(uuid)) {
+				bootableClients.add(etr);
+				uuidsList.add(uuid);
+				flag = true;
+			}
+		}
+		
+		return flag;
+	}
+
+}
diff --git a/sources/teavm-boot-menu/java/net/lax1dude/eaglercraft/v1_8/boot_menu/teavm/CheckboxListController.java b/sources/teavm-boot-menu/java/net/lax1dude/eaglercraft/v1_8/boot_menu/teavm/CheckboxListController.java
new file mode 100644
index 00000000..033ddb32
--- /dev/null
+++ b/sources/teavm-boot-menu/java/net/lax1dude/eaglercraft/v1_8/boot_menu/teavm/CheckboxListController.java
@@ -0,0 +1,108 @@
+package net.lax1dude.eaglercraft.v1_8.boot_menu.teavm;
+
+import java.util.Arrays;
+import java.util.List;
+
+import org.teavm.jso.dom.html.HTMLElement;
+
+import com.google.common.collect.Collections2;
+import com.google.common.collect.Iterators;
+import com.google.common.collect.Lists;
+
+/**
+ * Copyright (c) 2024 lax1dude. All Rights Reserved.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ * 
+ */
+public abstract class CheckboxListController<T extends SelectionListController.ListItem>
+		extends SelectionListController<SelectionListController.ListItem> {
+
+	protected static final SelectionListController.ListItem LIST_ITEM_CANCEL = new SelectionListController.ListItem() {
+		@Override
+		public String getName() {
+			return "Cancel";
+		}
+	};
+
+	protected static final SelectionListController.ListItem LIST_ITEM_DONE = new SelectionListController.ListItem() {
+		@Override
+		public String getName() {
+			return "Done";
+		}
+	};
+
+	protected static class ListItemWrapper implements SelectionListController.ListItem {
+
+		protected final SelectionListController.ListItem parent;
+
+		protected ListItemWrapper(SelectionListController.ListItem parent) {
+			this.parent = parent;
+		}
+
+		@Override
+		public String getName() {
+			return (parent.getAlwaysSelected() ? "[X] " : "[ ] ") + parent.getName();
+		}
+
+		@Override
+		public boolean getAlwaysSelected() {
+			return parent.getAlwaysSelected();
+		}
+
+	}
+
+	public CheckboxListController(HTMLElement parent, List<T> selectionList) {
+		super(parent, Lists.newArrayList(Iterators.concat(Iterators.transform(selectionList.iterator(), ListItemWrapper::new),
+						Arrays.asList(LIST_ITEM_CANCEL, LIST_ITEM_DONE).iterator())));
+	}
+
+	public List<T> getSelectedItems() {
+		return Lists.newArrayList(Collections2.transform(
+				Collections2.filter(selectionEnableList, (e) -> (e.userVal && !e.listItem.getAlwaysSelected())),
+				(e) -> (T) ((ListItemWrapper) e.listItem).parent));
+	}
+
+	protected void itemSelectedLow(ListItemInstance<SelectionListController.ListItem> item) {
+		if(item.listItem == LIST_ITEM_CANCEL) {
+			cancelSelected();
+		}else if(item.listItem == LIST_ITEM_DONE) {
+			doneSelected(getSelectedItems());
+		}else {
+			if(!item.listItem.getAlwaysSelected()) {
+				item.userVal = !item.userVal;
+				item.element.setInnerText((item.userVal ? "[X]" : "[ ]") + item.element.getInnerText().substring(3));
+			}
+		}
+	}
+
+	public void handleKeyDown(int keyCode) {
+		if(keyCode == KeyCodes.DOM_KEY_SPACE) {
+			if(currentSelected >= 0 && currentSelected < selectionEnableList.size()) {
+				if(!selectionEnableList.get(currentSelected).listItem.getAlwaysSelected()) {
+					fireSelect();
+				}
+			}
+			return;
+		}
+		super.handleKeyDown(keyCode);
+	}
+
+	@Override
+	protected final void itemSelected(SelectionListController.ListItem item) {
+	}
+
+	protected abstract void cancelSelected();
+
+	protected abstract void doneSelected(List<T> selectedItems);
+
+}
diff --git a/sources/teavm-boot-menu/java/net/lax1dude/eaglercraft/v1_8/boot_menu/teavm/ClientBootFactory.java b/sources/teavm-boot-menu/java/net/lax1dude/eaglercraft/v1_8/boot_menu/teavm/ClientBootFactory.java
new file mode 100644
index 00000000..9f74c45a
--- /dev/null
+++ b/sources/teavm-boot-menu/java/net/lax1dude/eaglercraft/v1_8/boot_menu/teavm/ClientBootFactory.java
@@ -0,0 +1,725 @@
+package net.lax1dude.eaglercraft.v1_8.boot_menu.teavm;
+
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.function.Supplier;
+
+import org.json.JSONArray;
+import org.json.JSONObject;
+import org.teavm.jso.JSBody;
+import org.teavm.jso.dom.html.HTMLDocument;
+import org.teavm.jso.dom.html.HTMLScriptElement;
+
+import net.lax1dude.eaglercraft.v1_8.Base64;
+import net.lax1dude.eaglercraft.v1_8.EagUtils;
+import net.lax1dude.eaglercraft.v1_8.EaglerInputStream;
+import net.lax1dude.eaglercraft.v1_8.EaglerOutputStream;
+import net.lax1dude.eaglercraft.v1_8.EaglerZLIB;
+import net.lax1dude.eaglercraft.v1_8.EaglercraftUUID;
+import net.lax1dude.eaglercraft.v1_8.cache.EaglerLoadingCache;
+import net.lax1dude.eaglercraft.v1_8.internal.teavm.TeaVMBlobURLHandle;
+import net.lax1dude.eaglercraft.v1_8.internal.teavm.TeaVMBlobURLManager;
+import net.lax1dude.eaglercraft.v1_8.log4j.LogManager;
+import net.lax1dude.eaglercraft.v1_8.log4j.Logger;
+import net.minecraft.nbt.CompressedStreamTools;
+import net.minecraft.nbt.JsonToNBT;
+import net.minecraft.nbt.NBTException;
+import net.minecraft.nbt.NBTTagCompound;
+
+/**
+ * Copyright (c) 2024 lax1dude. All Rights Reserved.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ * 
+ */
+public class ClientBootFactory {
+
+	private static final Logger logger = LogManager.getLogger("ClientBootFactory");
+
+	private static class UUIDStringPair {
+
+		private final EaglercraftUUID uuid;
+		private final String str;
+
+		private UUIDStringPair(EaglercraftUUID uuid, String str) {
+			this.uuid = uuid;
+			this.str = str;
+		}
+
+		@Override
+		public int hashCode() {
+			return (31 + uuid.hashCode()) * 31 + str.hashCode();
+		}
+
+		@Override
+		public boolean equals(Object obj) {
+			if(this == obj)
+				return true;
+			if(obj == null || !(obj instanceof UUIDStringPair))
+				return false;
+			UUIDStringPair other = (UUIDStringPair) obj;
+			return Objects.equals(str, other.str) && Objects.equals(uuid, other.uuid);
+		}
+
+	}
+
+	public static void bootClient(LaunchConfigEntry launchConf, ClientDataEntry clientData,
+			Map<EaglercraftUUID, Supplier<byte[]>> loaders, IProgressMsgCallback cb) {
+		if(launchConf.clearCookiesBeforeLaunch) {
+			BootMenuEntryPoint.clearCookies();
+		}
+		if(BootMenuConstants.UUID_CLIENT_DATA_ORIGIN.equals(clientData.uuid)) {
+			bootOriginClient(launchConf, clientData, cb);
+			return;
+		}
+		EaglerLoadingCache<EaglercraftUUID, byte[]> loadingCacheA = new EaglerLoadingCache<EaglercraftUUID, byte[]>((uuid) -> {
+			Supplier<byte[]> sup = loaders.get(uuid);
+			return sup != null ? sup.get() : null;
+		});
+		EaglerLoadingCache<UUIDStringPair, TeaVMBlobURLHandle> loadingCacheB = new EaglerLoadingCache<UUIDStringPair, TeaVMBlobURLHandle>((uuidMime) -> {
+			byte[] b = loadingCacheA.get(uuidMime.uuid);
+			return b != null ? TeaVMBlobURLManager.registerNewURLByte(b, uuidMime.str) : null;
+		});
+		switch(launchConf.type) {
+		case STANDARD_OFFLINE_V1:
+			if(clientData.type == EnumClientFormatType.EAGLER_STANDARD_OFFLINE) {
+				bootClientStandardOffline(launchConf, clientData, loadingCacheB, cb);
+			}else {
+				throw new UnsupportedOperationException("Wrong client data type " + clientData.type + " for STANDARD_OFFLINE_V1!");
+			}
+			break;
+		case EAGLERX_V1:
+			if(clientData.type == EnumClientFormatType.EAGLER_STANDARD_OFFLINE) {
+				bootClientEaglerX18(launchConf, clientData, loadingCacheB, cb);
+			}else {
+				throw new UnsupportedOperationException("Wrong client data type " + clientData.type + " for EAGLERX_V1!");
+			}
+			break;
+		case EAGLERX_SIGNED_V1:
+			if(clientData.type == EnumClientFormatType.EAGLER_SIGNED_OFFLINE) {
+				bootClientEaglerX18Signed(launchConf, clientData, loadingCacheA, loadingCacheB, cb);
+			}else {
+				throw new UnsupportedOperationException("Wrong client data type " + clientData.type + " for EAGLERX_SIGNED_V1!");
+			}
+			break;
+		case EAGLER_1_5_V1:
+			if(clientData.type == EnumClientFormatType.EAGLER_STANDARD_OFFLINE) {
+				bootClientEagler15Old(launchConf, clientData, loadingCacheB, cb);
+			}else {
+				throw new UnsupportedOperationException("Wrong client data type " + clientData.type + " for EAGLER_1_5_V1!");
+			}
+			break;
+		case EAGLER_1_5_V2:
+			if(clientData.type == EnumClientFormatType.EAGLER_STANDARD_1_5_OFFLINE) {
+				bootClientEagler15New(launchConf, clientData, loadingCacheA, loadingCacheB, cb);
+			}else {
+				throw new UnsupportedOperationException("Wrong client data type " + clientData.type + " for EAGLER_1_5_V2!");
+			}
+			break;
+		case EAGLER_BETA_V1:
+			if(clientData.type == EnumClientFormatType.EAGLER_STANDARD_OFFLINE) {
+				bootClientEaglerB13(launchConf, clientData, loadingCacheB, cb);
+			}else {
+				throw new UnsupportedOperationException("Wrong client data type " + clientData.type + " for EAGLER_1_5_V2!");
+			}
+			break;
+		case PEYTON_V1:
+			if(clientData.type == EnumClientFormatType.EAGLER_STANDARD_OFFLINE) {
+				bootClientPeytonIndev(launchConf, clientData, loadingCacheB, cb);
+			}else {
+				throw new UnsupportedOperationException("Wrong client data type " + clientData.type + " for PEYTON_V1!");
+			}
+			break;
+		case PEYTON_V2:
+			if(clientData.type == EnumClientFormatType.EAGLER_STANDARD_OFFLINE) {
+				bootClientPeytonAlphaBeta(launchConf, clientData, loadingCacheB, cb);
+			}else {
+				throw new UnsupportedOperationException("Wrong client data type " + clientData.type + " for PEYTON_V2!");
+			}
+			break;
+		}
+	}
+
+	private static void doUpdateMessage(IProgressMsgCallback cb, String str) {
+		logger.info(str);
+		cb.updateMessage(str);
+	}
+
+	@JSBody(params = { "mainName" }, script = "window[mainName] = null;")
+	private static native boolean clearMain(String mainName);
+
+	@JSBody(params = { "mainName" }, script = "return (typeof window[mainName] === \"function\");")
+	private static native boolean isMainReady(String mainName);
+
+	@JSBody(params = { "optsVarName", "optsVarJSON", "mainName", "blockUnsigned" }, script = "setTimeout(function() { window[optsVarName] = JSON.parse(optsVarJSON); if(blockUnsigned) window[optsVarName].bootMenuBlocksUnsignedClients = true; window[mainName](); }, 1);")
+	private static native void callMain(String optsVarName, String optsVarJSON, String mainName, boolean blockUnsigned);
+
+	@JSBody(params = { "clientSigURL", "clientPayloadURL", "launchOptsJSON", "blockUnsigned" }, script = "window.eaglercraftXOptsHints = JSON.parse(launchOptsJSON); if(blockUnsigned) window.eaglercraftXOptsHints.bootMenuBlocksUnsignedClients = true; window.eaglercraftXClientSignature = clientSigURL; window.eaglercraftXClientBundle = clientPayloadURL;")
+	private static native void setupSignedClientOpts(String clientSigURL, String clientPayloadURL, String launchOptsJSON, boolean blockUnsigned);
+
+	@JSBody(params = { "optsVarName", "containerId", "assetsEPKURL", "b64Opts", "joinServer", "mainName", "blockUnsigned" }, script = "setTimeout(function() { window[optsVarName] = [ containerId, assetsEPKURL, b64Opts ]; if(blockUnsigned && (typeof window.eaglercraftXOpts === \"object\")) window.eaglercraftXOpts.bootMenuBlocksUnsignedClients = true; if(joinServer.length > 0) window[optsVarName].push(joinServer); window[mainName](); }, 1);")
+	private static native void callMainOld15(String optsVarName, String containerId, String assetsEPKURL, String b64Opts, String joinServer, String mainName, boolean blockUnsigned);
+
+	@JSBody(params = { "optsVarName", "containerId", "assetsEPKURL", "joinServer", "mainName", "blockUnsigned" }, script = "setTimeout(function() { window[optsVarName] = [ containerId, assetsEPKURL ]; if(blockUnsigned && (typeof window.eaglercraftXOpts === \"object\")) window.eaglercraftXOpts.bootMenuBlocksUnsignedClients = true; if(joinServer.length > 0) window[optsVarName].push(joinServer); window[mainName](); }, 1);")
+	private static native void callMainOldB13(String optsVarName, String containerId, String assetsEPKURL, String joinServer, String mainName, boolean blockUnsigned);
+
+	@JSBody(params = { "optsVarName", "optsVarJSON", "blockUnsigned" }, script = "window[optsVarName] = JSON.parse(optsVarJSON); if(blockUnsigned) window[optsVarName].bootMenuBlocksUnsignedClients = true;")
+	private static native void setJSONOpts(String optsVarName, String optsVarJSON, boolean blockUnsigned);
+
+	private static void bootOriginClient(LaunchConfigEntry launchConf, ClientDataEntry clientData,
+			IProgressMsgCallback cb) {
+		doUpdateMessage(cb, "Preparing launch opts...");
+		JSONObject launchOpts = new JSONObject(launchConf.launchOpts);
+		launchOpts.put("container", BootMenuEntryPoint.getOriginContainer());
+		launchOpts.put("assetsURI", BootMenuEntryPoint.getUnsignedClientAssetsEPKRaw());
+		final String launchOptsStr = RelayRandomizeHelper.replaceRelayMacroWithConstant(launchOpts.toString());
+		BootMenuMain.continueBootToOriginClient(() -> {
+			setJSONOpts("eaglercraftXOpts", launchOptsStr, IBootMenuConfigAdapter.instance.isBootMenuBlocksUnsignedClients());
+		});
+	}
+
+	private static void bootClientEaglerX18(LaunchConfigEntry launchConf, ClientDataEntry clientData,
+			EaglerLoadingCache<UUIDStringPair, TeaVMBlobURLHandle> loadingCache, IProgressMsgCallback cb) {
+		boolean blockUnsigned = IBootMenuConfigAdapter.instance.isBootMenuBlocksUnsignedClients();
+		if(blockUnsigned) {
+			throw new UnsignedBootException();
+		}
+		JSONObject launchOpts = new JSONObject(launchConf.launchOpts);
+		doUpdateMessage(cb, "Resolving classes.js (" + clientData.mainPayload + ")");
+		TeaVMBlobURLHandle classesJSURL = loadingCache.get(new UUIDStringPair(clientData.mainPayload, "text/javascript"));
+		List<TeaVMBlobURLHandle> toCleanOnException = new ArrayList<>();
+		if(classesJSURL == null) {
+			String msg = "Could not resolve classes.js! (" + clientData.mainPayload + ")";
+			logger.error(msg);
+			throw new NullPointerException(msg);
+		}
+		toCleanOnException.add(classesJSURL);
+		JSONArray epkFiles = new JSONArray();
+		for(EPKDataEntry etr : clientData.epkFiles) {
+			doUpdateMessage(cb, "Resolving assets.epk (" + etr.dataUUID + ", path: /" + etr.extractTo + ")");
+			TeaVMBlobURLHandle epkURL = loadingCache.get(new UUIDStringPair(etr.dataUUID, "application/octet-stream"));
+			if(epkURL == null) {
+				for(TeaVMBlobURLHandle url : toCleanOnException) {
+					try {
+						TeaVMBlobURLManager.releaseURL(url);
+					}catch(Throwable t) {
+					}
+				}
+				String msg = "Could not resolve assets.epk! (" + etr.dataUUID + ", path: /" + etr.extractTo + ")";
+				logger.error(msg);
+				throw new NullPointerException(msg);
+			}
+			toCleanOnException.add(epkURL);
+			JSONObject epkEntry = new JSONObject();
+			epkEntry.put("url", epkURL.toExternalForm());
+			epkEntry.put("path", etr.extractTo);
+			epkFiles.put(epkEntry);
+		}
+		launchOpts.put("assetsURI", epkFiles);
+		doUpdateMessage(cb, "Launching client...");
+		BootMenuMain.runLaterMS(() -> {
+			clearMain("main");
+			HTMLDocument docTemp = BootMenuMain.doc;
+			launchOpts.put("container", BootMenuMain.createRootElementForClient());
+			final String launchOptsStr = RelayRandomizeHelper.replaceRelayMacroWithConstant(launchOpts.toString());
+			HTMLScriptElement scriptElement = (HTMLScriptElement)docTemp.createElement("script");
+			scriptElement.addEventListener("load", (evt) -> {
+				BootMenuMain.runLater(() -> {
+					while(!isMainReady("main")) {
+						logger.error("main function is not available yet! waiting 250ms...");
+						EagUtils.sleep(250l);
+					}
+					BootMenuMain.stopEventLoop();
+					callMain("eaglercraftXOpts", launchOptsStr, "main", blockUnsigned);
+				});
+			});
+			scriptElement.setType("text/javascript");
+			scriptElement.setSrc(classesJSURL.toExternalForm());
+			docTemp.getHead().appendChild(scriptElement);
+		}, 250);
+	}
+
+	private static void bootClientEaglerX18Signed(LaunchConfigEntry launchConf, ClientDataEntry clientData,
+			EaglerLoadingCache<EaglercraftUUID, byte[]> loadingCacheBytes,
+			EaglerLoadingCache<UUIDStringPair, TeaVMBlobURLHandle> loadingCache, IProgressMsgCallback cb) {
+		JSONObject launchOpts = new JSONObject(launchConf.launchOpts);
+		if(!launchOpts.has("hintsVersion")) {
+			launchOpts.put("hintsVersion", 1);
+		}
+		doUpdateMessage(cb, "Resolving client signature (" + clientData.clientSignature + ")");
+		byte[] clientSigBytes = loadingCacheBytes.get(clientData.clientSignature);
+		final TeaVMBlobURLHandle clientSigURL = loadingCache.get(new UUIDStringPair(clientData.clientSignature, "application/octet-stream"));
+		List<TeaVMBlobURLHandle> toCleanOnException = new ArrayList<>();
+		if(clientSigURL == null) {
+			clientSigBytes = null;
+			String msg = "Could not resolve client signature! (" + clientData.clientSignature + ")";
+			logger.error(msg);
+			throw new NullPointerException(msg);
+		}
+		toCleanOnException.add(clientSigURL);
+		doUpdateMessage(cb, "Resolving client payload (" + clientData.mainPayload + ")");
+		byte[] clientPayloadBytes = loadingCacheBytes.get(clientData.mainPayload);
+		final TeaVMBlobURLHandle clientPayloadURL = loadingCache.get(new UUIDStringPair(clientData.mainPayload, "application/octet-stream"));
+		if(clientPayloadURL == null) {
+			clientSigBytes = null;
+			clientPayloadBytes = null;
+			for(TeaVMBlobURLHandle url : toCleanOnException) {
+				try {
+					TeaVMBlobURLManager.releaseURL(url);
+				}catch(Throwable t) {
+				}
+			}
+			String msg = "Could not resolve client payload! (" + clientData.mainPayload + ")";
+			logger.error(msg);
+			throw new NullPointerException(msg);
+		}
+		toCleanOnException.add(clientPayloadURL);
+		boolean blockUnsigned = IBootMenuConfigAdapter.instance.isBootMenuBlocksUnsignedClients();
+		if(blockUnsigned) {
+			doUpdateMessage(cb, "Verifying signature...");
+			boolean valid = SignatureCheckHelper.checkSignatureValid(clientSigBytes, clientPayloadBytes);
+			if(!valid) {
+				for(TeaVMBlobURLHandle url : toCleanOnException) {
+					try {
+						TeaVMBlobURLManager.releaseURL(url);
+					}catch(Throwable t) {
+					}
+				}
+				throw new UnsignedBootException();
+			}
+		}
+		doUpdateMessage(cb, "Decompressing payload...");
+		EaglerOutputStream bao = new EaglerOutputStream(0x1000000);
+		try(InputStream is = EaglerZLIB.newGZIPInputStream(new EaglerInputStream(clientPayloadBytes))) {
+			byte[] copybuffer = new byte[16384];
+			int i;
+			while((i = is.read(copybuffer)) != -1) {
+				bao.write(copybuffer, 0, i);
+			}
+		}catch(IOException ex) {
+			clientSigBytes = null;
+			clientPayloadBytes = null;
+			for(TeaVMBlobURLHandle url : toCleanOnException) {
+				try {
+					TeaVMBlobURLManager.releaseURL(url);
+				}catch(Throwable t) {
+				}
+			}
+			throw new IllegalArgumentException("Could not decompress signed client payload!");
+		}
+		byte[] decompressed = bao.toByteArray();
+		bao = null;
+		clientSigBytes = null;
+		clientPayloadBytes = null;
+		final TeaVMBlobURLHandle clientPayloadURLDecompress = TeaVMBlobURLManager.registerNewURLByte(decompressed, "text/javascript");
+		toCleanOnException.add(clientPayloadURLDecompress);
+		doUpdateMessage(cb, "Launching client...");
+		BootMenuMain.runLaterMS(() -> {
+			HTMLDocument docTemp = BootMenuMain.doc;
+			launchOpts.put("container", BootMenuMain.createRootElementForClient());
+			final String launchOptsStr = RelayRandomizeHelper.replaceRelayMacroWithConstant(launchOpts.toString());
+			setupSignedClientOpts(clientSigURL.toExternalForm(), clientPayloadURL.toExternalForm(), launchOptsStr, blockUnsigned);
+			HTMLScriptElement scriptElement = (HTMLScriptElement)docTemp.createElement("script");
+			scriptElement.setType("text/javascript");
+			scriptElement.setSrc(clientPayloadURLDecompress.toExternalForm());
+			docTemp.getHead().appendChild(scriptElement);
+			BootMenuMain.stopEventLoop();
+		}, 250);
+	}
+
+	private static void bootClientEagler15New(LaunchConfigEntry launchConf, ClientDataEntry clientData,
+			EaglerLoadingCache<EaglercraftUUID, byte[]> loadingCacheBytes,
+			EaglerLoadingCache<UUIDStringPair, TeaVMBlobURLHandle> loadingCache, IProgressMsgCallback cb) {
+		boolean blockUnsigned = IBootMenuConfigAdapter.instance.isBootMenuBlocksUnsignedClients();
+		if(blockUnsigned) {
+			throw new UnsignedBootException();
+		}
+		if(clientData.epkFiles.size() != 1) {
+			throw new UnsupportedOperationException("Wrong number of EPK files: " + clientData.epkFiles.size());
+		}
+		JSONObject launchOpts = new JSONObject(launchConf.launchOpts);
+		doUpdateMessage(cb, "Resolving classes.js (" + clientData.mainPayload + ")");
+		TeaVMBlobURLHandle classesJSURL = loadingCache.get(new UUIDStringPair(clientData.mainPayload, "text/javascript"));
+		List<TeaVMBlobURLHandle> toCleanOnException = new ArrayList<>();
+		if(classesJSURL == null) {
+			String msg = "Could not resolve classes.js! (" + clientData.mainPayload + ")";
+			logger.error(msg);
+			throw new NullPointerException(msg);
+		}
+		toCleanOnException.add(classesJSURL);
+		doUpdateMessage(cb, "Resolving classes_server.js (" + clientData.integratedServer + ")");
+		byte[] classesServerJS = loadingCacheBytes.get(clientData.integratedServer);
+		if(classesServerJS == null) {
+			for(TeaVMBlobURLHandle url : toCleanOnException) {
+				try {
+					TeaVMBlobURLManager.releaseURL(url);
+				}catch(Throwable t) {
+				}
+			}
+			String msg = "Could not resolve classes_server.js! (" + clientData.integratedServer + ")";
+			logger.error(msg);
+			throw new NullPointerException(msg);
+		}
+		classesServerJS = OfflineDownloadFactory.removeUseStrict(classesServerJS);
+		byte[] appendToClassesServerJS = "\"use strict\";var eaglercraftServerOpts;onmessage = function(o) { eaglercraftServerOpts = o.data; main(); };".getBytes(StandardCharsets.UTF_8);
+		byte[] concatClassesServerJS = new byte[classesServerJS.length + appendToClassesServerJS.length];
+		System.arraycopy(appendToClassesServerJS, 0, concatClassesServerJS, 0, appendToClassesServerJS.length);
+		System.arraycopy(classesServerJS, 0, concatClassesServerJS, appendToClassesServerJS.length, classesServerJS.length);
+		TeaVMBlobURLHandle classesServerJSURL = TeaVMBlobURLManager.registerNewURLByte(concatClassesServerJS, "text/javascript");
+		toCleanOnException.add(classesServerJSURL);
+		launchOpts.put("serverWorkerURI", classesServerJSURL);
+		doUpdateMessage(cb, "Resolving assets.epk (" + clientData.epkFiles.get(0).dataUUID + ")");
+		TeaVMBlobURLHandle assetsEPKURL = loadingCache.get(new UUIDStringPair(clientData.epkFiles.get(0).dataUUID, "application/octet-stream"));
+		if(assetsEPKURL == null) {
+			for(TeaVMBlobURLHandle url : toCleanOnException) {
+				try {
+					TeaVMBlobURLManager.releaseURL(url);
+				}catch(Throwable t) {
+				}
+			}
+			String msg = "Could not resolve assets.epk! (" + clientData.epkFiles.get(0).dataUUID + ")";
+			logger.error(msg);
+			throw new NullPointerException(msg);
+		}
+		toCleanOnException.add(assetsEPKURL);
+		launchOpts.put("assetsURI", assetsEPKURL.toExternalForm());
+		doUpdateMessage(cb, "Launching client...");
+		BootMenuMain.runLaterMS(() -> {
+			clearMain("main");
+			HTMLDocument docTemp = BootMenuMain.doc;
+			launchOpts.put("container", BootMenuMain.createRootElementForClient());
+			final String launchOptsStr = RelayRandomizeHelper.replaceRelayMacroWithConstant(launchOpts.toString());
+			HTMLScriptElement scriptElement = (HTMLScriptElement)docTemp.createElement("script");
+			scriptElement.addEventListener("load", (evt) -> {
+				BootMenuMain.runLater(() -> {
+					while(!isMainReady("main")) {
+						logger.error("main function is not available yet! waiting 250ms...");
+						EagUtils.sleep(250l);
+					}
+					BootMenuMain.stopEventLoop();
+					callMain("eaglercraftOpts", launchOptsStr, "main", blockUnsigned);
+				});
+			});
+			scriptElement.setType("text/javascript");
+			scriptElement.setSrc(classesJSURL.toExternalForm());
+			docTemp.getHead().appendChild(scriptElement);
+		}, 250);
+	}
+
+	private static void bootClientEagler15Old(LaunchConfigEntry launchConf, ClientDataEntry clientData,
+			EaglerLoadingCache<UUIDStringPair, TeaVMBlobURLHandle> loadingCache, IProgressMsgCallback cb) {
+		boolean blockUnsigned = IBootMenuConfigAdapter.instance.isBootMenuBlocksUnsignedClients();
+		if(blockUnsigned) {
+			throw new UnsignedBootException();
+		}
+		final String b64Opts = translateNBTOpts(launchConf.launchOpts);
+		if(clientData.epkFiles.size() != 1) {
+			throw new UnsupportedOperationException("Wrong number of EPK files: " + clientData.epkFiles.size());
+		}
+		doUpdateMessage(cb, "Resolving classes.js (" + clientData.mainPayload + ")");
+		final TeaVMBlobURLHandle classesJSURL = loadingCache.get(new UUIDStringPair(clientData.mainPayload, "text/javascript"));
+		List<TeaVMBlobURLHandle> toCleanOnException = new ArrayList<>();
+		if(classesJSURL == null) {
+			String msg = "Could not resolve classes.js! (" + clientData.mainPayload + ")";
+			logger.error(msg);
+			throw new NullPointerException(msg);
+		}
+		toCleanOnException.add(classesJSURL);
+		doUpdateMessage(cb, "Resolving assets.epk (" + clientData.epkFiles.get(0) + ")");
+		final TeaVMBlobURLHandle assetsEPKURL = loadingCache.get(new UUIDStringPair(clientData.epkFiles.get(0).dataUUID, "application/octet-stream"));
+		if(assetsEPKURL == null) {
+			for(TeaVMBlobURLHandle url : toCleanOnException) {
+				try {
+					TeaVMBlobURLManager.releaseURL(url);
+				}catch(Throwable t) {
+				}
+			}
+			String msg = "Could not resolve assets.epk! (" + clientData.epkFiles.get(0).dataUUID + ")";
+			logger.error(msg);
+			throw new NullPointerException(msg);
+		}
+		toCleanOnException.add(assetsEPKURL);
+		doUpdateMessage(cb, "Launching client...");
+		BootMenuMain.runLaterMS(() -> {
+			clearMain("main");
+			HTMLDocument docTemp = BootMenuMain.doc;
+			final String container = BootMenuMain.createRootElementForClient();
+			HTMLScriptElement scriptElement = (HTMLScriptElement)docTemp.createElement("script");
+			scriptElement.addEventListener("load", (evt) -> {
+				BootMenuMain.runLater(() -> {
+					while(!isMainReady("main")) {
+						logger.error("main function is not available yet! waiting 250ms...");
+						EagUtils.sleep(250l);
+					}
+					BootMenuMain.stopEventLoop();
+					callMainOld15("minecraftOpts", container, assetsEPKURL.toExternalForm(), b64Opts, launchConf.joinServer, "main", blockUnsigned);
+				});
+			});
+			scriptElement.setType("text/javascript");
+			scriptElement.setSrc(classesJSURL.toExternalForm());
+			docTemp.getHead().appendChild(scriptElement);
+		}, 250);
+	}
+
+	static String translateNBTOpts(String opts) {
+		opts = opts.trim();
+		if(!opts.startsWith("[NBT]") || !opts.endsWith("[/NBT]")) {
+			throw new IllegalArgumentException("Eaglercraft opts are not in NBT format!");
+		}
+		NBTTagCompound readTag;
+		try {
+			readTag = JsonToNBT.getTagFromJson(opts.substring(5, opts.length() - 6).trim());
+		} catch (NBTException e) {
+			throw new IllegalArgumentException("Eaglercraft opts are invalid: " + e.getMessage());
+		}
+		EaglerOutputStream bao = new EaglerOutputStream(256);
+		try {
+			CompressedStreamTools.write(readTag, new DataOutputStream(bao));
+		} catch (IOException e) {
+			throw new RuntimeException("Could not write NBT tag compound!");
+		}
+		return Base64.encodeBase64String(bao.toByteArray());
+	}
+
+	private static void bootClientEaglerB13(LaunchConfigEntry launchConf, ClientDataEntry clientData,
+			EaglerLoadingCache<UUIDStringPair, TeaVMBlobURLHandle> loadingCache, IProgressMsgCallback cb) {
+		boolean blockUnsigned = IBootMenuConfigAdapter.instance.isBootMenuBlocksUnsignedClients();
+		if(blockUnsigned) {
+			throw new UnsignedBootException();
+		}
+		if(clientData.epkFiles.size() != 1) {
+			throw new UnsupportedOperationException("Wrong number of EPK files: " + clientData.epkFiles.size());
+		}
+		doUpdateMessage(cb, "Resolving classes.js (" + clientData.mainPayload + ")");
+		final TeaVMBlobURLHandle classesJSURL = loadingCache.get(new UUIDStringPair(clientData.mainPayload, "text/javascript"));
+		List<TeaVMBlobURLHandle> toCleanOnException = new ArrayList<>();
+		if(classesJSURL == null) {
+			String msg = "Could not resolve classes.js! (" + clientData.mainPayload + ")";
+			logger.error(msg);
+			throw new NullPointerException(msg);
+		}
+		toCleanOnException.add(classesJSURL);
+		doUpdateMessage(cb, "Resolving assets.epk (" + clientData.epkFiles.get(0) + ")");
+		final TeaVMBlobURLHandle assetsEPKURL = loadingCache.get(new UUIDStringPair(clientData.epkFiles.get(0).dataUUID, "application/octet-stream"));
+		if(assetsEPKURL == null) {
+			for(TeaVMBlobURLHandle url : toCleanOnException) {
+				try {
+					TeaVMBlobURLManager.releaseURL(url);
+				}catch(Throwable t) {
+				}
+			}
+			String msg = "Could not resolve assets.epk! (" + clientData.epkFiles.get(0).dataUUID + ")";
+			logger.error(msg);
+			throw new NullPointerException(msg);
+		}
+		toCleanOnException.add(assetsEPKURL);
+		doUpdateMessage(cb, "Launching client...");
+		BootMenuMain.runLaterMS(() -> {
+			clearMain("main");
+			HTMLDocument docTemp = BootMenuMain.doc;
+			final String container = BootMenuMain.createRootElementForClient();
+			HTMLScriptElement scriptElement = (HTMLScriptElement)docTemp.createElement("script");
+			scriptElement.addEventListener("load", (evt) -> {
+				BootMenuMain.runLater(() -> {
+					while(!isMainReady("main")) {
+						logger.error("main function is not available yet! waiting 250ms...");
+						EagUtils.sleep(250l);
+					}
+					BootMenuMain.stopEventLoop();
+					callMainOldB13("minecraftOpts", container, assetsEPKURL.toExternalForm(), launchConf.joinServer, "main", blockUnsigned);
+				});
+			});
+			scriptElement.setType("text/javascript");
+			scriptElement.setSrc(classesJSURL.toExternalForm());
+			docTemp.getHead().appendChild(scriptElement);
+		}, 250);
+	}
+
+	private static void bootClientPeytonAlphaBeta(LaunchConfigEntry launchConf, ClientDataEntry clientData,
+			EaglerLoadingCache<UUIDStringPair, TeaVMBlobURLHandle> loadingCache, IProgressMsgCallback cb) {
+		boolean blockUnsigned = IBootMenuConfigAdapter.instance.isBootMenuBlocksUnsignedClients();
+		if(blockUnsigned) {
+			throw new UnsignedBootException();
+		}
+		if(clientData.epkFiles.size() != 1) {
+			throw new UnsupportedOperationException("Wrong number of EPK files: " + clientData.epkFiles.size());
+		}
+		JSONObject launchOpts = new JSONObject(launchConf.launchOpts);
+		doUpdateMessage(cb, "Resolving classes.js (" + clientData.mainPayload + ")");
+		final TeaVMBlobURLHandle classesJSURL = loadingCache.get(new UUIDStringPair(clientData.mainPayload, "text/javascript"));
+		List<TeaVMBlobURLHandle> toCleanOnException = new ArrayList<>();
+		if(classesJSURL == null) {
+			String msg = "Could not resolve classes.js! (" + clientData.mainPayload + ")";
+			logger.error(msg);
+			throw new NullPointerException(msg);
+		}
+		toCleanOnException.add(classesJSURL);
+		doUpdateMessage(cb, "Resolving assets.epk (" + clientData.epkFiles.get(0) + ")");
+		final TeaVMBlobURLHandle assetsEPKURL = loadingCache.get(new UUIDStringPair(clientData.epkFiles.get(0).dataUUID, "application/octet-stream"));
+		if(assetsEPKURL == null) {
+			for(TeaVMBlobURLHandle url : toCleanOnException) {
+				try {
+					TeaVMBlobURLManager.releaseURL(url);
+				}catch(Throwable t) {
+				}
+			}
+			String msg = "Could not resolve assets.epk! (" + clientData.epkFiles.get(0).dataUUID + ")";
+			logger.error(msg);
+			throw new NullPointerException(msg);
+		}
+		toCleanOnException.add(assetsEPKURL);
+		launchOpts.put("assetsLocation", assetsEPKURL.toExternalForm());
+		doUpdateMessage(cb, "Launching client...");
+		BootMenuMain.runLaterMS(() -> {
+			clearMain("main");
+			HTMLDocument docTemp = BootMenuMain.doc;
+			launchOpts.put("gameContainer", BootMenuMain.createRootElementForClient());
+			final String launchOptsStr = launchOpts.toString();
+			HTMLScriptElement scriptElement = (HTMLScriptElement)docTemp.createElement("script");
+			scriptElement.addEventListener("load", (evt) -> {
+				BootMenuMain.runLater(() -> {
+					while(!isMainReady("main")) {
+						logger.error("main function is not available yet! waiting 250ms...");
+						EagUtils.sleep(250l);
+					}
+					BootMenuMain.stopEventLoop();
+					callMain("config", launchOptsStr, "main", blockUnsigned);
+				});
+			});
+			scriptElement.setType("text/javascript");
+			scriptElement.setSrc(classesJSURL.toExternalForm());
+			docTemp.getHead().appendChild(scriptElement);
+		}, 250);
+	}
+
+	private static void bootClientPeytonIndev(LaunchConfigEntry launchConf, ClientDataEntry clientData,
+			EaglerLoadingCache<UUIDStringPair, TeaVMBlobURLHandle> loadingCache, IProgressMsgCallback cb) {
+		boolean blockUnsigned = IBootMenuConfigAdapter.instance.isBootMenuBlocksUnsignedClients();
+		if(blockUnsigned) {
+			throw new UnsignedBootException();
+		}
+		if(clientData.epkFiles.size() != 1) {
+			throw new UnsupportedOperationException("Wrong number of EPK files: " + clientData.epkFiles.size());
+		}
+		doUpdateMessage(cb, "Resolving classes.js (" + clientData.mainPayload + ")");
+		final TeaVMBlobURLHandle classesJSURL = loadingCache.get(new UUIDStringPair(clientData.mainPayload, "text/javascript"));
+		List<TeaVMBlobURLHandle> toCleanOnException = new ArrayList<>();
+		if(classesJSURL == null) {
+			String msg = "Could not resolve classes.js! (" + clientData.mainPayload + ")";
+			logger.error(msg);
+			throw new NullPointerException(msg);
+		}
+		toCleanOnException.add(classesJSURL);
+		doUpdateMessage(cb, "Resolving assets.epk (" + clientData.epkFiles.get(0) + ")");
+		final TeaVMBlobURLHandle assetsEPKURL = loadingCache.get(new UUIDStringPair(clientData.epkFiles.get(0).dataUUID, "application/octet-stream"));
+		if(assetsEPKURL == null) {
+			for(TeaVMBlobURLHandle url : toCleanOnException) {
+				try {
+					TeaVMBlobURLManager.releaseURL(url);
+				}catch(Throwable t) {
+				}
+			}
+			String msg = "Could not resolve assets.epk! (" + clientData.epkFiles.get(0).dataUUID + ")";
+			logger.error(msg);
+			throw new NullPointerException(msg);
+		}
+		toCleanOnException.add(assetsEPKURL);
+		doUpdateMessage(cb, "Launching client...");
+		BootMenuMain.runLaterMS(() -> {
+			clearMain("main");
+			HTMLDocument docTemp = BootMenuMain.doc;
+			final String container = BootMenuMain.createRootElementForClient();
+			HTMLScriptElement scriptElement = (HTMLScriptElement)docTemp.createElement("script");
+			scriptElement.addEventListener("load", (evt) -> {
+				BootMenuMain.runLater(() -> {
+					while(!isMainReady("main")) {
+						logger.error("main function is not available yet! waiting 250ms...");
+						EagUtils.sleep(250l);
+					}
+					BootMenuMain.stopEventLoop();
+					callMainOldB13("classicConfig", container, assetsEPKURL.toExternalForm(), "", "main", blockUnsigned);
+				});
+			});
+			scriptElement.setType("text/javascript");
+			scriptElement.setSrc(classesJSURL.toExternalForm());
+			docTemp.getHead().appendChild(scriptElement);
+		}, 250);
+	}
+
+	private static void bootClientStandardOffline(LaunchConfigEntry launchConf, ClientDataEntry clientData,
+			EaglerLoadingCache<UUIDStringPair, TeaVMBlobURLHandle> loadingCache, IProgressMsgCallback cb) {
+		boolean blockUnsigned = IBootMenuConfigAdapter.instance.isBootMenuBlocksUnsignedClients();
+		if(blockUnsigned) {
+			throw new UnsignedBootException();
+		}
+		JSONObject launchOpts = new JSONObject(launchConf.launchOpts);
+		doUpdateMessage(cb, "Resolving classes.js (" + clientData.mainPayload + ")");
+		TeaVMBlobURLHandle classesJSURL = loadingCache.get(new UUIDStringPair(clientData.mainPayload, "text/javascript"));
+		List<TeaVMBlobURLHandle> toCleanOnException = new ArrayList<>();
+		if(classesJSURL == null) {
+			String msg = "Could not resolve classes.js! (" + clientData.mainPayload + ")";
+			logger.error(msg);
+			throw new NullPointerException(msg);
+		}
+		toCleanOnException.add(classesJSURL);
+		JSONArray epkFiles = new JSONArray();
+		for(EPKDataEntry etr : clientData.epkFiles) {
+			doUpdateMessage(cb, "Resolving assets.epk (" + etr.dataUUID + ", path: /" + etr.extractTo + ")");
+			TeaVMBlobURLHandle epkURL = loadingCache.get(new UUIDStringPair(etr.dataUUID, "application/octet-stream"));
+			if(epkURL == null) {
+				for(TeaVMBlobURLHandle url : toCleanOnException) {
+					try {
+						TeaVMBlobURLManager.releaseURL(url);
+					}catch(Throwable t) {
+					}
+				}
+				String msg = "Could not resolve assets.epk! (" + etr.dataUUID + ", path: /" + etr.extractTo + ")";
+				logger.error(msg);
+				throw new NullPointerException(msg);
+			}
+			toCleanOnException.add(epkURL);
+			JSONObject epkEntry = new JSONObject();
+			epkEntry.put("url", epkURL.toExternalForm());
+			epkEntry.put("path", etr.extractTo);
+			epkFiles.put(epkEntry);
+		}
+		launchOpts.put(launchConf.launchOptsAssetsURIVar, epkFiles);
+		doUpdateMessage(cb, "Launching client...");
+		BootMenuMain.runLaterMS(() -> {
+			clearMain("main");
+			HTMLDocument docTemp = BootMenuMain.doc;
+			launchOpts.put(launchConf.launchOptsContainerVar, BootMenuMain.createRootElementForClient());
+			final String launchOptsStr = RelayRandomizeHelper.replaceRelayMacroWithConstant(launchOpts.toString());
+			HTMLScriptElement scriptElement = (HTMLScriptElement)docTemp.createElement("script");
+			scriptElement.addEventListener("load", (evt) -> {
+				BootMenuMain.runLater(() -> {
+					while(!isMainReady("main")) {
+						logger.error("main function is not available yet! waiting 250ms...");
+						EagUtils.sleep(250l);
+					}
+					BootMenuMain.stopEventLoop();
+					callMain(launchConf.launchOptsVar, launchOptsStr, launchConf.mainFunction, blockUnsigned);
+				});
+			});
+			scriptElement.setType("text/javascript");
+			scriptElement.setSrc(classesJSURL.toExternalForm());
+			docTemp.getHead().appendChild(scriptElement);
+		}, 250);
+	}
+
+}
diff --git a/sources/teavm-boot-menu/java/net/lax1dude/eaglercraft/v1_8/boot_menu/teavm/ClientDataEntry.java b/sources/teavm-boot-menu/java/net/lax1dude/eaglercraft/v1_8/boot_menu/teavm/ClientDataEntry.java
new file mode 100644
index 00000000..9819f7b5
--- /dev/null
+++ b/sources/teavm-boot-menu/java/net/lax1dude/eaglercraft/v1_8/boot_menu/teavm/ClientDataEntry.java
@@ -0,0 +1,152 @@
+package net.lax1dude.eaglercraft.v1_8.boot_menu.teavm;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+import org.json.JSONArray;
+import org.json.JSONObject;
+
+import com.google.common.collect.Collections2;
+
+import net.lax1dude.eaglercraft.v1_8.EaglercraftUUID;
+
+/**
+ * Copyright (c) 2024 lax1dude. All Rights Reserved.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ * 
+ */
+public class ClientDataEntry {
+
+	public final EnumClientFormatType type;
+	public final EaglercraftUUID uuid;
+	public final EaglercraftUUID mainPayload;
+	public final EaglercraftUUID integratedServer;
+	public final EaglercraftUUID clientSignature;
+	public final List<EPKDataEntry> epkFiles;
+
+	public ClientDataEntry(EnumClientFormatType type, EaglercraftUUID uuid, EaglercraftUUID mainPayload,
+			EaglercraftUUID integratedServer, EaglercraftUUID clientSignature, List<EPKDataEntry> epkFiles) {
+		this.type = type;
+		this.uuid = uuid;
+		this.mainPayload = mainPayload;
+		this.integratedServer = integratedServer;
+		this.clientSignature = clientSignature;
+		this.epkFiles = epkFiles;
+	}
+
+	public ClientDataEntry(EaglercraftUUID uuid, JSONObject jsonObject) {
+		this.uuid = uuid;
+		EaglercraftUUID sanityUUID = EaglercraftUUID.fromString(jsonObject.getString("uuid"));
+		if(!sanityUUID.equals(uuid)) {
+			throw new IllegalArgumentException("The file's name UUID does not equal the UUID string found in the file!");
+		}
+		int typeId = jsonObject.getInt("type");
+		type = EnumClientFormatType.getById(typeId);
+		if(type == null) {
+			throw new IllegalArgumentException("Unknown client data type " + typeId + "!");
+		}
+		switch(type) {
+		default:
+		case EAGLER_STANDARD_OFFLINE:
+			mainPayload = EaglercraftUUID.fromString(jsonObject.getString("mainPayload"));
+			integratedServer = null;
+			clientSignature = null;
+			epkFiles = loadEPKFiles(jsonObject.getJSONArray("epkFiles"));
+			break;
+		case EAGLER_STANDARD_1_5_OFFLINE:
+			mainPayload = EaglercraftUUID.fromString(jsonObject.getString("mainPayload"));
+			integratedServer = EaglercraftUUID.fromString(jsonObject.getString("integratedServer"));
+			clientSignature = null;
+			epkFiles = loadEPKFiles(jsonObject.getJSONArray("epkFiles"));
+			break;
+		case EAGLER_SIGNED_OFFLINE:
+			mainPayload = EaglercraftUUID.fromString(jsonObject.getString("mainPayload"));
+			integratedServer = null;
+			clientSignature = EaglercraftUUID.fromString(jsonObject.getString("clientSignature"));
+			epkFiles = null;
+			break;
+		}
+	}
+
+	public void writeJSON(JSONObject jsonObject) {
+		jsonObject.put("uuid", uuid.toString());
+		jsonObject.put("type", type.id);
+		switch(type) {
+		case EAGLER_STANDARD_OFFLINE:
+		default:
+			jsonObject.put("mainPayload", mainPayload.toString());
+			jsonObject.put("epkFiles", storeEPKFiles(epkFiles));
+			break;
+		case EAGLER_STANDARD_1_5_OFFLINE:
+			jsonObject.put("mainPayload", mainPayload.toString());
+			jsonObject.put("integratedServer", integratedServer.toString());
+			jsonObject.put("epkFiles", storeEPKFiles(epkFiles));
+			break;
+		case EAGLER_SIGNED_OFFLINE:
+			jsonObject.put("mainPayload", mainPayload.toString());
+			jsonObject.put("clientSignature", clientSignature.toString());
+			break;
+		}
+	}
+
+	protected static List<EPKDataEntry> loadEPKFiles(JSONArray arr) {
+		int cnt = arr.length();
+		List<EPKDataEntry> ret = new ArrayList<>(cnt);
+		for(int i = 0; i < cnt; ++i) {
+			JSONObject obj = arr.getJSONObject(i);
+			ret.add(new EPKDataEntry(obj.optString("path", ""), EaglercraftUUID.fromString(obj.getString("uuid"))));
+		}
+		return ret;
+	}
+
+	protected static JSONArray storeEPKFiles(List<EPKDataEntry> arr) {
+		int cnt = arr.size();
+		JSONArray ret = new JSONArray(cnt);
+		for(int i = 0; i < cnt; ++i) {
+			EPKDataEntry etr = arr.get(i);
+			JSONObject obj = (new JSONObject()).put("uuid", etr.dataUUID.toString());
+			if(etr.extractTo.length() > 0) {
+				obj.put("path", etr.extractTo);
+			}
+			ret.put(obj);
+		}
+		return ret;
+	}
+
+	public Collection<EaglercraftUUID> getReferencedBlobs() {
+		List<EaglercraftUUID> toRet = new ArrayList<>(4);
+		switch(type) {
+		case EAGLER_STANDARD_OFFLINE:
+		default:
+			toRet.add(mainPayload);
+			toRet.addAll(Collections2.transform(epkFiles, (e) -> e.dataUUID));
+			break;
+		case EAGLER_STANDARD_1_5_OFFLINE:
+			toRet.add(mainPayload);
+			toRet.add(integratedServer);
+			toRet.addAll(Collections2.transform(epkFiles, (e) -> e.dataUUID));
+			break;
+		case EAGLER_SIGNED_OFFLINE:
+			toRet.add(mainPayload);
+			toRet.add(clientSignature);
+			break;
+		}
+		return toRet;
+	}
+
+	public ClientDataEntry rotateUUID(EaglercraftUUID rotatedClientUUID) {
+		return new ClientDataEntry(type, rotatedClientUUID, mainPayload, integratedServer, clientSignature, epkFiles);
+	}
+
+}
diff --git a/sources/teavm-boot-menu/java/net/lax1dude/eaglercraft/v1_8/boot_menu/teavm/ConfirmationPopupController.java b/sources/teavm-boot-menu/java/net/lax1dude/eaglercraft/v1_8/boot_menu/teavm/ConfirmationPopupController.java
new file mode 100644
index 00000000..5b075e5e
--- /dev/null
+++ b/sources/teavm-boot-menu/java/net/lax1dude/eaglercraft/v1_8/boot_menu/teavm/ConfirmationPopupController.java
@@ -0,0 +1,191 @@
+package net.lax1dude.eaglercraft.v1_8.boot_menu.teavm;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.teavm.jso.dom.html.HTMLElement;
+
+import com.google.common.escape.Escaper;
+import com.google.common.html.HtmlEscapers;
+
+/**
+ * Copyright (c) 2024 lax1dude. All Rights Reserved.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ * 
+ */
+public abstract class ConfirmationPopupController<T extends ConfirmationPopupController.SelectionOption> {
+
+	public static interface SelectionOption {
+
+		String getName();
+		
+		default boolean getEnabled() {
+			return true;
+		}
+
+	}
+
+	public static class SelectionOptionEnum<E> implements SelectionOption {
+
+		protected final String displayName;
+		protected final boolean enabled;
+		protected final E itemEnum;
+
+		public SelectionOptionEnum(String displayName, boolean enabled, E itemEnum) {
+			this.displayName = displayName;
+			this.enabled = enabled;
+			this.itemEnum = itemEnum;
+		}
+
+		public SelectionOptionEnum(String displayName, E itemEnum) {
+			this.displayName = displayName;
+			this.enabled = true;
+			this.itemEnum = itemEnum;
+		}
+
+		@Override
+		public String getName() {
+			return displayName;
+		}
+
+		@Override
+		public boolean getEnabled() {
+			return enabled;
+		}
+
+		public E getEnum() {
+			return itemEnum;
+		}
+
+	}
+
+	protected static class ConfirmationOptionInstance<E extends ConfirmationPopupController.SelectionOption> {
+		
+		protected final E listItem;
+		protected final HTMLElement element;
+		
+		protected ConfirmationOptionInstance(E listItem, HTMLElement element) {
+			this.listItem = listItem;
+			this.element = element;
+		}
+		
+	}
+
+	protected final HTMLElement parent;
+	protected final List<T> optionList;
+	protected final List<ConfirmationOptionInstance<T>> optionEnableList;
+	protected int currentSelected = -1;
+
+	public ConfirmationPopupController(HTMLElement parent, List<T> optionList) {
+		this.parent = parent;
+		this.optionList = optionList;
+		this.optionEnableList = new ArrayList<>(optionList.size());
+	}
+
+	public void setup() {
+		optionEnableList.clear();
+		parent.setInnerHTML("");
+		StringBuilder htmlBuilder = new StringBuilder();
+		Escaper escaper = HtmlEscapers.htmlEscaper();
+		currentSelected = -1;
+		for(int i = 0, l = optionList.size(); i < l; ++i) {
+			T itm = optionList.get(i);
+			if(i > 0) {
+				htmlBuilder.append(" &emsp; ");
+			}
+			htmlBuilder.append(
+					"<span class=\"_eaglercraftX_boot_menu_popup_confirm_opt _eaglercraftX_boot_menu_popup_confirm_opt"
+							+ i + "\">&nbsp;&lt;&nbsp;");
+			htmlBuilder.append(escaper.escape(itm.getName()));
+			htmlBuilder.append("&nbsp;&gt;&nbsp;</span>");
+		}
+		parent.setInnerHTML(htmlBuilder.toString());
+		for(int i = 0, l = optionList.size(); i < l; ++i) {
+			T itm = optionList.get(i);
+			HTMLElement el = parent.querySelector("._eaglercraftX_boot_menu_popup_confirm_opt" + i);
+			if(el == null) {
+				throw new RuntimeException("Failed to select element from page: ._eaglercraftX_boot_menu_popup_confirm_opt" + i);
+			}
+			if(itm.getEnabled()) {
+				if(currentSelected == -1) {
+					currentSelected = 0;
+					el.getClassList().add(BootMenuConstants.cssClassPrefixBootMenu + "popup_confirm_opt_selected");
+				}
+				final ConfirmationOptionInstance<T> newInstance = new ConfirmationOptionInstance<T>(itm, el);
+				final int ii = optionEnableList.size();
+				el.addEventListener("mouseover", (evt) -> {
+					BootMenuMain.runLater(() -> {
+						setSelected(ii);
+					});
+				});
+				el.addEventListener("click", (evt) -> {
+					BootMenuMain.runLater(() -> {
+						optionSelected(newInstance.listItem);
+					});
+				});
+				optionEnableList.add(newInstance);
+			}else {
+				el.getClassList().add(BootMenuConstants.cssClassPrefixBootMenu + "popup_confirm_opt_disabled");
+			}
+		}
+	}
+
+	public void destroy() {
+		parent.setInnerHTML("");
+		currentSelected = -1;
+		optionEnableList.clear();
+	}
+
+	public void setSelected(int idx) {
+		int listLen = optionEnableList.size();
+		if(listLen == 0) {
+			idx = -1;
+		}else if(idx >= listLen) {
+			idx = listLen - 1;
+		}else if(idx < 0) {
+			idx = 0;
+		}
+		if(idx == currentSelected) {
+			return;
+		}
+		if(currentSelected >= 0 && currentSelected < optionEnableList.size()) {
+			optionEnableList.get(currentSelected).element.getClassList().remove(BootMenuConstants.cssClassPrefixBootMenu + "popup_confirm_opt_selected");
+		}
+		currentSelected = idx;
+		if(idx != -1) {
+			optionEnableList.get(idx).element.getClassList().add(BootMenuConstants.cssClassPrefixBootMenu + "popup_confirm_opt_selected");
+		}
+	}
+
+	public void handleKeyDown(int keyCode) {
+		if(keyCode == KeyCodes.DOM_KEY_ARROW_LEFT) {
+			setSelected(currentSelected - 1);
+		}else if(keyCode == KeyCodes.DOM_KEY_ARROW_RIGHT) {
+			setSelected(currentSelected + 1);
+		}else if(keyCode == KeyCodes.DOM_KEY_ENTER) {
+			if(currentSelected >= 0 && currentSelected < optionEnableList.size()) {
+				optionSelected(optionEnableList.get(currentSelected).listItem);
+			}
+		}
+	}
+
+	public void handleKeyRepeat(int keyCode) {
+		if(keyCode == KeyCodes.DOM_KEY_ARROW_LEFT) {
+			setSelected(currentSelected - 1);
+		}else if(keyCode == KeyCodes.DOM_KEY_ARROW_RIGHT) {
+			setSelected(currentSelected + 1);
+		}
+	}
+
+	protected abstract void optionSelected(T item);
+}
diff --git a/sources/teavm-boot-menu/java/net/lax1dude/eaglercraft/v1_8/boot_menu/teavm/EPKClientFactory.java b/sources/teavm-boot-menu/java/net/lax1dude/eaglercraft/v1_8/boot_menu/teavm/EPKClientFactory.java
new file mode 100644
index 00000000..eaadb2fc
--- /dev/null
+++ b/sources/teavm-boot-menu/java/net/lax1dude/eaglercraft/v1_8/boot_menu/teavm/EPKClientFactory.java
@@ -0,0 +1,100 @@
+package net.lax1dude.eaglercraft.v1_8.boot_menu.teavm;
+
+import java.nio.charset.StandardCharsets;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.function.Supplier;
+
+import org.json.JSONArray;
+import org.json.JSONObject;
+
+import net.lax1dude.eaglercraft.v1_8.EagRuntime;
+import net.lax1dude.eaglercraft.v1_8.EaglercraftUUID;
+import net.lax1dude.eaglercraft.v1_8.log4j.LogManager;
+import net.lax1dude.eaglercraft.v1_8.log4j.Logger;
+import net.lax1dude.eaglercraft.v1_8.sp.server.export.EPKCompiler;
+
+/**
+ * Copyright (c) 2024 lax1dude. All Rights Reserved.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ * 
+ */
+public class EPKClientFactory {
+
+	private static final Logger logger = LogManager.getLogger("EPKClientFactory");
+
+	private static void doUpdateMessage(IProgressMsgCallback cb, String str) {
+		logger.info(str);
+		cb.updateMessage(str);
+	}
+
+	public static void downloadEPKClient(LaunchConfigEntry launchConf, ClientDataEntry clientData,
+			Map<EaglercraftUUID, Supplier<byte[]>> loaders, IProgressMsgCallback cb) {
+		doUpdateMessage(cb, "Generating manifest...");
+		EaglercraftUUID randomLaunchUUID = EaglercraftUUID.randomUUID();
+		EaglercraftUUID randomClientUUID = EaglercraftUUID.randomUUID();
+		launchConf = launchConf.rotateUUIDs(randomLaunchUUID, randomClientUUID);
+		clientData = clientData.rotateUUID(randomClientUUID);
+		JSONArray launchDatas = new JSONArray();
+		JSONObject launchObj = new JSONObject();
+		launchConf.writeJSON(launchObj);
+		launchDatas.put(launchObj);
+		JSONArray clientDatas = new JSONArray();
+		JSONObject clientObj = new JSONObject();
+		clientData.writeJSON(clientObj);
+		clientDatas.put(clientObj);
+		JSONObject manifestObj = new JSONObject();
+		manifestObj.put("launchData", launchDatas);
+		manifestObj.put("clientData", clientDatas);
+		byte[] manifestBytes = manifestObj.toString().getBytes(StandardCharsets.UTF_8);
+		Map<String,byte[]> blobs = new HashMap<>();
+		for(EaglercraftUUID uuid : clientData.getReferencedBlobs()) {
+			String name = uuid.toString();
+			doUpdateMessage(cb, "Resolving blobs (" + name + ")");
+			if(!blobs.containsKey(name)) {
+				Supplier<byte[]> loader = loaders.get(uuid);
+				byte[] dat = null;
+				if(loader != null) {
+					dat = loader.get();
+				}
+				if(dat == null) {
+					String msg = "Could not resolve blob! (" + name + ")";
+					logger.error(msg);
+					throw new NullPointerException(msg);
+				}
+				blobs.put(name, dat);
+			}
+		}
+		doUpdateMessage(cb, "Compressing EPK file...");
+		String fileName = launchConf.displayName.replaceAll("[^a-zA-Z0-9\\-_\\.]", "_");
+		if(fileName.length() > 251) {
+			fileName = fileName.substring(0, 251);
+		}
+		fileName = fileName + ".epk";
+		EPKCompiler epkComp = new EPKCompiler(fileName, "unknown", "epk/client-archive-v1", true, false,
+				"\n\n #  Eagler EPK v2.0 Client Archive v1\n #  Clients: \"" + launchConf.displayName + "\"\n\n");
+		byte[] epkData;
+		try {
+			epkComp.append("manifest.json", manifestBytes);
+			for(Entry<String,byte[]> blob : blobs.entrySet()) {
+				epkComp.append(blob.getKey(), blob.getValue());
+			}
+		}finally {
+			epkData = epkComp.complete();
+		}
+		doUpdateMessage(cb, "Downloading file...");
+		EagRuntime.downloadFileWithName(fileName, epkData);
+	}
+
+}
diff --git a/sources/teavm-boot-menu/java/net/lax1dude/eaglercraft/v1_8/boot_menu/teavm/EPKClientParser.java b/sources/teavm-boot-menu/java/net/lax1dude/eaglercraft/v1_8/boot_menu/teavm/EPKClientParser.java
new file mode 100644
index 00000000..728c73c6
--- /dev/null
+++ b/sources/teavm-boot-menu/java/net/lax1dude/eaglercraft/v1_8/boot_menu/teavm/EPKClientParser.java
@@ -0,0 +1,136 @@
+package net.lax1dude.eaglercraft.v1_8.boot_menu.teavm;
+
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import org.json.JSONArray;
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import net.lax1dude.eaglercraft.v1_8.EaglercraftUUID;
+import net.lax1dude.eaglercraft.v1_8.boot_menu.teavm.OfflineDownloadParser.ParsedOfflineAdapter;
+import net.lax1dude.eaglercraft.v1_8.log4j.LogManager;
+import net.lax1dude.eaglercraft.v1_8.log4j.Logger;
+import net.lax1dude.eaglercraft.v1_8.sp.server.export.EPKDecompiler;
+
+/**
+ * Copyright (c) 2024 lax1dude. All Rights Reserved.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ * 
+ */
+public class EPKClientParser {
+
+	private static final Logger logger = LogManager.getLogger("EPKClientParser");
+
+	public static List<ParsedOfflineAdapter> parseEPKClient(byte[] epkData) throws IOException {
+		EPKDecompiler epkDecompiler = new EPKDecompiler(epkData);
+		EPKDecompiler.FileEntry fetr = epkDecompiler.readFile();
+		if(fetr == null || !fetr.type.equals("HEAD") || !fetr.name.equals("file-type")) {
+			epkDecompiler.close();
+			throw new IOException("File is incomplete!");
+		}
+		if(!Arrays.equals(fetr.data, "epk/client-archive-v1".getBytes(StandardCharsets.UTF_8))) {
+			throw new IOException("File is not a client archive!");
+		}
+		Map<String,byte[]> files = new HashMap<>();
+		while((fetr = epkDecompiler.readFile()) != null) {
+			if(fetr.type.equals("FILE")) {
+				files.put(fetr.name, fetr.data);
+			}else {
+				logger.error("Skipping non-FILE entry: {} {}", fetr.type, fetr.name);
+			}
+		}
+		byte[] manifestData = files.get("manifest.json");
+		if(manifestData == null) {
+			throw new IOException("File is incomplete!");
+		}
+		List<EaglercraftUUID> lst = new ArrayList<>();
+		Map<EaglercraftUUID,ClientDataEntry> clientDatas;
+		List<LaunchConfigEntry> launchDatas;
+		try {
+			JSONObject mainfestJSON = new JSONObject(new String(manifestData, StandardCharsets.UTF_8));
+			JSONArray launches = mainfestJSON.getJSONArray("launchData");
+			JSONArray clients = mainfestJSON.getJSONArray("clientData");
+			clientDatas = new HashMap<>(clients.length());
+			launchDatas = new ArrayList<>(launches.length());
+			for(int i = 0, l = clients.length(); i < l; ++i) {
+				JSONObject obj = clients.getJSONObject(i);
+				EaglercraftUUID theUUID = EaglercraftUUID.fromString(obj.getString("uuid"));
+				if(!theUUID.equals(BootMenuConstants.UUID_CLIENT_DATA_ORIGIN)) {
+					clientDatas.put(theUUID, new ClientDataEntry(theUUID, obj));
+				}
+			}
+			for(int i = 0, l = launches.length(); i < l; ++i) {
+				JSONObject obj = launches.getJSONObject(i);
+				EaglercraftUUID theUUID = EaglercraftUUID.fromString(obj.getString("uuid"));
+				if(!theUUID.equals(BootMenuConstants.UUID_CLIENT_LAUNCH_ORIGIN)) {
+					LaunchConfigEntry theEtr = new LaunchConfigEntry(theUUID, obj);
+					if(!BootMenuConstants.UUID_CLIENT_DATA_ORIGIN.equals(theEtr.clientDataUUID)) {
+						if(clientDatas.containsKey(theEtr.clientDataUUID)) {
+							launchDatas.add(theEtr);
+						}else {
+							logger.warn("Skipping launch config {} because the client data {} is missing!", theUUID, theEtr.clientDataUUID);
+						}
+					}
+				}
+			}
+		}catch(JSONException ex) {
+			throw new IOException("File manifest is corrupt!", ex);
+		}
+		Map<EaglercraftUUID, byte[]> blobs = new HashMap<>();
+		Iterator<ClientDataEntry> itr = clientDatas.values().iterator();
+		loadClientDatas: while(itr.hasNext()) {
+			ClientDataEntry etr = itr.next();
+			for(EaglercraftUUID uuid : etr.getReferencedBlobs()) {
+				if(!blobs.containsKey(uuid)) {
+					byte[] blobBytes = files.get(uuid.toString());
+					if(blobBytes == null) {
+						logger.error("Blob UUID {} for client data {} is missing!", uuid, etr.uuid);
+						itr.remove();
+						continue loadClientDatas;
+					}
+					if(!EaglercraftUUID.nameUUIDFromBytes(blobBytes).equals(uuid)) {
+						logger.error("Blob UUID {} for client data {} has an invalid checksum!", uuid, etr.uuid);
+						itr.remove();
+						continue loadClientDatas;
+					}
+					blobs.put(uuid, blobBytes);
+				}
+			}
+		}
+		List<ParsedOfflineAdapter> list = new ArrayList<>(launchDatas.size());
+		for(LaunchConfigEntry etr : launchDatas) {
+			ClientDataEntry clientData = clientDatas.get(etr.clientDataUUID);
+			if(clientData == null) {
+				logger.error("Client data UUID {} for launch data {} is missing!", etr.clientDataUUID, etr.uuid);
+				continue;
+			}
+			Map<EaglercraftUUID, byte[]> entryBlob = new HashMap<>();
+			for(EaglercraftUUID uuid : clientData.getReferencedBlobs()) {
+				entryBlob.put(uuid, blobs.get(uuid));
+			}
+			list.add(new ParsedOfflineAdapter(etr, clientData, entryBlob));
+		}
+		logger.info("Loaded {} blobs from fat offline", blobs.size());
+		logger.info("Loaded {} client configurations from EPK file", clientDatas.size());
+		logger.info("Loaded {} launch configurations from EPK file", launchDatas.size());
+		return list;
+	}
+
+}
diff --git a/sources/teavm-boot-menu/java/net/lax1dude/eaglercraft/v1_8/boot_menu/teavm/EPKDataEntry.java b/sources/teavm-boot-menu/java/net/lax1dude/eaglercraft/v1_8/boot_menu/teavm/EPKDataEntry.java
new file mode 100644
index 00000000..f956971f
--- /dev/null
+++ b/sources/teavm-boot-menu/java/net/lax1dude/eaglercraft/v1_8/boot_menu/teavm/EPKDataEntry.java
@@ -0,0 +1,30 @@
+package net.lax1dude.eaglercraft.v1_8.boot_menu.teavm;
+
+import net.lax1dude.eaglercraft.v1_8.EaglercraftUUID;
+
+/**
+ * Copyright (c) 2024 lax1dude. All Rights Reserved.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ * 
+ */
+public class EPKDataEntry {
+
+	public final String extractTo;
+	public final EaglercraftUUID dataUUID;
+
+	public EPKDataEntry(String extractTo, EaglercraftUUID dataUUID) {
+		this.extractTo = extractTo;
+		this.dataUUID = dataUUID;
+	}
+
+}
diff --git a/sources/teavm-boot-menu/java/net/lax1dude/eaglercraft/v1_8/boot_menu/teavm/EnumClientFormatType.java b/sources/teavm-boot-menu/java/net/lax1dude/eaglercraft/v1_8/boot_menu/teavm/EnumClientFormatType.java
new file mode 100644
index 00000000..fc8c1695
--- /dev/null
+++ b/sources/teavm-boot-menu/java/net/lax1dude/eaglercraft/v1_8/boot_menu/teavm/EnumClientFormatType.java
@@ -0,0 +1,67 @@
+package net.lax1dude.eaglercraft.v1_8.boot_menu.teavm;
+
+import java.util.Set;
+
+import com.google.common.collect.Sets;
+
+/**
+ * Copyright (c) 2024 lax1dude. All Rights Reserved.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ * 
+ */
+public enum EnumClientFormatType {
+	/**
+	 * Eagler 1.8, b1.3, or pre-singleplayer 1.5 offline
+	 */
+	EAGLER_STANDARD_OFFLINE(0, "Standard Offline", Sets.newHashSet(EnumClientLaunchType.EAGLERX_V1, EnumClientLaunchType.EAGLER_1_5_V1,
+					EnumClientLaunchType.EAGLER_BETA_V1, EnumClientLaunchType.PEYTON_V2, EnumClientLaunchType.PEYTON_V1,
+					EnumClientLaunchType.STANDARD_OFFLINE_V1)),
+
+	/**
+	 * Eagler 1.5 offline with integrated server
+	 */
+	EAGLER_STANDARD_1_5_OFFLINE(1, "Standard 1.5 Offline", Sets.newHashSet(EnumClientLaunchType.EAGLER_1_5_V2)),
+	
+	/**
+	 * Eagler 1.8 with certificate
+	 */
+	EAGLER_SIGNED_OFFLINE(2, "Signed Offline", Sets.newHashSet(EnumClientLaunchType.EAGLERX_SIGNED_V1));
+
+	public final int id;
+	public final String displayName;
+	public final Set<EnumClientLaunchType> launchTypes;
+
+	private EnumClientFormatType(int id, String displayName, Set<EnumClientLaunchType> launchTypes) {
+		this.id = id;
+		this.displayName = displayName;
+		this.launchTypes = launchTypes;
+	}
+
+	private static final EnumClientFormatType[] lookup = new EnumClientFormatType[3];
+
+	public static EnumClientFormatType getById(int id) {
+		if(id >= 0 && id < lookup.length) {
+			return lookup[id];
+		}else {
+			return null;
+		}
+	}
+
+	static {
+		EnumClientFormatType[] _values = values();
+		for(int i = 0; i < _values.length; ++i) {
+			lookup[_values[i].id] = _values[i];
+		}
+	}
+
+}
diff --git a/sources/teavm-boot-menu/java/net/lax1dude/eaglercraft/v1_8/boot_menu/teavm/EnumClientLaunchType.java b/sources/teavm-boot-menu/java/net/lax1dude/eaglercraft/v1_8/boot_menu/teavm/EnumClientLaunchType.java
new file mode 100644
index 00000000..eadbcc54
--- /dev/null
+++ b/sources/teavm-boot-menu/java/net/lax1dude/eaglercraft/v1_8/boot_menu/teavm/EnumClientLaunchType.java
@@ -0,0 +1,86 @@
+package net.lax1dude.eaglercraft.v1_8.boot_menu.teavm;
+
+/**
+ * Copyright (c) 2024 lax1dude. All Rights Reserved.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ * 
+ */
+public enum EnumClientLaunchType {
+	/**
+	 * Configuable Eagler 1.8-like offline
+	 */
+	STANDARD_OFFLINE_V1(0),
+	
+	/**
+	 * Eagler 1.8 standard
+	 */
+	EAGLERX_V1(1),
+	
+	/**
+	 * Eagler 1.8 with certificate
+	 */
+	EAGLERX_SIGNED_V1(2),
+	
+	/**
+	 * Eagler 1.5 array "window.minecraftOpts" of element id, epk file, servers, server to join
+	 */
+	EAGLER_1_5_V1(3),
+	
+	/**
+	 * Eagler 1.5 array "window.eaglercraftOpts" with "container" and "assetsURI" and "serverWorkerURI"
+	 */
+	EAGLER_1_5_V2(4),
+	
+	/**
+	 * Eagler beta array "window.minecraftOpts" of element id, epk file, server to join
+	 */
+	EAGLER_BETA_V1(5),
+	
+	/**
+	 * Peyton format with "window.classicConfig" array of root element id and epk file
+	 */
+	PEYTON_V1(6),
+	
+	/**
+	 * Peyton format with "window.config" JSON object with "gameContainer" and "assetsLocation"
+	 */
+	PEYTON_V2(7);
+
+	public final int id;
+
+	private EnumClientLaunchType(int id) {
+		this.id = id;
+	}
+
+	private static final EnumClientLaunchType[] lookup = new EnumClientLaunchType[8];
+
+	public static EnumClientLaunchType getById(int id) {
+		if(id >= 0 && id < lookup.length) {
+			return lookup[id];
+		}else {
+			return null;
+		}
+	}
+
+	public static EnumClientLaunchType[] _values() {
+		return lookup;
+	}
+
+	static {
+		EnumClientLaunchType[] _values = values();
+		for(int i = 0; i < _values.length; ++i) {
+			lookup[_values[i].id] = _values[i];
+		}
+	}
+
+}
diff --git a/sources/teavm-boot-menu/java/net/lax1dude/eaglercraft/v1_8/boot_menu/teavm/EnumOfflineParseType.java b/sources/teavm-boot-menu/java/net/lax1dude/eaglercraft/v1_8/boot_menu/teavm/EnumOfflineParseType.java
new file mode 100644
index 00000000..8639a27e
--- /dev/null
+++ b/sources/teavm-boot-menu/java/net/lax1dude/eaglercraft/v1_8/boot_menu/teavm/EnumOfflineParseType.java
@@ -0,0 +1,53 @@
+package net.lax1dude.eaglercraft.v1_8.boot_menu.teavm;
+
+/**
+ * Copyright (c) 2024 lax1dude. All Rights Reserved.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ * 
+ */
+public enum EnumOfflineParseType {
+	EAGLERCRAFTX_1_8_OFFLINE,
+	EAGLERCRAFTX_1_8_SIGNED,
+	EAGLERCRAFTX_1_8_FAT_OFFLINE,
+	EAGLERCRAFTX_1_8_FAT_SIGNED,
+	EAGLERCRAFT_1_5_NEW_OFFLINE,
+	EAGLERCRAFT_1_5_OLD_OFFLINE,
+	EAGLERCRAFT_BETA_B1_3_OFFLINE,
+	PEYTONPLAYZ585_ALPHA_BETA,
+	PEYTONPLAYZ585_INDEV,
+	EXPORTED_STANDARD_OFFLINE,
+	EAGLERCRAFT_EPK_FILE;
+
+	public static EnumOfflineParseType inferFromClientFormat(EnumClientLaunchType etr) {
+		switch(etr) {
+		case STANDARD_OFFLINE_V1:
+			return EXPORTED_STANDARD_OFFLINE;
+		case EAGLERX_V1:
+			return EAGLERCRAFTX_1_8_OFFLINE;
+		case EAGLERX_SIGNED_V1:
+			return EAGLERCRAFTX_1_8_SIGNED;
+		case EAGLER_1_5_V1:
+			return EAGLERCRAFT_1_5_OLD_OFFLINE;
+		case EAGLER_1_5_V2:
+			return EAGLERCRAFT_1_5_NEW_OFFLINE;
+		case EAGLER_BETA_V1:
+			return EAGLERCRAFT_BETA_B1_3_OFFLINE;
+		case PEYTON_V1:
+			return PEYTONPLAYZ585_INDEV;
+		case PEYTON_V2:
+			return PEYTONPLAYZ585_ALPHA_BETA;
+		default:
+			throw new IllegalArgumentException();
+		}
+	}
+}
diff --git a/sources/teavm-boot-menu/java/net/lax1dude/eaglercraft/v1_8/boot_menu/teavm/FatOfflineDownloadFactory.java b/sources/teavm-boot-menu/java/net/lax1dude/eaglercraft/v1_8/boot_menu/teavm/FatOfflineDownloadFactory.java
new file mode 100644
index 00000000..ec584eaf
--- /dev/null
+++ b/sources/teavm-boot-menu/java/net/lax1dude/eaglercraft/v1_8/boot_menu/teavm/FatOfflineDownloadFactory.java
@@ -0,0 +1,207 @@
+package net.lax1dude.eaglercraft.v1_8.boot_menu.teavm;
+
+import java.nio.charset.StandardCharsets;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+import java.util.function.Supplier;
+
+import org.apache.commons.lang3.StringUtils;
+import org.json.JSONArray;
+import org.json.JSONObject;
+
+import net.lax1dude.eaglercraft.v1_8.Base64;
+import net.lax1dude.eaglercraft.v1_8.EagRuntime;
+import net.lax1dude.eaglercraft.v1_8.EaglercraftUUID;
+import net.lax1dude.eaglercraft.v1_8.boot_menu.teavm.BootMenuEntryPoint.UnsignedClientEPKLoader;
+import net.lax1dude.eaglercraft.v1_8.log4j.LogManager;
+import net.lax1dude.eaglercraft.v1_8.log4j.Logger;
+
+/**
+ * Copyright (c) 2024 lax1dude. All Rights Reserved.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ * 
+ */
+public class FatOfflineDownloadFactory {
+
+	private static final Logger logger = LogManager.getLogger("FatOfflineDownloadFactory");
+
+	public static void downloadOffline(List<BootableClientEntry> lst, IProgressMsgCallback cb) {
+		Map<EaglercraftUUID, byte[]> loadedBlobs = new HashMap<>();
+		JSONArray manifestClientDatas = new JSONArray();
+		Set<EaglercraftUUID> manifestClientDatasSet = new HashSet<>();
+		JSONArray manifestLaunchDatas = new JSONArray();
+		Set<EaglercraftUUID> manifestLaunchDatasSet = new HashSet<>();
+		for(BootableClientEntry etr : lst) {
+			ClientDataEntry clientData = etr.bootAdapter.getClientDataEntry();
+			LaunchConfigEntry launchConf = etr.bootAdapter.getLaunchConfigEntry();
+			if(launchConf.uuid.equals(BootMenuConstants.UUID_CLIENT_LAUNCH_ORIGIN)) {
+				logger.warn("Cannot export origin launch configuration to fat offline!");
+				continue;
+			}
+			if(manifestLaunchDatasSet.add(launchConf.uuid)) {
+				JSONObject obj = new JSONObject();
+				launchConf.writeJSON(obj);
+				manifestLaunchDatas.put(obj);
+				if(!clientData.uuid.equals(BootMenuConstants.UUID_CLIENT_DATA_ORIGIN) && manifestClientDatasSet.add(clientData.uuid)) {
+					obj = new JSONObject();
+					clientData.writeJSON(obj);
+					manifestClientDatas.put(obj);
+					Map<EaglercraftUUID, Supplier<byte[]>> loaders = etr.bootAdapter.getBlobLoaders();
+					for(EaglercraftUUID uuid : clientData.getReferencedBlobs()) {
+						doUpdateMessage(cb, "Resolving data for \"" + launchConf.displayName + "\" (" + uuid + ")");
+						if(!cacheLoad(loadedBlobs, loaders, uuid)) {
+							throw new NullPointerException("Blob for configuration \"" + launchConf.displayName + "\" is missing: " + uuid);
+						}
+					}
+				}
+			}else {
+				logger.warn("Skipping duplicate launch config uuid: {}", launchConf.uuid);
+			}
+		}
+		JSONObject manifest = new JSONObject();
+		manifest.put("clientData", manifestClientDatas);
+		manifest.put("launchData", manifestLaunchDatas);
+		String manifestStr = manifest.toString().replace(StringUtils.reverse(">elyts/<"), "<_style>");
+		boolean isSigned = BootMenuEntryPoint.isSignedClient();
+		String template;
+		if(isSigned) {
+			doUpdateMessage(cb, "Loading offline_template_eaglercraftX_1_8_fat_signed.html");
+			template = OfflineDownloadFactory.loadTemplate("offline_template_eaglercraftX_1_8_fat_signed.html");
+		}else {
+			doUpdateMessage(cb, "Loading offline_template_eaglercraftX_1_8_fat_offline.html");
+			template = OfflineDownloadFactory.loadTemplate("offline_template_eaglercraftX_1_8_fat_offline.html");
+		}
+		template = template.replace("${date}", (new SimpleDateFormat("MM/dd/yyyy")).format(new Date()));
+		template = template.replace("${num_clients}", Integer.toString(manifestLaunchDatas.length() + 1));
+		JSONObject optsDump = BootMenuEntryPoint.getOriginLaunchOptsJSON();
+		optsDump.put("bootMenuBlocksUnsignedClients", false);
+		RelayRandomizeHelper.makeOptsJSONHaveMacroHack(optsDump);
+		String optsStr = optsDump.toString();
+		JSONObject launchConfJSON = new JSONObject();
+		(new LaunchConfigEntry(BootMenuConstants.UUID_CLIENT_LAUNCH_ORIGIN, BootMenuConstants.UUID_CLIENT_DATA_ORIGIN,
+				BootMenuConstants.client_projectForkName + " " + BootMenuConstants.client_projectOriginRevision + " "
+						+ BootMenuConstants.client_projectOriginVersion,
+				isSigned ? EnumClientLaunchType.EAGLERX_SIGNED_V1 : EnumClientLaunchType.EAGLERX_V1, null, null, null,
+				null, null, optsStr, false)).writeJSON(launchConfJSON);
+		template = template.replace("${launch_conf_json}", launchConfJSON.toString());
+		int relayIdCount = RelayRandomizeHelper.countRelayMacro(optsStr);
+		if(relayIdCount > 0) {
+			optsStr = RelayRandomizeHelper.replaceRelayMacroWithEqRelayId(optsStr);
+		}
+		template = template.replace("${relayId_max}", Integer.toString(relayIdCount));
+		template = template.replace("${launch_opts}", optsStr);
+		if(isSigned) {
+			doUpdateMessage(cb, "Retrieving origin client signature and payload");
+			template = template.replace("${client_signature}", Base64.encodeBase64String(BootMenuEntryPoint.getSignedClientSignature()));
+			template = template.replace("${client_bundle}", Base64.encodeBase64String(BootMenuEntryPoint.getSignedClientBundle()));
+		}else {
+			doUpdateMessage(cb, "Retrieving origin client classes.js");
+			byte[] classesJS = BootMenuEntryPoint.getUnsignedClientClassesJS();
+			if(classesJS == null) {
+				throw new NullPointerException("Could not load classes.js!");
+			}
+			template = template.replace(StringUtils.reverse("}sj_sessalc{$"), new String(OfflineDownloadFactory.removeUseStrict(classesJS), StandardCharsets.UTF_8));
+			UnsignedClientEPKLoader epkLoader = BootMenuEntryPoint.getUnsignedClientAssetsEPK();
+			String assetsEPKVal;
+			int epkNum = epkLoader.list.size();
+			if(epkNum > 1 || !StringUtils.isEmpty(epkLoader.list.get(0).extractTo)) {
+				StringBuilder assetsEPKBuilder = new StringBuilder("[ ");
+				for(int i = 0; i < epkNum; ++i) {
+					EPKDataEntry epk = epkLoader.list.get(i);
+					doUpdateMessage(cb, "Resolving assets.epk (" + epk.dataUUID + ", path: /" + epk.extractTo + ")");
+					Supplier<byte[]> epkDataGetter = epkLoader.loaders.get(epk.dataUUID);
+					byte[] epkData = null;
+					if(epkDataGetter != null) {
+						epkData = epkDataGetter.get();
+					}
+					if(epkData == null) {
+						String msg = "Could not resolve assets.epk! (" + epk.dataUUID + ", path: /" + epk.extractTo + ")";
+						logger.error(msg);
+						throw new NullPointerException(msg);
+					}
+					if(i > 0) {
+						assetsEPKBuilder.append(", ");
+					}
+					assetsEPKBuilder.append("{ url: \"data:application/octet-stream;base64,");
+					assetsEPKBuilder.append(Base64.encodeBase64String(epkData));
+					assetsEPKBuilder.append("\", path: \"");
+					assetsEPKBuilder.append(OfflineDownloadFactory.stupidJSONEscape(epk.extractTo));
+					assetsEPKBuilder.append("\" }");
+				}
+				assetsEPKBuilder.append(" ]");
+				assetsEPKVal = assetsEPKBuilder.toString();
+			}else {
+				EPKDataEntry epk = epkLoader.list.get(0);
+				doUpdateMessage(cb, "Resolving assets.epk (" + epk.dataUUID + ", path: /)");
+				Supplier<byte[]> epkDataGetter = epkLoader.loaders.get(epk.dataUUID);
+				byte[] epkData = null;
+				if(epkDataGetter != null) {
+					epkData = epkDataGetter.get();
+				}
+				if(epkData == null) {
+					String msg = "Could not resolve assets.epk! (" + epk.dataUUID + ", path: /)";
+					logger.error(msg);
+					throw new NullPointerException(msg);
+				}
+				assetsEPKVal = "\"data:application/octet-stream;base64," + Base64.encodeBase64String(epkData) + "\"";
+			}
+			
+			template = template.replace(StringUtils.reverse("}kpe_stessa{$"), assetsEPKVal);
+		}
+		doUpdateMessage(cb, "Embedding additional clients as base64");
+		StringBuilder fatOfflineDataBuilder = new StringBuilder();
+		fatOfflineDataBuilder.append(StringUtils.reverse(">\"1v_tsefinam_enilffOtaFrelgae_\"=di \"tfarcrelgae\"=epyt elyts<"));
+		fatOfflineDataBuilder.append(manifestStr);
+		fatOfflineDataBuilder.append(StringUtils.reverse("\n>elyts/<"));
+		for(Entry<EaglercraftUUID, byte[]> etr : loadedBlobs.entrySet()) {
+			fatOfflineDataBuilder.append(StringUtils.reverse("_enilffOtaFrelgae_\"=di \"tfarcrelgae\"=epyt elyts<") + etr.getKey().toString() + "\">");
+			fatOfflineDataBuilder.append(Base64.encodeBase64String(etr.getValue()));
+			fatOfflineDataBuilder.append(StringUtils.reverse("\n>elyts/<"));
+		}
+		template = template.replace(StringUtils.reverse("}atad_enilffo_taf{$"), fatOfflineDataBuilder.toString());
+		doUpdateMessage(cb, "Downloading file...");
+		EagRuntime.downloadFileWithName("EaglercraftX_1.8_Fat_Offline_Download.html", template.getBytes(StandardCharsets.UTF_8));
+	}
+
+	private static void doUpdateMessage(IProgressMsgCallback cb, String str) {
+		logger.info(str);
+		cb.updateMessage(str);
+	}
+
+	private static boolean cacheLoad(Map<EaglercraftUUID, byte[]> loadedBlobs,
+			Map<EaglercraftUUID, Supplier<byte[]>> loaders, EaglercraftUUID uuid) {
+		if(!loadedBlobs.containsKey(uuid)) {
+			Supplier<byte[]> getter = loaders.get(uuid);
+			if(getter != null) {
+				byte[] dat = getter.get();
+				if(dat != null) {
+					loadedBlobs.put(uuid, dat);
+					return true;
+				}else {
+					return false;
+				}
+			}else {
+				return false;
+			}
+		}else {
+			return true;
+		}
+	}
+
+}
diff --git a/sources/teavm-boot-menu/java/net/lax1dude/eaglercraft/v1_8/boot_menu/teavm/IBootMenuConfigAdapter.java b/sources/teavm-boot-menu/java/net/lax1dude/eaglercraft/v1_8/boot_menu/teavm/IBootMenuConfigAdapter.java
new file mode 100644
index 00000000..785a9aa0
--- /dev/null
+++ b/sources/teavm-boot-menu/java/net/lax1dude/eaglercraft/v1_8/boot_menu/teavm/IBootMenuConfigAdapter.java
@@ -0,0 +1,30 @@
+package net.lax1dude.eaglercraft.v1_8.boot_menu.teavm;
+
+import net.lax1dude.eaglercraft.v1_8.internal.teavm.TeaVMClientConfigAdapter;
+
+/**
+ * Copyright (c) 2024 lax1dude. All Rights Reserved.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ * 
+ */
+public interface IBootMenuConfigAdapter {
+
+	public static final IBootMenuConfigAdapter instance = (IBootMenuConfigAdapter)TeaVMClientConfigAdapter.instance;
+
+	boolean isAllowBootMenu();
+
+	boolean isShowBootMenuOnLaunch();
+
+	boolean isBootMenuBlocksUnsignedClients();
+
+}
diff --git a/sources/teavm-boot-menu/java/net/lax1dude/eaglercraft/v1_8/boot_menu/teavm/IProgressMsgCallback.java b/sources/teavm-boot-menu/java/net/lax1dude/eaglercraft/v1_8/boot_menu/teavm/IProgressMsgCallback.java
new file mode 100644
index 00000000..fa206ce5
--- /dev/null
+++ b/sources/teavm-boot-menu/java/net/lax1dude/eaglercraft/v1_8/boot_menu/teavm/IProgressMsgCallback.java
@@ -0,0 +1,22 @@
+package net.lax1dude.eaglercraft.v1_8.boot_menu.teavm;
+
+/**
+ * Copyright (c) 2024 lax1dude. All Rights Reserved.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ * 
+ */
+public interface IProgressMsgCallback {
+
+	void updateMessage(String msg);
+
+}
diff --git a/sources/teavm-boot-menu/java/net/lax1dude/eaglercraft/v1_8/boot_menu/teavm/InputPopupController.java b/sources/teavm-boot-menu/java/net/lax1dude/eaglercraft/v1_8/boot_menu/teavm/InputPopupController.java
new file mode 100644
index 00000000..050194b3
--- /dev/null
+++ b/sources/teavm-boot-menu/java/net/lax1dude/eaglercraft/v1_8/boot_menu/teavm/InputPopupController.java
@@ -0,0 +1,111 @@
+package net.lax1dude.eaglercraft.v1_8.boot_menu.teavm;
+
+import org.teavm.jso.dom.html.HTMLElement;
+import org.teavm.jso.dom.html.HTMLInputElement;
+
+/**
+ * Copyright (c) 2024 lax1dude. All Rights Reserved.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ * 
+ */
+public abstract class InputPopupController {
+
+	public final HTMLInputElement inputField;
+	public final boolean intValue;
+	public final HTMLElement cancelButton;
+	public final  HTMLElement doneButton;
+	protected boolean cancelSelected = true;
+
+	public InputPopupController(HTMLInputElement inputField, boolean intValue, HTMLElement cancelButton, HTMLElement doneButton) {
+		this.inputField = inputField;
+		this.intValue = intValue;
+		this.cancelButton = cancelButton;
+		this.doneButton = doneButton;
+	}
+
+	public void setup(String initialValue) {
+		cancelSelected = true;
+		inputField.setValue(initialValue);
+		cancelButton.getClassList().add(BootMenuConstants.cssClassPrefixBootMenu + "popup_input_opt_selected");
+		doneButton.getClassList().remove(BootMenuConstants.cssClassPrefixBootMenu + "popup_input_opt_selected");
+	}
+
+	public void handleOnChanged(HTMLElement htmlElement) {
+		if(inputField == htmlElement) {
+			if(intValue) {
+				int i;
+				try {
+					i = Integer.parseInt(inputField.getValue().trim());
+				}catch(NumberFormatException ex) {
+					inputField.setValue("0");
+					return;
+				}
+				if(i < 0) {
+					inputField.setValue("0");
+				}
+			}else {
+				inputField.setValue(inputField.getValue().trim());
+			}
+		}
+	}
+
+	public void handleOnClick(HTMLElement htmlElement) {
+		if(doneButton == htmlElement) {
+			onSave(inputField);
+		}else if(cancelButton == htmlElement) {
+			onCancel();
+		}
+	}
+
+	public void handleOnMouseOver(HTMLElement htmlElement) {
+		if(doneButton == htmlElement) {
+			setCancelSelected(false);
+		}else if(cancelButton == htmlElement) {
+			setCancelSelected(true);
+		}
+	}
+
+	public void handleKeyDown(int keyCode) {
+		if(keyCode == KeyCodes.DOM_KEY_ARROW_RIGHT) {
+			setCancelSelected(false);
+		}else if(keyCode == KeyCodes.DOM_KEY_ARROW_LEFT) {
+			setCancelSelected(true);
+		}else if(keyCode == KeyCodes.DOM_KEY_ENTER) {
+			handleOnChanged(inputField);
+			onSave(inputField);
+		}else if(keyCode == KeyCodes.DOM_KEY_ESCAPE) {
+			onCancel();
+		}
+	}
+
+	public void setCancelSelected(boolean sel) {
+		if(sel) {
+			if(!cancelSelected) {
+				cancelSelected = true;
+				cancelButton.getClassList().add(BootMenuConstants.cssClassPrefixBootMenu + "popup_input_opt_selected");
+				doneButton.getClassList().remove(BootMenuConstants.cssClassPrefixBootMenu + "popup_input_opt_selected");
+			}
+		}else {
+			if(cancelSelected) {
+				cancelSelected = false;
+				doneButton.getClassList().add(BootMenuConstants.cssClassPrefixBootMenu + "popup_input_opt_selected");
+				cancelButton.getClassList().remove(BootMenuConstants.cssClassPrefixBootMenu + "popup_input_opt_selected");
+			}
+		}
+	}
+
+	protected abstract void onSave(HTMLInputElement inputField);
+
+	protected abstract void onCancel();
+
+}
diff --git a/sources/teavm-boot-menu/java/net/lax1dude/eaglercraft/v1_8/boot_menu/teavm/KeyCodes.java b/sources/teavm-boot-menu/java/net/lax1dude/eaglercraft/v1_8/boot_menu/teavm/KeyCodes.java
new file mode 100644
index 00000000..c7d33efe
--- /dev/null
+++ b/sources/teavm-boot-menu/java/net/lax1dude/eaglercraft/v1_8/boot_menu/teavm/KeyCodes.java
@@ -0,0 +1,34 @@
+package net.lax1dude.eaglercraft.v1_8.boot_menu.teavm;
+
+/**
+ * Copyright (c) 2024 lax1dude. All Rights Reserved.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ * 
+ */
+public class KeyCodes {
+
+	public static final int DOM_KEY_SHIFT = 16;
+	public static final int DOM_KEY_CONTROL = 17;
+	public static final int DOM_KEY_ALT = 18;
+	public static final int DOM_KEY_ENTER = 13;
+	public static final int DOM_KEY_ESCAPE = 27;
+
+	public static final int DOM_KEY_E = 69;
+	public static final int DOM_KEY_SPACE = 32;
+
+	public static final int DOM_KEY_ARROW_LEFT = 37;
+	public static final int DOM_KEY_ARROW_UP = 38;
+	public static final int DOM_KEY_ARROW_RIGHT = 39;
+	public static final int DOM_KEY_ARROW_DOWN = 40;
+
+}
diff --git a/sources/teavm-boot-menu/java/net/lax1dude/eaglercraft/v1_8/boot_menu/teavm/LaunchConfigEntry.java b/sources/teavm-boot-menu/java/net/lax1dude/eaglercraft/v1_8/boot_menu/teavm/LaunchConfigEntry.java
new file mode 100644
index 00000000..de04f67a
--- /dev/null
+++ b/sources/teavm-boot-menu/java/net/lax1dude/eaglercraft/v1_8/boot_menu/teavm/LaunchConfigEntry.java
@@ -0,0 +1,143 @@
+package net.lax1dude.eaglercraft.v1_8.boot_menu.teavm;
+
+import org.json.JSONObject;
+
+import net.lax1dude.eaglercraft.v1_8.EaglercraftUUID;
+
+/**
+ * Copyright (c) 2024 lax1dude. All Rights Reserved.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ * 
+ */
+public class LaunchConfigEntry {
+
+	public final EaglercraftUUID uuid;
+	public final EaglercraftUUID clientDataUUID;
+	public String displayName;
+	public EnumClientLaunchType type;
+	public String joinServer;
+	public String launchOptsVar;
+	public String launchOptsAssetsURIVar;
+	public String launchOptsContainerVar;
+	public String mainFunction;
+	public String launchOpts;
+	public boolean clearCookiesBeforeLaunch;
+
+	public LaunchConfigEntry(EaglercraftUUID uuid, EaglercraftUUID clientDataUUID) {
+		this.uuid = uuid;
+		this.clientDataUUID = clientDataUUID;
+	}
+
+	public LaunchConfigEntry(EaglercraftUUID uuid, EaglercraftUUID clientDataUUID, String displayName,
+			EnumClientLaunchType type, String joinServer, String launchOptsVar, String assetsURIVar,
+			String containerVar, String mainFunction, String launchOpts, boolean clearCookiesBeforeLaunch) {
+		this.uuid = uuid;
+		this.clientDataUUID = clientDataUUID;
+		this.displayName = displayName;
+		this.type = type;
+		this.joinServer = joinServer;
+		this.launchOptsVar = launchOptsVar;
+		this.launchOptsAssetsURIVar = assetsURIVar;
+		this.launchOptsContainerVar = containerVar;
+		this.mainFunction = mainFunction;
+		this.launchOpts = launchOpts;
+		this.clearCookiesBeforeLaunch = clearCookiesBeforeLaunch;
+	}
+
+	public LaunchConfigEntry(EaglercraftUUID uuid, JSONObject jsonObject) {
+		this.uuid = uuid;
+		EaglercraftUUID sanityUUID = EaglercraftUUID.fromString(jsonObject.getString("uuid"));
+		if(!sanityUUID.equals(uuid)) {
+			throw new IllegalArgumentException("The file's name UUID does not equal the UUID string found in the file!");
+		}
+		int typeId = jsonObject.getInt("type");
+		type = EnumClientLaunchType.getById(typeId);
+		if(type == null) {
+			throw new IllegalArgumentException("Unknown launch configuration type " + typeId + "!");
+		}
+		clientDataUUID = EaglercraftUUID.fromString(jsonObject.getString("dataUUID"));
+		displayName = jsonObject.getString("displayName");
+		clearCookiesBeforeLaunch = jsonObject.getBoolean("clearCookies");
+		switch(type) {
+		case STANDARD_OFFLINE_V1:
+			launchOpts = jsonObject.getString("launchOpts");
+			launchOptsVar = jsonObject.getString("launchOptsVar");
+			launchOptsAssetsURIVar = jsonObject.getString("assetsURIVar");
+			launchOptsContainerVar = jsonObject.getString("containerVar");
+			mainFunction = jsonObject.getString("entryPoint");
+			break;
+		case EAGLERX_V1:
+		case EAGLERX_SIGNED_V1:
+		case EAGLER_1_5_V2:
+		case PEYTON_V2:
+			launchOpts = jsonObject.getString("launchOpts");
+			break;
+		case EAGLER_1_5_V1:
+			launchOpts = jsonObject.getString("launchOpts");
+			joinServer = jsonObject.getString("joinServer");
+			break;
+		case EAGLER_BETA_V1:
+			joinServer = jsonObject.getString("joinServer");
+			break;
+		case PEYTON_V1:
+			break;
+		default: //?
+			break;
+		}
+	}
+
+	public void writeJSON(JSONObject jsonObject) {
+		jsonObject.put("uuid", uuid.toString());
+		jsonObject.put("type", type.id);
+		jsonObject.put("dataUUID", clientDataUUID.toString());
+		jsonObject.put("displayName", displayName);
+		jsonObject.put("clearCookies", clearCookiesBeforeLaunch);
+		switch(type) {
+		case STANDARD_OFFLINE_V1:
+			jsonObject.put("launchOpts", launchOpts != null ? launchOpts : "{ }");
+			jsonObject.put("launchOptsVar", launchOptsVar != null ? launchOptsVar : "eaglercraftXOpts");
+			jsonObject.put("assetsURIVar", launchOptsAssetsURIVar != null ? launchOptsAssetsURIVar : "assetsURI");
+			jsonObject.put("containerVar", launchOptsContainerVar != null ? launchOptsContainerVar : "container");
+			jsonObject.put("entryPoint", mainFunction != null ? mainFunction : "main");
+			break;
+		case EAGLERX_V1:
+		case EAGLERX_SIGNED_V1:
+		case EAGLER_1_5_V2:
+		case PEYTON_V2:
+			jsonObject.put("launchOpts", launchOpts != null ? launchOpts : "{ }");
+			break;
+		case EAGLER_1_5_V1:
+			jsonObject.put("launchOpts", launchOpts != null ? launchOpts : "[NBT]{ }[/NBT]");
+			jsonObject.put("joinServer", joinServer != null ? joinServer : "");
+			break;
+		case EAGLER_BETA_V1:
+			jsonObject.put("joinServer", joinServer != null ? joinServer : "");
+			break;
+		case PEYTON_V1:
+			break;
+		default: //?
+			break;
+		}
+	}
+
+	public LaunchConfigEntry rotateUUIDs(EaglercraftUUID rotatedLaunchUUID, EaglercraftUUID rotatedClientUUID) {
+		return new LaunchConfigEntry(rotatedLaunchUUID, rotatedClientUUID, displayName, type, joinServer, launchOptsVar,
+				launchOptsAssetsURIVar, launchOptsContainerVar, mainFunction, launchOpts, clearCookiesBeforeLaunch);
+	}
+
+	public LaunchConfigEntry fork() {
+		return new LaunchConfigEntry(uuid, clientDataUUID, displayName, type, joinServer, launchOptsVar,
+				launchOptsAssetsURIVar, launchOptsContainerVar, mainFunction, launchOpts, clearCookiesBeforeLaunch);
+	}
+
+}
diff --git a/sources/teavm-boot-menu/java/net/lax1dude/eaglercraft/v1_8/boot_menu/teavm/MenuPopupStateConfirmation.java b/sources/teavm-boot-menu/java/net/lax1dude/eaglercraft/v1_8/boot_menu/teavm/MenuPopupStateConfirmation.java
new file mode 100644
index 00000000..77762a16
--- /dev/null
+++ b/sources/teavm-boot-menu/java/net/lax1dude/eaglercraft/v1_8/boot_menu/teavm/MenuPopupStateConfirmation.java
@@ -0,0 +1,141 @@
+package net.lax1dude.eaglercraft.v1_8.boot_menu.teavm;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.teavm.jso.dom.html.HTMLElement;
+
+import com.google.common.collect.Collections2;
+
+/**
+ * Copyright (c) 2024 lax1dude. All Rights Reserved.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ * 
+ */
+public abstract class MenuPopupStateConfirmation<E> extends MenuState {
+
+	public static enum EnumYesNoHelper {
+		YES("Yes"),
+		NO("No");
+		
+		private final String str;
+		
+		private EnumYesNoHelper(String str) {
+			this.str = str;
+		}
+		
+		@Override
+		public String toString() {
+			return str;
+		}
+	}
+
+	protected class SelectionItem implements ConfirmationPopupController.SelectionOption {
+
+		protected E enumValue;
+
+		protected SelectionItem(E enumValue) {
+			this.enumValue = enumValue;
+		}
+
+		@Override
+		public String getName() {
+			return enumValue.toString();
+		}
+
+	}
+
+	protected final String title;
+	protected final List<E> options;
+	protected final ConfirmationPopupController<SelectionItem> popupController;
+
+	public MenuPopupStateConfirmation(String title, List<E> options) {
+		this.title = title;
+		this.options = options;
+		this.popupController = new ConfirmationPopupController<SelectionItem>(
+				BootMenuMain.bootMenuDOM.popup_confirm_opts,
+				new ArrayList<SelectionItem>(Collections2.transform(options, SelectionItem::new))) {
+			@Override
+			protected void optionSelected(SelectionItem item) {
+				MenuPopupStateConfirmation.this.selectCallback(item.enumValue);
+			}
+		};
+	}
+
+	@Override
+	protected void enterState() {
+		popupController.setup();
+		BootMenuMain.bootMenuDOM.popup_confirm_title.setInnerText(title);
+		BootMenuDOM.show(BootMenuMain.bootMenuDOM.popup_view_confirm);
+		BootMenuDOM.show(BootMenuMain.bootMenuDOM.popup);
+	}
+
+	@Override
+	protected void exitState() {
+		popupController.destroy();
+		BootMenuDOM.hide(BootMenuMain.bootMenuDOM.popup_view_confirm);
+		BootMenuDOM.hide(BootMenuMain.bootMenuDOM.popup);
+	}
+
+	@Override
+	protected void enterPopupBlockingState() {
+		throw new IllegalStateException();
+	}
+
+	@Override
+	protected void exitPopupBlockingState() {
+		throw new IllegalStateException();
+	}
+
+	@Override
+	protected void handleKeyDown(int keyCode) {
+		if(keyCode == KeyCodes.DOM_KEY_ESCAPE) {
+			BootMenuMain.currentState.changePopupState(null);
+			return;
+		}
+		popupController.handleKeyDown(keyCode);
+	}
+
+	@Override
+	protected void handleKeyUp(int keyCode) {
+		
+	}
+
+	@Override
+	protected void handleKeyRepeat(int keyCode) {
+		popupController.handleKeyRepeat(keyCode);
+	}
+
+	@Override
+	protected void handleOnChanged(HTMLElement htmlElement) {
+		
+	}
+
+	@Override
+	protected void handleOnClick(HTMLElement htmlElement) {
+		
+	}
+
+	@Override
+	protected void handleOnMouseOver(HTMLElement htmlElement) {
+		
+	}
+
+	@Override
+	protected void update() {
+		
+	}
+
+	protected abstract void selectCallback(E enumValue);
+
+}
diff --git a/sources/teavm-boot-menu/java/net/lax1dude/eaglercraft/v1_8/boot_menu/teavm/MenuPopupStateEditInteger.java b/sources/teavm-boot-menu/java/net/lax1dude/eaglercraft/v1_8/boot_menu/teavm/MenuPopupStateEditInteger.java
new file mode 100644
index 00000000..67e560a2
--- /dev/null
+++ b/sources/teavm-boot-menu/java/net/lax1dude/eaglercraft/v1_8/boot_menu/teavm/MenuPopupStateEditInteger.java
@@ -0,0 +1,114 @@
+package net.lax1dude.eaglercraft.v1_8.boot_menu.teavm;
+
+import org.teavm.jso.dom.html.HTMLElement;
+import org.teavm.jso.dom.html.HTMLInputElement;
+
+/**
+ * Copyright (c) 2024 lax1dude. All Rights Reserved.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ * 
+ */
+public abstract class MenuPopupStateEditInteger extends MenuState {
+
+	protected final InputPopupController inputPopupController;
+	protected final String menuTitle;
+	protected final int defaultValue;
+
+	public MenuPopupStateEditInteger(String menuTitle, int defaultValue) {
+		this.inputPopupController = new InputPopupController((HTMLInputElement) BootMenuMain.bootMenuDOM.popup_input_val,
+				true, BootMenuMain.bootMenuDOM.popup_input_opt_cancel, BootMenuMain.bootMenuDOM.popup_input_opt_done) {
+
+					@Override
+					protected void onSave(HTMLInputElement inputField) {
+						int i = 0;
+						try {
+							i = Integer.parseInt(inputField.getValue().trim());
+						}catch(NumberFormatException ex) {
+						}
+						MenuPopupStateEditInteger.this.onSave(i);
+					}
+
+					@Override
+					protected void onCancel() {
+						MenuPopupStateEditInteger.this.onCancel();
+					}
+
+		};
+		this.menuTitle = menuTitle;
+		this.defaultValue = defaultValue;
+	}
+
+	@Override
+	protected void enterState() {
+		BootMenuMain.bootMenuDOM.popup_input_title.setInnerText(menuTitle);
+		BootMenuDOM.show(BootMenuMain.bootMenuDOM.popup_view_input);
+		BootMenuDOM.show(BootMenuMain.bootMenuDOM.popup);
+		inputPopupController.setup(Integer.toString(defaultValue));
+	}
+
+	@Override
+	protected void exitState() {
+		BootMenuDOM.hide(BootMenuMain.bootMenuDOM.popup_view_input);
+		BootMenuDOM.hide(BootMenuMain.bootMenuDOM.popup);
+	}
+
+	@Override
+	protected void enterPopupBlockingState() {
+		throw new IllegalStateException();
+	}
+
+	@Override
+	protected void exitPopupBlockingState() {
+		throw new IllegalStateException();
+	}
+
+	@Override
+	protected void handleKeyDown(int keyCode) {
+		inputPopupController.handleKeyDown(keyCode);
+	}
+
+	@Override
+	protected void handleKeyUp(int keyCode) {
+		
+	}
+
+	@Override
+	protected void handleKeyRepeat(int keyCode) {
+		
+	}
+
+	@Override
+	protected void handleOnChanged(HTMLElement htmlElement) {
+		inputPopupController.handleOnChanged(htmlElement);
+	}
+
+	@Override
+	protected void handleOnClick(HTMLElement htmlElement) {
+		inputPopupController.handleOnClick(htmlElement);
+	}
+
+	@Override
+	protected void handleOnMouseOver(HTMLElement htmlElement) {
+		inputPopupController.handleOnMouseOver(htmlElement);
+	}
+
+	@Override
+	protected void update() {
+		
+	}
+
+	protected abstract void onSave(int i);
+
+	protected abstract void onCancel();
+
+}
diff --git a/sources/teavm-boot-menu/java/net/lax1dude/eaglercraft/v1_8/boot_menu/teavm/MenuPopupStateEditString.java b/sources/teavm-boot-menu/java/net/lax1dude/eaglercraft/v1_8/boot_menu/teavm/MenuPopupStateEditString.java
new file mode 100644
index 00000000..7f3e37c7
--- /dev/null
+++ b/sources/teavm-boot-menu/java/net/lax1dude/eaglercraft/v1_8/boot_menu/teavm/MenuPopupStateEditString.java
@@ -0,0 +1,109 @@
+package net.lax1dude.eaglercraft.v1_8.boot_menu.teavm;
+
+import org.teavm.jso.dom.html.HTMLElement;
+import org.teavm.jso.dom.html.HTMLInputElement;
+
+/**
+ * Copyright (c) 2024 lax1dude. All Rights Reserved.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ * 
+ */
+public abstract class MenuPopupStateEditString extends MenuState {
+
+	protected final InputPopupController inputPopupController;
+	protected final String menuTitle;
+	protected final String defaultValue;
+
+	public MenuPopupStateEditString(String menuTitle, String defaultValue) {
+		this.inputPopupController = new InputPopupController((HTMLInputElement) BootMenuMain.bootMenuDOM.popup_input_val,
+				false, BootMenuMain.bootMenuDOM.popup_input_opt_cancel, BootMenuMain.bootMenuDOM.popup_input_opt_done) {
+
+					@Override
+					protected void onSave(HTMLInputElement inputField) {
+						MenuPopupStateEditString.this.onSave(inputField.getValue().trim());
+					}
+
+					@Override
+					protected void onCancel() {
+						MenuPopupStateEditString.this.onCancel();
+					}
+
+		};
+		this.menuTitle = menuTitle;
+		this.defaultValue = defaultValue;
+	}
+
+	@Override
+	protected void enterState() {
+		BootMenuMain.bootMenuDOM.popup_input_title.setInnerText(menuTitle);
+		BootMenuDOM.show(BootMenuMain.bootMenuDOM.popup_view_input);
+		BootMenuDOM.show(BootMenuMain.bootMenuDOM.popup);
+		inputPopupController.setup(defaultValue);
+	}
+
+	@Override
+	protected void exitState() {
+		BootMenuDOM.hide(BootMenuMain.bootMenuDOM.popup_view_input);
+		BootMenuDOM.hide(BootMenuMain.bootMenuDOM.popup);
+	}
+
+	@Override
+	protected void enterPopupBlockingState() {
+		throw new IllegalStateException();
+	}
+
+	@Override
+	protected void exitPopupBlockingState() {
+		throw new IllegalStateException();
+	}
+
+	@Override
+	protected void handleKeyDown(int keyCode) {
+		inputPopupController.handleKeyDown(keyCode);
+	}
+
+	@Override
+	protected void handleKeyUp(int keyCode) {
+		
+	}
+
+	@Override
+	protected void handleKeyRepeat(int keyCode) {
+		
+	}
+
+	@Override
+	protected void handleOnChanged(HTMLElement htmlElement) {
+		inputPopupController.handleOnChanged(htmlElement);
+	}
+
+	@Override
+	protected void handleOnClick(HTMLElement htmlElement) {
+		inputPopupController.handleOnClick(htmlElement);
+	}
+
+	@Override
+	protected void handleOnMouseOver(HTMLElement htmlElement) {
+		inputPopupController.handleOnMouseOver(htmlElement);
+	}
+
+	@Override
+	protected void update() {
+		
+	}
+
+	protected abstract void onSave(String str);
+
+	protected abstract void onCancel();
+
+}
diff --git a/sources/teavm-boot-menu/java/net/lax1dude/eaglercraft/v1_8/boot_menu/teavm/MenuPopupStateFileChooser.java b/sources/teavm-boot-menu/java/net/lax1dude/eaglercraft/v1_8/boot_menu/teavm/MenuPopupStateFileChooser.java
new file mode 100644
index 00000000..d55a3648
--- /dev/null
+++ b/sources/teavm-boot-menu/java/net/lax1dude/eaglercraft/v1_8/boot_menu/teavm/MenuPopupStateFileChooser.java
@@ -0,0 +1,106 @@
+package net.lax1dude.eaglercraft.v1_8.boot_menu.teavm;
+
+import org.teavm.jso.dom.html.HTMLElement;
+
+import net.lax1dude.eaglercraft.v1_8.EagRuntime;
+import net.lax1dude.eaglercraft.v1_8.internal.FileChooserResult;
+
+/**
+ * Copyright (c) 2024 lax1dude. All Rights Reserved.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ * 
+ */
+public abstract class MenuPopupStateFileChooser extends MenuState {
+
+	protected final String text;
+	protected final String mime;
+	protected final String ext;
+	protected String msg;
+	private boolean waitingForFile = false;
+
+	public MenuPopupStateFileChooser(String text, String mime, String ext) {
+		this.text = text;
+		this.mime = mime;
+		this.ext = ext;
+	}
+
+	@Override
+	protected void enterState() {
+		BootMenuMain.bootMenuDOM.popup_confirm_opts.setInnerHTML("");
+		BootMenuMain.bootMenuDOM.popup_confirm_title.setInnerText(text + "\n\nPress ESC to cancel");
+		BootMenuDOM.show(BootMenuMain.bootMenuDOM.popup_view_confirm);
+		BootMenuDOM.show(BootMenuMain.bootMenuDOM.popup);
+		EagRuntime.displayFileChooser(mime, ext);
+		waitingForFile = true;
+	}
+
+	@Override
+	protected void exitState() {
+		BootMenuDOM.hide(BootMenuMain.bootMenuDOM.popup_view_confirm);
+		BootMenuDOM.hide(BootMenuMain.bootMenuDOM.popup);
+	}
+
+	@Override
+	protected void enterPopupBlockingState() {
+		throw new IllegalStateException();
+	}
+
+	@Override
+	protected void exitPopupBlockingState() {
+		throw new IllegalStateException();
+	}
+
+	@Override
+	protected void handleKeyDown(int keyCode) {
+		if(keyCode == KeyCodes.DOM_KEY_ESCAPE) {
+			waitingForFile = false;
+			onResult(null);
+		}
+	}
+
+	@Override
+	protected void handleKeyUp(int keyCode) {
+		
+	}
+
+	@Override
+	protected void handleKeyRepeat(int keyCode) {
+		
+	}
+
+	@Override
+	protected void handleOnChanged(HTMLElement htmlElement) {
+		
+	}
+
+	@Override
+	protected void handleOnClick(HTMLElement htmlElement) {
+		
+	}
+
+	@Override
+	protected void handleOnMouseOver(HTMLElement htmlElement) {
+		
+	}
+
+	@Override
+	protected void update() {
+		if(waitingForFile && EagRuntime.fileChooserHasResult()) {
+			waitingForFile = false;
+			onResult(EagRuntime.getFileChooserResult());
+		}
+	}
+
+	protected abstract void onResult(FileChooserResult res);
+
+}
\ No newline at end of file
diff --git a/sources/teavm-boot-menu/java/net/lax1dude/eaglercraft/v1_8/boot_menu/teavm/MenuPopupStateLoading.java b/sources/teavm-boot-menu/java/net/lax1dude/eaglercraft/v1_8/boot_menu/teavm/MenuPopupStateLoading.java
new file mode 100644
index 00000000..6c6564d2
--- /dev/null
+++ b/sources/teavm-boot-menu/java/net/lax1dude/eaglercraft/v1_8/boot_menu/teavm/MenuPopupStateLoading.java
@@ -0,0 +1,98 @@
+package net.lax1dude.eaglercraft.v1_8.boot_menu.teavm;
+
+import org.apache.commons.lang3.StringUtils;
+import org.teavm.jso.dom.html.HTMLElement;
+
+import net.lax1dude.eaglercraft.v1_8.EagUtils;
+
+/**
+ * Copyright (c) 2024 lax1dude. All Rights Reserved.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ * 
+ */
+public class MenuPopupStateLoading extends MenuState implements IProgressMsgCallback {
+
+	protected final String text;
+	protected String msg;
+
+	public MenuPopupStateLoading(String text) {
+		this.text = text;
+	}
+
+	@Override
+	protected void enterState() {
+		BootMenuMain.bootMenuDOM.popup_confirm_opts.setInnerHTML("");
+		BootMenuMain.bootMenuDOM.popup_confirm_title.setInnerText(!StringUtils.isAllEmpty(msg) ? (text + "\n\n" + msg) : text);
+		BootMenuDOM.show(BootMenuMain.bootMenuDOM.popup_view_confirm);
+		BootMenuDOM.show(BootMenuMain.bootMenuDOM.popup);
+	}
+
+	@Override
+	protected void exitState() {
+		BootMenuDOM.hide(BootMenuMain.bootMenuDOM.popup_view_confirm);
+		BootMenuDOM.hide(BootMenuMain.bootMenuDOM.popup);
+	}
+
+	@Override
+	protected void enterPopupBlockingState() {
+		throw new IllegalStateException();
+	}
+
+	@Override
+	protected void exitPopupBlockingState() {
+		throw new IllegalStateException();
+	}
+
+	@Override
+	protected void handleKeyDown(int keyCode) {
+		
+	}
+
+	@Override
+	protected void handleKeyUp(int keyCode) {
+		
+	}
+
+	@Override
+	protected void handleKeyRepeat(int keyCode) {
+		
+	}
+
+	@Override
+	protected void handleOnChanged(HTMLElement htmlElement) {
+		
+	}
+
+	@Override
+	protected void handleOnClick(HTMLElement htmlElement) {
+		
+	}
+
+	@Override
+	protected void handleOnMouseOver(HTMLElement htmlElement) {
+		
+	}
+
+	@Override
+	public void updateMessage(String msg) {
+		this.msg = msg;
+		BootMenuMain.bootMenuDOM.popup_confirm_title.setInnerText(!StringUtils.isAllEmpty(msg) ? (text + "\n\n" + msg) : text);
+		EagUtils.sleep(50l);
+	}
+
+	@Override
+	protected void update() {
+		
+	}
+
+}
diff --git a/sources/teavm-boot-menu/java/net/lax1dude/eaglercraft/v1_8/boot_menu/teavm/MenuPopupStateSelection.java b/sources/teavm-boot-menu/java/net/lax1dude/eaglercraft/v1_8/boot_menu/teavm/MenuPopupStateSelection.java
new file mode 100644
index 00000000..fa02c6d4
--- /dev/null
+++ b/sources/teavm-boot-menu/java/net/lax1dude/eaglercraft/v1_8/boot_menu/teavm/MenuPopupStateSelection.java
@@ -0,0 +1,141 @@
+package net.lax1dude.eaglercraft.v1_8.boot_menu.teavm;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.function.Consumer;
+
+import org.teavm.jso.dom.html.HTMLElement;
+
+import com.google.common.collect.Collections2;
+
+/**
+ * Copyright (c) 2024 lax1dude. All Rights Reserved.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ * 
+ */
+public abstract class MenuPopupStateSelection<T> extends MenuState {
+
+	public static class SelectionItem<E> implements SelectionListController.ListItem {
+
+		protected final String name;
+		protected final E enumValue;
+
+		public SelectionItem(E enumValue, String name) {
+			this.name = name;
+			this.enumValue = enumValue;
+		}
+
+		public SelectionItem(E enumValue) {
+			this.name = enumValue.toString();
+			this.enumValue = enumValue;
+		}
+
+		@Override
+		public String getName() {
+			return name;
+		}
+
+	}
+
+	protected final String title;
+	protected final List<SelectionItem<T>> items;
+	protected SelectionListController<SelectionItem<T>> selectionController;
+
+	public MenuPopupStateSelection(String title, List<SelectionItem<T>> items) {
+		this.title = title;
+		this.items = items;
+		this.selectionController = new SelectionListController<SelectionItem<T>>(BootMenuMain.bootMenuDOM.popup_selection, items) {
+			@Override
+			protected void itemSelected(SelectionItem<T> item) {
+				MenuPopupStateSelection.this.itemSelected(item.enumValue);
+			}
+		};
+	}
+
+	public static <T> MenuPopupStateSelection<T> createHelper(String title, List<T> items, Consumer<T> selectCallback) {
+		return new MenuPopupStateSelection<T>(title,
+				new ArrayList<SelectionItem<T>>(Collections2.transform(items, SelectionItem<T>::new))) {
+			@Override
+			protected void itemSelected(T item) {
+				selectCallback.accept(item);
+			}
+		};
+	}
+
+	@Override
+	protected void enterState() {
+		selectionController.setup();
+		BootMenuMain.bootMenuDOM.popup_selection_title.setInnerText(title);
+		BootMenuDOM.show(BootMenuMain.bootMenuDOM.popup_view_selection);
+		BootMenuDOM.show(BootMenuMain.bootMenuDOM.popup);
+	}
+
+	@Override
+	protected void exitState() {
+		selectionController.destroy();
+		BootMenuDOM.hide(BootMenuMain.bootMenuDOM.popup_view_selection);
+		BootMenuDOM.hide(BootMenuMain.bootMenuDOM.popup);
+	}
+
+	@Override
+	protected void enterPopupBlockingState() {
+		throw new IllegalStateException();
+	}
+
+	@Override
+	protected void exitPopupBlockingState() {
+		throw new IllegalStateException();
+	}
+
+	@Override
+	protected void handleKeyDown(int keyCode) {
+		if(keyCode == KeyCodes.DOM_KEY_ESCAPE) {
+			BootMenuMain.currentState.changePopupState(null);
+			return;
+		}
+		selectionController.handleKeyDown(keyCode);
+	}
+
+	@Override
+	protected void handleKeyUp(int keyCode) {
+		
+	}
+
+	@Override
+	protected void handleKeyRepeat(int keyCode) {
+		selectionController.handleKeyRepeat(keyCode);
+	}
+
+	@Override
+	protected void handleOnChanged(HTMLElement htmlElement) {
+		
+	}
+
+	@Override
+	protected void handleOnClick(HTMLElement htmlElement) {
+		
+	}
+
+	@Override
+	protected void handleOnMouseOver(HTMLElement htmlElement) {
+		
+	}
+
+	@Override
+	protected void update() {
+		
+	}
+
+	protected abstract void itemSelected(T item);
+
+}
diff --git a/sources/teavm-boot-menu/java/net/lax1dude/eaglercraft/v1_8/boot_menu/teavm/MenuState.java b/sources/teavm-boot-menu/java/net/lax1dude/eaglercraft/v1_8/boot_menu/teavm/MenuState.java
new file mode 100644
index 00000000..a07f137e
--- /dev/null
+++ b/sources/teavm-boot-menu/java/net/lax1dude/eaglercraft/v1_8/boot_menu/teavm/MenuState.java
@@ -0,0 +1,135 @@
+package net.lax1dude.eaglercraft.v1_8.boot_menu.teavm;
+
+import org.teavm.jso.dom.html.HTMLElement;
+
+/**
+ * Copyright (c) 2024 lax1dude. All Rights Reserved.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ * 
+ */
+public abstract class MenuState {
+
+	protected MenuState currentPopup = null;
+
+	public void changePopupState(MenuState popup) {
+		if(popup == null) {
+			if(currentPopup != null) {
+				currentPopup.exitState();
+				exitPopupBlockingState();
+				currentPopup = null;
+			}
+		}else {
+			if(currentPopup != null) {
+				currentPopup.exitState();
+			}
+			currentPopup = popup;
+			enterPopupBlockingState();
+			popup.enterState();
+		}
+	}
+
+	public void doEnterState() {
+		enterState();
+		if(currentPopup != null) {
+			enterPopupBlockingState();
+			currentPopup.enterState();
+		}
+	}
+
+	public void doExitState() {
+		if(currentPopup != null) {
+			currentPopup.exitState();
+			exitPopupBlockingState();
+		}
+		exitState();
+	}
+
+	protected abstract void enterState();
+
+	protected abstract void exitState();
+
+	protected abstract void enterPopupBlockingState();
+
+	protected abstract void exitPopupBlockingState();
+
+	public void doHandleKeyDown(int keyCode) {
+		if(currentPopup != null) {
+			currentPopup.doHandleKeyDown(keyCode);
+		}else {
+			handleKeyDown(keyCode);
+		}
+	}
+
+	public void doHandleKeyUp(int keyCode) {
+		if(currentPopup != null) {
+			currentPopup.doHandleKeyUp(keyCode);
+		}else {
+			handleKeyUp(keyCode);
+		}
+	}
+
+	public void doHandleKeyRepeat(int keyCode) {
+		if(currentPopup != null) {
+			currentPopup.doHandleKeyRepeat(keyCode);
+		}else {
+			handleKeyRepeat(keyCode);
+		}
+	}
+
+	public void doHandleOnChange(HTMLElement element) {
+		if(currentPopup != null) {
+			currentPopup.doHandleOnChange(element);
+		}else {
+			handleOnChanged(element);
+		}
+	}
+
+	public void doHandleOnClick(HTMLElement element) {
+		if(currentPopup != null) {
+			currentPopup.doHandleOnClick(element);
+		}else {
+			handleOnClick(element);
+		}
+	}
+
+	public void doHandleOnMouseOver(HTMLElement element) {
+		if(currentPopup != null) {
+			currentPopup.doHandleOnMouseOver(element);
+		}else {
+			handleOnMouseOver(element);
+		}
+	}
+
+	public void doUpdate() {
+		if(currentPopup != null) {
+			currentPopup.doUpdate();
+		}else {
+			update();
+		}
+	}
+
+	protected abstract void handleKeyDown(int keyCode);
+
+	protected abstract void handleKeyUp(int keyCode);
+
+	protected abstract void handleKeyRepeat(int keyCode);
+
+	protected abstract void handleOnChanged(HTMLElement htmlElement);
+
+	protected abstract void handleOnClick(HTMLElement htmlElement);
+
+	protected abstract void handleOnMouseOver(HTMLElement htmlElement);
+
+	protected abstract void update();
+
+}
diff --git a/sources/teavm-boot-menu/java/net/lax1dude/eaglercraft/v1_8/boot_menu/teavm/MenuStateBoot.java b/sources/teavm-boot-menu/java/net/lax1dude/eaglercraft/v1_8/boot_menu/teavm/MenuStateBoot.java
new file mode 100644
index 00000000..62b5d60f
--- /dev/null
+++ b/sources/teavm-boot-menu/java/net/lax1dude/eaglercraft/v1_8/boot_menu/teavm/MenuStateBoot.java
@@ -0,0 +1,583 @@
+package net.lax1dude.eaglercraft.v1_8.boot_menu.teavm;
+
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.function.Consumer;
+
+import org.teavm.jso.dom.html.HTMLElement;
+
+import com.google.common.collect.Collections2;
+import com.google.common.collect.Lists;
+
+import net.lax1dude.eaglercraft.v1_8.EagRuntime;
+import net.lax1dude.eaglercraft.v1_8.EagUtils;
+import net.lax1dude.eaglercraft.v1_8.EaglercraftUUID;
+import net.lax1dude.eaglercraft.v1_8.boot_menu.teavm.BootMenuMetadata.DefaultLaunchTemplate;
+import net.lax1dude.eaglercraft.v1_8.boot_menu.teavm.OfflineDownloadParser.ParsedOfflineAdapter;
+import net.lax1dude.eaglercraft.v1_8.internal.FileChooserResult;
+import net.lax1dude.eaglercraft.v1_8.log4j.LogManager;
+import net.lax1dude.eaglercraft.v1_8.log4j.Logger;
+
+/**
+ * Copyright (c) 2024 lax1dude. All Rights Reserved.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ * 
+ */
+public class MenuStateBoot extends MenuState {
+
+	private static final Logger logger = LogManager.getLogger("MenuStateBoot");
+
+	private static class BootItem implements SelectionListController.ListItem, Runnable {
+
+		private final String name;
+		private final Consumer<BootItem> runnable;
+		private final Consumer<BootItem> onEdit;
+
+		private BootItem(String name, Consumer<BootItem> runnable, Consumer<BootItem> onEdit) {
+			this.name = name;
+			this.runnable = runnable;
+			this.onEdit = onEdit;
+		}
+
+		@Override
+		public String getName() {
+			return name;
+		}
+
+		@Override
+		public void run() {
+			runnable.accept(this);
+		}
+
+	}
+
+	protected SelectionListController<BootItem> selectionController;
+
+	private static enum EnumImportExportMenu {
+		IMPORT_CLIENT("Import Client"),
+		EXPORT_CLIENT("Export Client"),
+		EXPORT_OFFLINE_BUNDLE("Export Offline Bundle"),
+		CANCEL("Cancel");
+		
+		private final String str;
+		
+		private EnumImportExportMenu(String str) {
+			this.str = str;
+		}
+
+		@Override
+		public String toString() {
+			return str;
+		}
+
+	}
+
+	private static final List<EnumImportExportMenu> OPTIONS_NO_BUNDLE = Arrays.asList(
+			EnumImportExportMenu.IMPORT_CLIENT, EnumImportExportMenu.EXPORT_CLIENT, EnumImportExportMenu.CANCEL);
+
+	private static final List<EnumImportExportMenu> OPTIONS_BUNDLE = Arrays.asList(EnumImportExportMenu.IMPORT_CLIENT,
+			EnumImportExportMenu.EXPORT_CLIENT, EnumImportExportMenu.EXPORT_OFFLINE_BUNDLE,
+			EnumImportExportMenu.CANCEL);
+
+	private static enum EnumImportModeMenu {
+		AUTO_DETECT("Auto Detect"),
+		EAGLERCRAFT_EPK_FILE(".EPK Client Archive"),
+		EAGLERCRAFTX_1_8_OFFLINE("EaglercraftX 1.8 Offline .HTML"),
+		EAGLERCRAFTX_1_8_SIGNED("EaglercraftX 1.8 Signed .HTML"),
+		EAGLERCRAFTX_1_8_FAT_OFFLINE("EaglercraftX 1.8 Fat Offline .HTML"),
+		EAGLERCRAFTX_1_8_FAT_SIGNED("EaglercraftX 1.8 Fat Signed .HTML"),
+		EAGLERCRAFT_1_5_NEW_OFFLINE("Eaglercraft 1.5.2 Offline .HTML (post-22w34a)"),
+		EAGLERCRAFT_1_5_OLD_OFFLINE("Eaglercraft 1.5.2 Offline .HTML (pre-22w34a)"),
+		EAGLERCRAFT_BETA_B1_3_OFFLINE("Eaglercraft Beta 1.3 Offline .HTML"),
+		PEYTONPLAYZ585_BETA_1_7_3("PeytonPlayz585 Beta 1.7.3 Offline .HTML"),
+		PEYTONPLAYZ585_ALPHA_1_2_6("PeytonPlayz585 Alpha 1.2.6 Offline .HTML"),
+		PEYTONPLAYZ585_INDEV("PeytonPlayz585 Indev Offline .HTML"),
+		CANCEL("Cancel");
+		
+		private final String str;
+		
+		private EnumImportModeMenu(String str) {
+			this.str = str;
+		}
+
+		@Override
+		public String toString() {
+			return str;
+		}
+
+	}
+
+	private static enum EnumUnsignedClientAction {
+		DOWNLOAD_OFFLINE("Download Client"),
+		DOWNLOAD_EAGLERX_OFFLINE("Download EaglercraftX"),
+		CANCEL("Cancel");
+		
+		private final String str;
+		
+		private EnumUnsignedClientAction(String str) {
+			this.str = str;
+		}
+		
+		@Override
+		public String toString() {
+			return str;
+		}
+	}
+
+	public static void displayUnsignedError(final MenuState parentState, final Consumer<IProgressMsgCallback> onDownloadOffline, final Runnable onDone) {
+		parentState.changePopupState(new MenuPopupStateConfirmation<EnumUnsignedClientAction>(
+				"Error: This client does not have a valid signature!\n\nUnsigned clients are disabled on this website",
+				Arrays.asList(EnumUnsignedClientAction.values())) {
+			@Override
+			protected void selectCallback(EnumUnsignedClientAction enumValue) {
+				switch(enumValue) {
+				case DOWNLOAD_OFFLINE:
+					MenuPopupStateLoading loadingScreen = new MenuPopupStateLoading("Downloading client...");
+					parentState.changePopupState(loadingScreen);
+					try {
+						onDownloadOffline.accept(loadingScreen);
+					}catch(Throwable t) {
+						logger.error("Failed to invoke download offline function!");
+						logger.error(t);
+						parentState.changePopupState(new MenuPopupStateConfirmation<String>(
+								"Error: Failed to download!\n\n" + t.toString(),
+								Arrays.asList("OK")) {
+							@Override
+							protected void selectCallback(String enumValue) {
+								onDone.run();
+							}
+						});
+						return;
+					}
+					onDone.run();
+					break;
+				case DOWNLOAD_EAGLERX_OFFLINE:
+					loadingScreen = new MenuPopupStateLoading("Downloading client...");
+					parentState.changePopupState(loadingScreen);
+					try {
+						BootableClientEntry.getOriginClient().bootAdapter.downloadOffline(loadingScreen);
+					}catch(Throwable t) {
+						logger.error("Failed to invoke download offline function!");
+						logger.error(t);
+						parentState.changePopupState(new MenuPopupStateConfirmation<String>(
+								"Error: Failed to download!\n\n" + t.toString(),
+								Arrays.asList("OK")) {
+							@Override
+							protected void selectCallback(String enumValue) {
+								onDone.run();
+							}
+						});
+						return;
+					}
+					onDone.run();
+					break;
+				case CANCEL:
+				default:
+					onDone.run();
+					break;
+				}
+			}
+		});
+	}
+
+	protected int bootCountDown = 0;
+	protected int bootCountDownCur = 0;
+	protected long bootCountDownStart = 0l;
+	protected boolean doCountDown;
+
+	public MenuStateBoot(boolean doCountDown) {
+		this.doCountDown = doCountDown;
+		List<BootItem> list = new ArrayList<>();
+		final List<BootableClientEntry> bootableClients = BootableClientEntry.enumerateBootableClients();
+		if(BootableClientEntry.applyClientOrdering(BootMenuMain.bootMenuDataManager.launchOrderList, bootableClients)) {
+			BootMenuMain.bootMenuDataManager.writeManifest();
+		}
+		for(int i = 0, l = bootableClients.size(); i < l; ++i) {
+			final BootableClientEntry etr = bootableClients.get(i);
+			list.add(new BootItem(etr.bootAdapter.getDisplayName(),
+					(itm) -> {
+						MenuPopupStateLoading popupState = new MenuPopupStateLoading("Booting: '" + itm.name + "'...");
+						MenuStateBoot.this.changePopupState(popupState);
+						BootMenuMain.runLaterMS(() -> {
+							try {
+								etr.bootAdapter.bootClient(popupState);
+							}catch(UnsignedBootException ex) {
+								displayUnsignedError(MenuStateBoot.this, etr.bootAdapter::downloadOffline, () -> {
+									MenuStateBoot.this.changePopupState(null);
+								});
+								return;
+							}catch(Throwable t) {
+								logger.error("Failed to boot client!");
+								logger.error(t);
+								changePopupState(new MenuPopupStateConfirmation<String>("Error: Failed to boot client!\n\n" + t.toString(),
+										Arrays.asList("OK")) {
+									@Override
+									protected void selectCallback(String enumValue) {
+										MenuStateBoot.this.changePopupState(null);
+									}
+								});
+								return;
+							}
+						}, 250);
+					}, (itm) -> {
+						ClientDataEntry clientData = etr.bootAdapter.getClientDataEntry();
+						LaunchConfigEntry launchConf = etr.bootAdapter.getLaunchConfigEntry();
+						if(clientData != null && launchConf != null) {
+							BootMenuMain.changeState(new MenuStateEditingLaunch(MenuStateBoot.this, launchConf.fork(),
+									clientData, false, etr.bootAdapter.getBlobLoaders()));
+						}
+					}));
+		}
+		list.add(new BootItem("Import/Export",
+				(itm) -> {
+					MenuStateBoot.this.changePopupState(MenuPopupStateSelection.createHelper("What do you wanna do?",
+							bootableClients.size() > 1 ? OPTIONS_BUNDLE : OPTIONS_NO_BUNDLE, (enumValue) -> {
+								switch(enumValue) {
+								case IMPORT_CLIENT:
+									MenuStateBoot.this.changePopupState(MenuPopupStateSelection.createHelper("Select the format of the client:",
+											Arrays.asList(EnumImportModeMenu.values()), (enumValue2) -> {
+												EnumOfflineParseType parseType = null;
+												if(enumValue2 == EnumImportModeMenu.CANCEL) {
+													MenuStateBoot.this.changePopupState(null);
+													return;
+												}else if(enumValue2 != EnumImportModeMenu.AUTO_DETECT) {
+													switch(enumValue2) {
+													case EAGLERCRAFTX_1_8_OFFLINE: parseType = EnumOfflineParseType.EAGLERCRAFTX_1_8_OFFLINE; break;
+													case EAGLERCRAFTX_1_8_SIGNED: parseType = EnumOfflineParseType.EAGLERCRAFTX_1_8_SIGNED; break;
+													case EAGLERCRAFTX_1_8_FAT_OFFLINE: parseType = EnumOfflineParseType.EAGLERCRAFTX_1_8_FAT_OFFLINE; break;
+													case EAGLERCRAFTX_1_8_FAT_SIGNED: parseType = EnumOfflineParseType.EAGLERCRAFTX_1_8_FAT_SIGNED; break;
+													case EAGLERCRAFT_1_5_NEW_OFFLINE: parseType = EnumOfflineParseType.EAGLERCRAFT_1_5_NEW_OFFLINE; break;
+													case EAGLERCRAFT_1_5_OLD_OFFLINE: parseType = EnumOfflineParseType.EAGLERCRAFT_1_5_OLD_OFFLINE; break;
+													case EAGLERCRAFT_BETA_B1_3_OFFLINE: parseType = EnumOfflineParseType.EAGLERCRAFT_BETA_B1_3_OFFLINE; break;
+													case PEYTONPLAYZ585_BETA_1_7_3: parseType = EnumOfflineParseType.PEYTONPLAYZ585_ALPHA_BETA; break;
+													case PEYTONPLAYZ585_ALPHA_1_2_6: parseType = EnumOfflineParseType.PEYTONPLAYZ585_ALPHA_BETA; break;
+													case PEYTONPLAYZ585_INDEV: parseType = EnumOfflineParseType.PEYTONPLAYZ585_INDEV; break;
+													case EAGLERCRAFT_EPK_FILE: parseType = EnumOfflineParseType.EAGLERCRAFT_EPK_FILE; break;
+													default:
+														MenuStateBoot.this.changePopupState(null);
+														return;
+													}
+												}
+												String mime = parseType == EnumOfflineParseType.EAGLERCRAFT_EPK_FILE ? null : "text/html";
+												String ext = parseType == EnumOfflineParseType.EAGLERCRAFT_EPK_FILE ? "epk" : "html";
+												final EnumOfflineParseType parseTypeF = parseType;
+												MenuStateBoot.this.changePopupState(new MenuPopupStateFileChooser("Importing client...", mime, ext) {
+													@Override
+													protected void onResult(FileChooserResult res) {
+														if(res != null) {
+															MenuPopupStateLoading loadingScreen = new MenuPopupStateLoading("Importing client...");
+															MenuStateBoot.this.changePopupState(loadingScreen);
+															EagUtils.sleep(50l);
+															String offlineData = new String(res.fileData, StandardCharsets.UTF_8).replace("\r\n", "\n");
+															EnumOfflineParseType parseType2 = parseTypeF;
+															if(parseType2 == null) {
+																loadingScreen.updateMessage("Detecting type...");
+																try {
+																	parseType2 = OfflineDownloadParser.detectOfflineType(offlineData);
+																	if(parseType2 == null) {
+																		throw new IllegalStateException("Failed to detect offline download type!");
+																	}
+																}catch(Throwable t) {
+																	MenuStateBoot.this.changePopupState(new MenuPopupStateConfirmation<EnumImportModeMenu>(
+																			t.toString(), Arrays.asList(EnumImportModeMenu.CANCEL)) {
+																		@Override
+																		protected void selectCallback(EnumImportModeMenu enumValue) {
+																			MenuStateBoot.this.changePopupState(null);
+																			return;
+																		}
+																	});
+																	return;
+																}
+															}
+															loadingScreen.updateMessage("Parsing file...");
+															List<ParsedOfflineAdapter> parsedOfflines;
+															try {
+																if(parseType2 == EnumOfflineParseType.EAGLERCRAFT_EPK_FILE) {
+																	parsedOfflines = EPKClientParser.parseEPKClient(res.fileData);
+																}else {
+																	parsedOfflines = OfflineDownloadParser.parseOffline(parseType2, offlineData);
+																}
+																if(parsedOfflines == null || parsedOfflines.size() == 0) {
+																	throw new IllegalStateException("Failed to parse the file as \"" + parseType2 + "\"!");
+																}
+															}catch(Throwable t) {
+																MenuStateBoot.this.changePopupState(new MenuPopupStateConfirmation<EnumImportModeMenu>(
+																		t.toString(), Arrays.asList(EnumImportModeMenu.CANCEL)) {
+																	@Override
+																	protected void selectCallback(EnumImportModeMenu enumValue) {
+																		MenuStateBoot.this.changePopupState(null);
+																	}
+																});
+																return;
+															}
+															if(parsedOfflines.size() == 1) {
+																ParsedOfflineAdapter pp = parsedOfflines.get(0);
+																if(pp.launchData == null) {
+																	List<DefaultLaunchTemplate> templates = BootMenuMain.bootMenuMetadata.getTemplatesForParseType(pp.parseType);
+																	if(templates.size() == 0) {
+																		throw new IllegalStateException("Missing default launch type for parse type: " + pp.parseType);
+																	}
+																	if(templates.size() == 1) {
+																		EaglercraftUUID rotatedLaunchUUID = EaglercraftUUID.randomUUID();
+																		EaglercraftUUID rotatedClientUUID = EaglercraftUUID.randomUUID();
+																		LaunchConfigEntry launchConfig = templates.get(0).createLaunchConfig(rotatedLaunchUUID, rotatedClientUUID);
+																		ClientDataEntry clientData = pp.clientData.rotateUUID(rotatedClientUUID);
+																		MenuStateBoot.this.changePopupState(null);
+																		BootMenuMain.changeState(MenuStateEditingLaunch.createHelper(MenuStateBoot.this, launchConfig, clientData, true, pp.blobs));
+																	}else {
+																		MenuStateBoot.this.changePopupState(
+																				MenuPopupStateSelection.createHelper(
+																						"Please select the template launch configuration to use:",
+																						templates, (template) -> {
+																			if(template != null) {
+																				EaglercraftUUID rotatedLaunchUUID = EaglercraftUUID.randomUUID();
+																				EaglercraftUUID rotatedClientUUID = EaglercraftUUID.randomUUID();
+																				LaunchConfigEntry launchConfig = template.createLaunchConfig(rotatedLaunchUUID, rotatedClientUUID);
+																				ClientDataEntry clientData = pp.clientData.rotateUUID(rotatedClientUUID);
+																				MenuStateBoot.this.changePopupState(null);
+																				BootMenuMain.changeState(MenuStateEditingLaunch.createHelper(MenuStateBoot.this, launchConfig, clientData, true, pp.blobs));
+																			}else {
+																				MenuStateBoot.this.changePopupState(null);
+																			}
+																		}));
+																	}
+																}else {
+																	EaglercraftUUID rotatedLaunchUUID = EaglercraftUUID.randomUUID();
+																	EaglercraftUUID rotatedClientUUID = EaglercraftUUID.randomUUID();
+																	LaunchConfigEntry launchConfig = pp.launchData.rotateUUIDs(rotatedLaunchUUID, rotatedClientUUID);
+																	ClientDataEntry clientData = pp.clientData.rotateUUID(rotatedClientUUID);
+																	MenuStateBoot.this.changePopupState(null);
+																	BootMenuMain.changeState(MenuStateEditingLaunch.createHelper(MenuStateBoot.this, launchConfig, clientData, true, pp.blobs));
+																}
+															}else {
+																MenuStateBoot.this.changePopupState(null);
+																BootMenuMain.changeState(new MenuStateImportMultiSelect(MenuStateBoot.this, parsedOfflines));
+															}
+														}else {
+															MenuStateBoot.this.changePopupState(null);
+															return;
+														}
+													}
+												});
+												
+											}));
+									break;
+								case EXPORT_CLIENT:
+									final MenuState[] formatSelState = new MenuState[1];
+									formatSelState[0] = MenuPopupStateSelection.createHelper("Select the format of the client:",
+											Arrays.asList(EnumImportModeMenu.AUTO_DETECT, EnumImportModeMenu.EAGLERCRAFT_EPK_FILE,
+													EnumImportModeMenu.EAGLERCRAFTX_1_8_OFFLINE,
+													EnumImportModeMenu.EAGLERCRAFTX_1_8_SIGNED,
+													EnumImportModeMenu.EAGLERCRAFT_1_5_NEW_OFFLINE,
+													EnumImportModeMenu.EAGLERCRAFT_1_5_OLD_OFFLINE,
+													EnumImportModeMenu.EAGLERCRAFT_BETA_B1_3_OFFLINE,
+													EnumImportModeMenu.PEYTONPLAYZ585_BETA_1_7_3,
+													EnumImportModeMenu.PEYTONPLAYZ585_ALPHA_1_2_6,
+													EnumImportModeMenu.PEYTONPLAYZ585_INDEV,
+													EnumImportModeMenu.CANCEL), (enumValue2) -> {
+												List<BootableClientEntry> filteredList;
+												if(enumValue2 == EnumImportModeMenu.CANCEL) {
+													MenuStateBoot.this.changePopupState(null);
+													return;
+												}else if(enumValue2 == EnumImportModeMenu.AUTO_DETECT || enumValue2 == EnumImportModeMenu.EAGLERCRAFT_EPK_FILE) {
+													filteredList = bootableClients;
+												}else {
+													filteredList = Lists.newArrayList(Collections2.filter(bootableClients, (etr) -> {
+														switch(enumValue2) {
+														case EAGLERCRAFTX_1_8_OFFLINE:
+														case EAGLERCRAFT_1_5_OLD_OFFLINE:
+														case EAGLERCRAFT_BETA_B1_3_OFFLINE:
+														case PEYTONPLAYZ585_BETA_1_7_3:
+														case PEYTONPLAYZ585_ALPHA_1_2_6:
+														case PEYTONPLAYZ585_INDEV:
+															return etr.bootAdapter.getClientDataEntry().type == EnumClientFormatType.EAGLER_STANDARD_OFFLINE;
+														case EAGLERCRAFTX_1_8_SIGNED:
+															return etr.bootAdapter.getClientDataEntry().type == EnumClientFormatType.EAGLER_SIGNED_OFFLINE;
+														case EAGLERCRAFT_1_5_NEW_OFFLINE:
+															return etr.bootAdapter.getClientDataEntry().type == EnumClientFormatType.EAGLER_STANDARD_1_5_OFFLINE;
+														default:
+															return false;
+														}
+													}));
+												}
+												if(filteredList.size() > 0) {
+													MenuStateBoot.this.changePopupState(null);
+													BootMenuMain.changeState(new MenuStateSelectExportClients(enumValue2 == EnumImportModeMenu.EAGLERCRAFT_EPK_FILE, MenuStateBoot.this, filteredList));
+												}else {
+													changePopupState(new MenuPopupStateConfirmation<String>("Error: No clients available to export!",
+															Arrays.asList("OK")) {
+														@Override
+														protected void selectCallback(String enumValue) {
+															MenuStateBoot.this.changePopupState(formatSelState[0]);
+														}
+													});
+												}
+											});
+									MenuStateBoot.this.changePopupState(formatSelState[0]);
+									break;
+								case EXPORT_OFFLINE_BUNDLE:
+									MenuStateBoot.this.changePopupState(null);
+									BootMenuMain.changeState(new MenuStateClientMultiSelect(MenuStateBoot.this, bootableClients) {
+										@Override
+										protected void onDone(List<BootableClientEntry> entries) {
+											if(entries.size() > 0) {
+												MenuPopupStateLoading popupState = new MenuPopupStateLoading("Exporting Fat Offline...");
+												this.changePopupState(popupState);
+												try {
+													FatOfflineDownloadFactory.downloadOffline(entries, popupState);
+												}catch(Throwable t) {
+													logger.error("Failed to export fat offline!");
+													logger.error(t);
+													changePopupState(new MenuPopupStateConfirmation<String>(
+															"Error: Failed to export!\n\n" + t.toString(),
+															Arrays.asList("OK")) {
+														@Override
+														protected void selectCallback(String enumValue) {
+															BootMenuMain.changeState(MenuStateBoot.this);
+														}
+													});
+													return;
+												}
+											}
+											BootMenuMain.changeState(MenuStateBoot.this);
+										}
+									});
+									break;
+								case CANCEL:
+									MenuStateBoot.this.changePopupState(null);
+									break;
+								default:
+									break;
+								}
+							}));
+				}, null));
+		list.add(new BootItem("Enter Setup",
+				(itm) -> {
+					BootMenuMain.changeState(new MenuStateEnterSetup(bootableClients));
+				}, null));
+		selectionController = new SelectionListController<BootItem>(BootMenuMain.bootMenuDOM.content_selection, list) {
+				@Override
+				protected void itemSelected(BootItem item) {
+					item.run();
+				}
+		};
+	}
+
+	@Override
+	protected void enterState() {
+		if(doCountDown) {
+			bootCountDownStart = EagRuntime.steadyTimeMillis();
+			bootCountDown = BootMenuMain.bootMenuDataManager.confBootTimeout;
+			bootCountDownCur = bootCountDown;
+		}
+		selectionController.setup();
+		if(bootCountDown > 0) {
+			BootMenuDOM.show(BootMenuMain.bootMenuDOM.footer_text_boot_select_count);
+			BootMenuMain.bootMenuDOM.footer_text_boot_countdown.setInnerText(Integer.toString(bootCountDown));
+		}else {
+			BootMenuDOM.show(BootMenuMain.bootMenuDOM.footer_text_boot_select);
+		}
+		BootMenuDOM.show(BootMenuMain.bootMenuDOM.content_view_selection);
+	}
+
+	@Override
+	protected void exitState() {
+		selectionController.destroy();
+		BootMenuDOM.hide(BootMenuMain.bootMenuDOM.footer_text_boot_select);
+		BootMenuDOM.hide(BootMenuMain.bootMenuDOM.footer_text_boot_select_count);
+		BootMenuDOM.hide(BootMenuMain.bootMenuDOM.content_view_selection);
+	}
+
+	@Override
+	protected void enterPopupBlockingState() {
+		selectionController.setCursorEventsSuspended(true);
+	}
+
+	@Override
+	protected void exitPopupBlockingState() {
+		selectionController.setCursorEventsSuspended(false);
+	}
+
+	@Override
+	protected void handleKeyDown(int keyCode) {
+		boolean cancelEsc = bootCountDown > 0;
+		cancelCountdown();
+		if(keyCode == KeyCodes.DOM_KEY_ESCAPE) {
+			if(!cancelEsc) {
+				BootItem def = selectionController.selectionEnableList.get(0).listItem;
+				def.runnable.accept(def);
+			}
+		}else if(keyCode == KeyCodes.DOM_KEY_E) {
+			BootItem itm = selectionController.getSelected();
+			if(itm.onEdit != null) {
+				itm.onEdit.accept(itm);
+			}
+		}else {
+			selectionController.handleKeyDown(keyCode);
+		}
+	}
+
+	@Override
+	protected void handleKeyUp(int keyCode) {
+		
+	}
+
+	@Override
+	protected void handleKeyRepeat(int keyCode) {
+		cancelCountdown();
+		selectionController.handleKeyRepeat(keyCode);
+	}
+
+	@Override
+	protected void handleOnChanged(HTMLElement htmlElement) {
+		
+	}
+
+	@Override
+	protected void handleOnClick(HTMLElement htmlElement) {
+		
+	}
+
+	@Override
+	protected void handleOnMouseOver(HTMLElement htmlElement) {
+		
+	}
+
+	@Override
+	protected void update() {
+		if(bootCountDown > 0) {
+			int countDownCur = bootCountDown - (int)((EagRuntime.steadyTimeMillis() - bootCountDownStart) / 1000l);
+			if(countDownCur < 0) {
+				BootItem def = selectionController.selectionEnableList.get(0).listItem;
+				def.runnable.accept(def);
+				bootCountDown = 0;
+				return;
+			}
+			if(bootCountDownCur != countDownCur) {
+				bootCountDownCur = countDownCur;
+				BootMenuMain.bootMenuDOM.footer_text_boot_countdown.setInnerText(Integer.toString(countDownCur));
+			}
+		}
+	}
+
+	public void cancelCountdown() {
+		if(bootCountDown > 0) {
+			bootCountDown = 0;
+			BootMenuDOM.hide(BootMenuMain.bootMenuDOM.footer_text_boot_select_count);
+			BootMenuDOM.show(BootMenuMain.bootMenuDOM.footer_text_boot_select);
+		}
+	}
+
+}
diff --git a/sources/teavm-boot-menu/java/net/lax1dude/eaglercraft/v1_8/boot_menu/teavm/MenuStateClientMultiSelect.java b/sources/teavm-boot-menu/java/net/lax1dude/eaglercraft/v1_8/boot_menu/teavm/MenuStateClientMultiSelect.java
new file mode 100644
index 00000000..8cf17a8c
--- /dev/null
+++ b/sources/teavm-boot-menu/java/net/lax1dude/eaglercraft/v1_8/boot_menu/teavm/MenuStateClientMultiSelect.java
@@ -0,0 +1,137 @@
+package net.lax1dude.eaglercraft.v1_8.boot_menu.teavm;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.teavm.jso.dom.html.HTMLElement;
+
+import com.google.common.collect.Collections2;
+import com.google.common.collect.Lists;
+
+/**
+ * Copyright (c) 2024 lax1dude. All Rights Reserved.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ * 
+ */
+public abstract class MenuStateClientMultiSelect extends MenuState {
+
+	protected static class BootItem implements SelectionListController.ListItem {
+
+		protected final BootableClientEntry bootableClient;
+		protected final boolean alwaysSelected;
+
+		public BootItem(BootableClientEntry bootableClient) {
+			this.bootableClient = bootableClient;
+			this.alwaysSelected = BootMenuConstants.UUID_CLIENT_LAUNCH_ORIGIN
+					.equals(bootableClient.bootAdapter.getLaunchConfigEntry().uuid);
+		}
+
+		@Override
+		public String getName() {
+			return bootableClient.bootAdapter.getDisplayName();
+		}
+
+		@Override
+		public boolean getAlwaysSelected() {
+			return alwaysSelected;
+		}
+
+	}
+
+	protected MenuState parentState;
+	protected CheckboxListController<BootItem> selectionController;
+
+	public MenuStateClientMultiSelect(MenuState parentState, List<BootableClientEntry> bootableClients) {
+		this.parentState = parentState;
+		List<BootItem> list = new ArrayList<>(Collections2.transform(bootableClients, BootItem::new));
+		selectionController = new CheckboxListController<BootItem>(BootMenuMain.bootMenuDOM.content_selection, list) {
+
+			@Override
+			protected void cancelSelected() {
+				BootMenuMain.changeState(MenuStateClientMultiSelect.this.parentState);
+			}
+
+			@Override
+			protected void doneSelected(List<BootItem> selectedItems) {
+				MenuStateClientMultiSelect.this.onDone(Lists.newArrayList(Collections2.transform(selectedItems, (itm) -> itm.bootableClient)));
+			}
+
+		};
+	}
+
+	@Override
+	protected void enterState() {
+		selectionController.setup();
+		BootMenuDOM.show(BootMenuMain.bootMenuDOM.content_view_selection);
+		BootMenuDOM.show(BootMenuMain.bootMenuDOM.footer_text_menu_select);
+	}
+
+	@Override
+	protected void exitState() {
+		selectionController.destroy();
+		BootMenuDOM.hide(BootMenuMain.bootMenuDOM.content_view_selection);
+		BootMenuDOM.hide(BootMenuMain.bootMenuDOM.footer_text_menu_select);
+	}
+
+	@Override
+	protected void enterPopupBlockingState() {
+		selectionController.setCursorEventsSuspended(true);
+	}
+
+	@Override
+	protected void exitPopupBlockingState() {
+		selectionController.setCursorEventsSuspended(false);
+	}
+
+	@Override
+	protected void handleKeyDown(int keyCode) {
+		if(keyCode == KeyCodes.DOM_KEY_ESCAPE) {
+			BootMenuMain.changeState(MenuStateClientMultiSelect.this.parentState);
+		}else {
+			selectionController.handleKeyDown(keyCode);
+		}
+	}
+
+	@Override
+	protected void handleKeyUp(int keyCode) {
+		
+	}
+
+	@Override
+	protected void handleKeyRepeat(int keyCode) {
+		selectionController.handleKeyRepeat(keyCode);
+	}
+
+	@Override
+	protected void handleOnChanged(HTMLElement htmlElement) {
+		
+	}
+
+	@Override
+	protected void handleOnClick(HTMLElement htmlElement) {
+		
+	}
+
+	@Override
+	protected void handleOnMouseOver(HTMLElement htmlElement) {
+		
+	}
+
+	@Override
+	protected void update() {
+		
+	}
+
+	protected abstract void onDone(List<BootableClientEntry> entries);
+
+}
diff --git a/sources/teavm-boot-menu/java/net/lax1dude/eaglercraft/v1_8/boot_menu/teavm/MenuStateEditBootOrder.java b/sources/teavm-boot-menu/java/net/lax1dude/eaglercraft/v1_8/boot_menu/teavm/MenuStateEditBootOrder.java
new file mode 100644
index 00000000..22399d47
--- /dev/null
+++ b/sources/teavm-boot-menu/java/net/lax1dude/eaglercraft/v1_8/boot_menu/teavm/MenuStateEditBootOrder.java
@@ -0,0 +1,268 @@
+package net.lax1dude.eaglercraft.v1_8.boot_menu.teavm;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.teavm.jso.dom.html.HTMLElement;
+
+import net.lax1dude.eaglercraft.v1_8.EaglercraftUUID;
+
+/**
+ * Copyright (c) 2024 lax1dude. All Rights Reserved.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ * 
+ */
+public abstract class MenuStateEditBootOrder extends MenuState {
+
+	private static final EaglercraftUUID MAGIC_UUID_CANCEL = new EaglercraftUUID(0xD13983F5B764B3DL, 0xBF2C5157DEFDB5F9L);
+	private static final EaglercraftUUID MAGIC_UUID_DONE = new EaglercraftUUID(0x1F2BBFD548DD4818L, 0xB00B79D143BBF607L);
+
+	private static final BootOrderItem CANCEL_ITEM = new BootOrderItem("Cancel", MAGIC_UUID_CANCEL);
+	private static final BootOrderItem DONE_ITEM = new BootOrderItem("Done", MAGIC_UUID_DONE);
+
+	public static class BootOrderItem implements SelectionListController.ListItem {
+
+		public final String displayName;
+		public final EaglercraftUUID uuid;
+
+		public BootOrderItem(String displayName, EaglercraftUUID uuid) {
+			this.displayName = displayName;
+			this.uuid = uuid;
+		}
+
+		@Override
+		public String getName() {
+			return displayName;
+		}
+
+	}
+
+	public static class BootOrderItemContainer {
+
+		public final EaglercraftUUID uuid;
+		public final BootOrderItem exists;
+
+		public BootOrderItemContainer(EaglercraftUUID uuid, BootOrderItem exists) {
+			this.uuid = uuid;
+			this.exists = exists;
+		}
+
+	}
+
+	protected final MenuState parent;
+	protected final SelectionListController<BootOrderItem> selectionController;
+	protected final List<BootOrderItem> existingBootItems;
+	protected final List<BootOrderItemContainer> allBootItems;
+	protected boolean controlDown = false;
+
+	public MenuStateEditBootOrder(MenuState parent) {
+		this(parent, helper());
+	}
+
+	private static List<BootableClientEntry> helper() {
+		List<BootableClientEntry> enumBootItems = BootableClientEntry.enumerateBootableClients();
+		if(BootableClientEntry.applyClientOrdering(BootMenuMain.bootMenuDataManager.launchOrderList, enumBootItems)) {
+			BootMenuMain.bootMenuDataManager.writeManifest();
+		}
+		return enumBootItems;
+	}
+
+	public MenuStateEditBootOrder(MenuState parent, List<BootableClientEntry> enumBootItems) {
+		this.parent = parent;
+		Map<EaglercraftUUID,BootableClientEntry> enumBootItemsMap = new HashMap<>(enumBootItems.size());
+		for(int i = 0, l = enumBootItems.size(); i < l; ++i) {
+			BootableClientEntry etr = enumBootItems.get(i);
+			enumBootItemsMap.put(etr.bootAdapter.getLaunchConfigEntry().uuid, etr);
+		}
+		List<BootOrderItem> lst = new ArrayList<>();
+		List<BootOrderItemContainer> lst2 = new ArrayList<>();
+		List<EaglercraftUUID> lstSrc = BootMenuMain.bootMenuDataManager.launchOrderList;
+		for(int i = 0, l = lstSrc.size(); i < l; ++i) {
+			EaglercraftUUID uuid = lstSrc.get(i);
+			BootableClientEntry etr =  enumBootItemsMap.get(uuid);
+			if(etr != null) {
+				BootOrderItem itm = new BootOrderItem(etr.bootAdapter.getDisplayName(), uuid);
+				lst.add(itm);
+				lst2.add(new BootOrderItemContainer(uuid, itm));
+			}else {
+				lst2.add(new BootOrderItemContainer(uuid, null));
+			}
+		}
+		existingBootItems = lst;
+		allBootItems = lst2;
+		List<BootOrderItem> lst3 = new ArrayList<>(lst.size() + 2);
+		lst3.addAll(lst);
+		lst3.add(CANCEL_ITEM);
+		lst3.add(DONE_ITEM);
+		selectionController = new SelectionListController<BootOrderItem>(BootMenuMain.bootMenuDOM.content_selection, lst3) {
+			@Override
+			protected void itemSelected(BootOrderItem item) {
+				if(item == DONE_ITEM) {
+					MenuStateEditBootOrder.this.fireHandleSave();
+				}else if(item == CANCEL_ITEM) {
+					MenuStateEditBootOrder.this.handleCancel();
+				}
+			}
+		};
+		selectionController.setCursorEventsSuspended(true); // mouse over events might make it hard to reorder
+	}
+
+	protected void fireHandleSave() {
+		List<EaglercraftUUID> retList = new ArrayList<>(allBootItems.size());
+		for(int i = 0, l = allBootItems.size(); i < l; ++i) {
+			retList.add(allBootItems.get(i).uuid);
+		}
+		handleSave(retList);
+	}
+
+	@Override
+	protected void enterState() {
+		selectionController.setup();
+		BootMenuDOM.show(BootMenuMain.bootMenuDOM.footer_text_boot_order);
+		BootMenuDOM.show(BootMenuMain.bootMenuDOM.content_view_selection);
+	}
+
+	@Override
+	protected void exitState() {
+		selectionController.destroy();
+		BootMenuDOM.hide(BootMenuMain.bootMenuDOM.footer_text_boot_order);
+		BootMenuDOM.hide(BootMenuMain.bootMenuDOM.content_view_selection);
+	}
+
+	@Override
+	protected void enterPopupBlockingState() {
+		
+	}
+
+	@Override
+	protected void exitPopupBlockingState() {
+		
+	}
+
+	@Override
+	protected void handleKeyDown(int keyCode) {
+		if(keyCode == KeyCodes.DOM_KEY_ESCAPE) {
+			handleCancel();
+		}else if(keyCode == KeyCodes.DOM_KEY_CONTROL) {
+			controlDown = true;
+		}else if(controlDown && keyCode == KeyCodes.DOM_KEY_ARROW_UP) {
+			moveEntryUp();
+		}else if(controlDown && keyCode == KeyCodes.DOM_KEY_ARROW_DOWN) {
+			moveEntryDown();
+		}else {
+			selectionController.handleKeyDown(keyCode);
+		}
+	}
+
+	protected void moveEntryUp() {
+		BootOrderItem itm = selectionController.getSelected();
+		if(itm == null || itm == DONE_ITEM || itm == CANCEL_ITEM) {
+			return;
+		}
+		int index = selectionController.currentSelected;
+		if(index <= 0) {
+			return;
+		}
+		EaglercraftUUID currentUUID = itm.uuid;
+		int index2 = -1;
+		for(int i = 0, l = allBootItems.size(); i < l; ++i) {
+			BootOrderItemContainer itm2 = allBootItems.get(i);
+			if(itm2.uuid.equals(currentUUID)) {
+				index2 = i;
+				break;
+			}
+		}
+		if(index2 == -1) {
+			throw new IllegalStateException();
+		}
+		int newIndex = index - 1;
+		int newIndex2 = index2 - 1;
+		while(newIndex2 > 0 && allBootItems.get(newIndex2).exists == null) {
+			--newIndex2;
+		}
+		Collections.swap(existingBootItems, index, newIndex);
+		Collections.swap(allBootItems, index2, newIndex2);
+		selectionController.moveEntryUp(index);
+	}
+
+	protected void moveEntryDown() {
+		BootOrderItem itm = selectionController.getSelected();
+		if(itm == null || itm == DONE_ITEM || itm == CANCEL_ITEM) {
+			return;
+		}
+		int index = selectionController.currentSelected;
+		if(index >= existingBootItems.size() - 1) {
+			return;
+		}
+		EaglercraftUUID currentUUID = itm.uuid;
+		int index2 = -1;
+		for(int i = 0, l = allBootItems.size(); i < l; ++i) {
+			BootOrderItemContainer itm2 = allBootItems.get(i);
+			if(itm2.uuid.equals(currentUUID)) {
+				index2 = i;
+				break;
+			}
+		}
+		if(index2 == -1) {
+			throw new IllegalStateException();
+		}
+		int newIndex = index + 1;
+		int newIndex2 = index2 + 1;
+		while(newIndex2 < allBootItems.size() - 1 && allBootItems.get(newIndex2).exists == null) {
+			++newIndex2;
+		}
+		Collections.swap(existingBootItems, index, newIndex);
+		Collections.swap(allBootItems, index2, newIndex2);
+		selectionController.moveEntryDown(index);
+	}
+
+	@Override
+	protected void handleKeyUp(int keyCode) {
+		if(keyCode == KeyCodes.DOM_KEY_CONTROL) {
+			controlDown = false;
+		}
+	}
+
+	@Override
+	protected void handleKeyRepeat(int keyCode) {
+		selectionController.handleKeyDown(keyCode);
+	}
+
+	@Override
+	protected void handleOnChanged(HTMLElement htmlElement) {
+		
+	}
+
+	@Override
+	protected void handleOnClick(HTMLElement htmlElement) {
+		
+	}
+
+	@Override
+	protected void handleOnMouseOver(HTMLElement htmlElement) {
+		
+	}
+
+	@Override
+	protected void update() {
+		
+	}
+
+	protected abstract void handleSave(List<EaglercraftUUID> reorderedList);
+
+	protected abstract void handleCancel();
+
+}
diff --git a/sources/teavm-boot-menu/java/net/lax1dude/eaglercraft/v1_8/boot_menu/teavm/MenuStateEditingLaunch.java b/sources/teavm-boot-menu/java/net/lax1dude/eaglercraft/v1_8/boot_menu/teavm/MenuStateEditingLaunch.java
new file mode 100644
index 00000000..bc850b56
--- /dev/null
+++ b/sources/teavm-boot-menu/java/net/lax1dude/eaglercraft/v1_8/boot_menu/teavm/MenuStateEditingLaunch.java
@@ -0,0 +1,674 @@
+package net.lax1dude.eaglercraft.v1_8.boot_menu.teavm;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.function.Supplier;
+
+import org.json.JSONException;
+import org.json.JSONObject;
+import org.teavm.jso.dom.html.HTMLElement;
+
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+
+import net.lax1dude.eaglercraft.v1_8.EaglercraftUUID;
+import net.lax1dude.eaglercraft.v1_8.boot_menu.teavm.BootMenuMetadata.DefaultLaunchTemplate;
+import net.lax1dude.eaglercraft.v1_8.boot_menu.teavm.BootMenuMetadata.LaunchTemplate;
+import net.lax1dude.eaglercraft.v1_8.log4j.LogManager;
+import net.lax1dude.eaglercraft.v1_8.log4j.Logger;
+import net.minecraft.nbt.JsonToNBT;
+import net.minecraft.nbt.NBTException;
+
+/**
+ * Copyright (c) 2024 lax1dude. All Rights Reserved.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ * 
+ */
+public class MenuStateEditingLaunch extends MenuState {
+
+	private static final Logger logger = LogManager.getLogger("MenuStateEditingLaunch");
+
+	protected final MenuState previousMenu;
+	protected final LaunchConfigEntry launchConf;
+	protected final ClientDataEntry clientData;
+	protected final boolean isImporting;
+	protected final Map<EaglercraftUUID, Supplier<byte[]>> importClientBlobs;
+	protected boolean controlDown = false;
+
+	public static MenuStateEditingLaunch createHelper(MenuState previousMenu, LaunchConfigEntry launchConf,
+			ClientDataEntry clientData, boolean isImporting, Map<EaglercraftUUID, byte[]> importClientBlobs) {
+		return new MenuStateEditingLaunch(previousMenu, launchConf, clientData, isImporting,
+				Maps.transformValues(importClientBlobs, (blob) -> {
+			return () -> blob;
+		}));
+	}
+
+	public MenuStateEditingLaunch(MenuState previousMenu, LaunchConfigEntry launchConf, ClientDataEntry clientData,
+			boolean isImporting, Map<EaglercraftUUID, Supplier<byte[]>> importClientBlobs) {
+		this.previousMenu = previousMenu;
+		this.launchConf = launchConf;
+		this.clientData = clientData;
+		this.isImporting = isImporting;
+		this.importClientBlobs = importClientBlobs;
+	}
+
+	private void setVisibleControlSet() {
+		EnumClientLaunchType launchType = launchConf.type;
+		switch(launchType) {
+		case EAGLERX_V1:
+		case EAGLERX_SIGNED_V1:
+		case EAGLER_1_5_V2:
+		case PEYTON_V2:
+		case PEYTON_V1:
+			BootMenuDOM.hide(BootMenuMain.bootMenuDOM.launch_conf_join_server);
+			BootMenuDOM.hide(BootMenuMain.bootMenuDOM.launch_conf_opts_name);
+			BootMenuDOM.hide(BootMenuMain.bootMenuDOM.launch_conf_assetsURI);
+			BootMenuDOM.hide(BootMenuMain.bootMenuDOM.launch_conf_container);
+			BootMenuDOM.hide(BootMenuMain.bootMenuDOM.launch_conf_main_func);
+			break;
+		case EAGLER_1_5_V1:
+		case EAGLER_BETA_V1:
+			BootMenuDOM.show(BootMenuMain.bootMenuDOM.launch_conf_join_server);
+			BootMenuDOM.hide(BootMenuMain.bootMenuDOM.launch_conf_opts_name);
+			BootMenuDOM.hide(BootMenuMain.bootMenuDOM.launch_conf_assetsURI);
+			BootMenuDOM.hide(BootMenuMain.bootMenuDOM.launch_conf_container);
+			BootMenuDOM.hide(BootMenuMain.bootMenuDOM.launch_conf_main_func);
+			break;
+		case STANDARD_OFFLINE_V1:
+			BootMenuDOM.hide(BootMenuMain.bootMenuDOM.launch_conf_join_server);
+			BootMenuDOM.show(BootMenuMain.bootMenuDOM.launch_conf_opts_name);
+			BootMenuDOM.show(BootMenuMain.bootMenuDOM.launch_conf_assetsURI);
+			BootMenuDOM.show(BootMenuMain.bootMenuDOM.launch_conf_container);
+			BootMenuDOM.show(BootMenuMain.bootMenuDOM.launch_conf_main_func);
+			break;
+		}
+	}
+
+	private void setControlSetValues() {
+		BootMenuMain.bootMenuDOM.launch_conf_val_data_format.setInnerText(clientData.type.displayName);
+		EnumClientLaunchType launchType = launchConf.type;
+		BootMenuDOM.setValue(BootMenuMain.bootMenuDOM.launch_conf_val_launch_type, launchType.toString());
+		BootMenuDOM.setValue(BootMenuMain.bootMenuDOM.launch_conf_val_profile_name, launchConf.displayName);
+		BootMenuDOM.setChecked(BootMenuMain.bootMenuDOM.launch_conf_val_clear_cookies, launchConf.clearCookiesBeforeLaunch);
+		switch(launchType) {
+		case EAGLERX_V1:
+		case EAGLERX_SIGNED_V1:
+		case EAGLER_1_5_V2:
+		case PEYTON_V2:
+			BootMenuDOM.setValue(BootMenuMain.bootMenuDOM.launch_opt_editor, tryJSONFormat(launchConf.launchOpts));
+			BootMenuDOM.setValue(BootMenuMain.bootMenuDOM.launch_conf_val_join_server, "");
+			BootMenuDOM.setValue(BootMenuMain.bootMenuDOM.launch_conf_val_opts_name, "");
+			BootMenuDOM.setValue(BootMenuMain.bootMenuDOM.launch_conf_val_assetsURI, "");
+			BootMenuDOM.setValue(BootMenuMain.bootMenuDOM.launch_conf_val_container, "");
+			BootMenuDOM.setValue(BootMenuMain.bootMenuDOM.launch_conf_val_main_func, "");
+			break;
+		case EAGLER_1_5_V1:
+			BootMenuDOM.setValue(BootMenuMain.bootMenuDOM.launch_opt_editor, launchConf.launchOpts);
+			BootMenuDOM.setValue(BootMenuMain.bootMenuDOM.launch_conf_val_join_server, launchConf.joinServer);
+			BootMenuDOM.setValue(BootMenuMain.bootMenuDOM.launch_conf_val_opts_name, "");
+			BootMenuDOM.setValue(BootMenuMain.bootMenuDOM.launch_conf_val_assetsURI, "");
+			BootMenuDOM.setValue(BootMenuMain.bootMenuDOM.launch_conf_val_container, "");
+			BootMenuDOM.setValue(BootMenuMain.bootMenuDOM.launch_conf_val_main_func, "");
+			break;
+		case EAGLER_BETA_V1:
+			BootMenuDOM.setValue(BootMenuMain.bootMenuDOM.launch_opt_editor, "JSON opts are not supported for Eaglercraft b1.3!");
+			BootMenuDOM.setValue(BootMenuMain.bootMenuDOM.launch_conf_val_join_server, launchConf.joinServer);
+			BootMenuDOM.setValue(BootMenuMain.bootMenuDOM.launch_conf_val_opts_name, "");
+			BootMenuDOM.setValue(BootMenuMain.bootMenuDOM.launch_conf_val_assetsURI, "");
+			BootMenuDOM.setValue(BootMenuMain.bootMenuDOM.launch_conf_val_container, "");
+			BootMenuDOM.setValue(BootMenuMain.bootMenuDOM.launch_conf_val_main_func, "");
+			break;
+		case PEYTON_V1:
+			BootMenuDOM.setValue(BootMenuMain.bootMenuDOM.launch_opt_editor, "JSON opts are not supported for Indev!");
+			BootMenuDOM.setValue(BootMenuMain.bootMenuDOM.launch_conf_val_join_server, "");
+			BootMenuDOM.setValue(BootMenuMain.bootMenuDOM.launch_conf_val_opts_name, "");
+			BootMenuDOM.setValue(BootMenuMain.bootMenuDOM.launch_conf_val_assetsURI, "");
+			BootMenuDOM.setValue(BootMenuMain.bootMenuDOM.launch_conf_val_container, "");
+			BootMenuDOM.setValue(BootMenuMain.bootMenuDOM.launch_conf_val_main_func, "");
+			break;
+		case STANDARD_OFFLINE_V1:
+			BootMenuDOM.setValue(BootMenuMain.bootMenuDOM.launch_opt_editor, tryJSONFormat(launchConf.launchOpts));
+			BootMenuDOM.setValue(BootMenuMain.bootMenuDOM.launch_conf_val_join_server, "");
+			BootMenuDOM.setValue(BootMenuMain.bootMenuDOM.launch_conf_val_opts_name, launchConf.launchOptsVar);
+			BootMenuDOM.setValue(BootMenuMain.bootMenuDOM.launch_conf_val_assetsURI, launchConf.launchOptsAssetsURIVar);
+			BootMenuDOM.setValue(BootMenuMain.bootMenuDOM.launch_conf_val_container, launchConf.launchOptsContainerVar);
+			BootMenuDOM.setValue(BootMenuMain.bootMenuDOM.launch_conf_val_main_func, launchConf.mainFunction);
+			break;
+		}
+	}
+
+	private void setEnabledControlSet() {
+		BootMenuDOM.setDisabled(BootMenuMain.bootMenuDOM.launch_conf_val_launch_type, false);
+		setEnabledLaunchTypes();
+		BootMenuDOM.setDisabled(BootMenuMain.bootMenuDOM.launch_conf_val_profile_name, false);
+		BootMenuDOM.setDisabled(BootMenuMain.bootMenuDOM.launch_conf_val_clear_cookies, false);
+		EnumClientLaunchType launchType = launchConf.type;
+		switch(launchType) {
+		case EAGLERX_V1:
+		case EAGLERX_SIGNED_V1:
+		case EAGLER_1_5_V2:
+		case PEYTON_V2:
+			BootMenuDOM.setDisabled(BootMenuMain.bootMenuDOM.launch_opt_editor, false);
+			BootMenuDOM.setDisabled(BootMenuMain.bootMenuDOM.launch_conf_val_join_server, true);
+			BootMenuDOM.setDisabled(BootMenuMain.bootMenuDOM.launch_conf_val_opts_name, true);
+			BootMenuDOM.setDisabled(BootMenuMain.bootMenuDOM.launch_conf_val_assetsURI, true);
+			BootMenuDOM.setDisabled(BootMenuMain.bootMenuDOM.launch_conf_val_container, true);
+			BootMenuDOM.setDisabled(BootMenuMain.bootMenuDOM.launch_conf_val_main_func, true);
+			break;
+		case EAGLER_1_5_V1:
+			BootMenuDOM.setDisabled(BootMenuMain.bootMenuDOM.launch_opt_editor, false);
+			BootMenuDOM.setDisabled(BootMenuMain.bootMenuDOM.launch_conf_val_join_server, false);
+			BootMenuDOM.setDisabled(BootMenuMain.bootMenuDOM.launch_conf_val_opts_name, true);
+			BootMenuDOM.setDisabled(BootMenuMain.bootMenuDOM.launch_conf_val_assetsURI, true);
+			BootMenuDOM.setDisabled(BootMenuMain.bootMenuDOM.launch_conf_val_container, true);
+			BootMenuDOM.setDisabled(BootMenuMain.bootMenuDOM.launch_conf_val_main_func, true);
+			break;
+		case EAGLER_BETA_V1:
+			BootMenuDOM.setDisabled(BootMenuMain.bootMenuDOM.launch_opt_editor, true);
+			BootMenuDOM.setDisabled(BootMenuMain.bootMenuDOM.launch_conf_val_join_server, false);
+			BootMenuDOM.setDisabled(BootMenuMain.bootMenuDOM.launch_conf_val_opts_name, true);
+			BootMenuDOM.setDisabled(BootMenuMain.bootMenuDOM.launch_conf_val_assetsURI, true);
+			BootMenuDOM.setDisabled(BootMenuMain.bootMenuDOM.launch_conf_val_container, true);
+			BootMenuDOM.setDisabled(BootMenuMain.bootMenuDOM.launch_conf_val_main_func, true);
+			break;
+		case PEYTON_V1:
+			BootMenuDOM.setDisabled(BootMenuMain.bootMenuDOM.launch_opt_editor, true);
+			BootMenuDOM.setDisabled(BootMenuMain.bootMenuDOM.launch_conf_val_join_server, true);
+			BootMenuDOM.setDisabled(BootMenuMain.bootMenuDOM.launch_conf_val_opts_name, true);
+			BootMenuDOM.setDisabled(BootMenuMain.bootMenuDOM.launch_conf_val_assetsURI, true);
+			BootMenuDOM.setDisabled(BootMenuMain.bootMenuDOM.launch_conf_val_container, true);
+			BootMenuDOM.setDisabled(BootMenuMain.bootMenuDOM.launch_conf_val_main_func, true);
+			break;
+		case STANDARD_OFFLINE_V1:
+			BootMenuDOM.setDisabled(BootMenuMain.bootMenuDOM.launch_opt_editor, true);
+			BootMenuDOM.setDisabled(BootMenuMain.bootMenuDOM.launch_conf_val_join_server, true);
+			BootMenuDOM.setDisabled(BootMenuMain.bootMenuDOM.launch_conf_val_opts_name, false);
+			BootMenuDOM.setDisabled(BootMenuMain.bootMenuDOM.launch_conf_val_assetsURI, false);
+			BootMenuDOM.setDisabled(BootMenuMain.bootMenuDOM.launch_conf_val_container, false);
+			BootMenuDOM.setDisabled(BootMenuMain.bootMenuDOM.launch_conf_val_main_func, false);
+			break;
+		}
+	}
+
+	private void readAllValues() {
+		EnumClientLaunchType newLaunchType = EnumClientLaunchType.valueOf(BootMenuDOM.getValue(BootMenuMain.bootMenuDOM.launch_conf_val_launch_type));
+		if(!clientData.type.launchTypes.contains(newLaunchType)) {
+			logger.error("nope!");
+			throw new IllegalStateException("nope!");
+		}
+		EnumClientLaunchType launchType = launchConf.type;
+		launchConf.type = newLaunchType;
+		launchConf.displayName = BootMenuDOM.getValue(BootMenuMain.bootMenuDOM.launch_conf_val_profile_name).trim();
+		launchConf.clearCookiesBeforeLaunch = BootMenuDOM.getChecked(BootMenuMain.bootMenuDOM.launch_conf_val_clear_cookies);
+		switch(launchType) {
+		case EAGLERX_V1:
+		case EAGLERX_SIGNED_V1:
+		case EAGLER_1_5_V2:
+		case PEYTON_V2:
+			launchConf.launchOpts = BootMenuDOM.getValue(BootMenuMain.bootMenuDOM.launch_opt_editor).trim();
+			break;
+		case EAGLER_1_5_V1:
+			launchConf.launchOpts = BootMenuDOM.getValue(BootMenuMain.bootMenuDOM.launch_opt_editor).trim();
+			launchConf.joinServer = BootMenuDOM.getValue(BootMenuMain.bootMenuDOM.launch_conf_val_join_server).trim();
+			break;
+		case EAGLER_BETA_V1:
+			launchConf.joinServer = BootMenuDOM.getValue(BootMenuMain.bootMenuDOM.launch_conf_val_join_server).trim();
+			break;
+		case PEYTON_V1:
+			break;
+		case STANDARD_OFFLINE_V1:
+			launchConf.launchOpts = BootMenuDOM.getValue(BootMenuMain.bootMenuDOM.launch_opt_editor).trim();
+			launchConf.launchOptsVar = BootMenuDOM.getValue(BootMenuMain.bootMenuDOM.launch_conf_val_opts_name).trim();
+			launchConf.launchOptsAssetsURIVar = BootMenuDOM.getValue(BootMenuMain.bootMenuDOM.launch_conf_val_assetsURI).trim();
+			launchConf.launchOptsContainerVar = BootMenuDOM.getValue(BootMenuMain.bootMenuDOM.launch_conf_val_container).trim();
+			launchConf.mainFunction = BootMenuDOM.getValue(BootMenuMain.bootMenuDOM.launch_conf_val_main_func).trim();
+			break;
+		}
+	}
+
+	private void setEnabledLaunchTypes() {
+		EnumClientFormatType clientType = clientData.type;
+		Set<EnumClientLaunchType> launchTypes = clientType.launchTypes;
+		EnumClientLaunchType[] itr = EnumClientLaunchType._values();
+		for(int i = 0; i < itr.length; ++i) {
+			EnumClientLaunchType enumType = itr[i];
+			BootMenuDOM.setDisabled(BootMenuMain.bootMenuDOM.launch_conf_val_launch_type_opts.get(enumType),
+					!launchTypes.contains(enumType));
+		}
+	}
+
+	private static String tryJSONFormat(String input) {
+		try {
+			return (new JSONObject(input)).toString(4);
+		}catch(JSONException ex) {
+			logger.warn("This client's JSON is corrupt! Failed to format");
+			logger.warn(ex);
+			return input;
+		}
+	}
+
+	@Override
+	protected void enterState() {
+		if(isImporting) {
+			BootMenuDOM.show(BootMenuMain.bootMenuDOM.footer_text_opts_editor_alt);
+		}else {
+			BootMenuDOM.show(BootMenuMain.bootMenuDOM.footer_text_opts_editor);
+		}
+		BootMenuDOM.show(BootMenuMain.bootMenuDOM.content_view_editor);
+		setEnabledControlSet();
+		setControlSetValues();
+		setVisibleControlSet();
+	}
+
+	@Override
+	protected void exitState() {
+		if(isImporting) {
+			BootMenuDOM.hide(BootMenuMain.bootMenuDOM.footer_text_opts_editor_alt);
+		}else {
+			BootMenuDOM.hide(BootMenuMain.bootMenuDOM.footer_text_opts_editor);
+		}
+		BootMenuDOM.hide(BootMenuMain.bootMenuDOM.content_view_editor);
+		BootMenuDOM.hide(BootMenuMain.bootMenuDOM.launch_conf_join_server);
+		BootMenuDOM.hide(BootMenuMain.bootMenuDOM.launch_conf_opts_name);
+		BootMenuDOM.hide(BootMenuMain.bootMenuDOM.launch_conf_assetsURI);
+		BootMenuDOM.hide(BootMenuMain.bootMenuDOM.launch_conf_container);
+		BootMenuDOM.hide(BootMenuMain.bootMenuDOM.launch_conf_main_func);
+	}
+
+	@Override
+	protected void enterPopupBlockingState() {
+		BootMenuDOM.setDisabled(BootMenuMain.bootMenuDOM.launch_opt_editor, true);
+		BootMenuDOM.setDisabled(BootMenuMain.bootMenuDOM.launch_conf_val_launch_type, true);
+		BootMenuDOM.setDisabled(BootMenuMain.bootMenuDOM.launch_conf_val_profile_name, true);
+		BootMenuDOM.setDisabled(BootMenuMain.bootMenuDOM.launch_conf_val_join_server, true);
+		BootMenuDOM.setDisabled(BootMenuMain.bootMenuDOM.launch_conf_val_opts_name, true);
+		BootMenuDOM.setDisabled(BootMenuMain.bootMenuDOM.launch_conf_val_assetsURI, true);
+		BootMenuDOM.setDisabled(BootMenuMain.bootMenuDOM.launch_conf_val_container, true);
+		BootMenuDOM.setDisabled(BootMenuMain.bootMenuDOM.launch_conf_val_main_func, true);
+		BootMenuDOM.setDisabled(BootMenuMain.bootMenuDOM.launch_conf_val_clear_cookies, true);
+	}
+
+	@Override
+	protected void exitPopupBlockingState() {
+		setEnabledControlSet();
+	}
+
+	public static enum EnumEditorMenu {
+		BOOT("Boot configuration"),
+		SAVE("Save configuration"),
+		SAVE_COPY("Save a copy"),
+		LOAD_DEFAULTS("Load defaults"),
+		LOAD_TEMPLATE("Load template"),
+		EXPORT_OFFLINE("Export Offline"),
+		DELETE("Delete configuration"),
+		RETURN("Return to menu"),
+		CANCEL("Cancel");
+		
+		private final String str;
+		
+		private EnumEditorMenu(String str) {
+			this.str = str;
+		}
+		
+		@Override
+		public String toString() {
+			return str;
+		}
+	}
+
+	protected static final List<EnumEditorMenu> EDITOR_MENU = Arrays.asList(EnumEditorMenu.BOOT, EnumEditorMenu.SAVE,
+			EnumEditorMenu.SAVE_COPY, EnumEditorMenu.LOAD_DEFAULTS, EnumEditorMenu.LOAD_TEMPLATE,
+			EnumEditorMenu.EXPORT_OFFLINE, EnumEditorMenu.DELETE, EnumEditorMenu.RETURN, EnumEditorMenu.CANCEL);
+
+	protected static final List<EnumEditorMenu> IMPORTER_MENU = Arrays.asList(EnumEditorMenu.SAVE,
+			EnumEditorMenu.LOAD_DEFAULTS, EnumEditorMenu.LOAD_TEMPLATE, EnumEditorMenu.EXPORT_OFFLINE,
+			EnumEditorMenu.RETURN, EnumEditorMenu.CANCEL);
+
+	@Override
+	protected void handleKeyDown(int keyCode) {
+		if(keyCode == KeyCodes.DOM_KEY_ESCAPE) {
+			returnToMenu();
+		}else if(keyCode == KeyCodes.DOM_KEY_CONTROL) {
+			controlDown = true;
+		}else if(keyCode == KeyCodes.DOM_KEY_SHIFT) {
+			if(controlDown) {
+				changePopupState(MenuPopupStateSelection.createHelper("What do you wanna do?", isImporting ? IMPORTER_MENU : EDITOR_MENU, (opt) -> {
+					switch(opt) {
+					case BOOT:
+						bootCurrentConfig();
+						break;
+					case SAVE:
+						saveAndExit();
+						break;
+					case SAVE_COPY:
+						saveCopy();
+						break;
+					case LOAD_DEFAULTS:
+						loadDefaults();
+						break;
+					case LOAD_TEMPLATE:
+						loadTemplate();
+						break;
+					case EXPORT_OFFLINE:
+						exportOffline();
+						break;
+					case DELETE:
+						deleteConfig();
+						break;
+					case RETURN:
+						returnToMenu();
+						break;
+					case CANCEL:
+					default:
+						changePopupState(null);
+						break;
+					}
+				}));
+			}
+		}else if(keyCode == KeyCodes.DOM_KEY_ENTER) {
+			if(controlDown) {
+				if(isImporting) {
+					saveAndExit();
+				}else {
+					bootCurrentConfig();
+				}
+			}
+		}
+	}
+
+	private String validateLaunchOpts() {
+		EnumClientLaunchType launchType = launchConf.type;
+		switch(launchType) {
+		case EAGLERX_V1:
+		case EAGLERX_SIGNED_V1:
+		case EAGLER_1_5_V2:
+		case PEYTON_V2:
+		case STANDARD_OFFLINE_V1:
+			try {
+				new JSONObject(launchConf.launchOpts);
+				return null;
+			}catch(JSONException ex) {
+				return ex.toString();
+			}
+		case EAGLER_1_5_V1:
+			if(!launchConf.launchOpts.startsWith("[NBT]") || !launchConf.launchOpts.endsWith("[/NBT]")) {
+				return "Content does not begin/end with \"[NBT]\" and \"[/NBT]\"";
+			}
+			try {
+				String str = launchConf.launchOpts;
+				JsonToNBT.getTagFromJson(str.substring(5, str.length() - 6).trim());
+				return null;
+			}catch(NBTException ex) {
+				return ex.toString();
+			}
+		case EAGLER_BETA_V1:
+		case PEYTON_V1:
+		default:
+			return null;
+		}
+	}
+
+	private void bootCurrentConfig() {
+		readAllValues();
+		String err = validateLaunchOpts();
+		if(err != null) {
+			changePopupState(new MenuPopupStateConfirmation<String>("Error: Invalid syntax in launch opts!\n\n" + err,
+					Arrays.asList("OK")) {
+				@Override
+				protected void selectCallback(String enumValue) {
+					MenuStateEditingLaunch.this.changePopupState(null);
+				}
+			});
+			return;
+		}
+		MenuPopupStateLoading popupState = new MenuPopupStateLoading("Booting: '" + launchConf.displayName + "'...");
+		changePopupState(popupState);
+		BootMenuMain.runLaterMS(() -> {
+			try {
+				ClientBootFactory.bootClient(launchConf, clientData, importClientBlobs, popupState);
+			}catch(UnsignedBootException ex) {
+				MenuStateBoot.displayUnsignedError(MenuStateEditingLaunch.this, (cb) -> {
+					MenuStateEditingLaunch.this.exportOffline();
+				}, () -> {
+					MenuStateEditingLaunch.this.changePopupState(null);
+				});
+				return;
+			}catch(Throwable t) {
+				logger.error("Failed to boot client!");
+				logger.error(t);
+				changePopupState(new MenuPopupStateConfirmation<String>("Error: Failed to boot client!\n\n" + t.toString(),
+						Arrays.asList("OK")) {
+					@Override
+					protected void selectCallback(String enumValue) {
+						MenuStateEditingLaunch.this.changePopupState(null);
+					}
+				});
+				return;
+			}
+			try {
+				changePopupState(null);
+			}catch(Throwable t) {
+			}
+		}, 250);
+	}
+
+	private void saveAndExit() {
+		readAllValues();
+		String err = validateLaunchOpts();
+		if(err != null) {
+			changePopupState(new MenuPopupStateConfirmation<String>("Error: Invalid syntax in launch opts!\n\n" + err,
+					Arrays.asList("OK")) {
+				@Override
+				protected void selectCallback(String enumValue) {
+					MenuStateEditingLaunch.this.changePopupState(null);
+				}
+			});
+			return;
+		}
+		MenuPopupStateLoading popupState = new MenuPopupStateLoading("Saving: '" + launchConf.displayName + "'...");
+		changePopupState(popupState);
+		BootMenuMain.runLaterMS(() -> {
+			try {
+				BootMenuMain.bootMenuDataManager.installNewLaunchConfig(launchConf, clientData,
+						Maps.transformValues(importClientBlobs, (e) -> e.get()), false);
+			}catch(Throwable t) {
+				logger.error("Error: could not save launch config!");
+				logger.error(t);
+				changePopupState(new MenuPopupStateConfirmation<String>("Error: Could not save launch config!\n\n" + t.toString(),
+						Arrays.asList("OK")) {
+					@Override
+					protected void selectCallback(String enumValue) {
+						MenuStateEditingLaunch.this.changePopupState(null);
+					}
+				});
+				return;
+			}
+			BootMenuMain.changeState(new MenuStateBoot(false));
+		}, 250);
+	}
+
+	private void saveCopy() {
+		readAllValues();
+		String err = validateLaunchOpts();
+		if(err != null) {
+			changePopupState(new MenuPopupStateConfirmation<String>("Error: Invalid syntax in launch opts!\n\n" + err,
+					Arrays.asList("OK")) {
+				@Override
+				protected void selectCallback(String enumValue) {
+					MenuStateEditingLaunch.this.changePopupState(null);
+				}
+			});
+			return;
+		}
+		final LaunchConfigEntry launchConfCopy = launchConf.rotateUUIDs(EaglercraftUUID.randomUUID(), launchConf.clientDataUUID);
+		MenuPopupStateLoading popupState = new MenuPopupStateLoading("Saving: '" + launchConfCopy.displayName + "'...");
+		changePopupState(popupState);
+		BootMenuMain.runLaterMS(() -> {
+			try {
+				BootMenuMain.bootMenuDataManager.installNewLaunchConfig(launchConfCopy, clientData,
+						Maps.transformValues(importClientBlobs, (e) -> e.get()), false);
+			}catch(Throwable t) {
+				logger.error("Error: could not save launch config!");
+				logger.error(t);
+				changePopupState(new MenuPopupStateConfirmation<String>("Error: Could not save launch config!\n\n" + t.toString(),
+						Arrays.asList("OK")) {
+					@Override
+					protected void selectCallback(String enumValue) {
+						MenuStateEditingLaunch.this.changePopupState(null);
+					}
+				});
+				return;
+			}
+			BootMenuMain.changeState(new MenuStateBoot(false));
+		}, 250);
+	}
+
+	private void loadDefaults() {
+		LaunchTemplate def = BootMenuMain.bootMenuMetadata.formatDefaultOptsMap.get(launchConf.type);
+		if(def != null) {
+			def.configureLaunchConfig(launchConf);
+			setControlSetValues();
+			changePopupState(null);
+		}else {
+			changePopupState(new MenuPopupStateConfirmation<String>("Error: Could not find default config!",
+					Arrays.asList("OK")) {
+				@Override
+				protected void selectCallback(String enumValue) {
+					MenuStateEditingLaunch.this.changePopupState(null);
+				}
+			});
+		}
+	}
+
+	private void loadTemplate() {
+		List<DefaultLaunchTemplate> templates = BootMenuMain.bootMenuMetadata.getTemplatesForParseType(EnumOfflineParseType.inferFromClientFormat(launchConf.type));
+		if(templates != null && !templates.isEmpty()) {
+			List<Object> listWithCancel = Lists.newArrayList(templates);
+			listWithCancel.add("Cancel");
+			changePopupState(MenuPopupStateSelection.createHelper("Select the template you would like to load:", listWithCancel, (template) -> {
+				if(template != null) {
+					if(!"Cancel".equals(template)) {
+						((DefaultLaunchTemplate)template).templateState.configureLaunchConfig(launchConf);
+						setControlSetValues();
+						changePopupState(null);
+					}else {
+						changePopupState(null);
+					}
+				}
+			}));
+		}else {
+			changePopupState(new MenuPopupStateConfirmation<String>("Error: Could not find any templates!",
+					Arrays.asList("OK")) {
+				@Override
+				protected void selectCallback(String enumValue) {
+					MenuStateEditingLaunch.this.changePopupState(null);
+				}
+			});
+		}
+	}
+
+	private void exportOffline() {
+		readAllValues();
+		String err = validateLaunchOpts();
+		if(err != null) {
+			changePopupState(new MenuPopupStateConfirmation<String>("Error: Invalid syntax in launch opts!\n\n" + err,
+					Arrays.asList("OK")) {
+				@Override
+				protected void selectCallback(String enumValue) {
+					MenuStateEditingLaunch.this.changePopupState(null);
+				}
+			});
+			return;
+		}
+		MenuPopupStateLoading popupState = new MenuPopupStateLoading("Exporting: '" + launchConf.displayName + "'...");
+		changePopupState(popupState);
+		BootMenuMain.runLaterMS(() -> {
+			try {
+				OfflineDownloadFactory.downloadOffline(launchConf, clientData, importClientBlobs, popupState);
+			}catch(Throwable t) {
+				logger.error("Failed to export offline!");
+				logger.error(t);
+				changePopupState(new MenuPopupStateConfirmation<String>("Error: Failed to export offline!\n\n" + t.toString(),
+						Arrays.asList("OK")) {
+					@Override
+					protected void selectCallback(String enumValue) {
+						MenuStateEditingLaunch.this.changePopupState(null);
+					}
+				});
+				return;
+			}
+			MenuStateEditingLaunch.this.changePopupState(null);
+		}, 250);
+		
+	}
+
+	private void deleteConfig() {
+		changePopupState(new MenuPopupStateLoading("Deleting: '" + launchConf.displayName + "'..."));
+		BootMenuMain.runLaterMS(() -> {
+			try {
+				BootMenuMain.bootMenuDataManager.deleteLaunchConfig(launchConf.uuid);
+			}finally {
+				BootMenuMain.changeState(new MenuStateBoot(false));
+			}
+		}, 250);
+	}
+
+	private void returnToMenu() {
+		if(previousMenu != null) {
+			BootMenuMain.changeState(previousMenu);
+		}
+	}
+
+	@Override
+	protected void handleKeyUp(int keyCode) {
+		if(keyCode == KeyCodes.DOM_KEY_CONTROL) {
+			controlDown = false;
+		}
+	}
+
+	@Override
+	protected void handleKeyRepeat(int keyCode) {
+		
+	}
+
+	@Override
+	protected void handleOnChanged(HTMLElement htmlElement) {
+		if(BootMenuMain.bootMenuDOM.launch_conf_val_launch_type == htmlElement) {
+			EnumClientLaunchType launchType = launchConf.type;
+			readAllValues();
+			if(launchConf.type != launchType) {
+				setEnabledControlSet();
+				setControlSetValues();
+				setVisibleControlSet();
+			}
+		}
+	}
+
+	@Override
+	protected void handleOnClick(HTMLElement htmlElement) {
+		
+	}
+
+	@Override
+	protected void handleOnMouseOver(HTMLElement htmlElement) {
+		
+	}
+
+	@Override
+	protected void update() {
+		
+	}
+
+}
diff --git a/sources/teavm-boot-menu/java/net/lax1dude/eaglercraft/v1_8/boot_menu/teavm/MenuStateEnterSetup.java b/sources/teavm-boot-menu/java/net/lax1dude/eaglercraft/v1_8/boot_menu/teavm/MenuStateEnterSetup.java
new file mode 100644
index 00000000..c60d6970
--- /dev/null
+++ b/sources/teavm-boot-menu/java/net/lax1dude/eaglercraft/v1_8/boot_menu/teavm/MenuStateEnterSetup.java
@@ -0,0 +1,261 @@
+package net.lax1dude.eaglercraft.v1_8.boot_menu.teavm;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import org.apache.commons.lang3.StringUtils;
+import org.teavm.jso.dom.html.HTMLElement;
+
+import net.lax1dude.eaglercraft.v1_8.EaglercraftUUID;
+
+/**
+ * Copyright (c) 2024 lax1dude. All Rights Reserved.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ * 
+ */
+public class MenuStateEnterSetup extends MenuState {
+
+	private static enum EnumListMultiSelectType {
+		CHECKBOX_ALWAYS_SHOW, SUBMENU_BOOT_ORDER, SUBMENU_DELETE_ITEM, AUTOMATIC_BOOT_TIMEOUT, SUBMENU_CHANGE_TITLE, DONE;
+	}
+
+	private static class MenuItem implements SelectionListController.ListItem {
+
+		private final EnumListMultiSelectType type;
+		private final String displayName;
+
+		private MenuItem(EnumListMultiSelectType type, String displayName) {
+			this.type = type;
+			this.displayName = displayName;
+		}
+
+		@Override
+		public String getName() {
+			return displayName;
+		}
+
+	}
+
+	protected SelectionListController<MenuItem> selectionController;
+
+	public MenuStateEnterSetup(List<BootableClientEntry> bootableClients) {
+		int bootFlagsRet = BootMenuDataManager.getBootMenuFlags(BootMenuMain.win);
+		final int bootFlags = bootFlagsRet == -1 ? 0 : bootFlagsRet;
+		final boolean[] alwaysShowState = new boolean[] { (bootFlags & 1) != 0 };
+		int timeout = BootMenuMain.bootMenuDataManager.confBootTimeout;
+		selectionController = new SelectionListController<MenuItem>(BootMenuMain.bootMenuDOM.content_selection, Arrays.asList(
+					new MenuItem(EnumListMultiSelectType.CHECKBOX_ALWAYS_SHOW, (alwaysShowState[0] ? "[X]" : "[ ]") + " Always show boot menu on launch"),
+					new MenuItem(EnumListMultiSelectType.SUBMENU_BOOT_ORDER, "Change Boot Order"),
+					new MenuItem(EnumListMultiSelectType.SUBMENU_DELETE_ITEM, "Delete Boot Item"),
+					new MenuItem(EnumListMultiSelectType.AUTOMATIC_BOOT_TIMEOUT, "Automatic Boot Timeout: " + (timeout == 0 ? "Disabled" : timeout)),
+					new MenuItem(EnumListMultiSelectType.SUBMENU_CHANGE_TITLE, "Change Menu Title"),
+					new MenuItem(EnumListMultiSelectType.DONE, "Done")
+				)) {
+
+			@Override
+			public void handleKeyDown(int keyCode) {
+				if(keyCode == KeyCodes.DOM_KEY_SPACE) {
+					if(currentSelected == 0) { // the checkbox
+						fireSelect();
+					}
+				}else {
+					super.handleKeyDown(keyCode);
+				}
+			}
+
+			@Override
+			protected void itemSelectedLow(ListItemInstance<MenuItem> item) {
+				switch(item.listItem.type) {
+				case CHECKBOX_ALWAYS_SHOW:
+					alwaysShowState[0] = !alwaysShowState[0];
+					BootMenuDataManager.setBootMenuFlags(BootMenuMain.win, (bootFlags & ~1) | (alwaysShowState[0] ? 1 : 0));
+					item.element.setInnerText((alwaysShowState[0] ? "[X]" : "[ ]") + " Always show boot menu on launch");
+					break;
+				case SUBMENU_BOOT_ORDER:
+					BootMenuMain.changeState(new MenuStateEditBootOrder(MenuStateEnterSetup.this, bootableClients) {
+
+						@Override
+						protected void handleSave(List<EaglercraftUUID> reorderedList) {
+							BootMenuMain.bootMenuDataManager.launchOrderList.clear();
+							BootMenuMain.bootMenuDataManager.launchOrderList.addAll(reorderedList);
+							BootableClientEntry.applyClientOrdering(BootMenuMain.bootMenuDataManager.launchOrderList, bootableClients);
+							BootMenuMain.bootMenuDataManager.writeManifest();
+							BootMenuMain.changeState(MenuStateEnterSetup.this);
+						}
+
+						@Override
+						protected void handleCancel() {
+							BootMenuMain.changeState(MenuStateEnterSetup.this);
+						}
+
+					});
+					break;
+				case SUBMENU_DELETE_ITEM:
+					List<BootableClientEntry> deletableClients = new ArrayList<>(bootableClients.size() - 1);
+					for(int i = 0, l = bootableClients.size(); i < l; ++i) {
+						BootableClientEntry etr = bootableClients.get(i);
+						if(etr.dataType == BootableClientEntry.EnumDataType.LOCAL_STORAGE) {
+							deletableClients.add(etr);
+						}
+					}
+					if(!deletableClients.isEmpty()) {
+						BootMenuMain.changeState(new MenuStateClientMultiSelect(MenuStateEnterSetup.this, deletableClients) {
+							@Override
+							protected void onDone(List<BootableClientEntry> entries) {
+								if(entries != null && !entries.isEmpty()) {
+									for(int i = 0, l = entries.size(); i < l; ++i) {
+										EaglercraftUUID toDelete = entries.get(i).bootAdapter.getLaunchConfigEntry().uuid;
+										BootMenuMain.bootMenuDataManager.deleteLaunchConfig(toDelete);
+									}
+									List<BootableClientEntry> newEnum = BootableClientEntry.enumerateBootableClients();
+									if(BootableClientEntry.applyClientOrdering(BootMenuMain.bootMenuDataManager.launchOrderList, newEnum)) {
+										BootMenuMain.bootMenuDataManager.writeManifest();
+									}
+									BootMenuMain.changeState(new MenuStateEnterSetup(newEnum));
+								}else {
+									BootMenuMain.changeState(MenuStateEnterSetup.this);
+								}
+							}
+						});
+					}else {
+						changePopupState(new MenuPopupStateConfirmation<String>(
+								"Error: No deletable clients!",
+								Arrays.asList("OK")) {
+							@Override
+							protected void selectCallback(String enumValue) {
+								MenuStateEnterSetup.this.changePopupState(null);
+							}
+						});
+					}
+					break;
+				case AUTOMATIC_BOOT_TIMEOUT:
+					MenuStateEnterSetup.this.changePopupState(new MenuPopupStateEditInteger("Enter the number of seconds, or 0 to disable:", BootMenuMain.bootMenuDataManager.confBootTimeout) {
+
+						@Override
+						protected void onSave(int i) {
+							if(i < 0) i = 0;
+							if(i != BootMenuMain.bootMenuDataManager.confBootTimeout) {
+								BootMenuMain.bootMenuDataManager.confBootTimeout = i;
+								BootMenuMain.bootMenuDataManager.saveAdditionalConf();
+								item.element.setInnerText("Automatic Boot Timeout: " + (i == 0 ? "Disabled" : i));
+							}
+							MenuStateEnterSetup.this.changePopupState(null);
+						}
+
+						@Override
+						protected void onCancel() {
+							MenuStateEnterSetup.this.changePopupState(null);
+						}
+
+					});
+					break;
+				case SUBMENU_CHANGE_TITLE:
+					MenuStateEnterSetup.this.changePopupState(new MenuPopupStateEditString(
+							"Enter the title to display on the menu:", BootMenuMain.bootMenuDataManager.confMenuTitle) {
+
+						@Override
+						protected void onSave(String str) {
+							str = str.trim();
+							if(!StringUtils.isEmpty(str) && !str.equals(BootMenuMain.bootMenuDataManager.confMenuTitle)) {
+								BootMenuMain.bootMenuDataManager.confMenuTitle = str;
+								BootMenuMain.bootMenuDataManager.saveAdditionalConf();
+								BootMenuMain.bootMenuDOM.header_title.setInnerText(str);
+							}
+							MenuStateEnterSetup.this.changePopupState(null);
+						}
+
+						@Override
+						protected void onCancel() {
+							MenuStateEnterSetup.this.changePopupState(null);
+						}
+
+					});
+					break;
+				case DONE:
+					BootMenuMain.changeState(new MenuStateBoot(false));
+					break;
+				default:
+					break;
+				}
+			}
+			@Override
+			protected void itemSelected(MenuItem item) {
+			}
+		};
+	}
+
+	@Override
+	protected void enterState() {
+		selectionController.setup();
+		BootMenuDOM.show(BootMenuMain.bootMenuDOM.content_view_selection);
+		BootMenuDOM.show(BootMenuMain.bootMenuDOM.footer_text_menu_select);
+	}
+
+	@Override
+	protected void exitState() {
+		selectionController.destroy();
+		BootMenuDOM.hide(BootMenuMain.bootMenuDOM.content_view_selection);
+		BootMenuDOM.hide(BootMenuMain.bootMenuDOM.footer_text_menu_select);
+	}
+
+	@Override
+	protected void enterPopupBlockingState() {
+		selectionController.setCursorEventsSuspended(true);
+	}
+
+	@Override
+	protected void exitPopupBlockingState() {
+		selectionController.setCursorEventsSuspended(false);
+	}
+
+	@Override
+	protected void handleKeyDown(int keyCode) {
+		if(keyCode == KeyCodes.DOM_KEY_ESCAPE) {
+			BootMenuMain.changeState(new MenuStateBoot(false));
+		}else {
+			selectionController.handleKeyDown(keyCode);
+		}
+	}
+
+	@Override
+	protected void handleKeyUp(int keyCode) {
+		
+	}
+
+	@Override
+	protected void handleKeyRepeat(int keyCode) {
+		selectionController.handleKeyRepeat(keyCode);
+	}
+
+	@Override
+	protected void handleOnChanged(HTMLElement htmlElement) {
+		
+	}
+
+	@Override
+	protected void handleOnClick(HTMLElement htmlElement) {
+		
+	}
+
+	@Override
+	protected void handleOnMouseOver(HTMLElement htmlElement) {
+		
+	}
+
+	@Override
+	protected void update() {
+		
+	}
+
+}
diff --git a/sources/teavm-boot-menu/java/net/lax1dude/eaglercraft/v1_8/boot_menu/teavm/MenuStateImportMultiSelect.java b/sources/teavm-boot-menu/java/net/lax1dude/eaglercraft/v1_8/boot_menu/teavm/MenuStateImportMultiSelect.java
new file mode 100644
index 00000000..6d38f8c4
--- /dev/null
+++ b/sources/teavm-boot-menu/java/net/lax1dude/eaglercraft/v1_8/boot_menu/teavm/MenuStateImportMultiSelect.java
@@ -0,0 +1,144 @@
+package net.lax1dude.eaglercraft.v1_8.boot_menu.teavm;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.teavm.jso.dom.html.HTMLElement;
+
+import com.google.common.collect.Collections2;
+
+import net.lax1dude.eaglercraft.v1_8.boot_menu.teavm.OfflineDownloadParser.ParsedOfflineAdapter;
+
+/**
+ * Copyright (c) 2024 lax1dude. All Rights Reserved.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ * 
+ */
+public class MenuStateImportMultiSelect extends MenuState {
+
+	protected static class BootItem implements SelectionListController.ListItem {
+
+		protected final ParsedOfflineAdapter parsedClient;
+
+		public BootItem(ParsedOfflineAdapter parsedClient) {
+			this.parsedClient = parsedClient;
+		}
+
+		@Override
+		public String getName() {
+			return parsedClient.launchData.displayName;
+		}
+
+		@Override
+		public boolean getAlwaysSelected() {
+			return false;
+		}
+
+	}
+
+	protected MenuState parentState;
+	protected CheckboxListController<BootItem> selectionController;
+
+	public MenuStateImportMultiSelect(MenuState parentState, List<ParsedOfflineAdapter> parsedClients) {
+		this.parentState = parentState;
+		List<BootItem> list = new ArrayList<>(Collections2.transform(parsedClients, BootItem::new));
+		selectionController = new CheckboxListController<BootItem>(BootMenuMain.bootMenuDOM.content_selection, list) {
+
+			@Override
+			protected void cancelSelected() {
+				BootMenuMain.changeState(MenuStateImportMultiSelect.this.parentState);
+			}
+
+			@Override
+			protected void doneSelected(List<BootItem> selectedItems) {
+				if(selectedItems.isEmpty()) {
+					cancelSelected();
+					return;
+				}
+				MenuPopupStateLoading loadingScreen = new MenuPopupStateLoading("Importing clients...");
+				MenuStateImportMultiSelect.this.changePopupState(loadingScreen);
+				for(int i = 0, l = selectedItems.size(); i < l; ++i) {
+					loadingScreen.updateMessage("Importing (" + (i + 1) + " / " + l + ")...");
+					ParsedOfflineAdapter cl = selectedItems.get(i).parsedClient;
+					BootMenuMain.bootMenuDataManager.installNewClientData(cl.launchData, cl.clientData, cl.blobs, true);
+				}
+				BootMenuMain.changeState(new MenuStateBoot(false));
+			}
+
+		};
+	}
+
+	@Override
+	protected void enterState() {
+		selectionController.setup();
+		BootMenuDOM.show(BootMenuMain.bootMenuDOM.content_view_selection);
+		BootMenuDOM.show(BootMenuMain.bootMenuDOM.footer_text_menu_select);
+	}
+
+	@Override
+	protected void exitState() {
+		selectionController.destroy();
+		BootMenuDOM.hide(BootMenuMain.bootMenuDOM.content_view_selection);
+		BootMenuDOM.hide(BootMenuMain.bootMenuDOM.footer_text_menu_select);
+	}
+
+	@Override
+	protected void enterPopupBlockingState() {
+		selectionController.setCursorEventsSuspended(true);
+	}
+
+	@Override
+	protected void exitPopupBlockingState() {
+		selectionController.setCursorEventsSuspended(false);
+	}
+
+	@Override
+	protected void handleKeyDown(int keyCode) {
+		if(keyCode == KeyCodes.DOM_KEY_ESCAPE) {
+			BootMenuMain.changeState(MenuStateImportMultiSelect.this.parentState);
+		}else {
+			selectionController.handleKeyDown(keyCode);
+		}
+	}
+
+	@Override
+	protected void handleKeyUp(int keyCode) {
+		
+	}
+
+	@Override
+	protected void handleKeyRepeat(int keyCode) {
+		selectionController.handleKeyRepeat(keyCode);
+	}
+
+	@Override
+	protected void handleOnChanged(HTMLElement htmlElement) {
+		
+	}
+
+	@Override
+	protected void handleOnClick(HTMLElement htmlElement) {
+		
+	}
+
+	@Override
+	protected void handleOnMouseOver(HTMLElement htmlElement) {
+		
+	}
+
+	@Override
+	protected void update() {
+		
+	}
+
+}
diff --git a/sources/teavm-boot-menu/java/net/lax1dude/eaglercraft/v1_8/boot_menu/teavm/MenuStateSelectExportClients.java b/sources/teavm-boot-menu/java/net/lax1dude/eaglercraft/v1_8/boot_menu/teavm/MenuStateSelectExportClients.java
new file mode 100644
index 00000000..fe1cc687
--- /dev/null
+++ b/sources/teavm-boot-menu/java/net/lax1dude/eaglercraft/v1_8/boot_menu/teavm/MenuStateSelectExportClients.java
@@ -0,0 +1,151 @@
+package net.lax1dude.eaglercraft.v1_8.boot_menu.teavm;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.function.Consumer;
+
+import org.teavm.jso.dom.html.HTMLElement;
+
+import net.lax1dude.eaglercraft.v1_8.log4j.LogManager;
+import net.lax1dude.eaglercraft.v1_8.log4j.Logger;
+
+/**
+ * Copyright (c) 2024 lax1dude. All Rights Reserved.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ * 
+ */
+public class MenuStateSelectExportClients extends MenuState {
+
+	private static final Logger logger = LogManager.getLogger("MenuStateSelectExportClients");
+
+	private static class BootItem implements SelectionListController.ListItem {
+
+		private final BootableClientEntry bootEntry;
+		private final Consumer<BootableClientEntry> onSelected;
+
+		public BootItem(BootableClientEntry bootEntry, Consumer<BootableClientEntry> onSelected) {
+			this.bootEntry = bootEntry;
+			this.onSelected = onSelected;
+		}
+
+		@Override
+		public String getName() {
+			return bootEntry.bootAdapter.getDisplayName();
+		}
+
+	}
+
+	protected final boolean exportEPK;
+	protected final MenuState parentState;
+	protected SelectionListController<BootItem> selectionController;
+
+	public MenuStateSelectExportClients(boolean exportEPK, MenuStateBoot parentState, List<BootableClientEntry> filteredList) {
+		this.exportEPK = exportEPK;
+		this.parentState = parentState;
+		List<BootItem> lst = new ArrayList<>(filteredList.size());
+		for(int i = 0, l = filteredList.size(); i < l; ++i) {
+			lst.add(new BootItem(filteredList.get(i), (etr) -> {
+				MenuPopupStateLoading popupState = new MenuPopupStateLoading("Downloading: '" + etr.bootAdapter.getDisplayName() + "'...");
+				MenuStateSelectExportClients.this.changePopupState(popupState);
+				BootMenuMain.runLaterMS(() -> {
+					try {
+						if(exportEPK) {
+							etr.bootAdapter.downloadEPK(popupState);
+						}else {
+							etr.bootAdapter.downloadOffline(popupState);
+						}
+					}catch(Throwable t) {
+						logger.error("Failed to download client!");
+						logger.error(t);
+						changePopupState(new MenuPopupStateConfirmation<String>("Error: Failed to download client!\n\n" + t.toString(),
+								Arrays.asList("OK")) {
+							@Override
+							protected void selectCallback(String enumValue) {
+								BootMenuMain.changeState(parentState);
+							}
+						});
+						return;
+					}
+					BootMenuMain.changeState(parentState);
+				}, 250);
+			}));
+		}
+		selectionController = new SelectionListController<BootItem>(BootMenuMain.bootMenuDOM.content_selection, lst) {
+			@Override
+			protected void itemSelected(BootItem item) {
+				item.onSelected.accept(item.bootEntry);
+			}
+		};
+	}
+
+	@Override
+	protected void enterState() {
+		selectionController.setup();
+		BootMenuDOM.show(BootMenuMain.bootMenuDOM.content_view_selection);
+		BootMenuDOM.show(BootMenuMain.bootMenuDOM.footer_text_menu_select);
+	}
+
+	@Override
+	protected void exitState() {
+		selectionController.destroy();
+		BootMenuDOM.hide(BootMenuMain.bootMenuDOM.content_view_selection);
+		BootMenuDOM.hide(BootMenuMain.bootMenuDOM.footer_text_menu_select);
+	}
+
+	@Override
+	protected void enterPopupBlockingState() {
+		selectionController.setCursorEventsSuspended(true);
+	}
+
+	@Override
+	protected void exitPopupBlockingState() {
+		selectionController.setCursorEventsSuspended(false);
+	}
+
+	@Override
+	protected void handleKeyDown(int keyCode) {
+		selectionController.handleKeyDown(keyCode);
+	}
+
+	@Override
+	protected void handleKeyUp(int keyCode) {
+		
+	}
+
+	@Override
+	protected void handleKeyRepeat(int keyCode) {
+		selectionController.handleKeyRepeat(keyCode);
+	}
+
+	@Override
+	protected void handleOnChanged(HTMLElement htmlElement) {
+		
+	}
+
+	@Override
+	protected void handleOnClick(HTMLElement htmlElement) {
+		
+	}
+
+	@Override
+	protected void handleOnMouseOver(HTMLElement htmlElement) {
+		
+	}
+
+	@Override
+	protected void update() {
+		
+	}
+
+}
diff --git a/sources/teavm-boot-menu/java/net/lax1dude/eaglercraft/v1_8/boot_menu/teavm/OfflineDownloadFactory.java b/sources/teavm-boot-menu/java/net/lax1dude/eaglercraft/v1_8/boot_menu/teavm/OfflineDownloadFactory.java
new file mode 100644
index 00000000..de93e925
--- /dev/null
+++ b/sources/teavm-boot-menu/java/net/lax1dude/eaglercraft/v1_8/boot_menu/teavm/OfflineDownloadFactory.java
@@ -0,0 +1,613 @@
+package net.lax1dude.eaglercraft.v1_8.boot_menu.teavm;
+
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+import java.text.SimpleDateFormat;
+import java.util.Arrays;
+import java.util.Date;
+import java.util.Map;
+import java.util.function.Supplier;
+
+import org.apache.commons.lang3.StringUtils;
+import org.json.JSONArray;
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import com.google.common.html.HtmlEscapers;
+
+import net.lax1dude.eaglercraft.v1_8.Base64;
+import net.lax1dude.eaglercraft.v1_8.EagRuntime;
+import net.lax1dude.eaglercraft.v1_8.EaglercraftUUID;
+import net.lax1dude.eaglercraft.v1_8.cache.EaglerLoadingCache;
+import net.lax1dude.eaglercraft.v1_8.log4j.LogManager;
+import net.lax1dude.eaglercraft.v1_8.log4j.Logger;
+import net.lax1dude.eaglercraft.v1_8.update.CertificateInvalidException;
+import net.lax1dude.eaglercraft.v1_8.update.UpdateCertificate;
+
+/**
+ * Copyright (c) 2024 lax1dude. All Rights Reserved.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ * 
+ */
+public class OfflineDownloadFactory {
+
+	private static final Logger logger = LogManager.getLogger("OfflineDownloadFactory");
+
+	public static void downloadOffline(LaunchConfigEntry launchConf, ClientDataEntry clientData,
+			Map<EaglercraftUUID, Supplier<byte[]>> loaders, IProgressMsgCallback cb) {
+		EaglerLoadingCache<EaglercraftUUID, byte[]> loadingCache = new EaglerLoadingCache<EaglercraftUUID, byte[]>((uuid) -> {
+			Supplier<byte[]> sup = loaders.get(uuid);
+			return sup != null ? sup.get() : null;
+		});
+		switch(launchConf.type) {
+		case STANDARD_OFFLINE_V1:
+			if(clientData.type == EnumClientFormatType.EAGLER_STANDARD_OFFLINE) {
+				downloadClientStandardOffline(launchConf, clientData, loadingCache, cb);
+			}else {
+				throw new UnsupportedOperationException("Wrong client data type " + clientData.type + " for STANDARD_OFFLINE_V1!");
+			}
+			break;
+		case EAGLERX_V1:
+			if(clientData.type == EnumClientFormatType.EAGLER_STANDARD_OFFLINE) {
+				downloadClientEaglerX18(launchConf, clientData, loadingCache, cb);
+			}else {
+				throw new UnsupportedOperationException("Wrong client data type " + clientData.type + " for EAGLERX_V1!");
+			}
+			break;
+		case EAGLERX_SIGNED_V1:
+			if(clientData.type == EnumClientFormatType.EAGLER_SIGNED_OFFLINE) {
+				downloadClientEaglerX18Signed(launchConf, clientData, loadingCache, cb);
+			}else {
+				throw new UnsupportedOperationException("Wrong client data type " + clientData.type + " for EAGLERX_SIGNED_V1!");
+			}
+			break;
+		case EAGLER_1_5_V1:
+			if(clientData.type == EnumClientFormatType.EAGLER_STANDARD_OFFLINE) {
+				downloadClientEagler15Old(launchConf, clientData, loadingCache, cb);
+			}else {
+				throw new UnsupportedOperationException("Wrong client data type " + clientData.type + " for EAGLER_1_5_V1!");
+			}
+			break;
+		case EAGLER_1_5_V2:
+			if(clientData.type == EnumClientFormatType.EAGLER_STANDARD_1_5_OFFLINE) {
+				downloadClientEagler15New(launchConf, clientData, loadingCache, cb);
+			}else {
+				throw new UnsupportedOperationException("Wrong client data type " + clientData.type + " for EAGLER_1_5_V2!");
+			}
+			break;
+		case EAGLER_BETA_V1:
+			if(clientData.type == EnumClientFormatType.EAGLER_STANDARD_OFFLINE) {
+				downloadClientEaglerB13(launchConf, clientData, loadingCache, cb);
+			}else {
+				throw new UnsupportedOperationException("Wrong client data type " + clientData.type + " for EAGLER_1_5_V2!");
+			}
+			break;
+		case PEYTON_V1:
+			if(clientData.type == EnumClientFormatType.EAGLER_STANDARD_OFFLINE) {
+				downloadClientPeytonIndev(launchConf, clientData, loadingCache, cb);
+			}else {
+				throw new UnsupportedOperationException("Wrong client data type " + clientData.type + " for PEYTON_V1!");
+			}
+			break;
+		case PEYTON_V2:
+			if(clientData.type == EnumClientFormatType.EAGLER_STANDARD_OFFLINE) {
+				downloadClientPeytonAlphaBeta(launchConf, clientData, loadingCache, cb);
+			}else {
+				throw new UnsupportedOperationException("Wrong client data type " + clientData.type + " for PEYTON_V2!");
+			}
+			break;
+		}
+	}
+
+	static String loadTemplate(String name) {
+		name = "/assets/eagler/boot_menu/" + name;
+		String template = BootMenuAssets.loadResourceString(name);
+		if(template == null) {
+			throw new NullPointerException("Could not locate offline download template: " + name);
+		}
+		return template;
+	}
+
+	private static void doUpdateMessage(IProgressMsgCallback cb, String str) {
+		logger.info(str);
+		cb.updateMessage(str);
+	}
+
+	private static void downloadClientEaglerX18(LaunchConfigEntry launchConf, ClientDataEntry clientData,
+			EaglerLoadingCache<EaglercraftUUID, byte[]> loadingCache, IProgressMsgCallback cb) {
+		doUpdateMessage(cb, "Resolving classes.js (" + clientData.mainPayload + ")");
+		byte[] classesJSBytes = loadingCache.get(clientData.mainPayload);
+		if(classesJSBytes == null) {
+			String msg = "Could not resolve classes.js! (" + clientData.mainPayload + ")";
+			logger.error(msg);
+			throw new NullPointerException(msg);
+		}
+		String assetsEPKVal;
+		int epkNum = clientData.epkFiles.size();
+		if(epkNum > 1 || !StringUtils.isEmpty(clientData.epkFiles.get(0).extractTo)) {
+			StringBuilder assetsEPKBuilder = new StringBuilder("[ ");
+			for(int i = 0; i < epkNum; ++i) {
+				EPKDataEntry epk = clientData.epkFiles.get(i);
+				doUpdateMessage(cb, "Resolving assets.epk (" + epk.dataUUID + ", path: /" + epk.extractTo + ")");
+				byte[] epkData = loadingCache.get(epk.dataUUID);
+				if(epkData == null) {
+					String msg = "Could not resolve assets.epk! (" + epk.dataUUID + ", path: /" + epk.extractTo + ")";
+					logger.error(msg);
+					throw new NullPointerException(msg);
+				}
+				if(i > 0) {
+					assetsEPKBuilder.append(", ");
+				}
+				assetsEPKBuilder.append("{ url: \"data:application/octet-stream;base64,");
+				assetsEPKBuilder.append(Base64.encodeBase64String(epkData));
+				assetsEPKBuilder.append("\", path: \"");
+				assetsEPKBuilder.append(stupidJSONEscape(epk.extractTo));
+				assetsEPKBuilder.append("\" }");
+			}
+			assetsEPKBuilder.append(" ]");
+			assetsEPKVal = assetsEPKBuilder.toString();
+		}else {
+			EPKDataEntry epk = clientData.epkFiles.get(0);
+			doUpdateMessage(cb, "Resolving assets.epk (" + epk.dataUUID + ", path: /)");
+			byte[] epkData = loadingCache.get(epk.dataUUID);
+			if(epkData == null) {
+				String msg = "Could not resolve assets.epk! (" + epk.dataUUID + ", path: /)";
+				logger.error(msg);
+				throw new NullPointerException(msg);
+			}
+			assetsEPKVal = "\"data:application/octet-stream;base64," + Base64.encodeBase64String(epkData) + "\"";
+		}
+		doUpdateMessage(cb, "Loading offline_template_eaglercraftX_1_8.html");
+		String template = loadTemplate("offline_template_eaglercraftX_1_8.html");
+		template = template.replace("${client_name}", HtmlEscapers.htmlEscaper().escape(launchConf.displayName));
+		template = template.replace("${date}", (new SimpleDateFormat("MM/dd/yyyy")).format(new Date()));
+		int relayIdCount = RelayRandomizeHelper.countRelayMacro(launchConf.launchOpts);
+		template = template.replace("${relayId_max}", Integer.toString(relayIdCount));
+		String launchOptsFormatted;
+		try {
+			launchOptsFormatted = (new JSONObject(launchConf.launchOpts)).toString(4);
+		}catch(JSONException ex) {
+			throw new IllegalArgumentException("Launch options JSON is invalid! " + ex.toString());
+		}
+		if(relayIdCount > 0) {
+			launchOptsFormatted = RelayRandomizeHelper.replaceRelayMacroWithEqRelayId(launchOptsFormatted);
+		}
+		template = template.replace("${launch_opts}", launchOptsFormatted);
+		JSONObject launchConfJSON = new JSONObject();
+		launchConf.writeJSON(launchConfJSON);
+		template = template.replace("${launch_conf_json}", launchConfJSON.toString());
+		template = template.replace(StringUtils.reverse("}kpe_stessa{$"), assetsEPKVal);
+		template = template.replace(StringUtils.reverse("}sj_sessalc{$"), new String(removeUseStrict(classesJSBytes), StandardCharsets.UTF_8));
+		doUpdateMessage(cb, "Downloading file...");
+		EagRuntime.downloadFileWithName(launchConf.displayName.replaceAll("[^a-zA-Z0-9\\-_\\.]", "_") + ".html", template.getBytes(StandardCharsets.UTF_8));
+	}
+
+	private static void downloadClientEaglerX18Signed(LaunchConfigEntry launchConf, ClientDataEntry clientData,
+			EaglerLoadingCache<EaglercraftUUID, byte[]> loadingCache, IProgressMsgCallback cb) {
+		doUpdateMessage(cb, "Resolving client signature (" + clientData.clientSignature + ")");
+		byte[] clientSignature = loadingCache.get(clientData.clientSignature);
+		if(clientSignature == null) {
+			String msg = "Could not resolve client signature! (" + clientData.clientSignature + ")";
+			logger.error(msg);
+			throw new NullPointerException(msg);
+		}
+		doUpdateMessage(cb, "Resolving client payload (" + clientData.mainPayload + ")");
+		byte[] clientPayload = loadingCache.get(clientData.mainPayload);
+		if(clientPayload == null) {
+			String msg = "Could not resolve client payload! (" + clientData.mainPayload + ")";
+			logger.error(msg);
+			throw new NullPointerException(msg);
+		}
+		doUpdateMessage(cb, "Checking signature validity");
+		UpdateCertificate cert = null;
+		try {
+			cert = UpdateCertificate.parseAndVerifyCertificate(clientSignature);
+		}catch(CertificateInvalidException | IOException e) {
+			logger.error("Signature invalid or not recognized!");
+			logger.error(e);
+			logger.info("The client will be exported anyway. RIP");
+		}
+		if(cert != null) {
+			if(!cert.isBundleDataValid(clientPayload)) {
+				logger.error("Client payload checksum does not match the certificate!");
+				cert = null;
+			}
+		}else {
+			logger.info("Signature is valid: {} - {}", cert.bundleDisplayName, cert.bundleDisplayVersion);
+		}
+		doUpdateMessage(cb, "Loading offline_template_eaglercraftX_1_8_signed.html");
+		String template = loadTemplate("offline_template_eaglercraftX_1_8_signed.html");
+		template = template.replace("${client_name}", HtmlEscapers.htmlEscaper().escape(cert != null ? (cert.bundleDisplayName + " " + cert.bundleDisplayVersion) : launchConf.displayName));
+		SimpleDateFormat df = new SimpleDateFormat("MM/dd/yyyy");
+		template = template.replace("${date}", df.format(new Date()));
+		int relayIdCount = RelayRandomizeHelper.countRelayMacro(launchConf.launchOpts);
+		template = template.replace("${relayId_max}", Integer.toString(relayIdCount));
+		String launchOptsFormatted;
+		try {
+			launchOptsFormatted = (new JSONObject(launchConf.launchOpts)).toString(4);
+		}catch(JSONException ex) {
+			throw new IllegalArgumentException("Launch options JSON is invalid! " + ex.toString());
+		}
+		if(relayIdCount > 0) {
+			launchOptsFormatted = RelayRandomizeHelper.replaceRelayMacroWithEqRelayId(launchOptsFormatted);
+		}
+		template = template.replace("${launch_opts}", launchOptsFormatted);
+		JSONObject launchConfJSON = new JSONObject();
+		launchConf.writeJSON(launchConfJSON);
+		template = template.replace("${launch_conf_json}", launchConfJSON.toString());
+		String fileName;
+		if(cert != null) {
+			String d8 = df.format(new Date(cert.sigTimestamp));
+			template = template.replace("${signature_details}", cert.bundleDisplayName + " " + cert.bundleDisplayVersion
+					+ " (" + cert.bundleVersionInteger + ") " + d8 + ", Author: " + cert.bundleAuthorName);
+			template = template.replace("${client_name_or_origin_date}", "This file is from <span style=\"color:#AA0000;\">" + d8 + "</span>");
+			fileName = cert.bundleDisplayName + "_" + cert.bundleDisplayVersion + "_Offline_Signed";
+		}else {
+			template = template.replace("${signature_details}", "INVALID! (Or just from a 3rd party client)");
+			template = template.replace("${client_name_or_origin_date}", HtmlEscapers.htmlEscaper().escape(launchConf.displayName));
+			fileName = launchConf.displayName;
+		}
+		template = template.replace("${client_signature}", Base64.encodeBase64String(clientSignature));
+		template = template.replace("${client_bundle}", Base64.encodeBase64String(clientPayload));
+		doUpdateMessage(cb, "Downloading file...");
+		EagRuntime.downloadFileWithName(fileName.replaceAll("[^a-zA-Z0-9\\-_\\.]", "_") + ".html", template.getBytes(StandardCharsets.UTF_8));
+	}
+
+	private static void downloadClientEagler15New(LaunchConfigEntry launchConf, ClientDataEntry clientData,
+			EaglerLoadingCache<EaglercraftUUID, byte[]> loadingCache, IProgressMsgCallback cb) {
+		if(clientData.epkFiles.size() != 1) {
+			throw new UnsupportedOperationException("Wrong number of EPK files: " + clientData.epkFiles.size());
+		}
+		doUpdateMessage(cb, "Resolving classes.js (" + clientData.mainPayload + ")");
+		byte[] classesJSBytes = loadingCache.get(clientData.mainPayload);
+		if(classesJSBytes == null) {
+			String msg = "Could not resolve classes.js! (" + clientData.mainPayload + ")";
+			logger.error(msg);
+			throw new NullPointerException(msg);
+		}
+		doUpdateMessage(cb, "Resolving classes_server.js (" + clientData.integratedServer + ")");
+		byte[] classesServerJSBytes = loadingCache.get(clientData.integratedServer);
+		if(classesServerJSBytes == null) {
+			String msg = "Could not resolve classes_server.js! (" + clientData.integratedServer + ")";
+			logger.error(msg);
+			throw new NullPointerException(msg);
+		}
+		doUpdateMessage(cb, "Resolving assets.epk (" + clientData.epkFiles.get(0).dataUUID + ")");
+		byte[] assetsEPKBytes = loadingCache.get(clientData.epkFiles.get(0).dataUUID);
+		if(assetsEPKBytes == null) {
+			String msg = "Could not resolve assets.epk! (" + clientData.epkFiles.get(0).dataUUID + ")";
+			logger.error(msg);
+			throw new NullPointerException(msg);
+		}
+		doUpdateMessage(cb, "Loading offline_template_eaglercraft_1_5.html");
+		String template = loadTemplate("offline_template_eaglercraft_1_5.html");
+		template = template.replace("${client_name}", HtmlEscapers.htmlEscaper().escape(launchConf.displayName));
+		template = template.replace("${date}", (new SimpleDateFormat("MM/dd/yyyy")).format(new Date()));
+		int relayIdCount = RelayRandomizeHelper.countRelayMacro(launchConf.launchOpts);
+		template = template.replace("${relayId_max}", Integer.toString(relayIdCount));
+		String launchOptsFormatted;
+		try {
+			launchOptsFormatted = (new JSONObject(launchConf.launchOpts)).toString(4);
+		}catch(JSONException ex) {
+			throw new IllegalArgumentException("Launch options JSON is invalid! " + ex.toString());
+		}
+		if(relayIdCount > 0) {
+			launchOptsFormatted = RelayRandomizeHelper.replaceRelayMacroWithEqRelayId(launchOptsFormatted);
+		}
+		template = template.replace("${launch_opts}", launchOptsFormatted);
+		JSONObject launchConfJSON = new JSONObject();
+		launchConf.writeJSON(launchConfJSON);
+		template = template.replace("${launch_conf_json}", launchConfJSON.toString());
+		template = template.replace(StringUtils.reverse("}kpe_stessa{$"), Base64.encodeBase64String(assetsEPKBytes));
+		template = template.replace(StringUtils.reverse("}sj_sessalc{$"), new String(removeUseStrict(classesJSBytes), StandardCharsets.UTF_8));
+		template = template.replace("${classes_server_js}", new String(removeUseStrict(classesServerJSBytes), StandardCharsets.UTF_8));
+		doUpdateMessage(cb, "Downloading file...");
+		EagRuntime.downloadFileWithName(launchConf.displayName.replaceAll("[^a-zA-Z0-9\\-_\\.]", "_") + ".html", template.getBytes(StandardCharsets.UTF_8));
+	}
+
+	private static void downloadClientEagler15Old(LaunchConfigEntry launchConf, ClientDataEntry clientData,
+			EaglerLoadingCache<EaglercraftUUID, byte[]> loadingCache, IProgressMsgCallback cb) {
+		if(clientData.epkFiles.size() != 1) {
+			throw new UnsupportedOperationException("Wrong number of EPK files: " + clientData.epkFiles.size());
+		}
+		doUpdateMessage(cb, "Resolving classes.js (" + clientData.mainPayload + ")");
+		byte[] classesJSBytes = loadingCache.get(clientData.mainPayload);
+		if(classesJSBytes == null) {
+			String msg = "Could not resolve classes.js! (" + clientData.mainPayload + ")";
+			logger.error(msg);
+			throw new NullPointerException(msg);
+		}
+		doUpdateMessage(cb, "Resolving assets.epk (" + clientData.epkFiles.get(0).dataUUID + ")");
+		byte[] assetsEPKBytes = loadingCache.get(clientData.epkFiles.get(0).dataUUID);
+		if(assetsEPKBytes == null) {
+			String msg = "Could not resolve assets.epk! (" + clientData.epkFiles.get(0).dataUUID + ")";
+			logger.error(msg);
+			throw new NullPointerException(msg);
+		}
+		doUpdateMessage(cb, "Loading offline_template_eaglercraft_1_5_legacy.html");
+		String template = loadTemplate("offline_template_eaglercraft_1_5_legacy.html");
+		template = template.replace("${client_name}", HtmlEscapers.htmlEscaper().escape(launchConf.displayName));
+		template = template.replace("${date}", (new SimpleDateFormat("MM/dd/yyyy")).format(new Date()));
+		JSONObject launchConfJSON = new JSONObject();
+		launchConf.writeJSON(launchConfJSON);
+		template = template.replace("${launch_conf_json}", launchConfJSON.toString());
+		template = template.replace("${launch_opts}", ClientBootFactory.translateNBTOpts(launchConf.launchOpts));
+		template = template.replace(StringUtils.reverse("}kpe_stessa{$"), Base64.encodeBase64String(assetsEPKBytes));
+		template = template.replace(StringUtils.reverse("}sj_sessalc{$"), new String(removeUseStrict(classesJSBytes), StandardCharsets.UTF_8));
+		doUpdateMessage(cb, "Downloading file...");
+		EagRuntime.downloadFileWithName(launchConf.displayName.replaceAll("[^a-zA-Z0-9\\-_\\.]", "_") + ".html", template.getBytes(StandardCharsets.UTF_8));
+	}
+
+	private static void downloadClientEaglerB13(LaunchConfigEntry launchConf, ClientDataEntry clientData,
+			EaglerLoadingCache<EaglercraftUUID, byte[]> loadingCache, IProgressMsgCallback cb) {
+		if(clientData.epkFiles.size() != 1) {
+			throw new UnsupportedOperationException("Wrong number of EPK files: " + clientData.epkFiles.size());
+		}
+		doUpdateMessage(cb, "Resolving classes.js (" + clientData.mainPayload + ")");
+		byte[] classesJSBytes = loadingCache.get(clientData.mainPayload);
+		if(classesJSBytes == null) {
+			String msg = "Could not resolve classes.js! (" + clientData.mainPayload + ")";
+			logger.error(msg);
+			throw new NullPointerException(msg);
+		}
+		doUpdateMessage(cb, "Resolving assets.epk (" + clientData.epkFiles.get(0).dataUUID + ")");
+		byte[] assetsEPKBytes = loadingCache.get(clientData.epkFiles.get(0).dataUUID);
+		if(assetsEPKBytes == null) {
+			String msg = "Could not resolve assets.epk! (" + clientData.epkFiles.get(0).dataUUID + ")";
+			logger.error(msg);
+			throw new NullPointerException(msg);
+		}
+		doUpdateMessage(cb, "Loading offline_template_eaglercraft_b1_3.html");
+		String template = loadTemplate("offline_template_eaglercraft_b1_3.html");
+		template = template.replace("${client_name}", HtmlEscapers.htmlEscaper().escape(launchConf.displayName));
+		template = template.replace("${date}", (new SimpleDateFormat("MM/dd/yyyy")).format(new Date()));
+		JSONObject launchConfJSON = new JSONObject();
+		launchConf.writeJSON(launchConfJSON);
+		template = template.replace("${launch_conf_json}", launchConfJSON.toString());
+		template = template.replace(StringUtils.reverse("}kpe_stessa{$"), Base64.encodeBase64String(assetsEPKBytes));
+		template = template.replace(StringUtils.reverse("}sj_sessalc{$"), new String(removeUseStrict(classesJSBytes), StandardCharsets.UTF_8));
+		doUpdateMessage(cb, "Downloading file...");
+		EagRuntime.downloadFileWithName(launchConf.displayName.replaceAll("[^a-zA-Z0-9\\-_\\.]", "_") + ".html", template.getBytes(StandardCharsets.UTF_8));
+	}
+
+	private static void downloadClientPeytonAlphaBeta(LaunchConfigEntry launchConf, ClientDataEntry clientData,
+			EaglerLoadingCache<EaglercraftUUID, byte[]> loadingCache, IProgressMsgCallback cb) {
+		if(clientData.epkFiles.size() != 1) {
+			throw new UnsupportedOperationException("Wrong number of EPK files: " + clientData.epkFiles.size());
+		}
+		doUpdateMessage(cb, "Resolving classes.js (" + clientData.mainPayload + ")");
+		byte[] classesJSBytes = loadingCache.get(clientData.mainPayload);
+		if(classesJSBytes == null) {
+			String msg = "Could not resolve classes.js! (" + clientData.mainPayload + ")";
+			logger.error(msg);
+			throw new NullPointerException(msg);
+		}
+		doUpdateMessage(cb, "Resolving assets.epk (" + clientData.epkFiles.get(0).dataUUID + ")");
+		byte[] assetsEPKBytes = loadingCache.get(clientData.epkFiles.get(0).dataUUID);
+		if(assetsEPKBytes == null) {
+			String msg = "Could not resolve assets.epk! (" + clientData.epkFiles.get(0).dataUUID + ")";
+			logger.error(msg);
+			throw new NullPointerException(msg);
+		}
+		doUpdateMessage(cb, "Loading offline_template_peytonplayz585_a_b.html");
+		String template = loadTemplate("offline_template_peytonplayz585_a_b.html");
+		template = template.replace("${client_name}", HtmlEscapers.htmlEscaper().escape(launchConf.displayName));
+		template = template.replace("${date}", (new SimpleDateFormat("MM/dd/yyyy")).format(new Date()));
+		String launchOptsFormatted;
+		try {
+			launchOptsFormatted = (new JSONObject(launchConf.launchOpts)).toString(4);
+		}catch(JSONException ex) {
+			throw new IllegalArgumentException("Launch options JSON is invalid! " + ex.toString());
+		}
+		template = template.replace("${launch_opts}", launchOptsFormatted);
+		JSONObject launchConfJSON = new JSONObject();
+		launchConf.writeJSON(launchConfJSON);
+		template = template.replace("${launch_conf_json}", launchConfJSON.toString());
+		template = template.replace(StringUtils.reverse("}kpe_stessa{$"), Base64.encodeBase64String(assetsEPKBytes));
+		template = template.replace(StringUtils.reverse("}sj_sessalc{$"), new String(removeUseStrict(classesJSBytes), StandardCharsets.UTF_8));
+		doUpdateMessage(cb, "Downloading file...");
+		EagRuntime.downloadFileWithName(launchConf.displayName.replaceAll("[^a-zA-Z0-9\\-_\\.]", "_") + ".html", template.getBytes(StandardCharsets.UTF_8));
+	}
+
+	private static void downloadClientPeytonIndev(LaunchConfigEntry launchConf, ClientDataEntry clientData,
+			EaglerLoadingCache<EaglercraftUUID, byte[]> loadingCache, IProgressMsgCallback cb) {
+		if(clientData.epkFiles.size() != 1) {
+			throw new UnsupportedOperationException("Wrong number of EPK files: " + clientData.epkFiles.size());
+		}
+		doUpdateMessage(cb, "Resolving classes.js (" + clientData.mainPayload + ")");
+		byte[] classesJSBytes = loadingCache.get(clientData.mainPayload);
+		if(classesJSBytes == null) {
+			String msg = "Could not resolve classes.js! (" + clientData.mainPayload + ")";
+			logger.error(msg);
+			throw new NullPointerException(msg);
+		}
+		doUpdateMessage(cb, "Resolving assets.epk (" + clientData.epkFiles.get(0).dataUUID + ")");
+		byte[] assetsEPKBytes = loadingCache.get(clientData.epkFiles.get(0).dataUUID);
+		if(assetsEPKBytes == null) {
+			String msg = "Could not resolve assets.epk! (" + clientData.epkFiles.get(0).dataUUID + ")";
+			logger.error(msg);
+			throw new NullPointerException(msg);
+		}
+		doUpdateMessage(cb, "Loading offline_template_peytonplayz585_indev.html");
+		String template = loadTemplate("offline_template_peytonplayz585_indev.html");
+		template = template.replace("${client_name}", HtmlEscapers.htmlEscaper().escape(launchConf.displayName));
+		template = template.replace("${date}", (new SimpleDateFormat("MM/dd/yyyy")).format(new Date()));
+		JSONObject launchConfJSON = new JSONObject();
+		launchConf.writeJSON(launchConfJSON);
+		template = template.replace("${launch_conf_json}", launchConfJSON.toString());
+		template = template.replace(StringUtils.reverse("}kpe_stessa{$"), Base64.encodeBase64String(assetsEPKBytes));
+		template = template.replace(StringUtils.reverse("}sj_sessalc{$"), new String(removeUseStrict(classesJSBytes), StandardCharsets.UTF_8));
+		doUpdateMessage(cb, "Downloading file...");
+		EagRuntime.downloadFileWithName(launchConf.displayName.replaceAll("[^a-zA-Z0-9\\-_\\.]", "_") + ".html", template.getBytes(StandardCharsets.UTF_8));
+	}
+
+	static String stupidJSONEscape(String str) {
+		str = (new JSONArray().put(str)).toString();
+		return str.substring(2, str.length() - 2);
+	}
+
+	private static void downloadClientStandardOffline(LaunchConfigEntry launchConf, ClientDataEntry clientData,
+			EaglerLoadingCache<EaglercraftUUID, byte[]> loadingCache, IProgressMsgCallback cb) {
+		doUpdateMessage(cb, "Resolving classes.js (" + clientData.mainPayload + ")");
+		byte[] classesJSBytes = loadingCache.get(clientData.mainPayload);
+		if(classesJSBytes == null) {
+			String msg = "Could not resolve classes.js! (" + clientData.mainPayload + ")";
+			logger.error(msg);
+			throw new NullPointerException(msg);
+		}
+		JSONArray assetsEPKs = new JSONArray();
+		for(EPKDataEntry epk : clientData.epkFiles) {
+			doUpdateMessage(cb, "Resolving assets.epk (" + epk.dataUUID + ", path: /" + epk.extractTo + ")");
+			byte[] epkData = loadingCache.get(epk.dataUUID);
+			if(epkData == null) {
+				String msg = "Could not resolve assets.epk! (" + epk.dataUUID + ", path: /" + epk.extractTo + ")";
+				logger.error(msg);
+				throw new NullPointerException(msg);
+			}
+			JSONObject obj = new JSONObject();
+			obj.put("url", "data:application/octet-stream;base64," + Base64.encodeBase64String(epkData));
+			obj.put("path", epk.extractTo);
+			assetsEPKs.put(obj);
+		}
+		doUpdateMessage(cb, "Loading offline_template_eaglercraftX_1_8.html");
+		String template = loadTemplate("offline_template_eaglercraftX_1_8.html");
+		template = template.replace("${client_name}", HtmlEscapers.htmlEscaper().escape(launchConf.displayName));
+		template = template.replace("${date}", (new SimpleDateFormat("MM/dd/yyyy")).format(new Date()));
+		template = template.replace("${launch_opts_var_name}", stupidJSONEscape(launchConf.launchOptsVar));
+		template = template.replace("${launch_opts_var_container_name}", stupidJSONEscape(launchConf.launchOptsContainerVar));
+		template = template.replace("${launch_opts_var_assetsURI_name}", stupidJSONEscape(launchConf.launchOptsAssetsURIVar));
+		template = template.replace("${main_function_name}", stupidJSONEscape(launchConf.mainFunction));
+		int relayIdCount = RelayRandomizeHelper.countRelayMacro(launchConf.launchOpts);
+		template = template.replace("${relayId_max}", Integer.toString(relayIdCount));
+		String launchOptsFormatted;
+		try {
+			launchOptsFormatted = (new JSONObject(launchConf.launchOpts)).toString(4);
+		}catch(JSONException ex) {
+			throw new IllegalArgumentException("Launch options JSON is invalid! " + ex.toString());
+		}
+		if(relayIdCount > 0) {
+			launchOptsFormatted = RelayRandomizeHelper.replaceRelayMacroWithEqRelayId(launchOptsFormatted);
+		}
+		template = template.replace("${launch_opts}", launchOptsFormatted);
+		JSONObject launchConfJSON = new JSONObject();
+		launchConf.writeJSON(launchConfJSON);
+		template = template.replace("${launch_conf_json}", launchConfJSON.toString());
+		template = template.replace(StringUtils.reverse("}kpe_stessa{$"), assetsEPKs.toString());
+		template = template.replace(StringUtils.reverse("}sj_sessalc{$"), new String(removeUseStrict(classesJSBytes), StandardCharsets.UTF_8));
+		doUpdateMessage(cb, "Downloading file...");
+		EagRuntime.downloadFileWithName(launchConf.displayName.replaceAll("[^a-zA-Z0-9\\-_\\.]", "_") + ".html", template.getBytes(StandardCharsets.UTF_8));
+	}
+
+	public static byte[] removeClientScriptElement(byte[] input, boolean addUseStrict) {
+		byte[] str = "\"use strict\";\r\nif(typeof window !== \"undefined\") window.eaglercraftXClientScriptElement = document.currentScript;".getBytes(StandardCharsets.UTF_8);
+		if(input.length < str.length + 2) {
+			return input;
+		}
+		if(Arrays.equals(str, 0, str.length, input, 0, str.length)) {
+			return doUseStrict(input, str.length, addUseStrict);
+		}
+		if(Arrays.equals(str, 0, str.length, input, 1, str.length + 1)) {
+			return doUseStrict(input, str.length + 1, addUseStrict);
+		}
+		if(Arrays.equals(str, 0, str.length, input, 2, str.length + 2)) {
+			return doUseStrict(input, str.length + 2, addUseStrict);
+		}
+		str = "\"use strict\";\nif(typeof window !== \"undefined\") window.eaglercraftXClientScriptElement = document.currentScript;".getBytes(StandardCharsets.UTF_8);
+		if(input.length < str.length) {
+			return input;
+		}
+		if(Arrays.equals(str, 0, str.length, input, 0, str.length)) {
+			return doUseStrict(input, str.length, addUseStrict);
+		}
+		if(Arrays.equals(str, 0, str.length, input, 1, str.length + 1)) {
+			return doUseStrict(input, str.length + 1, addUseStrict);
+		}
+		if(Arrays.equals(str, 0, str.length, input, 2, str.length + 2)) {
+			return doUseStrict(input, str.length + 2, addUseStrict);
+		}
+		if(addUseStrict) {
+			str = new byte[] {(byte)34, (byte)117, (byte)115, (byte)101, (byte)32, (byte)115, (byte)116, (byte)114, (byte)105, (byte)99, (byte)116, (byte)34, (byte)59};
+			if(Arrays.equals(str, 0, str.length, input, 0, str.length)) {
+				return input;
+			}
+			if(Arrays.equals(str, 0, str.length, input, 1, str.length + 1)) {
+				return input;
+			}
+			if(Arrays.equals(str, 0, str.length, input, 2, str.length + 2)) {
+				return input;
+			}
+			return doUseStrict(input, 0, addUseStrict);
+		}else {
+			return input;
+		}
+	}
+
+	private static byte[] doUseStrict(byte[] input, int removeLength, boolean addUseStrict) {
+		if(addUseStrict) {
+			byte[] useStrict = new byte[] {(byte)34, (byte)117, (byte)115, (byte)101, (byte)32, (byte)115, (byte)116, (byte)114, (byte)105, (byte)99, (byte)116, (byte)34, (byte)59, (byte)10};
+			while(removeLength < input.length && (input[removeLength] == '\n' || input[removeLength] == '\r')) {
+				++removeLength;
+			}
+			int endRemoveLength = input.length;
+			while(endRemoveLength > removeLength + 1 && (input[endRemoveLength - 1] == '\n' || input[endRemoveLength - 1] == '\r')) {
+				--endRemoveLength;
+			}
+			byte[] ret = new byte[endRemoveLength - removeLength + useStrict.length];
+			System.arraycopy(useStrict, 0, ret, 0, useStrict.length);
+			System.arraycopy(input, removeLength, ret, useStrict.length, endRemoveLength - removeLength);
+			return ret;
+		}else {
+			int endRemoveLength = input.length;
+			while(endRemoveLength > removeLength + 1 && (input[endRemoveLength - 1] == '\n' || input[endRemoveLength - 1] == '\r')) {
+				--endRemoveLength;
+			}
+			if(removeLength > 0 || endRemoveLength != input.length) {
+				return Arrays.copyOfRange(input, removeLength, endRemoveLength);
+			}else {
+				return input;
+			}
+		}
+	}
+
+	public static byte[] removeUseStrict(byte[] input) {
+		byte[] str = new byte[] {(byte)34, (byte)117, (byte)115, (byte)101, (byte)32, (byte)115, (byte)116, (byte)114, (byte)105, (byte)99, (byte)116, (byte)34, (byte)59};
+		if(input.length < str.length + 2) {
+			return input;
+		}
+		int i = 0;
+		if (Arrays.equals(str, 0, str.length, input, 0, str.length)
+				|| Arrays.equals(str, 0, str.length, input, ++i, str.length + i)
+				|| Arrays.equals(str, 0, str.length, input, ++i, str.length + i)) {
+			int removeLength = str.length + i;
+			while(removeLength < input.length && (input[removeLength] == '\n' || input[removeLength] == '\r')) {
+				++removeLength;
+			}
+			int endRemoveLength = input.length;
+			while(endRemoveLength > removeLength + 1 && (input[endRemoveLength - 1] == '\n' || input[endRemoveLength - 1] == '\r')) {
+				--endRemoveLength;
+			}
+			return Arrays.copyOfRange(input, removeLength, endRemoveLength);
+		}else {
+			int endRemoveLength = input.length;
+			while(endRemoveLength > 1 && (input[endRemoveLength - 1] == '\n' || input[endRemoveLength - 1] == '\r')) {
+				--endRemoveLength;
+			}
+			if(endRemoveLength != input.length) {
+				return Arrays.copyOfRange(input, 0, endRemoveLength);
+			}else {
+				return input;
+			}
+		}
+	}
+
+}
diff --git a/sources/teavm-boot-menu/java/net/lax1dude/eaglercraft/v1_8/boot_menu/teavm/OfflineDownloadParser.java b/sources/teavm-boot-menu/java/net/lax1dude/eaglercraft/v1_8/boot_menu/teavm/OfflineDownloadParser.java
new file mode 100644
index 00000000..6bb96983
--- /dev/null
+++ b/sources/teavm-boot-menu/java/net/lax1dude/eaglercraft/v1_8/boot_menu/teavm/OfflineDownloadParser.java
@@ -0,0 +1,990 @@
+package net.lax1dude.eaglercraft.v1_8.boot_menu.teavm;
+
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.commons.lang3.StringUtils;
+import org.json.JSONArray;
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import com.google.common.collect.Lists;
+
+import net.lax1dude.eaglercraft.v1_8.Base64;
+import net.lax1dude.eaglercraft.v1_8.EaglercraftUUID;
+import net.lax1dude.eaglercraft.v1_8.log4j.LogManager;
+import net.lax1dude.eaglercraft.v1_8.log4j.Logger;
+
+/**
+ * Copyright (c) 2024 lax1dude. All Rights Reserved.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ * 
+ */
+public class OfflineDownloadParser {
+
+	private static final Logger logger = LogManager.getLogger("OfflineDownloadParser");
+
+	public static EnumOfflineParseType detectOfflineType(String offlineDownloadData) {
+		int hintIndex = offlineDownloadData.indexOf(StringUtils.reverse(">\"tniHesraPenilffOtfarcrelgae\"=epyt elyts<"));
+		if(hintIndex != -1) {
+			hintIndex += 42;
+			int closeTagIndex = offlineDownloadData.indexOf(StringUtils.reverse(">elyts/<"), hintIndex);
+			if(closeTagIndex != -1) {
+				try {
+					JSONObject parseHint = new JSONObject(offlineDownloadData.substring(hintIndex, closeTagIndex));
+					return EnumOfflineParseType.valueOf(parseHint.getString("type"));
+				}catch(JSONException | IllegalArgumentException ex) {
+					logger.error("This offline download has a parse hint section, but the JSON is corrupt!");
+					logger.error(ex);
+				}
+			}
+		}
+		if(offlineDownloadData.startsWith("EAGPKG$$")) {
+			logger.info("Detected format: EAGLERCRAFT_EPK_FILE");
+			return EnumOfflineParseType.EAGLERCRAFT_EPK_FILE;
+		}
+		if(foundWithin(offlineDownloadData.indexOf(StringUtils.reverse(",46esab;maerts-tetco/noitacilppa:atad>\"erutangiStneilCXtfarcrelgae\"=di \"tfarcrelgae\"=epyt elyts<")), 32, 2048)) {
+			logger.info("Detected format: EAGLERCRAFTX_1_8_SIGNED (post u24)");
+			return EnumOfflineParseType.EAGLERCRAFTX_1_8_SIGNED;
+		}
+		if(foundWithin(offlineDownloadData.indexOf(StringUtils.reverse(",46esab;maerts-tetco/noitacilppa:atad\" = erutangiStneilCXtfarcrelgae.wodniw")), 32, 2048)) {
+			logger.info("Detected format: EAGLERCRAFTX_1_8_SIGNED (pre u24)");
+			return EnumOfflineParseType.EAGLERCRAFTX_1_8_SIGNED;
+		}
+		if(foundWithin(offlineDownloadData.indexOf(StringUtils.reverse(",46esab;maerts-tetco/noitacilppa:atad\" = IRUstessa.stpOXtfarcrelgae.wodniw")), 8388608, offlineDownloadData.length() - 1048576)) {
+			logger.info("Detected format: EAGLERCRAFTX_1_8_OFFLINE (en_US)");
+			return EnumOfflineParseType.EAGLERCRAFTX_1_8_OFFLINE;
+		}
+		if(foundWithin(offlineDownloadData.indexOf(StringUtils.reverse(",46esab;maerts-tetco/noitacilppa:atad\" :lru { [ = IRUstessa.stpOXtfarcrelgae.wodniw")), 8388608, offlineDownloadData.length() - 1048576)) {
+			logger.info("Detected format: EAGLERCRAFTX_1_8_OFFLINE (International)");
+			return EnumOfflineParseType.EAGLERCRAFTX_1_8_OFFLINE;
+		}
+		if(foundWithin(offlineDownloadData.indexOf(StringUtils.reverse("{ = stpOtfarcrelgae.wodniw")), 32, 2048) && foundWithin(offlineDownloadData.indexOf(StringUtils.reverse(">\"rekrow_ps\"=di \"rekrowrelgae/txet\"=epyt tpircs<")), 4194304, offlineDownloadData.length() - 1048576)) {
+			logger.info("Detected format: EAGLERCRAFTX_1_5_NEW_OFFLINE");
+			return EnumOfflineParseType.EAGLERCRAFT_1_5_NEW_OFFLINE;
+		}
+		if(foundWithin(offlineDownloadData.indexOf(StringUtils.reverse(",\"emarf_emag\"\t\t\n[ = stpOtfarcenim.wodniw")), 32, 2048) || foundWithin(offlineDownloadData.indexOf(StringUtils.reverse(",\"emarf_emag\"        \n[ = stpOtfarcenim.wodniw")), 32, 2048)) {
+			if(foundWithin(offlineDownloadData.indexOf("\"eaglercraft.minecraft = \\\"b1.3\\\"\\n\""), 524288, offlineDownloadData.length() - 1048576)) {
+				logger.info("Detected format: EAGLERCRAFT_BETA_B1_3_OFFLINE");
+				return EnumOfflineParseType.EAGLERCRAFT_BETA_B1_3_OFFLINE;
+			}else if(foundWithin(offlineDownloadData.indexOf("\"eaglercraft.minecraft = \\\"1.5.2\\\"\\n\""), 2097152, offlineDownloadData.length() - 2097152)) {
+				logger.info("Detected format: EAGLERCRAFTX_1_5_OLD_OFFLINE");
+				return EnumOfflineParseType.EAGLERCRAFT_1_5_OLD_OFFLINE;
+			}
+		}
+		if(foundWithin(offlineDownloadData.indexOf(StringUtils.reverse("{ = gifnoc.wodniw")), 32, 512)) {
+			logger.info("Detected format: PEYTONPLAYZ585_ALPHA_BETA");
+			return EnumOfflineParseType.PEYTONPLAYZ585_ALPHA_BETA;
+		}
+		if(foundWithin(offlineDownloadData.indexOf(StringUtils.reverse(",\"emarf_emag\"\t\t\n[ = gifnoCcissalc.wodniw")), 32, 512) || foundWithin(offlineDownloadData.indexOf(StringUtils.reverse(",\"emarf_emag\"    \n[ = gifnoCcissalc.wodniw")), 32, 512)) {
+			logger.info("Detected format: PEYTONPLAYZ585_INDEV");
+			return EnumOfflineParseType.PEYTONPLAYZ585_INDEV;
+		}
+		if(foundWithin(offlineDownloadData.indexOf(StringUtils.reverse(">eltit/<evirD elgooG - evirD yM>eltit<\n>/ \"8-FTU\"=tesrahc atem<\n>daeh<")), 32, 2048)) {
+			logger.info("Detected format: EAGLERCRAFTX_1_5_NEW_OFFLINE (maybe)");
+			return EnumOfflineParseType.EAGLERCRAFT_1_5_NEW_OFFLINE;
+		}
+		if(foundWithin(offlineDownloadData.indexOf(StringUtils.reverse(">eltit/<lacol tfarcrelgae>eltit<\n>daeh<")), 32, 2048)) {
+			if(foundWithin(offlineDownloadData.indexOf("\"eaglercraft.minecraft = \\\"b1.3\\\"\\n\""), 524288, offlineDownloadData.length() - 1048576)) {
+				logger.info("Detected format: EAGLERCRAFT_BETA_B1_3_OFFLINE");
+				return EnumOfflineParseType.EAGLERCRAFT_BETA_B1_3_OFFLINE;
+			}else if(foundWithin(offlineDownloadData.indexOf("\"eaglercraft.minecraft = \\\"1.5.2\\\"\\n\""), 2097152, offlineDownloadData.length() - 2097152)) {
+				logger.info("Detected format: EAGLERCRAFTX_1_5_OLD_OFFLINE");
+				return EnumOfflineParseType.EAGLERCRAFT_1_5_OLD_OFFLINE;
+			}
+		}
+		if(foundWithin(offlineDownloadData.indexOf(StringUtils.reverse(">eltit/<8.1 XtfarcrelgaE>eltit<\n>/ \"8.8.1 ,8.1 ,tfarcenim ,xtfarcrelgae ,tfarcrelgae\"=tnetnoc \"sdrowyek\"=eman atem<\n>/ \"enilffO 8.1 XtfarcrelgaE\"=tnetnoc \"noitpircsed\"=eman atem<")), 32, 2048)) {
+			logger.info("Detected format: EAGLERCRAFTX_1_8_OFFLINE (maybe)");
+			return EnumOfflineParseType.EAGLERCRAFTX_1_8_OFFLINE;
+		}
+		if(foundWithin(offlineDownloadData.indexOf(StringUtils.reverse(">eltit/<3.7.1 ateB>eltit<")), 8, 512)) {
+			logger.info("Detected format: PEYTONPLAYZ585_ALPHA_BETA (maybe)");
+			return EnumOfflineParseType.PEYTONPLAYZ585_ALPHA_BETA;
+		}
+		if(foundWithin(offlineDownloadData.indexOf(StringUtils.reverse(">eltit/<6.2.1v ahplA>eltit<")), 8, 512)) {
+			logger.info("Detected format: PEYTONPLAYZ585_ALPHA_BETA (maybe)");
+			return EnumOfflineParseType.PEYTONPLAYZ585_ALPHA_BETA;
+		}
+		if(foundWithin(offlineDownloadData.indexOf(StringUtils.reverse(">eltit/<vednI tfarceniM>eltit<")), 8, 512)) {
+			logger.info("Detected format: PEYTONPLAYZ585_INDEV (maybe)");
+			return EnumOfflineParseType.PEYTONPLAYZ585_INDEV;
+		}
+		return null;
+	}
+
+	private static boolean foundWithin(int idx, int min, int max) {
+		return idx >= min && idx < max;
+	}
+
+	public static class ParsedOfflineAdapter {
+
+		public final EnumOfflineParseType parseType;
+		public final LaunchConfigEntry launchData;
+		public final ClientDataEntry clientData;
+		public final Map<EaglercraftUUID, byte[]> blobs;
+
+		public ParsedOfflineAdapter(EnumOfflineParseType parseType, ClientDataEntry clientData,
+				Map<EaglercraftUUID, byte[]> blobs) {
+			this.parseType = parseType;
+			this.launchData = null;
+			this.clientData = clientData;
+			this.blobs = blobs;
+		}
+
+		public ParsedOfflineAdapter(LaunchConfigEntry launchData, ClientDataEntry clientData,
+				Map<EaglercraftUUID, byte[]> blobs) {
+			this.parseType = EnumOfflineParseType.inferFromClientFormat(launchData.type);
+			this.launchData = launchData;
+			this.clientData = clientData;
+			this.blobs = blobs;
+		}
+
+	}
+
+	public static List<ParsedOfflineAdapter> parseOffline(EnumOfflineParseType parseType, String offlineDownloadData) {
+		if(parseType == null) {
+			parseType = detectOfflineType(offlineDownloadData);
+			if(parseType == null) {
+				throw new IllegalArgumentException("Could not automatically detect offline download type!");
+			}
+		}
+		switch(parseType) {
+		case EAGLERCRAFTX_1_8_OFFLINE:
+			return parseOfflineEaglerX18(offlineDownloadData);
+		case EAGLERCRAFTX_1_8_SIGNED:
+			return parseOfflineEaglerX18Signed(offlineDownloadData);
+		case EAGLERCRAFTX_1_8_FAT_OFFLINE:
+			return parseOfflineEaglerX18Fat(offlineDownloadData);
+		case EAGLERCRAFTX_1_8_FAT_SIGNED:
+			return parseOfflineEaglerX18FatSigned(offlineDownloadData);
+		case EAGLERCRAFT_1_5_NEW_OFFLINE:
+			return parseOfflineEagler15New(offlineDownloadData);
+		case EAGLERCRAFT_1_5_OLD_OFFLINE:
+			return parseOfflineEagler15Old(offlineDownloadData);
+		case EAGLERCRAFT_BETA_B1_3_OFFLINE:
+			return parseOfflineEaglerB13(offlineDownloadData);
+		case PEYTONPLAYZ585_ALPHA_BETA:
+			return parseOfflinePeytonAlphaBeta(offlineDownloadData);
+		case PEYTONPLAYZ585_INDEV:
+			return parseOfflinePeytonIndev(offlineDownloadData);
+		case EXPORTED_STANDARD_OFFLINE:
+			return parseStandardOffline(offlineDownloadData);
+		default:
+			throw new UnsupportedOperationException();
+		}
+	}
+
+	public static class TagIsolator {
+
+		protected final String openTag;
+		protected final String closeTag;
+		protected final String str;
+		protected int currentIndex = 0;
+		
+		public TagIsolator(String openTag, String closeTag, String str) {
+			this.openTag = openTag;
+			this.closeTag = closeTag;
+			this.str = str;
+		}
+		
+		public String nextScript() {
+			if(currentIndex != -1) {
+				currentIndex = str.indexOf(openTag, currentIndex);
+				if(currentIndex == -1) {
+					return null;
+				}
+				currentIndex += openTag.length();
+				int i2 = str.indexOf(closeTag, currentIndex);
+				if(i2 == -1) {
+					currentIndex = -1;
+					return null;
+				}
+				String ret = str.substring(currentIndex, i2);
+				currentIndex = i2 + closeTag.length();
+				return ret;
+			}else {
+				return null;
+			}
+		}
+		
+		public List<String> getAllTags() {
+			List<String> ret = new ArrayList<>();
+			String str;
+			while((str = nextScript()) != null) {
+				ret.add(str);
+			}
+			return ret;
+		}
+		
+	}
+
+	private static LaunchConfigEntry tryReadParseHint(EnumOfflineParseType expectedType, String offlineDownloadData) {
+		int hintIndex = offlineDownloadData.indexOf(StringUtils.reverse(">\"tniHesraPenilffOtfarcrelgae\"=epyt elyts<"));
+		if(hintIndex != -1) {
+			hintIndex += 42;
+			int closeTagIndex = offlineDownloadData.indexOf(StringUtils.reverse(">elyts/<"), hintIndex);
+			if(closeTagIndex != -1) {
+				try {
+					JSONObject parseHint = new JSONObject(offlineDownloadData.substring(hintIndex, closeTagIndex));
+					EnumOfflineParseType realType = EnumOfflineParseType.valueOf(parseHint.getString("type"));
+					if(realType != expectedType) {
+						throw new IllegalStateException("The offline download type is not \"" + expectedType + "\", metadata says it is \"" + realType + "\"!");
+					}
+					JSONObject launchConf = parseHint.getJSONObject("launchConf");
+					EaglercraftUUID theUUID = EaglercraftUUID.fromString(launchConf.getString("uuid"));
+					return new LaunchConfigEntry(theUUID, launchConf);
+				}catch(JSONException | IllegalArgumentException ex) {
+					logger.error("This offline download has a parse hint section, but the JSON is corrupt!");
+					logger.error(ex);
+				}
+			}
+		}
+		return null;
+	}
+
+	private static List<ParsedOfflineAdapter> parseOfflineEaglerX18(String offlineDownloadData) {
+		logger.info("Attempting to parse as: EAGLERCRAFTX_1_8_OFFLINE");
+		return parseOfflineEaglerX18(EnumOfflineParseType.EAGLERCRAFTX_1_8_OFFLINE, offlineDownloadData);
+	}
+
+	private static List<ParsedOfflineAdapter> parseOfflineEaglerX18(EnumOfflineParseType expectedType, String offlineDownloadData) {
+		LaunchConfigEntry launchConf = null;
+		try {
+			launchConf = tryReadParseHint(expectedType, offlineDownloadData);
+		}catch(IllegalStateException ex) {
+			logger.error(ex.getMessage());
+			return null;
+		}
+		List<String> scripts = (new TagIsolator(StringUtils.reverse(">\"tpircsavaj/txet\"=epyt tpircs<"), StringUtils.reverse(">tpircs/<"), offlineDownloadData)).getAllTags();
+		if(scripts.size() == 1) {
+			logger.info("Detected a single script tag, must be u19 or earlier");
+			return parseOfflineEaglerX18PreU20(launchConf, scripts.get(0));
+		}
+		byte[] classesJSSrc = null;
+		int classesTagIndex = -1;
+		for(int i = 0, l = scripts.size(); i < l; ++i) {
+			String script = scripts.get(i);
+			int j;
+			if(foundWithin(j = script.indexOf(StringUtils.reverse("\n;tpircStnerruc.tnemucod = tnemelEtpircStneilCXtfarcrelgae.wodniw )\"denifednu\" ==! wodniw foepyt(fi")), 0, 32)) {
+				classesJSSrc = ("\"use strict\";\n" + script.substring(j + 99).trim()).getBytes(StandardCharsets.UTF_8);
+				classesTagIndex = i;
+				break;
+			}
+		}
+		if(classesJSSrc == null) {
+			logger.error("Could not find script tag for classes.js!");
+			return null;
+		}
+		EaglercraftUUID classesJSUUID = EaglercraftUUID.nameUUIDFromBytes(classesJSSrc);
+		Map<EaglercraftUUID, byte[]> blobs = new HashMap<>();
+		List<EPKDataEntry> epks = new ArrayList<>(2);
+		blobs.put(classesJSUUID, classesJSSrc);
+		for(int i = 0, l = scripts.size(); i < l; ++i) {
+			if(i == classesTagIndex) {
+				continue;
+			}
+			String script = scripts.get(i);
+			int j;
+			if(foundWithin(j = script.indexOf(StringUtils.reverse(",46esab;maerts-tetco/noitacilppa:atad\" :lru { [ = IRUstessa.stpOXtfarcrelgae.wodniw")), 0, 512)) {
+				int assetsEPKStart = j + 36;
+				int assetsEPKEnd = script.indexOf("];", assetsEPKStart);
+				if(assetsEPKEnd == -1) {
+					logger.error("Could not find where assets.epk ends!");
+					return null;
+				}
+				assetsEPKEnd += 1;
+				String assetsEPKs = script.substring(assetsEPKStart, assetsEPKEnd);
+				assetsEPKs = assetsEPKs.replace("url:", "\"url\":");
+				assetsEPKs = assetsEPKs.replace("path:", "\"path\":");
+				try {
+					JSONArray epksJSON = new JSONArray(assetsEPKs);
+					for(int ii = 0, ll = epksJSON.length(); ii < ll; ++ii) {
+						JSONObject obj = epksJSON.getJSONObject(ii);
+						String path = obj.optString("path", "");
+						String url = obj.getString("url");
+						if(!url.startsWith("data:application/octet-stream;base64,")) {
+							logger.error("assetsURI is not base64!");
+							return null;
+						}
+						byte[] binary = Base64.decodeBase64(url.substring(37));
+						EaglercraftUUID assetsEPKUUID = EaglercraftUUID.nameUUIDFromBytes(binary);
+						blobs.put(assetsEPKUUID, binary);
+						epks.add(new EPKDataEntry(path, assetsEPKUUID));
+					}
+				}catch(JSONException | IllegalStateException | IllegalArgumentException ex) {
+					logger.error("assetsURI is not valid json!");
+					return null;
+				}
+			}else if(foundWithin(j = script.indexOf(StringUtils.reverse(",46esab;maerts-tetco/noitacilppa:atad\" = IRUstessa.stpOXtfarcrelgae.wodniw")), 0, 512)) {
+				int assetsEPKStart = j + 74;
+				int assetsEPKEnd = script.indexOf("\";", assetsEPKStart);
+				if(assetsEPKEnd == -1) {
+					logger.error("Could not find where assets.epk ends!");
+					return null;
+				}
+				byte[] assetsEPK;
+				try {
+					assetsEPK = Base64.decodeBase64(script.substring(assetsEPKStart, assetsEPKEnd));
+				}catch(IllegalArgumentException | IllegalStateException ex) {
+					logger.error("assets.epk is not valid base64!");
+					return null;
+				}
+				EaglercraftUUID assetsEPKUUID = EaglercraftUUID.nameUUIDFromBytes(assetsEPK);
+				blobs.put(assetsEPKUUID, assetsEPK);
+				epks.add(new EPKDataEntry("", assetsEPKUUID));
+			}
+		}
+		logger.info("Successfully loaded classes.js {} and assets.epk {}", classesJSUUID, String.join(", ", Lists.transform(epks, (e) -> e.dataUUID.toString())));
+		if(launchConf == null) {
+			return Arrays.asList(new ParsedOfflineAdapter(EnumOfflineParseType.EAGLERCRAFTX_1_8_OFFLINE,
+					new ClientDataEntry(EnumClientFormatType.EAGLER_STANDARD_OFFLINE, EaglercraftUUID.randomUUID(),
+							classesJSUUID, null, null, epks), blobs));
+		}else {
+			return Arrays.asList(new ParsedOfflineAdapter(launchConf,
+					new ClientDataEntry(EnumClientFormatType.EAGLER_STANDARD_OFFLINE, EaglercraftUUID.randomUUID(),
+							classesJSUUID, null, null, epks), blobs));
+		}
+	}
+
+	private static List<ParsedOfflineAdapter> parseOfflineEaglerX18PreU20(LaunchConfigEntry launchConf, String script) {
+		int classesJSStart = script.indexOf(StringUtils.reverse(";dees_tr$=x rav{)(dItxen_tr$ noitcnuf;2424353642=dees_tr$ rav\n{)(noitcnuf(;niam rav"));
+		if(classesJSStart == -1 || classesJSStart > 32767) {
+			logger.error("Could not find where classes.js begins!");
+			return null;
+		}
+		boolean isInternational = false;
+		int classesJSEnd = script.indexOf(StringUtils.reverse(",46esab;maerts-tetco/noitacilppa:atad\" = IRUstessa.stpOXtfarcrelgae.wodniw"));
+		if(classesJSEnd == -1) {
+			classesJSEnd = script.indexOf(StringUtils.reverse(",46esab;maerts-tetco/noitacilppa:atad\" :lru { [ = IRUstessa.stpOXtfarcrelgae.wodniw"));
+			if(classesJSEnd == -1) {
+				logger.error("Could not find where classes.js ends!");
+				return null;
+			}else {
+				isInternational = true;
+			}
+		}
+		byte[] classesJSSrc = script.substring(classesJSStart, classesJSEnd).trim().getBytes(StandardCharsets.UTF_8);
+		EaglercraftUUID classesJSUUID = EaglercraftUUID.nameUUIDFromBytes(classesJSSrc);
+		Map<EaglercraftUUID, byte[]> blobs = new HashMap<>();
+		List<EPKDataEntry> epks = new ArrayList<>(2);
+		blobs.put(classesJSUUID, classesJSSrc);
+		if(isInternational) {
+			int assetsEPKStart = classesJSEnd + 36;
+			int assetsEPKEnd = script.indexOf("];", assetsEPKStart);
+			if(assetsEPKEnd == -1) {
+				logger.error("Could not find where assets.epk ends!");
+				return null;
+			}
+			assetsEPKEnd += 1;
+			String assetsEPKs = script.substring(assetsEPKStart, assetsEPKEnd);
+			assetsEPKs = assetsEPKs.replace("url:", "\"url\":");
+			assetsEPKs = assetsEPKs.replace("path:", "\"path\":");
+			try {
+				JSONArray epksJSON = new JSONArray(assetsEPKs);
+				for(int i = 0, l = epksJSON.length(); i < l; ++i) {
+					JSONObject obj = epksJSON.getJSONObject(i);
+					String path = obj.optString("path", "");
+					String url = obj.getString("url");
+					if(!url.startsWith("data:application/octet-stream;base64,")) {
+						logger.error("assetsURI is not base64!");
+						return null;
+					}
+					byte[] binary = Base64.decodeBase64(url.substring(37));
+					EaglercraftUUID assetsEPKUUID = EaglercraftUUID.nameUUIDFromBytes(binary);
+					blobs.put(assetsEPKUUID, binary);
+					epks.add(new EPKDataEntry(path, assetsEPKUUID));
+				}
+			}catch(JSONException | IllegalStateException | IllegalArgumentException ex) {
+				logger.error("assetsURI is not valid json!");
+				return null;
+			}
+		}else {
+			int assetsEPKStart = classesJSEnd + 74;
+			int assetsEPKEnd = script.indexOf("\";", assetsEPKStart);
+			if(assetsEPKEnd == -1) {
+				logger.error("Could not find where assets.epk ends!");
+				return null;
+			}
+			byte[] assetsEPK;
+			try {
+				assetsEPK = Base64.decodeBase64(script.substring(assetsEPKStart, assetsEPKEnd));
+			}catch(IllegalArgumentException | IllegalStateException ex) {
+				logger.error("assets.epk is not valid base64!");
+				return null;
+			}
+			EaglercraftUUID assetsEPKUUID = EaglercraftUUID.nameUUIDFromBytes(assetsEPK);
+			blobs.put(assetsEPKUUID, assetsEPK);
+			epks.add(new EPKDataEntry("", assetsEPKUUID));
+		}
+		logger.info("Successfully loaded classes.js {} and assets.epk {}", classesJSUUID, String.join(", ", Lists.transform(epks, (e) -> e.dataUUID.toString())));
+		if(launchConf == null) {
+			return Arrays.asList(new ParsedOfflineAdapter(EnumOfflineParseType.EAGLERCRAFTX_1_8_OFFLINE,
+					new ClientDataEntry(EnumClientFormatType.EAGLER_STANDARD_OFFLINE, EaglercraftUUID.randomUUID(),
+							classesJSUUID, null, null, epks), blobs));
+		}else {
+			return Arrays.asList(new ParsedOfflineAdapter(launchConf,
+					new ClientDataEntry(EnumClientFormatType.EAGLER_STANDARD_OFFLINE, EaglercraftUUID.randomUUID(),
+							classesJSUUID, null, null, epks), blobs));
+		}
+	}
+
+	private static List<ParsedOfflineAdapter> parseOfflineEaglerX18Signed(String offlineDownloadData) {
+		logger.info("Attempting to parse as: EAGLERCRAFTX_1_8_SIGNED");
+		return parseOfflineEaglerX18Signed(EnumOfflineParseType.EAGLERCRAFTX_1_8_SIGNED, offlineDownloadData);
+	}
+
+	private static List<ParsedOfflineAdapter> parseOfflineEaglerX18Signed(EnumOfflineParseType expectType, String offlineDownloadData) {
+		LaunchConfigEntry launchConf = null;
+		try {
+			launchConf = tryReadParseHint(expectType, offlineDownloadData);
+		}catch(IllegalStateException ex) {
+			logger.error(ex.getMessage());
+			return null;
+		}
+		int signatureStart = offlineDownloadData.indexOf(StringUtils.reverse(",46esab;maerts-tetco/noitacilppa:atad>\"erutangiStneilCXtfarcrelgae\"=di \"tfarcrelgae\"=epyt elyts<"));
+		boolean isPreU24 = false;
+		if(signatureStart == -1) {
+			signatureStart = offlineDownloadData.indexOf(StringUtils.reverse(",46esab;maerts-tetco/noitacilppa:atad\" = erutangiStneilCXtfarcrelgae.wodniw"));
+			if(signatureStart == -1) {
+				logger.error("Could not find client signature!");
+				return null;
+			}
+			isPreU24 = true;
+			signatureStart += 75;
+			logger.info("Client is a pre-u24 signed offline");
+		}else {
+			signatureStart += 96;
+		}
+		Map<EaglercraftUUID, byte[]> blobs = new HashMap<>();
+		EaglercraftUUID signatureUUID;
+		EaglercraftUUID payloadUUID;
+		if(!isPreU24) {
+			int signatureEnd = offlineDownloadData.indexOf(StringUtils.reverse(">elyts/<"), signatureStart);
+			if(signatureEnd == -1) {
+				logger.error("Could not find end of client signature!");
+				return null;
+			}
+			byte[] signature;
+			try {
+				signature = Base64.decodeBase64(offlineDownloadData.substring(signatureStart, signatureEnd));
+			}catch(IllegalArgumentException | IllegalStateException ex) {
+				logger.error("Client signature is not valid base64!");
+				return null;
+			}
+			int bundleStart = offlineDownloadData.indexOf(StringUtils.reverse(",46esab;maerts-tetco/noitacilppa:atad>\"eldnuBtneilCXtfarcrelgae\"=di \"tfarcrelgae\"=epyt elyts<"), signatureStart);
+			if(bundleStart == -1) {
+				logger.error("Could not find client payload!");
+				return null;
+			}
+			bundleStart += 93;
+			int bundleEnd = offlineDownloadData.indexOf(StringUtils.reverse(">elyts/<"), bundleStart);
+			if(bundleEnd == -1) {
+				logger.error("Could not find end of client payload!");
+				return null;
+			}
+			byte[] payload;
+			try {
+				payload = Base64.decodeBase64(offlineDownloadData.substring(bundleStart, bundleEnd));
+			}catch(IllegalArgumentException | IllegalStateException ex) {
+				logger.error("Client payload is not valid base64!");
+				return null;
+			}
+			signatureUUID = EaglercraftUUID.nameUUIDFromBytes(signature);
+			blobs.put(signatureUUID, signature);
+			payloadUUID = EaglercraftUUID.nameUUIDFromBytes(payload);
+			blobs.put(payloadUUID, payload);
+		}else {
+			int signatureEnd = offlineDownloadData.indexOf(StringUtils.reverse(";\""), signatureStart);
+			if(signatureEnd == -1) {
+				logger.error("Could not find end of client signature!");
+				return null;
+			}
+			byte[] signature;
+			try {
+				signature = Base64.decodeBase64(offlineDownloadData.substring(signatureStart, signatureEnd));
+			}catch(IllegalArgumentException | IllegalStateException ex) {
+				logger.error("Client signature is not valid base64!");
+				return null;
+			}
+			int bundleStart = offlineDownloadData.indexOf(StringUtils.reverse(",46esab;maerts-tetco/noitacilppa:atad\" = eldnuBtneilCXtfarcrelgae.wodniw"), signatureStart);
+			if(bundleStart == -1) {
+				logger.error("Could not find client payload!");
+				return null;
+			}
+			bundleStart += 72;
+			int bundleEnd = offlineDownloadData.indexOf(StringUtils.reverse(";\""), bundleStart);
+			if(bundleEnd == -1) {
+				logger.error("Could not find end of client payload!");
+				return null;
+			}
+			byte[] payload;
+			try {
+				payload = Base64.decodeBase64(offlineDownloadData.substring(bundleStart, bundleEnd));
+			}catch(IllegalArgumentException | IllegalStateException ex) {
+				logger.error("Client payload is not valid base64!");
+				return null;
+			}
+			signatureUUID = EaglercraftUUID.nameUUIDFromBytes(signature);
+			blobs.put(signatureUUID, signature);
+			payloadUUID = EaglercraftUUID.nameUUIDFromBytes(payload);
+			blobs.put(payloadUUID, payload);
+		}
+		logger.info("Successfully loaded signature {} and payload {}", signatureUUID, payloadUUID);
+		if(launchConf == null) {
+			return Arrays.asList(new ParsedOfflineAdapter(EnumOfflineParseType.EAGLERCRAFTX_1_8_SIGNED,
+					new ClientDataEntry(EnumClientFormatType.EAGLER_SIGNED_OFFLINE, EaglercraftUUID.randomUUID(),
+							payloadUUID, null, signatureUUID, null), blobs));
+		}else {
+			return Arrays.asList(new ParsedOfflineAdapter(launchConf,
+					new ClientDataEntry(EnumClientFormatType.EAGLER_SIGNED_OFFLINE, EaglercraftUUID.randomUUID(),
+							payloadUUID, null, signatureUUID, null), blobs));
+		}
+	}
+
+	private static List<ParsedOfflineAdapter> parseOfflineEaglerX18Fat(String offlineDownloadData) {
+		logger.info("Attempting to parse as: EAGLERCRAFTX_1_8_FAT_OFFLINE");
+		List<ParsedOfflineAdapter> lst = parseOfflineEaglerX18(EnumOfflineParseType.EAGLERCRAFTX_1_8_FAT_OFFLINE, offlineDownloadData);
+		if(lst == null || lst.size() != 1) {
+			logger.error("Fat client type is not EAGLERCRAFTX_1_8_FAT_OFFLINE");
+			return null;
+		}
+		List<ParsedOfflineAdapter> lst2 = parseOfflineEaglerX18FatEmbeddedClients(lst.get(0), offlineDownloadData);
+		if(lst2 == null) {
+			logger.error("Could not parse embedded clients!");
+			return null;
+		}
+		return lst2;
+	}
+
+	private static List<ParsedOfflineAdapter> parseOfflineEaglerX18FatSigned(String offlineDownloadData) {
+		logger.info("Attempting to parse as: EAGLERCRAFTX_1_8_FAT_SIGNED");
+		List<ParsedOfflineAdapter> lst = parseOfflineEaglerX18Signed(EnumOfflineParseType.EAGLERCRAFTX_1_8_FAT_SIGNED, offlineDownloadData);
+		if(lst == null || lst.size() != 1) {
+			logger.error("Fat client type is not EAGLERCRAFTX_1_8_FAT_OFFLINE");
+			return null;
+		}
+		List<ParsedOfflineAdapter> lst2 = parseOfflineEaglerX18FatEmbeddedClients(lst.get(0), offlineDownloadData);
+		if(lst2 == null) {
+			logger.error("Could not parse embedded clients!");
+			return null;
+		}
+		return lst2;
+	}
+
+	private static List<ParsedOfflineAdapter> parseOfflineEaglerX18FatEmbeddedClients(ParsedOfflineAdapter parentClient, String offlineDownloadData) {
+		logger.info("Attempting to parse embedded clients");
+		String magicStart = StringUtils.reverse("_enilffOtaFrelgae_\"=di \"tfarcrelgae\"=epyt elyts<");
+		String magicEnd = StringUtils.reverse("\n>elyts/<");
+		Map<String,String> fatClientData = new HashMap<>();
+		int i = 0, j, k, l;
+		for(;;) {
+			if((i = offlineDownloadData.indexOf(magicStart, i)) == -1) {
+				break;
+			}
+			i += 48;
+			if((j = offlineDownloadData.indexOf("\">", i)) == -1 && j - i < 64) {
+				break;
+			}
+			String name = offlineDownloadData.substring(i, j);
+			if((k = offlineDownloadData.indexOf(magicEnd, j + 2)) == -1) {
+				break;
+			}
+			fatClientData.put(name, offlineDownloadData.substring(j + 2, k));
+		}
+		String manifest = fatClientData.get("manifest_v1");
+		if(manifest == null) {
+			logger.error("Could not find manifest tag!");
+		}
+		Map<EaglercraftUUID,ClientDataEntry> clientDatas;
+		List<LaunchConfigEntry> launchDatas;
+		try {
+			JSONObject obj = new JSONObject(manifest);
+			JSONArray manifestClientDatas = obj.getJSONArray("clientData");
+			int n = manifestClientDatas.length();
+			clientDatas = new HashMap<>(n + 1);
+			clientDatas.put(BootMenuConstants.UUID_CLIENT_DATA_ORIGIN, parentClient.clientData.rotateUUID(BootMenuConstants.UUID_CLIENT_DATA_ORIGIN));
+			for(l = 0; l < n; ++l) {
+				JSONObject obj2 = manifestClientDatas.getJSONObject(l);
+				EaglercraftUUID theUUID = EaglercraftUUID.fromString(obj2.getString("uuid"));
+				clientDatas.put(theUUID, new ClientDataEntry(theUUID, obj2));
+			}
+			JSONArray manifestLaunchDatas = obj.getJSONArray("launchData");
+			n = manifestLaunchDatas.length();
+			launchDatas = new ArrayList<>(n + 1);
+			launchDatas.add(parentClient.launchData.rotateUUIDs(BootMenuConstants.UUID_CLIENT_LAUNCH_ORIGIN, BootMenuConstants.UUID_CLIENT_DATA_ORIGIN));
+			for(l = 0; l < n; ++l) {
+				JSONObject obj2 = manifestLaunchDatas.getJSONObject(l);
+				EaglercraftUUID theUUID = EaglercraftUUID.fromString(obj2.getString("uuid"));
+				launchDatas.add(new LaunchConfigEntry(theUUID, obj2));
+			}
+			
+		}catch(JSONException ex) {
+			logger.error("The manifest JSON is corrupt!");
+			logger.error(ex);
+			return null;
+		}
+		Map<EaglercraftUUID, byte[]> blobs = new HashMap<>();
+		Iterator<ClientDataEntry> itr = clientDatas.values().iterator();
+		loadClientDatas: while(itr.hasNext()) {
+			ClientDataEntry etr = itr.next();
+			for(EaglercraftUUID uuid : etr.getReferencedBlobs()) {
+				if(!blobs.containsKey(uuid)) {
+					String str = fatClientData.get(uuid.toString());
+					if(str == null) {
+						logger.error("Blob UUID {} for client data {} is missing!", uuid, etr.uuid);
+						itr.remove();
+						continue loadClientDatas;
+					}
+					byte[] blobBytes;
+					try {
+						blobBytes = Base64.decodeBase64(str);
+					}catch(IllegalArgumentException | IllegalStateException ex) {
+						logger.error("Blob UUID {} for client data {} is invalid base64!", uuid, etr.uuid);
+						itr.remove();
+						continue loadClientDatas;
+					}
+					if(!EaglercraftUUID.nameUUIDFromBytes(blobBytes).equals(uuid)) {
+						logger.error("Blob UUID {} for client data {} has an invalid checksum!", uuid, etr.uuid);
+						itr.remove();
+						continue loadClientDatas;
+					}
+					blobs.put(uuid, blobBytes);
+				}
+			}
+		}
+		List<ParsedOfflineAdapter> list = new ArrayList<>(launchDatas.size());
+		for(LaunchConfigEntry etr : launchDatas) {
+			EaglercraftUUID clientDataUUID = etr.clientDataUUID;
+			if(clientDataUUID.equals(BootMenuConstants.UUID_CLIENT_DATA_ORIGIN)) {
+				list.add(new ParsedOfflineAdapter(etr, parentClient.clientData, parentClient.blobs));
+			}else {
+				ClientDataEntry clientData = clientDatas.get(clientDataUUID);
+				if(clientData == null) {
+					logger.error("Client data UUID {} for launch data {} is missing!", clientDataUUID, etr.uuid);
+					continue;
+				}
+				Map<EaglercraftUUID, byte[]> entryBlob = new HashMap<>();
+				for(EaglercraftUUID uuid : clientData.getReferencedBlobs()) {
+					entryBlob.put(uuid, blobs.get(uuid));
+				}
+				list.add(new ParsedOfflineAdapter(etr, clientData, entryBlob));
+			}
+		}
+		logger.info("Loaded {} blobs from fat offline", blobs.size());
+		logger.info("Loaded {} client configurations from fat offline", clientDatas.size());
+		logger.info("Loaded {} launch configurations from fat offline", launchDatas.size());
+		return list;
+	}
+
+	private static List<ParsedOfflineAdapter> parseOfflineEagler15New(String offlineDownloadData) {
+		logger.info("Attempting to parse as: EAGLERCRAFTX_1_5_NEW_OFFLINE");
+		LaunchConfigEntry launchConf = null;
+		try {
+			launchConf = tryReadParseHint(EnumOfflineParseType.EAGLERCRAFT_1_5_NEW_OFFLINE, offlineDownloadData);
+		}catch(IllegalStateException ex) {
+			logger.error(ex.getMessage());
+			return null;
+		}
+		byte[] assetsEPK = null;
+		byte[] classesJS = null;
+		List<String> scripts = (new TagIsolator(StringUtils.reverse(">\"tpircsavaj/txet\"=epyt tpircs<"), StringUtils.reverse(">tpircs/<"), offlineDownloadData)).getAllTags();
+		for(String str : scripts) {
+			if(str.length() > 262144) {
+				int i = -1;
+				int j = -1;
+				i = str.indexOf(StringUtils.reverse(",46esab;maerts-tetco/noitacilppa:atad\" nruter\t\n{ )(IRUstessAteg noitcnuf"));
+				if(i == -1 || i >= 1024) {
+					i = str.indexOf(StringUtils.reverse(",46esab;maerts-tetco/noitacilppa:atad\" nruter\n{ )(IRUstessAteg noitcnuf"));
+					if(i != -1 && i < 1024) {
+						i += 71;
+					}else {
+						i = -1;
+					}
+				}else {
+					i += 72;
+				}
+				if(i != -1) {
+					j = str.indexOf("\";", i);
+					if(j != -1) {
+						if(assetsEPK == null) {
+							try {
+								assetsEPK = Base64.decodeBase64(str.substring(i, j));
+							}catch(IllegalStateException | IllegalArgumentException ex) {
+							}
+						}
+						if(assetsEPK != null) {
+							continue;
+						}
+					}else {
+						j = -1;
+					}
+				}
+				i = -1;
+				j = -1;
+				if(foundWithin(str.indexOf(StringUtils.reverse("{ )le(IRUrekroWetaerc noitcnuf")), 0, 512)) {
+					continue;
+				}
+				if(foundWithin(str.indexOf(StringUtils.reverse(";)0001 ,} ;\")4 ni hcnual lliw emaG(\" = txeTrenni.c {)(noitcnuf(tuoemiTtes")), 0, 512)) {
+					continue;
+				}
+				if(foundWithin(str.indexOf(StringUtils.reverse("{ )(noitcnuf ,\"daol\"(renetsiLtnevEdda.wodniw")), 0, 512)) {
+					continue;
+				}
+				if(classesJS == null) {
+					classesJS = str.trim().getBytes(StandardCharsets.UTF_8);
+				}
+				if(assetsEPK != null && classesJS != null) {
+					break;
+				}
+			}
+		}
+		if(classesJS == null) {
+			logger.error("Could not find classes.js!");
+			return null;
+		}
+		if(assetsEPK == null) {
+			logger.error("Could not find assets.epk!");
+			return null;
+		}
+		int workerIdx = offlineDownloadData.indexOf(StringUtils.reverse(">\"rekrow_ps\"=di \"rekrowrelgae/txet\"=epyt tpircs<"));
+		if(workerIdx == -1) {
+			logger.error("Could not find start of integrated server!");
+			return null;
+		}else {
+			workerIdx += 48;
+		}
+		int workerIdxEnd = offlineDownloadData.indexOf(StringUtils.reverse(">tpircs/<"), workerIdx);
+		if(workerIdxEnd == -1) {
+			logger.error("Could not find end of integrated server!");
+			return null;
+		}
+		byte[] classesServerJS = offlineDownloadData.substring(workerIdx, workerIdxEnd).trim().getBytes(StandardCharsets.UTF_8);
+		Map<EaglercraftUUID, byte[]> blobs = new HashMap<>();
+		EaglercraftUUID classesJSUUID = EaglercraftUUID.nameUUIDFromBytes(classesJS);
+		blobs.put(classesJSUUID, classesJS);
+		EaglercraftUUID assetsEPKUUID = EaglercraftUUID.nameUUIDFromBytes(assetsEPK);
+		blobs.put(assetsEPKUUID, assetsEPK);
+		EaglercraftUUID classesServerJSUUID = EaglercraftUUID.nameUUIDFromBytes(classesServerJS);
+		blobs.put(classesServerJSUUID, classesServerJS);
+		logger.info("Successfully loaded classes.js {}, classes_server.js {}, and assets.epk {}", classesJSUUID, classesServerJS, assetsEPKUUID);
+		if(launchConf == null) {
+			return Arrays.asList(new ParsedOfflineAdapter(EnumOfflineParseType.EAGLERCRAFT_1_5_NEW_OFFLINE,
+					new ClientDataEntry(EnumClientFormatType.EAGLER_STANDARD_1_5_OFFLINE, EaglercraftUUID.randomUUID(),
+							classesJSUUID, classesServerJSUUID, null, Arrays.asList(new EPKDataEntry("", assetsEPKUUID))), blobs));
+		}else {
+			return Arrays.asList(new ParsedOfflineAdapter(launchConf,
+					new ClientDataEntry(EnumClientFormatType.EAGLER_STANDARD_1_5_OFFLINE, EaglercraftUUID.randomUUID(),
+							classesJSUUID, classesServerJSUUID, null, Arrays.asList(new EPKDataEntry("", assetsEPKUUID))), blobs));
+		}
+	}
+
+	private static List<ParsedOfflineAdapter> parseOfflineEagler15Old(String offlineDownloadData) {
+		logger.info("Attempting to parse as: EAGLERCRAFTX_1_5_OLD_OFFLINE");
+		return parseOfflineEagler15OldImpl(EnumOfflineParseType.EAGLERCRAFT_1_5_OLD_OFFLINE, offlineDownloadData);
+	}
+
+	private static List<ParsedOfflineAdapter> parseOfflineEagler15OldImpl(EnumOfflineParseType parseType, String offlineDownloadData) {
+		LaunchConfigEntry launchConf = null;
+		try {
+			launchConf = tryReadParseHint(parseType, offlineDownloadData);
+		}catch(IllegalStateException ex) {
+			logger.error(ex.getMessage());
+			return null;
+		}
+		byte[] assetsEPK = null;
+		byte[] classesJS = null;
+		List<String> scripts = (new TagIsolator(StringUtils.reverse(">\"tpircsavaj/txet\"=epyt tpircs<"), StringUtils.reverse(">tpircs/<"), offlineDownloadData)).getAllTags();
+		for(String str : scripts) {
+			if(str.length() > 262144) {
+				if(foundWithin(str.indexOf(StringUtils.reverse("{ )le(IRUtessAetaerc noitcnuf")), 0, 512)) {
+					continue;
+				}
+				if(foundWithin(str.indexOf(StringUtils.reverse(";)0001 ,} ;\")4 ni hcnual lliw emaG(\" = txeTrenni.c {)(noitcnuf(tuoemiTtes")), 0, 512)) {
+					continue;
+				}
+				if(foundWithin(str.indexOf(StringUtils.reverse("{ )(noitcnuf ,\"daol\"(renetsiLtnevEdda.wodniw")), 0, 512)) {
+					continue;
+				}
+				if(assetsEPK == null) {
+					int i = str.indexOf(StringUtils.reverse(",46esab;maerts-tetco/noitacilppa:atad\" nruter\t\n{ )(IRUstessAteg noitcnuf"));
+					if(i == -1 || i >= 1024) {
+						i = str.indexOf(StringUtils.reverse(",46esab;maerts-tetco/noitacilppa:atad\" nruter\n{ )(IRUstessAteg noitcnuf"));
+						if(i != -1 && i < 1024) {
+							i += 71;
+						}else {
+							i = -1;
+						}
+					}else {
+						i += 72;
+					}
+					if(i != -1) {
+						int j = str.indexOf("\";", i);
+						if(j != -1) {
+							if(assetsEPK == null) {
+								try {
+									assetsEPK = Base64.decodeBase64(str.substring(i, j));
+								}catch(IllegalStateException | IllegalArgumentException ex) {
+								}
+							}
+							if(assetsEPK != null) {
+								continue;
+							}
+						}
+					}
+				}
+				if(classesJS == null) {
+					classesJS = str.trim().getBytes(StandardCharsets.UTF_8);
+				}
+				if(assetsEPK != null && classesJS != null) {
+					break;
+				}
+			}
+		}
+		if(classesJS == null) {
+			logger.error("Could not find classes.js!");
+			return null;
+		}
+		if(assetsEPK == null) {
+			int epkIdx = offlineDownloadData.indexOf(StringUtils.reverse(">\"stessa\"=di \";enon:yalpsid\"=elyts vid<"));
+			if(epkIdx == -1) {
+				logger.error("Could not find start of assets.epk!");
+				return null;
+			}else {
+				epkIdx += 39;
+			}
+			int epkIdxEnd = offlineDownloadData.indexOf(StringUtils.reverse(">vid/<"), epkIdx);
+			if(epkIdxEnd == -1) {
+				logger.error("Could not find end of assets.epk!");
+				return null;
+			}
+			try {
+				assetsEPK = Base64.decodeBase64(offlineDownloadData.substring(epkIdx, epkIdxEnd).trim());
+			}catch(IllegalStateException | IllegalArgumentException ex) {
+				logger.error("Could not base64 decode assets.epk!");
+				return null;
+			}
+		}
+		Map<EaglercraftUUID, byte[]> blobs = new HashMap<>();
+		EaglercraftUUID classesJSUUID = EaglercraftUUID.nameUUIDFromBytes(classesJS);
+		blobs.put(classesJSUUID, classesJS);
+		EaglercraftUUID assetsEPKUUID = EaglercraftUUID.nameUUIDFromBytes(assetsEPK);
+		blobs.put(assetsEPKUUID, assetsEPK);
+		logger.info("Successfully loaded classes.js {}, and assets.epk {}", classesJSUUID, assetsEPKUUID);
+		if(launchConf == null) {
+			return Arrays.asList(new ParsedOfflineAdapter(parseType,
+					new ClientDataEntry(EnumClientFormatType.EAGLER_STANDARD_OFFLINE, EaglercraftUUID.randomUUID(),
+							classesJSUUID, null, null, Arrays.asList(new EPKDataEntry("", assetsEPKUUID))), blobs));
+		}else {
+			return Arrays.asList(new ParsedOfflineAdapter(launchConf,
+					new ClientDataEntry(EnumClientFormatType.EAGLER_STANDARD_OFFLINE, EaglercraftUUID.randomUUID(),
+							classesJSUUID, null, null, Arrays.asList(new EPKDataEntry("", assetsEPKUUID))), blobs));
+		}
+	}
+
+	private static List<ParsedOfflineAdapter> parseOfflineEaglerB13(String offlineDownloadData) {
+		logger.info("Attempting to parse as: EAGLERCRAFT_BETA_B1_3_OFFLINE");
+		return parseOfflineEagler15OldImpl(EnumOfflineParseType.EAGLERCRAFT_BETA_B1_3_OFFLINE, offlineDownloadData);
+	}
+
+	private static List<ParsedOfflineAdapter> parseOfflinePeytonAlphaBeta(String offlineDownloadData) {
+		logger.info("Attempting to parse as: PEYTONPLAYZ585_ALPHA_BETA");
+		return parseOfflineEagler15OldImpl(EnumOfflineParseType.PEYTONPLAYZ585_ALPHA_BETA, offlineDownloadData);
+	}
+
+	private static List<ParsedOfflineAdapter> parseOfflinePeytonIndev(String offlineDownloadData) {
+		logger.info("Attempting to parse as: PEYTONPLAYZ585_INDEV");
+		return parseOfflineEagler15OldImpl(EnumOfflineParseType.PEYTONPLAYZ585_INDEV, offlineDownloadData);
+	}
+
+	private static List<ParsedOfflineAdapter> parseStandardOffline(String offlineDownloadData) {
+		LaunchConfigEntry launchConf;
+		int hintIndex = offlineDownloadData.indexOf(StringUtils.reverse(">\"tniHesraPenilffOtfarcrelgae\"=epyt elyts<"));
+		if(hintIndex != -1) {
+			hintIndex += 42;
+			int closeTagIndex = offlineDownloadData.indexOf(StringUtils.reverse(">elyts/<"), hintIndex);
+			if(closeTagIndex != -1) {
+				try {
+					JSONObject parseHint = new JSONObject(offlineDownloadData.substring(hintIndex, closeTagIndex));
+					EnumOfflineParseType typeEnum = EnumOfflineParseType.valueOf(parseHint.getString("type"));
+					if(typeEnum != EnumOfflineParseType.EXPORTED_STANDARD_OFFLINE) {
+						logger.error("This is not a \"EXPORTED_STANDARD_OFFLINE\" type offline!");
+						return null;
+					}
+					JSONObject launchConfJSON = parseHint.getJSONObject("launchConf");
+					EaglercraftUUID theUUID = EaglercraftUUID.fromString(launchConfJSON.getString("uuid"));
+					launchConf = new LaunchConfigEntry(theUUID, launchConfJSON);
+				}catch(JSONException | IllegalArgumentException ex) {
+					logger.error("This offline download has a parse hint section, but the JSON is corrupt!");
+					logger.error(ex);
+					return null;
+				}
+			}else {
+				logger.error("Could not find parse hint section!");
+				return null;
+			}
+		}else {
+			logger.error("Could not find parse hint section!");
+			return null;
+		}
+		List<String> scripts = (new TagIsolator(StringUtils.reverse(">\"tpircsavaj/txet\"=epyt tpircs<"), StringUtils.reverse(">tpircs/<"), offlineDownloadData)).getAllTags();
+		if(scripts.size() != 3) {
+			logger.error("Wrong number of script tags!");
+			return null;
+		}
+		byte[] classesJSSrc = OfflineDownloadFactory.removeClientScriptElement(scripts.get(1).getBytes(StandardCharsets.UTF_8), true);
+		EaglercraftUUID classesJSUUID = EaglercraftUUID.nameUUIDFromBytes(classesJSSrc);
+		Map<EaglercraftUUID, byte[]> blobs = new HashMap<>();
+		List<EPKDataEntry> epks = new ArrayList<>(2);
+		blobs.put(classesJSUUID, classesJSSrc);
+		String script = scripts.get(2);
+		int j;
+		if(foundWithin(j = script.indexOf(StringUtils.reverse("/*}:KPE_STESSA_NIGEB:{*/")), 0, 512)) {
+			int assetsEPKStart = j + 24;
+			int assetsEPKEnd = script.indexOf(StringUtils.reverse("/*}:KPE_STESSA_DNE:{*/"), assetsEPKStart);
+			if(assetsEPKEnd == -1) {
+				logger.error("Could not find where assets.epk ends!");
+				return null;
+			}
+			String assetsEPKs = script.substring(assetsEPKStart, assetsEPKEnd);
+			try {
+				JSONArray epksJSON = new JSONArray(assetsEPKs);
+				for(int ii = 0, ll = epksJSON.length(); ii < ll; ++ii) {
+					JSONObject obj = epksJSON.getJSONObject(ii);
+					String path = obj.optString("path", "");
+					String url = obj.getString("url");
+					if(!url.startsWith("data:application/octet-stream;base64,")) {
+						logger.error("assetsURI is not base64!");
+						return null;
+					}
+					byte[] binary = Base64.decodeBase64(url.substring(37));
+					EaglercraftUUID assetsEPKUUID = EaglercraftUUID.nameUUIDFromBytes(binary);
+					blobs.put(assetsEPKUUID, binary);
+					epks.add(new EPKDataEntry(path, assetsEPKUUID));
+				}
+			}catch(JSONException | IllegalStateException | IllegalArgumentException ex) {
+				logger.error("assetsURI is not valid json!");
+				return null;
+			}
+		}
+		logger.info("Successfully loaded classes.js {} and assets.epk {}", classesJSUUID, String.join(", ", Lists.transform(epks, (e) -> e.dataUUID.toString())));
+		return Arrays.asList(new ParsedOfflineAdapter(launchConf,
+				new ClientDataEntry(EnumClientFormatType.EAGLER_STANDARD_OFFLINE, EaglercraftUUID.randomUUID(),
+						classesJSUUID, null, null, epks), blobs));
+	}
+
+}
diff --git a/sources/teavm-boot-menu/java/net/lax1dude/eaglercraft/v1_8/boot_menu/teavm/RelayRandomizeHelper.java b/sources/teavm-boot-menu/java/net/lax1dude/eaglercraft/v1_8/boot_menu/teavm/RelayRandomizeHelper.java
new file mode 100644
index 00000000..5e24b6d1
--- /dev/null
+++ b/sources/teavm-boot-menu/java/net/lax1dude/eaglercraft/v1_8/boot_menu/teavm/RelayRandomizeHelper.java
@@ -0,0 +1,71 @@
+package net.lax1dude.eaglercraft.v1_8.boot_menu.teavm;
+
+import org.json.JSONArray;
+import org.json.JSONObject;
+
+import net.lax1dude.eaglercraft.v1_8.ThreadLocalRandom;
+
+/**
+ * Copyright (c) 2024 lax1dude. All Rights Reserved.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ * 
+ */
+public class RelayRandomizeHelper {
+
+	public static int countRelayMacro(String launchOpts) {
+		int i = 0;
+		while(launchOpts.contains("\"$random_relay_primary_" + i + "\"")) {
+			++i;
+		}
+		return i;
+	}
+
+	public static String replaceRelayMacroWithConstant(String launchOpts) {
+		int i = countRelayMacro(launchOpts);
+		if(i == 0) {
+			return launchOpts;
+		}
+		int randomRelay = ThreadLocalRandom.current().nextInt(i);
+		for(int j = 0; j < i; ++j) {
+			launchOpts = launchOpts.replace("\"$random_relay_primary_" + j + "\"", randomRelay == j ? "true" : "false");
+		}
+		return launchOpts;
+	}
+
+	public static String replaceRelayMacroWithEqRelayId(String launchOpts) {
+		int i = countRelayMacro(launchOpts);
+		if(i == 0) {
+			return launchOpts;
+		}
+		for(int j = 0; j < i; ++j) {
+			launchOpts = launchOpts.replace("\"$random_relay_primary_" + j + "\"", "relayId === " + j);
+		}
+		return launchOpts;
+	}
+
+	public static void makeOptsJSONHaveMacroHack(JSONObject optsDump) {
+		int i = 0;
+		JSONArray arr = optsDump.optJSONArray("relays");
+		if(arr != null) {
+			for(int j = 0, l = arr.length(); j < l; ++j) {
+				JSONObject relay = arr.optJSONObject(j);
+				if(relay != null) {
+					if(relay.has("primary")) {
+						relay.put("primary", "$random_relay_primary_" + i++);
+					}
+				}
+			}
+		}
+	}
+
+}
diff --git a/sources/teavm-boot-menu/java/net/lax1dude/eaglercraft/v1_8/boot_menu/teavm/SelectionListController.java b/sources/teavm-boot-menu/java/net/lax1dude/eaglercraft/v1_8/boot_menu/teavm/SelectionListController.java
new file mode 100644
index 00000000..c7ee279d
--- /dev/null
+++ b/sources/teavm-boot-menu/java/net/lax1dude/eaglercraft/v1_8/boot_menu/teavm/SelectionListController.java
@@ -0,0 +1,240 @@
+package net.lax1dude.eaglercraft.v1_8.boot_menu.teavm;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import org.teavm.jso.dom.html.HTMLElement;
+
+/**
+ * Copyright (c) 2024 lax1dude. All Rights Reserved.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ * 
+ */
+public abstract class SelectionListController<T extends SelectionListController.ListItem> {
+
+	public static interface ListItem {
+		
+		String getName();
+		
+		default boolean getEnabled() {
+			return true;
+		}
+		
+		default boolean getAlwaysSelected() {
+			return true;
+		}
+		
+	}
+
+	public static class ListItemEnum<E> implements ListItem {
+
+		protected final String displayName;
+		protected final boolean enabled;
+		protected final E itemEnum;
+
+		public ListItemEnum(String displayName, boolean enabled, E itemEnum) {
+			this.displayName = displayName;
+			this.enabled = enabled;
+			this.itemEnum = itemEnum;
+		}
+
+		public ListItemEnum(String displayName, E itemEnum) {
+			this.displayName = displayName;
+			this.enabled = true;
+			this.itemEnum = itemEnum;
+		}
+
+		@Override
+		public String getName() {
+			return displayName;
+		}
+
+		@Override
+		public boolean getEnabled() {
+			return enabled;
+		}
+
+		public E getEnum() {
+			return itemEnum;
+		}
+
+	}
+
+	protected static class ListItemInstance<E extends SelectionListController.ListItem> {
+		
+		protected final E listItem;
+		protected final HTMLElement element;
+		protected int index;
+		protected boolean userVal = false;
+		
+		protected ListItemInstance(E listItem, HTMLElement element, int index) {
+			this.listItem = listItem;
+			this.element = element;
+			this.index = index;
+		}
+		
+	}
+
+	protected final HTMLElement parent;
+	protected final List<T> selectionList;
+	protected final List<ListItemInstance<T>> selectionEnableList;
+	protected int currentSelected = -1;
+	protected boolean cursorEventsSuspended = false;
+
+	public SelectionListController(HTMLElement parent, List<T> selectionList) {
+		this.parent = parent;
+		this.selectionList = selectionList;
+		this.selectionEnableList = new ArrayList<>(selectionList.size());
+	}
+
+	public void setup() {
+		selectionEnableList.clear();
+		parent.setInnerHTML("");
+		currentSelected = -1;
+		for(int i = 0, l = selectionList.size(); i < l; ++i) {
+			T itm = selectionList.get(i);
+			HTMLElement el = BootMenuMain.doc.createElement("p");
+			el.setInnerText(itm.getName());
+			el.getClassList().add(BootMenuConstants.cssClassPrefixBootMenu + "content_item");
+			if(itm.getEnabled()) {
+				if(currentSelected == -1) {
+					currentSelected = 0;
+					el.getClassList().add(BootMenuConstants.cssClassPrefixBootMenu + "content_item_selected");
+				}
+				final int ii = selectionEnableList.size();
+				final ListItemInstance<T> newInstance = new ListItemInstance<T>(itm, el, ii);
+				el.addEventListener("mouseover", (evt) -> {
+					BootMenuMain.runLater(() -> {
+						if(!cursorEventsSuspended) {
+							setSelected(newInstance.index);
+						}
+					});
+				});
+				el.addEventListener("click", (evt) -> {
+					BootMenuMain.runLater(() -> {
+						if(!cursorEventsSuspended) {
+							itemSelectedLow(newInstance);
+						}
+					});
+				});
+				selectionEnableList.add(newInstance);
+			}else {
+				el.getClassList().add(BootMenuConstants.cssClassPrefixBootMenu + "content_item_disabled");
+			}
+			parent.appendChild(el);
+		}
+	}
+
+	public void destroy() {
+		parent.setInnerHTML("");
+		currentSelected = -1;
+		selectionEnableList.clear();
+	}
+
+	public void setSelected(int idx) {
+		int listLen = selectionEnableList.size();
+		if(listLen == 0) {
+			idx = -1;
+		}else if(idx >= listLen) {
+			idx = listLen - 1;
+		}else if(idx < 0) {
+			idx = 0;
+		}
+		if(idx == currentSelected) {
+			return;
+		}
+		if(currentSelected >= 0 && currentSelected < selectionEnableList.size()) {
+			selectionEnableList.get(currentSelected).element.getClassList().remove(BootMenuConstants.cssClassPrefixBootMenu + "content_item_selected");
+		}
+		currentSelected = idx;
+		if(idx != -1) {
+			selectionEnableList.get(idx).element.getClassList().add(BootMenuConstants.cssClassPrefixBootMenu + "content_item_selected");
+		}
+	}
+
+	public T getSelected() {
+		if(currentSelected >= 0 && currentSelected < selectionEnableList.size()) {
+			return selectionEnableList.get(currentSelected).listItem;
+		}else {
+			return null;
+		}
+	}
+
+	public void moveEntryUp(int index) {
+		if(index < 1 || index >= selectionEnableList.size()) return;
+		if(currentSelected == index) {
+			--currentSelected;
+		}
+		ListItemInstance<T> etr = selectionEnableList.get(index);
+		ListItemInstance<T> etr2 = selectionEnableList.get(index - 1);
+		Collections.swap(selectionEnableList, index, index - 1);
+		etr.index--;
+		etr2.index++;
+		parent.removeChild(etr.element);
+		parent.insertBefore(etr.element, etr2.element);
+	}
+
+	public void moveEntryDown(int index) {
+		if(index < 0 || index >= selectionEnableList.size() - 1) return;
+		if(currentSelected == index) {
+			++currentSelected;
+		}
+		ListItemInstance<T> etr = selectionEnableList.get(index);
+		Collections.swap(selectionEnableList, index, index + 1);
+		etr.index++;
+		selectionEnableList.get(index + 1).index--;
+		parent.removeChild(etr.element);
+		if(index >= selectionEnableList.size() - 2) {
+			parent.appendChild(etr.element);
+		}else {
+			ListItemInstance<T> etr2 = selectionEnableList.get(index + 2);
+			parent.insertBefore(etr.element, etr2.element);
+		}
+	}
+
+	public void handleKeyDown(int keyCode) {
+		if(keyCode == KeyCodes.DOM_KEY_ARROW_UP) {
+			setSelected(currentSelected - 1);
+		}else if(keyCode == KeyCodes.DOM_KEY_ARROW_DOWN) {
+			setSelected(currentSelected + 1);
+		}else if(keyCode == KeyCodes.DOM_KEY_ENTER) {
+			fireSelect();
+		}
+	}
+
+	protected void fireSelect() {
+		if(currentSelected >= 0 && currentSelected < selectionEnableList.size()) {
+			itemSelectedLow(selectionEnableList.get(currentSelected));
+		}
+	}
+
+	public void handleKeyRepeat(int keyCode) {
+		if(keyCode == KeyCodes.DOM_KEY_ARROW_UP) {
+			setSelected(currentSelected - 1);
+		}else if(keyCode == KeyCodes.DOM_KEY_ARROW_DOWN) {
+			setSelected(currentSelected + 1);
+		}
+	}
+
+	public void setCursorEventsSuspended(boolean sus) {
+		cursorEventsSuspended = sus;
+	}
+
+	protected void itemSelectedLow(ListItemInstance<T> item) {
+		itemSelected(item.listItem);
+	}
+
+	protected abstract void itemSelected(T item);
+
+}
diff --git a/sources/teavm-boot-menu/java/net/lax1dude/eaglercraft/v1_8/boot_menu/teavm/SignatureCheckHelper.java b/sources/teavm-boot-menu/java/net/lax1dude/eaglercraft/v1_8/boot_menu/teavm/SignatureCheckHelper.java
new file mode 100644
index 00000000..d04f4e8b
--- /dev/null
+++ b/sources/teavm-boot-menu/java/net/lax1dude/eaglercraft/v1_8/boot_menu/teavm/SignatureCheckHelper.java
@@ -0,0 +1,48 @@
+package net.lax1dude.eaglercraft.v1_8.boot_menu.teavm;
+
+import java.io.IOException;
+
+import net.lax1dude.eaglercraft.v1_8.log4j.LogManager;
+import net.lax1dude.eaglercraft.v1_8.log4j.Logger;
+import net.lax1dude.eaglercraft.v1_8.update.CertificateInvalidException;
+import net.lax1dude.eaglercraft.v1_8.update.UpdateCertificate;
+
+/**
+ * Copyright (c) 2024 lax1dude. All Rights Reserved.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ * 
+ */
+public class SignatureCheckHelper {
+
+	private static final Logger logger = LogManager.getLogger("SignatureCheckHelper");
+
+	public static boolean checkSignatureValid(byte[] signatureBytes, byte[] payloadBytes) {
+		UpdateCertificate cert;
+		try {
+			cert = UpdateCertificate.parseAndVerifyCertificate(signatureBytes);
+		} catch (CertificateInvalidException | IOException e) {
+			logger.error("The client's signature is invalid because the update certificate is bad");
+			logger.error(e);
+			return false;
+		}
+		if(!cert.isBundleDataValid(payloadBytes)) {
+			logger.error("The client's signature is invalid because the payload checksum does not match the expected checksum in the update certificate");
+			logger.error("(Update certificate client name and version: {} - {})", cert.bundleDisplayName, cert.bundleDisplayVersion);
+			return false;
+		}else {
+			logger.info("Signature is valid: {} - {}", cert.bundleDisplayName, cert.bundleDisplayVersion);
+			return true;
+		}
+	}
+
+}
diff --git a/sources/teavm-boot-menu/java/net/lax1dude/eaglercraft/v1_8/boot_menu/teavm/SignedClientInstaller.java b/sources/teavm-boot-menu/java/net/lax1dude/eaglercraft/v1_8/boot_menu/teavm/SignedClientInstaller.java
new file mode 100644
index 00000000..c980a319
--- /dev/null
+++ b/sources/teavm-boot-menu/java/net/lax1dude/eaglercraft/v1_8/boot_menu/teavm/SignedClientInstaller.java
@@ -0,0 +1,77 @@
+package net.lax1dude.eaglercraft.v1_8.boot_menu.teavm;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.json.JSONObject;
+import org.teavm.jso.browser.Window;
+
+import net.lax1dude.eaglercraft.v1_8.EaglercraftUUID;
+import net.lax1dude.eaglercraft.v1_8.log4j.LogManager;
+import net.lax1dude.eaglercraft.v1_8.log4j.Logger;
+
+/**
+ * Copyright (c) 2024 lax1dude. All Rights Reserved.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ * 
+ */
+public class SignedClientInstaller {
+
+	private static final Logger logger = LogManager.getLogger("SignedClientInstaller");
+
+	public static void installSignedClientAtRuntime(String displayName, Window win, byte[] clientCert,
+			byte[] clientPayload, boolean setDefault, boolean setTimeout) {
+		logger.info("Enabling boot menu...");
+		int f = BootMenuDataManager.getBootMenuFlags(win);
+		if(f == -1) f = 0;
+		f |= 1;
+		BootMenuDataManager.setBootMenuFlags(win, f);
+		logger.info("Loading datastore...");
+		BootMenuDatastore dstore = BootMenuDatastore.openDatastore();
+		try {
+			logger.info("Loading manifest...");
+			BootMenuDataManager dmgr = new BootMenuDataManager(dstore);
+			logger.info("Generating client data...");
+			EaglercraftUUID certUUID = EaglercraftUUID.nameUUIDFromBytes(clientCert);
+			EaglercraftUUID payloadUUID = EaglercraftUUID.nameUUIDFromBytes(clientPayload);
+			Map<EaglercraftUUID, byte[]> blobs = new HashMap<>(2);
+			blobs.put(certUUID, clientCert);
+			blobs.put(payloadUUID, clientPayload);
+			ClientDataEntry clientData = new ClientDataEntry(EnumClientFormatType.EAGLER_SIGNED_OFFLINE,
+					EaglercraftUUID.randomUUID(), payloadUUID, null, certUUID, null);
+			JSONObject launchOptsJSON = BootMenuEntryPoint.getOriginLaunchOptsJSON();
+			launchOptsJSON.put("bootMenuBlocksUnsignedClients", false);
+			RelayRandomizeHelper.makeOptsJSONHaveMacroHack(launchOptsJSON);
+			String launchOpts = launchOptsJSON.toString(4);
+			LaunchConfigEntry launchData = new LaunchConfigEntry(EaglercraftUUID.randomUUID(), clientData.uuid, displayName,
+					EnumClientLaunchType.EAGLERX_SIGNED_V1, null, null, null, null, null, launchOpts, false);
+			logger.info("Installing client data...");
+			dmgr.installNewClientData(launchData, clientData, blobs, false);
+			if(setDefault) {
+				logger.info("Setting boot order...");
+				while(dmgr.launchOrderList.remove(launchData.uuid));
+				dmgr.launchOrderList.add(0, launchData.uuid);
+				dmgr.writeManifest();
+				if(setTimeout) {
+					logger.info("Setting boot timeout...");
+					dmgr.confBootTimeout = 5;
+					dmgr.saveAdditionalConf();
+				}
+			}
+		}finally {
+			logger.info("Cleaning up...");
+			dstore.closeDatastore();
+		}
+	}
+
+}
diff --git a/sources/teavm-boot-menu/java/net/lax1dude/eaglercraft/v1_8/boot_menu/teavm/TemplateLoader.java b/sources/teavm-boot-menu/java/net/lax1dude/eaglercraft/v1_8/boot_menu/teavm/TemplateLoader.java
new file mode 100644
index 00000000..c5e48258
--- /dev/null
+++ b/sources/teavm-boot-menu/java/net/lax1dude/eaglercraft/v1_8/boot_menu/teavm/TemplateLoader.java
@@ -0,0 +1,77 @@
+package net.lax1dude.eaglercraft.v1_8.boot_menu.teavm;
+
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+
+import net.lax1dude.eaglercraft.v1_8.EaglercraftRandom;
+
+/**
+ * Copyright (c) 2024 lax1dude. All Rights Reserved.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ * 
+ */
+public class TemplateLoader {
+
+	public static final Map<String, String> baseGlobals;
+	
+	static {
+		baseGlobals = new HashMap<>();
+		baseGlobals.put("client_name", BootMenuConstants.client_projectForkName);
+		baseGlobals.put("client_vendor", BootMenuConstants.client_projectForkVendor);
+		baseGlobals.put("client_version", BootMenuConstants.client_projectForkVersion);
+		baseGlobals.put("game_version", BootMenuConstants.client_projectOriginRevision);
+		baseGlobals.put("client_fork_name", BootMenuConstants.client_projectForkName);
+		baseGlobals.put("client_fork_vendor", BootMenuConstants.client_projectForkVendor);
+		baseGlobals.put("client_fork_version", BootMenuConstants.client_projectForkVersion);
+		baseGlobals.put("client_origin_name", BootMenuConstants.client_projectOriginName);
+		baseGlobals.put("client_origin_vendor", BootMenuConstants.client_projectOriginAuthor);
+		baseGlobals.put("client_origin_version", BootMenuConstants.client_projectOriginVersion);
+		baseGlobals.put("client_origin_revision", BootMenuConstants.client_projectOriginRevision);
+		EaglercraftRandom randomCharGenerator = new EaglercraftRandom();
+		char[] vigg = new char[16];
+		String charSel = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
+		for(int i = 0; i < vigg.length; ++i) {
+			vigg[i] = charSel.charAt(randomCharGenerator.nextInt(charSel.length()));
+		}
+		baseGlobals.put("root_class_gen", BootMenuConstants.cssClassPrefix + (new String(vigg)));
+	}
+
+	public static String loadTemplate(String path) throws IOException {
+		return loadTemplate(path, null);
+	}
+
+	public static String loadTemplate(String path, Map<String, String> globals) throws IOException {
+		String basePath;
+		int i = path.lastIndexOf('/');
+		if(i != -1) {
+			basePath = path.substring(0, i);
+		}else {
+			basePath = "";
+		}
+		if(globals != null) {
+			Map<String, String> newGlobals = new HashMap<>();
+			newGlobals.putAll(baseGlobals);
+			newGlobals.putAll(globals);
+			globals = newGlobals;
+		}else {
+			globals = baseGlobals;
+		}
+		String templateContent = BootMenuAssets.loadResourceString(path);
+		if(templateContent == null) {
+			throw new IOException("Could not load template: \"" + path + "\"");
+		}
+		return TemplateParser.loadTemplate(templateContent, basePath, true, globals);
+	}
+
+}
diff --git a/sources/teavm-boot-menu/java/net/lax1dude/eaglercraft/v1_8/boot_menu/teavm/TemplateParser.java b/sources/teavm-boot-menu/java/net/lax1dude/eaglercraft/v1_8/boot_menu/teavm/TemplateParser.java
new file mode 100644
index 00000000..cf80b482
--- /dev/null
+++ b/sources/teavm-boot-menu/java/net/lax1dude/eaglercraft/v1_8/boot_menu/teavm/TemplateParser.java
@@ -0,0 +1,260 @@
+package net.lax1dude.eaglercraft.v1_8.boot_menu.teavm;
+
+import java.io.IOException;
+import java.util.Map;
+
+import org.apache.commons.lang3.text.StrTokenizer;
+import org.json.JSONObject;
+
+import com.google.common.html.HtmlEscapers;
+
+import net.lax1dude.eaglercraft.v1_8.Base64;
+
+/**
+ * Copyright (c) 2024 lax1dude. All Rights Reserved.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ * 
+ */
+public class TemplateParser {
+
+	private static class State {
+		private boolean evalAllowed;
+		private String baseDir;
+		private Map<String, String> globals;
+		private boolean htmlEscape;
+		private boolean strEscape;
+		private boolean disableMacros;
+		private boolean enableEval;
+		private State(String baseDir, boolean evalAllowed, Map<String, String> globals) {
+			this.baseDir = baseDir;
+			this.evalAllowed = evalAllowed;
+			this.globals = globals;
+		}
+		private State push() {
+			return new State(baseDir, evalAllowed, globals);
+		}
+	}
+
+	public static String loadTemplate(String content, String baseDir, boolean evalAllowed, Map<String, String> globals) throws IOException {
+		return loadTemplate(content, new State(baseDir, evalAllowed, globals));
+	}
+
+	private static String loadTemplate(String content, State state) throws IOException {
+		StringBuilder ret = new StringBuilder();
+		int i = 0, j = 0;
+		while((i = content.indexOf("{%", j)) != -1) {
+			ret.append(content, j, i);
+			j = i;
+			i = content.indexOf("%}", j + 2);
+			if(i != -1) {
+				ret.append(processMacro(content.substring(j + 2, i), state));
+				j = i + 2;
+			}else {
+				break;
+			}
+		}
+		ret.append(content, j, content.length());
+		return ret.toString();
+	}
+
+	public static class InvalidMacroException extends RuntimeException {
+
+		public InvalidMacroException(String message, Throwable cause) {
+			super(message, cause);
+		}
+
+		public InvalidMacroException(String message) {
+			super(message);
+		}
+
+	}
+
+	private static String processMacro(String content, State state) throws IOException {
+		String trimmed = content.trim();
+		try {
+			String[] strs = (new StrTokenizer(trimmed, ' ', '`')).getTokenArray();
+			if(strs.length < 1) {
+				return "{%" + content + "%}";
+			}
+			if(strs[0].equals("disablemacros") && strs.length == 2) {
+				switch(strs[1]) {
+				case "on":
+					if(state.disableMacros) {
+						return "{%" + content + "%}";
+					}else {
+						state.disableMacros = true;
+						return "";
+					}
+				case "off":
+					state.disableMacros = false;
+					return "";
+				default:
+					if(state.disableMacros) {
+						return "{%" + content + "%}";
+					}else {
+						throw new InvalidMacroException("Unknown disablemacros mode: " + strs[1] + " (Expected: on, off)");
+					}
+				}
+			}else if(!state.disableMacros) {
+				switch(strs[0]) {
+				case "embed":
+					argCheck(3, strs.length);
+					switch(strs[1]) {
+					case "base64":
+						return Base64.encodeBase64String(loadResourceBytes(state.baseDir + "/" + strs[2]));
+					case "text":
+						return escapeMacroResult(loadResourceString(state.baseDir + "/" + strs[2]), state);
+					case "eval":
+						if(state.evalAllowed) {
+							return escapeMacroResult(loadTemplate(loadResourceString(state.baseDir + "/" + strs[2]), state.push()), state);
+						}else {
+							throw new InvalidMacroException("Template tried to eval file \"" + strs[2] + "\"! (eval is disabled)");
+						}
+					default:
+						throw new InvalidMacroException("Unknown embed mode: " + strs[1] + " (Expected: base64, text, eval)");
+					}
+				case "htmlescape":
+					argCheck(2, strs.length);
+					switch(strs[1]) {
+					case "on":
+						state.htmlEscape = true;
+						return "";
+					case "off":
+						state.htmlEscape = false;
+						return "";
+					default:
+						throw new InvalidMacroException("Unknown htmlescape mode: " + strs[1] + " (Expected: on, off)");
+					}
+				case "strescape":
+					argCheck(2, strs.length);
+					switch(strs[1]) {
+					case "on":
+						state.strEscape = true;
+						return "";
+					case "off":
+						state.strEscape = false;
+						return "";
+					default:
+						throw new InvalidMacroException("Unknown strescape mode: " + strs[1] + " (Expected: on, off)");
+					}
+				case "eval":
+					argCheck(2, strs.length);
+					switch(strs[1]) {
+					case "on":
+						if(!state.evalAllowed) {
+							throw new InvalidMacroException("Template tried to enable eval! (eval is disabled)");
+						}
+						state.enableEval = true;
+						return "";
+					case "off":
+						state.enableEval = false;
+						return "";
+					default:
+						throw new InvalidMacroException("Unknown eval mode: " + strs[1] + " (Expected: on, off)");
+					}
+				case "global":
+					argCheck(2, 3, strs.length);
+					String ret = state.globals.get(strs[1]);
+					if(ret == null) {
+						if(strs.length == 3) {
+							ret = strs[2];
+						}else {
+							throw new InvalidMacroException("Unknown global \"" + strs[1] + "\"! (Available: " + String.join(", ", state.globals.keySet()) + ")");
+						}
+					}
+					return escapeMacroResult(ret, state);
+				case "property":
+					argCheck(2, 3, strs.length);
+					ret = System.getProperty(strs[1]);
+					if(ret == null) {
+						if(strs.length == 3) {
+							ret = strs[2];
+						}else {
+							throw new InvalidMacroException("Unknown system property \"" + strs[1] + "\"!");
+						}
+					}
+					return escapeMacroResult(ret, state);
+				case "text":
+					argCheck(2, strs.length);
+					return escapeMacroResult(strs[1], state);
+//				case "translate":
+//					argCheckMin(2, strs.length);
+//					String[] additionalArgs = new String[strs.length - 2];
+//					System.arraycopy(strs, 2, additionalArgs, 0, additionalArgs.length);
+//					return escapeMacroResult(BungeeCord.getInstance().getTranslation(strs[1], (Object[])additionalArgs), state);
+				default:
+					return "{%" + content + "%}";
+				}
+			}else {
+				return "{%" + content + "%}";
+			}
+		}catch(InvalidMacroException ex) {
+			throw new IOException("Invalid macro: {% " + trimmed + " %}, message: " + ex.getMessage(), ex);
+		}catch(Throwable th) {
+			throw new IOException("Error processing: {% " + trimmed + " %}, raised: " + th.toString(), th);
+		}
+	}
+
+	private static String escapeMacroResult(String str, State state) throws IOException {
+		if(str.length() > 0) {
+			if(state.evalAllowed && state.enableEval) {
+				str = loadTemplate(str, state.push());
+			}
+			if(state.strEscape) {
+				str = (new JSONObject()).put("e", str).toString(); //rip
+				if(str.length() >= 8) {
+					str = str.substring(6, str.length() - 2);
+				}
+			}
+			if(state.htmlEscape) {
+				str = HtmlEscapers.htmlEscaper().escape(str);
+			}
+		}
+		return str;
+	}
+
+	private static void argCheck(int expect, int actual) {
+		if(expect != actual) {
+			throw new InvalidMacroException("Wrong number of arguments (" + actual + ", expected " + expect + ")");
+		}
+	}
+
+	private static void argCheck(int expectMin, int expectMax, int actual) {
+		if(expectMin > actual || expectMax < actual) {
+			throw new InvalidMacroException("Wrong number of arguments (" + actual + ", expected " + expectMin + " to " + expectMax + ")");
+		}
+	}
+
+	private static void argCheckMin(int expectMin, int actual) {
+		if(expectMin > actual) {
+			throw new InvalidMacroException("Wrong number of arguments (expected " + expectMin + " or more, got " + actual + ")");
+		}
+	}
+
+	private static byte[] loadResourceBytes(String path) {
+		byte[] res = BootMenuAssets.loadResourceBytes(path);
+		if(res == null) {
+			throw new InvalidMacroException("Unknown file: " + path);
+		}
+		return res;
+	}
+
+	private static String loadResourceString(String path) {
+		String res = BootMenuAssets.loadResourceString(path);
+		if(res == null) {
+			throw new InvalidMacroException("Unknown file: " + path);
+		}
+		return res;
+	}
+
+}
diff --git a/sources/teavm-boot-menu/java/net/lax1dude/eaglercraft/v1_8/boot_menu/teavm/UnsignedBootException.java b/sources/teavm-boot-menu/java/net/lax1dude/eaglercraft/v1_8/boot_menu/teavm/UnsignedBootException.java
new file mode 100644
index 00000000..2641b756
--- /dev/null
+++ b/sources/teavm-boot-menu/java/net/lax1dude/eaglercraft/v1_8/boot_menu/teavm/UnsignedBootException.java
@@ -0,0 +1,23 @@
+package net.lax1dude.eaglercraft.v1_8.boot_menu.teavm;
+
+/**
+ * Copyright (c) 2024 lax1dude. All Rights Reserved.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ * 
+ */
+public class UnsignedBootException extends RuntimeException {
+
+	public UnsignedBootException() {
+	}
+
+}
diff --git a/sources/teavm/java/com/jcraft/jogg/Buffer.java b/sources/teavm/java/com/jcraft/jogg/Buffer.java
new file mode 100644
index 00000000..dde9158a
--- /dev/null
+++ b/sources/teavm/java/com/jcraft/jogg/Buffer.java
@@ -0,0 +1,293 @@
+/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
+/* JOrbis
+ * Copyright (C) 2000 ymnk, JCraft,Inc.
+ *  
+ * Written by: 2000 ymnk<ymnk@jcraft.com>
+ *   
+ * Many thanks to 
+ *   Monty <monty@xiph.org> and 
+ *   The XIPHOPHORUS Company http://www.xiph.org/ .
+ * JOrbis has been based on their awesome works, Vorbis codec.
+ *   
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public License
+ * as published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+   
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Library General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Library General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+package com.jcraft.jogg;
+
+public class Buffer {
+	private static final int BUFFER_INCREMENT = 256;
+
+	private static final int[] mask = { 0x00000000, 0x00000001, 0x00000003, 0x00000007, 0x0000000f, 0x0000001f,
+			0x0000003f, 0x0000007f, 0x000000ff, 0x000001ff, 0x000003ff, 0x000007ff, 0x00000fff, 0x00001fff, 0x00003fff,
+			0x00007fff, 0x0000ffff, 0x0001ffff, 0x0003ffff, 0x0007ffff, 0x000fffff, 0x001fffff, 0x003fffff, 0x007fffff,
+			0x00ffffff, 0x01ffffff, 0x03ffffff, 0x07ffffff, 0x0fffffff, 0x1fffffff, 0x3fffffff, 0x7fffffff,
+			0xffffffff };
+
+	int ptr = 0;
+	byte[] buffer = null;
+	int endbit = 0;
+	int endbyte = 0;
+	int storage = 0;
+
+	public void writeinit() {
+		buffer = new byte[BUFFER_INCREMENT];
+		ptr = 0;
+		buffer[0] = (byte) '\0';
+		storage = BUFFER_INCREMENT;
+	}
+
+	public void write(byte[] s) {
+		for (int i = 0; i < s.length; i++) {
+			if (s[i] == 0)
+				break;
+			write(s[i], 8);
+		}
+	}
+
+	public void read(byte[] s, int bytes) {
+		int i = 0;
+		while (bytes-- != 0) {
+			s[i++] = (byte) (read(8));
+		}
+	}
+
+	void reset() {
+		ptr = 0;
+		buffer[0] = (byte) '\0';
+		endbit = endbyte = 0;
+	}
+
+	public void writeclear() {
+		buffer = null;
+	}
+
+	public void readinit(byte[] buf, int bytes) {
+		readinit(buf, 0, bytes);
+	}
+
+	public void readinit(byte[] buf, int start, int bytes) {
+		ptr = start;
+		buffer = buf;
+		endbit = endbyte = 0;
+		storage = bytes;
+	}
+
+	public void write(int value, int bits) {
+		if (endbyte + 4 >= storage) {
+			byte[] foo = new byte[storage + BUFFER_INCREMENT];
+			System.arraycopy(buffer, 0, foo, 0, storage);
+			buffer = foo;
+			storage += BUFFER_INCREMENT;
+		}
+
+		value &= mask[bits];
+		bits += endbit;
+		buffer[ptr] |= (byte) (value << endbit);
+
+		if (bits >= 8) {
+			buffer[ptr + 1] = (byte) (value >>> (8 - endbit));
+			if (bits >= 16) {
+				buffer[ptr + 2] = (byte) (value >>> (16 - endbit));
+				if (bits >= 24) {
+					buffer[ptr + 3] = (byte) (value >>> (24 - endbit));
+					if (bits >= 32) {
+						if (endbit > 0)
+							buffer[ptr + 4] = (byte) (value >>> (32 - endbit));
+						else
+							buffer[ptr + 4] = 0;
+					}
+				}
+			}
+		}
+
+		endbyte += bits / 8;
+		ptr += bits / 8;
+		endbit = bits & 7;
+	}
+
+	public int look(int bits) {
+		int ret;
+		int m = mask[bits];
+
+		bits += endbit;
+
+		if (endbyte + 4 >= storage) {
+			if (endbyte + (bits - 1) / 8 >= storage)
+				return (-1);
+		}
+
+		ret = ((buffer[ptr]) & 0xff) >>> endbit;
+		if (bits > 8) {
+			ret |= ((buffer[ptr + 1]) & 0xff) << (8 - endbit);
+			if (bits > 16) {
+				ret |= ((buffer[ptr + 2]) & 0xff) << (16 - endbit);
+				if (bits > 24) {
+					ret |= ((buffer[ptr + 3]) & 0xff) << (24 - endbit);
+					if (bits > 32 && endbit != 0) {
+						ret |= ((buffer[ptr + 4]) & 0xff) << (32 - endbit);
+					}
+				}
+			}
+		}
+		return (m & ret);
+	}
+
+	public int look1() {
+		if (endbyte >= storage)
+			return (-1);
+		return ((buffer[ptr] >> endbit) & 1);
+	}
+
+	public void adv(int bits) {
+		bits += endbit;
+		ptr += bits / 8;
+		endbyte += bits / 8;
+		endbit = bits & 7;
+	}
+
+	public void adv1() {
+		++endbit;
+		if (endbit > 7) {
+			endbit = 0;
+			ptr++;
+			endbyte++;
+		}
+	}
+
+	public int read(int bits) {
+		int ret;
+		int m = mask[bits];
+
+		bits += endbit;
+
+		if (endbyte + 4 >= storage) {
+			ret = -1;
+			if (endbyte + (bits - 1) / 8 >= storage) {
+				ptr += bits / 8;
+				endbyte += bits / 8;
+				endbit = bits & 7;
+				return (ret);
+			}
+		}
+
+		ret = ((buffer[ptr]) & 0xff) >>> endbit;
+		if (bits > 8) {
+			ret |= ((buffer[ptr + 1]) & 0xff) << (8 - endbit);
+			if (bits > 16) {
+				ret |= ((buffer[ptr + 2]) & 0xff) << (16 - endbit);
+				if (bits > 24) {
+					ret |= ((buffer[ptr + 3]) & 0xff) << (24 - endbit);
+					if (bits > 32 && endbit != 0) {
+						ret |= ((buffer[ptr + 4]) & 0xff) << (32 - endbit);
+					}
+				}
+			}
+		}
+
+		ret &= m;
+
+		ptr += bits / 8;
+		endbyte += bits / 8;
+		endbit = bits & 7;
+		return (ret);
+	}
+
+	public int readB(int bits) {
+		int ret;
+		int m = 32 - bits;
+
+		bits += endbit;
+
+		if (endbyte + 4 >= storage) {
+			/* not the main path */
+			ret = -1;
+			if (endbyte * 8 + bits > storage * 8) {
+				ptr += bits / 8;
+				endbyte += bits / 8;
+				endbit = bits & 7;
+				return (ret);
+			}
+		}
+
+		ret = (buffer[ptr] & 0xff) << (24 + endbit);
+		if (bits > 8) {
+			ret |= (buffer[ptr + 1] & 0xff) << (16 + endbit);
+			if (bits > 16) {
+				ret |= (buffer[ptr + 2] & 0xff) << (8 + endbit);
+				if (bits > 24) {
+					ret |= (buffer[ptr + 3] & 0xff) << (endbit);
+					if (bits > 32 && (endbit != 0))
+						ret |= (buffer[ptr + 4] & 0xff) >> (8 - endbit);
+				}
+			}
+		}
+		ret = (ret >>> (m >> 1)) >>> ((m + 1) >> 1);
+
+		ptr += bits / 8;
+		endbyte += bits / 8;
+		endbit = bits & 7;
+		return (ret);
+	}
+
+	public int read1() {
+		int ret;
+		if (endbyte >= storage) {
+			ret = -1;
+			endbit++;
+			if (endbit > 7) {
+				endbit = 0;
+				ptr++;
+				endbyte++;
+			}
+			return (ret);
+		}
+
+		ret = (buffer[ptr] >> endbit) & 1;
+
+		endbit++;
+		if (endbit > 7) {
+			endbit = 0;
+			ptr++;
+			endbyte++;
+		}
+		return (ret);
+	}
+
+	public int bytes() {
+		return (endbyte + (endbit + 7) / 8);
+	}
+
+	public int bits() {
+		return (endbyte * 8 + endbit);
+	}
+
+	public byte[] buffer() {
+		return (buffer);
+	}
+
+	public static int ilog(int v) {
+		int ret = 0;
+		while (v > 0) {
+			ret++;
+			v >>>= 1;
+		}
+		return (ret);
+	}
+
+	public static void report(String in) {
+		System.err.println(in);
+		System.exit(1);
+	}
+}
diff --git a/sources/teavm/java/com/jcraft/jogg/Packet.java b/sources/teavm/java/com/jcraft/jogg/Packet.java
new file mode 100644
index 00000000..d78e6f5a
--- /dev/null
+++ b/sources/teavm/java/com/jcraft/jogg/Packet.java
@@ -0,0 +1,45 @@
+/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
+/* JOrbis
+ * Copyright (C) 2000 ymnk, JCraft,Inc.
+ *  
+ * Written by: 2000 ymnk<ymnk@jcraft.com>
+ *   
+ * Many thanks to 
+ *   Monty <monty@xiph.org> and 
+ *   The XIPHOPHORUS Company http://www.xiph.org/ .
+ * JOrbis has been based on their awesome works, Vorbis codec.
+ *   
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public License
+ * as published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+   
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Library General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Library General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+package com.jcraft.jogg;
+
+public class Packet {
+	public byte[] packet_base;
+	public int packet;
+	public int bytes;
+	public int b_o_s;
+	public int e_o_s;
+
+	public long granulepos;
+
+	/**
+	 * sequence number for decode; the framing knows where there's a hole in the
+	 * data, but we need coupling so that the codec (which is in a seperate
+	 * abstraction layer) also knows about the gap
+	 */
+	public long packetno;
+
+}
diff --git a/sources/teavm/java/com/jcraft/jogg/Page.java b/sources/teavm/java/com/jcraft/jogg/Page.java
new file mode 100644
index 00000000..f9d29fe7
--- /dev/null
+++ b/sources/teavm/java/com/jcraft/jogg/Page.java
@@ -0,0 +1,130 @@
+/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
+/* JOrbis
+ * Copyright (C) 2000 ymnk, JCraft,Inc.
+ *  
+ * Written by: 2000 ymnk<ymnk@jcraft.com>
+ *   
+ * Many thanks to 
+ *   Monty <monty@xiph.org> and 
+ *   The XIPHOPHORUS Company http://www.xiph.org/ .
+ * JOrbis has been based on their awesome works, Vorbis codec.
+ *   
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public License
+ * as published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+   
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Library General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Library General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+package com.jcraft.jogg;
+
+public class Page {
+	private static int[] crc_lookup = new int[256];
+	static {
+		for (int i = 0; i < crc_lookup.length; i++) {
+			crc_lookup[i] = crc_entry(i);
+		}
+	}
+
+	private static int crc_entry(int index) {
+		int r = index << 24;
+		for (int i = 0; i < 8; i++) {
+			if ((r & 0x80000000) != 0) {
+				r = (r << 1) ^ 0x04c11db7; /*
+											 * The same as the ethernet generator polynomial, although we use an
+											 * unreflected alg and an init/final of 0, not 0xffffffff
+											 */
+			} else {
+				r <<= 1;
+			}
+		}
+		return (r & 0xffffffff);
+	}
+
+	public byte[] header_base;
+	public int header;
+	public int header_len;
+	public byte[] body_base;
+	public int body;
+	public int body_len;
+
+	int version() {
+		return header_base[header + 4] & 0xff;
+	}
+
+	int continued() {
+		return (header_base[header + 5] & 0x01);
+	}
+
+	public int bos() {
+		return (header_base[header + 5] & 0x02);
+	}
+
+	public int eos() {
+		return (header_base[header + 5] & 0x04);
+	}
+
+	public long granulepos() {
+		long foo = header_base[header + 13] & 0xff;
+		foo = (foo << 8) | (header_base[header + 12] & 0xff);
+		foo = (foo << 8) | (header_base[header + 11] & 0xff);
+		foo = (foo << 8) | (header_base[header + 10] & 0xff);
+		foo = (foo << 8) | (header_base[header + 9] & 0xff);
+		foo = (foo << 8) | (header_base[header + 8] & 0xff);
+		foo = (foo << 8) | (header_base[header + 7] & 0xff);
+		foo = (foo << 8) | (header_base[header + 6] & 0xff);
+		return (foo);
+	}
+
+	public int serialno() {
+		return (header_base[header + 14] & 0xff) | ((header_base[header + 15] & 0xff) << 8)
+				| ((header_base[header + 16] & 0xff) << 16) | ((header_base[header + 17] & 0xff) << 24);
+	}
+
+	int pageno() {
+		return (header_base[header + 18] & 0xff) | ((header_base[header + 19] & 0xff) << 8)
+				| ((header_base[header + 20] & 0xff) << 16) | ((header_base[header + 21] & 0xff) << 24);
+	}
+
+	void checksum() {
+		int crc_reg = 0;
+
+		for (int i = 0; i < header_len; i++) {
+			crc_reg = (crc_reg << 8) ^ crc_lookup[((crc_reg >>> 24) & 0xff) ^ (header_base[header + i] & 0xff)];
+		}
+		for (int i = 0; i < body_len; i++) {
+			crc_reg = (crc_reg << 8) ^ crc_lookup[((crc_reg >>> 24) & 0xff) ^ (body_base[body + i] & 0xff)];
+		}
+		header_base[header + 22] = (byte) crc_reg;
+		header_base[header + 23] = (byte) (crc_reg >>> 8);
+		header_base[header + 24] = (byte) (crc_reg >>> 16);
+		header_base[header + 25] = (byte) (crc_reg >>> 24);
+	}
+
+	public Page copy() {
+		return copy(new Page());
+	}
+
+	public Page copy(Page p) {
+		byte[] tmp = new byte[header_len];
+		System.arraycopy(header_base, header, tmp, 0, header_len);
+		p.header_len = header_len;
+		p.header_base = tmp;
+		p.header = 0;
+		tmp = new byte[body_len];
+		System.arraycopy(body_base, body, tmp, 0, body_len);
+		p.body_len = body_len;
+		p.body_base = tmp;
+		p.body = 0;
+		return p;
+	}
+
+}
diff --git a/sources/teavm/java/com/jcraft/jogg/StreamState.java b/sources/teavm/java/com/jcraft/jogg/StreamState.java
new file mode 100644
index 00000000..e9c36634
--- /dev/null
+++ b/sources/teavm/java/com/jcraft/jogg/StreamState.java
@@ -0,0 +1,538 @@
+/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
+/* JOrbis
+ * Copyright (C) 2000 ymnk, JCraft,Inc.
+ *  
+ * Written by: 2000 ymnk<ymnk@jcraft.com>
+ *   
+ * Many thanks to 
+ *   Monty <monty@xiph.org> and 
+ *   The XIPHOPHORUS Company http://www.xiph.org/ .
+ * JOrbis has been based on their awesome works, Vorbis codec.
+ *   
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public License
+ * as published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+   
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Library General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Library General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+package com.jcraft.jogg;
+
+public class StreamState {
+	byte[] body_data; /* bytes from packet bodies */
+	int body_storage; /* storage elements allocated */
+	int body_fill; /* elements stored; fill mark */
+	private int body_returned; /* elements of fill returned */
+
+	int[] lacing_vals; /* The values that will go to the segment table */
+	long[] granule_vals; /*
+							 * pcm_pos values for headers. Not compact this way, but it is simple coupled to
+							 * the lacing fifo
+							 */
+	int lacing_storage;
+	int lacing_fill;
+	int lacing_packet;
+	int lacing_returned;
+
+	byte[] header = new byte[282]; /* working space for header encode */
+	int header_fill;
+
+	public int e_o_s; /*
+						 * set when we have buffered the last packet in the logical bitstream
+						 */
+	int b_o_s; /*
+				 * set after we've written the initial page of a logical bitstream
+				 */
+	int serialno;
+	int pageno;
+	long packetno; /*
+					 * sequence number for decode; the framing knows where there's a hole in the
+					 * data, but we need coupling so that the codec (which is in a seperate
+					 * abstraction layer) also knows about the gap
+					 */
+	long granulepos;
+
+	public StreamState() {
+		init();
+	}
+
+	StreamState(int serialno) {
+		this();
+		init(serialno);
+	}
+
+	void init() {
+		body_storage = 16 * 1024;
+		body_data = new byte[body_storage];
+		lacing_storage = 1024;
+		lacing_vals = new int[lacing_storage];
+		granule_vals = new long[lacing_storage];
+	}
+
+	public void init(int serialno) {
+		if (body_data == null) {
+			init();
+		} else {
+			for (int i = 0; i < body_data.length; i++)
+				body_data[i] = 0;
+			for (int i = 0; i < lacing_vals.length; i++)
+				lacing_vals[i] = 0;
+			for (int i = 0; i < granule_vals.length; i++)
+				granule_vals[i] = 0;
+		}
+		this.serialno = serialno;
+	}
+
+	public void clear() {
+		body_data = null;
+		lacing_vals = null;
+		granule_vals = null;
+	}
+
+	void destroy() {
+		clear();
+	}
+
+	void body_expand(int needed) {
+		if (body_storage <= body_fill + needed) {
+			body_storage += (needed + 1024);
+			byte[] foo = new byte[body_storage];
+			System.arraycopy(body_data, 0, foo, 0, body_data.length);
+			body_data = foo;
+		}
+	}
+
+	void lacing_expand(int needed) {
+		if (lacing_storage <= lacing_fill + needed) {
+			lacing_storage += (needed + 32);
+			int[] foo = new int[lacing_storage];
+			System.arraycopy(lacing_vals, 0, foo, 0, lacing_vals.length);
+			lacing_vals = foo;
+
+			long[] bar = new long[lacing_storage];
+			System.arraycopy(granule_vals, 0, bar, 0, granule_vals.length);
+			granule_vals = bar;
+		}
+	}
+
+	/* submit data to the internal buffer of the framing engine */
+	public int packetin(Packet op) {
+		int lacing_val = op.bytes / 255 + 1;
+
+		if (body_returned != 0) {
+			/*
+			 * advance packet data according to the body_returned pointer. We had to keep it
+			 * around to return a pointer into the buffer last call
+			 */
+
+			body_fill -= body_returned;
+			if (body_fill != 0) {
+				System.arraycopy(body_data, body_returned, body_data, 0, body_fill);
+			}
+			body_returned = 0;
+		}
+
+		/* make sure we have the buffer storage */
+		body_expand(op.bytes);
+		lacing_expand(lacing_val);
+
+		/*
+		 * Copy in the submitted packet. Yes, the copy is a waste; this is the liability
+		 * of overly clean abstraction for the time being. It will actually be fairly
+		 * easy to eliminate the extra copy in the future
+		 */
+
+		System.arraycopy(op.packet_base, op.packet, body_data, body_fill, op.bytes);
+		body_fill += op.bytes;
+
+		/* Store lacing vals for this packet */
+		int j;
+		for (j = 0; j < lacing_val - 1; j++) {
+			lacing_vals[lacing_fill + j] = 255;
+			granule_vals[lacing_fill + j] = granulepos;
+		}
+		lacing_vals[lacing_fill + j] = (op.bytes) % 255;
+		granulepos = granule_vals[lacing_fill + j] = op.granulepos;
+
+		/* flag the first segment as the beginning of the packet */
+		lacing_vals[lacing_fill] |= 0x100;
+
+		lacing_fill += lacing_val;
+
+		/* for the sake of completeness */
+		packetno++;
+
+		if (op.e_o_s != 0)
+			e_o_s = 1;
+		return (0);
+	}
+
+	public int packetout(Packet op) {
+
+		/*
+		 * The last part of decode. We have the stream broken into packet segments. Now
+		 * we need to group them into packets (or return the out of sync markers)
+		 */
+
+		int ptr = lacing_returned;
+
+		if (lacing_packet <= ptr) {
+			return (0);
+		}
+
+		if ((lacing_vals[ptr] & 0x400) != 0) {
+			/* We lost sync here; let the app know */
+			lacing_returned++;
+
+			/*
+			 * we need to tell the codec there's a gap; it might need to handle previous
+			 * packet dependencies.
+			 */
+			packetno++;
+			return (-1);
+		}
+
+		/* Gather the whole packet. We'll have no holes or a partial packet */
+		{
+			int size = lacing_vals[ptr] & 0xff;
+			int bytes = 0;
+
+			op.packet_base = body_data;
+			op.packet = body_returned;
+			op.e_o_s = lacing_vals[ptr] & 0x200; /* last packet of the stream? */
+			op.b_o_s = lacing_vals[ptr] & 0x100; /* first packet of the stream? */
+			bytes += size;
+
+			while (size == 255) {
+				int val = lacing_vals[++ptr];
+				size = val & 0xff;
+				if ((val & 0x200) != 0)
+					op.e_o_s = 0x200;
+				bytes += size;
+			}
+
+			op.packetno = packetno;
+			op.granulepos = granule_vals[ptr];
+			op.bytes = bytes;
+
+			body_returned += bytes;
+
+			lacing_returned = ptr + 1;
+		}
+		packetno++;
+		return (1);
+	}
+
+	// add the incoming page to the stream state; we decompose the page
+	// into packet segments here as well.
+
+	public int pagein(Page og) {
+		byte[] header_base = og.header_base;
+		int header = og.header;
+		byte[] body_base = og.body_base;
+		int body = og.body;
+		int bodysize = og.body_len;
+		int segptr = 0;
+
+		int version = og.version();
+		int continued = og.continued();
+		int bos = og.bos();
+		int eos = og.eos();
+		long granulepos = og.granulepos();
+		int _serialno = og.serialno();
+		int _pageno = og.pageno();
+		int segments = header_base[header + 26] & 0xff;
+
+		// clean up 'returned data'
+		{
+			int lr = lacing_returned;
+			int br = body_returned;
+
+			// body data
+			if (br != 0) {
+				body_fill -= br;
+				if (body_fill != 0) {
+					System.arraycopy(body_data, br, body_data, 0, body_fill);
+				}
+				body_returned = 0;
+			}
+
+			if (lr != 0) {
+				// segment table
+				if ((lacing_fill - lr) != 0) {
+					System.arraycopy(lacing_vals, lr, lacing_vals, 0, lacing_fill - lr);
+					System.arraycopy(granule_vals, lr, granule_vals, 0, lacing_fill - lr);
+				}
+				lacing_fill -= lr;
+				lacing_packet -= lr;
+				lacing_returned = 0;
+			}
+		}
+
+		// check the serial number
+		if (_serialno != serialno)
+			return (-1);
+		if (version > 0)
+			return (-1);
+
+		lacing_expand(segments + 1);
+
+		// are we in sequence?
+		if (_pageno != pageno) {
+			int i;
+
+			// unroll previous partial packet (if any)
+			for (i = lacing_packet; i < lacing_fill; i++) {
+				body_fill -= lacing_vals[i] & 0xff;
+				// System.out.println("??");
+			}
+			lacing_fill = lacing_packet;
+
+			// make a note of dropped data in segment table
+			if (pageno != -1) {
+				lacing_vals[lacing_fill++] = 0x400;
+				lacing_packet++;
+			}
+
+			// are we a 'continued packet' page? If so, we'll need to skip
+			// some segments
+			if (continued != 0) {
+				bos = 0;
+				for (; segptr < segments; segptr++) {
+					int val = (header_base[header + 27 + segptr] & 0xff);
+					body += val;
+					bodysize -= val;
+					if (val < 255) {
+						segptr++;
+						break;
+					}
+				}
+			}
+		}
+
+		if (bodysize != 0) {
+			body_expand(bodysize);
+			System.arraycopy(body_base, body, body_data, body_fill, bodysize);
+			body_fill += bodysize;
+		}
+
+		{
+			int saved = -1;
+			while (segptr < segments) {
+				int val = (header_base[header + 27 + segptr] & 0xff);
+				lacing_vals[lacing_fill] = val;
+				granule_vals[lacing_fill] = -1;
+
+				if (bos != 0) {
+					lacing_vals[lacing_fill] |= 0x100;
+					bos = 0;
+				}
+
+				if (val < 255)
+					saved = lacing_fill;
+
+				lacing_fill++;
+				segptr++;
+
+				if (val < 255)
+					lacing_packet = lacing_fill;
+			}
+
+			/* set the granulepos on the last pcmval of the last full packet */
+			if (saved != -1) {
+				granule_vals[saved] = granulepos;
+			}
+		}
+
+		if (eos != 0) {
+			e_o_s = 1;
+			if (lacing_fill > 0)
+				lacing_vals[lacing_fill - 1] |= 0x200;
+		}
+
+		pageno = _pageno + 1;
+		return (0);
+	}
+
+	/*
+	 * This will flush remaining packets into a page (returning nonzero), even if
+	 * there is not enough data to trigger a flush normally (undersized page). If
+	 * there are no packets or partial packets to flush, ogg_stream_flush returns 0.
+	 * Note that ogg_stream_flush will try to flush a normal sized page like
+	 * ogg_stream_pageout; a call to ogg_stream_flush does not gurantee that all
+	 * packets have flushed. Only a return value of 0 from ogg_stream_flush
+	 * indicates all packet data is flushed into pages.
+	 * 
+	 * ogg_stream_page will flush the last page in a stream even if it's undersized;
+	 * you almost certainly want to use ogg_stream_pageout (and *not*
+	 * ogg_stream_flush) unless you need to flush an undersized page in the middle
+	 * of a stream for some reason.
+	 */
+
+	public int flush(Page og) {
+
+		int i;
+		int vals = 0;
+		int maxvals = (lacing_fill > 255 ? 255 : lacing_fill);
+		int bytes = 0;
+		int acc = 0;
+		long granule_pos = granule_vals[0];
+
+		if (maxvals == 0)
+			return (0);
+
+		/* construct a page */
+		/* decide how many segments to include */
+
+		/*
+		 * If this is the initial header case, the first page must only include the
+		 * initial header packet
+		 */
+		if (b_o_s == 0) { /* 'initial header page' case */
+			granule_pos = 0;
+			for (vals = 0; vals < maxvals; vals++) {
+				if ((lacing_vals[vals] & 0x0ff) < 255) {
+					vals++;
+					break;
+				}
+			}
+		} else {
+			for (vals = 0; vals < maxvals; vals++) {
+				if (acc > 4096)
+					break;
+				acc += (lacing_vals[vals] & 0x0ff);
+				granule_pos = granule_vals[vals];
+			}
+		}
+
+		/* construct the header in temp storage */
+		System.arraycopy("OggS".getBytes(), 0, header, 0, 4);
+
+		/* stream structure version */
+		header[4] = 0x00;
+
+		/* continued packet flag? */
+		header[5] = 0x00;
+		if ((lacing_vals[0] & 0x100) == 0)
+			header[5] |= 0x01;
+		/* first page flag? */
+		if (b_o_s == 0)
+			header[5] |= 0x02;
+		/* last page flag? */
+		if (e_o_s != 0 && lacing_fill == vals)
+			header[5] |= 0x04;
+		b_o_s = 1;
+
+		/* 64 bits of PCM position */
+		for (i = 6; i < 14; i++) {
+			header[i] = (byte) granule_pos;
+			granule_pos >>>= 8;
+		}
+
+		/* 32 bits of stream serial number */
+		{
+			int _serialno = serialno;
+			for (i = 14; i < 18; i++) {
+				header[i] = (byte) _serialno;
+				_serialno >>>= 8;
+			}
+		}
+
+		/*
+		 * 32 bits of page counter (we have both counter and page header because this
+		 * val can roll over)
+		 */
+		if (pageno == -1)
+			pageno = 0; /*
+						 * because someone called stream_reset; this would be a strange thing to do in
+						 * an encode stream, but it has plausible uses
+						 */
+		{
+			int _pageno = pageno++;
+			for (i = 18; i < 22; i++) {
+				header[i] = (byte) _pageno;
+				_pageno >>>= 8;
+			}
+		}
+
+		/* zero for computation; filled in later */
+		header[22] = 0;
+		header[23] = 0;
+		header[24] = 0;
+		header[25] = 0;
+
+		/* segment table */
+		header[26] = (byte) vals;
+		for (i = 0; i < vals; i++) {
+			header[i + 27] = (byte) lacing_vals[i];
+			bytes += (header[i + 27] & 0xff);
+		}
+
+		/* set pointers in the ogg_page struct */
+		og.header_base = header;
+		og.header = 0;
+		og.header_len = header_fill = vals + 27;
+		og.body_base = body_data;
+		og.body = body_returned;
+		og.body_len = bytes;
+
+		/* advance the lacing data and set the body_returned pointer */
+
+		lacing_fill -= vals;
+		System.arraycopy(lacing_vals, vals, lacing_vals, 0, lacing_fill * 4);
+		System.arraycopy(granule_vals, vals, granule_vals, 0, lacing_fill * 8);
+		body_returned += bytes;
+
+		/* calculate the checksum */
+
+		og.checksum();
+
+		/* done */
+		return (1);
+	}
+
+	/*
+	 * This constructs pages from buffered packet segments. The pointers returned
+	 * are to static buffers; do not free. The returned buffers are good only until
+	 * the next call (using the same ogg_stream_state)
+	 */
+	public int pageout(Page og) {
+		if ((e_o_s != 0 && lacing_fill != 0) || /* 'were done, now flush' case */
+				body_fill - body_returned > 4096 || /* 'page nominal size' case */
+				lacing_fill >= 255 || /* 'segment table full' case */
+				(lacing_fill != 0 && b_o_s == 0)) { /* 'initial header page' case */
+			return flush(og);
+		}
+		return 0;
+	}
+
+	public int eof() {
+		return e_o_s;
+	}
+
+	public int reset() {
+		body_fill = 0;
+		body_returned = 0;
+
+		lacing_fill = 0;
+		lacing_packet = 0;
+		lacing_returned = 0;
+
+		header_fill = 0;
+
+		e_o_s = 0;
+		b_o_s = 0;
+		pageno = -1;
+		packetno = 0;
+		granulepos = 0;
+		return (0);
+	}
+}
diff --git a/sources/teavm/java/com/jcraft/jogg/SyncState.java b/sources/teavm/java/com/jcraft/jogg/SyncState.java
new file mode 100644
index 00000000..a706c4fe
--- /dev/null
+++ b/sources/teavm/java/com/jcraft/jogg/SyncState.java
@@ -0,0 +1,273 @@
+/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
+/* JOrbis
+ * Copyright (C) 2000 ymnk, JCraft,Inc.
+ *  
+ * Written by: 2000 ymnk<ymnk@jcraft.com>
+ *   
+ * Many thanks to 
+ *   Monty <monty@xiph.org> and 
+ *   The XIPHOPHORUS Company http://www.xiph.org/ .
+ * JOrbis has been based on their awesome works, Vorbis codec.
+ *   
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public License
+ * as published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+   
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Library General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Library General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+package com.jcraft.jogg;
+
+// DECODING PRIMITIVES: packet streaming layer
+
+// This has two layers to place more of the multi-serialno and paging
+// control in the application's hands.  First, we expose a data buffer
+// using ogg_decode_buffer().  The app either copies into the
+// buffer, or passes it directly to read(), etc.  We then call
+// ogg_decode_wrote() to tell how many bytes we just added.
+//
+// Pages are returned (pointers into the buffer in ogg_sync_state)
+// by ogg_decode_stream().  The page is then submitted to
+// ogg_decode_page() along with the appropriate
+// ogg_stream_state* (ie, matching serialno).  We then get raw
+// packets out calling ogg_stream_packet() with a
+// ogg_stream_state.  See the 'frame-prog.txt' docs for details and
+// example code.
+
+public class SyncState {
+
+	public byte[] data;
+	int storage;
+	int fill;
+	int returned;
+
+	int unsynced;
+	int headerbytes;
+	int bodybytes;
+
+	public int clear() {
+		data = null;
+		return (0);
+	}
+
+	public int buffer(int size) {
+		// first, clear out any space that has been previously returned
+		if (returned != 0) {
+			fill -= returned;
+			if (fill > 0) {
+				System.arraycopy(data, returned, data, 0, fill);
+			}
+			returned = 0;
+		}
+
+		if (size > storage - fill) {
+			// We need to extend the internal buffer
+			int newsize = size + fill + 4096; // an extra page to be nice
+			if (data != null) {
+				byte[] foo = new byte[newsize];
+				System.arraycopy(data, 0, foo, 0, data.length);
+				data = foo;
+			} else {
+				data = new byte[newsize];
+			}
+			storage = newsize;
+		}
+
+		return (fill);
+	}
+
+	public int wrote(int bytes) {
+		if (fill + bytes > storage)
+			return (-1);
+		fill += bytes;
+		return (0);
+	}
+
+	// sync the stream. This is meant to be useful for finding page
+	// boundaries.
+	//
+	// return values for this:
+	// -n) skipped n bytes
+	// 0) page not ready; more data (no bytes skipped)
+	// n) page synced at current location; page length n bytes
+	private Page pageseek = new Page();
+	private byte[] chksum = new byte[4];
+
+	public int pageseek(Page og) {
+		int page = returned;
+		int next;
+		int bytes = fill - returned;
+
+		if (headerbytes == 0) {
+			int _headerbytes, i;
+			if (bytes < 27)
+				return (0); // not enough for a header
+
+			/* verify capture pattern */
+			if (data[page] != 'O' || data[page + 1] != 'g' || data[page + 2] != 'g' || data[page + 3] != 'S') {
+				headerbytes = 0;
+				bodybytes = 0;
+
+				// search for possible capture
+				next = 0;
+				for (int ii = 0; ii < bytes - 1; ii++) {
+					if (data[page + 1 + ii] == 'O') {
+						next = page + 1 + ii;
+						break;
+					}
+				}
+				// next=memchr(page+1,'O',bytes-1);
+				if (next == 0)
+					next = fill;
+
+				returned = next;
+				return (-(next - page));
+			}
+			_headerbytes = (data[page + 26] & 0xff) + 27;
+			if (bytes < _headerbytes)
+				return (0); // not enough for header + seg table
+
+			// count up body length in the segment table
+
+			for (i = 0; i < (data[page + 26] & 0xff); i++) {
+				bodybytes += (data[page + 27 + i] & 0xff);
+			}
+			headerbytes = _headerbytes;
+		}
+
+		if (bodybytes + headerbytes > bytes)
+			return (0);
+
+		// The whole test page is buffered. Verify the checksum
+		synchronized (chksum) {
+			// Grab the checksum bytes, set the header field to zero
+
+			System.arraycopy(data, page + 22, chksum, 0, 4);
+			data[page + 22] = 0;
+			data[page + 23] = 0;
+			data[page + 24] = 0;
+			data[page + 25] = 0;
+
+			// set up a temp page struct and recompute the checksum
+			Page log = pageseek;
+			log.header_base = data;
+			log.header = page;
+			log.header_len = headerbytes;
+
+			log.body_base = data;
+			log.body = page + headerbytes;
+			log.body_len = bodybytes;
+			log.checksum();
+
+			// Compare
+			if (chksum[0] != data[page + 22] || chksum[1] != data[page + 23] || chksum[2] != data[page + 24]
+					|| chksum[3] != data[page + 25]) {
+				// D'oh. Mismatch! Corrupt page (or miscapture and not a page at all)
+				// replace the computed checksum with the one actually read in
+				System.arraycopy(chksum, 0, data, page + 22, 4);
+				// Bad checksum. Lose sync */
+
+				headerbytes = 0;
+				bodybytes = 0;
+				// search for possible capture
+				next = 0;
+				for (int ii = 0; ii < bytes - 1; ii++) {
+					if (data[page + 1 + ii] == 'O') {
+						next = page + 1 + ii;
+						break;
+					}
+				}
+				// next=memchr(page+1,'O',bytes-1);
+				if (next == 0)
+					next = fill;
+				returned = next;
+				return (-(next - page));
+			}
+		}
+
+		// yes, have a whole page all ready to go
+		{
+			page = returned;
+
+			if (og != null) {
+				og.header_base = data;
+				og.header = page;
+				og.header_len = headerbytes;
+				og.body_base = data;
+				og.body = page + headerbytes;
+				og.body_len = bodybytes;
+			}
+
+			unsynced = 0;
+			returned += (bytes = headerbytes + bodybytes);
+			headerbytes = 0;
+			bodybytes = 0;
+			return (bytes);
+		}
+	}
+
+	// sync the stream and get a page. Keep trying until we find a page.
+	// Supress 'sync errors' after reporting the first.
+	//
+	// return values:
+	// -1) recapture (hole in data)
+	// 0) need more data
+	// 1) page returned
+	//
+	// Returns pointers into buffered data; invalidated by next call to
+	// _stream, _clear, _init, or _buffer
+
+	public int pageout(Page og) {
+		// all we need to do is verify a page at the head of the stream
+		// buffer. If it doesn't verify, we look for the next potential
+		// frame
+
+		while (true) {
+			int ret = pageseek(og);
+			if (ret > 0) {
+				// have a page
+				return (1);
+			}
+			if (ret == 0) {
+				// need more data
+				return (0);
+			}
+
+			// head did not start a synced page... skipped some bytes
+			if (unsynced == 0) {
+				unsynced = 1;
+				return (-1);
+			}
+			// loop. keep looking
+		}
+	}
+
+	// clear things to an initial state. Good to call, eg, before seeking
+	public int reset() {
+		fill = 0;
+		returned = 0;
+		unsynced = 0;
+		headerbytes = 0;
+		bodybytes = 0;
+		return (0);
+	}
+
+	public void init() {
+	}
+
+	public int getDataOffset() {
+		return returned;
+	}
+
+	public int getBufferOffset() {
+		return fill;
+	}
+}
diff --git a/sources/teavm/java/com/jcraft/jorbis/Block.java b/sources/teavm/java/com/jcraft/jorbis/Block.java
new file mode 100644
index 00000000..0a0e1663
--- /dev/null
+++ b/sources/teavm/java/com/jcraft/jorbis/Block.java
@@ -0,0 +1,126 @@
+/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
+/* JOrbis
+ * Copyright (C) 2000 ymnk, JCraft,Inc.
+ *  
+ * Written by: 2000 ymnk<ymnk@jcraft.com>
+ *   
+ * Many thanks to 
+ *   Monty <monty@xiph.org> and 
+ *   The XIPHOPHORUS Company http://www.xiph.org/ .
+ * JOrbis has been based on their awesome works, Vorbis codec.
+ *   
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public License
+ * as published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+   
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Library General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Library General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+package com.jcraft.jorbis;
+
+import com.jcraft.jogg.*;
+
+public class Block {
+	/// necessary stream state for linking to the framing abstraction
+	float[][] pcm = new float[0][]; // this is a pointer into local storage
+	Buffer opb = new Buffer();
+
+	int lW;
+	int W;
+	int nW;
+	int pcmend;
+	int mode;
+
+	int eofflag;
+	long granulepos;
+	long sequence;
+	DspState vd; // For read-only access of configuration
+
+	// bitmetrics for the frame
+	int glue_bits;
+	int time_bits;
+	int floor_bits;
+	int res_bits;
+
+	public Block(DspState vd) {
+		this.vd = vd;
+		if (vd.analysisp != 0) {
+			opb.writeinit();
+		}
+	}
+
+	public void init(DspState vd) {
+		this.vd = vd;
+	}
+
+	public int clear() {
+		if (vd != null) {
+			if (vd.analysisp != 0) {
+				opb.writeclear();
+			}
+		}
+		return (0);
+	}
+
+	public int synthesis(Packet op) {
+		Info vi = vd.vi;
+
+		// first things first. Make sure decode is ready
+		opb.readinit(op.packet_base, op.packet, op.bytes);
+
+		// Check the packet type
+		if (opb.read(1) != 0) {
+			// Oops. This is not an audio data packet
+			return (-1);
+		}
+
+		// read our mode and pre/post windowsize
+		int _mode = opb.read(vd.modebits);
+		if (_mode == -1)
+			return (-1);
+
+		mode = _mode;
+		W = vi.mode_param[mode].blockflag;
+		if (W != 0) {
+			lW = opb.read(1);
+			nW = opb.read(1);
+			if (nW == -1)
+				return (-1);
+		} else {
+			lW = 0;
+			nW = 0;
+		}
+
+		// more setup
+		granulepos = op.granulepos;
+		sequence = op.packetno - 3; // first block is third packet
+		eofflag = op.e_o_s;
+
+		// alloc pcm passback storage
+		pcmend = vi.blocksizes[W];
+		if (pcm.length < vi.channels) {
+			pcm = new float[vi.channels][];
+		}
+		for (int i = 0; i < vi.channels; i++) {
+			if (pcm[i] == null || pcm[i].length < pcmend) {
+				pcm[i] = new float[pcmend];
+			} else {
+				for (int j = 0; j < pcmend; j++) {
+					pcm[i][j] = 0;
+				}
+			}
+		}
+
+		// unpack_header enforces range checking
+		int type = vi.map_type[vi.mode_param[mode].mapping];
+		return (FuncMapping.mapping_P[type].inverse(this, vd.mode[mode]));
+	}
+}
diff --git a/sources/teavm/java/com/jcraft/jorbis/CodeBook.java b/sources/teavm/java/com/jcraft/jorbis/CodeBook.java
new file mode 100644
index 00000000..c6c7f9fd
--- /dev/null
+++ b/sources/teavm/java/com/jcraft/jorbis/CodeBook.java
@@ -0,0 +1,471 @@
+/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
+/* JOrbis
+ * Copyright (C) 2000 ymnk, JCraft,Inc.
+ *  
+ * Written by: 2000 ymnk<ymnk@jcraft.com>
+ *   
+ * Many thanks to 
+ *   Monty <monty@xiph.org> and 
+ *   The XIPHOPHORUS Company http://www.xiph.org/ .
+ * JOrbis has been based on their awesome works, Vorbis codec.
+ *   
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public License
+ * as published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+   
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Library General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Library General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+package com.jcraft.jorbis;
+
+import com.jcraft.jogg.*;
+
+class CodeBook {
+	int dim; // codebook dimensions (elements per vector)
+	int entries; // codebook entries
+	StaticCodeBook c = new StaticCodeBook();
+
+	float[] valuelist; // list of dim*entries actual entry values
+	int[] codelist; // list of bitstream codewords for each entry
+	DecodeAux decode_tree;
+
+	// returns the number of bits
+	int encode(int a, Buffer b) {
+		b.write(codelist[a], c.lengthlist[a]);
+		return (c.lengthlist[a]);
+	}
+
+	// One the encode side, our vector writers are each designed for a
+	// specific purpose, and the encoder is not flexible without modification:
+	//
+	// The LSP vector coder uses a single stage nearest-match with no
+	// interleave, so no step and no error return. This is specced by floor0
+	// and doesn't change.
+	//
+	// Residue0 encoding interleaves, uses multiple stages, and each stage
+	// peels of a specific amount of resolution from a lattice (thus we want
+	// to match by threshhold, not nearest match). Residue doesn't *have* to
+	// be encoded that way, but to change it, one will need to add more
+	// infrastructure on the encode side (decode side is specced and simpler)
+
+	// floor0 LSP (single stage, non interleaved, nearest match)
+	// returns entry number and *modifies a* to the quantization value
+	int errorv(float[] a) {
+		int best = best(a, 1);
+		for (int k = 0; k < dim; k++) {
+			a[k] = valuelist[best * dim + k];
+		}
+		return (best);
+	}
+
+	// returns the number of bits and *modifies a* to the quantization value
+	int encodev(int best, float[] a, Buffer b) {
+		for (int k = 0; k < dim; k++) {
+			a[k] = valuelist[best * dim + k];
+		}
+		return (encode(best, b));
+	}
+
+	// res0 (multistage, interleave, lattice)
+	// returns the number of bits and *modifies a* to the remainder value
+	int encodevs(float[] a, Buffer b, int step, int addmul) {
+		int best = besterror(a, step, addmul);
+		return (encode(best, b));
+	}
+
+	private int[] t = new int[15]; // decodevs_add is synchronized for re-using t.
+
+	synchronized int decodevs_add(float[] a, int offset, Buffer b, int n) {
+		int step = n / dim;
+		int entry;
+		int i, j, o;
+
+		if (t.length < step) {
+			t = new int[step];
+		}
+
+		for (i = 0; i < step; i++) {
+			entry = decode(b);
+			if (entry == -1)
+				return (-1);
+			t[i] = entry * dim;
+		}
+		for (i = 0, o = 0; i < dim; i++, o += step) {
+			for (j = 0; j < step; j++) {
+				a[offset + o + j] += valuelist[t[j] + i];
+			}
+		}
+
+		return (0);
+	}
+
+	int decodev_add(float[] a, int offset, Buffer b, int n) {
+		int i, j, entry;
+		int t;
+
+		if (dim > 8) {
+			for (i = 0; i < n;) {
+				entry = decode(b);
+				if (entry == -1)
+					return (-1);
+				t = entry * dim;
+				for (j = 0; j < dim;) {
+					a[offset + (i++)] += valuelist[t + (j++)];
+				}
+			}
+		} else {
+			for (i = 0; i < n;) {
+				entry = decode(b);
+				if (entry == -1)
+					return (-1);
+				t = entry * dim;
+				j = 0;
+				switch (dim) {
+				case 8:
+					a[offset + (i++)] += valuelist[t + (j++)];
+				case 7:
+					a[offset + (i++)] += valuelist[t + (j++)];
+				case 6:
+					a[offset + (i++)] += valuelist[t + (j++)];
+				case 5:
+					a[offset + (i++)] += valuelist[t + (j++)];
+				case 4:
+					a[offset + (i++)] += valuelist[t + (j++)];
+				case 3:
+					a[offset + (i++)] += valuelist[t + (j++)];
+				case 2:
+					a[offset + (i++)] += valuelist[t + (j++)];
+				case 1:
+					a[offset + (i++)] += valuelist[t + (j++)];
+				case 0:
+					break;
+				}
+			}
+		}
+		return (0);
+	}
+
+	int decodev_set(float[] a, int offset, Buffer b, int n) {
+		int i, j, entry;
+		int t;
+
+		for (i = 0; i < n;) {
+			entry = decode(b);
+			if (entry == -1)
+				return (-1);
+			t = entry * dim;
+			for (j = 0; j < dim;) {
+				a[offset + i++] = valuelist[t + (j++)];
+			}
+		}
+		return (0);
+	}
+
+	int decodevv_add(float[][] a, int offset, int ch, Buffer b, int n) {
+		int i, j, entry;
+		int chptr = 0;
+
+		for (i = offset / ch; i < (offset + n) / ch;) {
+			entry = decode(b);
+			if (entry == -1)
+				return (-1);
+
+			int t = entry * dim;
+			for (j = 0; j < dim; j++) {
+				a[chptr++][i] += valuelist[t + j];
+				if (chptr == ch) {
+					chptr = 0;
+					i++;
+				}
+			}
+		}
+		return (0);
+	}
+
+	// Decode side is specced and easier, because we don't need to find
+	// matches using different criteria; we simply read and map. There are
+	// two things we need to do 'depending':
+	//
+	// We may need to support interleave. We don't really, but it's
+	// convenient to do it here rather than rebuild the vector later.
+	//
+	// Cascades may be additive or multiplicitive; this is not inherent in
+	// the codebook, but set in the code using the codebook. Like
+	// interleaving, it's easiest to do it here.
+	// stage==0 -> declarative (set the value)
+	// stage==1 -> additive
+	// stage==2 -> multiplicitive
+
+	// returns the entry number or -1 on eof
+	int decode(Buffer b) {
+		int ptr = 0;
+		DecodeAux t = decode_tree;
+		int lok = b.look(t.tabn);
+
+		if (lok >= 0) {
+			ptr = t.tab[lok];
+			b.adv(t.tabl[lok]);
+			if (ptr <= 0) {
+				return -ptr;
+			}
+		}
+		do {
+			switch (b.read1()) {
+			case 0:
+				ptr = t.ptr0[ptr];
+				break;
+			case 1:
+				ptr = t.ptr1[ptr];
+				break;
+			case -1:
+			default:
+				return (-1);
+			}
+		} while (ptr > 0);
+		return (-ptr);
+	}
+
+	// returns the entry number or -1 on eof
+	int decodevs(float[] a, int index, Buffer b, int step, int addmul) {
+		int entry = decode(b);
+		if (entry == -1)
+			return (-1);
+		switch (addmul) {
+		case -1:
+			for (int i = 0, o = 0; i < dim; i++, o += step)
+				a[index + o] = valuelist[entry * dim + i];
+			break;
+		case 0:
+			for (int i = 0, o = 0; i < dim; i++, o += step)
+				a[index + o] += valuelist[entry * dim + i];
+			break;
+		case 1:
+			for (int i = 0, o = 0; i < dim; i++, o += step)
+				a[index + o] *= valuelist[entry * dim + i];
+			break;
+		default:
+			// System.err.println("CodeBook.decodeves: addmul="+addmul);
+		}
+		return (entry);
+	}
+
+	int best(float[] a, int step) {
+		// brute force it!
+		{
+			int besti = -1;
+			float best = 0.f;
+			int e = 0;
+			for (int i = 0; i < entries; i++) {
+				if (c.lengthlist[i] > 0) {
+					float _this = dist(dim, valuelist, e, a, step);
+					if (besti == -1 || _this < best) {
+						best = _this;
+						besti = i;
+					}
+				}
+				e += dim;
+			}
+			return (besti);
+		}
+	}
+
+	// returns the entry number and *modifies a* to the remainder value
+	int besterror(float[] a, int step, int addmul) {
+		int best = best(a, step);
+		switch (addmul) {
+		case 0:
+			for (int i = 0, o = 0; i < dim; i++, o += step)
+				a[o] -= valuelist[best * dim + i];
+			break;
+		case 1:
+			for (int i = 0, o = 0; i < dim; i++, o += step) {
+				float val = valuelist[best * dim + i];
+				if (val == 0) {
+					a[o] = 0;
+				} else {
+					a[o] /= val;
+				}
+			}
+			break;
+		}
+		return (best);
+	}
+
+	void clear() {
+	}
+
+	private static float dist(int el, float[] ref, int index, float[] b, int step) {
+		float acc = (float) 0.;
+		for (int i = 0; i < el; i++) {
+			float val = (ref[index + i] - b[i * step]);
+			acc += val * val;
+		}
+		return (acc);
+	}
+
+	int init_decode(StaticCodeBook s) {
+		c = s;
+		entries = s.entries;
+		dim = s.dim;
+		valuelist = s.unquantize();
+
+		decode_tree = make_decode_tree();
+		if (decode_tree == null) {
+			clear();
+			return (-1);
+		}
+		return (0);
+	}
+
+	// given a list of word lengths, generate a list of codewords. Works
+	// for length ordered or unordered, always assigns the lowest valued
+	// codewords first. Extended to handle unused entries (length 0)
+	static int[] make_words(int[] l, int n) {
+		int[] marker = new int[33];
+		int[] r = new int[n];
+
+		for (int i = 0; i < n; i++) {
+			int length = l[i];
+			if (length > 0) {
+				int entry = marker[length];
+
+				// when we claim a node for an entry, we also claim the nodes
+				// below it (pruning off the imagined tree that may have dangled
+				// from it) as well as blocking the use of any nodes directly
+				// above for leaves
+
+				// update ourself
+				if (length < 32 && (entry >>> length) != 0) {
+					// error condition; the lengths must specify an overpopulated tree
+					// free(r);
+					return (null);
+				}
+				r[i] = entry;
+
+				// Look to see if the next shorter marker points to the node
+				// above. if so, update it and repeat.
+				{
+					for (int j = length; j > 0; j--) {
+						if ((marker[j] & 1) != 0) {
+							// have to jump branches
+							if (j == 1)
+								marker[1]++;
+							else
+								marker[j] = marker[j - 1] << 1;
+							break; // invariant says next upper marker would already
+							// have been moved if it was on the same path
+						}
+						marker[j]++;
+					}
+				}
+
+				// prune the tree; the implicit invariant says all the longer
+				// markers were dangling from our just-taken node. Dangle them
+				// from our *new* node.
+				for (int j = length + 1; j < 33; j++) {
+					if ((marker[j] >>> 1) == entry) {
+						entry = marker[j];
+						marker[j] = marker[j - 1] << 1;
+					} else {
+						break;
+					}
+				}
+			}
+		}
+
+		// bitreverse the words because our bitwise packer/unpacker is LSb
+		// endian
+		for (int i = 0; i < n; i++) {
+			int temp = 0;
+			for (int j = 0; j < l[i]; j++) {
+				temp <<= 1;
+				temp |= (r[i] >>> j) & 1;
+			}
+			r[i] = temp;
+		}
+
+		return (r);
+	}
+
+	// build the decode helper tree from the codewords
+	DecodeAux make_decode_tree() {
+		int top = 0;
+		DecodeAux t = new DecodeAux();
+		int[] ptr0 = t.ptr0 = new int[entries * 2];
+		int[] ptr1 = t.ptr1 = new int[entries * 2];
+		int[] codelist = make_words(c.lengthlist, c.entries);
+
+		if (codelist == null)
+			return (null);
+		t.aux = entries * 2;
+
+		for (int i = 0; i < entries; i++) {
+			if (c.lengthlist[i] > 0) {
+				int ptr = 0;
+				int j;
+				for (j = 0; j < c.lengthlist[i] - 1; j++) {
+					int bit = (codelist[i] >>> j) & 1;
+					if (bit == 0) {
+						if (ptr0[ptr] == 0) {
+							ptr0[ptr] = ++top;
+						}
+						ptr = ptr0[ptr];
+					} else {
+						if (ptr1[ptr] == 0) {
+							ptr1[ptr] = ++top;
+						}
+						ptr = ptr1[ptr];
+					}
+				}
+
+				if (((codelist[i] >>> j) & 1) == 0) {
+					ptr0[ptr] = -i;
+				} else {
+					ptr1[ptr] = -i;
+				}
+
+			}
+		}
+
+		t.tabn = Util.ilog(entries) - 4;
+
+		if (t.tabn < 5)
+			t.tabn = 5;
+		int n = 1 << t.tabn;
+		t.tab = new int[n];
+		t.tabl = new int[n];
+		for (int i = 0; i < n; i++) {
+			int p = 0;
+			int j = 0;
+			for (j = 0; j < t.tabn && (p > 0 || j == 0); j++) {
+				if ((i & (1 << j)) != 0) {
+					p = ptr1[p];
+				} else {
+					p = ptr0[p];
+				}
+			}
+			t.tab[i] = p; // -code
+			t.tabl[i] = j; // length
+		}
+
+		return (t);
+	}
+
+	class DecodeAux {
+		int[] tab;
+		int[] tabl;
+		int tabn;
+
+		int[] ptr0;
+		int[] ptr1;
+		int aux; // number of tree entries
+	}
+}
diff --git a/sources/teavm/java/com/jcraft/jorbis/Comment.java b/sources/teavm/java/com/jcraft/jorbis/Comment.java
new file mode 100644
index 00000000..77f95db7
--- /dev/null
+++ b/sources/teavm/java/com/jcraft/jorbis/Comment.java
@@ -0,0 +1,240 @@
+/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
+/* JOrbis
+ * Copyright (C) 2000 ymnk, JCraft,Inc.
+ *  
+ * Written by: 2000 ymnk<ymnk@jcraft.com>
+ *   
+ * Many thanks to 
+ *   Monty <monty@xiph.org> and 
+ *   The XIPHOPHORUS Company http://www.xiph.org/ .
+ * JOrbis has been based on their awesome works, Vorbis codec.
+ *   
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public License
+ * as published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+   
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Library General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Library General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+package com.jcraft.jorbis;
+
+import com.jcraft.jogg.*;
+
+// the comments are not part of vorbis_info so that vorbis_info can be
+// static storage
+public class Comment {
+	private static byte[] _vorbis = "vorbis".getBytes();
+	private static byte[] _vendor = "Xiphophorus libVorbis I 20000508".getBytes();
+
+	private static final int OV_EIMPL = -130;
+
+	// unlimited user comment fields.
+	public byte[][] user_comments;
+	public int[] comment_lengths;
+	public int comments;
+	public byte[] vendor;
+
+	public void init() {
+		user_comments = null;
+		comments = 0;
+		vendor = null;
+	}
+
+	public void add(String comment) {
+		add(comment.getBytes());
+	}
+
+	private void add(byte[] comment) {
+		byte[][] foo = new byte[comments + 2][];
+		if (user_comments != null) {
+			System.arraycopy(user_comments, 0, foo, 0, comments);
+		}
+		user_comments = foo;
+
+		int[] goo = new int[comments + 2];
+		if (comment_lengths != null) {
+			System.arraycopy(comment_lengths, 0, goo, 0, comments);
+		}
+		comment_lengths = goo;
+
+		byte[] bar = new byte[comment.length + 1];
+		System.arraycopy(comment, 0, bar, 0, comment.length);
+		user_comments[comments] = bar;
+		comment_lengths[comments] = comment.length;
+		comments++;
+		user_comments[comments] = null;
+	}
+
+	public void add_tag(String tag, String contents) {
+		if (contents == null)
+			contents = "";
+		add(tag + "=" + contents);
+	}
+
+	static boolean tagcompare(byte[] s1, byte[] s2, int n) {
+		int c = 0;
+		byte u1, u2;
+		while (c < n) {
+			u1 = s1[c];
+			u2 = s2[c];
+			if ('Z' >= u1 && u1 >= 'A')
+				u1 = (byte) (u1 - 'A' + 'a');
+			if ('Z' >= u2 && u2 >= 'A')
+				u2 = (byte) (u2 - 'A' + 'a');
+			if (u1 != u2) {
+				return false;
+			}
+			c++;
+		}
+		return true;
+	}
+
+	public String query(String tag) {
+		return query(tag, 0);
+	}
+
+	public String query(String tag, int count) {
+		int foo = query(tag.getBytes(), count);
+		if (foo == -1)
+			return null;
+		byte[] comment = user_comments[foo];
+		for (int i = 0; i < comment_lengths[foo]; i++) {
+			if (comment[i] == '=') {
+				return new String(comment, i + 1, comment_lengths[foo] - (i + 1));
+			}
+		}
+		return null;
+	}
+
+	private int query(byte[] tag, int count) {
+		int i = 0;
+		int found = 0;
+		int fulltaglen = tag.length + 1;
+		byte[] fulltag = new byte[fulltaglen];
+		System.arraycopy(tag, 0, fulltag, 0, tag.length);
+		fulltag[tag.length] = (byte) '=';
+
+		for (i = 0; i < comments; i++) {
+			if (tagcompare(user_comments[i], fulltag, fulltaglen)) {
+				if (count == found) {
+					// We return a pointer to the data, not a copy
+					// return user_comments[i] + taglen + 1;
+					return i;
+				} else {
+					found++;
+				}
+			}
+		}
+		return -1;
+	}
+
+	int unpack(Buffer opb) {
+		int vendorlen = opb.read(32);
+		if (vendorlen < 0) {
+			clear();
+			return (-1);
+		}
+		vendor = new byte[vendorlen + 1];
+		opb.read(vendor, vendorlen);
+		comments = opb.read(32);
+		if (comments < 0) {
+			clear();
+			return (-1);
+		}
+		user_comments = new byte[comments + 1][];
+		comment_lengths = new int[comments + 1];
+
+		for (int i = 0; i < comments; i++) {
+			int len = opb.read(32);
+			if (len < 0) {
+				clear();
+				return (-1);
+			}
+			comment_lengths[i] = len;
+			user_comments[i] = new byte[len + 1];
+			opb.read(user_comments[i], len);
+		}
+		if (opb.read(1) != 1) {
+			clear();
+			return (-1);
+
+		}
+		return (0);
+	}
+
+	int pack(Buffer opb) {
+		// preamble
+		opb.write(0x03, 8);
+		opb.write(_vorbis);
+
+		// vendor
+		opb.write(_vendor.length, 32);
+		opb.write(_vendor);
+
+		// comments
+		opb.write(comments, 32);
+		if (comments != 0) {
+			for (int i = 0; i < comments; i++) {
+				if (user_comments[i] != null) {
+					opb.write(comment_lengths[i], 32);
+					opb.write(user_comments[i]);
+				} else {
+					opb.write(0, 32);
+				}
+			}
+		}
+		opb.write(1, 1);
+		return (0);
+	}
+
+	public int header_out(Packet op) {
+		Buffer opb = new Buffer();
+		opb.writeinit();
+
+		if (pack(opb) != 0)
+			return OV_EIMPL;
+
+		op.packet_base = new byte[opb.bytes()];
+		op.packet = 0;
+		op.bytes = opb.bytes();
+		System.arraycopy(opb.buffer(), 0, op.packet_base, 0, op.bytes);
+		op.b_o_s = 0;
+		op.e_o_s = 0;
+		op.granulepos = 0;
+		return 0;
+	}
+
+	void clear() {
+		for (int i = 0; i < comments; i++)
+			user_comments[i] = null;
+		user_comments = null;
+		vendor = null;
+	}
+
+	public String getVendor() {
+		return new String(vendor, 0, vendor.length - 1);
+	}
+
+	public String getComment(int i) {
+		if (comments <= i)
+			return null;
+		return new String(user_comments[i], 0, user_comments[i].length - 1);
+	}
+
+	public String toString() {
+		String foo = "Vendor: " + new String(vendor, 0, vendor.length - 1);
+		for (int i = 0; i < comments; i++) {
+			foo = foo + "\nComment: " + new String(user_comments[i], 0, user_comments[i].length - 1);
+		}
+		foo = foo + "\n";
+		return foo;
+	}
+}
diff --git a/sources/teavm/java/com/jcraft/jorbis/Drft.java b/sources/teavm/java/com/jcraft/jorbis/Drft.java
new file mode 100644
index 00000000..de8aad4e
--- /dev/null
+++ b/sources/teavm/java/com/jcraft/jorbis/Drft.java
@@ -0,0 +1,1319 @@
+/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
+/* JOrbis
+ * Copyright (C) 2000 ymnk, JCraft,Inc.
+ *  
+ * Written by: 2000 ymnk<ymnk@jcraft.com>
+ *   
+ * Many thanks to 
+ *   Monty <monty@xiph.org> and 
+ *   The XIPHOPHORUS Company http://www.xiph.org/ .
+ * JOrbis has been based on their awesome works, Vorbis codec.
+ *   
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public License
+ * as published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+   
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Library General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Library General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+package com.jcraft.jorbis;
+
+class Drft {
+	int n;
+	float[] trigcache;
+	int[] splitcache;
+
+	void backward(float[] data) {
+		if (n == 1)
+			return;
+		drftb1(n, data, trigcache, trigcache, n, splitcache);
+	}
+
+	void init(int n) {
+		this.n = n;
+		trigcache = new float[3 * n];
+		splitcache = new int[32];
+		fdrffti(n, trigcache, splitcache);
+	}
+
+	void clear() {
+		if (trigcache != null)
+			trigcache = null;
+		if (splitcache != null)
+			splitcache = null;
+	}
+
+	static int[] ntryh = { 4, 2, 3, 5 };
+	static float tpi = 6.28318530717958647692528676655900577f;
+	static float hsqt2 = .70710678118654752440084436210485f;
+	static float taui = .86602540378443864676372317075293618f;
+	static float taur = -.5f;
+	static float sqrt2 = 1.4142135623730950488016887242097f;
+
+	static void drfti1(int n, float[] wa, int index, int[] ifac) {
+		float arg, argh, argld, fi;
+		int ntry = 0, i, j = -1;
+		int k1, l1, l2, ib;
+		int ld, ii, ip, is, nq, nr;
+		int ido, ipm, nfm1;
+		int nl = n;
+		int nf = 0;
+
+		int state = 101;
+
+		loop: while (true) {
+			switch (state) {
+			case 101:
+				j++;
+				if (j < 4)
+					ntry = ntryh[j];
+				else
+					ntry += 2;
+			case 104:
+				nq = nl / ntry;
+				nr = nl - ntry * nq;
+				if (nr != 0) {
+					state = 101;
+					break;
+				}
+				nf++;
+				ifac[nf + 1] = ntry;
+				nl = nq;
+				if (ntry != 2) {
+					state = 107;
+					break;
+				}
+				if (nf == 1) {
+					state = 107;
+					break;
+				}
+
+				for (i = 1; i < nf; i++) {
+					ib = nf - i + 1;
+					ifac[ib + 1] = ifac[ib];
+				}
+				ifac[2] = 2;
+			case 107:
+				if (nl != 1) {
+					state = 104;
+					break;
+				}
+				ifac[0] = n;
+				ifac[1] = nf;
+				argh = tpi / n;
+				is = 0;
+				nfm1 = nf - 1;
+				l1 = 1;
+
+				if (nfm1 == 0)
+					return;
+
+				for (k1 = 0; k1 < nfm1; k1++) {
+					ip = ifac[k1 + 2];
+					ld = 0;
+					l2 = l1 * ip;
+					ido = n / l2;
+					ipm = ip - 1;
+
+					for (j = 0; j < ipm; j++) {
+						ld += l1;
+						i = is;
+						argld = (float) ld * argh;
+						fi = 0.f;
+						for (ii = 2; ii < ido; ii += 2) {
+							fi += 1.f;
+							arg = fi * argld;
+							wa[index + i++] = (float) Math.cos(arg);
+							wa[index + i++] = (float) Math.sin(arg);
+						}
+						is += ido;
+					}
+					l1 = l2;
+				}
+				break loop;
+			}
+		}
+	}
+
+	static void fdrffti(int n, float[] wsave, int[] ifac) {
+		if (n == 1)
+			return;
+		drfti1(n, wsave, n, ifac);
+	}
+
+	static void dradf2(int ido, int l1, float[] cc, float[] ch, float[] wa1, int index) {
+		int i, k;
+		float ti2, tr2;
+		int t0, t1, t2, t3, t4, t5, t6;
+
+		t1 = 0;
+		t0 = (t2 = l1 * ido);
+		t3 = ido << 1;
+		for (k = 0; k < l1; k++) {
+			ch[t1 << 1] = cc[t1] + cc[t2];
+			ch[(t1 << 1) + t3 - 1] = cc[t1] - cc[t2];
+			t1 += ido;
+			t2 += ido;
+		}
+
+		if (ido < 2)
+			return;
+
+		if (ido != 2) {
+			t1 = 0;
+			t2 = t0;
+			for (k = 0; k < l1; k++) {
+				t3 = t2;
+				t4 = (t1 << 1) + (ido << 1);
+				t5 = t1;
+				t6 = t1 + t1;
+				for (i = 2; i < ido; i += 2) {
+					t3 += 2;
+					t4 -= 2;
+					t5 += 2;
+					t6 += 2;
+					tr2 = wa1[index + i - 2] * cc[t3 - 1] + wa1[index + i - 1] * cc[t3];
+					ti2 = wa1[index + i - 2] * cc[t3] - wa1[index + i - 1] * cc[t3 - 1];
+					ch[t6] = cc[t5] + ti2;
+					ch[t4] = ti2 - cc[t5];
+					ch[t6 - 1] = cc[t5 - 1] + tr2;
+					ch[t4 - 1] = cc[t5 - 1] - tr2;
+				}
+				t1 += ido;
+				t2 += ido;
+			}
+			if (ido % 2 == 1)
+				return;
+		}
+
+		t3 = (t2 = (t1 = ido) - 1);
+		t2 += t0;
+		for (k = 0; k < l1; k++) {
+			ch[t1] = -cc[t2];
+			ch[t1 - 1] = cc[t3];
+			t1 += ido << 1;
+			t2 += ido;
+			t3 += ido;
+		}
+	}
+
+	static void dradf4(int ido, int l1, float[] cc, float[] ch, float[] wa1, int index1, float[] wa2, int index2,
+			float[] wa3, int index3) {
+		int i, k, t0, t1, t2, t3, t4, t5, t6;
+		float ci2, ci3, ci4, cr2, cr3, cr4, ti1, ti2, ti3, ti4, tr1, tr2, tr3, tr4;
+		t0 = l1 * ido;
+
+		t1 = t0;
+		t4 = t1 << 1;
+		t2 = t1 + (t1 << 1);
+		t3 = 0;
+
+		for (k = 0; k < l1; k++) {
+			tr1 = cc[t1] + cc[t2];
+			tr2 = cc[t3] + cc[t4];
+
+			ch[t5 = t3 << 2] = tr1 + tr2;
+			ch[(ido << 2) + t5 - 1] = tr2 - tr1;
+			ch[(t5 += (ido << 1)) - 1] = cc[t3] - cc[t4];
+			ch[t5] = cc[t2] - cc[t1];
+
+			t1 += ido;
+			t2 += ido;
+			t3 += ido;
+			t4 += ido;
+		}
+		if (ido < 2)
+			return;
+
+		if (ido != 2) {
+			t1 = 0;
+			for (k = 0; k < l1; k++) {
+				t2 = t1;
+				t4 = t1 << 2;
+				t5 = (t6 = ido << 1) + t4;
+				for (i = 2; i < ido; i += 2) {
+					t3 = (t2 += 2);
+					t4 += 2;
+					t5 -= 2;
+
+					t3 += t0;
+					cr2 = wa1[index1 + i - 2] * cc[t3 - 1] + wa1[index1 + i - 1] * cc[t3];
+					ci2 = wa1[index1 + i - 2] * cc[t3] - wa1[index1 + i - 1] * cc[t3 - 1];
+					t3 += t0;
+					cr3 = wa2[index2 + i - 2] * cc[t3 - 1] + wa2[index2 + i - 1] * cc[t3];
+					ci3 = wa2[index2 + i - 2] * cc[t3] - wa2[index2 + i - 1] * cc[t3 - 1];
+					t3 += t0;
+					cr4 = wa3[index3 + i - 2] * cc[t3 - 1] + wa3[index3 + i - 1] * cc[t3];
+					ci4 = wa3[index3 + i - 2] * cc[t3] - wa3[index3 + i - 1] * cc[t3 - 1];
+
+					tr1 = cr2 + cr4;
+					tr4 = cr4 - cr2;
+					ti1 = ci2 + ci4;
+					ti4 = ci2 - ci4;
+
+					ti2 = cc[t2] + ci3;
+					ti3 = cc[t2] - ci3;
+					tr2 = cc[t2 - 1] + cr3;
+					tr3 = cc[t2 - 1] - cr3;
+
+					ch[t4 - 1] = tr1 + tr2;
+					ch[t4] = ti1 + ti2;
+
+					ch[t5 - 1] = tr3 - ti4;
+					ch[t5] = tr4 - ti3;
+
+					ch[t4 + t6 - 1] = ti4 + tr3;
+					ch[t4 + t6] = tr4 + ti3;
+
+					ch[t5 + t6 - 1] = tr2 - tr1;
+					ch[t5 + t6] = ti1 - ti2;
+				}
+				t1 += ido;
+			}
+			if ((ido & 1) != 0)
+				return;
+		}
+
+		t2 = (t1 = t0 + ido - 1) + (t0 << 1);
+		t3 = ido << 2;
+		t4 = ido;
+		t5 = ido << 1;
+		t6 = ido;
+
+		for (k = 0; k < l1; k++) {
+			ti1 = -hsqt2 * (cc[t1] + cc[t2]);
+			tr1 = hsqt2 * (cc[t1] - cc[t2]);
+
+			ch[t4 - 1] = tr1 + cc[t6 - 1];
+			ch[t4 + t5 - 1] = cc[t6 - 1] - tr1;
+
+			ch[t4] = ti1 - cc[t1 + t0];
+			ch[t4 + t5] = ti1 + cc[t1 + t0];
+
+			t1 += ido;
+			t2 += ido;
+			t4 += t3;
+			t6 += ido;
+		}
+	}
+
+	static void dradfg(int ido, int ip, int l1, int idl1, float[] cc, float[] c1, float[] c2, float[] ch, float[] ch2,
+			float[] wa, int index) {
+		int idij, ipph, i, j, k, l, ic, ik, is;
+		int t0, t1, t2 = 0, t3, t4, t5, t6, t7, t8, t9, t10;
+		float dc2, ai1, ai2, ar1, ar2, ds2;
+		int nbd;
+		float dcp = 0, arg, dsp = 0, ar1h, ar2h;
+		int idp2, ipp2;
+
+		arg = tpi / (float) ip;
+		dcp = (float) Math.cos(arg);
+		dsp = (float) Math.sin(arg);
+		ipph = (ip + 1) >> 1;
+		ipp2 = ip;
+		idp2 = ido;
+		nbd = (ido - 1) >> 1;
+		t0 = l1 * ido;
+		t10 = ip * ido;
+
+		int state = 100;
+		loop: while (true) {
+			switch (state) {
+			case 101:
+				if (ido == 1) {
+					state = 119;
+					break;
+				}
+				for (ik = 0; ik < idl1; ik++)
+					ch2[ik] = c2[ik];
+
+				t1 = 0;
+				for (j = 1; j < ip; j++) {
+					t1 += t0;
+					t2 = t1;
+					for (k = 0; k < l1; k++) {
+						ch[t2] = c1[t2];
+						t2 += ido;
+					}
+				}
+
+				is = -ido;
+				t1 = 0;
+				if (nbd > l1) {
+					for (j = 1; j < ip; j++) {
+						t1 += t0;
+						is += ido;
+						t2 = -ido + t1;
+						for (k = 0; k < l1; k++) {
+							idij = is - 1;
+							t2 += ido;
+							t3 = t2;
+							for (i = 2; i < ido; i += 2) {
+								idij += 2;
+								t3 += 2;
+								ch[t3 - 1] = wa[index + idij - 1] * c1[t3 - 1] + wa[index + idij] * c1[t3];
+								ch[t3] = wa[index + idij - 1] * c1[t3] - wa[index + idij] * c1[t3 - 1];
+							}
+						}
+					}
+				} else {
+
+					for (j = 1; j < ip; j++) {
+						is += ido;
+						idij = is - 1;
+						t1 += t0;
+						t2 = t1;
+						for (i = 2; i < ido; i += 2) {
+							idij += 2;
+							t2 += 2;
+							t3 = t2;
+							for (k = 0; k < l1; k++) {
+								ch[t3 - 1] = wa[index + idij - 1] * c1[t3 - 1] + wa[index + idij] * c1[t3];
+								ch[t3] = wa[index + idij - 1] * c1[t3] - wa[index + idij] * c1[t3 - 1];
+								t3 += ido;
+							}
+						}
+					}
+				}
+
+				t1 = 0;
+				t2 = ipp2 * t0;
+				if (nbd < l1) {
+					for (j = 1; j < ipph; j++) {
+						t1 += t0;
+						t2 -= t0;
+						t3 = t1;
+						t4 = t2;
+						for (i = 2; i < ido; i += 2) {
+							t3 += 2;
+							t4 += 2;
+							t5 = t3 - ido;
+							t6 = t4 - ido;
+							for (k = 0; k < l1; k++) {
+								t5 += ido;
+								t6 += ido;
+								c1[t5 - 1] = ch[t5 - 1] + ch[t6 - 1];
+								c1[t6 - 1] = ch[t5] - ch[t6];
+								c1[t5] = ch[t5] + ch[t6];
+								c1[t6] = ch[t6 - 1] - ch[t5 - 1];
+							}
+						}
+					}
+				} else {
+					for (j = 1; j < ipph; j++) {
+						t1 += t0;
+						t2 -= t0;
+						t3 = t1;
+						t4 = t2;
+						for (k = 0; k < l1; k++) {
+							t5 = t3;
+							t6 = t4;
+							for (i = 2; i < ido; i += 2) {
+								t5 += 2;
+								t6 += 2;
+								c1[t5 - 1] = ch[t5 - 1] + ch[t6 - 1];
+								c1[t6 - 1] = ch[t5] - ch[t6];
+								c1[t5] = ch[t5] + ch[t6];
+								c1[t6] = ch[t6 - 1] - ch[t5 - 1];
+							}
+							t3 += ido;
+							t4 += ido;
+						}
+					}
+				}
+			case 119:
+				for (ik = 0; ik < idl1; ik++)
+					c2[ik] = ch2[ik];
+
+				t1 = 0;
+				t2 = ipp2 * idl1;
+				for (j = 1; j < ipph; j++) {
+					t1 += t0;
+					t2 -= t0;
+					t3 = t1 - ido;
+					t4 = t2 - ido;
+					for (k = 0; k < l1; k++) {
+						t3 += ido;
+						t4 += ido;
+						c1[t3] = ch[t3] + ch[t4];
+						c1[t4] = ch[t4] - ch[t3];
+					}
+				}
+
+				ar1 = 1.f;
+				ai1 = 0.f;
+				t1 = 0;
+				t2 = ipp2 * idl1;
+				t3 = (ip - 1) * idl1;
+				for (l = 1; l < ipph; l++) {
+					t1 += idl1;
+					t2 -= idl1;
+					ar1h = dcp * ar1 - dsp * ai1;
+					ai1 = dcp * ai1 + dsp * ar1;
+					ar1 = ar1h;
+					t4 = t1;
+					t5 = t2;
+					t6 = t3;
+					t7 = idl1;
+
+					for (ik = 0; ik < idl1; ik++) {
+						ch2[t4++] = c2[ik] + ar1 * c2[t7++];
+						ch2[t5++] = ai1 * c2[t6++];
+					}
+
+					dc2 = ar1;
+					ds2 = ai1;
+					ar2 = ar1;
+					ai2 = ai1;
+
+					t4 = idl1;
+					t5 = (ipp2 - 1) * idl1;
+					for (j = 2; j < ipph; j++) {
+						t4 += idl1;
+						t5 -= idl1;
+
+						ar2h = dc2 * ar2 - ds2 * ai2;
+						ai2 = dc2 * ai2 + ds2 * ar2;
+						ar2 = ar2h;
+
+						t6 = t1;
+						t7 = t2;
+						t8 = t4;
+						t9 = t5;
+						for (ik = 0; ik < idl1; ik++) {
+							ch2[t6++] += ar2 * c2[t8++];
+							ch2[t7++] += ai2 * c2[t9++];
+						}
+					}
+				}
+				t1 = 0;
+				for (j = 1; j < ipph; j++) {
+					t1 += idl1;
+					t2 = t1;
+					for (ik = 0; ik < idl1; ik++)
+						ch2[ik] += c2[t2++];
+				}
+
+				if (ido < l1) {
+					state = 132;
+					break;
+				}
+
+				t1 = 0;
+				t2 = 0;
+				for (k = 0; k < l1; k++) {
+					t3 = t1;
+					t4 = t2;
+					for (i = 0; i < ido; i++)
+						cc[t4++] = ch[t3++];
+					t1 += ido;
+					t2 += t10;
+				}
+				state = 135;
+				break;
+
+			case 132:
+				for (i = 0; i < ido; i++) {
+					t1 = i;
+					t2 = i;
+					for (k = 0; k < l1; k++) {
+						cc[t2] = ch[t1];
+						t1 += ido;
+						t2 += t10;
+					}
+				}
+			case 135:
+				t1 = 0;
+				t2 = ido << 1;
+				t3 = 0;
+				t4 = ipp2 * t0;
+				for (j = 1; j < ipph; j++) {
+					t1 += t2;
+					t3 += t0;
+					t4 -= t0;
+
+					t5 = t1;
+					t6 = t3;
+					t7 = t4;
+
+					for (k = 0; k < l1; k++) {
+						cc[t5 - 1] = ch[t6];
+						cc[t5] = ch[t7];
+						t5 += t10;
+						t6 += ido;
+						t7 += ido;
+					}
+				}
+
+				if (ido == 1)
+					return;
+				if (nbd < l1) {
+					state = 141;
+					break;
+				}
+
+				t1 = -ido;
+				t3 = 0;
+				t4 = 0;
+				t5 = ipp2 * t0;
+				for (j = 1; j < ipph; j++) {
+					t1 += t2;
+					t3 += t2;
+					t4 += t0;
+					t5 -= t0;
+					t6 = t1;
+					t7 = t3;
+					t8 = t4;
+					t9 = t5;
+					for (k = 0; k < l1; k++) {
+						for (i = 2; i < ido; i += 2) {
+							ic = idp2 - i;
+							cc[i + t7 - 1] = ch[i + t8 - 1] + ch[i + t9 - 1];
+							cc[ic + t6 - 1] = ch[i + t8 - 1] - ch[i + t9 - 1];
+							cc[i + t7] = ch[i + t8] + ch[i + t9];
+							cc[ic + t6] = ch[i + t9] - ch[i + t8];
+						}
+						t6 += t10;
+						t7 += t10;
+						t8 += ido;
+						t9 += ido;
+					}
+				}
+				return;
+			case 141:
+				t1 = -ido;
+				t3 = 0;
+				t4 = 0;
+				t5 = ipp2 * t0;
+				for (j = 1; j < ipph; j++) {
+					t1 += t2;
+					t3 += t2;
+					t4 += t0;
+					t5 -= t0;
+					for (i = 2; i < ido; i += 2) {
+						t6 = idp2 + t1 - i;
+						t7 = i + t3;
+						t8 = i + t4;
+						t9 = i + t5;
+						for (k = 0; k < l1; k++) {
+							cc[t7 - 1] = ch[t8 - 1] + ch[t9 - 1];
+							cc[t6 - 1] = ch[t8 - 1] - ch[t9 - 1];
+							cc[t7] = ch[t8] + ch[t9];
+							cc[t6] = ch[t9] - ch[t8];
+							t6 += t10;
+							t7 += t10;
+							t8 += ido;
+							t9 += ido;
+						}
+					}
+				}
+				break loop;
+			}
+		}
+	}
+
+	static void drftf1(int n, float[] c, float[] ch, float[] wa, int[] ifac) {
+		int i, k1, l1, l2;
+		int na, kh, nf;
+		int ip, iw, ido, idl1, ix2, ix3;
+
+		nf = ifac[1];
+		na = 1;
+		l2 = n;
+		iw = n;
+
+		for (k1 = 0; k1 < nf; k1++) {
+			kh = nf - k1;
+			ip = ifac[kh + 1];
+			l1 = l2 / ip;
+			ido = n / l2;
+			idl1 = ido * l1;
+			iw -= (ip - 1) * ido;
+			na = 1 - na;
+
+			int state = 100;
+			loop: while (true) {
+				switch (state) {
+				case 100:
+					if (ip != 4) {
+						state = 102;
+						break;
+					}
+
+					ix2 = iw + ido;
+					ix3 = ix2 + ido;
+					if (na != 0)
+						dradf4(ido, l1, ch, c, wa, iw - 1, wa, ix2 - 1, wa, ix3 - 1);
+					else
+						dradf4(ido, l1, c, ch, wa, iw - 1, wa, ix2 - 1, wa, ix3 - 1);
+					state = 110;
+					break;
+				case 102:
+					if (ip != 2) {
+						state = 104;
+						break;
+					}
+					if (na != 0) {
+						state = 103;
+						break;
+					}
+					dradf2(ido, l1, c, ch, wa, iw - 1);
+					state = 110;
+					break;
+				case 103:
+					dradf2(ido, l1, ch, c, wa, iw - 1);
+				case 104:
+					if (ido == 1)
+						na = 1 - na;
+					if (na != 0) {
+						state = 109;
+						break;
+					}
+					dradfg(ido, ip, l1, idl1, c, c, c, ch, ch, wa, iw - 1);
+					na = 1;
+					state = 110;
+					break;
+				case 109:
+					dradfg(ido, ip, l1, idl1, ch, ch, ch, c, c, wa, iw - 1);
+					na = 0;
+				case 110:
+					l2 = l1;
+					break loop;
+				}
+			}
+		}
+		if (na == 1)
+			return;
+		for (i = 0; i < n; i++)
+			c[i] = ch[i];
+	}
+
+	static void dradb2(int ido, int l1, float[] cc, float[] ch, float[] wa1, int index) {
+		int i, k, t0, t1, t2, t3, t4, t5, t6;
+		float ti2, tr2;
+
+		t0 = l1 * ido;
+
+		t1 = 0;
+		t2 = 0;
+		t3 = (ido << 1) - 1;
+		for (k = 0; k < l1; k++) {
+			ch[t1] = cc[t2] + cc[t3 + t2];
+			ch[t1 + t0] = cc[t2] - cc[t3 + t2];
+			t2 = (t1 += ido) << 1;
+		}
+
+		if (ido < 2)
+			return;
+		if (ido != 2) {
+			t1 = 0;
+			t2 = 0;
+			for (k = 0; k < l1; k++) {
+				t3 = t1;
+				t5 = (t4 = t2) + (ido << 1);
+				t6 = t0 + t1;
+				for (i = 2; i < ido; i += 2) {
+					t3 += 2;
+					t4 += 2;
+					t5 -= 2;
+					t6 += 2;
+					ch[t3 - 1] = cc[t4 - 1] + cc[t5 - 1];
+					tr2 = cc[t4 - 1] - cc[t5 - 1];
+					ch[t3] = cc[t4] - cc[t5];
+					ti2 = cc[t4] + cc[t5];
+					ch[t6 - 1] = wa1[index + i - 2] * tr2 - wa1[index + i - 1] * ti2;
+					ch[t6] = wa1[index + i - 2] * ti2 + wa1[index + i - 1] * tr2;
+				}
+				t2 = (t1 += ido) << 1;
+			}
+			if ((ido % 2) == 1)
+				return;
+		}
+
+		t1 = ido - 1;
+		t2 = ido - 1;
+		for (k = 0; k < l1; k++) {
+			ch[t1] = cc[t2] + cc[t2];
+			ch[t1 + t0] = -(cc[t2 + 1] + cc[t2 + 1]);
+			t1 += ido;
+			t2 += ido << 1;
+		}
+	}
+
+	static void dradb3(int ido, int l1, float[] cc, float[] ch, float[] wa1, int index1, float[] wa2, int index2) {
+		int i, k, t0, t1, t2, t3, t4, t5, t6, t7, t8, t9, t10;
+		float ci2, ci3, di2, di3, cr2, cr3, dr2, dr3, ti2, tr2;
+		t0 = l1 * ido;
+
+		t1 = 0;
+		t2 = t0 << 1;
+		t3 = ido << 1;
+		t4 = ido + (ido << 1);
+		t5 = 0;
+		for (k = 0; k < l1; k++) {
+			tr2 = cc[t3 - 1] + cc[t3 - 1];
+			cr2 = cc[t5] + (taur * tr2);
+			ch[t1] = cc[t5] + tr2;
+			ci3 = taui * (cc[t3] + cc[t3]);
+			ch[t1 + t0] = cr2 - ci3;
+			ch[t1 + t2] = cr2 + ci3;
+			t1 += ido;
+			t3 += t4;
+			t5 += t4;
+		}
+
+		if (ido == 1)
+			return;
+
+		t1 = 0;
+		t3 = ido << 1;
+		for (k = 0; k < l1; k++) {
+			t7 = t1 + (t1 << 1);
+			t6 = (t5 = t7 + t3);
+			t8 = t1;
+			t10 = (t9 = t1 + t0) + t0;
+
+			for (i = 2; i < ido; i += 2) {
+				t5 += 2;
+				t6 -= 2;
+				t7 += 2;
+				t8 += 2;
+				t9 += 2;
+				t10 += 2;
+				tr2 = cc[t5 - 1] + cc[t6 - 1];
+				cr2 = cc[t7 - 1] + (taur * tr2);
+				ch[t8 - 1] = cc[t7 - 1] + tr2;
+				ti2 = cc[t5] - cc[t6];
+				ci2 = cc[t7] + (taur * ti2);
+				ch[t8] = cc[t7] + ti2;
+				cr3 = taui * (cc[t5 - 1] - cc[t6 - 1]);
+				ci3 = taui * (cc[t5] + cc[t6]);
+				dr2 = cr2 - ci3;
+				dr3 = cr2 + ci3;
+				di2 = ci2 + cr3;
+				di3 = ci2 - cr3;
+				ch[t9 - 1] = wa1[index1 + i - 2] * dr2 - wa1[index1 + i - 1] * di2;
+				ch[t9] = wa1[index1 + i - 2] * di2 + wa1[index1 + i - 1] * dr2;
+				ch[t10 - 1] = wa2[index2 + i - 2] * dr3 - wa2[index2 + i - 1] * di3;
+				ch[t10] = wa2[index2 + i - 2] * di3 + wa2[index2 + i - 1] * dr3;
+			}
+			t1 += ido;
+		}
+	}
+
+	static void dradb4(int ido, int l1, float[] cc, float[] ch, float[] wa1, int index1, float[] wa2, int index2,
+			float[] wa3, int index3) {
+		int i, k, t0, t1, t2, t3, t4, t5, t6, t7, t8;
+		float ci2, ci3, ci4, cr2, cr3, cr4, ti1, ti2, ti3, ti4, tr1, tr2, tr3, tr4;
+		t0 = l1 * ido;
+
+		t1 = 0;
+		t2 = ido << 2;
+		t3 = 0;
+		t6 = ido << 1;
+		for (k = 0; k < l1; k++) {
+			t4 = t3 + t6;
+			t5 = t1;
+			tr3 = cc[t4 - 1] + cc[t4 - 1];
+			tr4 = cc[t4] + cc[t4];
+			tr1 = cc[t3] - cc[(t4 += t6) - 1];
+			tr2 = cc[t3] + cc[t4 - 1];
+			ch[t5] = tr2 + tr3;
+			ch[t5 += t0] = tr1 - tr4;
+			ch[t5 += t0] = tr2 - tr3;
+			ch[t5 += t0] = tr1 + tr4;
+			t1 += ido;
+			t3 += t2;
+		}
+
+		if (ido < 2)
+			return;
+		if (ido != 2) {
+			t1 = 0;
+			for (k = 0; k < l1; k++) {
+				t5 = (t4 = (t3 = (t2 = t1 << 2) + t6)) + t6;
+				t7 = t1;
+				for (i = 2; i < ido; i += 2) {
+					t2 += 2;
+					t3 += 2;
+					t4 -= 2;
+					t5 -= 2;
+					t7 += 2;
+					ti1 = cc[t2] + cc[t5];
+					ti2 = cc[t2] - cc[t5];
+					ti3 = cc[t3] - cc[t4];
+					tr4 = cc[t3] + cc[t4];
+					tr1 = cc[t2 - 1] - cc[t5 - 1];
+					tr2 = cc[t2 - 1] + cc[t5 - 1];
+					ti4 = cc[t3 - 1] - cc[t4 - 1];
+					tr3 = cc[t3 - 1] + cc[t4 - 1];
+					ch[t7 - 1] = tr2 + tr3;
+					cr3 = tr2 - tr3;
+					ch[t7] = ti2 + ti3;
+					ci3 = ti2 - ti3;
+					cr2 = tr1 - tr4;
+					cr4 = tr1 + tr4;
+					ci2 = ti1 + ti4;
+					ci4 = ti1 - ti4;
+
+					ch[(t8 = t7 + t0) - 1] = wa1[index1 + i - 2] * cr2 - wa1[index1 + i - 1] * ci2;
+					ch[t8] = wa1[index1 + i - 2] * ci2 + wa1[index1 + i - 1] * cr2;
+					ch[(t8 += t0) - 1] = wa2[index2 + i - 2] * cr3 - wa2[index2 + i - 1] * ci3;
+					ch[t8] = wa2[index2 + i - 2] * ci3 + wa2[index2 + i - 1] * cr3;
+					ch[(t8 += t0) - 1] = wa3[index3 + i - 2] * cr4 - wa3[index3 + i - 1] * ci4;
+					ch[t8] = wa3[index3 + i - 2] * ci4 + wa3[index3 + i - 1] * cr4;
+				}
+				t1 += ido;
+			}
+			if (ido % 2 == 1)
+				return;
+		}
+
+		t1 = ido;
+		t2 = ido << 2;
+		t3 = ido - 1;
+		t4 = ido + (ido << 1);
+		for (k = 0; k < l1; k++) {
+			t5 = t3;
+			ti1 = cc[t1] + cc[t4];
+			ti2 = cc[t4] - cc[t1];
+			tr1 = cc[t1 - 1] - cc[t4 - 1];
+			tr2 = cc[t1 - 1] + cc[t4 - 1];
+			ch[t5] = tr2 + tr2;
+			ch[t5 += t0] = sqrt2 * (tr1 - ti1);
+			ch[t5 += t0] = ti2 + ti2;
+			ch[t5 += t0] = -sqrt2 * (tr1 + ti1);
+
+			t3 += ido;
+			t1 += t2;
+			t4 += t2;
+		}
+	}
+
+	static void dradbg(int ido, int ip, int l1, int idl1, float[] cc, float[] c1, float[] c2, float[] ch, float[] ch2,
+			float[] wa, int index) {
+
+		int idij, ipph = 0, i, j, k, l, ik, is, t0 = 0, t1, t2, t3, t4, t5, t6, t7, t8, t9, t10 = 0, t11, t12;
+		float dc2, ai1, ai2, ar1, ar2, ds2;
+		int nbd = 0;
+		float dcp = 0, arg, dsp = 0, ar1h, ar2h;
+		int ipp2 = 0;
+
+		int state = 100;
+
+		loop: while (true) {
+			switch (state) {
+			case 100:
+				t10 = ip * ido;
+				t0 = l1 * ido;
+				arg = tpi / (float) ip;
+				dcp = (float) Math.cos(arg);
+				dsp = (float) Math.sin(arg);
+				nbd = (ido - 1) >>> 1;
+				ipp2 = ip;
+				ipph = (ip + 1) >>> 1;
+				if (ido < l1) {
+					state = 103;
+					break;
+				}
+				t1 = 0;
+				t2 = 0;
+				for (k = 0; k < l1; k++) {
+					t3 = t1;
+					t4 = t2;
+					for (i = 0; i < ido; i++) {
+						ch[t3] = cc[t4];
+						t3++;
+						t4++;
+					}
+					t1 += ido;
+					t2 += t10;
+				}
+				state = 106;
+				break;
+			case 103:
+				t1 = 0;
+				for (i = 0; i < ido; i++) {
+					t2 = t1;
+					t3 = t1;
+					for (k = 0; k < l1; k++) {
+						ch[t2] = cc[t3];
+						t2 += ido;
+						t3 += t10;
+					}
+					t1++;
+				}
+			case 106:
+				t1 = 0;
+				t2 = ipp2 * t0;
+				t7 = (t5 = ido << 1);
+				for (j = 1; j < ipph; j++) {
+					t1 += t0;
+					t2 -= t0;
+					t3 = t1;
+					t4 = t2;
+					t6 = t5;
+					for (k = 0; k < l1; k++) {
+						ch[t3] = cc[t6 - 1] + cc[t6 - 1];
+						ch[t4] = cc[t6] + cc[t6];
+						t3 += ido;
+						t4 += ido;
+						t6 += t10;
+					}
+					t5 += t7;
+				}
+				if (ido == 1) {
+					state = 116;
+					break;
+				}
+				if (nbd < l1) {
+					state = 112;
+					break;
+				}
+
+				t1 = 0;
+				t2 = ipp2 * t0;
+				t7 = 0;
+				for (j = 1; j < ipph; j++) {
+					t1 += t0;
+					t2 -= t0;
+					t3 = t1;
+					t4 = t2;
+
+					t7 += (ido << 1);
+					t8 = t7;
+					for (k = 0; k < l1; k++) {
+						t5 = t3;
+						t6 = t4;
+						t9 = t8;
+						t11 = t8;
+						for (i = 2; i < ido; i += 2) {
+							t5 += 2;
+							t6 += 2;
+							t9 += 2;
+							t11 -= 2;
+							ch[t5 - 1] = cc[t9 - 1] + cc[t11 - 1];
+							ch[t6 - 1] = cc[t9 - 1] - cc[t11 - 1];
+							ch[t5] = cc[t9] - cc[t11];
+							ch[t6] = cc[t9] + cc[t11];
+						}
+						t3 += ido;
+						t4 += ido;
+						t8 += t10;
+					}
+				}
+				state = 116;
+				break;
+			case 112:
+				t1 = 0;
+				t2 = ipp2 * t0;
+				t7 = 0;
+				for (j = 1; j < ipph; j++) {
+					t1 += t0;
+					t2 -= t0;
+					t3 = t1;
+					t4 = t2;
+					t7 += (ido << 1);
+					t8 = t7;
+					t9 = t7;
+					for (i = 2; i < ido; i += 2) {
+						t3 += 2;
+						t4 += 2;
+						t8 += 2;
+						t9 -= 2;
+						t5 = t3;
+						t6 = t4;
+						t11 = t8;
+						t12 = t9;
+						for (k = 0; k < l1; k++) {
+							ch[t5 - 1] = cc[t11 - 1] + cc[t12 - 1];
+							ch[t6 - 1] = cc[t11 - 1] - cc[t12 - 1];
+							ch[t5] = cc[t11] - cc[t12];
+							ch[t6] = cc[t11] + cc[t12];
+							t5 += ido;
+							t6 += ido;
+							t11 += t10;
+							t12 += t10;
+						}
+					}
+				}
+			case 116:
+				ar1 = 1.f;
+				ai1 = 0.f;
+				t1 = 0;
+				t9 = (t2 = ipp2 * idl1);
+				t3 = (ip - 1) * idl1;
+				for (l = 1; l < ipph; l++) {
+					t1 += idl1;
+					t2 -= idl1;
+
+					ar1h = dcp * ar1 - dsp * ai1;
+					ai1 = dcp * ai1 + dsp * ar1;
+					ar1 = ar1h;
+					t4 = t1;
+					t5 = t2;
+					t6 = 0;
+					t7 = idl1;
+					t8 = t3;
+					for (ik = 0; ik < idl1; ik++) {
+						c2[t4++] = ch2[t6++] + ar1 * ch2[t7++];
+						c2[t5++] = ai1 * ch2[t8++];
+					}
+					dc2 = ar1;
+					ds2 = ai1;
+					ar2 = ar1;
+					ai2 = ai1;
+
+					t6 = idl1;
+					t7 = t9 - idl1;
+					for (j = 2; j < ipph; j++) {
+						t6 += idl1;
+						t7 -= idl1;
+						ar2h = dc2 * ar2 - ds2 * ai2;
+						ai2 = dc2 * ai2 + ds2 * ar2;
+						ar2 = ar2h;
+						t4 = t1;
+						t5 = t2;
+						t11 = t6;
+						t12 = t7;
+						for (ik = 0; ik < idl1; ik++) {
+							c2[t4++] += ar2 * ch2[t11++];
+							c2[t5++] += ai2 * ch2[t12++];
+						}
+					}
+				}
+
+				t1 = 0;
+				for (j = 1; j < ipph; j++) {
+					t1 += idl1;
+					t2 = t1;
+					for (ik = 0; ik < idl1; ik++)
+						ch2[ik] += ch2[t2++];
+				}
+
+				t1 = 0;
+				t2 = ipp2 * t0;
+				for (j = 1; j < ipph; j++) {
+					t1 += t0;
+					t2 -= t0;
+					t3 = t1;
+					t4 = t2;
+					for (k = 0; k < l1; k++) {
+						ch[t3] = c1[t3] - c1[t4];
+						ch[t4] = c1[t3] + c1[t4];
+						t3 += ido;
+						t4 += ido;
+					}
+				}
+
+				if (ido == 1) {
+					state = 132;
+					break;
+				}
+				if (nbd < l1) {
+					state = 128;
+					break;
+				}
+
+				t1 = 0;
+				t2 = ipp2 * t0;
+				for (j = 1; j < ipph; j++) {
+					t1 += t0;
+					t2 -= t0;
+					t3 = t1;
+					t4 = t2;
+					for (k = 0; k < l1; k++) {
+						t5 = t3;
+						t6 = t4;
+						for (i = 2; i < ido; i += 2) {
+							t5 += 2;
+							t6 += 2;
+							ch[t5 - 1] = c1[t5 - 1] - c1[t6];
+							ch[t6 - 1] = c1[t5 - 1] + c1[t6];
+							ch[t5] = c1[t5] + c1[t6 - 1];
+							ch[t6] = c1[t5] - c1[t6 - 1];
+						}
+						t3 += ido;
+						t4 += ido;
+					}
+				}
+				state = 132;
+				break;
+			case 128:
+				t1 = 0;
+				t2 = ipp2 * t0;
+				for (j = 1; j < ipph; j++) {
+					t1 += t0;
+					t2 -= t0;
+					t3 = t1;
+					t4 = t2;
+					for (i = 2; i < ido; i += 2) {
+						t3 += 2;
+						t4 += 2;
+						t5 = t3;
+						t6 = t4;
+						for (k = 0; k < l1; k++) {
+							ch[t5 - 1] = c1[t5 - 1] - c1[t6];
+							ch[t6 - 1] = c1[t5 - 1] + c1[t6];
+							ch[t5] = c1[t5] + c1[t6 - 1];
+							ch[t6] = c1[t5] - c1[t6 - 1];
+							t5 += ido;
+							t6 += ido;
+						}
+					}
+				}
+			case 132:
+				if (ido == 1)
+					return;
+
+				for (ik = 0; ik < idl1; ik++)
+					c2[ik] = ch2[ik];
+
+				t1 = 0;
+				for (j = 1; j < ip; j++) {
+					t2 = (t1 += t0);
+					for (k = 0; k < l1; k++) {
+						c1[t2] = ch[t2];
+						t2 += ido;
+					}
+				}
+
+				if (nbd > l1) {
+					state = 139;
+					break;
+				}
+
+				is = -ido - 1;
+				t1 = 0;
+				for (j = 1; j < ip; j++) {
+					is += ido;
+					t1 += t0;
+					idij = is;
+					t2 = t1;
+					for (i = 2; i < ido; i += 2) {
+						t2 += 2;
+						idij += 2;
+						t3 = t2;
+						for (k = 0; k < l1; k++) {
+							c1[t3 - 1] = wa[index + idij - 1] * ch[t3 - 1] - wa[index + idij] * ch[t3];
+							c1[t3] = wa[index + idij - 1] * ch[t3] + wa[index + idij] * ch[t3 - 1];
+							t3 += ido;
+						}
+					}
+				}
+				return;
+
+			case 139:
+				is = -ido - 1;
+				t1 = 0;
+				for (j = 1; j < ip; j++) {
+					is += ido;
+					t1 += t0;
+					t2 = t1;
+					for (k = 0; k < l1; k++) {
+						idij = is;
+						t3 = t2;
+						for (i = 2; i < ido; i += 2) {
+							idij += 2;
+							t3 += 2;
+							c1[t3 - 1] = wa[index + idij - 1] * ch[t3 - 1] - wa[index + idij] * ch[t3];
+							c1[t3] = wa[index + idij - 1] * ch[t3] + wa[index + idij] * ch[t3 - 1];
+						}
+						t2 += ido;
+					}
+				}
+				break loop;
+			}
+		}
+	}
+
+	static void drftb1(int n, float[] c, float[] ch, float[] wa, int index, int[] ifac) {
+		int i, k1, l1, l2 = 0;
+		int na;
+		int nf, ip = 0, iw, ix2, ix3, ido = 0, idl1 = 0;
+
+		nf = ifac[1];
+		na = 0;
+		l1 = 1;
+		iw = 1;
+
+		for (k1 = 0; k1 < nf; k1++) {
+			int state = 100;
+			loop: while (true) {
+				switch (state) {
+				case 100:
+					ip = ifac[k1 + 2];
+					l2 = ip * l1;
+					ido = n / l2;
+					idl1 = ido * l1;
+					if (ip != 4) {
+						state = 103;
+						break;
+					}
+					ix2 = iw + ido;
+					ix3 = ix2 + ido;
+
+					if (na != 0)
+						dradb4(ido, l1, ch, c, wa, index + iw - 1, wa, index + ix2 - 1, wa, index + ix3 - 1);
+					else
+						dradb4(ido, l1, c, ch, wa, index + iw - 1, wa, index + ix2 - 1, wa, index + ix3 - 1);
+					na = 1 - na;
+					state = 115;
+					break;
+				case 103:
+					if (ip != 2) {
+						state = 106;
+						break;
+					}
+
+					if (na != 0)
+						dradb2(ido, l1, ch, c, wa, index + iw - 1);
+					else
+						dradb2(ido, l1, c, ch, wa, index + iw - 1);
+					na = 1 - na;
+					state = 115;
+					break;
+
+				case 106:
+					if (ip != 3) {
+						state = 109;
+						break;
+					}
+
+					ix2 = iw + ido;
+					if (na != 0)
+						dradb3(ido, l1, ch, c, wa, index + iw - 1, wa, index + ix2 - 1);
+					else
+						dradb3(ido, l1, c, ch, wa, index + iw - 1, wa, index + ix2 - 1);
+					na = 1 - na;
+					state = 115;
+					break;
+				case 109:
+					if (na != 0)
+						dradbg(ido, ip, l1, idl1, ch, ch, ch, c, c, wa, index + iw - 1);
+					else
+						dradbg(ido, ip, l1, idl1, c, c, c, ch, ch, wa, index + iw - 1);
+					if (ido == 1)
+						na = 1 - na;
+
+				case 115:
+					l1 = l2;
+					iw += (ip - 1) * ido;
+					break loop;
+				}
+			}
+		}
+		if (na == 0)
+			return;
+		for (i = 0; i < n; i++)
+			c[i] = ch[i];
+	}
+}
diff --git a/sources/teavm/java/com/jcraft/jorbis/DspState.java b/sources/teavm/java/com/jcraft/jorbis/DspState.java
new file mode 100644
index 00000000..997397f9
--- /dev/null
+++ b/sources/teavm/java/com/jcraft/jorbis/DspState.java
@@ -0,0 +1,369 @@
+/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
+/* JOrbis
+ * Copyright (C) 2000 ymnk, JCraft,Inc.
+ *  
+ * Written by: 2000 ymnk<ymnk@jcraft.com>
+ *   
+ * Many thanks to 
+ *   Monty <monty@xiph.org> and 
+ *   The XIPHOPHORUS Company http://www.xiph.org/ .
+ * JOrbis has been based on their awesome works, Vorbis codec.
+ *   
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public License
+ * as published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+   
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Library General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Library General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+package com.jcraft.jorbis;
+
+public class DspState {
+	static final float M_PI = 3.1415926539f;
+	static final int VI_TRANSFORMB = 1;
+	static final int VI_WINDOWB = 1;
+
+	int analysisp;
+	Info vi;
+	int modebits;
+
+	float[][] pcm;
+	int pcm_storage;
+	int pcm_current;
+	int pcm_returned;
+
+	float[] multipliers;
+	int envelope_storage;
+	int envelope_current;
+
+	int eofflag;
+
+	int lW;
+	int W;
+	int nW;
+	int centerW;
+
+	long granulepos;
+	long sequence;
+
+	long glue_bits;
+	long time_bits;
+	long floor_bits;
+	long res_bits;
+
+	// local lookup storage
+	float[][][][][] window; // block, leadin, leadout, type
+	Object[][] transform;
+	CodeBook[] fullbooks;
+	// backend lookups are tied to the mode, not the backend or naked mapping
+	Object[] mode;
+
+	// local storage, only used on the encoding side. This way the
+	// application does not need to worry about freeing some packets'
+	// memory and not others'; packet storage is always tracked.
+	// Cleared next call to a _dsp_ function
+	byte[] header;
+	byte[] header1;
+	byte[] header2;
+
+	public DspState() {
+		transform = new Object[2][];
+		window = new float[2][][][][];
+		window[0] = new float[2][][][];
+		window[0][0] = new float[2][][];
+		window[0][1] = new float[2][][];
+		window[0][0][0] = new float[2][];
+		window[0][0][1] = new float[2][];
+		window[0][1][0] = new float[2][];
+		window[0][1][1] = new float[2][];
+		window[1] = new float[2][][][];
+		window[1][0] = new float[2][][];
+		window[1][1] = new float[2][][];
+		window[1][0][0] = new float[2][];
+		window[1][0][1] = new float[2][];
+		window[1][1][0] = new float[2][];
+		window[1][1][1] = new float[2][];
+	}
+
+	static float[] window(int type, int window, int left, int right) {
+		float[] ret = new float[window];
+		switch (type) {
+		case 0:
+		// The 'vorbis window' (window 0) is sin(sin(x)*sin(x)*2pi)
+		{
+			int leftbegin = window / 4 - left / 2;
+			int rightbegin = window - window / 4 - right / 2;
+
+			for (int i = 0; i < left; i++) {
+				float x = (float) ((i + .5) / left * M_PI / 2.);
+				x = (float) Math.sin(x);
+				x *= x;
+				x *= M_PI / 2.;
+				x = (float) Math.sin(x);
+				ret[i + leftbegin] = x;
+			}
+
+			for (int i = leftbegin + left; i < rightbegin; i++) {
+				ret[i] = 1.f;
+			}
+
+			for (int i = 0; i < right; i++) {
+				float x = (float) ((right - i - .5) / right * M_PI / 2.);
+				x = (float) Math.sin(x);
+				x *= x;
+				x *= M_PI / 2.;
+				x = (float) Math.sin(x);
+				ret[i + rightbegin] = x;
+			}
+		}
+			break;
+		default:
+			// free(ret);
+			return (null);
+		}
+		return (ret);
+	}
+
+	// Analysis side code, but directly related to blocking. Thus it's
+	// here and not in analysis.c (which is for analysis transforms only).
+	// The init is here because some of it is shared
+
+	int init(Info vi, boolean encp) {
+		this.vi = vi;
+		modebits = Util.ilog2(vi.modes);
+
+		transform[0] = new Object[VI_TRANSFORMB];
+		transform[1] = new Object[VI_TRANSFORMB];
+
+		// MDCT is tranform 0
+
+		transform[0][0] = new Mdct();
+		transform[1][0] = new Mdct();
+		((Mdct) transform[0][0]).init(vi.blocksizes[0]);
+		((Mdct) transform[1][0]).init(vi.blocksizes[1]);
+
+		window[0][0][0] = new float[VI_WINDOWB][];
+		window[0][0][1] = window[0][0][0];
+		window[0][1][0] = window[0][0][0];
+		window[0][1][1] = window[0][0][0];
+		window[1][0][0] = new float[VI_WINDOWB][];
+		window[1][0][1] = new float[VI_WINDOWB][];
+		window[1][1][0] = new float[VI_WINDOWB][];
+		window[1][1][1] = new float[VI_WINDOWB][];
+
+		for (int i = 0; i < VI_WINDOWB; i++) {
+			window[0][0][0][i] = window(i, vi.blocksizes[0], vi.blocksizes[0] / 2, vi.blocksizes[0] / 2);
+			window[1][0][0][i] = window(i, vi.blocksizes[1], vi.blocksizes[0] / 2, vi.blocksizes[0] / 2);
+			window[1][0][1][i] = window(i, vi.blocksizes[1], vi.blocksizes[0] / 2, vi.blocksizes[1] / 2);
+			window[1][1][0][i] = window(i, vi.blocksizes[1], vi.blocksizes[1] / 2, vi.blocksizes[0] / 2);
+			window[1][1][1][i] = window(i, vi.blocksizes[1], vi.blocksizes[1] / 2, vi.blocksizes[1] / 2);
+		}
+
+		fullbooks = new CodeBook[vi.books];
+		for (int i = 0; i < vi.books; i++) {
+			fullbooks[i] = new CodeBook();
+			fullbooks[i].init_decode(vi.book_param[i]);
+		}
+
+		// initialize the storage vectors to a decent size greater than the
+		// minimum
+
+		pcm_storage = 8192; // we'll assume later that we have
+		// a minimum of twice the blocksize of
+		// accumulated samples in analysis
+		pcm = new float[vi.channels][];
+		{
+			for (int i = 0; i < vi.channels; i++) {
+				pcm[i] = new float[pcm_storage];
+			}
+		}
+
+		// all 1 (large block) or 0 (small block)
+		// explicitly set for the sake of clarity
+		lW = 0; // previous window size
+		W = 0; // current window size
+
+		// all vector indexes; multiples of samples_per_envelope_step
+		centerW = vi.blocksizes[1] / 2;
+
+		pcm_current = centerW;
+
+		// initialize all the mapping/backend lookups
+		mode = new Object[vi.modes];
+		for (int i = 0; i < vi.modes; i++) {
+			int mapnum = vi.mode_param[i].mapping;
+			int maptype = vi.map_type[mapnum];
+			mode[i] = FuncMapping.mapping_P[maptype].look(this, vi.mode_param[i], vi.map_param[mapnum]);
+		}
+		return (0);
+	}
+
+	public int synthesis_init(Info vi) {
+		init(vi, false);
+		// Adjust centerW to allow an easier mechanism for determining output
+		pcm_returned = centerW;
+		centerW -= vi.blocksizes[W] / 4 + vi.blocksizes[lW] / 4;
+		granulepos = -1;
+		sequence = -1;
+		return (0);
+	}
+
+	DspState(Info vi) {
+		this();
+		init(vi, false);
+		// Adjust centerW to allow an easier mechanism for determining output
+		pcm_returned = centerW;
+		centerW -= vi.blocksizes[W] / 4 + vi.blocksizes[lW] / 4;
+		granulepos = -1;
+		sequence = -1;
+	}
+
+	// Unike in analysis, the window is only partially applied for each
+	// block. The time domain envelope is not yet handled at the point of
+	// calling (as it relies on the previous block).
+
+	public int synthesis_blockin(Block vb) {
+		// Shift out any PCM/multipliers that we returned previously
+		// centerW is currently the center of the last block added
+		if (centerW > vi.blocksizes[1] / 2 && pcm_returned > 8192) {
+			// don't shift too much; we need to have a minimum PCM buffer of
+			// 1/2 long block
+
+			int shiftPCM = centerW - vi.blocksizes[1] / 2;
+			shiftPCM = (pcm_returned < shiftPCM ? pcm_returned : shiftPCM);
+
+			pcm_current -= shiftPCM;
+			centerW -= shiftPCM;
+			pcm_returned -= shiftPCM;
+			if (shiftPCM != 0) {
+				for (int i = 0; i < vi.channels; i++) {
+					System.arraycopy(pcm[i], shiftPCM, pcm[i], 0, pcm_current);
+				}
+			}
+		}
+
+		lW = W;
+		W = vb.W;
+		nW = -1;
+
+		glue_bits += vb.glue_bits;
+		time_bits += vb.time_bits;
+		floor_bits += vb.floor_bits;
+		res_bits += vb.res_bits;
+
+		if (sequence + 1 != vb.sequence)
+			granulepos = -1; // out of sequence; lose count
+
+		sequence = vb.sequence;
+
+		{
+			int sizeW = vi.blocksizes[W];
+			int _centerW = centerW + vi.blocksizes[lW] / 4 + sizeW / 4;
+			int beginW = _centerW - sizeW / 2;
+			int endW = beginW + sizeW;
+			int beginSl = 0;
+			int endSl = 0;
+
+			// Do we have enough PCM/mult storage for the block?
+			if (endW > pcm_storage) {
+				// expand the storage
+				pcm_storage = endW + vi.blocksizes[1];
+				for (int i = 0; i < vi.channels; i++) {
+					float[] foo = new float[pcm_storage];
+					System.arraycopy(pcm[i], 0, foo, 0, pcm[i].length);
+					pcm[i] = foo;
+				}
+			}
+
+			// overlap/add PCM
+			switch (W) {
+			case 0:
+				beginSl = 0;
+				endSl = vi.blocksizes[0] / 2;
+				break;
+			case 1:
+				beginSl = vi.blocksizes[1] / 4 - vi.blocksizes[lW] / 4;
+				endSl = beginSl + vi.blocksizes[lW] / 2;
+				break;
+			}
+
+			for (int j = 0; j < vi.channels; j++) {
+				int _pcm = beginW;
+				// the overlap/add section
+				int i = 0;
+				for (i = beginSl; i < endSl; i++) {
+					pcm[j][_pcm + i] += vb.pcm[j][i];
+				}
+				// the remaining section
+				for (; i < sizeW; i++) {
+					pcm[j][_pcm + i] = vb.pcm[j][i];
+				}
+			}
+
+			// track the frame number... This is for convenience, but also
+			// making sure our last packet doesn't end with added padding. If
+			// the last packet is partial, the number of samples we'll have to
+			// return will be past the vb->granulepos.
+			//
+			// This is not foolproof! It will be confused if we begin
+			// decoding at the last page after a seek or hole. In that case,
+			// we don't have a starting point to judge where the last frame
+			// is. For this reason, vorbisfile will always try to make sure
+			// it reads the last two marked pages in proper sequence
+
+			if (granulepos == -1) {
+				granulepos = vb.granulepos;
+			} else {
+				granulepos += (_centerW - centerW);
+				if (vb.granulepos != -1 && granulepos != vb.granulepos) {
+					if (granulepos > vb.granulepos && vb.eofflag != 0) {
+						// partial last frame. Strip the padding off
+						_centerW -= (granulepos - vb.granulepos);
+					} // else{ Shouldn't happen *unless* the bitstream is out of
+						// spec. Either way, believe the bitstream }
+					granulepos = vb.granulepos;
+				}
+			}
+
+			// Update, cleanup
+
+			centerW = _centerW;
+			pcm_current = endW;
+			if (vb.eofflag != 0)
+				eofflag = 1;
+		}
+		return (0);
+	}
+
+	// pcm==NULL indicates we just want the pending samples, no more
+	public int synthesis_pcmout(float[][][] _pcm, int[] index) {
+		if (pcm_returned < centerW) {
+			if (_pcm != null) {
+				for (int i = 0; i < vi.channels; i++) {
+					index[i] = pcm_returned;
+				}
+				_pcm[0] = pcm;
+			}
+			return (centerW - pcm_returned);
+		}
+		return (0);
+	}
+
+	public int synthesis_read(int bytes) {
+		if (bytes != 0 && pcm_returned + bytes > centerW)
+			return (-1);
+		pcm_returned += bytes;
+		return (0);
+	}
+
+	public void clear() {
+	}
+}
diff --git a/sources/teavm/java/com/jcraft/jorbis/Floor0.java b/sources/teavm/java/com/jcraft/jorbis/Floor0.java
new file mode 100644
index 00000000..b2d49c6c
--- /dev/null
+++ b/sources/teavm/java/com/jcraft/jorbis/Floor0.java
@@ -0,0 +1,332 @@
+/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
+/* JOrbis
+ * Copyright (C) 2000 ymnk, JCraft,Inc.
+ *  
+ * Written by: 2000 ymnk<ymnk@jcraft.com>
+ *   
+ * Many thanks to 
+ *   Monty <monty@xiph.org> and 
+ *   The XIPHOPHORUS Company http://www.xiph.org/ .
+ * JOrbis has been based on their awesome works, Vorbis codec.
+ *   
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public License
+ * as published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+   
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Library General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Library General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+package com.jcraft.jorbis;
+
+import com.jcraft.jogg.*;
+
+class Floor0 extends FuncFloor {
+
+	void pack(Object i, Buffer opb) {
+		InfoFloor0 info = (InfoFloor0) i;
+		opb.write(info.order, 8);
+		opb.write(info.rate, 16);
+		opb.write(info.barkmap, 16);
+		opb.write(info.ampbits, 6);
+		opb.write(info.ampdB, 8);
+		opb.write(info.numbooks - 1, 4);
+		for (int j = 0; j < info.numbooks; j++)
+			opb.write(info.books[j], 8);
+	}
+
+	Object unpack(Info vi, Buffer opb) {
+		InfoFloor0 info = new InfoFloor0();
+		info.order = opb.read(8);
+		info.rate = opb.read(16);
+		info.barkmap = opb.read(16);
+		info.ampbits = opb.read(6);
+		info.ampdB = opb.read(8);
+		info.numbooks = opb.read(4) + 1;
+
+		if ((info.order < 1) || (info.rate < 1) || (info.barkmap < 1) || (info.numbooks < 1)) {
+			return (null);
+		}
+
+		for (int j = 0; j < info.numbooks; j++) {
+			info.books[j] = opb.read(8);
+			if (info.books[j] < 0 || info.books[j] >= vi.books) {
+				return (null);
+			}
+		}
+		return (info);
+	}
+
+	Object look(DspState vd, InfoMode mi, Object i) {
+		float scale;
+		Info vi = vd.vi;
+		InfoFloor0 info = (InfoFloor0) i;
+		LookFloor0 look = new LookFloor0();
+		look.m = info.order;
+		look.n = vi.blocksizes[mi.blockflag] / 2;
+		look.ln = info.barkmap;
+		look.vi = info;
+		look.lpclook.init(look.ln, look.m);
+
+		// we choose a scaling constant so that:
+		scale = look.ln / toBARK((float) (info.rate / 2.));
+
+		// the mapping from a linear scale to a smaller bark scale is
+		// straightforward. We do *not* make sure that the linear mapping
+		// does not skip bark-scale bins; the decoder simply skips them and
+		// the encoder may do what it wishes in filling them. They're
+		// necessary in some mapping combinations to keep the scale spacing
+		// accurate
+		look.linearmap = new int[look.n];
+		for (int j = 0; j < look.n; j++) {
+			int val = (int) Math.floor(toBARK((float) ((info.rate / 2.) / look.n * j)) * scale); // bark numbers
+																									// represent band
+																									// edges
+			if (val >= look.ln)
+				val = look.ln; // guard against the approximation
+			look.linearmap[j] = val;
+		}
+		return look;
+	}
+
+	static float toBARK(float f) {
+		return (float) (13.1 * Math.atan(.00074 * (f)) + 2.24 * Math.atan((f) * (f) * 1.85e-8) + 1e-4 * (f));
+	}
+
+	Object state(Object i) {
+		EchstateFloor0 state = new EchstateFloor0();
+		InfoFloor0 info = (InfoFloor0) i;
+
+		// a safe size if usually too big (dim==1)
+		state.codewords = new int[info.order];
+		state.curve = new float[info.barkmap];
+		state.frameno = -1;
+		return (state);
+	}
+
+	void free_info(Object i) {
+	}
+
+	void free_look(Object i) {
+	}
+
+	void free_state(Object vs) {
+	}
+
+	int forward(Block vb, Object i, float[] in, float[] out, Object vs) {
+		return 0;
+	}
+
+	float[] lsp = null;
+
+	int inverse(Block vb, Object i, float[] out) {
+		// System.err.println("Floor0.inverse "+i.getClass()+"]");
+		LookFloor0 look = (LookFloor0) i;
+		InfoFloor0 info = look.vi;
+		int ampraw = vb.opb.read(info.ampbits);
+		if (ampraw > 0) { // also handles the -1 out of data case
+			int maxval = (1 << info.ampbits) - 1;
+			float amp = (float) ampraw / maxval * info.ampdB;
+			int booknum = vb.opb.read(Util.ilog(info.numbooks));
+
+			if (booknum != -1 && booknum < info.numbooks) {
+
+				synchronized (this) {
+					if (lsp == null || lsp.length < look.m) {
+						lsp = new float[look.m];
+					} else {
+						for (int j = 0; j < look.m; j++)
+							lsp[j] = 0.f;
+					}
+
+					CodeBook b = vb.vd.fullbooks[info.books[booknum]];
+					float last = 0.f;
+
+					for (int j = 0; j < look.m; j++)
+						out[j] = 0.0f;
+
+					for (int j = 0; j < look.m; j += b.dim) {
+						if (b.decodevs(lsp, j, vb.opb, 1, -1) == -1) {
+							for (int k = 0; k < look.n; k++)
+								out[k] = 0.0f;
+							return (0);
+						}
+					}
+					for (int j = 0; j < look.m;) {
+						for (int k = 0; k < b.dim; k++, j++)
+							lsp[j] += last;
+						last = lsp[j - 1];
+					}
+					// take the coefficients back to a spectral envelope curve
+					Lsp.lsp_to_curve(out, look.linearmap, look.n, look.ln, lsp, look.m, amp, info.ampdB);
+
+					return (1);
+				}
+			}
+		}
+		return (0);
+	}
+
+	Object inverse1(Block vb, Object i, Object memo) {
+		LookFloor0 look = (LookFloor0) i;
+		InfoFloor0 info = look.vi;
+		float[] lsp = null;
+		if (memo instanceof float[]) {
+			lsp = (float[]) memo;
+		}
+
+		int ampraw = vb.opb.read(info.ampbits);
+		if (ampraw > 0) { // also handles the -1 out of data case
+			int maxval = (1 << info.ampbits) - 1;
+			float amp = (float) ampraw / maxval * info.ampdB;
+			int booknum = vb.opb.read(Util.ilog(info.numbooks));
+
+			if (booknum != -1 && booknum < info.numbooks) {
+				CodeBook b = vb.vd.fullbooks[info.books[booknum]];
+				float last = 0.f;
+
+				if (lsp == null || lsp.length < look.m + 1) {
+					lsp = new float[look.m + 1];
+				} else {
+					for (int j = 0; j < lsp.length; j++)
+						lsp[j] = 0.f;
+				}
+
+				for (int j = 0; j < look.m; j += b.dim) {
+					if (b.decodev_set(lsp, j, vb.opb, b.dim) == -1) {
+						return (null);
+					}
+				}
+
+				for (int j = 0; j < look.m;) {
+					for (int k = 0; k < b.dim; k++, j++)
+						lsp[j] += last;
+					last = lsp[j - 1];
+				}
+				lsp[look.m] = amp;
+				return (lsp);
+			}
+		}
+		return (null);
+	}
+
+	int inverse2(Block vb, Object i, Object memo, float[] out) {
+		LookFloor0 look = (LookFloor0) i;
+		InfoFloor0 info = look.vi;
+
+		if (memo != null) {
+			float[] lsp = (float[]) memo;
+			float amp = lsp[look.m];
+
+			Lsp.lsp_to_curve(out, look.linearmap, look.n, look.ln, lsp, look.m, amp, info.ampdB);
+			return (1);
+		}
+		for (int j = 0; j < look.n; j++) {
+			out[j] = 0.f;
+		}
+		return (0);
+	}
+
+	static float fromdB(float x) {
+		return (float) (Math.exp((x) * .11512925));
+	}
+
+	static void lsp_to_lpc(float[] lsp, float[] lpc, int m) {
+		int i, j, m2 = m / 2;
+		float[] O = new float[m2];
+		float[] E = new float[m2];
+		float A;
+		float[] Ae = new float[m2 + 1];
+		float[] Ao = new float[m2 + 1];
+		float B;
+		float[] Be = new float[m2];
+		float[] Bo = new float[m2];
+		float temp;
+
+		// even/odd roots setup
+		for (i = 0; i < m2; i++) {
+			O[i] = (float) (-2. * Math.cos(lsp[i * 2]));
+			E[i] = (float) (-2. * Math.cos(lsp[i * 2 + 1]));
+		}
+
+		// set up impulse response
+		for (j = 0; j < m2; j++) {
+			Ae[j] = 0.f;
+			Ao[j] = 1.f;
+			Be[j] = 0.f;
+			Bo[j] = 1.f;
+		}
+		Ao[j] = 1.f;
+		Ae[j] = 1.f;
+
+		// run impulse response
+		for (i = 1; i < m + 1; i++) {
+			A = B = 0.f;
+			for (j = 0; j < m2; j++) {
+				temp = O[j] * Ao[j] + Ae[j];
+				Ae[j] = Ao[j];
+				Ao[j] = A;
+				A += temp;
+
+				temp = E[j] * Bo[j] + Be[j];
+				Be[j] = Bo[j];
+				Bo[j] = B;
+				B += temp;
+			}
+			lpc[i - 1] = (A + Ao[j] + B - Ae[j]) / 2;
+			Ao[j] = A;
+			Ae[j] = B;
+		}
+	}
+
+	static void lpc_to_curve(float[] curve, float[] lpc, float amp, LookFloor0 l, String name, int frameno) {
+		// l->m+1 must be less than l->ln, but guard in case we get a bad stream
+		float[] lcurve = new float[Math.max(l.ln * 2, l.m * 2 + 2)];
+
+		if (amp == 0) {
+			for (int j = 0; j < l.n; j++)
+				curve[j] = 0.0f;
+			return;
+		}
+		l.lpclook.lpc_to_curve(lcurve, lpc, amp);
+
+		for (int i = 0; i < l.n; i++)
+			curve[i] = lcurve[l.linearmap[i]];
+	}
+
+	class InfoFloor0 {
+		int order;
+		int rate;
+		int barkmap;
+
+		int ampbits;
+		int ampdB;
+
+		int numbooks; // <= 16
+		int[] books = new int[16];
+	}
+
+	class LookFloor0 {
+		int n;
+		int ln;
+		int m;
+		int[] linearmap;
+
+		InfoFloor0 vi;
+		Lpc lpclook = new Lpc();
+	}
+
+	class EchstateFloor0 {
+		int[] codewords;
+		float[] curve;
+		long frameno;
+		long codes;
+	}
+}
diff --git a/sources/teavm/java/com/jcraft/jorbis/Floor1.java b/sources/teavm/java/com/jcraft/jorbis/Floor1.java
new file mode 100644
index 00000000..c9f77c3f
--- /dev/null
+++ b/sources/teavm/java/com/jcraft/jorbis/Floor1.java
@@ -0,0 +1,584 @@
+/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
+/* JOrbis
+ * Copyright (C) 2000 ymnk, JCraft,Inc.
+ *  
+ * Written by: 2000 ymnk<ymnk@jcraft.com>
+ *   
+ * Many thanks to 
+ *   Monty <monty@xiph.org> and 
+ *   The XIPHOPHORUS Company http://www.xiph.org/ .
+ * JOrbis has been based on their awesome works, Vorbis codec.
+ *   
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public License
+ * as published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+   
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Library General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Library General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+package com.jcraft.jorbis;
+
+import com.jcraft.jogg.*;
+
+class Floor1 extends FuncFloor {
+	static final int floor1_rangedb = 140;
+	static final int VIF_POSIT = 63;
+
+	void pack(Object i, Buffer opb) {
+		InfoFloor1 info = (InfoFloor1) i;
+
+		int count = 0;
+		int rangebits;
+		int maxposit = info.postlist[1];
+		int maxclass = -1;
+
+		/* save out partitions */
+		opb.write(info.partitions, 5); /* only 0 to 31 legal */
+		for (int j = 0; j < info.partitions; j++) {
+			opb.write(info.partitionclass[j], 4); /* only 0 to 15 legal */
+			if (maxclass < info.partitionclass[j])
+				maxclass = info.partitionclass[j];
+		}
+
+		/* save out partition classes */
+		for (int j = 0; j < maxclass + 1; j++) {
+			opb.write(info.class_dim[j] - 1, 3); /* 1 to 8 */
+			opb.write(info.class_subs[j], 2); /* 0 to 3 */
+			if (info.class_subs[j] != 0) {
+				opb.write(info.class_book[j], 8);
+			}
+			for (int k = 0; k < (1 << info.class_subs[j]); k++) {
+				opb.write(info.class_subbook[j][k] + 1, 8);
+			}
+		}
+
+		/* save out the post list */
+		opb.write(info.mult - 1, 2); /* only 1,2,3,4 legal now */
+		opb.write(Util.ilog2(maxposit), 4);
+		rangebits = Util.ilog2(maxposit);
+
+		for (int j = 0, k = 0; j < info.partitions; j++) {
+			count += info.class_dim[info.partitionclass[j]];
+			for (; k < count; k++) {
+				opb.write(info.postlist[k + 2], rangebits);
+			}
+		}
+	}
+
+	Object unpack(Info vi, Buffer opb) {
+		int count = 0, maxclass = -1, rangebits;
+		InfoFloor1 info = new InfoFloor1();
+
+		/* read partitions */
+		info.partitions = opb.read(5); /* only 0 to 31 legal */
+		for (int j = 0; j < info.partitions; j++) {
+			info.partitionclass[j] = opb.read(4); /* only 0 to 15 legal */
+			if (maxclass < info.partitionclass[j])
+				maxclass = info.partitionclass[j];
+		}
+
+		/* read partition classes */
+		for (int j = 0; j < maxclass + 1; j++) {
+			info.class_dim[j] = opb.read(3) + 1; /* 1 to 8 */
+			info.class_subs[j] = opb.read(2); /* 0,1,2,3 bits */
+			if (info.class_subs[j] < 0) {
+				info.free();
+				return (null);
+			}
+			if (info.class_subs[j] != 0) {
+				info.class_book[j] = opb.read(8);
+			}
+			if (info.class_book[j] < 0 || info.class_book[j] >= vi.books) {
+				info.free();
+				return (null);
+			}
+			for (int k = 0; k < (1 << info.class_subs[j]); k++) {
+				info.class_subbook[j][k] = opb.read(8) - 1;
+				if (info.class_subbook[j][k] < -1 || info.class_subbook[j][k] >= vi.books) {
+					info.free();
+					return (null);
+				}
+			}
+		}
+
+		/* read the post list */
+		info.mult = opb.read(2) + 1; /* only 1,2,3,4 legal now */
+		rangebits = opb.read(4);
+
+		for (int j = 0, k = 0; j < info.partitions; j++) {
+			count += info.class_dim[info.partitionclass[j]];
+			for (; k < count; k++) {
+				int t = info.postlist[k + 2] = opb.read(rangebits);
+				if (t < 0 || t >= (1 << rangebits)) {
+					info.free();
+					return (null);
+				}
+			}
+		}
+		info.postlist[0] = 0;
+		info.postlist[1] = 1 << rangebits;
+
+		return (info);
+	}
+
+	Object look(DspState vd, InfoMode mi, Object i) {
+		int _n = 0;
+
+		int[] sortpointer = new int[VIF_POSIT + 2];
+
+		// Info vi=vd.vi;
+
+		InfoFloor1 info = (InfoFloor1) i;
+		LookFloor1 look = new LookFloor1();
+		look.vi = info;
+		look.n = info.postlist[1];
+
+		/*
+		 * we drop each position value in-between already decoded values, and use linear
+		 * interpolation to predict each new value past the edges. The positions are
+		 * read in the order of the position list... we precompute the bounding
+		 * positions in the lookup. Of course, the neighbors can change (if a position
+		 * is declined), but this is an initial mapping
+		 */
+
+		for (int j = 0; j < info.partitions; j++) {
+			_n += info.class_dim[info.partitionclass[j]];
+		}
+		_n += 2;
+		look.posts = _n;
+
+		/* also store a sorted position index */
+		for (int j = 0; j < _n; j++) {
+			sortpointer[j] = j;
+		}
+		// qsort(sortpointer,n,sizeof(int),icomp); // !!
+
+		int foo;
+		for (int j = 0; j < _n - 1; j++) {
+			for (int k = j; k < _n; k++) {
+				if (info.postlist[sortpointer[j]] > info.postlist[sortpointer[k]]) {
+					foo = sortpointer[k];
+					sortpointer[k] = sortpointer[j];
+					sortpointer[j] = foo;
+				}
+			}
+		}
+
+		/* points from sort order back to range number */
+		for (int j = 0; j < _n; j++) {
+			look.forward_index[j] = sortpointer[j];
+		}
+		/* points from range order to sorted position */
+		for (int j = 0; j < _n; j++) {
+			look.reverse_index[look.forward_index[j]] = j;
+		}
+		/* we actually need the post values too */
+		for (int j = 0; j < _n; j++) {
+			look.sorted_index[j] = info.postlist[look.forward_index[j]];
+		}
+
+		/* quantize values to multiplier spec */
+		switch (info.mult) {
+		case 1: /* 1024 -> 256 */
+			look.quant_q = 256;
+			break;
+		case 2: /* 1024 -> 128 */
+			look.quant_q = 128;
+			break;
+		case 3: /* 1024 -> 86 */
+			look.quant_q = 86;
+			break;
+		case 4: /* 1024 -> 64 */
+			look.quant_q = 64;
+			break;
+		default:
+			look.quant_q = -1;
+		}
+
+		/*
+		 * discover our neighbors for decode where we don't use fit flags (that would
+		 * push the neighbors outward)
+		 */
+		for (int j = 0; j < _n - 2; j++) {
+			int lo = 0;
+			int hi = 1;
+			int lx = 0;
+			int hx = look.n;
+			int currentx = info.postlist[j + 2];
+			for (int k = 0; k < j + 2; k++) {
+				int x = info.postlist[k];
+				if (x > lx && x < currentx) {
+					lo = k;
+					lx = x;
+				}
+				if (x < hx && x > currentx) {
+					hi = k;
+					hx = x;
+				}
+			}
+			look.loneighbor[j] = lo;
+			look.hineighbor[j] = hi;
+		}
+
+		return look;
+	}
+
+	void free_info(Object i) {
+	}
+
+	void free_look(Object i) {
+	}
+
+	void free_state(Object vs) {
+	}
+
+	int forward(Block vb, Object i, float[] in, float[] out, Object vs) {
+		return 0;
+	}
+
+	Object inverse1(Block vb, Object ii, Object memo) {
+		LookFloor1 look = (LookFloor1) ii;
+		InfoFloor1 info = look.vi;
+		CodeBook[] books = vb.vd.fullbooks;
+
+		/* unpack wrapped/predicted values from stream */
+		if (vb.opb.read(1) == 1) {
+			int[] fit_value = null;
+			if (memo instanceof int[]) {
+				fit_value = (int[]) memo;
+			}
+			if (fit_value == null || fit_value.length < look.posts) {
+				fit_value = new int[look.posts];
+			} else {
+				for (int i = 0; i < fit_value.length; i++)
+					fit_value[i] = 0;
+			}
+
+			fit_value[0] = vb.opb.read(Util.ilog(look.quant_q - 1));
+			fit_value[1] = vb.opb.read(Util.ilog(look.quant_q - 1));
+
+			/* partition by partition */
+			for (int i = 0, j = 2; i < info.partitions; i++) {
+				int clss = info.partitionclass[i];
+				int cdim = info.class_dim[clss];
+				int csubbits = info.class_subs[clss];
+				int csub = 1 << csubbits;
+				int cval = 0;
+
+				/* decode the partition's first stage cascade value */
+				if (csubbits != 0) {
+					cval = books[info.class_book[clss]].decode(vb.opb);
+
+					if (cval == -1) {
+						return (null);
+					}
+				}
+
+				for (int k = 0; k < cdim; k++) {
+					int book = info.class_subbook[clss][cval & (csub - 1)];
+					cval >>>= csubbits;
+					if (book >= 0) {
+						if ((fit_value[j + k] = books[book].decode(vb.opb)) == -1) {
+							return (null);
+						}
+					} else {
+						fit_value[j + k] = 0;
+					}
+				}
+				j += cdim;
+			}
+
+			/* unwrap positive values and reconsitute via linear interpolation */
+			for (int i = 2; i < look.posts; i++) {
+				int predicted = render_point(info.postlist[look.loneighbor[i - 2]],
+						info.postlist[look.hineighbor[i - 2]], fit_value[look.loneighbor[i - 2]],
+						fit_value[look.hineighbor[i - 2]], info.postlist[i]);
+				int hiroom = look.quant_q - predicted;
+				int loroom = predicted;
+				int room = (hiroom < loroom ? hiroom : loroom) << 1;
+				int val = fit_value[i];
+
+				if (val != 0) {
+					if (val >= room) {
+						if (hiroom > loroom) {
+							val = val - loroom;
+						} else {
+							val = -1 - (val - hiroom);
+						}
+					} else {
+						if ((val & 1) != 0) {
+							val = -((val + 1) >>> 1);
+						} else {
+							val >>= 1;
+						}
+					}
+
+					fit_value[i] = val + predicted;
+					fit_value[look.loneighbor[i - 2]] &= 0x7fff;
+					fit_value[look.hineighbor[i - 2]] &= 0x7fff;
+				} else {
+					fit_value[i] = predicted | 0x8000;
+				}
+			}
+			return (fit_value);
+		}
+
+		return (null);
+	}
+
+	private static int render_point(int x0, int x1, int y0, int y1, int x) {
+		y0 &= 0x7fff; /* mask off flag */
+		y1 &= 0x7fff;
+
+		{
+			int dy = y1 - y0;
+			int adx = x1 - x0;
+			int ady = Math.abs(dy);
+			int err = ady * (x - x0);
+
+			int off = (int) (err / adx);
+			if (dy < 0)
+				return (y0 - off);
+			return (y0 + off);
+		}
+	}
+
+	int inverse2(Block vb, Object i, Object memo, float[] out) {
+		LookFloor1 look = (LookFloor1) i;
+		InfoFloor1 info = look.vi;
+		int n = vb.vd.vi.blocksizes[vb.mode] / 2;
+
+		if (memo != null) {
+			/* render the lines */
+			int[] fit_value = (int[]) memo;
+			int hx = 0;
+			int lx = 0;
+			int ly = fit_value[0] * info.mult;
+			for (int j = 1; j < look.posts; j++) {
+				int current = look.forward_index[j];
+				int hy = fit_value[current] & 0x7fff;
+				if (hy == fit_value[current]) {
+					hy *= info.mult;
+					hx = info.postlist[current];
+
+					render_line(lx, hx, ly, hy, out);
+
+					lx = hx;
+					ly = hy;
+				}
+			}
+			for (int j = hx; j < n; j++) {
+				out[j] *= out[j - 1]; /* be certain */
+			}
+			return (1);
+		}
+		for (int j = 0; j < n; j++) {
+			out[j] = 0.f;
+		}
+		return (0);
+	}
+
+	private static float[] FLOOR_fromdB_LOOKUP = { 1.0649863e-07F, 1.1341951e-07F, 1.2079015e-07F, 1.2863978e-07F,
+			1.3699951e-07F, 1.4590251e-07F, 1.5538408e-07F, 1.6548181e-07F, 1.7623575e-07F, 1.8768855e-07F,
+			1.9988561e-07F, 2.128753e-07F, 2.2670913e-07F, 2.4144197e-07F, 2.5713223e-07F, 2.7384213e-07F,
+			2.9163793e-07F, 3.1059021e-07F, 3.3077411e-07F, 3.5226968e-07F, 3.7516214e-07F, 3.9954229e-07F,
+			4.2550680e-07F, 4.5315863e-07F, 4.8260743e-07F, 5.1396998e-07F, 5.4737065e-07F, 5.8294187e-07F,
+			6.2082472e-07F, 6.6116941e-07F, 7.0413592e-07F, 7.4989464e-07F, 7.9862701e-07F, 8.5052630e-07F,
+			9.0579828e-07F, 9.6466216e-07F, 1.0273513e-06F, 1.0941144e-06F, 1.1652161e-06F, 1.2409384e-06F,
+			1.3215816e-06F, 1.4074654e-06F, 1.4989305e-06F, 1.5963394e-06F, 1.7000785e-06F, 1.8105592e-06F,
+			1.9282195e-06F, 2.0535261e-06F, 2.1869758e-06F, 2.3290978e-06F, 2.4804557e-06F, 2.6416497e-06F,
+			2.8133190e-06F, 2.9961443e-06F, 3.1908506e-06F, 3.3982101e-06F, 3.6190449e-06F, 3.8542308e-06F,
+			4.1047004e-06F, 4.3714470e-06F, 4.6555282e-06F, 4.9580707e-06F, 5.2802740e-06F, 5.6234160e-06F,
+			5.9888572e-06F, 6.3780469e-06F, 6.7925283e-06F, 7.2339451e-06F, 7.7040476e-06F, 8.2047000e-06F,
+			8.7378876e-06F, 9.3057248e-06F, 9.9104632e-06F, 1.0554501e-05F, 1.1240392e-05F, 1.1970856e-05F,
+			1.2748789e-05F, 1.3577278e-05F, 1.4459606e-05F, 1.5399272e-05F, 1.6400004e-05F, 1.7465768e-05F,
+			1.8600792e-05F, 1.9809576e-05F, 2.1096914e-05F, 2.2467911e-05F, 2.3928002e-05F, 2.5482978e-05F,
+			2.7139006e-05F, 2.8902651e-05F, 3.0780908e-05F, 3.2781225e-05F, 3.4911534e-05F, 3.7180282e-05F,
+			3.9596466e-05F, 4.2169667e-05F, 4.4910090e-05F, 4.7828601e-05F, 5.0936773e-05F, 5.4246931e-05F,
+			5.7772202e-05F, 6.1526565e-05F, 6.5524908e-05F, 6.9783085e-05F, 7.4317983e-05F, 7.9147585e-05F,
+			8.4291040e-05F, 8.9768747e-05F, 9.5602426e-05F, 0.00010181521F, 0.00010843174F, 0.00011547824F,
+			0.00012298267F, 0.00013097477F, 0.00013948625F, 0.00014855085F, 0.00015820453F, 0.00016848555F,
+			0.00017943469F, 0.00019109536F, 0.00020351382F, 0.00021673929F, 0.00023082423F, 0.00024582449F,
+			0.00026179955F, 0.00027881276F, 0.00029693158F, 0.00031622787F, 0.00033677814F, 0.00035866388F,
+			0.00038197188F, 0.00040679456F, 0.00043323036F, 0.00046138411F, 0.00049136745F, 0.00052329927F,
+			0.00055730621F, 0.00059352311F, 0.00063209358F, 0.00067317058F, 0.00071691700F, 0.00076350630F,
+			0.00081312324F, 0.00086596457F, 0.00092223983F, 0.00098217216F, 0.0010459992F, 0.0011139742F, 0.0011863665F,
+			0.0012634633F, 0.0013455702F, 0.0014330129F, 0.0015261382F, 0.0016253153F, 0.0017309374F, 0.0018434235F,
+			0.0019632195F, 0.0020908006F, 0.0022266726F, 0.0023713743F, 0.0025254795F, 0.0026895994F, 0.0028643847F,
+			0.0030505286F, 0.0032487691F, 0.0034598925F, 0.0036847358F, 0.0039241906F, 0.0041792066F, 0.0044507950F,
+			0.0047400328F, 0.0050480668F, 0.0053761186F, 0.0057254891F, 0.0060975636F, 0.0064938176F, 0.0069158225F,
+			0.0073652516F, 0.0078438871F, 0.0083536271F, 0.0088964928F, 0.009474637F, 0.010090352F, 0.010746080F,
+			0.011444421F, 0.012188144F, 0.012980198F, 0.013823725F, 0.014722068F, 0.015678791F, 0.016697687F,
+			0.017782797F, 0.018938423F, 0.020169149F, 0.021479854F, 0.022875735F, 0.024362330F, 0.025945531F,
+			0.027631618F, 0.029427276F, 0.031339626F, 0.033376252F, 0.035545228F, 0.037855157F, 0.040315199F,
+			0.042935108F, 0.045725273F, 0.048696758F, 0.051861348F, 0.055231591F, 0.058820850F, 0.062643361F,
+			0.066714279F, 0.071049749F, 0.075666962F, 0.080584227F, 0.085821044F, 0.091398179F, 0.097337747F,
+			0.10366330F, 0.11039993F, 0.11757434F, 0.12521498F, 0.13335215F, 0.14201813F, 0.15124727F, 0.16107617F,
+			0.17154380F, 0.18269168F, 0.19456402F, 0.20720788F, 0.22067342F, 0.23501402F, 0.25028656F, 0.26655159F,
+			0.28387361F, 0.30232132F, 0.32196786F, 0.34289114F, 0.36517414F, 0.38890521F, 0.41417847F, 0.44109412F,
+			0.46975890F, 0.50028648F, 0.53279791F, 0.56742212F, 0.60429640F, 0.64356699F, 0.68538959F, 0.72993007F,
+			0.77736504F, 0.82788260F, 0.88168307F, 0.9389798F, 1.F };
+
+	private static void render_line(int x0, int x1, int y0, int y1, float[] d) {
+		int dy = y1 - y0;
+		int adx = x1 - x0;
+		int ady = Math.abs(dy);
+		int base = dy / adx;
+		int sy = (dy < 0 ? base - 1 : base + 1);
+		int x = x0;
+		int y = y0;
+		int err = 0;
+
+		ady -= Math.abs(base * adx);
+
+		d[x] *= FLOOR_fromdB_LOOKUP[y];
+		while (++x < x1) {
+			err = err + ady;
+			if (err >= adx) {
+				err -= adx;
+				y += sy;
+			} else {
+				y += base;
+			}
+			d[x] *= FLOOR_fromdB_LOOKUP[y];
+		}
+	}
+
+	class InfoFloor1 {
+		static final int VIF_POSIT = 63;
+		static final int VIF_CLASS = 16;
+		static final int VIF_PARTS = 31;
+
+		int partitions; /* 0 to 31 */
+		int[] partitionclass = new int[VIF_PARTS]; /* 0 to 15 */
+
+		int[] class_dim = new int[VIF_CLASS]; /* 1 to 8 */
+		int[] class_subs = new int[VIF_CLASS]; /* 0,1,2,3 (bits: 1<<n poss) */
+		int[] class_book = new int[VIF_CLASS]; /* subs ^ dim entries */
+		int[][] class_subbook = new int[VIF_CLASS][]; /* [VIF_CLASS][subs] */
+
+		int mult; /* 1 2 3 or 4 */
+		int[] postlist = new int[VIF_POSIT + 2]; /* first two implicit */
+
+		/* encode side analysis parameters */
+		float maxover;
+		float maxunder;
+		float maxerr;
+
+		int twofitminsize;
+		int twofitminused;
+		int twofitweight;
+		float twofitatten;
+		int unusedminsize;
+		int unusedmin_n;
+
+		int n;
+
+		InfoFloor1() {
+			for (int i = 0; i < class_subbook.length; i++) {
+				class_subbook[i] = new int[8];
+			}
+		}
+
+		void free() {
+			partitionclass = null;
+			class_dim = null;
+			class_subs = null;
+			class_book = null;
+			class_subbook = null;
+			postlist = null;
+		}
+
+		Object copy_info() {
+			InfoFloor1 info = this;
+			InfoFloor1 ret = new InfoFloor1();
+
+			ret.partitions = info.partitions;
+			System.arraycopy(info.partitionclass, 0, ret.partitionclass, 0, VIF_PARTS);
+			System.arraycopy(info.class_dim, 0, ret.class_dim, 0, VIF_CLASS);
+			System.arraycopy(info.class_subs, 0, ret.class_subs, 0, VIF_CLASS);
+			System.arraycopy(info.class_book, 0, ret.class_book, 0, VIF_CLASS);
+
+			for (int j = 0; j < VIF_CLASS; j++) {
+				System.arraycopy(info.class_subbook[j], 0, ret.class_subbook[j], 0, 8);
+			}
+
+			ret.mult = info.mult;
+			System.arraycopy(info.postlist, 0, ret.postlist, 0, VIF_POSIT + 2);
+
+			ret.maxover = info.maxover;
+			ret.maxunder = info.maxunder;
+			ret.maxerr = info.maxerr;
+
+			ret.twofitminsize = info.twofitminsize;
+			ret.twofitminused = info.twofitminused;
+			ret.twofitweight = info.twofitweight;
+			ret.twofitatten = info.twofitatten;
+			ret.unusedminsize = info.unusedminsize;
+			ret.unusedmin_n = info.unusedmin_n;
+
+			ret.n = info.n;
+
+			return (ret);
+		}
+
+	}
+
+	class LookFloor1 {
+		static final int VIF_POSIT = 63;
+
+		int[] sorted_index = new int[VIF_POSIT + 2];
+		int[] forward_index = new int[VIF_POSIT + 2];
+		int[] reverse_index = new int[VIF_POSIT + 2];
+		int[] hineighbor = new int[VIF_POSIT];
+		int[] loneighbor = new int[VIF_POSIT];
+		int posts;
+
+		int n;
+		int quant_q;
+		InfoFloor1 vi;
+
+		int phrasebits;
+		int postbits;
+		int frames;
+
+		void free() {
+			sorted_index = null;
+			forward_index = null;
+			reverse_index = null;
+			hineighbor = null;
+			loneighbor = null;
+		}
+	}
+
+	class Lsfit_acc {
+		long x0;
+		long x1;
+
+		long xa;
+		long ya;
+		long x2a;
+		long y2a;
+		long xya;
+		long n;
+		long an;
+		long un;
+		long edgey0;
+		long edgey1;
+	}
+
+	class EchstateFloor1 {
+		int[] codewords;
+		float[] curve;
+		long frameno;
+		long codes;
+	}
+}
diff --git a/sources/teavm/java/com/jcraft/jorbis/FuncFloor.java b/sources/teavm/java/com/jcraft/jorbis/FuncFloor.java
new file mode 100644
index 00000000..110c5f03
--- /dev/null
+++ b/sources/teavm/java/com/jcraft/jorbis/FuncFloor.java
@@ -0,0 +1,52 @@
+/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
+/* JOrbis
+ * Copyright (C) 2000 ymnk, JCraft,Inc.
+ *  
+ * Written by: 2000 ymnk<ymnk@jcraft.com>
+ *   
+ * Many thanks to 
+ *   Monty <monty@xiph.org> and 
+ *   The XIPHOPHORUS Company http://www.xiph.org/ .
+ * JOrbis has been based on their awesome works, Vorbis codec.
+ *   
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public License
+ * as published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+   
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Library General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Library General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+package com.jcraft.jorbis;
+
+import com.jcraft.jogg.*;
+
+abstract class FuncFloor {
+
+	public static FuncFloor[] floor_P = { new Floor0(), new Floor1() };
+
+	abstract void pack(Object i, Buffer opb);
+
+	abstract Object unpack(Info vi, Buffer opb);
+
+	abstract Object look(DspState vd, InfoMode mi, Object i);
+
+	abstract void free_info(Object i);
+
+	abstract void free_look(Object i);
+
+	abstract void free_state(Object vs);
+
+	abstract int forward(Block vb, Object i, float[] in, float[] out, Object vs);
+
+	abstract Object inverse1(Block vb, Object i, Object memo);
+
+	abstract int inverse2(Block vb, Object i, Object memo, float[] out);
+}
diff --git a/sources/teavm/java/com/jcraft/jorbis/FuncMapping.java b/sources/teavm/java/com/jcraft/jorbis/FuncMapping.java
new file mode 100644
index 00000000..1a830985
--- /dev/null
+++ b/sources/teavm/java/com/jcraft/jorbis/FuncMapping.java
@@ -0,0 +1,45 @@
+/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
+/* JOrbis
+ * Copyright (C) 2000 ymnk, JCraft,Inc.
+ *  
+ * Written by: 2000 ymnk<ymnk@jcraft.com>
+ *   
+ * Many thanks to 
+ *   Monty <monty@xiph.org> and 
+ *   The XIPHOPHORUS Company http://www.xiph.org/ .
+ * JOrbis has been based on their awesome works, Vorbis codec.
+ *   
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public License
+ * as published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+   
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Library General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Library General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+package com.jcraft.jorbis;
+
+import com.jcraft.jogg.*;
+
+abstract class FuncMapping {
+	public static FuncMapping[] mapping_P = { new Mapping0() };
+
+	abstract void pack(Info info, Object imap, Buffer buffer);
+
+	abstract Object unpack(Info info, Buffer buffer);
+
+	abstract Object look(DspState vd, InfoMode vm, Object m);
+
+	abstract void free_info(Object imap);
+
+	abstract void free_look(Object imap);
+
+	abstract int inverse(Block vd, Object lm);
+}
diff --git a/sources/teavm/java/com/jcraft/jorbis/FuncResidue.java b/sources/teavm/java/com/jcraft/jorbis/FuncResidue.java
new file mode 100644
index 00000000..33ab1e2a
--- /dev/null
+++ b/sources/teavm/java/com/jcraft/jorbis/FuncResidue.java
@@ -0,0 +1,45 @@
+/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
+/* JOrbis
+ * Copyright (C) 2000 ymnk, JCraft,Inc.
+ *  
+ * Written by: 2000 ymnk<ymnk@jcraft.com>
+ *   
+ * Many thanks to 
+ *   Monty <monty@xiph.org> and 
+ *   The XIPHOPHORUS Company http://www.xiph.org/ .
+ * JOrbis has been based on their awesome works, Vorbis codec.
+ *   
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public License
+ * as published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+   
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Library General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Library General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+package com.jcraft.jorbis;
+
+import com.jcraft.jogg.*;
+
+abstract class FuncResidue {
+	public static FuncResidue[] residue_P = { new Residue0(), new Residue1(), new Residue2() };
+
+	abstract void pack(Object vr, Buffer opb);
+
+	abstract Object unpack(Info vi, Buffer opb);
+
+	abstract Object look(DspState vd, InfoMode vm, Object vr);
+
+	abstract void free_info(Object i);
+
+	abstract void free_look(Object i);
+
+	abstract int inverse(Block vb, Object vl, float[][] in, int[] nonzero, int ch);
+}
diff --git a/sources/teavm/java/com/jcraft/jorbis/FuncTime.java b/sources/teavm/java/com/jcraft/jorbis/FuncTime.java
new file mode 100644
index 00000000..019b6342
--- /dev/null
+++ b/sources/teavm/java/com/jcraft/jorbis/FuncTime.java
@@ -0,0 +1,45 @@
+/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
+/* JOrbis
+ * Copyright (C) 2000 ymnk, JCraft,Inc.
+ *  
+ * Written by: 2000 ymnk<ymnk@jcraft.com>
+ *   
+ * Many thanks to 
+ *   Monty <monty@xiph.org> and 
+ *   The XIPHOPHORUS Company http://www.xiph.org/ .
+ * JOrbis has been based on their awesome works, Vorbis codec.
+ *   
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public License
+ * as published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+   
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Library General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Library General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+package com.jcraft.jorbis;
+
+import com.jcraft.jogg.*;
+
+abstract class FuncTime {
+	public static FuncTime[] time_P = { new Time0() };
+
+	abstract void pack(Object i, Buffer opb);
+
+	abstract Object unpack(Info vi, Buffer opb);
+
+	abstract Object look(DspState vd, InfoMode vm, Object i);
+
+	abstract void free_info(Object i);
+
+	abstract void free_look(Object i);
+
+	abstract int inverse(Block vb, Object i, float[] in, float[] out);
+}
diff --git a/sources/teavm/java/com/jcraft/jorbis/Info.java b/sources/teavm/java/com/jcraft/jorbis/Info.java
new file mode 100644
index 00000000..e0f0285d
--- /dev/null
+++ b/sources/teavm/java/com/jcraft/jorbis/Info.java
@@ -0,0 +1,468 @@
+/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
+/* JOrbis
+ * Copyright (C) 2000 ymnk, JCraft,Inc.
+ *  
+ * Written by: 2000 ymnk<ymnk@jcraft.com>
+ *   
+ * Many thanks to 
+ *   Monty <monty@xiph.org> and 
+ *   The XIPHOPHORUS Company http://www.xiph.org/ .
+ * JOrbis has been based on their awesome works, Vorbis codec.
+ *   
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public License
+ * as published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+   
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Library General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Library General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+package com.jcraft.jorbis;
+
+import com.jcraft.jogg.*;
+
+public class Info {
+	private static final int OV_EBADPACKET = -136;
+	private static final int OV_ENOTAUDIO = -135;
+
+	private static byte[] _vorbis = "vorbis".getBytes();
+	private static final int VI_TIMEB = 1;
+	// private static final int VI_FLOORB=1;
+	private static final int VI_FLOORB = 2;
+	// private static final int VI_RESB=1;
+	private static final int VI_RESB = 3;
+	private static final int VI_MAPB = 1;
+	private static final int VI_WINDOWB = 1;
+
+	public int version;
+	public int channels;
+	public int rate;
+
+	// The below bitrate declarations are *hints*.
+	// Combinations of the three values carry the following implications:
+	//
+	// all three set to the same value:
+	// implies a fixed rate bitstream
+	// only nominal set:
+	// implies a VBR stream that averages the nominal bitrate. No hard
+	// upper/lower limit
+	// upper and or lower set:
+	// implies a VBR bitstream that obeys the bitrate limits. nominal
+	// may also be set to give a nominal rate.
+	// none set:
+	// the coder does not care to speculate.
+
+	int bitrate_upper;
+	int bitrate_nominal;
+	int bitrate_lower;
+
+	// Vorbis supports only short and long blocks, but allows the
+	// encoder to choose the sizes
+
+	int[] blocksizes = new int[2];
+
+	// modes are the primary means of supporting on-the-fly different
+	// blocksizes, different channel mappings (LR or mid-side),
+	// different residue backends, etc. Each mode consists of a
+	// blocksize flag and a mapping (along with the mapping setup
+
+	int modes;
+	int maps;
+	int times;
+	int floors;
+	int residues;
+	int books;
+	int psys; // encode only
+
+	InfoMode[] mode_param = null;
+
+	int[] map_type = null;
+	Object[] map_param = null;
+
+	int[] time_type = null;
+	Object[] time_param = null;
+
+	int[] floor_type = null;
+	Object[] floor_param = null;
+
+	int[] residue_type = null;
+	Object[] residue_param = null;
+
+	StaticCodeBook[] book_param = null;
+
+	PsyInfo[] psy_param = new PsyInfo[64]; // encode only
+
+	// for block long/sort tuning; encode only
+	int envelopesa;
+	float preecho_thresh;
+	float preecho_clamp;
+
+	// used by synthesis, which has a full, alloced vi
+	public void init() {
+		rate = 0;
+	}
+
+	public void clear() {
+		for (int i = 0; i < modes; i++) {
+			mode_param[i] = null;
+		}
+		mode_param = null;
+
+		for (int i = 0; i < maps; i++) { // unpack does the range checking
+			FuncMapping.mapping_P[map_type[i]].free_info(map_param[i]);
+		}
+		map_param = null;
+
+		for (int i = 0; i < times; i++) { // unpack does the range checking
+			FuncTime.time_P[time_type[i]].free_info(time_param[i]);
+		}
+		time_param = null;
+
+		for (int i = 0; i < floors; i++) { // unpack does the range checking
+			FuncFloor.floor_P[floor_type[i]].free_info(floor_param[i]);
+		}
+		floor_param = null;
+
+		for (int i = 0; i < residues; i++) { // unpack does the range checking
+			FuncResidue.residue_P[residue_type[i]].free_info(residue_param[i]);
+		}
+		residue_param = null;
+
+		// the static codebooks *are* freed if you call info_clear, because
+		// decode side does alloc a 'static' codebook. Calling clear on the
+		// full codebook does not clear the static codebook (that's our
+		// responsibility)
+		for (int i = 0; i < books; i++) {
+			// just in case the decoder pre-cleared to save space
+			if (book_param[i] != null) {
+				book_param[i].clear();
+				book_param[i] = null;
+			}
+		}
+		// if(vi->book_param)free(vi->book_param);
+		book_param = null;
+
+		for (int i = 0; i < psys; i++) {
+			psy_param[i].free();
+		}
+
+	}
+
+	// Header packing/unpacking
+	int unpack_info(Buffer opb) {
+		version = opb.read(32);
+		if (version != 0)
+			return (-1);
+
+		channels = opb.read(8);
+		rate = opb.read(32);
+
+		bitrate_upper = opb.read(32);
+		bitrate_nominal = opb.read(32);
+		bitrate_lower = opb.read(32);
+
+		blocksizes[0] = 1 << opb.read(4);
+		blocksizes[1] = 1 << opb.read(4);
+
+		if ((rate < 1) || (channels < 1) || (blocksizes[0] < 8) || (blocksizes[1] < blocksizes[0])
+				|| (opb.read(1) != 1)) {
+			clear();
+			return (-1);
+		}
+		return (0);
+	}
+
+	// all of the real encoding details are here. The modes, books,
+	// everything
+	int unpack_books(Buffer opb) {
+
+		books = opb.read(8) + 1;
+
+		if (book_param == null || book_param.length != books)
+			book_param = new StaticCodeBook[books];
+		for (int i = 0; i < books; i++) {
+			book_param[i] = new StaticCodeBook();
+			if (book_param[i].unpack(opb) != 0) {
+				clear();
+				return (-1);
+			}
+		}
+
+		// time backend settings
+		times = opb.read(6) + 1;
+		if (time_type == null || time_type.length != times)
+			time_type = new int[times];
+		if (time_param == null || time_param.length != times)
+			time_param = new Object[times];
+		for (int i = 0; i < times; i++) {
+			time_type[i] = opb.read(16);
+			if (time_type[i] < 0 || time_type[i] >= VI_TIMEB) {
+				clear();
+				return (-1);
+			}
+			time_param[i] = FuncTime.time_P[time_type[i]].unpack(this, opb);
+			if (time_param[i] == null) {
+				clear();
+				return (-1);
+			}
+		}
+
+		// floor backend settings
+		floors = opb.read(6) + 1;
+		if (floor_type == null || floor_type.length != floors)
+			floor_type = new int[floors];
+		if (floor_param == null || floor_param.length != floors)
+			floor_param = new Object[floors];
+
+		for (int i = 0; i < floors; i++) {
+			floor_type[i] = opb.read(16);
+			if (floor_type[i] < 0 || floor_type[i] >= VI_FLOORB) {
+				clear();
+				return (-1);
+			}
+
+			floor_param[i] = FuncFloor.floor_P[floor_type[i]].unpack(this, opb);
+			if (floor_param[i] == null) {
+				clear();
+				return (-1);
+			}
+		}
+
+		// residue backend settings
+		residues = opb.read(6) + 1;
+
+		if (residue_type == null || residue_type.length != residues)
+			residue_type = new int[residues];
+
+		if (residue_param == null || residue_param.length != residues)
+			residue_param = new Object[residues];
+
+		for (int i = 0; i < residues; i++) {
+			residue_type[i] = opb.read(16);
+			if (residue_type[i] < 0 || residue_type[i] >= VI_RESB) {
+				clear();
+				return (-1);
+			}
+			residue_param[i] = FuncResidue.residue_P[residue_type[i]].unpack(this, opb);
+			if (residue_param[i] == null) {
+				clear();
+				return (-1);
+			}
+		}
+
+		// map backend settings
+		maps = opb.read(6) + 1;
+		if (map_type == null || map_type.length != maps)
+			map_type = new int[maps];
+		if (map_param == null || map_param.length != maps)
+			map_param = new Object[maps];
+		for (int i = 0; i < maps; i++) {
+			map_type[i] = opb.read(16);
+			if (map_type[i] < 0 || map_type[i] >= VI_MAPB) {
+				clear();
+				return (-1);
+			}
+			map_param[i] = FuncMapping.mapping_P[map_type[i]].unpack(this, opb);
+			if (map_param[i] == null) {
+				clear();
+				return (-1);
+			}
+		}
+
+		// mode settings
+		modes = opb.read(6) + 1;
+		if (mode_param == null || mode_param.length != modes)
+			mode_param = new InfoMode[modes];
+		for (int i = 0; i < modes; i++) {
+			mode_param[i] = new InfoMode();
+			mode_param[i].blockflag = opb.read(1);
+			mode_param[i].windowtype = opb.read(16);
+			mode_param[i].transformtype = opb.read(16);
+			mode_param[i].mapping = opb.read(8);
+
+			if ((mode_param[i].windowtype >= VI_WINDOWB) || (mode_param[i].transformtype >= VI_WINDOWB)
+					|| (mode_param[i].mapping >= maps)) {
+				clear();
+				return (-1);
+			}
+		}
+
+		if (opb.read(1) != 1) {
+			clear();
+			return (-1);
+		}
+
+		return (0);
+	}
+
+	// The Vorbis header is in three packets; the initial small packet in
+	// the first page that identifies basic parameters, a second packet
+	// with bitstream comments and a third packet that holds the
+	// codebook.
+
+	public int synthesis_headerin(Comment vc, Packet op) {
+		Buffer opb = new Buffer();
+
+		if (op != null) {
+			opb.readinit(op.packet_base, op.packet, op.bytes);
+
+			// Which of the three types of header is this?
+			// Also verify header-ness, vorbis
+			{
+				byte[] buffer = new byte[6];
+				int packtype = opb.read(8);
+				opb.read(buffer, 6);
+				if (buffer[0] != 'v' || buffer[1] != 'o' || buffer[2] != 'r' || buffer[3] != 'b' || buffer[4] != 'i'
+						|| buffer[5] != 's') {
+					// not a vorbis header
+					return (-1);
+				}
+				switch (packtype) {
+				case 0x01: // least significant *bit* is read first
+					if (op.b_o_s == 0) {
+						// Not the initial packet
+						return (-1);
+					}
+					if (rate != 0) {
+						// previously initialized info header
+						return (-1);
+					}
+					return (unpack_info(opb));
+				case 0x03: // least significant *bit* is read first
+					if (rate == 0) {
+						// um... we didn't get the initial header
+						return (-1);
+					}
+					return (vc.unpack(opb));
+				case 0x05: // least significant *bit* is read first
+					if (rate == 0 || vc.vendor == null) {
+						// um... we didn;t get the initial header or comments yet
+						return (-1);
+					}
+					return (unpack_books(opb));
+				default:
+					// Not a valid vorbis header type
+					// return(-1);
+					break;
+				}
+			}
+		}
+		return (-1);
+	}
+
+	// pack side
+	int pack_info(Buffer opb) {
+		// preamble
+		opb.write(0x01, 8);
+		opb.write(_vorbis);
+
+		// basic information about the stream
+		opb.write(0x00, 32);
+		opb.write(channels, 8);
+		opb.write(rate, 32);
+
+		opb.write(bitrate_upper, 32);
+		opb.write(bitrate_nominal, 32);
+		opb.write(bitrate_lower, 32);
+
+		opb.write(Util.ilog2(blocksizes[0]), 4);
+		opb.write(Util.ilog2(blocksizes[1]), 4);
+		opb.write(1, 1);
+		return (0);
+	}
+
+	int pack_books(Buffer opb) {
+		opb.write(0x05, 8);
+		opb.write(_vorbis);
+
+		// books
+		opb.write(books - 1, 8);
+		for (int i = 0; i < books; i++) {
+			if (book_param[i].pack(opb) != 0) {
+				// goto err_out;
+				return (-1);
+			}
+		}
+
+		// times
+		opb.write(times - 1, 6);
+		for (int i = 0; i < times; i++) {
+			opb.write(time_type[i], 16);
+			FuncTime.time_P[time_type[i]].pack(this.time_param[i], opb);
+		}
+
+		// floors
+		opb.write(floors - 1, 6);
+		for (int i = 0; i < floors; i++) {
+			opb.write(floor_type[i], 16);
+			FuncFloor.floor_P[floor_type[i]].pack(floor_param[i], opb);
+		}
+
+		// residues
+		opb.write(residues - 1, 6);
+		for (int i = 0; i < residues; i++) {
+			opb.write(residue_type[i], 16);
+			FuncResidue.residue_P[residue_type[i]].pack(residue_param[i], opb);
+		}
+
+		// maps
+		opb.write(maps - 1, 6);
+		for (int i = 0; i < maps; i++) {
+			opb.write(map_type[i], 16);
+			FuncMapping.mapping_P[map_type[i]].pack(this, map_param[i], opb);
+		}
+
+		// modes
+		opb.write(modes - 1, 6);
+		for (int i = 0; i < modes; i++) {
+			opb.write(mode_param[i].blockflag, 1);
+			opb.write(mode_param[i].windowtype, 16);
+			opb.write(mode_param[i].transformtype, 16);
+			opb.write(mode_param[i].mapping, 8);
+		}
+		opb.write(1, 1);
+		return (0);
+	}
+
+	public int blocksize(Packet op) {
+		// codec_setup_info
+		Buffer opb = new Buffer();
+
+		int mode;
+
+		opb.readinit(op.packet_base, op.packet, op.bytes);
+
+		/* Check the packet type */
+		if (opb.read(1) != 0) {
+			/* Oops. This is not an audio data packet */
+			return (OV_ENOTAUDIO);
+		}
+		{
+			int modebits = 0;
+			int v = modes;
+			while (v > 1) {
+				modebits++;
+				v >>>= 1;
+			}
+
+			/* read our mode and pre/post windowsize */
+			mode = opb.read(modebits);
+		}
+		if (mode == -1)
+			return (OV_EBADPACKET);
+		return (blocksizes[mode_param[mode].blockflag]);
+	}
+
+	public String toString() {
+		return "version:" + version + ", channels:" + channels + ", rate:" + rate
+				+ ", bitrate:" + bitrate_upper + "," + bitrate_nominal + ","
+				+ bitrate_lower;
+	}
+}
diff --git a/sources/teavm/java/com/jcraft/jorbis/InfoMode.java b/sources/teavm/java/com/jcraft/jorbis/InfoMode.java
new file mode 100644
index 00000000..e7f203cc
--- /dev/null
+++ b/sources/teavm/java/com/jcraft/jorbis/InfoMode.java
@@ -0,0 +1,34 @@
+/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
+/* JOrbis
+ * Copyright (C) 2000 ymnk, JCraft,Inc.
+ *  
+ * Written by: 2000 ymnk<ymnk@jcraft.com>
+ *   
+ * Many thanks to 
+ *   Monty <monty@xiph.org> and 
+ *   The XIPHOPHORUS Company http://www.xiph.org/ .
+ * JOrbis has been based on their awesome works, Vorbis codec.
+ *   
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public License
+ * as published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+   
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Library General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Library General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+package com.jcraft.jorbis;
+
+class InfoMode {
+	int blockflag;
+	int windowtype;
+	int transformtype;
+	int mapping;
+}
diff --git a/sources/teavm/java/com/jcraft/jorbis/JOrbisException.java b/sources/teavm/java/com/jcraft/jorbis/JOrbisException.java
new file mode 100644
index 00000000..7862e980
--- /dev/null
+++ b/sources/teavm/java/com/jcraft/jorbis/JOrbisException.java
@@ -0,0 +1,40 @@
+/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
+/* JOrbis
+ * Copyright (C) 2000 ymnk, JCraft,Inc.
+ *  
+ * Written by: 2000 ymnk<ymnk@jcraft.com>
+ *   
+ * Many thanks to 
+ *   Monty <monty@xiph.org> and 
+ *   The XIPHOPHORUS Company http://www.xiph.org/ .
+ * JOrbis has been based on their awesome works, Vorbis codec.
+ *   
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public License
+ * as published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+   
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Library General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Library General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+package com.jcraft.jorbis;
+
+public class JOrbisException extends Exception {
+
+	private static final long serialVersionUID = 1L;
+
+	public JOrbisException() {
+		super();
+	}
+
+	public JOrbisException(String s) {
+		super("JOrbis: " + s);
+	}
+}
diff --git a/sources/teavm/java/com/jcraft/jorbis/Lookup.java b/sources/teavm/java/com/jcraft/jorbis/Lookup.java
new file mode 100644
index 00000000..5accc93b
--- /dev/null
+++ b/sources/teavm/java/com/jcraft/jorbis/Lookup.java
@@ -0,0 +1,122 @@
+/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
+/* JOrbis
+ * Copyright (C) 2000 ymnk, JCraft,Inc.
+ *  
+ * Written by: 2000 ymnk<ymnk@jcraft.com>
+ *   
+ * Many thanks to 
+ *   Monty <monty@xiph.org> and 
+ *   The XIPHOPHORUS Company http://www.xiph.org/ .
+ * JOrbis has been based on their awesome works, Vorbis codec.
+ *   
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public License
+ * as published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+   
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Library General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Library General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+package com.jcraft.jorbis;
+
+class Lookup {
+	static final int COS_LOOKUP_SZ = 128;
+	static final float[] COS_LOOKUP = { +1.0000000000000f, +0.9996988186962f, +0.9987954562052f, +0.9972904566787f,
+			+0.9951847266722f, +0.9924795345987f, +0.9891765099648f, +0.9852776423889f, +0.9807852804032f,
+			+0.9757021300385f, +0.9700312531945f, +0.9637760657954f, +0.9569403357322f, +0.9495281805930f,
+			+0.9415440651830f, +0.9329927988347f, +0.9238795325113f, +0.9142097557035f, +0.9039892931234f,
+			+0.8932243011955f, +0.8819212643484f, +0.8700869911087f, +0.8577286100003f, +0.8448535652497f,
+			+0.8314696123025f, +0.8175848131516f, +0.8032075314806f, +0.7883464276266f, +0.7730104533627f,
+			+0.7572088465065f, +0.7409511253550f, +0.7242470829515f, +0.7071067811865f, +0.6895405447371f,
+			+0.6715589548470f, +0.6531728429538f, +0.6343932841636f, +0.6152315905806f, +0.5956993044924f,
+			+0.5758081914178f, +0.5555702330196f, +0.5349976198871f, +0.5141027441932f, +0.4928981922298f,
+			+0.4713967368260f, +0.4496113296546f, +0.4275550934303f, +0.4052413140050f, +0.3826834323651f,
+			+0.3598950365350f, +0.3368898533922f, +0.3136817403989f, +0.2902846772545f, +0.2667127574749f,
+			+0.2429801799033f, +0.2191012401569f, +0.1950903220161f, +0.1709618887603f, +0.1467304744554f,
+			+0.1224106751992f, +0.0980171403296f, +0.0735645635997f, +0.0490676743274f, +0.0245412285229f,
+			+0.0000000000000f, -0.0245412285229f, -0.0490676743274f, -0.0735645635997f, -0.0980171403296f,
+			-0.1224106751992f, -0.1467304744554f, -0.1709618887603f, -0.1950903220161f, -0.2191012401569f,
+			-0.2429801799033f, -0.2667127574749f, -0.2902846772545f, -0.3136817403989f, -0.3368898533922f,
+			-0.3598950365350f, -0.3826834323651f, -0.4052413140050f, -0.4275550934303f, -0.4496113296546f,
+			-0.4713967368260f, -0.4928981922298f, -0.5141027441932f, -0.5349976198871f, -0.5555702330196f,
+			-0.5758081914178f, -0.5956993044924f, -0.6152315905806f, -0.6343932841636f, -0.6531728429538f,
+			-0.6715589548470f, -0.6895405447371f, -0.7071067811865f, -0.7242470829515f, -0.7409511253550f,
+			-0.7572088465065f, -0.7730104533627f, -0.7883464276266f, -0.8032075314806f, -0.8175848131516f,
+			-0.8314696123025f, -0.8448535652497f, -0.8577286100003f, -0.8700869911087f, -0.8819212643484f,
+			-0.8932243011955f, -0.9039892931234f, -0.9142097557035f, -0.9238795325113f, -0.9329927988347f,
+			-0.9415440651830f, -0.9495281805930f, -0.9569403357322f, -0.9637760657954f, -0.9700312531945f,
+			-0.9757021300385f, -0.9807852804032f, -0.9852776423889f, -0.9891765099648f, -0.9924795345987f,
+			-0.9951847266722f, -0.9972904566787f, -0.9987954562052f, -0.9996988186962f, -1.0000000000000f, };
+
+	/* interpolated lookup based cos function, domain 0 to PI only */
+	static float coslook(float a) {
+		double d = a * (.31830989 * (float) COS_LOOKUP_SZ);
+		int i = (int) d;
+		return COS_LOOKUP[i] + ((float) (d - i)) * (COS_LOOKUP[i + 1] - COS_LOOKUP[i]);
+	}
+
+	static final int INVSQ_LOOKUP_SZ = 32;
+	static final float[] INVSQ_LOOKUP = { 1.414213562373f, 1.392621247646f, 1.371988681140f, 1.352246807566f,
+			1.333333333333f, 1.315191898443f, 1.297771369046f, 1.281025230441f, 1.264911064067f, 1.249390095109f,
+			1.234426799697f, 1.219988562661f, 1.206045378311f, 1.192569588000f, 1.179535649239f, 1.166919931983f,
+			1.154700538379f, 1.142857142857f, 1.131370849898f, 1.120224067222f, 1.109400392450f, 1.098884511590f,
+			1.088662107904f, 1.078719779941f, 1.069044967650f, 1.059625885652f, 1.050451462878f, 1.041511287847f,
+			1.032795558989f, 1.024295039463f, 1.016001016002f, 1.007905261358f, 1.000000000000f, };
+
+	/* interpolated 1./sqrt(p) where .5 <= p < 1. */
+	static float invsqlook(float a) {
+		double d = a * (2.f * (float) INVSQ_LOOKUP_SZ) - (float) INVSQ_LOOKUP_SZ;
+		int i = (int) d;
+		return INVSQ_LOOKUP[i] + ((float) (d - i)) * (INVSQ_LOOKUP[i + 1] - INVSQ_LOOKUP[i]);
+	}
+
+	static final int INVSQ2EXP_LOOKUP_MIN = -32;
+	static final int INVSQ2EXP_LOOKUP_MAX = 32;
+	static final float[] INVSQ2EXP_LOOKUP = { 65536.f, 46340.95001f, 32768.f, 23170.47501f, 16384.f, 11585.2375f,
+			8192.f, 5792.618751f, 4096.f, 2896.309376f, 2048.f, 1448.154688f, 1024.f, 724.0773439f, 512.f, 362.038672f,
+			256.f, 181.019336f, 128.f, 90.50966799f, 64.f, 45.254834f, 32.f, 22.627417f, 16.f, 11.3137085f, 8.f,
+			5.656854249f, 4.f, 2.828427125f, 2.f, 1.414213562f, 1.f, 0.7071067812f, 0.5f, 0.3535533906f, 0.25f,
+			0.1767766953f, 0.125f, 0.08838834765f, 0.0625f, 0.04419417382f, 0.03125f, 0.02209708691f, 0.015625f,
+			0.01104854346f, 0.0078125f, 0.005524271728f, 0.00390625f, 0.002762135864f, 0.001953125f, 0.001381067932f,
+			0.0009765625f, 0.000690533966f, 0.00048828125f, 0.000345266983f, 0.000244140625f, 0.0001726334915f,
+			0.0001220703125f, 8.631674575e-05f, 6.103515625e-05f, 4.315837288e-05f, 3.051757812e-05f, 2.157918644e-05f,
+			1.525878906e-05f, };
+
+	/* interpolated 1./sqrt(p) where .5 <= p < 1. */
+	static float invsq2explook(int a) {
+		return INVSQ2EXP_LOOKUP[a - INVSQ2EXP_LOOKUP_MIN];
+	}
+
+	static final int FROMdB_LOOKUP_SZ = 35;
+	static final int FROMdB2_LOOKUP_SZ = 32;
+	static final int FROMdB_SHIFT = 5;
+	static final int FROMdB2_SHIFT = 3;
+	static final int FROMdB2_MASK = 31;
+	static final float[] FROMdB_LOOKUP = { 1.f, 0.6309573445f, 0.3981071706f, 0.2511886432f, 0.1584893192f, 0.1f,
+			0.06309573445f, 0.03981071706f, 0.02511886432f, 0.01584893192f, 0.01f, 0.006309573445f, 0.003981071706f,
+			0.002511886432f, 0.001584893192f, 0.001f, 0.0006309573445f, 0.0003981071706f, 0.0002511886432f,
+			0.0001584893192f, 0.0001f, 6.309573445e-05f, 3.981071706e-05f, 2.511886432e-05f, 1.584893192e-05f, 1e-05f,
+			6.309573445e-06f, 3.981071706e-06f, 2.511886432e-06f, 1.584893192e-06f, 1e-06f, 6.309573445e-07f,
+			3.981071706e-07f, 2.511886432e-07f, 1.584893192e-07f, };
+	static final float[] FROMdB2_LOOKUP = { 0.9928302478f, 0.9786445908f, 0.9646616199f, 0.9508784391f, 0.9372921937f,
+			0.92390007f, 0.9106992942f, 0.8976871324f, 0.8848608897f, 0.8722179097f, 0.8597555737f, 0.8474713009f,
+			0.835362547f, 0.8234268041f, 0.8116616003f, 0.8000644989f, 0.7886330981f, 0.7773650302f, 0.7662579617f,
+			0.755309592f, 0.7445176537f, 0.7338799116f, 0.7233941627f, 0.7130582353f, 0.7028699885f, 0.6928273125f,
+			0.6829281272f, 0.6731703824f, 0.6635520573f, 0.6540711597f, 0.6447257262f, 0.6355138211f, };
+
+	/* interpolated lookup based fromdB function, domain -140dB to 0dB only */
+	static float fromdBlook(float a) {
+		int i = (int) (a * ((float) (-(1 << FROMdB2_SHIFT))));
+		return (i < 0) ? 1.f
+				: ((i >= (FROMdB_LOOKUP_SZ << FROMdB_SHIFT)) ? 0.f
+						: FROMdB_LOOKUP[i >>> FROMdB_SHIFT] * FROMdB2_LOOKUP[i & FROMdB2_MASK]);
+	}
+
+}
diff --git a/sources/teavm/java/com/jcraft/jorbis/Lpc.java b/sources/teavm/java/com/jcraft/jorbis/Lpc.java
new file mode 100644
index 00000000..4160c50a
--- /dev/null
+++ b/sources/teavm/java/com/jcraft/jorbis/Lpc.java
@@ -0,0 +1,185 @@
+/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
+/* JOrbis
+ * Copyright (C) 2000 ymnk, JCraft,Inc.
+ *  
+ * Written by: 2000 ymnk<ymnk@jcraft.com>
+ *   
+ * Many thanks to 
+ *   Monty <monty@xiph.org> and 
+ *   The XIPHOPHORUS Company http://www.xiph.org/ .
+ * JOrbis has been based on their awesome works, Vorbis codec.
+ *   
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public License
+ * as published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+   
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Library General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Library General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+package com.jcraft.jorbis;
+
+class Lpc {
+	// en/decode lookups
+	Drft fft = new Drft();;
+
+	int ln;
+	int m;
+
+	// Autocorrelation LPC coeff generation algorithm invented by
+	// N. Levinson in 1947, modified by J. Durbin in 1959.
+
+	// Input : n elements of time doamin data
+	// Output: m lpc coefficients, excitation energy
+
+	static float lpc_from_data(float[] data, float[] lpc, int n, int m) {
+		float[] aut = new float[m + 1];
+		float error;
+		int i, j;
+
+		// autocorrelation, p+1 lag coefficients
+
+		j = m + 1;
+		while (j-- != 0) {
+			float d = 0;
+			for (i = j; i < n; i++)
+				d += data[i] * data[i - j];
+			aut[j] = d;
+		}
+
+		// Generate lpc coefficients from autocorr values
+
+		error = aut[0];
+		/*
+		 * if(error==0){ for(int k=0; k<m; k++) lpc[k]=0.0f; return 0; }
+		 */
+
+		for (i = 0; i < m; i++) {
+			float r = -aut[i + 1];
+
+			if (error == 0) {
+				for (int k = 0; k < m; k++)
+					lpc[k] = 0.0f;
+				return 0;
+			}
+
+			// Sum up this iteration's reflection coefficient; note that in
+			// Vorbis we don't save it. If anyone wants to recycle this code
+			// and needs reflection coefficients, save the results of 'r' from
+			// each iteration.
+
+			for (j = 0; j < i; j++)
+				r -= lpc[j] * aut[i - j];
+			r /= error;
+
+			// Update LPC coefficients and total error
+
+			lpc[i] = r;
+			for (j = 0; j < i / 2; j++) {
+				float tmp = lpc[j];
+				lpc[j] += r * lpc[i - 1 - j];
+				lpc[i - 1 - j] += r * tmp;
+			}
+			if (i % 2 != 0)
+				lpc[j] += lpc[j] * r;
+
+			error *= 1.0 - r * r;
+		}
+
+		// we need the error value to know how big an impulse to hit the
+		// filter with later
+
+		return error;
+	}
+
+	// Input : n element envelope spectral curve
+	// Output: m lpc coefficients, excitation energy
+
+	float lpc_from_curve(float[] curve, float[] lpc) {
+		int n = ln;
+		float[] work = new float[n + n];
+		float fscale = (float) (.5 / n);
+		int i, j;
+
+		// input is a real curve. make it complex-real
+		// This mixes phase, but the LPC generation doesn't care.
+		for (i = 0; i < n; i++) {
+			work[i * 2] = curve[i] * fscale;
+			work[i * 2 + 1] = 0;
+		}
+		work[n * 2 - 1] = curve[n - 1] * fscale;
+
+		n *= 2;
+		fft.backward(work);
+
+		// The autocorrelation will not be circular. Shift, else we lose
+		// most of the power in the edges.
+
+		for (i = 0, j = n / 2; i < n / 2;) {
+			float temp = work[i];
+			work[i++] = work[j];
+			work[j++] = temp;
+		}
+
+		return (lpc_from_data(work, lpc, n, m));
+	}
+
+	void init(int mapped, int m) {
+		ln = mapped;
+		this.m = m;
+
+		// we cheat decoding the LPC spectrum via FFTs
+		fft.init(mapped * 2);
+	}
+
+	void clear() {
+		fft.clear();
+	}
+
+	static float FAST_HYPOT(float a, float b) {
+		return (float) Math.sqrt((a) * (a) + (b) * (b));
+	}
+
+	// One can do this the long way by generating the transfer function in
+	// the time domain and taking the forward FFT of the result. The
+	// results from direct calculation are cleaner and faster.
+	//
+	// This version does a linear curve generation and then later
+	// interpolates the log curve from the linear curve.
+
+	void lpc_to_curve(float[] curve, float[] lpc, float amp) {
+
+		for (int i = 0; i < ln * 2; i++)
+			curve[i] = 0.0f;
+
+		if (amp == 0)
+			return;
+
+		for (int i = 0; i < m; i++) {
+			curve[i * 2 + 1] = lpc[i] / (4 * amp);
+			curve[i * 2 + 2] = -lpc[i] / (4 * amp);
+		}
+
+		fft.backward(curve);
+
+		{
+			int l2 = ln * 2;
+			float unit = (float) (1. / amp);
+			curve[0] = (float) (1. / (curve[0] * 2 + unit));
+			for (int i = 1; i < ln; i++) {
+				float real = (curve[i] + curve[l2 - i]);
+				float imag = (curve[i] - curve[l2 - i]);
+
+				float a = real + unit;
+				curve[i] = (float) (1.0 / FAST_HYPOT(a, imag));
+			}
+		}
+	}
+}
diff --git a/sources/teavm/java/com/jcraft/jorbis/Lsp.java b/sources/teavm/java/com/jcraft/jorbis/Lsp.java
new file mode 100644
index 00000000..7107234e
--- /dev/null
+++ b/sources/teavm/java/com/jcraft/jorbis/Lsp.java
@@ -0,0 +1,102 @@
+/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
+/* JOrbis
+ * Copyright (C) 2000 ymnk, JCraft,Inc.
+ *  
+ * Written by: 2000 ymnk<ymnk@jcraft.com>
+ *   
+ * Many thanks to 
+ *   Monty <monty@xiph.org> and 
+ *   The XIPHOPHORUS Company http://www.xiph.org/ .
+ * JOrbis has been based on their awesome works, Vorbis codec.
+ *   
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public License
+ * as published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+   
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Library General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Library General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+package com.jcraft.jorbis;
+
+/*
+  function: LSP (also called LSF) conversion routines
+
+  The LSP generation code is taken (with minimal modification) from
+  "On the Computation of the LSP Frequencies" by Joseph Rothweiler
+  <rothwlr@altavista.net>, available at:
+  
+  http://www2.xtdl.com/~rothwlr/lsfpaper/lsfpage.html 
+ ********************************************************************/
+
+class Lsp {
+
+	static final float M_PI = (float) (3.1415926539);
+
+	static void lsp_to_curve(float[] curve, int[] map, int n, int ln, float[] lsp, int m, float amp, float ampoffset) {
+		int i;
+		float wdel = M_PI / ln;
+		for (i = 0; i < m; i++)
+			lsp[i] = Lookup.coslook(lsp[i]);
+		int m2 = (m / 2) * 2;
+
+		i = 0;
+		while (i < n) {
+			int k = map[i];
+			float p = .7071067812f;
+			float q = .7071067812f;
+			float w = Lookup.coslook(wdel * k);
+
+			for (int j = 0; j < m2; j += 2) {
+				q *= lsp[j] - w;
+				p *= lsp[j + 1] - w;
+			}
+
+			if ((m & 1) != 0) {
+				/* odd order filter; slightly assymetric */
+				/* the last coefficient */
+				q *= lsp[m - 1] - w;
+				q *= q;
+				p *= p * (1.f - w * w);
+			} else {
+				/* even order filter; still symmetric */
+				q *= q * (1.f + w);
+				p *= p * (1.f - w);
+			}
+
+			// q=frexp(p+q,&qexp);
+			q = p + q;
+			int hx = Float.floatToIntBits(q);
+			int ix = 0x7fffffff & hx;
+			int qexp = 0;
+
+			if (ix >= 0x7f800000 || (ix == 0)) {
+				// 0,inf,nan
+			} else {
+				if (ix < 0x00800000) { // subnormal
+					q *= 3.3554432000e+07; // 0x4c000000
+					hx = Float.floatToIntBits(q);
+					ix = 0x7fffffff & hx;
+					qexp = -25;
+				}
+				qexp += ((ix >>> 23) - 126);
+				hx = (hx & 0x807fffff) | 0x3f000000;
+				q = Float.intBitsToFloat(hx);
+			}
+
+			q = Lookup.fromdBlook(amp * Lookup.invsqlook(q) * Lookup.invsq2explook(qexp + m) - ampoffset);
+
+			do {
+				curve[i++] *= q;
+			} while (i < n && map[i] == k);
+
+		}
+	}
+}
diff --git a/sources/teavm/java/com/jcraft/jorbis/Mapping0.java b/sources/teavm/java/com/jcraft/jorbis/Mapping0.java
new file mode 100644
index 00000000..005562c5
--- /dev/null
+++ b/sources/teavm/java/com/jcraft/jorbis/Mapping0.java
@@ -0,0 +1,361 @@
+/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
+/* JOrbis
+ * Copyright (C) 2000 ymnk, JCraft,Inc.
+ *  
+ * Written by: 2000 ymnk<ymnk@jcraft.com>
+ *   
+ * Many thanks to 
+ *   Monty <monty@xiph.org> and 
+ *   The XIPHOPHORUS Company http://www.xiph.org/ .
+ * JOrbis has been based on their awesome works, Vorbis codec.
+ *   
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public License
+ * as published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+   
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Library General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Library General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+package com.jcraft.jorbis;
+
+import com.jcraft.jogg.*;
+
+class Mapping0 extends FuncMapping {
+	static int seq = 0;
+
+	void free_info(Object imap) {
+	};
+
+	void free_look(Object imap) {
+	}
+
+	Object look(DspState vd, InfoMode vm, Object m) {
+		// System.err.println("Mapping0.look");
+		Info vi = vd.vi;
+		LookMapping0 look = new LookMapping0();
+		InfoMapping0 info = look.map = (InfoMapping0) m;
+		look.mode = vm;
+
+		look.time_look = new Object[info.submaps];
+		look.floor_look = new Object[info.submaps];
+		look.residue_look = new Object[info.submaps];
+
+		look.time_func = new FuncTime[info.submaps];
+		look.floor_func = new FuncFloor[info.submaps];
+		look.residue_func = new FuncResidue[info.submaps];
+
+		for (int i = 0; i < info.submaps; i++) {
+			int timenum = info.timesubmap[i];
+			int floornum = info.floorsubmap[i];
+			int resnum = info.residuesubmap[i];
+
+			look.time_func[i] = FuncTime.time_P[vi.time_type[timenum]];
+			look.time_look[i] = look.time_func[i].look(vd, vm, vi.time_param[timenum]);
+			look.floor_func[i] = FuncFloor.floor_P[vi.floor_type[floornum]];
+			look.floor_look[i] = look.floor_func[i].look(vd, vm, vi.floor_param[floornum]);
+			look.residue_func[i] = FuncResidue.residue_P[vi.residue_type[resnum]];
+			look.residue_look[i] = look.residue_func[i].look(vd, vm, vi.residue_param[resnum]);
+
+		}
+
+		if (vi.psys != 0 && vd.analysisp != 0) {
+			// ??
+		}
+
+		look.ch = vi.channels;
+
+		return (look);
+	}
+
+	void pack(Info vi, Object imap, Buffer opb) {
+		InfoMapping0 info = (InfoMapping0) imap;
+
+		/*
+		 * another 'we meant to do it this way' hack... up to beta 4, we packed 4 binary
+		 * zeros here to signify one submapping in use. We now redefine that to mean
+		 * four bitflags that indicate use of deeper features; bit0:submappings,
+		 * bit1:coupling, bit2,3:reserved. This is backward compatable with all actual
+		 * uses of the beta code.
+		 */
+
+		if (info.submaps > 1) {
+			opb.write(1, 1);
+			opb.write(info.submaps - 1, 4);
+		} else {
+			opb.write(0, 1);
+		}
+
+		if (info.coupling_steps > 0) {
+			opb.write(1, 1);
+			opb.write(info.coupling_steps - 1, 8);
+			for (int i = 0; i < info.coupling_steps; i++) {
+				opb.write(info.coupling_mag[i], Util.ilog2(vi.channels));
+				opb.write(info.coupling_ang[i], Util.ilog2(vi.channels));
+			}
+		} else {
+			opb.write(0, 1);
+		}
+
+		opb.write(0, 2); /* 2,3:reserved */
+
+		/* we don't write the channel submappings if we only have one... */
+		if (info.submaps > 1) {
+			for (int i = 0; i < vi.channels; i++)
+				opb.write(info.chmuxlist[i], 4);
+		}
+		for (int i = 0; i < info.submaps; i++) {
+			opb.write(info.timesubmap[i], 8);
+			opb.write(info.floorsubmap[i], 8);
+			opb.write(info.residuesubmap[i], 8);
+		}
+	}
+
+	// also responsible for range checking
+	Object unpack(Info vi, Buffer opb) {
+		InfoMapping0 info = new InfoMapping0();
+
+		if (opb.read(1) != 0) {
+			info.submaps = opb.read(4) + 1;
+		} else {
+			info.submaps = 1;
+		}
+
+		if (opb.read(1) != 0) {
+			info.coupling_steps = opb.read(8) + 1;
+
+			for (int i = 0; i < info.coupling_steps; i++) {
+				int testM = info.coupling_mag[i] = opb.read(Util.ilog2(vi.channels));
+				int testA = info.coupling_ang[i] = opb.read(Util.ilog2(vi.channels));
+
+				if (testM < 0 || testA < 0 || testM == testA || testM >= vi.channels || testA >= vi.channels) {
+					// goto err_out;
+					info.free();
+					return (null);
+				}
+			}
+		}
+
+		if (opb.read(2) > 0) { /* 2,3:reserved */
+			info.free();
+			return (null);
+		}
+
+		if (info.submaps > 1) {
+			for (int i = 0; i < vi.channels; i++) {
+				info.chmuxlist[i] = opb.read(4);
+				if (info.chmuxlist[i] >= info.submaps) {
+					info.free();
+					return (null);
+				}
+			}
+		}
+
+		for (int i = 0; i < info.submaps; i++) {
+			info.timesubmap[i] = opb.read(8);
+			if (info.timesubmap[i] >= vi.times) {
+				info.free();
+				return (null);
+			}
+			info.floorsubmap[i] = opb.read(8);
+			if (info.floorsubmap[i] >= vi.floors) {
+				info.free();
+				return (null);
+			}
+			info.residuesubmap[i] = opb.read(8);
+			if (info.residuesubmap[i] >= vi.residues) {
+				info.free();
+				return (null);
+			}
+		}
+		return info;
+	}
+
+	float[][] pcmbundle = null;
+	int[] zerobundle = null;
+	int[] nonzero = null;
+	Object[] floormemo = null;
+
+	synchronized int inverse(Block vb, Object l) {
+		DspState vd = vb.vd;
+		Info vi = vd.vi;
+		LookMapping0 look = (LookMapping0) l;
+		InfoMapping0 info = look.map;
+		InfoMode mode = look.mode;
+		int n = vb.pcmend = vi.blocksizes[vb.W];
+
+		float[] window = vd.window[vb.W][vb.lW][vb.nW][mode.windowtype];
+		if (pcmbundle == null || pcmbundle.length < vi.channels) {
+			pcmbundle = new float[vi.channels][];
+			nonzero = new int[vi.channels];
+			zerobundle = new int[vi.channels];
+			floormemo = new Object[vi.channels];
+		}
+
+		// time domain information decode (note that applying the
+		// information would have to happen later; we'll probably add a
+		// function entry to the harness for that later
+		// NOT IMPLEMENTED
+
+		// recover the spectral envelope; store it in the PCM vector for now
+		for (int i = 0; i < vi.channels; i++) {
+			float[] pcm = vb.pcm[i];
+			int submap = info.chmuxlist[i];
+
+			floormemo[i] = look.floor_func[submap].inverse1(vb, look.floor_look[submap], floormemo[i]);
+			if (floormemo[i] != null) {
+				nonzero[i] = 1;
+			} else {
+				nonzero[i] = 0;
+			}
+			for (int j = 0; j < n / 2; j++) {
+				pcm[j] = 0;
+			}
+
+		}
+
+		for (int i = 0; i < info.coupling_steps; i++) {
+			if (nonzero[info.coupling_mag[i]] != 0 || nonzero[info.coupling_ang[i]] != 0) {
+				nonzero[info.coupling_mag[i]] = 1;
+				nonzero[info.coupling_ang[i]] = 1;
+			}
+		}
+
+		// recover the residue, apply directly to the spectral envelope
+
+		for (int i = 0; i < info.submaps; i++) {
+			int ch_in_bundle = 0;
+			for (int j = 0; j < vi.channels; j++) {
+				if (info.chmuxlist[j] == i) {
+					if (nonzero[j] != 0) {
+						zerobundle[ch_in_bundle] = 1;
+					} else {
+						zerobundle[ch_in_bundle] = 0;
+					}
+					pcmbundle[ch_in_bundle++] = vb.pcm[j];
+				}
+			}
+
+			look.residue_func[i].inverse(vb, look.residue_look[i], pcmbundle, zerobundle, ch_in_bundle);
+		}
+
+		for (int i = info.coupling_steps - 1; i >= 0; i--) {
+			float[] pcmM = vb.pcm[info.coupling_mag[i]];
+			float[] pcmA = vb.pcm[info.coupling_ang[i]];
+
+			for (int j = 0; j < n / 2; j++) {
+				float mag = pcmM[j];
+				float ang = pcmA[j];
+
+				if (mag > 0) {
+					if (ang > 0) {
+						pcmM[j] = mag;
+						pcmA[j] = mag - ang;
+					} else {
+						pcmA[j] = mag;
+						pcmM[j] = mag + ang;
+					}
+				} else {
+					if (ang > 0) {
+						pcmM[j] = mag;
+						pcmA[j] = mag + ang;
+					} else {
+						pcmA[j] = mag;
+						pcmM[j] = mag - ang;
+					}
+				}
+			}
+		}
+
+		// /* compute and apply spectral envelope */
+
+		for (int i = 0; i < vi.channels; i++) {
+			float[] pcm = vb.pcm[i];
+			int submap = info.chmuxlist[i];
+			look.floor_func[submap].inverse2(vb, look.floor_look[submap], floormemo[i], pcm);
+		}
+
+		// transform the PCM data; takes PCM vector, vb; modifies PCM vector
+		// only MDCT right now....
+
+		for (int i = 0; i < vi.channels; i++) {
+			float[] pcm = vb.pcm[i];
+			// _analysis_output("out",seq+i,pcm,n/2,0,0);
+			((Mdct) vd.transform[vb.W][0]).backward(pcm, pcm);
+		}
+
+		// now apply the decoded pre-window time information
+		// NOT IMPLEMENTED
+
+		// window the data
+		for (int i = 0; i < vi.channels; i++) {
+			float[] pcm = vb.pcm[i];
+			if (nonzero[i] != 0) {
+				for (int j = 0; j < n; j++) {
+					pcm[j] *= window[j];
+				}
+			} else {
+				for (int j = 0; j < n; j++) {
+					pcm[j] = 0.f;
+				}
+			}
+		}
+
+		// now apply the decoded post-window time information
+		// NOT IMPLEMENTED
+		// all done!
+		return (0);
+	}
+
+	class InfoMapping0 {
+		int submaps; // <= 16
+		int[] chmuxlist = new int[256]; // up to 256 channels in a Vorbis stream
+
+		int[] timesubmap = new int[16]; // [mux]
+		int[] floorsubmap = new int[16]; // [mux] submap to floors
+		int[] residuesubmap = new int[16];// [mux] submap to residue
+		int[] psysubmap = new int[16]; // [mux]; encode only
+
+		int coupling_steps;
+		int[] coupling_mag = new int[256];
+		int[] coupling_ang = new int[256];
+
+		void free() {
+			chmuxlist = null;
+			timesubmap = null;
+			floorsubmap = null;
+			residuesubmap = null;
+			psysubmap = null;
+
+			coupling_mag = null;
+			coupling_ang = null;
+		}
+	}
+
+	class LookMapping0 {
+		InfoMode mode;
+		InfoMapping0 map;
+		Object[] time_look;
+		Object[] floor_look;
+		Object[] floor_state;
+		Object[] residue_look;
+		PsyLook[] psy_look;
+
+		FuncTime[] time_func;
+		FuncFloor[] floor_func;
+		FuncResidue[] residue_func;
+
+		int ch;
+		float[][] decay;
+		int lastframe; // if a different mode is called, we need to
+		// invalidate decay and floor state
+	}
+
+}
diff --git a/sources/teavm/java/com/jcraft/jorbis/Mdct.java b/sources/teavm/java/com/jcraft/jorbis/Mdct.java
new file mode 100644
index 00000000..c2b29fb0
--- /dev/null
+++ b/sources/teavm/java/com/jcraft/jorbis/Mdct.java
@@ -0,0 +1,249 @@
+/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
+/* JOrbis
+ * Copyright (C) 2000 ymnk, JCraft,Inc.
+ *  
+ * Written by: 2000 ymnk<ymnk@jcraft.com>
+ *   
+ * Many thanks to 
+ *   Monty <monty@xiph.org> and 
+ *   The XIPHOPHORUS Company http://www.xiph.org/ .
+ * JOrbis has been based on their awesome works, Vorbis codec.
+ *   
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public License
+ * as published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+   
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Library General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Library General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+package com.jcraft.jorbis;
+
+class Mdct {
+
+	int n;
+	int log2n;
+
+	float[] trig;
+	int[] bitrev;
+
+	float scale;
+
+	void init(int n) {
+		bitrev = new int[n / 4];
+		trig = new float[n + n / 4];
+
+		log2n = (int) Math.rint(Math.log(n) / Math.log(2));
+		this.n = n;
+
+		int AE = 0;
+		int AO = 1;
+		int BE = AE + n / 2;
+		int BO = BE + 1;
+		int CE = BE + n / 2;
+		int CO = CE + 1;
+		// trig lookups...
+		for (int i = 0; i < n / 4; i++) {
+			trig[AE + i * 2] = (float) Math.cos((Math.PI / n) * (4 * i));
+			trig[AO + i * 2] = (float) -Math.sin((Math.PI / n) * (4 * i));
+			trig[BE + i * 2] = (float) Math.cos((Math.PI / (2 * n)) * (2 * i + 1));
+			trig[BO + i * 2] = (float) Math.sin((Math.PI / (2 * n)) * (2 * i + 1));
+		}
+		for (int i = 0; i < n / 8; i++) {
+			trig[CE + i * 2] = (float) Math.cos((Math.PI / n) * (4 * i + 2));
+			trig[CO + i * 2] = (float) -Math.sin((Math.PI / n) * (4 * i + 2));
+		}
+
+		{
+			int mask = (1 << (log2n - 1)) - 1;
+			int msb = 1 << (log2n - 2);
+			for (int i = 0; i < n / 8; i++) {
+				int acc = 0;
+				for (int j = 0; msb >>> j != 0; j++)
+					if (((msb >>> j) & i) != 0)
+						acc |= 1 << j;
+				bitrev[i * 2] = ((~acc) & mask);
+				// bitrev[i*2]=((~acc)&mask)-1;
+				bitrev[i * 2 + 1] = acc;
+			}
+		}
+		scale = 4.f / n;
+	}
+
+	void clear() {
+	}
+
+	void forward(float[] in, float[] out) {
+	}
+
+	float[] _x = new float[1024];
+	float[] _w = new float[1024];
+
+	synchronized void backward(float[] in, float[] out) {
+		if (_x.length < n / 2) {
+			_x = new float[n / 2];
+		}
+		if (_w.length < n / 2) {
+			_w = new float[n / 2];
+		}
+		float[] x = _x;
+		float[] w = _w;
+		int n2 = n >>> 1;
+		int n4 = n >>> 2;
+		int n8 = n >>> 3;
+
+		// rotate + step 1
+		{
+			int inO = 1;
+			int xO = 0;
+			int A = n2;
+
+			int i;
+			for (i = 0; i < n8; i++) {
+				A -= 2;
+				x[xO++] = -in[inO + 2] * trig[A + 1] - in[inO] * trig[A];
+				x[xO++] = in[inO] * trig[A + 1] - in[inO + 2] * trig[A];
+				inO += 4;
+			}
+
+			inO = n2 - 4;
+
+			for (i = 0; i < n8; i++) {
+				A -= 2;
+				x[xO++] = in[inO] * trig[A + 1] + in[inO + 2] * trig[A];
+				x[xO++] = in[inO] * trig[A] - in[inO + 2] * trig[A + 1];
+				inO -= 4;
+			}
+		}
+
+		float[] xxx = mdct_kernel(x, w, n, n2, n4, n8);
+		int xx = 0;
+
+		// step 8
+
+		{
+			int B = n2;
+			int o1 = n4, o2 = o1 - 1;
+			int o3 = n4 + n2, o4 = o3 - 1;
+
+			for (int i = 0; i < n4; i++) {
+				float temp1 = (xxx[xx] * trig[B + 1] - xxx[xx + 1] * trig[B]);
+				float temp2 = -(xxx[xx] * trig[B] + xxx[xx + 1] * trig[B + 1]);
+
+				out[o1] = -temp1;
+				out[o2] = temp1;
+				out[o3] = temp2;
+				out[o4] = temp2;
+
+				o1++;
+				o2--;
+				o3++;
+				o4--;
+				xx += 2;
+				B += 2;
+			}
+		}
+	}
+
+	private float[] mdct_kernel(float[] x, float[] w, int n, int n2, int n4, int n8) {
+		// step 2
+
+		int xA = n4;
+		int xB = 0;
+		int w2 = n4;
+		int A = n2;
+
+		for (int i = 0; i < n4;) {
+			float x0 = x[xA] - x[xB];
+			float x1;
+			w[w2 + i] = x[xA++] + x[xB++];
+
+			x1 = x[xA] - x[xB];
+			A -= 4;
+
+			w[i++] = x0 * trig[A] + x1 * trig[A + 1];
+			w[i] = x1 * trig[A] - x0 * trig[A + 1];
+
+			w[w2 + i] = x[xA++] + x[xB++];
+			i++;
+		}
+
+		// step 3
+
+		{
+			for (int i = 0; i < log2n - 3; i++) {
+				int k0 = n >>> (i + 2);
+				int k1 = 1 << (i + 3);
+				int wbase = n2 - 2;
+
+				A = 0;
+				float[] temp;
+
+				for (int r = 0; r < (k0 >>> 2); r++) {
+					int w1 = wbase;
+					w2 = w1 - (k0 >> 1);
+					float AEv = trig[A], wA;
+					float AOv = trig[A + 1], wB;
+					wbase -= 2;
+
+					k0++;
+					for (int s = 0; s < (2 << i); s++) {
+						wB = w[w1] - w[w2];
+						x[w1] = w[w1] + w[w2];
+
+						wA = w[++w1] - w[++w2];
+						x[w1] = w[w1] + w[w2];
+
+						x[w2] = wA * AEv - wB * AOv;
+						x[w2 - 1] = wB * AEv + wA * AOv;
+
+						w1 -= k0;
+						w2 -= k0;
+					}
+					k0--;
+					A += k1;
+				}
+
+				temp = w;
+				w = x;
+				x = temp;
+			}
+		}
+
+		// step 4, 5, 6, 7
+		{
+			int C = n;
+			int bit = 0;
+			int x1 = 0;
+			int x2 = n2 - 1;
+
+			for (int i = 0; i < n8; i++) {
+				int t1 = bitrev[bit++];
+				int t2 = bitrev[bit++];
+
+				float wA = w[t1] - w[t2 + 1];
+				float wB = w[t1 - 1] + w[t2];
+				float wC = w[t1] + w[t2 + 1];
+				float wD = w[t1 - 1] - w[t2];
+
+				float wACE = wA * trig[C];
+				float wBCE = wB * trig[C++];
+				float wACO = wA * trig[C];
+				float wBCO = wB * trig[C++];
+
+				x[x1++] = (wC + wACO + wBCE) * .5f;
+				x[x2--] = (-wD + wBCO - wACE) * .5f;
+				x[x1++] = (wD + wBCO - wACE) * .5f;
+				x[x2--] = (wC - wACO - wBCE) * .5f;
+			}
+		}
+		return (x);
+	}
+}
diff --git a/sources/teavm/java/com/jcraft/jorbis/PsyInfo.java b/sources/teavm/java/com/jcraft/jorbis/PsyInfo.java
new file mode 100644
index 00000000..906efab5
--- /dev/null
+++ b/sources/teavm/java/com/jcraft/jorbis/PsyInfo.java
@@ -0,0 +1,74 @@
+/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
+/* JOrbis
+ * Copyright (C) 2000 ymnk, JCraft,Inc.
+ *  
+ * Written by: 2000 ymnk<ymnk@jcraft.com>
+ *   
+ * Many thanks to 
+ *   Monty <monty@xiph.org> and 
+ *   The XIPHOPHORUS Company http://www.xiph.org/ .
+ * JOrbis has been based on their awesome works, Vorbis codec.
+ *   
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public License
+ * as published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+   
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Library General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Library General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+package com.jcraft.jorbis;
+
+// psychoacoustic setup
+class PsyInfo {
+	int athp;
+	int decayp;
+	int smoothp;
+	int noisefitp;
+	int noisefit_subblock;
+	float noisefit_threshdB;
+
+	float ath_att;
+
+	int tonemaskp;
+	float[] toneatt_125Hz = new float[5];
+	float[] toneatt_250Hz = new float[5];
+	float[] toneatt_500Hz = new float[5];
+	float[] toneatt_1000Hz = new float[5];
+	float[] toneatt_2000Hz = new float[5];
+	float[] toneatt_4000Hz = new float[5];
+	float[] toneatt_8000Hz = new float[5];
+
+	int peakattp;
+	float[] peakatt_125Hz = new float[5];
+	float[] peakatt_250Hz = new float[5];
+	float[] peakatt_500Hz = new float[5];
+	float[] peakatt_1000Hz = new float[5];
+	float[] peakatt_2000Hz = new float[5];
+	float[] peakatt_4000Hz = new float[5];
+	float[] peakatt_8000Hz = new float[5];
+
+	int noisemaskp;
+	float[] noiseatt_125Hz = new float[5];
+	float[] noiseatt_250Hz = new float[5];
+	float[] noiseatt_500Hz = new float[5];
+	float[] noiseatt_1000Hz = new float[5];
+	float[] noiseatt_2000Hz = new float[5];
+	float[] noiseatt_4000Hz = new float[5];
+	float[] noiseatt_8000Hz = new float[5];
+
+	float max_curve_dB;
+
+	float attack_coeff;
+	float decay_coeff;
+
+	void free() {
+	}
+}
diff --git a/sources/teavm/java/com/jcraft/jorbis/PsyLook.java b/sources/teavm/java/com/jcraft/jorbis/PsyLook.java
new file mode 100644
index 00000000..8fee7bf2
--- /dev/null
+++ b/sources/teavm/java/com/jcraft/jorbis/PsyLook.java
@@ -0,0 +1,42 @@
+/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
+/* JOrbis
+ * Copyright (C) 2000 ymnk, JCraft,Inc.
+ *  
+ * Written by: 2000 ymnk<ymnk@jcraft.com>
+ *   
+ * Many thanks to 
+ *   Monty <monty@xiph.org> and 
+ *   The XIPHOPHORUS Company http://www.xiph.org/ .
+ * JOrbis has been based on their awesome works, Vorbis codec.
+ *   
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public License
+ * as published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+   
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Library General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Library General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+package com.jcraft.jorbis;
+
+class PsyLook {
+	int n;
+	PsyInfo vi;
+
+	float[][][] tonecurves;
+	float[][] peakatt;
+	float[][][] noisecurves;
+
+	float[] ath;
+	int[] octave;
+
+	void init(PsyInfo vi, int n, int rate) {
+	}
+}
diff --git a/sources/teavm/java/com/jcraft/jorbis/Residue0.java b/sources/teavm/java/com/jcraft/jorbis/Residue0.java
new file mode 100644
index 00000000..d9197096
--- /dev/null
+++ b/sources/teavm/java/com/jcraft/jorbis/Residue0.java
@@ -0,0 +1,326 @@
+/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
+/* JOrbis
+ * Copyright (C) 2000 ymnk, JCraft,Inc.
+ *  
+ * Written by: 2000 ymnk<ymnk@jcraft.com>
+ *   
+ * Many thanks to 
+ *   Monty <monty@xiph.org> and 
+ *   The XIPHOPHORUS Company http://www.xiph.org/ .
+ * JOrbis has been based on their awesome works, Vorbis codec.
+ *   
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public License
+ * as published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+   
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Library General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Library General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+package com.jcraft.jorbis;
+
+import com.jcraft.jogg.*;
+
+class Residue0 extends FuncResidue {
+	void pack(Object vr, Buffer opb) {
+		InfoResidue0 info = (InfoResidue0) vr;
+		int acc = 0;
+		opb.write(info.begin, 24);
+		opb.write(info.end, 24);
+
+		opb.write(info.grouping - 1, 24); /*
+											 * residue vectors to group and code with a partitioned book
+											 */
+		opb.write(info.partitions - 1, 6); /* possible partition choices */
+		opb.write(info.groupbook, 8); /* group huffman book */
+
+		/*
+		 * secondstages is a bitmask; as encoding progresses pass by pass, a bitmask of
+		 * one indicates this partition class has bits to write this pass
+		 */
+		for (int j = 0; j < info.partitions; j++) {
+			int i = info.secondstages[j];
+			if (Util.ilog(i) > 3) {
+				/* yes, this is a minor hack due to not thinking ahead */
+				opb.write(i, 3);
+				opb.write(1, 1);
+				opb.write(i >>> 3, 5);
+			} else {
+				opb.write(i, 4); /* trailing zero */
+			}
+			acc += Util.icount(i);
+		}
+		for (int j = 0; j < acc; j++) {
+			opb.write(info.booklist[j], 8);
+		}
+	}
+
+	Object unpack(Info vi, Buffer opb) {
+		int acc = 0;
+		InfoResidue0 info = new InfoResidue0();
+		info.begin = opb.read(24);
+		info.end = opb.read(24);
+		info.grouping = opb.read(24) + 1;
+		info.partitions = opb.read(6) + 1;
+		info.groupbook = opb.read(8);
+
+		for (int j = 0; j < info.partitions; j++) {
+			int cascade = opb.read(3);
+			if (opb.read(1) != 0) {
+				cascade |= (opb.read(5) << 3);
+			}
+			info.secondstages[j] = cascade;
+			acc += Util.icount(cascade);
+		}
+
+		for (int j = 0; j < acc; j++) {
+			info.booklist[j] = opb.read(8);
+		}
+
+		if (info.groupbook >= vi.books) {
+			free_info(info);
+			return (null);
+		}
+
+		for (int j = 0; j < acc; j++) {
+			if (info.booklist[j] >= vi.books) {
+				free_info(info);
+				return (null);
+			}
+		}
+		return (info);
+	}
+
+	Object look(DspState vd, InfoMode vm, Object vr) {
+		InfoResidue0 info = (InfoResidue0) vr;
+		LookResidue0 look = new LookResidue0();
+		int acc = 0;
+		int dim;
+		int maxstage = 0;
+		look.info = info;
+		look.map = vm.mapping;
+
+		look.parts = info.partitions;
+		look.fullbooks = vd.fullbooks;
+		look.phrasebook = vd.fullbooks[info.groupbook];
+
+		dim = look.phrasebook.dim;
+
+		look.partbooks = new int[look.parts][];
+
+		for (int j = 0; j < look.parts; j++) {
+			int i = info.secondstages[j];
+			int stages = Util.ilog(i);
+			if (stages != 0) {
+				if (stages > maxstage)
+					maxstage = stages;
+				look.partbooks[j] = new int[stages];
+				for (int k = 0; k < stages; k++) {
+					if ((i & (1 << k)) != 0) {
+						look.partbooks[j][k] = info.booklist[acc++];
+					}
+				}
+			}
+		}
+
+		look.partvals = (int) Math.rint(Math.pow(look.parts, dim));
+		look.stages = maxstage;
+		look.decodemap = new int[look.partvals][];
+		for (int j = 0; j < look.partvals; j++) {
+			int val = j;
+			int mult = look.partvals / look.parts;
+			look.decodemap[j] = new int[dim];
+
+			for (int k = 0; k < dim; k++) {
+				int deco = val / mult;
+				val -= deco * mult;
+				mult /= look.parts;
+				look.decodemap[j][k] = deco;
+			}
+		}
+		return (look);
+	}
+
+	void free_info(Object i) {
+	}
+
+	void free_look(Object i) {
+	}
+
+	private static int[][][] _01inverse_partword = new int[2][][]; // _01inverse is synchronized for
+
+	// re-using partword
+	synchronized static int _01inverse(Block vb, Object vl, float[][] in, int ch, int decodepart) {
+		int i, j, k, l, s;
+		LookResidue0 look = (LookResidue0) vl;
+		InfoResidue0 info = look.info;
+
+		// move all this setup out later
+		int samples_per_partition = info.grouping;
+		int partitions_per_word = look.phrasebook.dim;
+		int n = info.end - info.begin;
+
+		int partvals = n / samples_per_partition;
+		int partwords = (partvals + partitions_per_word - 1) / partitions_per_word;
+
+		if (_01inverse_partword.length < ch) {
+			_01inverse_partword = new int[ch][][];
+		}
+
+		for (j = 0; j < ch; j++) {
+			if (_01inverse_partword[j] == null || _01inverse_partword[j].length < partwords) {
+				_01inverse_partword[j] = new int[partwords][];
+			}
+		}
+
+		for (s = 0; s < look.stages; s++) {
+			// each loop decodes on partition codeword containing
+			// partitions_pre_word partitions
+			for (i = 0, l = 0; i < partvals; l++) {
+				if (s == 0) {
+					// fetch the partition word for each channel
+					for (j = 0; j < ch; j++) {
+						int temp = look.phrasebook.decode(vb.opb);
+						if (temp == -1) {
+							return (0);
+						}
+						_01inverse_partword[j][l] = look.decodemap[temp];
+						if (_01inverse_partword[j][l] == null) {
+							return (0);
+						}
+					}
+				}
+
+				// now we decode residual values for the partitions
+				for (k = 0; k < partitions_per_word && i < partvals; k++, i++)
+					for (j = 0; j < ch; j++) {
+						int offset = info.begin + i * samples_per_partition;
+						int index = _01inverse_partword[j][l][k];
+						if ((info.secondstages[index] & (1 << s)) != 0) {
+							CodeBook stagebook = look.fullbooks[look.partbooks[index][s]];
+							if (stagebook != null) {
+								if (decodepart == 0) {
+									if (stagebook.decodevs_add(in[j], offset, vb.opb, samples_per_partition) == -1) {
+										return (0);
+									}
+								} else if (decodepart == 1) {
+									if (stagebook.decodev_add(in[j], offset, vb.opb, samples_per_partition) == -1) {
+										return (0);
+									}
+								}
+							}
+						}
+					}
+			}
+		}
+		return (0);
+	}
+
+	static int[][] _2inverse_partword = null;
+
+	synchronized static int _2inverse(Block vb, Object vl, float[][] in, int ch) {
+		int i, k, l, s;
+		LookResidue0 look = (LookResidue0) vl;
+		InfoResidue0 info = look.info;
+
+		// move all this setup out later
+		int samples_per_partition = info.grouping;
+		int partitions_per_word = look.phrasebook.dim;
+		int n = info.end - info.begin;
+
+		int partvals = n / samples_per_partition;
+		int partwords = (partvals + partitions_per_word - 1) / partitions_per_word;
+
+		if (_2inverse_partword == null || _2inverse_partword.length < partwords) {
+			_2inverse_partword = new int[partwords][];
+		}
+		for (s = 0; s < look.stages; s++) {
+			for (i = 0, l = 0; i < partvals; l++) {
+				if (s == 0) {
+					// fetch the partition word for each channel
+					int temp = look.phrasebook.decode(vb.opb);
+					if (temp == -1) {
+						return (0);
+					}
+					_2inverse_partword[l] = look.decodemap[temp];
+					if (_2inverse_partword[l] == null) {
+						return (0);
+					}
+				}
+
+				// now we decode residual values for the partitions
+				for (k = 0; k < partitions_per_word && i < partvals; k++, i++) {
+					int offset = info.begin + i * samples_per_partition;
+					int index = _2inverse_partword[l][k];
+					if ((info.secondstages[index] & (1 << s)) != 0) {
+						CodeBook stagebook = look.fullbooks[look.partbooks[index][s]];
+						if (stagebook != null) {
+							if (stagebook.decodevv_add(in, offset, ch, vb.opb, samples_per_partition) == -1) {
+								return (0);
+							}
+						}
+					}
+				}
+			}
+		}
+		return (0);
+	}
+
+	int inverse(Block vb, Object vl, float[][] in, int[] nonzero, int ch) {
+		int used = 0;
+		for (int i = 0; i < ch; i++) {
+			if (nonzero[i] != 0) {
+				in[used++] = in[i];
+			}
+		}
+		if (used != 0)
+			return (_01inverse(vb, vl, in, used, 0));
+		else
+			return (0);
+	}
+
+	class LookResidue0 {
+		InfoResidue0 info;
+		int map;
+
+		int parts;
+		int stages;
+		CodeBook[] fullbooks;
+		CodeBook phrasebook;
+		int[][] partbooks;
+
+		int partvals;
+		int[][] decodemap;
+
+		int postbits;
+		int phrasebits;
+		int frames;
+	}
+
+	class InfoResidue0 {
+		// block-partitioned VQ coded straight residue
+		int begin;
+		int end;
+
+		// first stage (lossless partitioning)
+		int grouping; // group n vectors per partition
+		int partitions; // possible codebooks for a partition
+		int groupbook; // huffbook for partitioning
+		int[] secondstages = new int[64]; // expanded out to pointers in lookup
+		int[] booklist = new int[256]; // list of second stage books
+
+		// encode-only heuristic settings
+		float[] entmax = new float[64]; // book entropy threshholds
+		float[] ampmax = new float[64]; // book amp threshholds
+		int[] subgrp = new int[64]; // book heuristic subgroup size
+		int[] blimit = new int[64]; // subgroup position limits
+	}
+
+}
diff --git a/sources/teavm/java/com/jcraft/jorbis/Residue1.java b/sources/teavm/java/com/jcraft/jorbis/Residue1.java
new file mode 100644
index 00000000..55b0d9ae
--- /dev/null
+++ b/sources/teavm/java/com/jcraft/jorbis/Residue1.java
@@ -0,0 +1,44 @@
+/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
+/* JOrbis
+ * Copyright (C) 2000 ymnk, JCraft,Inc.
+ *  
+ * Written by: 2000 ymnk<ymnk@jcraft.com>
+ *   
+ * Many thanks to 
+ *   Monty <monty@xiph.org> and 
+ *   The XIPHOPHORUS Company http://www.xiph.org/ .
+ * JOrbis has been based on their awesome works, Vorbis codec.
+ *   
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public License
+ * as published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+   
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Library General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Library General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+package com.jcraft.jorbis;
+
+class Residue1 extends Residue0 {
+
+	int inverse(Block vb, Object vl, float[][] in, int[] nonzero, int ch) {
+		int used = 0;
+		for (int i = 0; i < ch; i++) {
+			if (nonzero[i] != 0) {
+				in[used++] = in[i];
+			}
+		}
+		if (used != 0) {
+			return (_01inverse(vb, vl, in, used, 1));
+		} else {
+			return 0;
+		}
+	}
+}
diff --git a/sources/teavm/java/com/jcraft/jorbis/Residue2.java b/sources/teavm/java/com/jcraft/jorbis/Residue2.java
new file mode 100644
index 00000000..cb4ec8f9
--- /dev/null
+++ b/sources/teavm/java/com/jcraft/jorbis/Residue2.java
@@ -0,0 +1,41 @@
+/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
+/* JOrbis
+ * Copyright (C) 2000 ymnk, JCraft,Inc.
+ *  
+ * Written by: 2000 ymnk<ymnk@jcraft.com>
+ *   
+ * Many thanks to 
+ *   Monty <monty@xiph.org> and 
+ *   The XIPHOPHORUS Company http://www.xiph.org/ .
+ * JOrbis has been based on their awesome works, Vorbis codec.
+ *   
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public License
+ * as published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+   
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Library General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Library General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+package com.jcraft.jorbis;
+
+class Residue2 extends Residue0 {
+
+	int inverse(Block vb, Object vl, float[][] in, int[] nonzero, int ch) {
+		int i = 0;
+		for (i = 0; i < ch; i++)
+			if (nonzero[i] != 0)
+				break;
+		if (i == ch)
+			return (0); /* no nonzero vectors */
+
+		return (_2inverse(vb, vl, in, ch));
+	}
+}
diff --git a/sources/teavm/java/com/jcraft/jorbis/StaticCodeBook.java b/sources/teavm/java/com/jcraft/jorbis/StaticCodeBook.java
new file mode 100644
index 00000000..d06a2e85
--- /dev/null
+++ b/sources/teavm/java/com/jcraft/jorbis/StaticCodeBook.java
@@ -0,0 +1,436 @@
+/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
+/* JOrbis
+ * Copyright (C) 2000 ymnk, JCraft,Inc.
+ *  
+ * Written by: 2000 ymnk<ymnk@jcraft.com>
+ *   
+ * Many thanks to 
+ *   Monty <monty@xiph.org> and 
+ *   The XIPHOPHORUS Company http://www.xiph.org/ .
+ * JOrbis has been based on their awesome works, Vorbis codec.
+ *   
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public License
+ * as published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+   
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Library General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Library General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+package com.jcraft.jorbis;
+
+import com.jcraft.jogg.*;
+
+class StaticCodeBook {
+	int dim; // codebook dimensions (elements per vector)
+	int entries; // codebook entries
+	int[] lengthlist; // codeword lengths in bits
+
+	// mapping
+	int maptype; // 0=none
+	// 1=implicitly populated values from map column
+	// 2=listed arbitrary values
+
+	// The below does a linear, single monotonic sequence mapping.
+	int q_min; // packed 32 bit float; quant value 0 maps to minval
+	int q_delta; // packed 32 bit float; val 1 - val 0 == delta
+	int q_quant; // bits: 0 < quant <= 16
+	int q_sequencep; // bitflag
+
+	// additional information for log (dB) mapping; the linear mapping
+	// is assumed to actually be values in dB. encodebias is used to
+	// assign an error weight to 0 dB. We have two additional flags:
+	// zeroflag indicates if entry zero is to represent -Inf dB; negflag
+	// indicates if we're to represent negative linear values in a
+	// mirror of the positive mapping.
+
+	int[] quantlist; // map == 1: (int)(entries/dim) element column map
+	// map == 2: list of dim*entries quantized entry vals
+
+	StaticCodeBook() {
+	}
+
+	int pack(Buffer opb) {
+		int i;
+		boolean ordered = false;
+
+		opb.write(0x564342, 24);
+		opb.write(dim, 16);
+		opb.write(entries, 24);
+
+		// pack the codewords. There are two packings; length ordered and
+		// length random. Decide between the two now.
+
+		for (i = 1; i < entries; i++) {
+			if (lengthlist[i] < lengthlist[i - 1])
+				break;
+		}
+		if (i == entries)
+			ordered = true;
+
+		if (ordered) {
+			// length ordered. We only need to say how many codewords of
+			// each length. The actual codewords are generated
+			// deterministically
+
+			int count = 0;
+			opb.write(1, 1); // ordered
+			opb.write(lengthlist[0] - 1, 5); // 1 to 32
+
+			for (i = 1; i < entries; i++) {
+				int _this = lengthlist[i];
+				int _last = lengthlist[i - 1];
+				if (_this > _last) {
+					for (int j = _last; j < _this; j++) {
+						opb.write(i - count, Util.ilog(entries - count));
+						count = i;
+					}
+				}
+			}
+			opb.write(i - count, Util.ilog(entries - count));
+		} else {
+			// length random. Again, we don't code the codeword itself, just
+			// the length. This time, though, we have to encode each length
+			opb.write(0, 1); // unordered
+
+			// algortihmic mapping has use for 'unused entries', which we tag
+			// here. The algorithmic mapping happens as usual, but the unused
+			// entry has no codeword.
+			for (i = 0; i < entries; i++) {
+				if (lengthlist[i] == 0)
+					break;
+			}
+
+			if (i == entries) {
+				opb.write(0, 1); // no unused entries
+				for (i = 0; i < entries; i++) {
+					opb.write(lengthlist[i] - 1, 5);
+				}
+			} else {
+				opb.write(1, 1); // we have unused entries; thus we tag
+				for (i = 0; i < entries; i++) {
+					if (lengthlist[i] == 0) {
+						opb.write(0, 1);
+					} else {
+						opb.write(1, 1);
+						opb.write(lengthlist[i] - 1, 5);
+					}
+				}
+			}
+		}
+
+		// is the entry number the desired return value, or do we have a
+		// mapping? If we have a mapping, what type?
+		opb.write(maptype, 4);
+		switch (maptype) {
+		case 0:
+			// no mapping
+			break;
+		case 1:
+		case 2:
+			// implicitly populated value mapping
+			// explicitly populated value mapping
+			if (quantlist == null) {
+				// no quantlist? error
+				return (-1);
+			}
+
+			// values that define the dequantization
+			opb.write(q_min, 32);
+			opb.write(q_delta, 32);
+			opb.write(q_quant - 1, 4);
+			opb.write(q_sequencep, 1);
+
+		{
+			int quantvals = 0;
+			switch (maptype) {
+			case 1:
+				// a single column of (c->entries/c->dim) quantized values for
+				// building a full value list algorithmically (square lattice)
+				quantvals = maptype1_quantvals();
+				break;
+			case 2:
+				// every value (c->entries*c->dim total) specified explicitly
+				quantvals = entries * dim;
+				break;
+			}
+
+			// quantized values
+			for (i = 0; i < quantvals; i++) {
+				opb.write(Math.abs(quantlist[i]), q_quant);
+			}
+		}
+			break;
+		default:
+			// error case; we don't have any other map types now
+			return (-1);
+		}
+		return (0);
+	}
+
+	// unpacks a codebook from the packet buffer into the codebook struct,
+	// readies the codebook auxiliary structures for decode
+	int unpack(Buffer opb) {
+		int i;
+		// memset(s,0,sizeof(static_codebook));
+
+		// make sure alignment is correct
+		if (opb.read(24) != 0x564342) {
+			// goto _eofout;
+			clear();
+			return (-1);
+		}
+
+		// first the basic parameters
+		dim = opb.read(16);
+		entries = opb.read(24);
+		if (entries == -1) {
+			// goto _eofout;
+			clear();
+			return (-1);
+		}
+
+		// codeword ordering.... length ordered or unordered?
+		switch (opb.read(1)) {
+		case 0:
+			// unordered
+			lengthlist = new int[entries];
+
+			// allocated but unused entries?
+			if (opb.read(1) != 0) {
+				// yes, unused entries
+
+				for (i = 0; i < entries; i++) {
+					if (opb.read(1) != 0) {
+						int num = opb.read(5);
+						if (num == -1) {
+							// goto _eofout;
+							clear();
+							return (-1);
+						}
+						lengthlist[i] = num + 1;
+					} else {
+						lengthlist[i] = 0;
+					}
+				}
+			} else {
+				// all entries used; no tagging
+				for (i = 0; i < entries; i++) {
+					int num = opb.read(5);
+					if (num == -1) {
+						// goto _eofout;
+						clear();
+						return (-1);
+					}
+					lengthlist[i] = num + 1;
+				}
+			}
+			break;
+		case 1:
+		// ordered
+		{
+			int length = opb.read(5) + 1;
+			lengthlist = new int[entries];
+
+			for (i = 0; i < entries;) {
+				int num = opb.read(Util.ilog(entries - i));
+				if (num == -1) {
+					// goto _eofout;
+					clear();
+					return (-1);
+				}
+				for (int j = 0; j < num; j++, i++) {
+					lengthlist[i] = length;
+				}
+				length++;
+			}
+		}
+			break;
+		default:
+			// EOF
+			return (-1);
+		}
+
+		// Do we have a mapping to unpack?
+		switch ((maptype = opb.read(4))) {
+		case 0:
+			// no mapping
+			break;
+		case 1:
+		case 2:
+			// implicitly populated value mapping
+			// explicitly populated value mapping
+			q_min = opb.read(32);
+			q_delta = opb.read(32);
+			q_quant = opb.read(4) + 1;
+			q_sequencep = opb.read(1);
+
+		{
+			int quantvals = 0;
+			switch (maptype) {
+			case 1:
+				quantvals = maptype1_quantvals();
+				break;
+			case 2:
+				quantvals = entries * dim;
+				break;
+			}
+
+			// quantized values
+			quantlist = new int[quantvals];
+			for (i = 0; i < quantvals; i++) {
+				quantlist[i] = opb.read(q_quant);
+			}
+			if (quantlist[quantvals - 1] == -1) {
+				// goto _eofout;
+				clear();
+				return (-1);
+			}
+		}
+			break;
+		default:
+			// goto _eofout;
+			clear();
+			return (-1);
+		}
+		// all set
+		return (0);
+		// _errout:
+		// _eofout:
+		// vorbis_staticbook_clear(s);
+		// return(-1);
+	}
+
+	// there might be a straightforward one-line way to do the below
+	// that's portable and totally safe against roundoff, but I haven't
+	// thought of it. Therefore, we opt on the side of caution
+	private int maptype1_quantvals() {
+		int vals = (int) (Math.floor(Math.pow(entries, 1. / dim)));
+
+		// the above *should* be reliable, but we'll not assume that FP is
+		// ever reliable when bitstream sync is at stake; verify via integer
+		// means that vals really is the greatest value of dim for which
+		// vals^b->bim <= b->entries
+		// treat the above as an initial guess
+		while (true) {
+			int acc = 1;
+			int acc1 = 1;
+			for (int i = 0; i < dim; i++) {
+				acc *= vals;
+				acc1 *= vals + 1;
+			}
+			if (acc <= entries && acc1 > entries) {
+				return (vals);
+			} else {
+				if (acc > entries) {
+					vals--;
+				} else {
+					vals++;
+				}
+			}
+		}
+	}
+
+	void clear() {
+	}
+
+	// unpack the quantized list of values for encode/decode
+	// we need to deal with two map types: in map type 1, the values are
+	// generated algorithmically (each column of the vector counts through
+	// the values in the quant vector). in map type 2, all the values came
+	// in in an explicit list. Both value lists must be unpacked
+	float[] unquantize() {
+
+		if (maptype == 1 || maptype == 2) {
+			int quantvals;
+			float mindel = float32_unpack(q_min);
+			float delta = float32_unpack(q_delta);
+			float[] r = new float[entries * dim];
+
+			// maptype 1 and 2 both use a quantized value vector, but
+			// different sizes
+			switch (maptype) {
+			case 1:
+				// most of the time, entries%dimensions == 0, but we need to be
+				// well defined. We define that the possible vales at each
+				// scalar is values == entries/dim. If entries%dim != 0, we'll
+				// have 'too few' values (values*dim<entries), which means that
+				// we'll have 'left over' entries; left over entries use zeroed
+				// values (and are wasted). So don't generate codebooks like that
+				quantvals = maptype1_quantvals();
+				for (int j = 0; j < entries; j++) {
+					float last = 0.f;
+					int indexdiv = 1;
+					for (int k = 0; k < dim; k++) {
+						int index = (j / indexdiv) % quantvals;
+						float val = quantlist[index];
+						val = Math.abs(val) * delta + mindel + last;
+						if (q_sequencep != 0)
+							last = val;
+						r[j * dim + k] = val;
+						indexdiv *= quantvals;
+					}
+				}
+				break;
+			case 2:
+				for (int j = 0; j < entries; j++) {
+					float last = 0.f;
+					for (int k = 0; k < dim; k++) {
+						float val = quantlist[j * dim + k];
+						// if((j*dim+k)==0){System.err.println(" | 0 -> "+val+" | ");}
+						val = Math.abs(val) * delta + mindel + last;
+						if (q_sequencep != 0)
+							last = val;
+						r[j * dim + k] = val;
+						// if((j*dim+k)==0){System.err.println(" $ r[0] -> "+r[0]+" | ");}
+					}
+				}
+				// System.err.println("\nr[0]="+r[0]);
+			}
+			return (r);
+		}
+		return (null);
+	}
+
+	// 32 bit float (not IEEE; nonnormalized mantissa +
+	// biased exponent) : neeeeeee eeemmmmm mmmmmmmm mmmmmmmm
+	// Why not IEEE? It's just not that important here.
+
+	static final int VQ_FEXP = 10;
+	static final int VQ_FMAN = 21;
+	static final int VQ_FEXP_BIAS = 768; // bias toward values smaller than 1.
+
+	// doesn't currently guard under/overflow
+	static long float32_pack(float val) {
+		int sign = 0;
+		int exp;
+		int mant;
+		if (val < 0) {
+			sign = 0x80000000;
+			val = -val;
+		}
+		exp = (int) Math.floor(Math.log(val) / Math.log(2));
+		mant = (int) Math.rint(Math.pow(val, (VQ_FMAN - 1) - exp));
+		exp = (exp + VQ_FEXP_BIAS) << VQ_FMAN;
+		return (sign | exp | mant);
+	}
+
+	static float float32_unpack(int val) {
+		float mant = val & 0x1fffff;
+		float exp = (val & 0x7fe00000) >>> VQ_FMAN;
+		if ((val & 0x80000000) != 0)
+			mant = -mant;
+		return (ldexp(mant, ((int) exp) - (VQ_FMAN - 1) - VQ_FEXP_BIAS));
+	}
+
+	static float ldexp(float foo, int e) {
+		return (float) (foo * Math.pow(2, e));
+	}
+}
diff --git a/sources/teavm/java/com/jcraft/jorbis/Time0.java b/sources/teavm/java/com/jcraft/jorbis/Time0.java
new file mode 100644
index 00000000..3e9e81f2
--- /dev/null
+++ b/sources/teavm/java/com/jcraft/jorbis/Time0.java
@@ -0,0 +1,52 @@
+/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
+/* JOrbis
+ * Copyright (C) 2000 ymnk, JCraft,Inc.
+ *  
+ * Written by: 2000 ymnk<ymnk@jcraft.com>
+ *   
+ * Many thanks to 
+ *   Monty <monty@xiph.org> and 
+ *   The XIPHOPHORUS Company http://www.xiph.org/ .
+ * JOrbis has been based on their awesome works, Vorbis codec.
+ *   
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public License
+ * as published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+   
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Library General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Library General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+package com.jcraft.jorbis;
+
+import com.jcraft.jogg.*;
+
+class Time0 extends FuncTime {
+	void pack(Object i, Buffer opb) {
+	}
+
+	Object unpack(Info vi, Buffer opb) {
+		return "";
+	}
+
+	Object look(DspState vd, InfoMode mi, Object i) {
+		return "";
+	}
+
+	void free_info(Object i) {
+	}
+
+	void free_look(Object i) {
+	}
+
+	int inverse(Block vb, Object i, float[] in, float[] out) {
+		return 0;
+	}
+}
diff --git a/sources/teavm/java/com/jcraft/jorbis/Util.java b/sources/teavm/java/com/jcraft/jorbis/Util.java
new file mode 100644
index 00000000..9efb0a9c
--- /dev/null
+++ b/sources/teavm/java/com/jcraft/jorbis/Util.java
@@ -0,0 +1,30 @@
+package com.jcraft.jorbis;
+
+class Util {
+	static int ilog(int v) {
+		int ret = 0;
+		while (v != 0) {
+			ret++;
+			v >>>= 1;
+		}
+		return (ret);
+	}
+
+	static int ilog2(int v) {
+		int ret = 0;
+		while (v > 1) {
+			ret++;
+			v >>>= 1;
+		}
+		return (ret);
+	}
+
+	static int icount(int v) {
+		int ret = 0;
+		while (v != 0) {
+			ret += (v & 1);
+			v >>>= 1;
+		}
+		return (ret);
+	}
+}
diff --git a/sources/teavm/java/com/jcraft/jorbis/VorbisFile.java b/sources/teavm/java/com/jcraft/jorbis/VorbisFile.java
new file mode 100644
index 00000000..42227408
--- /dev/null
+++ b/sources/teavm/java/com/jcraft/jorbis/VorbisFile.java
@@ -0,0 +1,1348 @@
+/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
+/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
+/* JOrbis
+ * Copyright (C) 2000 ymnk, JCraft,Inc.
+ *  
+ * Written by: 2000 ymnk<ymnk@jcraft.com>
+ *   
+ * Many thanks to 
+ *   Monty <monty@xiph.org> and 
+ *   The XIPHOPHORUS Company http://www.xiph.org/ .
+ * JOrbis has been based on their awesome works, Vorbis codec.
+ *   
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public License
+ * as published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+   
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Library General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Library General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+package com.jcraft.jorbis;
+
+import com.jcraft.jogg.*;
+
+import java.io.InputStream;
+import java.io.IOException;
+
+public class VorbisFile {
+	static final int CHUNKSIZE = 8500;
+	static final int SEEK_SET = 0;
+	static final int SEEK_CUR = 1;
+	static final int SEEK_END = 2;
+
+	static final int OV_FALSE = -1;
+	static final int OV_EOF = -2;
+	static final int OV_HOLE = -3;
+
+	static final int OV_EREAD = -128;
+	static final int OV_EFAULT = -129;
+	static final int OV_EIMPL = -130;
+	static final int OV_EINVAL = -131;
+	static final int OV_ENOTVORBIS = -132;
+	static final int OV_EBADHEADER = -133;
+	static final int OV_EVERSION = -134;
+	static final int OV_ENOTAUDIO = -135;
+	static final int OV_EBADPACKET = -136;
+	static final int OV_EBADLINK = -137;
+	static final int OV_ENOSEEK = -138;
+
+	InputStream datasource;
+	boolean seekable = false;
+	long offset;
+	long end;
+
+	SyncState oy = new SyncState();
+
+	int links;
+	long[] offsets;
+	long[] dataoffsets;
+	int[] serialnos;
+	long[] pcmlengths;
+	Info[] vi;
+	Comment[] vc;
+
+	// Decoding working state local storage
+	long pcm_offset;
+	boolean decode_ready = false;
+
+	int current_serialno;
+	int current_link;
+
+	float bittrack;
+	float samptrack;
+
+	StreamState os = new StreamState(); // take physical pages, weld into a logical
+	// stream of packets
+	DspState vd = new DspState(); // central working state for
+	// the packet->PCM decoder
+	Block vb = new Block(vd); // local working space for packet->PCM decode
+
+	// ov_callbacks callbacks;
+
+	public VorbisFile(String file) throws JOrbisException {
+		super();
+		InputStream is = null;
+		try {
+			is = new SeekableInputStream(file);
+			int ret = open(is, null, 0);
+			if (ret == -1) {
+				throw new JOrbisException("VorbisFile: open return -1");
+			}
+		} catch (Exception e) {
+			throw new JOrbisException("VorbisFile: " + e.toString());
+		} finally {
+			if (is != null) {
+				try {
+					is.close();
+				} catch (IOException e) {
+					e.printStackTrace();
+				}
+			}
+		}
+	}
+
+	public VorbisFile(InputStream is, byte[] initial, int ibytes) throws JOrbisException {
+		super();
+		int ret = open(is, initial, ibytes);
+		if (ret == -1) {
+		}
+	}
+
+	private int get_data() {
+		int index = oy.buffer(CHUNKSIZE);
+		byte[] buffer = oy.data;
+		int bytes = 0;
+		try {
+			bytes = datasource.read(buffer, index, CHUNKSIZE);
+		} catch (Exception e) {
+			return OV_EREAD;
+		}
+		oy.wrote(bytes);
+		if (bytes == -1) {
+			bytes = 0;
+		}
+		return bytes;
+	}
+
+	private void seek_helper(long offst) {
+		fseek(datasource, offst, SEEK_SET);
+		this.offset = offst;
+		oy.reset();
+	}
+
+	private int get_next_page(Page page, long boundary) {
+		if (boundary > 0)
+			boundary += offset;
+		while (true) {
+			int more;
+			if (boundary > 0 && offset >= boundary)
+				return OV_FALSE;
+			more = oy.pageseek(page);
+			if (more < 0) {
+				offset -= more;
+			} else {
+				if (more == 0) {
+					if (boundary == 0)
+						return OV_FALSE;
+					int ret = get_data();
+					if (ret == 0)
+						return OV_EOF;
+					if (ret < 0)
+						return OV_EREAD;
+				} else {
+					int ret = (int) offset; // !!!
+					offset += more;
+					return ret;
+				}
+			}
+		}
+	}
+
+	private int get_prev_page(Page page) throws JOrbisException {
+		long begin = offset; // !!!
+		int ret;
+		int offst = -1;
+		while (offst == -1) {
+			begin -= CHUNKSIZE;
+			if (begin < 0)
+				begin = 0;
+			seek_helper(begin);
+			while (offset < begin + CHUNKSIZE) {
+				ret = get_next_page(page, begin + CHUNKSIZE - offset);
+				if (ret == OV_EREAD) {
+					return OV_EREAD;
+				}
+				if (ret < 0) {
+					if (offst == -1)
+						throw new JOrbisException();
+					break;
+				} else {
+					offst = ret;
+				}
+			}
+		}
+		seek_helper(offst); // !!!
+		ret = get_next_page(page, CHUNKSIZE);
+		if (ret < 0) {
+			return OV_EFAULT;
+		}
+		return offst;
+	}
+
+	int bisect_forward_serialno(long begin, long searched, long end, int currentno, int m) {
+		long endsearched = end;
+		long next = end;
+		Page page = new Page();
+		int ret;
+
+		while (searched < endsearched) {
+			long bisect;
+			if (endsearched - searched < CHUNKSIZE) {
+				bisect = searched;
+			} else {
+				bisect = (searched + endsearched) / 2;
+			}
+
+			seek_helper(bisect);
+			ret = get_next_page(page, -1);
+			if (ret == OV_EREAD)
+				return OV_EREAD;
+			if (ret < 0 || page.serialno() != currentno) {
+				endsearched = bisect;
+				if (ret >= 0)
+					next = ret;
+			} else {
+				searched = ret + page.header_len + page.body_len;
+			}
+		}
+		seek_helper(next);
+		ret = get_next_page(page, -1);
+		if (ret == OV_EREAD)
+			return OV_EREAD;
+
+		if (searched >= end || ret == -1) {
+			links = m + 1;
+			offsets = new long[m + 2];
+			offsets[m + 1] = searched;
+		} else {
+			ret = bisect_forward_serialno(next, offset, end, page.serialno(), m + 1);
+			if (ret == OV_EREAD)
+				return OV_EREAD;
+		}
+		offsets[m] = begin;
+		return 0;
+	}
+
+	// uses the local ogg_stream storage in vf; this is important for
+	// non-streaming input sources
+	int fetch_headers(Info vi, Comment vc, int[] serialno, Page og_ptr) {
+		Page og = new Page();
+		Packet op = new Packet();
+		int ret;
+
+		if (og_ptr == null) {
+			ret = get_next_page(og, CHUNKSIZE);
+			if (ret == OV_EREAD)
+				return OV_EREAD;
+			if (ret < 0)
+				return OV_ENOTVORBIS;
+			og_ptr = og;
+		}
+
+		if (serialno != null)
+			serialno[0] = og_ptr.serialno();
+
+		os.init(og_ptr.serialno());
+
+		// extract the initial header from the first page and verify that the
+		// Ogg bitstream is in fact Vorbis data
+
+		vi.init();
+		vc.init();
+
+		int i = 0;
+		while (i < 3) {
+			os.pagein(og_ptr);
+			while (i < 3) {
+				int result = os.packetout(op);
+				if (result == 0)
+					break;
+				if (result == -1) {
+					vi.clear();
+					vc.clear();
+					os.clear();
+					return -1;
+				}
+				if (vi.synthesis_headerin(vc, op) != 0) {
+					vi.clear();
+					vc.clear();
+					os.clear();
+					return -1;
+				}
+				i++;
+			}
+			if (i < 3)
+				if (get_next_page(og_ptr, 1) < 0) {
+					vi.clear();
+					vc.clear();
+					os.clear();
+					return -1;
+				}
+		}
+		return 0;
+	}
+
+	// last step of the OggVorbis_File initialization; get all the
+	// vorbis_info structs and PCM positions. Only called by the seekable
+	// initialization (local stream storage is hacked slightly; pay
+	// attention to how that's done)
+	void prefetch_all_headers(Info first_i, Comment first_c, int dataoffset) throws JOrbisException {
+		Page og = new Page();
+		int ret;
+
+		vi = new Info[links];
+		vc = new Comment[links];
+		dataoffsets = new long[links];
+		pcmlengths = new long[links];
+		serialnos = new int[links];
+
+		for (int i = 0; i < links; i++) {
+			if (first_i != null && first_c != null && i == 0) {
+				// we already grabbed the initial header earlier. This just
+				// saves the waste of grabbing it again
+				vi[i] = first_i;
+				vc[i] = first_c;
+				dataoffsets[i] = dataoffset;
+			} else {
+				// seek to the location of the initial header
+				seek_helper(offsets[i]); // !!!
+				vi[i] = new Info();
+				vc[i] = new Comment();
+				if (fetch_headers(vi[i], vc[i], null, null) == -1) {
+					dataoffsets[i] = -1;
+				} else {
+					dataoffsets[i] = offset;
+					os.clear();
+				}
+			}
+
+			// get the serial number and PCM length of this link. To do this,
+			// get the last page of the stream
+			{
+				long end = offsets[i + 1]; // !!!
+				seek_helper(end);
+
+				while (true) {
+					ret = get_prev_page(og);
+					if (ret == -1) {
+						// this should not be possible
+						vi[i].clear();
+						vc[i].clear();
+						break;
+					}
+					if (og.granulepos() != -1) {
+						serialnos[i] = og.serialno();
+						pcmlengths[i] = og.granulepos();
+						break;
+					}
+				}
+			}
+		}
+	}
+
+	private int make_decode_ready() {
+		if (decode_ready)
+			System.exit(1);
+		vd.synthesis_init(vi[0]);
+		vb.init(vd);
+		decode_ready = true;
+		return (0);
+	}
+
+	int open_seekable() throws JOrbisException {
+		Info initial_i = new Info();
+		Comment initial_c = new Comment();
+		int serialno;
+		long end;
+		int ret;
+		int dataoffset;
+		Page og = new Page();
+		// is this even vorbis...?
+		int[] foo = new int[1];
+		ret = fetch_headers(initial_i, initial_c, foo, null);
+		serialno = foo[0];
+		dataoffset = (int) offset; // !!
+		os.clear();
+		if (ret == -1)
+			return (-1);
+		if (ret < 0)
+			return (ret);
+		// we can seek, so set out learning all about this file
+		seekable = true;
+		fseek(datasource, 0, SEEK_END);
+		offset = ftell(datasource);
+		end = offset;
+		// We get the offset for the last page of the physical bitstream.
+		// Most OggVorbis files will contain a single logical bitstream
+		end = get_prev_page(og);
+		// moer than one logical bitstream?
+		if (og.serialno() != serialno) {
+			// Chained bitstream. Bisect-search each logical bitstream
+			// section. Do so based on serial number only
+			if (bisect_forward_serialno(0, 0, end + 1, serialno, 0) < 0) {
+				clear();
+				return OV_EREAD;
+			}
+		} else {
+			// Only one logical bitstream
+			if (bisect_forward_serialno(0, end, end + 1, serialno, 0) < 0) {
+				clear();
+				return OV_EREAD;
+			}
+		}
+		prefetch_all_headers(initial_i, initial_c, dataoffset);
+		return 0;
+	}
+
+	int open_nonseekable() {
+		// we cannot seek. Set up a 'single' (current) logical bitstream entry
+		links = 1;
+		vi = new Info[links];
+		vi[0] = new Info(); // ??
+		vc = new Comment[links];
+		vc[0] = new Comment(); // ?? bug?
+
+		// Try to fetch the headers, maintaining all the storage
+		int[] foo = new int[1];
+		if (fetch_headers(vi[0], vc[0], foo, null) == -1)
+			return (-1);
+		current_serialno = foo[0];
+		make_decode_ready();
+		return 0;
+	}
+
+	// clear out the current logical bitstream decoder
+	void decode_clear() {
+		os.clear();
+		vd.clear();
+		vb.clear();
+		decode_ready = false;
+		bittrack = 0.f;
+		samptrack = 0.f;
+	}
+
+	// fetch and process a packet. Handles the case where we're at a
+	// bitstream boundary and dumps the decoding machine. If the decoding
+	// machine is unloaded, it loads it. It also keeps pcm_offset up to
+	// date (seek and read both use this. seek uses a special hack with
+	// readp).
+	//
+	// return: -1) hole in the data (lost packet)
+	// 0) need more date (only if readp==0)/eof
+	// 1) got a packet
+
+	int process_packet(int readp) {
+		Page og = new Page();
+
+		// handle one packet. Try to fetch it from current stream state
+		// extract packets from page
+		while (true) {
+			// process a packet if we can. If the machine isn't loaded,
+			// neither is a page
+			if (decode_ready) {
+				Packet op = new Packet();
+				int result = os.packetout(op);
+				long granulepos;
+				// if(result==-1)return(-1); // hole in the data. For now, swallow
+				// and go. We'll need to add a real
+				// error code in a bit.
+				if (result > 0) {
+					// got a packet. process it
+					granulepos = op.granulepos;
+					if (vb.synthesis(op) == 0) { // lazy check for lazy
+						// header handling. The
+						// header packets aren't
+						// audio, so if/when we
+						// submit them,
+						// vorbis_synthesis will
+						// reject them
+						// suck in the synthesis data and track bitrate
+						{
+							int oldsamples = vd.synthesis_pcmout(null, null);
+							vd.synthesis_blockin(vb);
+							samptrack += vd.synthesis_pcmout(null, null) - oldsamples;
+							bittrack += op.bytes * 8;
+						}
+
+						// update the pcm offset.
+						if (granulepos != -1 && op.e_o_s == 0) {
+							int link = (seekable ? current_link : 0);
+							int samples;
+							// this packet has a pcm_offset on it (the last packet
+							// completed on a page carries the offset) After processing
+							// (above), we know the pcm position of the *last* sample
+							// ready to be returned. Find the offset of the *first*
+							//
+							// As an aside, this trick is inaccurate if we begin
+							// reading anew right at the last page; the end-of-stream
+							// granulepos declares the last frame in the stream, and the
+							// last packet of the last page may be a partial frame.
+							// So, we need a previous granulepos from an in-sequence page
+							// to have a reference point. Thus the !op.e_o_s clause above
+
+							samples = vd.synthesis_pcmout(null, null);
+							granulepos -= samples;
+							for (int i = 0; i < link; i++) {
+								granulepos += pcmlengths[i];
+							}
+							pcm_offset = granulepos;
+						}
+						return (1);
+					}
+				}
+			}
+
+			if (readp == 0)
+				return (0);
+			if (get_next_page(og, -1) < 0)
+				return (0); // eof. leave unitialized
+
+			// bitrate tracking; add the header's bytes here, the body bytes
+			// are done by packet above
+			bittrack += og.header_len * 8;
+
+			// has our decoding just traversed a bitstream boundary?
+			if (decode_ready) {
+				if (current_serialno != og.serialno()) {
+					decode_clear();
+				}
+			}
+
+			// Do we need to load a new machine before submitting the page?
+			// This is different in the seekable and non-seekable cases.
+			//
+			// In the seekable case, we already have all the header
+			// information loaded and cached; we just initialize the machine
+			// with it and continue on our merry way.
+			//
+			// In the non-seekable (streaming) case, we'll only be at a
+			// boundary if we just left the previous logical bitstream and
+			// we're now nominally at the header of the next bitstream
+
+			if (!decode_ready) {
+				int i;
+				if (seekable) {
+					current_serialno = og.serialno();
+
+					// match the serialno to bitstream section. We use this rather than
+					// offset positions to avoid problems near logical bitstream
+					// boundaries
+					for (i = 0; i < links; i++) {
+						if (serialnos[i] == current_serialno)
+							break;
+					}
+					if (i == links)
+						return (-1); // sign of a bogus stream. error out,
+					// leave machine uninitialized
+					current_link = i;
+
+					os.init(current_serialno);
+					os.reset();
+
+				} else {
+					// we're streaming
+					// fetch the three header packets, build the info struct
+					int foo[] = new int[1];
+					int ret = fetch_headers(vi[0], vc[0], foo, og);
+					current_serialno = foo[0];
+					if (ret != 0)
+						return ret;
+					current_link++;
+					i = 0;
+				}
+				make_decode_ready();
+			}
+			os.pagein(og);
+		}
+	}
+
+	// The helpers are over; it's all toplevel interface from here on out
+	// clear out the OggVorbis_File struct
+	int clear() {
+		vb.clear();
+		vd.clear();
+		os.clear();
+
+		if (vi != null && links != 0) {
+			for (int i = 0; i < links; i++) {
+				vi[i].clear();
+				vc[i].clear();
+			}
+			vi = null;
+			vc = null;
+		}
+		if (dataoffsets != null)
+			dataoffsets = null;
+		if (pcmlengths != null)
+			pcmlengths = null;
+		if (serialnos != null)
+			serialnos = null;
+		if (offsets != null)
+			offsets = null;
+		oy.clear();
+
+		return (0);
+	}
+
+	static int fseek(InputStream fis, long off, int whence) {
+		if (fis instanceof SeekableInputStream) {
+			SeekableInputStream sis = (SeekableInputStream) fis;
+			try {
+				if (whence == SEEK_SET) {
+					sis.seek(off);
+				} else if (whence == SEEK_END) {
+					sis.seek(sis.getLength() - off);
+				} else {
+				}
+			} catch (Exception e) {
+			}
+			return 0;
+		}
+		try {
+			if (whence == 0) {
+				fis.reset();
+			}
+			fis.skip(off);
+		} catch (Exception e) {
+			return -1;
+		}
+		return 0;
+	}
+
+	static long ftell(InputStream fis) {
+		try {
+			if (fis instanceof SeekableInputStream) {
+				SeekableInputStream sis = (SeekableInputStream) fis;
+				return (sis.tell());
+			}
+		} catch (Exception e) {
+		}
+		return 0;
+	}
+
+	// inspects the OggVorbis file and finds/documents all the logical
+	// bitstreams contained in it. Tries to be tolerant of logical
+	// bitstream sections that are truncated/woogie.
+	//
+	// return: -1) error
+	// 0) OK
+
+	int open(InputStream is, byte[] initial, int ibytes) throws JOrbisException {
+		return open_callbacks(is, initial, ibytes);
+	}
+
+	int open_callbacks(InputStream is, byte[] initial, int ibytes// , callbacks callbacks
+	) throws JOrbisException {
+		int ret;
+		datasource = is;
+
+		oy.init();
+
+		// perhaps some data was previously read into a buffer for testing
+		// against other stream types. Allow initialization from this
+		// previously read data (as we may be reading from a non-seekable
+		// stream)
+		if (initial != null) {
+			int index = oy.buffer(ibytes);
+			System.arraycopy(initial, 0, oy.data, index, ibytes);
+			oy.wrote(ibytes);
+		}
+		// can we seek? Stevens suggests the seek test was portable
+		if (is instanceof SeekableInputStream) {
+			ret = open_seekable();
+		} else {
+			ret = open_nonseekable();
+		}
+		if (ret != 0) {
+			datasource = null;
+			clear();
+		}
+		return ret;
+	}
+
+	// How many logical bitstreams in this physical bitstream?
+	public int streams() {
+		return links;
+	}
+
+	// Is the FILE * associated with vf seekable?
+	public boolean seekable() {
+		return seekable;
+	}
+
+	// returns the bitrate for a given logical bitstream or the entire
+	// physical bitstream. If the file is open for random access, it will
+	// find the *actual* average bitrate. If the file is streaming, it
+	// returns the nominal bitrate (if set) else the average of the
+	// upper/lower bounds (if set) else -1 (unset).
+	//
+	// If you want the actual bitrate field settings, get them from the
+	// vorbis_info structs
+
+	public int bitrate(int i) {
+		if (i >= links)
+			return (-1);
+		if (!seekable && i != 0)
+			return (bitrate(0));
+		if (i < 0) {
+			long bits = 0;
+			for (int j = 0; j < links; j++) {
+				bits += (offsets[j + 1] - dataoffsets[j]) * 8;
+			}
+			return ((int) Math.rint(bits / time_total(-1)));
+		} else {
+			if (seekable) {
+				// return the actual bitrate
+				return ((int) Math.rint((offsets[i + 1] - dataoffsets[i]) * 8 / time_total(i)));
+			} else {
+				// return nominal if set
+				if (vi[i].bitrate_nominal > 0) {
+					return vi[i].bitrate_nominal;
+				} else {
+					if (vi[i].bitrate_upper > 0) {
+						if (vi[i].bitrate_lower > 0) {
+							return (vi[i].bitrate_upper + vi[i].bitrate_lower) / 2;
+						} else {
+							return vi[i].bitrate_upper;
+						}
+					}
+					return (-1);
+				}
+			}
+		}
+	}
+
+	// returns the actual bitrate since last call. returns -1 if no
+	// additional data to offer since last call (or at beginning of stream)
+	public int bitrate_instant() {
+		int _link = (seekable ? current_link : 0);
+		if (samptrack == 0)
+			return (-1);
+		int ret = (int) (bittrack / samptrack * vi[_link].rate + .5);
+		bittrack = 0.f;
+		samptrack = 0.f;
+		return (ret);
+	}
+
+	public int serialnumber(int i) {
+		if (i >= links)
+			return (-1);
+		if (!seekable && i >= 0)
+			return (serialnumber(-1));
+		if (i < 0) {
+			return (current_serialno);
+		} else {
+			return (serialnos[i]);
+		}
+	}
+
+	// returns: total raw (compressed) length of content if i==-1
+	// raw (compressed) length of that logical bitstream for i==0 to n
+	// -1 if the stream is not seekable (we can't know the length)
+
+	public long raw_total(int i) {
+		if (!seekable || i >= links)
+			return (-1);
+		if (i < 0) {
+			long acc = 0; // bug?
+			for (int j = 0; j < links; j++) {
+				acc += raw_total(j);
+			}
+			return (acc);
+		} else {
+			return (offsets[i + 1] - offsets[i]);
+		}
+	}
+
+	// returns: total PCM length (samples) of content if i==-1
+	// PCM length (samples) of that logical bitstream for i==0 to n
+	// -1 if the stream is not seekable (we can't know the length)
+	public long pcm_total(int i) {
+		if (!seekable || i >= links)
+			return (-1);
+		if (i < 0) {
+			long acc = 0;
+			for (int j = 0; j < links; j++) {
+				acc += pcm_total(j);
+			}
+			return (acc);
+		} else {
+			return (pcmlengths[i]);
+		}
+	}
+
+	// returns: total seconds of content if i==-1
+	// seconds in that logical bitstream for i==0 to n
+	// -1 if the stream is not seekable (we can't know the length)
+	public float time_total(int i) {
+		if (!seekable || i >= links)
+			return (-1);
+		if (i < 0) {
+			float acc = 0;
+			for (int j = 0; j < links; j++) {
+				acc += time_total(j);
+			}
+			return (acc);
+		} else {
+			return ((float) (pcmlengths[i]) / vi[i].rate);
+		}
+	}
+
+	// seek to an offset relative to the *compressed* data. This also
+	// immediately sucks in and decodes pages to update the PCM cursor. It
+	// will cross a logical bitstream boundary, but only if it can't get
+	// any packets out of the tail of the bitstream we seek to (so no
+	// surprises).
+	//
+	// returns zero on success, nonzero on failure
+
+	public int raw_seek(int pos) {
+		if (!seekable)
+			return (-1); // don't dump machine if we can't seek
+		if (pos < 0 || pos > offsets[links]) {
+			// goto seek_error;
+			pcm_offset = -1;
+			decode_clear();
+			return -1;
+		}
+
+		// clear out decoding machine state
+		pcm_offset = -1;
+		decode_clear();
+
+		// seek
+		seek_helper(pos);
+
+		// we need to make sure the pcm_offset is set. We use the
+		// _fetch_packet helper to process one packet with readp set, then
+		// call it until it returns '0' with readp not set (the last packet
+		// from a page has the 'granulepos' field set, and that's how the
+		// helper updates the offset
+
+		switch (process_packet(1)) {
+		case 0:
+			// oh, eof. There are no packets remaining. Set the pcm offset to
+			// the end of file
+			pcm_offset = pcm_total(-1);
+			return (0);
+		case -1:
+			// error! missing data or invalid bitstream structure
+			// goto seek_error;
+			pcm_offset = -1;
+			decode_clear();
+			return -1;
+		default:
+			// all OK
+			break;
+		}
+		while (true) {
+			switch (process_packet(0)) {
+			case 0:
+				// the offset is set. If it's a bogus bitstream with no offset
+				// information, it's not but that's not our fault. We still run
+				// gracefully, we're just missing the offset
+				return (0);
+			case -1:
+				// error! missing data or invalid bitstream structure
+				// goto seek_error;
+				pcm_offset = -1;
+				decode_clear();
+				return -1;
+			default:
+				// continue processing packets
+				break;
+			}
+		}
+
+		// seek_error:
+		// dump the machine so we're in a known state
+		// pcm_offset=-1;
+		// decode_clear();
+		// return -1;
+	}
+
+	// seek to a sample offset relative to the decompressed pcm stream
+	// returns zero on success, nonzero on failure
+
+	public int pcm_seek(long pos) {
+		int link = -1;
+		long total = pcm_total(-1);
+
+		if (!seekable)
+			return (-1); // don't dump machine if we can't seek
+		if (pos < 0 || pos > total) {
+			// goto seek_error;
+			pcm_offset = -1;
+			decode_clear();
+			return -1;
+		}
+
+		// which bitstream section does this pcm offset occur in?
+		for (link = links - 1; link >= 0; link--) {
+			total -= pcmlengths[link];
+			if (pos >= total)
+				break;
+		}
+
+		// search within the logical bitstream for the page with the highest
+		// pcm_pos preceeding (or equal to) pos. There is a danger here;
+		// missing pages or incorrect frame number information in the
+		// bitstream could make our task impossible. Account for that (it
+		// would be an error condition)
+		{
+			long target = pos - total;
+			long end = offsets[link + 1];
+			long begin = offsets[link];
+			int best = (int) begin;
+
+			Page og = new Page();
+			while (begin < end) {
+				long bisect;
+				int ret;
+
+				if (end - begin < CHUNKSIZE) {
+					bisect = begin;
+				} else {
+					bisect = (end + begin) / 2;
+				}
+
+				seek_helper(bisect);
+				ret = get_next_page(og, end - bisect);
+
+				if (ret == -1) {
+					end = bisect;
+				} else {
+					long granulepos = og.granulepos();
+					if (granulepos < target) {
+						best = ret; // raw offset of packet with granulepos
+						begin = offset; // raw offset of next packet
+					} else {
+						end = bisect;
+					}
+				}
+			}
+			// found our page. seek to it (call raw_seek).
+			if (raw_seek(best) != 0) {
+				// goto seek_error;
+				pcm_offset = -1;
+				decode_clear();
+				return -1;
+			}
+		}
+
+		// verify result
+		if (pcm_offset >= pos) {
+			// goto seek_error;
+			pcm_offset = -1;
+			decode_clear();
+			return -1;
+		}
+		if (pos > pcm_total(-1)) {
+			// goto seek_error;
+			pcm_offset = -1;
+			decode_clear();
+			return -1;
+		}
+
+		// discard samples until we reach the desired position. Crossing a
+		// logical bitstream boundary with abandon is OK.
+		while (pcm_offset < pos) {
+			int target = (int) (pos - pcm_offset);
+			float[][][] _pcm = new float[1][][];
+			int[] _index = new int[getInfo(-1).channels];
+			int samples = vd.synthesis_pcmout(_pcm, _index);
+
+			if (samples > target)
+				samples = target;
+			vd.synthesis_read(samples);
+			pcm_offset += samples;
+
+			if (samples < target)
+				if (process_packet(1) == 0) {
+					pcm_offset = pcm_total(-1); // eof
+				}
+		}
+		return 0;
+
+		// seek_error:
+		// dump machine so we're in a known state
+		// pcm_offset=-1;
+		// decode_clear();
+		// return -1;
+	}
+
+	// seek to a playback time relative to the decompressed pcm stream
+	// returns zero on success, nonzero on failure
+	int time_seek(float seconds) {
+		// translate time to PCM position and call pcm_seek
+
+		int link = -1;
+		long pcm_total = pcm_total(-1);
+		float time_total = time_total(-1);
+
+		if (!seekable)
+			return (-1); // don't dump machine if we can't seek
+		if (seconds < 0 || seconds > time_total) {
+			// goto seek_error;
+			pcm_offset = -1;
+			decode_clear();
+			return -1;
+		}
+
+		// which bitstream section does this time offset occur in?
+		for (link = links - 1; link >= 0; link--) {
+			pcm_total -= pcmlengths[link];
+			time_total -= time_total(link);
+			if (seconds >= time_total)
+				break;
+		}
+
+		// enough information to convert time offset to pcm offset
+		{
+			long target = (long) (pcm_total + (seconds - time_total) * vi[link].rate);
+			return (pcm_seek(target));
+		}
+
+		// seek_error:
+		// dump machine so we're in a known state
+		// pcm_offset=-1;
+		// decode_clear();
+		// return -1;
+	}
+
+	// tell the current stream offset cursor. Note that seek followed by
+	// tell will likely not give the set offset due to caching
+	public long raw_tell() {
+		return (offset);
+	}
+
+	// return PCM offset (sample) of next PCM sample to be read
+	public long pcm_tell() {
+		return (pcm_offset);
+	}
+
+	// return time offset (seconds) of next PCM sample to be read
+	public float time_tell() {
+		// translate time to PCM position and call pcm_seek
+
+		int link = -1;
+		long pcm_total = 0;
+		float time_total = 0.f;
+
+		if (seekable) {
+			pcm_total = pcm_total(-1);
+			time_total = time_total(-1);
+
+			// which bitstream section does this time offset occur in?
+			for (link = links - 1; link >= 0; link--) {
+				pcm_total -= pcmlengths[link];
+				time_total -= time_total(link);
+				if (pcm_offset >= pcm_total)
+					break;
+			}
+		}
+
+		return ((float) time_total + (float) (pcm_offset - pcm_total) / vi[link].rate);
+	}
+
+	// link: -1) return the vorbis_info struct for the bitstream section
+	// currently being decoded
+	// 0-n) to request information for a specific bitstream section
+	//
+	// In the case of a non-seekable bitstream, any call returns the
+	// current bitstream. NULL in the case that the machine is not
+	// initialized
+
+	public Info getInfo(int link) {
+		if (seekable) {
+			if (link < 0) {
+				if (decode_ready) {
+					return vi[current_link];
+				} else {
+					return null;
+				}
+			} else {
+				if (link >= links) {
+					return null;
+				} else {
+					return vi[link];
+				}
+			}
+		} else {
+			if (decode_ready) {
+				return vi[0];
+			} else {
+				return null;
+			}
+		}
+	}
+
+	public Comment getComment(int link) {
+		if (seekable) {
+			if (link < 0) {
+				if (decode_ready) {
+					return vc[current_link];
+				} else {
+					return null;
+				}
+			} else {
+				if (link >= links) {
+					return null;
+				} else {
+					return vc[link];
+				}
+			}
+		} else {
+			if (decode_ready) {
+				return vc[0];
+			} else {
+				return null;
+			}
+		}
+	}
+
+	int host_is_big_endian() {
+		return 1;
+		// short pattern = 0xbabe;
+		// unsigned char *bytewise = (unsigned char *)&pattern;
+		// if (bytewise[0] == 0xba) return 1;
+		// assert(bytewise[0] == 0xbe);
+		// return 0;
+	}
+
+	// up to this point, everything could more or less hide the multiple
+	// logical bitstream nature of chaining from the toplevel application
+	// if the toplevel application didn't particularly care. However, at
+	// the point that we actually read audio back, the multiple-section
+	// nature must surface: Multiple bitstream sections do not necessarily
+	// have to have the same number of channels or sampling rate.
+	//
+	// read returns the sequential logical bitstream number currently
+	// being decoded along with the PCM data in order that the toplevel
+	// application can take action on channel/sample rate changes. This
+	// number will be incremented even for streamed (non-seekable) streams
+	// (for seekable streams, it represents the actual logical bitstream
+	// index within the physical bitstream. Note that the accessor
+	// functions above are aware of this dichotomy).
+	//
+	// input values: buffer) a buffer to hold packed PCM data for return
+	// length) the byte length requested to be placed into buffer
+	// bigendianp) should the data be packed LSB first (0) or
+	// MSB first (1)
+	// word) word size for output. currently 1 (byte) or
+	// 2 (16 bit short)
+	//
+	// return values: -1) error/hole in data
+	// 0) EOF
+	// n) number of bytes of PCM actually returned. The
+	// below works on a packet-by-packet basis, so the
+	// return length is not related to the 'length' passed
+	// in, just guaranteed to fit.
+	//
+	// *section) set to the logical bitstream number
+
+	int read(byte[] buffer, int length, int bigendianp, int word, int sgned, int[] bitstream) {
+		int host_endian = host_is_big_endian();
+		int index = 0;
+
+		while (true) {
+			if (decode_ready) {
+				float[][] pcm;
+				float[][][] _pcm = new float[1][][];
+				int[] _index = new int[getInfo(-1).channels];
+				int samples = vd.synthesis_pcmout(_pcm, _index);
+				pcm = _pcm[0];
+				if (samples != 0) {
+					// yay! proceed to pack data into the byte buffer
+					int channels = getInfo(-1).channels;
+					int bytespersample = word * channels;
+					if (samples > length / bytespersample)
+						samples = length / bytespersample;
+
+					// a tight loop to pack each size
+					{
+						int val;
+						if (word == 1) {
+							int off = (sgned != 0 ? 0 : 128);
+							for (int j = 0; j < samples; j++) {
+								for (int i = 0; i < channels; i++) {
+									val = (int) (pcm[i][_index[i] + j] * 128. + 0.5);
+									if (val > 127)
+										val = 127;
+									else if (val < -128)
+										val = -128;
+									buffer[index++] = (byte) (val + off);
+								}
+							}
+						} else {
+							int off = (sgned != 0 ? 0 : 32768);
+
+							if (host_endian == bigendianp) {
+								if (sgned != 0) {
+									for (int i = 0; i < channels; i++) { // It's faster in this order
+										int src = _index[i];
+										int dest = i;
+										for (int j = 0; j < samples; j++) {
+											val = (int) (pcm[i][src + j] * 32768. + 0.5);
+											if (val > 32767)
+												val = 32767;
+											else if (val < -32768)
+												val = -32768;
+											buffer[dest] = (byte) (val >>> 8);
+											buffer[dest + 1] = (byte) (val);
+											dest += channels * 2;
+										}
+									}
+								} else {
+									for (int i = 0; i < channels; i++) {
+										float[] src = pcm[i];
+										int dest = i;
+										for (int j = 0; j < samples; j++) {
+											val = (int) (src[j] * 32768. + 0.5);
+											if (val > 32767)
+												val = 32767;
+											else if (val < -32768)
+												val = -32768;
+											buffer[dest] = (byte) ((val + off) >>> 8);
+											buffer[dest + 1] = (byte) (val + off);
+											dest += channels * 2;
+										}
+									}
+								}
+							} else if (bigendianp != 0) {
+								for (int j = 0; j < samples; j++) {
+									for (int i = 0; i < channels; i++) {
+										val = (int) (pcm[i][j] * 32768. + 0.5);
+										if (val > 32767)
+											val = 32767;
+										else if (val < -32768)
+											val = -32768;
+										val += off;
+										buffer[index++] = (byte) (val >>> 8);
+										buffer[index++] = (byte) val;
+									}
+								}
+							} else {
+								// int val;
+								for (int j = 0; j < samples; j++) {
+									for (int i = 0; i < channels; i++) {
+										val = (int) (pcm[i][j] * 32768. + 0.5);
+										if (val > 32767)
+											val = 32767;
+										else if (val < -32768)
+											val = -32768;
+										val += off;
+										buffer[index++] = (byte) val;
+										buffer[index++] = (byte) (val >>> 8);
+									}
+								}
+							}
+						}
+					}
+
+					vd.synthesis_read(samples);
+					pcm_offset += samples;
+					if (bitstream != null)
+						bitstream[0] = current_link;
+					return (samples * bytespersample);
+				}
+			}
+
+			// suck in another packet
+			switch (process_packet(1)) {
+			case 0:
+				return (0);
+			case -1:
+				return -1;
+			default:
+				break;
+			}
+		}
+	}
+
+	public Info[] getInfo() {
+		return vi;
+	}
+
+	public Comment[] getComment() {
+		return vc;
+	}
+
+	public void close() throws java.io.IOException {
+		datasource.close();
+	}
+
+	class SeekableInputStream extends InputStream {
+		java.io.RandomAccessFile raf = null;
+		final String mode = "r";
+
+		SeekableInputStream(String file) throws java.io.IOException {
+			raf = new java.io.RandomAccessFile(file, mode);
+		}
+
+		public int read() throws java.io.IOException {
+			return raf.read();
+		}
+
+		public int read(byte[] buf) throws java.io.IOException {
+			return raf.read(buf);
+		}
+
+		public int read(byte[] buf, int s, int len) throws java.io.IOException {
+			return raf.read(buf, s, len);
+		}
+
+		public long skip(long n) throws java.io.IOException {
+			return (long) (raf.skipBytes((int) n));
+		}
+
+		public long getLength() throws java.io.IOException {
+			return raf.length();
+		}
+
+		public long tell() throws java.io.IOException {
+			return raf.getFilePointer();
+		}
+
+		public int available() throws java.io.IOException {
+			return (raf.length() == raf.getFilePointer()) ? 0 : 1;
+		}
+
+		public void close() throws java.io.IOException {
+			raf.close();
+		}
+
+		public synchronized void mark(int m) {
+		}
+
+		public synchronized void reset() throws java.io.IOException {
+		}
+
+		public boolean markSupported() {
+			return false;
+		}
+
+		public void seek(long pos) throws java.io.IOException {
+			raf.seek(pos);
+		}
+	}
+
+}
diff --git a/sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/OpenGLObjects.java b/sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/OpenGLObjects.java
index cf0901db..ea3bb55a 100644
--- a/sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/OpenGLObjects.java
+++ b/sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/OpenGLObjects.java
@@ -29,85 +29,127 @@ import net.lax1dude.eaglercraft.v1_8.internal.teavm.WebGLVertexArray;
 class OpenGLObjects {
 
 	static class BufferGL implements IBufferGL {
-		
+
+		private static int hashGen = 0;
 		final WebGLBuffer ptr;
-		
+		final int hash;
+
 		BufferGL(WebGLBuffer ptr) {
 			this.ptr = ptr;
+			this.hash = ++hashGen;
+		}
+
+		public int hashCode() {
+			return hash;
 		}
 
 		@Override
 		public void free() {
 			PlatformOpenGL._wglDeleteBuffers(this);
 		}
-		
+
 	}
 
 	static class BufferArrayGL implements IBufferArrayGL {
-		
+
+		private static int hashGen = 0;
 		final WebGLVertexArray ptr;
-		
+		final int hash;
+
 		BufferArrayGL(WebGLVertexArray ptr) {
 			this.ptr = ptr;
+			this.hash = ++hashGen;
+		}
+
+		public int hashCode() {
+			return hash;
 		}
 
 		@Override
 		public void free() {
 			PlatformOpenGL._wglDeleteVertexArrays(this);
 		}
-		
+
 	}
 
 	static class TextureGL implements ITextureGL {
-		
+
+		private static int hashGen = 0;
 		final WebGLTexture ptr;
-		
+		final int hash;
+
 		TextureGL(WebGLTexture ptr) {
 			this.ptr = ptr;
+			this.hash = ++hashGen;
+		}
+
+		public int hashCode() {
+			return hash;
 		}
 
 		@Override
 		public void free() {
 			PlatformOpenGL._wglDeleteTextures(this);
 		}
-		
+
 	}
 
 	static class ProgramGL implements IProgramGL {
-		
+
+		private static int hashGen = 0;
 		final WebGLProgram ptr;
-		
+		final int hash;
+
 		ProgramGL(WebGLProgram ptr) {
 			this.ptr = ptr;
+			this.hash = ++hashGen;
+		}
+
+		public int hashCode() {
+			return hash;
 		}
 
 		@Override
 		public void free() {
 			PlatformOpenGL._wglDeleteProgram(this);
 		}
-		
+
 	}
 
 	static class UniformGL implements IUniformGL {
-		
+
+		private static int hashGen = 0;
 		final WebGLUniformLocation ptr;
-		
+		final int hash;
+
 		UniformGL(WebGLUniformLocation ptr) {
 			this.ptr = ptr;
+			this.hash = ++hashGen;
+		}
+
+		public int hashCode() {
+			return hash;
 		}
 
 		@Override
 		public void free() {
 		}
-		
+
 	}
 
 	static class ShaderGL implements IShaderGL {
-		
+
+		private static int hashGen = 0;
 		final WebGLShader ptr;
+		final int hash;
 		
 		ShaderGL(WebGLShader ptr) {
 			this.ptr = ptr;
+			this.hash = ++hashGen;
+		}
+
+		public int hashCode() {
+			return hash;
 		}
 
 		@Override
@@ -118,48 +160,69 @@ class OpenGLObjects {
 	}
 
 	static class FramebufferGL implements IFramebufferGL {
-		
+
+		private static int hashGen = 0;
 		final WebGLFramebuffer ptr;
+		final int hash;
 		
 		FramebufferGL(WebGLFramebuffer ptr) {
 			this.ptr = ptr;
+			this.hash = ++hashGen;
+		}
+
+		public int hashCode() {
+			return hash;
 		}
 
 		@Override
 		public void free() {
 			PlatformOpenGL._wglDeleteFramebuffer(this);
 		}
-		
+
 	}
 
 	static class RenderbufferGL implements IRenderbufferGL {
-		
+
+		private static int hashGen = 0;
 		final WebGLRenderbuffer ptr;
-		
+		final int hash;
+
 		RenderbufferGL(WebGLRenderbuffer ptr) {
 			this.ptr = ptr;
+			this.hash = ++hashGen;
+		}
+
+		public int hashCode() {
+			return hash;
 		}
 
 		@Override
 		public void free() {
 			PlatformOpenGL._wglDeleteRenderbuffer(this);
 		}
-		
+
 	}
 
 	static class QueryGL implements IQueryGL {
-		
+
+		private static int hashGen = 0;
 		final WebGLQuery ptr;
-		
+		final int hash;
+
 		QueryGL(WebGLQuery ptr) {
 			this.ptr = ptr;
+			this.hash = ++hashGen;
+		}
+
+		public int hashCode() {
+			return hash;
 		}
 
 		@Override
 		public void free() {
 			PlatformOpenGL._wglDeleteQueries(this);
 		}
-		
+
 	}
-	
+
 }
diff --git a/sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/PlatformApplication.java b/sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/PlatformApplication.java
index b9898651..b0917df4 100644
--- a/sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/PlatformApplication.java
+++ b/sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/PlatformApplication.java
@@ -1,5 +1,7 @@
 package net.lax1dude.eaglercraft.v1_8.internal;
 
+import java.net.URI;
+import java.net.URISyntaxException;
 import java.text.DateFormat;
 import java.text.SimpleDateFormat;
 import java.util.Date;
@@ -13,20 +15,25 @@ import org.teavm.jso.browser.Storage;
 import org.teavm.jso.browser.TimerHandler;
 import org.teavm.jso.browser.Window;
 import org.teavm.jso.canvas.CanvasRenderingContext2D;
+import org.teavm.jso.dom.css.CSSStyleDeclaration;
 import org.teavm.jso.dom.events.Event;
 import org.teavm.jso.dom.events.EventListener;
 import org.teavm.jso.dom.html.HTMLCanvasElement;
 import org.teavm.jso.dom.html.HTMLDocument;
+import org.teavm.jso.dom.html.HTMLElement;
 import org.teavm.jso.dom.html.HTMLInputElement;
 import org.teavm.jso.typedarrays.ArrayBuffer;
 
 import net.lax1dude.eaglercraft.v1_8.Base64;
-import net.lax1dude.eaglercraft.v1_8.EagRuntime;
+import net.lax1dude.eaglercraft.v1_8.internal.buffer.ByteBuffer;
+import net.lax1dude.eaglercraft.v1_8.internal.buffer.EaglerArrayBufferAllocator;
 import net.lax1dude.eaglercraft.v1_8.internal.teavm.DebugConsoleWindow;
+import net.lax1dude.eaglercraft.v1_8.internal.teavm.TeaVMBlobURLHandle;
+import net.lax1dude.eaglercraft.v1_8.internal.teavm.TeaVMBlobURLManager;
 import net.lax1dude.eaglercraft.v1_8.internal.teavm.TeaVMUtils;
 
 /**
- * Copyright (c) 2022-2023 lax1dude. All Rights Reserved.
+ * Copyright (c) 2022-2024 lax1dude. All Rights Reserved.
  * 
  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
@@ -46,7 +53,18 @@ public class PlatformApplication {
 		if(url.indexOf(':') == -1) {
 			url = "http://" + url;
 		}
-		Window.current().open(url, "_blank", "noopener,noreferrer");
+		URI parsedURL;
+		try {
+			parsedURL = new URI(url);
+		}catch(URISyntaxException ex) {
+			PlatformRuntime.logger.error("Refusing to open invalid URL: {}", url);
+			return;
+		}
+		try {
+			Window.current().open(parsedURL.toString(), "_blank", "noopener,noreferrer");
+		}catch(Throwable t) {
+			PlatformRuntime.logger.error("Exception opening link!");
+		}
 	}
 
 	public static void setClipboard(String text) {
@@ -54,6 +72,10 @@ public class PlatformApplication {
 			setClipboard0(text);
 		}catch(Throwable t) {
 			PlatformRuntime.logger.error("Exception setting clipboard data");
+			try {
+				Window.prompt("Here is the text you're trying to copy:", text);
+			}catch(Throwable t2) {
+			}
 		}
 	}
 	
@@ -62,7 +84,12 @@ public class PlatformApplication {
 			return getClipboard0();
 		}catch(Throwable t) {
 			PlatformRuntime.logger.error("Exception getting clipboard data");
-			return "";
+			try {
+				String ret = Window.prompt("Please enter the text to paste:");
+				return ret != null ? ret : "";
+			}catch(Throwable t2) {
+				return "";
+			}
 		}
 	}
 
@@ -75,11 +102,11 @@ public class PlatformApplication {
 	private static native String getClipboard0();
 	
 	private static void getClipboard0(final AsyncCallback<String> cb) {
-		final long start = System.currentTimeMillis();
+		final long start = PlatformRuntime.steadyTimeMillis();
 		getClipboard1(new StupidFunctionResolveString() {
 			@Override
 			public void resolveStr(String s) {
-				if(System.currentTimeMillis() - start > 500l) {
+				if(PlatformRuntime.steadyTimeMillis() - start > 500l) {
 					PlatformInput.unpressCTRL = true;
 				}
 				cb.complete(s);
@@ -87,10 +114,10 @@ public class PlatformApplication {
 		});
 	}
 	
-	@JSBody(params = { "cb" }, script = "if(!window.navigator.clipboard || !window.navigator.clipboard.readText) cb(\"\"); else window.navigator.clipboard.readText().then(function(s) { cb(s); }, function(s) { cb(\"\"); });")
+	@JSBody(params = { "cb" }, script = "if(!navigator.clipboard) { cb(prompt(\"Please enter the text to paste:\") || \"\"); } else if (!navigator.clipboard.readText) cb(\"\"); else navigator.clipboard.readText().then(function(s) { cb(s); }, function(s) { cb(\"\"); });")
 	private static native void getClipboard1(StupidFunctionResolveString cb);
 	
-	@JSBody(params = { "str" }, script = "if(window.navigator.clipboard) window.navigator.clipboard.writeText(str);")
+	@JSBody(params = { "str" }, script = "if(navigator.clipboard) clipboard.writeText(str);")
 	private static native void setClipboard0(String str);
 	
 	public static void setLocalStorage(String name, byte[] data) {
@@ -100,11 +127,11 @@ public class PlatformApplication {
 	public static void setLocalStorage(String name, byte[] data, boolean hooks) {
 		IClientConfigAdapter adapter = PlatformRuntime.getClientConfigAdapter();
 		String eagName = adapter.getLocalStorageNamespace() + "." + name;
-		String b64 = Base64.encodeBase64String(data);
+		String b64 = data != null ? Base64.encodeBase64String(data) : null;
 		try {
 			Storage s = Window.current().getLocalStorage();
 			if(s != null) {
-				if(data != null) {
+				if(b64 != null) {
 					s.setItem(eagName, b64);
 				}else {
 					s.removeItem(eagName);
@@ -157,24 +184,49 @@ public class PlatformApplication {
 		}
 	}
 	
-	private static final DateFormat dateFormatSS = EagRuntime.fixDateFormat(new SimpleDateFormat("yyyy-MM-dd_HH.mm.ss"));
+	private static final DateFormat dateFormatSS = new SimpleDateFormat("yyyy-MM-dd_HH.mm.ss");
 	
 	public static String saveScreenshot() {
+		PlatformOpenGL._wglBindFramebuffer(0x8D40, null);
+		int w = PlatformInput.getWindowWidth();
+		int h = PlatformInput.getWindowHeight();
+		ByteBuffer buf = PlatformRuntime.allocateByteBuffer(w * h * 4);
+		PlatformOpenGL._wglReadPixels(0, 0, w, h, 6408, 5121, buf);
+		for(int i = 3, l = buf.remaining(); i < l; i += 4) {
+			buf.put(i, (byte)0xFF);
+		}
 		String name = "screenshot_" + dateFormatSS.format(new Date()).toString() + ".png";
-		int w = PlatformRuntime.canvas.getWidth();
-		int h = PlatformRuntime.canvas.getHeight();
 		HTMLCanvasElement copyCanvas = (HTMLCanvasElement) Window.current().getDocument().createElement("canvas");
 		copyCanvas.setWidth(w);
 		copyCanvas.setHeight(h);
-		CanvasRenderingContext2D ctx = (CanvasRenderingContext2D) copyCanvas.getContext("2d");
-		ctx.drawImage(PlatformRuntime.canvas, 0, 0);
-		saveScreenshot(name, copyCanvas);
+		CanvasRenderingContext2D ctx = (CanvasRenderingContext2D) copyCanvas.getContext("2d", PlatformAssets.youEagler());
+		putImageData(ctx, EaglerArrayBufferAllocator.getDataView8(buf).getBuffer(), w, h);
+		PlatformRuntime.freeByteBuffer(buf);
+		downloadScreenshot(copyCanvas, name, PlatformRuntime.parent);
 		return name;
 	}
-	
-	@JSBody(params = { "name", "cvs" }, script = "var a=document.createElement(\"a\");a.href=cvs.toDataURL(\"image/png\");a.download=name;a.click();")
-	private static native void saveScreenshot(String name, HTMLCanvasElement cvs);
-	
+
+	@JSBody(params = { "ctx", "buffer", "w", "h" }, script = "var imgData = ctx.createImageData(w, h); var ww = w * 4; for(var i = 0; i < h; ++i) { imgData.data.set(new Uint8ClampedArray(buffer, (h - i - 1) * ww, ww), i * ww); } ctx.putImageData(imgData, 0, 0);")
+	private static native JSObject putImageData(CanvasRenderingContext2D ctx, ArrayBuffer buffer, int w, int h);
+
+	@JSBody(params = { "cvs", "name", "parentElement" }, script =
+			"var vigg = function(el, url){" +
+			"el.style.position = \"absolute\";" +
+			"el.style.left = \"0px\";" +
+			"el.style.top = \"0px\";" +
+			"el.style.zIndex = \"-100\";" +
+			"el.style.color = \"transparent\";" +
+			"el.innerText = \"Download Screenshot\";" +
+			"el.href = url;" +
+			"el.target = \"_blank\";" +
+			"el.download = name;" +
+			"parentElement.appendChild(el);" +
+			"setTimeout(function() { el.click();" +
+			"setTimeout(function() { parentElement.removeChild(el); }, 50);" +
+			"}, 50);" +
+			"}; setTimeout(function() { vigg(document.createElement(\"a\"), cvs.toDataURL(\"image/png\")); }, 50);")
+	private static native void downloadScreenshot(HTMLCanvasElement cvs, String name, HTMLElement parentElement);
+
 	public static void showPopup(final String msg) {
 		Window.setTimeout(new TimerHandler() {
 			@Override
@@ -205,16 +257,52 @@ public class PlatformApplication {
 
 	}
 
-	private static volatile boolean fileChooserHasResult = false;
-	private static volatile FileChooserResult fileChooserResultObject = null;
+	private static final int FILE_CHOOSER_IMPL_CORE = 0;
+	private static final int FILE_CHOOSER_IMPL_LEGACY = 1;
+	private static int fileChooserImpl = -1;
+	private static boolean fileChooserHasResult = false;
+	private static FileChooserResult fileChooserResultObject = null;
+	private static HTMLInputElement fileChooserElement = null;
+	private static HTMLElement fileChooserMobileElement = null;
 
 	@JSBody(params = { "inputElement", "callback" }, script = 
 			"if(inputElement.files.length > 0) {"
-			+ "const value = inputElement.files[0];"
+			+ "var eag = function(value){"
 			+ "value.arrayBuffer().then(function(arr){ callback(value.name, arr); })"
 			+ ".catch(function(){ callback(null, null); });"
-			+ "} else callback(null, null);")
-	private static native void getFileChooserResult(HTMLInputElement inputElement, FileChooserCallback callback);
+			+ "}; eag(inputElement.files[0]); } else callback(null, null);")
+	private static native void getFileChooserResultNew(HTMLInputElement inputElement, FileChooserCallback callback);
+
+	@JSBody(params = { "inputElement", "callback" }, script = 
+			"if(inputElement.files.length > 0) {"
+			+ "var eag = function(value, reader){"
+			+ "reader.addEventListener(\"loadend\",function(evt){ callback(value.name, reader.result); });"
+			+ "reader.addEventListener(\"error\",function(evt){ callback(null, null); });"
+			+ "reader.readAsArrayBuffer(value);"
+			+ "}; eag(inputElement.files[0], new FileReader()); } else callback(null, null);")
+	private static native void getFileChooserResultLegacy(HTMLInputElement inputElement, FileChooserCallback callback);
+
+	private static void getFileChooserResult(HTMLInputElement inputElement, FileChooserCallback callback) {
+		if(fileChooserImpl == -1) {
+			fileChooserImpl = getFileChooserImpl();
+			if(fileChooserImpl == FILE_CHOOSER_IMPL_LEGACY) {
+				PlatformRuntime.logger.info("Note: using legacy FileReader implementation because File.prototype.arrayBuffer() is not supported");
+			}
+		}
+		switch(fileChooserImpl) {
+		case FILE_CHOOSER_IMPL_CORE:
+			getFileChooserResultNew(inputElement, callback);
+			break;
+		case FILE_CHOOSER_IMPL_LEGACY:
+			getFileChooserResultLegacy(inputElement, callback);
+			break;
+		default:
+			throw new UnsupportedOperationException();
+		}
+	}
+
+	@JSBody(params = { }, script = "return (typeof File.prototype.arrayBuffer === \"function\") ? 0 : 1;")
+	private static native int getFileChooserImpl();
 
 	@JSBody(params = { "inputElement", "value" }, script = "inputElement.accept = value;")
 	private static native void setAcceptSelection(HTMLInputElement inputElement, String value);
@@ -223,21 +311,106 @@ public class PlatformApplication {
 	private static native void setMultipleSelection(HTMLInputElement inputElement, boolean enable);
 
 	public static void displayFileChooser(String mime, String ext) {
-		final HTMLInputElement inputElement = (HTMLInputElement) Window.current().getDocument().createElement("input");
-		inputElement.setType("file");
-		if(mime == null) {
-			setAcceptSelection(inputElement, "." + ext);
-		}else {
-			setAcceptSelection(inputElement, mime);
-		}
-		setMultipleSelection(inputElement, false);
-		inputElement.addEventListener("change", new EventListener<Event>() {
-			@Override
-			public void handleEvent(Event evt) {
-				getFileChooserResult(inputElement, FileChooserCallbackImpl.instance);
+		clearFileChooserResult();
+		final HTMLDocument doc = PlatformRuntime.doc != null ? PlatformRuntime.doc : Window.current().getDocument();
+		if(PlatformInput.isLikelyMobileBrowser) {
+			final HTMLElement element = fileChooserMobileElement = doc.createElement("div");
+			element.getClassList().add("_eaglercraftX_mobile_file_chooser_popup");
+			CSSStyleDeclaration decl = element.getStyle();
+			decl.setProperty("position", "absolute");
+			decl.setProperty("background-color", "white");
+			decl.setProperty("font-family", "sans-serif");
+			decl.setProperty("top", "10%");
+			decl.setProperty("left", "10%");
+			decl.setProperty("right", "10%");
+			decl.setProperty("border", "5px double black");
+			decl.setProperty("padding", "15px");
+			decl.setProperty("text-align", "left");
+			decl.setProperty("font-size", "20px");
+			decl.setProperty("user-select", "none");
+			decl.setProperty("z-index", "150");
+			final HTMLElement fileChooserTitle = doc.createElement("h3");
+			fileChooserTitle.appendChild(doc.createTextNode("File Chooser"));
+			element.appendChild(fileChooserTitle);
+			final HTMLElement inputElementContainer = doc.createElement("p");
+			final HTMLInputElement inputElement = fileChooserElement = (HTMLInputElement) doc.createElement("input");
+			inputElement.setType("file");
+			if(mime == null) {
+				setAcceptSelection(inputElement, "." + ext);
+			}else {
+				setAcceptSelection(inputElement, mime);
 			}
-		});
-		inputElement.click();
+			setMultipleSelection(inputElement, false);
+			inputElementContainer.appendChild(inputElement);
+			element.appendChild(inputElementContainer);
+			final HTMLElement fileChooserButtons = doc.createElement("p");
+			final HTMLElement fileChooserButtonCancel = doc.createElement("button");
+			fileChooserButtonCancel.getClassList().add("_eaglercraftX_mobile_file_chooser_btn_cancel");
+			fileChooserButtonCancel.getStyle().setProperty("font-size", "1.0em");
+			fileChooserButtonCancel.addEventListener("click", new EventListener<Event>() {
+				@Override
+				public void handleEvent(Event evt) {
+					if(fileChooserMobileElement == element) {
+						PlatformRuntime.parent.removeChild(element);
+						fileChooserMobileElement = null;
+						fileChooserElement = null;
+					}
+				}
+			});
+			fileChooserButtonCancel.appendChild(doc.createTextNode("Cancel"));
+			fileChooserButtons.appendChild(fileChooserButtonCancel);
+			fileChooserButtons.appendChild(doc.createTextNode(" "));
+			final HTMLElement fileChooserButtonDone = doc.createElement("button");
+			fileChooserButtonDone.getClassList().add("_eaglercraftX_mobile_file_chooser_btn_done");
+			fileChooserButtonDone.getStyle().setProperty("font-size", "1.0em");
+			fileChooserButtonDone.getStyle().setProperty("font-weight", "bold");
+			fileChooserButtonDone.addEventListener("click", new EventListener<Event>() {
+				@Override
+				public void handleEvent(Event evt) {
+					if(fileChooserMobileElement == element) {
+						getFileChooserResult(inputElement, FileChooserCallbackImpl.instance);
+						PlatformRuntime.parent.removeChild(element);
+						fileChooserMobileElement = null;
+						fileChooserElement = null;
+					}
+				}
+			});
+			fileChooserButtonDone.appendChild(doc.createTextNode("Done"));
+			fileChooserButtons.appendChild(fileChooserButtonDone);
+			element.appendChild(fileChooserButtons);
+			PlatformRuntime.parent.appendChild(element);
+		}else {
+			final HTMLInputElement inputElement = fileChooserElement = (HTMLInputElement) doc.createElement("input");
+			inputElement.setType("file");
+			CSSStyleDeclaration decl = inputElement.getStyle();
+			decl.setProperty("position", "absolute");
+			decl.setProperty("left", "0px");
+			decl.setProperty("top", "0px");
+			decl.setProperty("z-index", "-100");
+			if(mime == null) {
+				setAcceptSelection(inputElement, "." + ext);
+			}else {
+				setAcceptSelection(inputElement, mime);
+			}
+			setMultipleSelection(inputElement, false);
+			inputElement.addEventListener("change", new EventListener<Event>() {
+				@Override
+				public void handleEvent(Event evt) {
+					if(fileChooserElement == inputElement) {
+						getFileChooserResult(inputElement, FileChooserCallbackImpl.instance);
+						PlatformRuntime.parent.removeChild(inputElement);
+						fileChooserElement = null;
+					}
+				}
+			});
+			PlatformRuntime.parent.appendChild(inputElement);
+			Window.setTimeout(new TimerHandler() {
+				@Override
+				public void onTimer() {
+					inputElement.click();
+				}
+			}, 50);
+		}
 	}
 
 	public static boolean fileChooserHasResult() {
@@ -261,16 +434,16 @@ public class PlatformApplication {
 	private static native void documentWrite(HTMLDocument doc, String str);
 
 	public static void openCreditsPopup(String text) {
-		Window currentWin = Window.current();
+		Window currentWin = PlatformRuntime.win;
 		
-		int w = (int)(850 * currentWin.getDevicePixelRatio());
-		int h = (int)(700 * currentWin.getDevicePixelRatio());
+		int w = (int)(850 * PlatformInput.getDPI());
+		int h = (int)(700 * PlatformInput.getDPI());
 		
 		int x = (currentWin.getScreen().getWidth() - w) / 2;
 		int y = (currentWin.getScreen().getHeight() - h) / 2;
 		
 		Window newWin = Window.current().open("", "_blank", "top=" + y + ",left=" + x + ",width=" + w + ",height=" + h + ",menubar=0,status=0,titlebar=0,toolbar=0");
-		if(newWin == null) {
+		if(newWin == null || TeaVMUtils.isNotTruthy(newWin)) {
 			Window.alert("ERROR: Popup blocked!\n\nPlease make sure you have popups enabled for this site!");
 			return;
 		}
@@ -285,17 +458,48 @@ public class PlatformApplication {
 	public static void clearFileChooserResult() {
 		fileChooserHasResult = false;
 		fileChooserResultObject = null;
+		if(fileChooserMobileElement != null) {
+			PlatformRuntime.parent.removeChild(fileChooserMobileElement);
+			fileChooserMobileElement = null;
+			fileChooserElement = null;
+		}else if(fileChooserElement != null) {
+			PlatformRuntime.parent.removeChild(fileChooserElement);
+			fileChooserElement = null;
+		}
 	}
 
-	@JSBody(params = { "name", "buf" }, script =
-			"var hr = window.URL.createObjectURL(new Blob([buf], {type: \"octet/stream\"}));" +
-			"var a = document.createElement(\"a\");" +
-			"a.href = hr; a.download = name; a.click();" +
-			"window.URL.revokeObjectURL(hr);")
-	private static final native void downloadBytesImpl(String str, ArrayBuffer buf);
+	@JSFunctor
+	private static interface DownloadBytesBlobURLRevoke extends JSObject {
+		void call();
+	}
 
-	public static final void downloadFileWithName(String str, byte[] dat) {
-		downloadBytesImpl(str, TeaVMUtils.unwrapArrayBuffer(dat));
+	@JSBody(params = { "name", "url", "revokeFunc", "parentElement" }, script =
+			"var vigg = function(el){" +
+			"el.style.position = \"absolute\";" +
+			"el.style.left = \"0px\";" +
+			"el.style.top = \"0px\";" +
+			"el.style.zIndex = \"-100\";" +
+			"el.style.color = \"transparent\";" +
+			"el.innerText = \"Download File\";" +
+			"el.href = url;" +
+			"el.target = \"_blank\";" +
+			"el.download = name;" +
+			"parentElement.appendChild(el);" +
+			"setTimeout(function() { el.click();" +
+			"setTimeout(function() { parentElement.removeChild(el); }, 50);" +
+			"setTimeout(function() { revokeFunc(); }, 60000);" +
+			"}, 50);" +
+			"}; vigg(document.createElement(\"a\"));")
+	private static native void downloadBytesImpl(String str, String url, DownloadBytesBlobURLRevoke revokeFunc, HTMLElement parentElement);
+
+	public static void downloadFileWithName(String str, byte[] dat) {
+		TeaVMBlobURLHandle blobHandle = TeaVMBlobURLManager.registerNewURLByte(dat, "application/octet-stream");
+		downloadBytesImpl(str, blobHandle.toExternalForm(), blobHandle::release, PlatformRuntime.parent);
+	}
+
+	public static void downloadFileWithNameTeaVM(String str, ArrayBuffer dat) {
+		TeaVMBlobURLHandle blobHandle = TeaVMBlobURLManager.registerNewURLArrayBuffer(dat, "application/octet-stream");
+		downloadBytesImpl(str, blobHandle.toExternalForm(), blobHandle::release, PlatformRuntime.parent);
 	}
 
 	public static void showDebugConsole() {
@@ -312,4 +516,5 @@ public class PlatformApplication {
 
 	@JSBody(params = { "str" }, script = "window.minecraftServer = str;")
 	public static native void setMCServerWindowGlobal(String str);
+
 }
diff --git a/sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/PlatformAssets.java b/sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/PlatformAssets.java
index 678d99db..3e4a4f92 100644
--- a/sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/PlatformAssets.java
+++ b/sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/PlatformAssets.java
@@ -20,6 +20,8 @@ import org.teavm.jso.typedarrays.Uint8ClampedArray;
 
 import net.lax1dude.eaglercraft.v1_8.EaglerInputStream;
 import net.lax1dude.eaglercraft.v1_8.internal.teavm.ClientMain;
+import net.lax1dude.eaglercraft.v1_8.internal.teavm.TeaVMBlobURLHandle;
+import net.lax1dude.eaglercraft.v1_8.internal.teavm.TeaVMBlobURLManager;
 import net.lax1dude.eaglercraft.v1_8.internal.teavm.TeaVMUtils;
 import net.lax1dude.eaglercraft.v1_8.opengl.ImageData;
 
@@ -41,10 +43,34 @@ import net.lax1dude.eaglercraft.v1_8.opengl.ImageData;
 public class PlatformAssets {
 	
 	private static final byte[] MISSING_FILE = new byte[0];
+
+	static Map<String,byte[]> assets = new HashMap<>();
+
+	public static boolean getResourceExists(String path) {
+		if(path.startsWith("/")) {
+			path = path.substring(1);
+		}
+		byte[] ret = assets.get(path);
+		if(ret != null && ret != MISSING_FILE) {
+			return true;
+		}else {
+			if(path.startsWith("assets/minecraft/lang/") && !path.endsWith(".mcmeta")) {
+				ArrayBuffer file = PlatformRuntime.downloadRemoteURI(
+						ClientMain.configLocalesFolder + "/" + path.substring(22));
+				if(file != null) {
+					assets.put(path, TeaVMUtils.wrapByteArrayBuffer(file));
+					return true;
+				}else {
+					assets.put(path, MISSING_FILE);
+					return false;
+				}
+			}else {
+				return false;
+			}
+		}
+	}
 	
-	static final Map<String,byte[]> assets = new HashMap();
-	
-	public static final byte[] getResourceBytes(String path) {
+	public static byte[] getResourceBytes(String path) {
 		if(path.startsWith("/")) {
 			path = path.substring(1);
 		}
@@ -52,7 +78,7 @@ public class PlatformAssets {
 		if(data == null && path.startsWith("assets/minecraft/lang/") && !path.endsWith(".mcmeta")) {
 			ArrayBuffer file = PlatformRuntime.downloadRemoteURI(
 					ClientMain.configLocalesFolder + "/" + path.substring(22));
-			if(file != null && file.getByteLength() > 0) {
+			if(file != null) {
 				data = TeaVMUtils.wrapByteArrayBuffer(file);
 				assets.put(path, data);
 				return data;
@@ -65,10 +91,14 @@ public class PlatformAssets {
 		}
 	}
 	
-	public static final ImageData loadImageFile(InputStream data) {
+	public static ImageData loadImageFile(InputStream data) {
+		return loadImageFile(data, "image/png");
+	}
+	
+	public static ImageData loadImageFile(InputStream data, String mime) {
 		byte[] b = EaglerInputStream.inputStreamToBytesQuiet(data);
 		if(b != null) {
-			return loadImageFile(b);
+			return loadImageFile(b, mime);
 		}else {
 			return null;
 		}
@@ -78,21 +108,22 @@ public class PlatformAssets {
 	private static CanvasRenderingContext2D imageLoadContext = null;
 	
 	public static ImageData loadImageFile(byte[] data) {
-		return loadImageFile(TeaVMUtils.unwrapArrayBuffer(data));
+		return loadImageFile(data, "image/png");
 	}
 	
 	@JSBody(params = { }, script = "return { willReadFrequently: true };")
-	public static native JSObject youEagler();
+	static native JSObject youEagler();
 	
 	@JSBody(params = { "ctx" }, script = "ctx.imageSmoothingEnabled = false;")
 	private static native void disableImageSmoothing(CanvasRenderingContext2D ctx);
 	
 	@Async
-	private static native ImageData loadImageFile(ArrayBuffer data);
+	public static native ImageData loadImageFile(byte[] data, String mime);
 	
-	private static void loadImageFile(ArrayBuffer data, final AsyncCallback<ImageData> ret) {
+	private static void loadImageFile(byte[] data, String mime, final AsyncCallback<ImageData> ret) {
 		final Document doc = Window.current().getDocument();
 		final HTMLImageElement toLoad = (HTMLImageElement) doc.createElement("img");
+		final TeaVMBlobURLHandle[] src = new TeaVMBlobURLHandle[1];
 		toLoad.addEventListener("load", new EventListener<Event>() {
 			@Override
 			public void handleEvent(Event evt) {
@@ -114,7 +145,7 @@ public class PlatformAssets {
 				org.teavm.jso.canvas.ImageData pxlsDat = imageLoadContext.getImageData(0, 0, toLoad.getWidth(), toLoad.getHeight());
 				Uint8ClampedArray pxls = pxlsDat.getData();
 				int totalPixels = pxlsDat.getWidth() * pxlsDat.getHeight();
-				TeaVMUtils.freeDataURL(toLoad.getSrc());
+				TeaVMBlobURLManager.releaseURL(src[0]);
 				if(pxls.getByteLength() < totalPixels << 2) {
 					ret.complete(null);
 					return;
@@ -125,16 +156,19 @@ public class PlatformAssets {
 		toLoad.addEventListener("error", new EventListener<Event>() {
 			@Override
 			public void handleEvent(Event evt) {
-				TeaVMUtils.freeDataURL(toLoad.getSrc());
+				TeaVMBlobURLManager.releaseURL(src[0]);
 				ret.complete(null);
 			}
 		});
-		String src = TeaVMUtils.getDataURL(data, "image/png");
-		if(src != null) {
-			toLoad.setSrc(src);
+		src[0] = TeaVMBlobURLManager.registerNewURLByte(data, mime);
+		if(src[0] != null) {
+			toLoad.setSrc(src[0].toExternalForm());
 		}else {
 			ret.complete(null);
 		}
 	}
-	
+
+	public static void freeAssetRepoTeaVM() {
+		assets = new HashMap<>();
+	}
 }
diff --git a/sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/PlatformAudio.java b/sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/PlatformAudio.java
index 4fcedd52..622f16a2 100644
--- a/sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/PlatformAudio.java
+++ b/sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/PlatformAudio.java
@@ -2,16 +2,17 @@ package net.lax1dude.eaglercraft.v1_8.internal;
 
 import java.util.HashMap;
 import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
 import java.util.Map;
 
-import net.minecraft.client.Minecraft;
-import net.minecraft.client.audio.SoundCategory;
 import org.teavm.interop.Async;
 import org.teavm.interop.AsyncCallback;
+import org.teavm.jso.JSBody;
 import org.teavm.jso.JSObject;
 import org.teavm.jso.dom.events.EventListener;
 import org.teavm.jso.typedarrays.ArrayBuffer;
-import org.teavm.jso.typedarrays.Uint8Array;
+import org.teavm.jso.typedarrays.Int8Array;
 import org.teavm.jso.webaudio.AudioBuffer;
 import org.teavm.jso.webaudio.AudioBufferSourceNode;
 import org.teavm.jso.webaudio.AudioContext;
@@ -24,13 +25,16 @@ import org.teavm.jso.webaudio.MediaStream;
 import org.teavm.jso.webaudio.MediaStreamAudioDestinationNode;
 import org.teavm.jso.webaudio.PannerNode;
 
+import net.lax1dude.eaglercraft.v1_8.EagRuntime;
+import net.lax1dude.eaglercraft.v1_8.internal.teavm.JOrbisAudioBufferDecoder;
+import net.lax1dude.eaglercraft.v1_8.internal.teavm.TeaVMClientConfigAdapter;
 import net.lax1dude.eaglercraft.v1_8.internal.teavm.TeaVMUtils;
 import net.lax1dude.eaglercraft.v1_8.log4j.LogManager;
 import net.lax1dude.eaglercraft.v1_8.log4j.Logger;
 import net.minecraft.util.MathHelper;
 
 /**
- * Copyright (c) 2022-2023 lax1dude. All Rights Reserved.
+ * Copyright (c) 2022-2024 lax1dude. All Rights Reserved.
  * 
  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
@@ -49,10 +53,21 @@ public class PlatformAudio {
 	static final Logger logger = LogManager.getLogger("BrowserAudio");
 	
 	static AudioContext audioctx = null;
-	static MediaStreamAudioDestinationNode recDest = null;
-	private static final Map<String, BrowserAudioResource> soundCache = new HashMap();
-	
+	static MediaStreamAudioDestinationNode recDestNode = null;
+	static MediaStream recDestMediaStream = null;
+	static AudioBuffer silence = null;
+	static AudioBufferSourceNode recDestSilenceNode = null;
+	static GainNode micRecGain = null;
+	static GainNode gameRecGain = null;
+	private static final Map<String, BrowserAudioResource> soundCache = new HashMap<>();
+	private static final List<BrowserAudioHandle> activeSounds = new LinkedList<>();
+
 	private static long cacheFreeTimer = 0l;
+	private static long activeFreeTimer = 0l;
+	private static boolean oggSupport = false;
+	private static boolean loadViaAudioBufferSupport = false;
+	private static boolean loadViaWAV32FSupport = false;
+	private static boolean loadViaWAV16Support = false;
 	
 	protected static class BrowserAudioResource implements IAudioResource {
 		
@@ -105,7 +120,7 @@ public class PlatformAudio {
 			if(isEnded) {
 				isEnded = false;
 				AudioBufferSourceNode src = audioctx.createBufferSource();
-				resource.cacheHit = System.currentTimeMillis();
+				resource.cacheHit = PlatformRuntime.steadyTimeMillis();
 				src.setBuffer(resource.buffer);
 				src.getPlaybackRate().setValue(pitch);
 				source.disconnect();
@@ -166,44 +181,183 @@ public class PlatformAudio {
 	}
 	
 	static void initialize() {
+		oggSupport = false;
+		loadViaAudioBufferSupport = false;
+		loadViaWAV32FSupport = false;
+		loadViaWAV16Support = false;
 		
 		try {
 			audioctx = AudioContext.create();
-			recDest = audioctx.createMediaStreamDestination();
 		}catch(Throwable t) {
-			throw new PlatformRuntime.RuntimeInitializationFailureException("Could not initialize audio context!", t);
+			audioctx = null;
+			logger.error("Could not initialize audio context!");
+			logger.error(t);
+			return;
+		}
+		
+		detectOGGSupport();
+		
+		if(!oggSupport) {
+			loadViaAudioBufferSupport = detectLoadViaAudioBufferSupport(audioctx);
+			if(!loadViaAudioBufferSupport) {
+				logger.warn("Missing AudioContext buffer from Float32Array support, attempting to use WAV files as a container to load raw PCM data");
+				detectWAVFallbackSupport();
+				if(!loadViaWAV32FSupport && !loadViaWAV16Support) {
+					try {
+						audioctx.close();
+					}catch(Throwable t) {
+					}
+					audioctx = null;
+					logger.error("Audio context is missing some required features!");
+				}
+			}
 		}
 		
 		PlatformInput.clearEvenBuffers();
 		
 	}
 
-	private static GainNode micGain;
+	@JSBody(params = { "ctx" }, script = "var tmpBuf = ctx.createBuffer(2, 16, 16000); return (typeof tmpBuf.copyToChannel === \"function\");")
+	private static native boolean detectLoadViaAudioBufferSupport(AudioContext ctx);
 
-	public static void setMicVol(float vol) {
-		if (micGain == null) return;
-		micGain.getGain().setValue(vol);
-	}
+	private static void detectOGGSupport() {
+		byte[] fileData = EagRuntime.getRequiredResourceBytes("/assets/eagler/audioctx_test_ogg.dat");
 
-	protected static void initRecDest() {
-		AudioBufferSourceNode absn = audioctx.createBufferSource();
-		AudioBuffer ab = audioctx.createBuffer(1, 1, 48000);
-		ab.copyToChannel(new float[] { 0 }, 0);
-		absn.setBuffer(ab);
-		absn.setLoop(true);
-		absn.start();
-		absn.connect(recDest);
-		MediaStream mic = PlatformRuntime.getMic();
-		if (mic != null) {
-			micGain = audioctx.createGain();
-			micGain.getGain().setValue(Minecraft.getMinecraft().gameSettings.getSoundLevel(SoundCategory.VOICE));
-			audioctx.createMediaStreamSource(mic).connect(micGain);
-			micGain.connect(recDest);
+		if(((TeaVMClientConfigAdapter)PlatformRuntime.getClientConfigAdapter()).isUseJOrbisAudioDecoderTeaVM()) {
+			logger.info("Note: Using embedded JOrbis OGG decoder");
+			oggSupport = false;
+		}else {
+			try {
+				Int8Array arr = Int8Array.create(fileData.length);
+				arr.set(TeaVMUtils.unwrapByteArray(fileData), 0);
+				AudioBuffer buffer = decodeAudioBrowserAsync(arr.getBuffer(), null);
+				if(buffer == null || buffer.getLength() == 0) {
+					throw new RuntimeException();
+				}
+				oggSupport = true;
+			}catch(Throwable t) {
+				oggSupport = false;
+				logger.error("OGG file support detected as false! Using embedded JOrbis OGG decoder");
+			}
 		}
 	}
 
-	protected static MediaStream getRecStream() {
-		return recDest.getStream();
+	private static void detectWAVFallbackSupport() {
+		byte[] fileData = EagRuntime.getRequiredResourceBytes("/assets/eagler/audioctx_test_wav32f.dat");
+		
+		try {
+			Int8Array arr = Int8Array.create(fileData.length);
+			arr.set(TeaVMUtils.unwrapByteArray(fileData), 0);
+			AudioBuffer buffer = decodeAudioBrowserAsync(arr.getBuffer(), null);
+			if(buffer == null || buffer.getLength() == 0) {
+				throw new RuntimeException();
+			}
+			loadViaWAV32FSupport = true;
+			return;
+		}catch(Throwable t) {
+			loadViaWAV32FSupport = false;
+			logger.error("Could not load a 32-bit floating point WAV file, trying to use 16-bit integers");
+		}
+		
+		fileData = EagRuntime.getRequiredResourceBytes("/assets/eagler/audioctx_test_wav16.dat");
+		
+		try {
+			Int8Array arr = Int8Array.create(fileData.length);
+			arr.set(TeaVMUtils.unwrapByteArray(fileData), 0);
+			AudioBuffer buffer = decodeAudioBrowserAsync(arr.getBuffer(), null);
+			if(buffer == null || buffer.getLength() == 0) {
+				throw new RuntimeException();
+			}
+			loadViaWAV16Support = true;
+			return;
+		}catch(Throwable t) {
+			loadViaWAV16Support = false;
+			logger.error("Could not load a 16-bit integer WAV file, this browser is not supported");
+		}
+	}
+
+	static MediaStream initRecordingStream(float gameVol, float micVol) {
+		if(recDestMediaStream != null) {
+			return recDestMediaStream;
+		}
+		try {
+			if(silence == null) {
+				silence = audioctx.createBuffer(1, 1, 48000);
+				silence.copyToChannel(new float[] { 0 }, 0);
+			}
+			recDestNode = audioctx.createMediaStreamDestination();
+			recDestSilenceNode = audioctx.createBufferSource();
+			recDestSilenceNode.setBuffer(silence);
+			recDestSilenceNode.setLoop(true);
+			recDestSilenceNode.start();
+			recDestSilenceNode.connect(recDestNode);
+			if(micVol > 0.0f) {
+				MediaStream mic = PlatformScreenRecord.getMic();
+				if (mic != null) {
+					micRecGain = audioctx.createGain();
+					micRecGain.getGain().setValue(micVol);
+					audioctx.createMediaStreamSource(mic).connect(micRecGain);
+					micRecGain.connect(recDestNode);
+				}
+			}
+			gameRecGain = audioctx.createGain();
+			gameRecGain.getGain().setValue(gameVol);
+			synchronized(activeSounds) {
+				for(BrowserAudioHandle handle : activeSounds) {
+					if(handle.panner != null) {
+						handle.panner.connect(gameRecGain);
+					}else {
+						handle.gain.connect(gameRecGain);
+					}
+				}
+			}
+			PlatformVoiceClient.addRecordingDest(gameRecGain);
+			gameRecGain.connect(recDestNode);
+			recDestMediaStream = recDestNode.getStream();
+			return recDestMediaStream;
+		}catch(Throwable t) {
+			destroyRecordingStream();
+			throw t;
+		}
+	}
+
+	static void destroyRecordingStream() {
+		if(recDestSilenceNode != null) {
+			try {
+				recDestSilenceNode.disconnect();
+			}catch(Throwable t) {
+			}
+			recDestSilenceNode = null;
+		}
+		if(micRecGain != null) {
+			try {
+				micRecGain.disconnect();
+			}catch(Throwable t) {
+			}
+			micRecGain = null;
+		}
+		if(gameRecGain != null) {
+			try {
+				gameRecGain.disconnect();
+			}catch(Throwable t) {
+			}
+			synchronized(activeSounds) {
+				for(BrowserAudioHandle handle : activeSounds) {
+					try {
+						if(handle.panner != null) {
+							handle.panner.disconnect(gameRecGain);
+						}else {
+							handle.gain.disconnect(gameRecGain);
+						}
+					}catch(Throwable t) {
+					}
+				}
+			}
+			PlatformVoiceClient.removeRecordingDest(gameRecGain);
+			gameRecGain = null;
+		}
+		recDestNode = null;
+		recDestMediaStream = null;
 	}
 
 	public static IAudioResource loadAudioData(String filename, boolean holdInCache) {
@@ -214,7 +368,7 @@ public class PlatformAudio {
 		if(buffer == null) {
 			byte[] file = PlatformAssets.getResourceBytes(filename);
 			if(file == null) return null;
-			buffer = new BrowserAudioResource(decodeAudioAsync(TeaVMUtils.unwrapArrayBuffer(file), filename));
+			buffer = new BrowserAudioResource(decodeAudioData(file, filename));
 			if(holdInCache) {
 				synchronized(soundCache) {
 					soundCache.put(filename, buffer);
@@ -222,7 +376,7 @@ public class PlatformAudio {
 			}
 		}
 		if(buffer.buffer != null) {
-			buffer.cacheHit = System.currentTimeMillis();
+			buffer.cacheHit = PlatformRuntime.steadyTimeMillis();
 			return buffer;
 		}else {
 			return null;
@@ -241,9 +395,7 @@ public class PlatformAudio {
 		if(buffer == null) {
 			byte[] file = loader.loadFile(filename);
 			if(file == null) return null;
-			Uint8Array buf = Uint8Array.create(file.length);
-			buf.set(file);
-			buffer = new BrowserAudioResource(decodeAudioAsync(buf.getBuffer(), filename));
+			buffer = new BrowserAudioResource(decodeAudioData(file, filename));
 			if(holdInCache) {
 				synchronized(soundCache) {
 					soundCache.put(filename, buffer);
@@ -251,17 +403,40 @@ public class PlatformAudio {
 			}
 		}
 		if(buffer.buffer != null) {
-			buffer.cacheHit = System.currentTimeMillis();
+			buffer.cacheHit = PlatformRuntime.steadyTimeMillis();
 			return buffer;
 		}else {
 			return null;
 		}
 	}
 	
-	@Async
-	public static native AudioBuffer decodeAudioAsync(ArrayBuffer buffer, String errorFileName);
+	private static AudioBuffer decodeAudioData(byte[] data, String errorFileName) {
+		if(data == null) {
+			return null;
+		}
+		if(oggSupport) {
+			// browsers complain if we don't copy the array
+			Int8Array arr = Int8Array.create(data.length);
+			arr.set(TeaVMUtils.unwrapByteArray(data), 0);
+			return decodeAudioBrowserAsync(arr.getBuffer(), errorFileName);
+		}else {
+			if(data.length > 4 && data[0] == (byte)0x4F && data[1] == (byte)0x67 && data[2] == (byte)0x67 && data[3] == (byte)0x53) {
+				return JOrbisAudioBufferDecoder.decodeAudioJOrbis(audioctx, data, errorFileName,
+						loadViaAudioBufferSupport ? JOrbisAudioBufferDecoder.LOAD_VIA_AUDIOBUFFER
+								: (loadViaWAV32FSupport ? JOrbisAudioBufferDecoder.LOAD_VIA_WAV32F
+										: JOrbisAudioBufferDecoder.LOAD_VIA_WAV16));
+			} else {
+				Int8Array arr = Int8Array.create(data.length);
+				arr.set(TeaVMUtils.unwrapByteArray(data), 0);
+				return decodeAudioBrowserAsync(arr.getBuffer(), errorFileName);
+			}
+		}
+	}
 	
-	private static void decodeAudioAsync(ArrayBuffer buffer, final String errorFileName, final AsyncCallback<AudioBuffer> cb) {
+	@Async
+	public static native AudioBuffer decodeAudioBrowserAsync(ArrayBuffer buffer, String errorFileName);
+	
+	private static void decodeAudioBrowserAsync(ArrayBuffer buffer, final String errorFileName, final AsyncCallback<AudioBuffer> cb) {
 		audioctx.decodeAudioData(buffer, new DecodeSuccessCallback() {
 			@Override
 			public void onSuccess(AudioBuffer decodedData) {
@@ -270,14 +445,16 @@ public class PlatformAudio {
 		}, new DecodeErrorCallback() {
 			@Override
 			public void onError(JSObject error) {
-				logger.error("Could not load audio: {}", errorFileName);
+				if(errorFileName != null) {
+					logger.error("Could not load audio: {}", errorFileName);
+				}
 				cb.complete(null);
 			}
 		});
 	}
 
 	public static void clearAudioCache() {
-		long millis = System.currentTimeMillis();
+		long millis = PlatformRuntime.steadyTimeMillis();
 		if(millis - cacheFreeTimer > 30000l) {
 			cacheFreeTimer = millis;
 			synchronized(soundCache) {
@@ -289,22 +466,36 @@ public class PlatformAudio {
 				}
 			}
 		}
+		if(millis - activeFreeTimer > 700l) {
+			activeFreeTimer = millis;
+			synchronized(activeSounds) {
+				Iterator<BrowserAudioHandle> itr = activeSounds.iterator();
+				while(itr.hasNext()) {
+					if(itr.next().shouldFree()) {
+						itr.remove();
+					}
+				}
+			}
+		}
 	}
 
 	public static void flushAudioCache() {
 		synchronized(soundCache) {
 			soundCache.clear();
 		}
+		synchronized(activeSounds) {
+			activeSounds.clear();
+		}
 	}
 	
 	public static boolean available() {
-		return true; // this is not used
+		return audioctx != null;
 	}
 	
 	public static IAudioHandle beginPlayback(IAudioResource track, float x, float y, float z,
 			float volume, float pitch) {
 		BrowserAudioResource internalTrack = (BrowserAudioResource) track;
-		internalTrack.cacheHit = System.currentTimeMillis();
+		internalTrack.cacheHit = PlatformRuntime.steadyTimeMillis();
 		
 		AudioBufferSourceNode src = audioctx.createBufferSource();
 		src.setBuffer(internalTrack.buffer);
@@ -331,16 +522,22 @@ public class PlatformAudio {
 		src.connect(panner);
 		panner.connect(gain);
 		gain.connect(audioctx.getDestination());
-		gain.connect(recDest);
+		if(gameRecGain != null) {
+			gain.connect(gameRecGain);
+		}
 
 		src.start();
 		
-		return new BrowserAudioHandle(internalTrack, src, panner, gain, pitch);
+		BrowserAudioHandle ret = new BrowserAudioHandle(internalTrack, src, panner, gain, pitch);
+		synchronized(activeSounds) {
+			activeSounds.add(ret);
+		}
+		return ret;
 	}
 
 	public static IAudioHandle beginPlaybackStatic(IAudioResource track, float volume, float pitch) {
 		BrowserAudioResource internalTrack = (BrowserAudioResource) track;
-		internalTrack.cacheHit = System.currentTimeMillis();
+		internalTrack.cacheHit = PlatformRuntime.steadyTimeMillis();
 		
 		AudioBufferSourceNode src = audioctx.createBufferSource();
 		src.setBuffer(internalTrack.buffer);
@@ -353,11 +550,17 @@ public class PlatformAudio {
 		
 		src.connect(gain);
 		gain.connect(audioctx.getDestination());
-		gain.connect(recDest);
+		if(gameRecGain != null) {
+			gain.connect(gameRecGain);
+		}
 		
 		src.start();
 		
-		return new BrowserAudioHandle(internalTrack, src, null, gain, pitch);
+		BrowserAudioHandle ret = new BrowserAudioHandle(internalTrack, src, null, gain, pitch);
+		synchronized(activeSounds) {
+			activeSounds.add(ret);
+		}
+		return ret;
 	}
 
 	public static void setListener(float x, float y, float z, float pitchDegrees, float yawDegrees) {
@@ -369,5 +572,19 @@ public class PlatformAudio {
 		l.setPosition(x, y, z);
 		l.setOrientation(-var3 * var4, -var5, -var2 * var4, 0.0f, 1.0f, 0.0f);
 	}
+
+	static void destroy() {
+		soundCache.clear();
+		if(audioctx != null) {
+			audioctx.close();
+			audioctx = null;
+			recDestNode = null;
+			recDestMediaStream = null;
+			silence = null;
+			recDestSilenceNode = null;
+			micRecGain = null;
+			gameRecGain = null;
+		}
+	}
 	
 }
diff --git a/sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/PlatformFilesystem.java b/sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/PlatformFilesystem.java
index 5d948ae0..3c391799 100644
--- a/sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/PlatformFilesystem.java
+++ b/sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/PlatformFilesystem.java
@@ -1,29 +1,9 @@
 package net.lax1dude.eaglercraft.v1_8.internal;
 
-import org.teavm.interop.Async;
-import org.teavm.interop.AsyncCallback;
-import org.teavm.jso.JSBody;
-import org.teavm.jso.JSObject;
-import org.teavm.jso.dom.events.EventListener;
-import org.teavm.jso.indexeddb.EventHandler;
-import org.teavm.jso.indexeddb.IDBCountRequest;
-import org.teavm.jso.indexeddb.IDBCursor;
-import org.teavm.jso.indexeddb.IDBCursorRequest;
-import org.teavm.jso.indexeddb.IDBDatabase;
-import org.teavm.jso.indexeddb.IDBFactory;
-import org.teavm.jso.indexeddb.IDBGetRequest;
-import org.teavm.jso.indexeddb.IDBObjectStoreParameters;
-import org.teavm.jso.indexeddb.IDBOpenDBRequest;
-import org.teavm.jso.indexeddb.IDBRequest;
-import org.teavm.jso.indexeddb.IDBTransaction;
-import org.teavm.jso.indexeddb.IDBVersionChangeEvent;
-import org.teavm.jso.typedarrays.ArrayBuffer;
-import org.teavm.jso.typedarrays.Int8Array;
-
-import net.lax1dude.eaglercraft.v1_8.internal.buffer.ByteBuffer;
-import net.lax1dude.eaglercraft.v1_8.internal.buffer.EaglerArrayBufferAllocator;
-import net.lax1dude.eaglercraft.v1_8.internal.teavm.BooleanResult;
-import net.lax1dude.eaglercraft.v1_8.internal.vfs2.VFSIterator2;
+import net.lax1dude.eaglercraft.v1_8.internal.teavm.IndexedDBFilesystem;
+import net.lax1dude.eaglercraft.v1_8.internal.vfs2.EaglerFileSystemException;
+import net.lax1dude.eaglercraft.v1_8.log4j.LogManager;
+import net.lax1dude.eaglercraft.v1_8.log4j.Logger;
 
 /**
  * Copyright (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved.
@@ -42,311 +22,28 @@ import net.lax1dude.eaglercraft.v1_8.internal.vfs2.VFSIterator2;
  */
 public class PlatformFilesystem {
 
-	private static String filesystemDB = null;
-	private static IDBDatabase database = null;
+	private static final Logger logger = LogManager.getLogger("PlatformFilesystem");
 
-	public static void initialize(String dbName) {
-		filesystemDB = "_net_lax1dude_eaglercraft_v1_8_internal_PlatformFilesystem_1_8_8_" + dbName;
-		DatabaseOpen dbOpen = AsyncHandlers.openDB(filesystemDB);
-		
-		if(dbOpen.failedLocked) {
-			throw new FilesystemDatabaseLockedException(dbOpen.failedError);
+	public static IEaglerFilesystem initializePersist(String dbName) {
+		try {
+			return IndexedDBFilesystem.createFilesystem(dbName);
+		}catch(Throwable t) {
+			logger.error("Could not open IndexedDB filesystem: {}", dbName);
+			logger.error(t);
+			return null;
 		}
-		
-		if(dbOpen.failedInit) {
-			throw new FilesystemDatabaseInitializationException(dbOpen.failedError);
-		}
-		
-		if(dbOpen.database == null) {
-			throw new NullPointerException("IDBDatabase is null!");
-		}
-		
-		database = dbOpen.database;
 	}
 
-	public static class FilesystemDatabaseLockedException extends RuntimeException {
+	public static class FilesystemDatabaseLockedException extends EaglerFileSystemException {
 		public FilesystemDatabaseLockedException(String message) {
 			super(message);
 		}
 	}
 
-	public static class FilesystemDatabaseInitializationException extends RuntimeException {
+	public static class FilesystemDatabaseInitializationException extends EaglerFileSystemException {
 		public FilesystemDatabaseInitializationException(String message) {
 			super(message);
 		}
 	}
 
-	public static boolean eaglerDelete(String pathName) {
-		return AsyncHandlers.deleteFile(database, pathName).bool;
-	}
-
-	public static ByteBuffer eaglerRead(String pathName) {
-		ArrayBuffer ar = AsyncHandlers.readWholeFile(database, pathName);
-		if(ar == null) {
-			return null;
-		}
-		return EaglerArrayBufferAllocator.wrapByteBufferTeaVM(Int8Array.create(ar));
-	}
-
-	public static void eaglerWrite(String pathName, ByteBuffer data) {
-		if(!AsyncHandlers.writeWholeFile(database, pathName, EaglerArrayBufferAllocator.getDataView8Unsigned(data).getBuffer()).bool) {
-			throw new RuntimeException("Failed to write " + data.remaining() + " byte file to indexeddb table: " + pathName);
-		}
-	}
-
-	public static boolean eaglerExists(String pathName) {
-		return AsyncHandlers.fileExists(database, pathName).bool;
-	}
-
-	public static boolean eaglerMove(String pathNameOld, String pathNameNew) {
-		ArrayBuffer old = AsyncHandlers.readWholeFile(database, pathNameOld);
-		return old != null && AsyncHandlers.writeWholeFile(database, pathNameNew, old).bool && AsyncHandlers.deleteFile(database, pathNameOld).bool;
-	}
-
-	public static int eaglerCopy(String pathNameOld, String pathNameNew) {
-		ArrayBuffer old = AsyncHandlers.readWholeFile(database, pathNameOld);
-		if(old != null && AsyncHandlers.writeWholeFile(database, pathNameNew, old).bool) {
-			return old.getByteLength();
-		}else {
-			return -1;
-		}
-	}
-
-	public static int eaglerSize(String pathName) {
-		ArrayBuffer old = AsyncHandlers.readWholeFile(database, pathName);
-		return old == null ? -1 : old.getByteLength();
-	}
-
-	private static class VFSFilenameIteratorNonRecursive implements VFSFilenameIterator {
-
-		private final VFSFilenameIterator child;
-		private final int pathCount;
-
-		private VFSFilenameIteratorNonRecursive(VFSFilenameIterator child, int pathCount) {
-			this.child = child;
-			this.pathCount = pathCount;
-		}
-
-		@Override
-		public void next(String entry) {
-			if(countSlashes(entry) == pathCount) {
-				child.next(entry);
-			}
-		}
-
-	}
-
-	private static int countSlashes(String str) {
-		int j = 0;
-		for(int i = 0, l = str.length(); i < l; ++i) {
-			if(str.charAt(i) == '/') {
-				++j;
-			}
-		}
-		return j;
-	}
-
-	public static void eaglerIterate(String pathName, VFSFilenameIterator itr, boolean recursive) {
-		if(recursive) {
-			AsyncHandlers.iterateFiles(database, pathName, false, itr);
-		}else {
-			AsyncHandlers.iterateFiles(database, pathName, false, new VFSFilenameIteratorNonRecursive(itr, countSlashes(pathName) + 1));
-		}
-	}
-
-	protected static class DatabaseOpen {
-		
-		protected final boolean failedInit;
-		protected final boolean failedLocked;
-		protected final String failedError;
-		
-		protected final IDBDatabase database;
-		
-		protected DatabaseOpen(boolean init, boolean locked, String error, IDBDatabase db) {
-			failedInit = init;
-			failedLocked = locked;
-			failedError = error;
-			database = db;
-		}
-		
-	}
-
-	@JSBody(script = "return ((typeof indexedDB) !== 'undefined') ? indexedDB : null;")
-	protected static native IDBFactory createIDBFactory();
-	
-	protected static class AsyncHandlers {
-		
-		@Async
-		protected static native DatabaseOpen openDB(String name);
-		
-		private static void openDB(String name, final AsyncCallback<DatabaseOpen> cb) {
-			IDBFactory i = createIDBFactory();
-			if(i == null) {
-				cb.complete(new DatabaseOpen(false, false, "window.indexedDB was null or undefined", null));
-				return;
-			}
-			final IDBOpenDBRequest f = i.open(name, 1);
-			f.setOnBlocked(new EventHandler() {
-				@Override
-				public void handleEvent() {
-					cb.complete(new DatabaseOpen(false, true, null, null));
-				}
-			});
-			f.setOnSuccess(new EventHandler() {
-				@Override
-				public void handleEvent() {
-					cb.complete(new DatabaseOpen(false, false, null, f.getResult()));
-				}
-			});
-			f.setOnError(new EventHandler() {
-				@Override
-				public void handleEvent() {
-					cb.complete(new DatabaseOpen(false, false, "open error", null));
-				}
-			});
-			f.setOnUpgradeNeeded(new EventListener<IDBVersionChangeEvent>() {
-				@Override
-				public void handleEvent(IDBVersionChangeEvent evt) {
-					f.getResult().createObjectStore("filesystem", IDBObjectStoreParameters.create().keyPath("path"));
-				}
-			});
-		}
-		
-		@Async
-		protected static native BooleanResult deleteFile(IDBDatabase db, String name);
-		
-		private static void deleteFile(IDBDatabase db, String name, final AsyncCallback<BooleanResult> cb) {
-			IDBTransaction tx = db.transaction("filesystem", "readwrite");
-			final IDBRequest r = tx.objectStore("filesystem").delete(makeTheFuckingKeyWork(name));
-			
-			r.setOnSuccess(new EventHandler() {
-				@Override
-				public void handleEvent() {
-					cb.complete(BooleanResult.TRUE);
-				}
-			});
-			r.setOnError(new EventHandler() {
-				@Override
-				public void handleEvent() {
-					cb.complete(BooleanResult.FALSE);
-				}
-			});
-		}
-		
-		@JSBody(params = { "obj" }, script = "return (typeof obj === \"undefined\") ? null : ((typeof obj.data === \"undefined\") ? null : obj.data);")
-		protected static native ArrayBuffer readRow(JSObject obj);
-		
-		@JSBody(params = { "obj" }, script = "return [obj];")
-		private static native JSObject makeTheFuckingKeyWork(String k);
-		
-		@Async
-		protected static native ArrayBuffer readWholeFile(IDBDatabase db, String name);
-		
-		private static void readWholeFile(IDBDatabase db, String name, final AsyncCallback<ArrayBuffer> cb) {
-			IDBTransaction tx = db.transaction("filesystem", "readonly");
-			final IDBGetRequest r = tx.objectStore("filesystem").get(makeTheFuckingKeyWork(name));
-			r.setOnSuccess(new EventHandler() {
-				@Override
-				public void handleEvent() {
-					cb.complete(readRow(r.getResult()));
-				}
-			});
-			r.setOnError(new EventHandler() {
-				@Override
-				public void handleEvent() {
-					cb.complete(null);
-				}
-			});
-			
-		}
-		
-		@JSBody(params = { "k" }, script = "return ((typeof k) === \"string\") ? k : (((typeof k) === \"undefined\") ? null : (((typeof k[0]) === \"string\") ? k[0] : null));")
-		private static native String readKey(JSObject k);
-		
-		@JSBody(params = { "k" }, script = "return ((typeof k) === \"undefined\") ? null : (((typeof k.path) === \"undefined\") ? null : (((typeof k.path) === \"string\") ? k[0] : null));")
-		private static native String readRowKey(JSObject r);
-		
-		@Async
-		protected static native Integer iterateFiles(IDBDatabase db, final String prefix, boolean rw, final VFSFilenameIterator itr);
-		
-		private static void iterateFiles(IDBDatabase db, final String prefix, boolean rw, final VFSFilenameIterator itr, final AsyncCallback<Integer> cb) {
-			IDBTransaction tx = db.transaction("filesystem", rw ? "readwrite" : "readonly");
-			final IDBCursorRequest r = tx.objectStore("filesystem").openCursor();
-			final int[] res = new int[1];
-			r.setOnSuccess(new EventHandler() {
-				@Override
-				public void handleEvent() {
-					IDBCursor c = r.getResult();
-					if(c == null || c.getKey() == null || c.getValue() == null) {
-						cb.complete(res[0]);
-						return;
-					}
-					String k = readKey(c.getKey());
-					if(k != null) {
-						if(k.startsWith(prefix)) {
-							int ci = res[0]++;
-							try {
-								itr.next(k);
-							}catch(VFSIterator2.BreakLoop ex) {
-								cb.complete(res[0]);
-								return;
-							}
-						}
-					}
-					c.doContinue();
-				}
-			});
-			r.setOnError(new EventHandler() {
-				@Override
-				public void handleEvent() {
-					cb.complete(res[0] > 0 ? res[0] : -1);
-				}
-			});
-		}
-		
-		@Async
-		protected static native BooleanResult fileExists(IDBDatabase db, String name);
-		
-		private static void fileExists(IDBDatabase db, String name, final AsyncCallback<BooleanResult> cb) {
-			IDBTransaction tx = db.transaction("filesystem", "readonly");
-			final IDBCountRequest r = tx.objectStore("filesystem").count(makeTheFuckingKeyWork(name));
-			r.setOnSuccess(new EventHandler() {
-				@Override
-				public void handleEvent() {
-					cb.complete(BooleanResult._new(r.getResult() > 0));
-				}
-			});
-			r.setOnError(new EventHandler() {
-				@Override
-				public void handleEvent() {
-					cb.complete(BooleanResult.FALSE);
-				}
-			});
-		}
-		
-		@JSBody(params = { "pat", "dat" }, script = "return { path: pat, data: dat };")
-		protected static native JSObject writeRow(String name, ArrayBuffer data);
-		
-		@Async
-		protected static native BooleanResult writeWholeFile(IDBDatabase db, String name, ArrayBuffer data);
-		
-		private static void writeWholeFile(IDBDatabase db, String name, ArrayBuffer data, final AsyncCallback<BooleanResult> cb) {
-			IDBTransaction tx = db.transaction("filesystem", "readwrite");
-			final IDBRequest r = tx.objectStore("filesystem").put(writeRow(name, data));
-			
-			r.setOnSuccess(new EventHandler() {
-				@Override
-				public void handleEvent() {
-					cb.complete(BooleanResult.TRUE);
-				}
-			});
-			r.setOnError(new EventHandler() {
-				@Override
-				public void handleEvent() {
-					cb.complete(BooleanResult.FALSE);
-				}
-			});
-		}
-		
-	}
 }
diff --git a/sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/PlatformInput.java b/sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/PlatformInput.java
index 3bdb3803..cdff2098 100644
--- a/sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/PlatformInput.java
+++ b/sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/PlatformInput.java
@@ -1,34 +1,53 @@
 package net.lax1dude.eaglercraft.v1_8.internal;
 
+import java.util.ArrayList;
+import java.util.HashMap;
 import java.util.LinkedList;
 import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
 
 import net.lax1dude.eaglercraft.v1_8.internal.teavm.TeaVMUtils;
+import net.lax1dude.eaglercraft.v1_8.internal.teavm.Touch;
+import net.lax1dude.eaglercraft.v1_8.internal.teavm.TouchEvent;
+import net.lax1dude.eaglercraft.v1_8.internal.teavm.VisualViewport;
 
 import org.teavm.interop.Async;
 import org.teavm.interop.AsyncCallback;
 import org.teavm.jso.JSBody;
+import org.teavm.jso.JSFunctor;
 import org.teavm.jso.JSObject;
+import org.teavm.jso.browser.Navigator;
 import org.teavm.jso.browser.TimerHandler;
 import org.teavm.jso.browser.Window;
+import org.teavm.jso.core.JSNumber;
+import org.teavm.jso.dom.css.CSSStyleDeclaration;
 import org.teavm.jso.dom.events.Event;
 import org.teavm.jso.dom.events.EventListener;
 import org.teavm.jso.dom.events.KeyboardEvent;
 import org.teavm.jso.dom.events.MouseEvent;
 import org.teavm.jso.dom.events.WheelEvent;
 import org.teavm.jso.dom.html.HTMLCanvasElement;
+import org.teavm.jso.dom.html.HTMLDocument;
 import org.teavm.jso.dom.html.HTMLElement;
-import org.teavm.jso.webgl.WebGLFramebuffer;
-import org.teavm.jso.webgl.WebGLRenderbuffer;
+import org.teavm.jso.dom.html.HTMLFormElement;
+import org.teavm.jso.dom.html.HTMLInputElement;
+import org.teavm.jso.dom.html.TextRectangle;
+import org.teavm.jso.gamepad.Gamepad;
+import org.teavm.jso.gamepad.GamepadButton;
+import org.teavm.jso.gamepad.GamepadEvent;
 
 import net.lax1dude.eaglercraft.v1_8.EagUtils;
+import net.lax1dude.eaglercraft.v1_8.internal.teavm.ClientMain;
 import net.lax1dude.eaglercraft.v1_8.internal.teavm.EarlyLoadScreen;
-import net.lax1dude.eaglercraft.v1_8.internal.teavm.WebGL2RenderingContext;
-
-import static net.lax1dude.eaglercraft.v1_8.internal.teavm.WebGL2RenderingContext.*;
+import net.lax1dude.eaglercraft.v1_8.internal.teavm.InputEvent;
+import net.lax1dude.eaglercraft.v1_8.internal.teavm.LegacyKeycodeTranslator;
+import net.lax1dude.eaglercraft.v1_8.internal.teavm.OffsetTouch;
+import net.lax1dude.eaglercraft.v1_8.internal.teavm.SortedTouchEvent;
+import net.lax1dude.eaglercraft.v1_8.internal.teavm.WebGLBackBuffer;
 
 /**
- * Copyright (c) 2022-2023 lax1dude, ayunami2000. All Rights Reserved.
+ * Copyright (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved.
  * 
  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
@@ -45,75 +64,257 @@ import static net.lax1dude.eaglercraft.v1_8.internal.teavm.WebGL2RenderingContex
 public class PlatformInput {
 
 	private static Window win = null;
+	private static HTMLElement parent = null;
 	private static HTMLCanvasElement canvas = null;
-	static WebGL2RenderingContext context = null;
+	private static HTMLElement touchKeyboardOpenZone = null;
+	private static int touchOpenZoneX = 0;
+	private static int touchOpenZoneY = 0;
+	private static int touchOpenZoneW = 0;
+	private static int touchOpenZoneH = 0;
+	private static HTMLFormElement touchKeyboardForm = null;
+	private static HTMLInputElement touchKeyboardField = null;
+	private static boolean shownTouchKeyboardEventWarning = false;
+	private static boolean shownLegacyTouchKeyboardWarning = false;
+	private static boolean showniOSReturnTouchKeyboardWarning = false;
+	private static double lastTouchKeyboardEvtA = 0.0;
+	private static double lastTouchKeyboardEvtB = 0.0;
+	private static double lastTouchKeyboardEvtC = 0.0;
 
-	static WebGLFramebuffer mainFramebuffer = null;
-	static WebGLRenderbuffer mainColorRenderbuffer = null;
-	static WebGLRenderbuffer mainDepthRenderbuffer = null;
-	private static int framebufferWidth = -1;
-	private static int framebufferHeight = -1;
-	
-	private static EventListener contextmenu = null;
-	private static EventListener mousedown = null;
-	private static EventListener mouseup = null;
-	private static EventListener mousemove = null;
-	private static EventListener mouseenter = null;
-	private static EventListener mouseleave = null;
-	private static EventListener keydown = null;
-	private static EventListener keyup = null;
-	private static EventListener keypress = null;
-	private static EventListener wheel = null;
-	private static EventListener pointerlock = null;
+	private static EventListener<?> contextmenu = null;
+	private static EventListener<?> mousedown = null;
+	private static EventListener<?> mouseup = null;
+	private static EventListener<?> mousemove = null;
+	private static EventListener<?> mouseenter = null;
+	private static EventListener<?> mouseleave = null;
+	private static EventListener<?> touchstart = null;
+	private static EventListener<?> touchend = null;
+	private static EventListener<?> touchmove = null;
+	private static EventListener<?> touchcancel = null;
+	private static EventListener<?> gamepadconnected = null;
+	private static EventListener<?> gamepaddisconnected = null;
+	private static EventListener<?> keydown = null;
+	private static EventListener<?> keyup = null;
+	private static EventListener<?> touchKeyboardOpenZone_touchstart = null;
+	private static EventListener<?> touchKeyboardOpenZone_touchend = null;
+	private static EventListener<?> touchKeyboardOpenZone_touchmove = null;
+	private static EventListener<?> wheel = null;
+	private static EventListener<?> focus = null;
+	private static EventListener<?> blur = null;
+	private static EventListener<?> pointerlock = null;
 
-	private static List<MouseEvent> mouseEvents = new LinkedList();
-	private static List<KeyboardEvent> keyEvents = new LinkedList();
+	private static Map<String,LegacyKeycodeTranslator.LegacyKeycode> keyCodeTranslatorMap = null;
+
+	public static Map<String,LegacyKeycodeTranslator.LegacyKeycode> getKeyCodeTranslatorMapTeaVM() {
+		return keyCodeTranslatorMap;
+	}
+
+	private static final List<String> pastedStrings = new LinkedList<>();
+
+	private static final int EVENT_KEY_DOWN = 0;
+	private static final int EVENT_KEY_UP = 1;
+	private static final int EVENT_KEY_REPEAT = 2;
+
+	private static class VKeyEvent {
+
+		private final int keyCode;
+		private final int location;
+		private final int eagKey;
+		private final char keyChar;
+		private final int type;
+
+		private VKeyEvent(int keyCode, int location, int eagKey, char keyChar, int type) {
+			this.keyCode = keyCode;
+			this.location = location;
+			this.eagKey = eagKey;
+			this.keyChar = keyChar;
+			this.type = type;
+		}
+
+	}
+
+	private static final int EVENT_MOUSE_DOWN = 0;
+	private static final int EVENT_MOUSE_UP = 1;
+	private static final int EVENT_MOUSE_MOVE = 2;
+	private static final int EVENT_MOUSE_WHEEL = 3;
+
+	private static class VMouseEvent {
+
+		private final int posX;
+		private final int posY;
+		private final int button;
+		private final float wheel;
+		private final int type;
+
+		private VMouseEvent(int posX, int posY, int button, float wheel, int type) {
+			this.posX = posX;
+			this.posY = posY;
+			this.button = button;
+			this.wheel = wheel;
+			this.type = type;
+		}
+
+	}
+
+	private static final List<VMouseEvent> mouseEvents = new LinkedList<>();
+	private static final List<VKeyEvent> keyEvents = new LinkedList<>();
+	private static final List<SortedTouchEvent> touchEvents = new LinkedList<>();
+
+	private static boolean hasShownPressAnyKey = false;
+	private static boolean isOnMobilePressAnyKey = false;
+
+	private static interface MobilePressAnyKeyHandler {
+		void call(boolean enterBootMenu);
+	}
+
+	private static HTMLElement mobilePressAnyKeyScreen = null;
+	private static MobilePressAnyKeyHandler mobilePressAnyKey = null;
+	static boolean isLikelyMobileBrowser = false;
 
 	private static int mouseX = 0;
 	private static int mouseY = 0;
 	private static double mouseDX = 0.0D;
 	private static double mouseDY = 0.0D;
 	private static double mouseDWheel = 0.0D;
-	private static int width = 0;
-	private static int height = 0;
 	private static boolean enableRepeatEvents = true;
 	private static boolean isWindowFocused = true;
 	private static boolean isMouseOverWindow = true;
 	static boolean unpressCTRL = false;
 
+	private static SortedTouchEvent currentTouchState = null;
+	private static SortedTouchEvent currentTouchEvent = null;
+
+	public static int touchOffsetXTeaVM = 0;
+	public static int touchOffsetYTeaVM = 0;
+
+	private static boolean gamepadSupported = false;
+	private static final List<Gamepad> gamepadList = new ArrayList<>();
+	private static Gamepad selectedGamepad = null;
+	private static String selectedGamepadName = null;
+	private static double gamepadTimestamp = -1.0;
+	private static final boolean[] gamepadButtonStates = new boolean[24];
+	private static final float[] gamepadAxisStates = new float[4];
+
 	private static int windowWidth = -1;
 	private static int windowHeight = -1;
+	private static float windowDPI = 1.0f;
+	private static int visualViewportX = -1;
+	private static int visualViewportY = -1;
+	private static int visualViewportW = -1;
+	private static int visualViewportH = -1;
 	private static int lastWasResizedWindowWidth = -2;
 	private static int lastWasResizedWindowHeight = -2;
-	
-	private static MouseEvent currentEvent = null;
-	private static KeyboardEvent currentEventK = null;
+	private static float lastWasResizedWindowDPI = -2.0f;
+	private static int lastWasResizedVisualViewportX = -2;
+	private static int lastWasResizedVisualViewportY = -2;
+	private static int lastWasResizedVisualViewportW = -2;
+	private static int lastWasResizedVisualViewportH = -2;
+
+	private static VMouseEvent currentEvent = null;
+	private static VKeyEvent currentEventK = null;
 	private static boolean[] buttonStates = new boolean[8];
 	private static boolean[] keyStates = new boolean[256];
 
 	private static int functionKeyModifier = KeyboardConstants.KEY_F;
 
+	// Can't support webkit vendor prefix since there's no document.pointerLockElement
+	private static final int POINTER_LOCK_NONE = 0;
+	private static final int POINTER_LOCK_CORE = 1;
+	private static final int POINTER_LOCK_MOZ = 2;
+	private static int pointerLockSupported = POINTER_LOCK_NONE;
 	private static long mouseUngrabTimer = 0l;
 	private static long mouseGrabTimer = 0l;
 	private static int mouseUngrabTimeout = -1;
 	private static boolean pointerLockFlag = false;
 
+	private static final int FULLSCREEN_NONE = 0;
+	private static final int FULLSCREEN_CORE = 1;
+	private static final int FULLSCREEN_WEBKIT = 2;
+	private static final int FULLSCREEN_MOZ = 3;
+	private static int fullscreenSupported = FULLSCREEN_NONE;
+
 	private static JSObject fullscreenQuery = null;
 
 	public static boolean keyboardLockSupported = false;
 	public static boolean lockKeys = false;
 
-	private static boolean vsync = true;
-	private static boolean vsyncSupport = false;
+	static boolean vsync = true;
+	static boolean vsyncSupport = false;
+
+	private static long vsyncWaiting = -1l;
+	private static AsyncCallback<Void> vsyncAsyncCallback = null;
+	private static int vsyncTimeout = -1;
 	
-	@JSBody(params = { }, script = "window.onbeforeunload = () => {return false;};")
-	private static native void onBeforeCloseRegister();
-	
-	static void initHooks(Window window, HTMLCanvasElement canvaz) {
+	// hack to fix occasional freeze on iOS
+	private static int vsyncSaveLockInterval = -1;
+
+	@JSFunctor
+	private static interface UnloadCallback extends JSObject {
+		void call();
+	}
+
+	@JSBody(params = { "win", "cb" }, script = "win.__curEaglerX188UnloadListenerCB = cb; if((typeof win.__isEaglerX188UnloadListenerSet === \"string\") && win.__isEaglerX188UnloadListenerSet === \"yes\") return; win.onbeforeunload = function(evt) { if(win.__curEaglerX188UnloadListenerCB) win.__curEaglerX188UnloadListenerCB(); return false; }; win.__isEaglerX188UnloadListenerSet = \"yes\";")
+	private static native void onBeforeCloseRegister(Window win, UnloadCallback cb);
+
+	static void initHooks(Window window, HTMLElement parent_, HTMLCanvasElement canvaz) {
 		win = window;
+		parent = parent_;
 		canvas = canvaz;
 		canvas.getStyle().setProperty("cursor", "default");
-		win.addEventListener("contextmenu", contextmenu = new EventListener<MouseEvent>() {
+		updateTouchOffset();
+		lastWasResizedWindowWidth = -2;
+		lastWasResizedWindowHeight = -2;
+		lastWasResizedWindowDPI = -2.0f;
+		lastWasResizedVisualViewportX = -2;
+		lastWasResizedVisualViewportY = -2;
+		lastWasResizedVisualViewportW = -2;
+		lastWasResizedVisualViewportH = -2;
+		hasShownPressAnyKey = false;
+		touchOpenZoneX = 0;
+		touchOpenZoneY = 0;
+		touchOpenZoneW = 0;
+		touchOpenZoneH = 0;
+		touchKeyboardForm = null;
+		touchKeyboardField = null;
+		shownLegacyTouchKeyboardWarning = false;
+		shownTouchKeyboardEventWarning = false;
+		showniOSReturnTouchKeyboardWarning = false;
+		lastTouchKeyboardEvtA = 0.0;
+		lastTouchKeyboardEvtB = 0.0;
+		lastTouchKeyboardEvtC = 0.0;
+		touchKeyboardOpenZone = win.getDocument().createElement("div");
+		touchKeyboardOpenZone.getClassList().add("_eaglercraftX_keyboard_open_zone");
+		CSSStyleDeclaration decl = touchKeyboardOpenZone.getStyle();
+		decl.setProperty("display", "none");
+		decl.setProperty("position", "absolute");
+		decl.setProperty("background-color", "transparent");
+		decl.setProperty("top", "0px");
+		decl.setProperty("left", "0px");
+		decl.setProperty("width", "0px");
+		decl.setProperty("height", "0px");
+		decl.setProperty("z-index", "100");
+		decl.setProperty("touch-action", "pan-x pan-y");
+		decl.setProperty("-webkit-touch-callout", "none");
+		decl.setProperty("-webkit-tap-highlight-color", "rgba(255, 255, 255, 0)");
+		parent.appendChild(touchKeyboardOpenZone);
+		
+		PlatformRuntime.logger.info("Loading keyboard layout data");
+		
+		LegacyKeycodeTranslator keycodeTranslator = new LegacyKeycodeTranslator();
+		if(checkKeyboardLayoutSupported()) {
+			try {
+				iterateKeyboardLayout(keycodeTranslator::addBrowserLayoutMapping);
+			}catch(Throwable t) {
+				PlatformRuntime.logger.error("Caught exception querying keyboard layout from browser, using the default layout instead");
+				PlatformRuntime.logger.error(t);
+			}
+			int cnt = keycodeTranslator.getRemappedKeyCount();
+			if(cnt > 0) {
+				PlatformRuntime.logger.info("KeyboardLayoutMap remapped {} keys from their default codes", cnt);
+			}
+		}
+		keyCodeTranslatorMap = keycodeTranslator.buildLayoutTable();
+		
+		parent.addEventListener("contextmenu", contextmenu = new EventListener<MouseEvent>() {
 			@Override
 			public void handleEvent(MouseEvent evt) {
 				evt.preventDefault();
@@ -125,9 +326,18 @@ public class PlatformInput {
 			public void handleEvent(MouseEvent evt) {
 				evt.preventDefault();
 				evt.stopPropagation();
+				if(tryGrabCursorHook()) return;
 				int b = evt.getButton();
-				buttonStates[b == 1 ? 2 : (b == 2 ? 1 : b)] = true;
-				mouseEvents.add(evt);
+				b = b == 1 ? 2 : (b == 2 ? 1 : b);
+				buttonStates[b] = true;
+				int eventX = (int)(getOffsetX(evt) * windowDPI);
+				int eventY = windowHeight - (int)(getOffsetY(evt) * windowDPI) - 1;
+				synchronized(mouseEvents) {
+					mouseEvents.add(new VMouseEvent(eventX, eventY, b, 0.0f, EVENT_MOUSE_DOWN));
+					if(mouseEvents.size() > 64) {
+						mouseEvents.remove(0);
+					}
+				}
 			}
 		});
 		canvas.addEventListener("mouseup", mouseup = new EventListener<MouseEvent>() {
@@ -136,8 +346,16 @@ public class PlatformInput {
 				evt.preventDefault();
 				evt.stopPropagation();
 				int b = evt.getButton();
-				buttonStates[b == 1 ? 2 : (b == 2 ? 1 : b)] = false;
-				mouseEvents.add(evt);
+				b = b == 1 ? 2 : (b == 2 ? 1 : b);
+				buttonStates[b] = false;
+				int eventX = (int)(getOffsetX(evt) * windowDPI);
+				int eventY = windowHeight - (int)(getOffsetY(evt) * windowDPI) - 1;
+				synchronized(mouseEvents) {
+					mouseEvents.add(new VMouseEvent(eventX, eventY, b, 0.0f, EVENT_MOUSE_UP));
+					if(mouseEvents.size() > 64) {
+						mouseEvents.remove(0);
+					}
+				}
 			}
 		});
 		canvas.addEventListener("mousemove", mousemove = new EventListener<MouseEvent>() {
@@ -145,12 +363,19 @@ public class PlatformInput {
 			public void handleEvent(MouseEvent evt) {
 				evt.preventDefault();
 				evt.stopPropagation();
-				mouseX = (int)(getOffsetX(evt) * win.getDevicePixelRatio());
-				mouseY = (int)((canvas.getClientHeight() - getOffsetY(evt)) * win.getDevicePixelRatio());
+				mouseX = (int)(getOffsetX(evt) * windowDPI);
+				mouseY = windowHeight - (int)(getOffsetY(evt) * windowDPI) - 1;
 				mouseDX += evt.getMovementX();
 				mouseDY += -evt.getMovementY();
-				if(hasBeenActive()) {
-					mouseEvents.add(evt);
+				if(hasShownPressAnyKey) {
+					int eventX = (int)(getOffsetX(evt) * windowDPI);
+					int eventY = windowHeight - (int)(getOffsetY(evt) * windowDPI) - 1;
+					synchronized(mouseEvents) {
+						mouseEvents.add(new VMouseEvent(eventX, eventY, -1, 0.0f, EVENT_MOUSE_MOVE));
+						if(mouseEvents.size() > 64) {
+							mouseEvents.remove(0);
+						}
+					}
 				}
 			}
 		});
@@ -166,45 +391,205 @@ public class PlatformInput {
 				isMouseOverWindow = false;
 			}
 		});
+		canvas.addEventListener("touchstart", touchstart = new EventListener<TouchEvent>() {
+			@Override
+			public void handleEvent(TouchEvent evt) {
+				evt.preventDefault();
+				evt.stopPropagation();
+				SortedTouchEvent sorted = new SortedTouchEvent(evt, touchUIDMapperCreate);
+				currentTouchState = sorted;
+				List<OffsetTouch> lst = sorted.getEventTouches();
+				synchronized(touchEvents) {
+					touchEvents.add(sorted);
+					if(touchEvents.size() > 64) {
+						touchEvents.remove(0);
+					}
+				}
+				touchCloseDeviceKeyboard0(false);
+			}
+		});
+		canvas.addEventListener("touchend", touchend = new EventListener<TouchEvent>() {
+			@Override
+			public void handleEvent(TouchEvent evt) {
+				evt.preventDefault();
+				evt.stopPropagation();
+				SortedTouchEvent sorted = new SortedTouchEvent(evt, touchUIDMapper);
+				currentTouchState = sorted;
+				List<OffsetTouch> lst = sorted.getEventTouches();
+				int len = lst.size();
+				for (int i = 0; i < len; ++i) {
+					touchIDtoUID.remove(lst.get(i).touch.getIdentifier());
+				}
+				synchronized(touchEvents) {
+					touchEvents.add(sorted);
+					if(touchEvents.size() > 64) {
+						touchEvents.remove(0);
+					}
+				}
+			}
+		});
+		canvas.addEventListener("touchmove", touchmove = new EventListener<TouchEvent>() {
+			@Override
+			public void handleEvent(TouchEvent evt) {
+				evt.preventDefault();
+				evt.stopPropagation();
+				SortedTouchEvent sorted = new SortedTouchEvent(evt, touchUIDMapperCreate);
+				currentTouchState = sorted;
+				if(hasShownPressAnyKey) {
+					synchronized(touchEvents) {
+						touchEvents.add(sorted);
+						if(touchEvents.size() > 64) {
+							touchEvents.remove(0);
+						}
+					}
+				}
+			}
+		});
+		canvas.addEventListener("touchcancel", touchcancel = new EventListener<TouchEvent>() {
+			@Override
+			public void handleEvent(TouchEvent evt) {
+				SortedTouchEvent sorted = new SortedTouchEvent(evt, touchUIDMapper);
+				currentTouchState = sorted;
+				List<OffsetTouch> lst = sorted.getEventTouches();
+				int len = lst.size();
+				for (int i = 0; i < len; ++i) {
+					touchIDtoUID.remove(lst.get(i).touch.getIdentifier());
+				}
+				if(hasShownPressAnyKey) {
+					synchronized(touchEvents) {
+						touchEvents.add(sorted);
+						if(touchEvents.size() > 64) {
+							touchEvents.remove(0);
+						}
+					}
+				}
+			}
+		});
 		win.addEventListener("keydown", keydown = new EventListener<KeyboardEvent>() {
 			@Override
 			public void handleEvent(KeyboardEvent evt) {
-				int w = getWhich(evt);
-				if (w == 122) { // F11
-					toggleFullscreen();
-				}
 				evt.preventDefault();
 				evt.stopPropagation();
 				if(!enableRepeatEvents && evt.isRepeat()) return;
+				LegacyKeycodeTranslator.LegacyKeycode keyCode = null;
+				if(keyCodeTranslatorMap != null && hasCodeVar(evt)) {
+					keyCode = keyCodeTranslatorMap.get(evt.getCode());
+				}
+				int w;
+				int loc;
+				if(keyCode != null) {
+					w = keyCode.keyCode;
+					loc = keyCode.location;
+				}else {
+					w = getWhich(evt);
+					loc = getLocationSafe(evt);
+				}
+				if (w == 122 && !evt.isRepeat()) { // F11
+					toggleFullscreen();
+				}
 				int ww = processFunctionKeys(w);
-				keyStates[KeyboardConstants.getEaglerKeyFromBrowser(ww, ww == w ? evt.getLocation() : 0)] = true;
-				keyEvents.add(evt);
+				int eag = KeyboardConstants.getEaglerKeyFromBrowser(ww, ww == w ? loc : 0);
+				if(isOnMobilePressAnyKey && mobilePressAnyKey != null) {
+					if(eag == KeyboardConstants.KEY_DELETE) {
+						mobilePressAnyKey.call(true);
+						return;
+					}
+				}
+				if(eag != 0) {
+					keyStates[eag] = true;
+				}
+				String s = getCharOrNull(evt);
+				int l = s.length();
+				char c;
+				if(l == 1) {
+					c = s.charAt(0);
+				}else if(l == 0) {
+					c = keyToAsciiLegacy(w, evt.isShiftKey());
+				}else if(s.equals("Unidentified")) {
+					return;
+				}else {
+					c = '\0';
+				}
+				synchronized(keyEvents) {
+					keyEvents.add(new VKeyEvent(ww, loc, eag, c, EVENT_KEY_DOWN));
+					if(keyEvents.size() > 64) {
+						keyEvents.remove(0);
+					}
+				}
+				JSObject obj = evt.getTimeStamp();
+				if(TeaVMUtils.isTruthy(obj)) {
+					lastTouchKeyboardEvtA = ((JSNumber)obj).doubleValue();
+				}
 			}
 		});
 		win.addEventListener("keyup", keyup = new EventListener<KeyboardEvent>() {
 			@Override
 			public void handleEvent(KeyboardEvent evt) {
-				int w = getWhich(evt);
 				evt.preventDefault();
 				evt.stopPropagation();
-				if(!enableRepeatEvents && evt.isRepeat()) return;
+				LegacyKeycodeTranslator.LegacyKeycode keyCode = null;
+				if(keyCodeTranslatorMap != null && hasCodeVar(evt)) {
+					keyCode = keyCodeTranslatorMap.get(evt.getCode());
+				}
+				int w;
+				int loc;
+				if(keyCode != null) {
+					w = keyCode.keyCode;
+					loc = keyCode.location;
+				}else {
+					w = getWhich(evt);
+					loc = getLocationSafe(evt);
+				}
 				int ww = processFunctionKeys(w);
-				int eagKey = KeyboardConstants.getEaglerKeyFromBrowser(ww, ww == w ? evt.getLocation() : 0);
-				keyStates[eagKey] = false;
-				if(eagKey == functionKeyModifier) {
-					for(int key = KeyboardConstants.KEY_F1; key <= KeyboardConstants.KEY_F10; ++key) {
-						keyStates[key] = false;
+				int eag = KeyboardConstants.getEaglerKeyFromBrowser(ww, ww == w ? loc : 0);
+				if(eag != 0) {
+					keyStates[eag] = false;
+					if(eag == functionKeyModifier) {
+						for(int key = KeyboardConstants.KEY_F1; key <= KeyboardConstants.KEY_F10; ++key) {
+							keyStates[key] = false;
+						}
+					}
+				}
+				String s = getCharOrNull(evt);
+				int l = s.length();
+				char c;
+				if(l == 1) {
+					c = s.charAt(0);
+				}else if(l == 0) {
+					c = keyToAsciiLegacy(w, evt.isShiftKey());
+				}else if(s.equals("Unidentified")) {
+					return;
+				}else {
+					c = '\0';
+				}
+				synchronized(keyEvents) {
+					keyEvents.add(new VKeyEvent(ww, loc, eag, c, EVENT_KEY_UP));
+					if(keyEvents.size() > 64) {
+						keyEvents.remove(0);
 					}
 				}
-				keyEvents.add(evt);
 			}
 		});
-		win.addEventListener("keypress", keypress = new EventListener<KeyboardEvent>() {
+		touchKeyboardOpenZone.addEventListener("touchstart", touchKeyboardOpenZone_touchstart = new EventListener<TouchEvent>() {
 			@Override
-			public void handleEvent(KeyboardEvent evt) {
+			public void handleEvent(TouchEvent evt) {
+				evt.preventDefault();
+				evt.stopPropagation();
+			}
+		});
+		touchKeyboardOpenZone.addEventListener("touchend", touchKeyboardOpenZone_touchend = new EventListener<TouchEvent>() {
+			@Override
+			public void handleEvent(TouchEvent evt) {
+				evt.preventDefault();
+				evt.stopPropagation();
+				touchOpenDeviceKeyboard();
+			}
+		});
+		touchKeyboardOpenZone.addEventListener("touchmove", touchKeyboardOpenZone_touchmove = new EventListener<TouchEvent>() {
+			@Override
+			public void handleEvent(TouchEvent evt) {
 				evt.preventDefault();
 				evt.stopPropagation();
-				if(enableRepeatEvents && evt.isRepeat()) keyEvents.add(evt);
 			}
 		});
 		canvas.addEventListener("wheel", wheel = new EventListener<WheelEvent>() {
@@ -212,13 +597,23 @@ public class PlatformInput {
 			public void handleEvent(WheelEvent evt) {
 				evt.preventDefault();
 				evt.stopPropagation();
-				mouseEvents.add(evt);
-				mouseDWheel += evt.getDeltaY();
+				double delta = evt.getDeltaY();
+				mouseDWheel += delta;
+				if(hasShownPressAnyKey) {
+					int eventX = (int)(getOffsetX(evt) * windowDPI);
+					int eventY = windowHeight - (int)(getOffsetY(evt) * windowDPI) - 1;
+					synchronized(mouseEvents) {
+						mouseEvents.add(new VMouseEvent(eventX, eventY, -1, (float)delta, EVENT_MOUSE_WHEEL));
+						if(mouseEvents.size() > 64) {
+							mouseEvents.remove(0);
+						}
+					}
+				}
 			}
 		});
-		win.addEventListener("blur", new EventListener<WheelEvent>() {
+		win.addEventListener("blur", blur = new EventListener<Event>() {
 			@Override
-			public void handleEvent(WheelEvent evt) {
+			public void handleEvent(Event evt) {
 				isWindowFocused = false;
 				for(int i = 0; i < buttonStates.length; ++i) {
 					buttonStates[i] = false;
@@ -228,37 +623,94 @@ public class PlatformInput {
 				}
 			}
 		});
-		win.addEventListener("focus", new EventListener<WheelEvent>() {
+		win.addEventListener("focus", focus = new EventListener<Event>() {
 			@Override
-			public void handleEvent(WheelEvent evt) {
+			public void handleEvent(Event evt) {
 				isWindowFocused = true;
 			}
 		});
-		win.getDocument().addEventListener("pointerlockchange", pointerlock = new EventListener<WheelEvent>() {
-			@Override
-			public void handleEvent(WheelEvent evt) {
-				Window.setTimeout(new TimerHandler() {
-					@Override
-					public void onTimer() {
-						boolean grab = isPointerLocked();
-						if(!grab) {
-							if(pointerLockFlag) {
-								mouseUngrabTimer = System.currentTimeMillis();
+		
+		try {
+			pointerLockSupported = getSupportedPointerLock(win.getDocument());
+		}catch(Throwable t) {
+			pointerLockSupported = POINTER_LOCK_NONE;
+		}
+		if(pointerLockSupported != POINTER_LOCK_NONE) {
+			win.getDocument().addEventListener(pointerLockSupported == POINTER_LOCK_MOZ ? "mozpointerlockchange" : "pointerlockchange", pointerlock = new EventListener<Event>() {
+				@Override
+				public void handleEvent(Event evt) {
+					Window.setTimeout(new TimerHandler() {
+						@Override
+						public void onTimer() {
+							boolean grab = isPointerLocked();
+							if(!grab) {
+								if(pointerLockFlag) {
+									mouseUngrabTimer = PlatformRuntime.steadyTimeMillis();
+								}
 							}
+							pointerLockFlag = grab;
 						}
-						pointerLockFlag = grab;
-					}
-				}, 60);
-				mouseDX = 0.0D;
-				mouseDY = 0.0D;
+					}, 60);
+					mouseDX = 0.0D;
+					mouseDY = 0.0D;
+				}
+			});
+			if(pointerLockSupported == POINTER_LOCK_MOZ) {
+				PlatformRuntime.logger.info("Using moz- vendor prefix for pointer lock");
 			}
-		});
+		}else {
+			PlatformRuntime.logger.error("Pointer lock is not supported on this browser");
+		}
+
+		if(pointerLockSupported != POINTER_LOCK_NONE) {
+			String ua = PlatformRuntime.getUserAgentString();
+			if(ua != null) {
+				ua = ua.toLowerCase();
+				isLikelyMobileBrowser = ua.contains("mobi") || ua.contains("tablet");
+			}else {
+				isLikelyMobileBrowser = false;
+			}
+		}else {
+			isLikelyMobileBrowser = true;
+		}
 
 		try {
-			onBeforeCloseRegister();
+			fullscreenSupported = getSupportedFullScreen(win.getDocument());
+		}catch(Throwable t) {
+			fullscreenSupported = FULLSCREEN_NONE;
+		}
+		if(fullscreenSupported != FULLSCREEN_NONE) {
+			fullscreenQuery = fullscreenMediaQuery();
+			if(fullscreenSupported == FULLSCREEN_CORE && (keyboardLockSupported = checkKeyboardLockSupported())) {
+				TeaVMUtils.addEventListener(fullscreenQuery, "change", new EventListener<Event>() {
+					@Override
+					public void handleEvent(Event evt) {
+						if (!mediaQueryMatches(evt)) {
+							unlockKeys();
+							lockKeys = false;
+						}
+					}
+				});
+			}
+			if(pointerLockSupported == FULLSCREEN_WEBKIT) {
+				PlatformRuntime.logger.info("Using webkit- vendor prefix for fullscreen");
+			}else if(pointerLockSupported == FULLSCREEN_MOZ) {
+				PlatformRuntime.logger.info("Using moz- vendor prefix for fullscreen");
+			}
+		}else {
+			PlatformRuntime.logger.error("Fullscreen is not supported on this browser");
+		}
+
+		try {
+			onBeforeCloseRegister(window, () -> PlatformRuntime.beforeUnload());
 		}catch(Throwable t) {
 		}
 
+		vsyncWaiting = -1l;
+		vsyncAsyncCallback = null;
+		vsyncTimeout = -1;
+		vsyncSupport = false;
+
 		try {
 			asyncRequestAnimationFrame();
 			vsyncSupport = true;
@@ -266,22 +718,112 @@ public class PlatformInput {
 			PlatformRuntime.logger.error("VSync is not supported on this browser!");
 		}
 
-		fullscreenQuery = fullscreenMediaQuery();
-		if (keyboardLockSupported = checkKeyboardLockSupported()) {
-			TeaVMUtils.addEventListener(fullscreenQuery, "change", new EventListener<Event>() {
-				@Override
-				public void handleEvent(Event evt) {
-					if (!mediaQueryMatches(evt)) {
-						unlockKeys();
-						lockKeys = false;
+		if(vsyncSupport) {
+			if(vsyncSaveLockInterval != -1) {
+				try {
+					Window.clearInterval(vsyncSaveLockInterval);
+				}catch(Throwable t) {
+				}
+				vsyncSaveLockInterval = -1;
+			}
+			// fix for iOS freezing randomly...?
+			vsyncSaveLockInterval =  Window.setInterval(() -> {
+				if(vsyncWaiting != -1l) {
+					long steadyTime = PlatformRuntime.steadyTimeMillis();
+					if(steadyTime - vsyncWaiting > 1000) {
+						PlatformRuntime.logger.error("VSync lockup detected! Attempting to recover...");
+						vsyncWaiting = -1l;
+						if(vsyncTimeout != -1) {
+							try {
+								Window.clearTimeout(vsyncTimeout);
+							}catch(Throwable t) {
+							}
+							vsyncTimeout = -1;
+						}
+						if(vsyncAsyncCallback != null) {
+							AsyncCallback<Void> cb = vsyncAsyncCallback;
+							vsyncAsyncCallback = null;
+							cb.complete(null);
+						}else {
+							PlatformRuntime.logger.error("Async callback is null!");
+						}
 					}
 				}
-			});
+			}, 1000);
 		}
+
+		try {
+			gamepadSupported = gamepadSupported();
+			if(gamepadSupported) {
+				win.addEventListener("gamepadconnected", gamepadconnected = new EventListener<GamepadEvent>() {
+					@Override
+					public void handleEvent(GamepadEvent evt) {
+						enumerateGamepads();
+					}
+				});
+				win.addEventListener("gamepaddisconnected", gamepaddisconnected = new EventListener<GamepadEvent>() {
+					@Override
+					public void handleEvent(GamepadEvent evt) {
+						if(evt.getGamepad() == selectedGamepad) {
+							selectedGamepad = null;
+						}
+						enumerateGamepads();
+					}
+				});
+			}
+		}catch(Throwable t) {
+			gamepadSupported = false;
+			PlatformRuntime.logger.error("Gamepad detected as unsupported!");
+		}
+
+		enumerateGamepads();
 	}
 
-	@JSBody(params = { }, script = "if(window.navigator.userActivation){return window.navigator.userActivation.hasBeenActive;}else{return false;}")
-	public static native boolean hasBeenActive();
+	@JSFunctor
+	private static interface KeyboardLayoutIterator extends JSObject {
+		void call(String key, String val);
+	}
+
+	@JSFunctor
+	private static interface KeyboardLayoutDone extends JSObject {
+		void call();
+	}
+
+	@JSBody(params = { "cb", "cbDone" }, script = "return navigator.keyboard.getLayoutMap()"
+			+ ".then(function(layoutMap) { if(layoutMap && layoutMap.forEach) layoutMap.forEach(cb); cbDone(); })"
+			+ ".catch(function() { cbDone(); });")
+	private static native void iterateKeyboardLayout0(KeyboardLayoutIterator cb, KeyboardLayoutDone cbDone);
+
+	@Async
+	private static native void iterateKeyboardLayout(KeyboardLayoutIterator cb);
+
+	private static void iterateKeyboardLayout(KeyboardLayoutIterator cb, final AsyncCallback<Void> complete) {
+		iterateKeyboardLayout0(cb, () -> complete.complete(null));
+	}
+
+	@JSBody(params = { }, script = "return !!(navigator.keyboard && navigator.keyboard.getLayoutMap);")
+	private static native boolean checkKeyboardLayoutSupported();
+
+	@JSBody(params = { "doc" }, script = "return (typeof doc.exitPointerLock === \"function\") ? 1"
+			+ ": ((typeof doc.mozExitPointerLock === \"function\") ? 2 : -1);")
+	private static native int getSupportedPointerLock(HTMLDocument doc);
+
+	@JSBody(params = { "doc" }, script = "return (typeof doc.exitFullscreen === \"function\") ? 1"
+			+ ": ((typeof doc.webkitExitFullscreen === \"function\") ? 2"
+			+ ": ((typeof doc.mozExitFullscreen === \"function\") ? 3 : -1));")
+	private static native int getSupportedFullScreen(HTMLDocument doc);
+
+	@JSBody(params = { "evt" }, script = "return (typeof evt.key === \"string\");")
+	private static native boolean hasKeyVar(KeyboardEvent evt);
+
+	@JSBody(params = { "evt" }, script = "return (typeof evt.code === \"string\");")
+	private static native boolean hasCodeVar(KeyboardEvent evt);
+
+	@JSBody(params = { "evt" }, script = "return evt.keyIdentifier;")
+	private static native String getKeyIdentifier(KeyboardEvent evt);
+
+	@JSBody(params = { "fallback" }, script = "if(window.navigator.userActivation){return window.navigator.userActivation.hasBeenActive;}else{return fallback;}")
+	public static native boolean hasBeenActiveTeaVM(boolean fallback);
 	
 	@JSBody(params = { "m" }, script = "return m.offsetX;")
 	private static native int getOffsetX(MouseEvent m);
@@ -289,9 +831,15 @@ public class PlatformInput {
 	@JSBody(params = { "m" }, script = "return m.offsetY;")
 	private static native int getOffsetY(MouseEvent m);
 	
-	@JSBody(params = { "e" }, script = "return e.which;")
+	@JSBody(params = { "e" }, script = "return (typeof e.which === \"number\") ? e.which : ((typeof e.keyCode === \"number\") ? e.keyCode : 0);")
 	private static native int getWhich(KeyboardEvent e);
-	
+
+	@JSBody(params = { "e" }, script = "return (typeof e.location === \"number\") ? e.location : 0;")
+	private static native int getLocationSafe(KeyboardEvent e);
+
+	@JSBody(params = { "el", "i", "j" }, script = "el.setSelectionRange(el, i, j)")
+	private static native boolean setSelectionRange(HTMLElement el, int i, int j);
+
 	public static int getWindowWidth() {
 		return windowWidth;
 	}
@@ -300,6 +848,22 @@ public class PlatformInput {
 		return windowHeight;
 	}
 
+	public static int getVisualViewportX() {
+		return visualViewportX;
+	}
+
+	public static int getVisualViewportY() {
+		return visualViewportY;
+	}
+
+	public static int getVisualViewportW() {
+		return visualViewportW;
+	}
+
+	public static int getVisualViewportH() {
+		return visualViewportH;
+	}
+
 	public static boolean getWindowFocused() {
 		return isWindowFocused || isPointerLocked();
 	}
@@ -312,34 +876,67 @@ public class PlatformInput {
 		vsync = enable;
 	}
 
-	@JSBody(params = { "doc" }, script = "return (doc.visibilityState === \"visible\");")
+	@JSBody(params = { "doc" }, script = "return (typeof doc.visibilityState !== \"string\") || (doc.visibilityState === \"visible\");")
 	private static native boolean getVisibilityState(JSObject doc);
 
+	@JSBody(params = { "win" }, script = "return (typeof win.devicePixelRatio === \"number\") ? win.devicePixelRatio : 1.0;")
+	static native double getDevicePixelRatio(Window win);
+
 	public static void update() {
-		double r = win.getDevicePixelRatio();
-		int w = PlatformRuntime.parent.getClientWidth();
-		int h = PlatformRuntime.parent.getClientHeight();
+		double r = getDevicePixelRatio(win);
+		if(r < 0.01) r = 1.0;
+		windowDPI = (float)r;
+		updateTouchOffset();
+		int w = parent.getClientWidth();
+		int h = parent.getClientHeight();
 		int w2 = windowWidth = (int)(w * r);
 		int h2 = windowHeight = (int)(h * r);
+		if(PlatformRuntime.useVisualViewport) {
+			VisualViewport vv = PlatformRuntime.getVisualViewport();
+			double scale = vv.getScale();
+			visualViewportX = (int)(vv.getPageLeft() * r * scale);
+			visualViewportY = (int)(vv.getPageTop() * r * scale);
+			visualViewportW = (int)(vv.getWidth() * r * scale);
+			visualViewportH = (int)(vv.getHeight() * r * scale);
+			if(visualViewportW < 1) visualViewportW = 1;
+			if(visualViewportH < 1) visualViewportH = 1;
+			if(visualViewportX < 0) {
+				visualViewportW += visualViewportX;
+				visualViewportX = 0;
+			}else if(visualViewportX >= windowWidth) {
+				visualViewportX = windowWidth - 1;
+			}
+			if(visualViewportY < 0) {
+				visualViewportH += visualViewportY;
+				visualViewportY = 0;
+			}else if(visualViewportY >= windowHeight) {
+				visualViewportY = windowHeight - 1;
+			}
+			if((visualViewportX + visualViewportW) > windowWidth) {
+				visualViewportW = windowWidth - visualViewportX;
+			}
+			if((visualViewportY + visualViewportH) > windowHeight) {
+				visualViewportH = windowHeight - visualViewportY;
+			}
+		}else {
+			visualViewportX = 0;
+			visualViewportY = 0;
+			visualViewportW = w2;
+			visualViewportH = h2;
+		}
 		if(canvas.getWidth() != w2) {
 			canvas.setWidth(w2);
 		}
 		if(canvas.getHeight() != h2) {
 			canvas.setHeight(h2);
 		}
-		flipBuffer();
-		if (PlatformRuntime.recording) {
-			long t = System.currentTimeMillis();
-			if(t - PlatformRuntime.lastFrame > (1000 / 30)) {
-				PlatformRuntime.recFrame();
-				PlatformRuntime.lastFrame = t;
-			}
-		}
+		WebGLBackBuffer.flipBuffer(w2, h2);
+		PlatformScreenRecord.captureFrameHook();
 		if(getVisibilityState(win.getDocument())) {
 			if(vsyncSupport && vsync) {
 				asyncRequestAnimationFrame();
 			}else {
-				EagUtils.sleep(0l);
+				PlatformRuntime.swapDelayTeaVM();
 			}
 		}else {
 			EagUtils.sleep(50l);
@@ -350,19 +947,40 @@ public class PlatformInput {
 	private static native void asyncRequestAnimationFrame();
 
 	private static void asyncRequestAnimationFrame(AsyncCallback<Void> cb) {
-		final boolean[] hasCompleted = new boolean[1];
+		if(vsyncWaiting != -1l) {
+			cb.error(new IllegalStateException("Already waiting for vsync!"));
+			return;
+		}
+		vsyncWaiting = PlatformRuntime.steadyTimeMillis();
+		vsyncAsyncCallback = cb;
+		final boolean[] hasTimedOut = new boolean[] { false };
 		final int[] timeout = new int[] { -1 };
 		Window.requestAnimationFrame((d) -> {
-			if(!hasCompleted[0]) {
-				hasCompleted[0] = true;
-				Window.clearTimeout(timeout[0]);
-				cb.complete(null);
+			if(!hasTimedOut[0]) {
+				hasTimedOut[0] = true;
+				if(vsyncWaiting != -1l) {
+					vsyncWaiting = -1l;
+					if(vsyncTimeout != -1 && vsyncTimeout == timeout[0]) {
+						try {
+							Window.clearTimeout(vsyncTimeout);
+						}catch(Throwable t) {
+						}
+						vsyncTimeout = -1;
+					}
+					vsyncAsyncCallback = null;
+					cb.complete(null);
+				}
 			}
 		});
-		timeout[0] = Window.setTimeout(() -> {
-			if(!hasCompleted[0]) {
-				hasCompleted[0] = true;
-				cb.complete(null);
+		vsyncTimeout = timeout[0] = Window.setTimeout(() -> {
+			if(!hasTimedOut[0]) {
+				hasTimedOut[0] = true;
+				if(vsyncWaiting != -1l) {
+					vsyncTimeout = -1;
+					vsyncWaiting = -1l;
+					vsyncAsyncCallback = null;
+					cb.complete(null);
+				}
 			}
 		}, 50);
 	}
@@ -371,89 +989,173 @@ public class PlatformInput {
 		return vsyncSupport;
 	}
 
-	static void initFramebuffer(WebGL2RenderingContext ctx, WebGLFramebuffer fbo, int sw, int sh) {
-		context = ctx;
-		mainFramebuffer = fbo;
-		
-		framebufferWidth = windowWidth = sw;
-		framebufferHeight = windowHeight = sh;
-		
-		ctx.bindFramebuffer(FRAMEBUFFER, fbo);
-
-		mainColorRenderbuffer = ctx.createRenderbuffer();
-		mainDepthRenderbuffer = ctx.createRenderbuffer();
-		
-		ctx.bindRenderbuffer(RENDERBUFFER, mainColorRenderbuffer);
-		ctx.renderbufferStorage(RENDERBUFFER, RGBA8, sw, sh);
-		ctx.framebufferRenderbuffer(FRAMEBUFFER, COLOR_ATTACHMENT0, RENDERBUFFER, mainColorRenderbuffer);
-		
-		ctx.bindRenderbuffer(RENDERBUFFER, mainDepthRenderbuffer);
-		ctx.renderbufferStorage(RENDERBUFFER, DEPTH_COMPONENT32F, sw, sh);
-		ctx.framebufferRenderbuffer(FRAMEBUFFER, DEPTH_ATTACHMENT, RENDERBUFFER, mainDepthRenderbuffer);
-		
-		ctx.drawBuffers(new int[] { COLOR_ATTACHMENT0 });
-	}
-	
-	private static void flipBuffer() {
-		
-		context.bindFramebuffer(READ_FRAMEBUFFER, mainFramebuffer);
-		context.bindFramebuffer(DRAW_FRAMEBUFFER, null);
-		context.blitFramebuffer(0, 0, framebufferWidth, framebufferHeight, 0, 0, windowWidth, windowHeight, COLOR_BUFFER_BIT, NEAREST);
-		
-		context.bindFramebuffer(FRAMEBUFFER, mainFramebuffer);
-		
-		if(windowWidth != framebufferWidth || windowHeight != framebufferHeight) {
-			framebufferWidth = windowWidth;
-			framebufferHeight = windowHeight;
-			
-			context.bindRenderbuffer(RENDERBUFFER, mainColorRenderbuffer);
-			context.renderbufferStorage(RENDERBUFFER, RGBA8, framebufferWidth, framebufferHeight);
-			
-			context.bindRenderbuffer(RENDERBUFFER, mainDepthRenderbuffer);
-			context.renderbufferStorage(RENDERBUFFER, DEPTH_COMPONENT32F, framebufferWidth, framebufferHeight);
-		}
-		
-	}
-	
 	public static boolean wasResized() {
-		if(windowWidth != lastWasResizedWindowWidth || windowHeight != lastWasResizedWindowHeight) {
+		if (windowWidth != lastWasResizedWindowWidth || windowHeight != lastWasResizedWindowHeight
+				|| windowDPI != lastWasResizedWindowDPI) {
 			lastWasResizedWindowWidth = windowWidth;
 			lastWasResizedWindowHeight = windowHeight;
+			lastWasResizedWindowDPI = windowDPI;
 			return true;
 		}else {
 			return false;
 		}
 	}
-	
-	public static boolean keyboardNext() {
-		if(unpressCTRL) { //un-press ctrl after copy/paste permission
-			keyEvents.clear();
-			currentEventK = null;
-			keyStates[29] = false;
-			keyStates[157] = false;
-			keyStates[28] = false;
-			keyStates[219] = false;
-			keyStates[220] = false;
-			unpressCTRL = false;
+
+	public static boolean wasVisualViewportResized() {
+		if (visualViewportX != lastWasResizedVisualViewportX || visualViewportY != lastWasResizedVisualViewportY
+				|| visualViewportW != lastWasResizedVisualViewportW
+				|| visualViewportH != lastWasResizedVisualViewportH) {
+			lastWasResizedVisualViewportX = visualViewportX;
+			lastWasResizedVisualViewportY = visualViewportY;
+			lastWasResizedVisualViewportW = visualViewportW;
+			lastWasResizedVisualViewportH = visualViewportH;
+			return true;
+		}else {
 			return false;
 		}
-		currentEventK = null;
-		return !keyEvents.isEmpty() && (currentEventK = keyEvents.remove(0)) != null;
+	}
+
+	public static boolean keyboardNext() {
+		synchronized(keyEvents) {
+			if(unpressCTRL) { //un-press ctrl after copy/paste permission
+				keyEvents.clear();
+				currentEventK = null;
+				keyStates[29] = false;
+				keyStates[157] = false;
+				keyStates[28] = false;
+				keyStates[219] = false;
+				keyStates[220] = false;
+				unpressCTRL = false;
+				return false;
+			}
+			currentEventK = null;
+			return !keyEvents.isEmpty() && (currentEventK = keyEvents.remove(0)) != null;
+		}
+	}
+
+	public static void keyboardFireEvent(EnumFireKeyboardEvent eventType, int eagKey, char keyChar) {
+		synchronized(keyEvents) {
+			switch(eventType) {
+			case KEY_DOWN:
+				keyEvents.add(new VKeyEvent(-1, 0, eagKey, keyChar, EVENT_KEY_DOWN));
+				break;
+			case KEY_UP:
+				keyEvents.add(new VKeyEvent(-1, 0, eagKey, '\0', EVENT_KEY_UP));
+				break;
+			case KEY_REPEAT:
+				keyEvents.add(new VKeyEvent(-1, 0, eagKey, keyChar, EVENT_KEY_REPEAT));
+				break;
+			default:
+				throw new UnsupportedOperationException();
+			}
+			if(keyEvents.size() > 64) {
+				keyEvents.remove(0);
+			}
+		}
 	}
 
 	public static boolean keyboardGetEventKeyState() {
-		return currentEventK == null? false : !currentEventK.getType().equals("keyup");
+		return currentEventK == null ? false : (currentEventK.type != EVENT_KEY_UP);
 	}
 
 	public static int keyboardGetEventKey() {
-		int w = processFunctionKeys(getWhich(currentEventK));
-		return currentEventK == null ? -1 : KeyboardConstants.getEaglerKeyFromBrowser(w, currentEventK.getLocation());
+		return currentEventK == null ? -1 : currentEventK.eagKey;
+	}
+
+	@JSBody(params = { "evt" }, script = "return (typeof evt.key === \"string\") ? evt.key : \"\";")
+	private static native String getCharOrNull(KeyboardEvent evt);
+
+	private static char keyToAsciiLegacy(int whichIn, boolean shiftUp) {
+		switch(whichIn) {
+		case 188: whichIn = 44; break;
+		case 109: whichIn = 45; break;
+		case 190: whichIn = 46; break;
+		case 191: whichIn = 47; break;
+		case 192: whichIn = 96; break;
+		case 220: whichIn = 92; break;
+		case 222: whichIn = 39; break;
+		case 221: whichIn = 93; break;
+		case 219: whichIn = 91; break;
+		case 173: whichIn = 45; break;
+		case 187: whichIn = 61; break;
+		case 186: whichIn = 59; break;
+		case 189: whichIn = 45; break;
+		default: break;
+		}
+		if(shiftUp) {
+			switch(whichIn) {
+			case 96: return '~';
+			case 49: return '!';
+			case 50: return '@';
+			case 51: return '#';
+			case 52: return '$';
+			case 53: return '%';
+			case 54: return '^';
+			case 55: return '&';
+			case 56: return '*';
+			case 57: return '(';
+			case 48: return ')';
+			case 45: return '_';
+			case 61: return '+';
+			case 91: return '{';
+			case 93: return '}';
+			case 92: return '|';
+			case 59: return ':';
+			case 39: return '\"';
+			case 44: return '<';
+			case 46: return '>';
+			case 47: return '?';
+			default: return (char)whichIn;
+			}
+		}else {
+			if(whichIn >= 65 && whichIn <= 90) {
+				return (char)(whichIn + 32);
+			}else {
+				return (char)whichIn;
+			}
+		}
+	}
+
+	private static int asciiUpperToKeyLegacy(char charIn) {
+		switch(charIn) {
+		case '\n': return 17;
+		case '~': return 192;
+		case '!': return 49;
+		case '@': return 50;
+		case '#': return 51;
+		case '$': return 52;
+		case '%': return 53;
+		case '^': return 54;
+		case '&': return 55;
+		case '*': return 56;
+		case '(': return 57;
+		case ')': return 48;
+		case '_': return 173;
+		case '+': return 187;
+		case '{': return 219;
+		case '}': return 221;
+		case '|': return 220;
+		case ':': return 186;
+		case '\"': return 222;
+		case '<': return 188;
+		case '>': return 190;
+		case '?': return 191;
+		case '.': return 190;
+		case '\'': return 222;
+		case ';': return 186;
+		case '[': return 219;
+		case ']': return 221;
+		case ',': return 188;
+		case '/': return 191;
+		case '\\': return 220;
+		case '-': return 189;
+		case '`': return 192;
+		default: return (int)charIn;
+		}
 	}
 
 	public static char keyboardGetEventCharacter() {
-		if(currentEventK == null) return '\0';
-		String s = currentEventK.getKey();
-		return currentEventK == null ? ' ' : (char) (s.length() > 1 ? '\0' : s.charAt(0));
+		return currentEventK == null ? '\0' : currentEventK.keyChar;
 	}
 
 	public static boolean keyboardIsKeyDown(int key) {
@@ -468,7 +1170,7 @@ public class PlatformInput {
 	}
 
 	public static boolean keyboardIsRepeatEvent() {
-		return currentEventK == null ? false : currentEventK.isRepeat();
+		return currentEventK == null ? false : (currentEventK.type == EVENT_KEY_REPEAT);
 	}
 
 	public static void keyboardEnableRepeatEvents(boolean b) {
@@ -477,29 +1179,74 @@ public class PlatformInput {
 
 	public static boolean mouseNext() {
 		currentEvent = null;
-		return !mouseEvents.isEmpty() && (currentEvent = mouseEvents.remove(0)) != null;
+		synchronized(mouseEvents) {
+			return !mouseEvents.isEmpty() && (currentEvent = mouseEvents.remove(0)) != null;
+		}
+	}
+
+	public static void mouseFireMoveEvent(EnumFireMouseEvent eventType, int posX, int posY) {
+		if(eventType == EnumFireMouseEvent.MOUSE_MOVE) {
+			synchronized(mouseEvents) {
+				mouseEvents.add(new VMouseEvent(posX, posY, -1, 0.0f, EVENT_MOUSE_MOVE));
+				if(mouseEvents.size() > 64) {
+					mouseEvents.remove(0);
+				}
+			}
+		}else {
+			throw new UnsupportedOperationException();
+		}
+	}
+
+	public static void mouseFireButtonEvent(EnumFireMouseEvent eventType, int posX, int posY, int button) {
+		synchronized(mouseEvents) {
+			switch(eventType) {
+			case MOUSE_DOWN:
+				mouseEvents.add(new VMouseEvent(posX, posY, button, 0.0f, EVENT_MOUSE_DOWN));
+				break;
+			case MOUSE_UP:
+				mouseEvents.add(new VMouseEvent(posX, posY, button, 0.0f, EVENT_MOUSE_UP));
+				break;
+			default:
+				throw new UnsupportedOperationException();
+			}
+			if(mouseEvents.size() > 64) {
+				mouseEvents.remove(0);
+			}
+		}
+	}
+
+	public static void mouseFireWheelEvent(EnumFireMouseEvent eventType, int posX, int posY, float wheel) {
+		if(eventType == EnumFireMouseEvent.MOUSE_WHEEL) {
+			synchronized(mouseEvents) {
+				mouseEvents.add(new VMouseEvent(posX, posY, -1, wheel, EVENT_MOUSE_WHEEL));
+				if(mouseEvents.size() > 64) {
+					mouseEvents.remove(0);
+				}
+			}
+		}else {
+			throw new UnsupportedOperationException();
+		}
 	}
 
 	public static boolean mouseGetEventButtonState() {
-		return currentEvent == null ? false : currentEvent.getType().equals(MouseEvent.MOUSEDOWN);
+		return currentEvent == null ? false : (currentEvent.type == EVENT_MOUSE_DOWN);
 	}
 
 	public static int mouseGetEventButton() {
-		if(currentEvent == null || currentEvent.getType().equals(MouseEvent.MOUSEMOVE)) return -1;
-		int b = currentEvent.getButton();
-		return b == 1 ? 2 : (b == 2 ? 1 : b);
+		if(currentEvent == null || (currentEvent.type == EVENT_MOUSE_MOVE)) return -1;
+		return currentEvent.button;
 	}
 
 	public static int mouseGetEventX() {
-		return currentEvent == null ? -1 : (int)(currentEvent.getClientX() * win.getDevicePixelRatio());
+		return currentEvent == null ? -1 : currentEvent.posX;
 	}
 
 	public static int mouseGetEventY() {
-		return currentEvent == null ? -1 : (int)((canvas.getClientHeight() - currentEvent.getClientY()) * win.getDevicePixelRatio());
+		return currentEvent == null ? -1 : currentEvent.posY;
 	}
 
 	public static int mouseGetEventDWheel() {
-		return ("wheel".equals(currentEvent.getType())) ? (((WheelEvent)currentEvent).getDeltaY() == 0.0D ? 0 : (((WheelEvent)currentEvent).getDeltaY() > 0.0D ? -1 : 1)) : 0;
+		return (currentEvent.type == EVENT_MOUSE_WHEEL) ? (currentEvent.wheel == 0.0f ? 0 : (currentEvent.wheel > 0.0f ? -1 : 1)) : 0;
 	}
 
 	public static int mouseGetX() {
@@ -521,36 +1268,114 @@ public class PlatformInput {
 	}
 
 	public static void mouseSetGrabbed(boolean grab) {
-		long t = System.currentTimeMillis();
+		if(pointerLockSupported == POINTER_LOCK_NONE) {
+			return;
+		}
+		long t = PlatformRuntime.steadyTimeMillis();
 		pointerLockFlag = grab;
 		mouseGrabTimer = t;
 		if(grab) {
-			canvas.requestPointerLock();
+			callRequestPointerLock(canvas);
 			if(mouseUngrabTimeout != -1) Window.clearTimeout(mouseUngrabTimeout);
 			mouseUngrabTimeout = -1;
 			if(t - mouseUngrabTimer < 3000l) {
 				mouseUngrabTimeout = Window.setTimeout(new TimerHandler() {
 					@Override
 					public void onTimer() {
-						canvas.requestPointerLock();
+						callRequestPointerLock(canvas);
 					}
 				}, 3100 - (int)(t - mouseUngrabTimer));
 			}
 		}else {
 			if(mouseUngrabTimeout != -1) Window.clearTimeout(mouseUngrabTimeout);
 			mouseUngrabTimeout = -1;
-			Window.current().getDocument().exitPointerLock();
+			callExitPointerLock(win.getDocument());
 		}
 		mouseDX = 0.0D;
 		mouseDY = 0.0D;
 	}
 
+	private static boolean tryGrabCursorHook() {
+		if(pointerLockSupported == POINTER_LOCK_NONE) {
+			return false;
+		}
+		if(pointerLockFlag && !isPointerLocked()) {
+			mouseSetGrabbed(true);
+			return true;
+		}
+		return false;
+	}
+
+	private static void callRequestPointerLock(HTMLElement el) {
+		switch(pointerLockSupported) {
+		case POINTER_LOCK_CORE:
+			try {
+				el.requestPointerLock();
+			}catch(Throwable t) {
+			}
+			break;
+		case POINTER_LOCK_MOZ:
+			try {
+				mozRequestPointerLock(el);
+			}catch(Throwable t) {
+			}
+			break;
+		default:
+			PlatformRuntime.logger.warn("Failed to request pointer lock, it is not supported!");
+			break;
+		}
+	}
+
+	@JSBody(params = { "el" }, script = "el.mozRequestPointerLock();")
+	private static native void mozRequestPointerLock(HTMLElement el);
+
+	private static void callExitPointerLock(HTMLDocument doc) {
+		switch(pointerLockSupported) {
+		case POINTER_LOCK_CORE:
+			try {
+				doc.exitPointerLock();
+			}catch(Throwable t) {
+			}
+			break;
+		case POINTER_LOCK_MOZ:
+			try {
+				mozExitPointerLock(doc);
+			}catch(Throwable t) {
+			}
+			break;
+		default:
+			PlatformRuntime.logger.warn("Failed to exit pointer lock, it is not supported!");
+			break;
+		}
+	}
+
+	@JSBody(params = { "doc" }, script = "doc.mozExitPointerLock();")
+	private static native void mozExitPointerLock(HTMLDocument el);
+
+	public static boolean mouseGrabSupported() {
+		return pointerLockSupported != POINTER_LOCK_NONE;
+	}
+
 	public static boolean isMouseGrabbed() {
 		return pointerLockFlag;
 	}
 
-	@JSBody(params = { }, script = "return document.pointerLockElement != null;")
-	public static native boolean isPointerLocked();
+	public static boolean isPointerLocked() {
+		switch(pointerLockSupported) {
+		case POINTER_LOCK_CORE:
+			return isPointerLocked0(win.getDocument(), canvas);
+		case POINTER_LOCK_MOZ:
+			return isMozPointerLocked0(win.getDocument(), canvas);
+		default:
+			return false;
+		}
+	}
+
+	@JSBody(params = { "doc", "canvasEl" }, script = "return doc.pointerLockElement === canvasEl;")
+	private static native boolean isPointerLocked0(HTMLDocument doc, HTMLCanvasElement canvasEl);
+
+	@JSBody(params = { "doc", "canvasEl" }, script = "return doc.mozPointerLockElement === canvasEl;")
+	private static native boolean isMozPointerLocked0(HTMLDocument doc, HTMLCanvasElement canvasEl);
 
 	public static int mouseGetDX() {
 		int ret = (int)mouseDX;
@@ -590,40 +1415,203 @@ public class PlatformInput {
 	}
 
 	public static void removeEventHandlers() {
-		win.removeEventListener("contextmenu", contextmenu);
-		canvas.removeEventListener("mousedown", mousedown);
-		canvas.removeEventListener("mouseup", mouseup);
-		canvas.removeEventListener("mousemove", mousemove);
-		canvas.removeEventListener("mouseenter", mouseenter);
-		canvas.removeEventListener("mouseleave", mouseleave);
-		win.removeEventListener("keydown", keydown);
-		win.removeEventListener("keyup", keyup);
-		win.removeEventListener("keypress", keypress);
-		canvas.removeEventListener("wheel", wheel);
-		win.getDocument().removeEventListener("pointerlockchange", pointerlock);
+		if(contextmenu != null) {
+			parent.removeEventListener("contextmenu", contextmenu);
+			contextmenu = null;
+		}
+		if(mousedown != null) {
+			canvas.removeEventListener("mousedown", mousedown);
+			mousedown = null;
+		}
+		if(mouseup != null) {
+			canvas.removeEventListener("mouseup", mouseup);
+			mouseup = null;
+		}
+		if(mousemove != null) {
+			canvas.removeEventListener("mousemove", mousemove);
+			mousemove = null;
+		}
+		if(mouseenter != null) {
+			canvas.removeEventListener("mouseenter", mouseenter);
+			mouseenter = null;
+		}
+		if(mouseleave != null) {
+			canvas.removeEventListener("mouseleave", mouseleave);
+			mouseleave = null;
+		}
+		if(touchstart != null) {
+			canvas.removeEventListener("touchstart", touchstart);
+			touchstart = null;
+		}
+		if(touchmove != null) {
+			canvas.removeEventListener("touchmove", touchmove);
+			touchmove = null;
+		}
+		if(touchend != null) {
+			canvas.removeEventListener("touchend", touchend);
+			touchend = null;
+		}
+		if(touchcancel != null) {
+			canvas.removeEventListener("touchcancel", touchcancel);
+			touchcancel = null;
+		}
+		if(gamepadconnected != null) {
+			win.removeEventListener("gamepadconnected", gamepadconnected);
+			gamepadconnected = null;
+		}
+		if(gamepaddisconnected != null) {
+			win.removeEventListener("gamepaddisconnected", gamepaddisconnected);
+			gamepaddisconnected = null;
+		}
+		if(keydown != null) {
+			win.removeEventListener("keydown", keydown);
+			keydown = null;
+		}
+		if(keyup != null) {
+			win.removeEventListener("keyup", keyup);
+			keyup = null;
+		}
+		if(focus != null) {
+			win.removeEventListener("focus", focus);
+			focus = null;
+		}
+		if(blur != null) {
+			win.removeEventListener("blur", blur);
+			blur = null;
+		}
+		if(wheel != null) {
+			canvas.removeEventListener("wheel", wheel);
+			wheel = null;
+		}
+		if(pointerlock != null) {
+			win.getDocument().removeEventListener("pointerlockchange", pointerlock);
+			pointerlock = null;
+		}
 		if(mouseUngrabTimeout != -1) {
 			Window.clearTimeout(mouseUngrabTimeout);
 			mouseUngrabTimeout = -1;
 		}
+		if(vsyncSaveLockInterval != -1) {
+			try {
+				Window.clearInterval(vsyncSaveLockInterval);
+			}catch(Throwable t) {
+			}
+			vsyncSaveLockInterval = -1;
+		}
+		if(touchKeyboardField != null) {
+			touchKeyboardField.blur();
+			if(parent != null) {
+				parent.removeChild(touchKeyboardField);
+			}
+			touchKeyboardField = null;
+		}
+		if(touchKeyboardOpenZone != null) {
+			if(touchKeyboardOpenZone_touchstart != null) {
+				touchKeyboardOpenZone.removeEventListener("touchstart", touchKeyboardOpenZone_touchstart);
+				touchKeyboardOpenZone_touchstart = null;
+			}
+			if(touchKeyboardOpenZone_touchend != null) {
+				touchKeyboardOpenZone.removeEventListener("touchend", touchKeyboardOpenZone_touchend);
+				touchKeyboardOpenZone_touchend = null;
+			}
+			if(touchKeyboardOpenZone_touchmove != null) {
+				touchKeyboardOpenZone.removeEventListener("touchmove", touchKeyboardOpenZone_touchmove);
+				touchKeyboardOpenZone_touchmove = null;
+			}
+			if(parent != null) {
+				parent.removeChild(touchKeyboardOpenZone);
+			}
+			touchKeyboardOpenZone = null;
+		}
 		try {
-			win.getDocument().exitPointerLock();
+			callExitPointerLock(win.getDocument());
 		}catch(Throwable t) {
 		}
+		ClientMain.removeErrorHandler(win);
 	}
 
 	public static void pressAnyKeyScreen() {
-		if(mouseEvents.isEmpty() && keyEvents.isEmpty() && !hasBeenActive()) {
-			EarlyLoadScreen.paintEnable();
-			
-			while(mouseEvents.isEmpty() && keyEvents.isEmpty()) {
-				EagUtils.sleep(100l);
+		IClientConfigAdapter cfgAdapter = PlatformRuntime.getClientConfigAdapter();
+		boolean allowBootMenu = cfgAdapter.isAllowBootMenu();
+		if(isLikelyMobileBrowser) {
+			EarlyLoadScreen.paintEnable(PlatformOpenGL.checkVAOCapable(), allowBootMenu);
+			try {
+				isOnMobilePressAnyKey = true;
+				setupAnyKeyScreenMobile(allowBootMenu);
+				if(pressAnyKeyScreenMobile() && allowBootMenu) {
+					PlatformRuntime.enterBootMenu();
+				}
+			}finally {
+				isOnMobilePressAnyKey = false;
+			}
+		}else {
+			if(mouseEvents.isEmpty() && keyEvents.isEmpty() && !hasBeenActiveTeaVM(false)) {
+				EarlyLoadScreen.paintEnable(PlatformOpenGL.checkVAOCapable(), allowBootMenu);
+				
+				while(mouseEvents.isEmpty() && keyEvents.isEmpty() && touchEvents.isEmpty()) {
+					EagUtils.sleep(100l);
+				}
 			}
 		}
+		hasShownPressAnyKey = true;
+	}
+
+	private static void setupAnyKeyScreenMobile(boolean allowBootMenu) {
+		if(mobilePressAnyKeyScreen != null) {
+			parent.removeChild(mobilePressAnyKeyScreen);
+		}
+		mobilePressAnyKeyScreen = win.getDocument().createElement("div");
+		mobilePressAnyKeyScreen.getClassList().add("_eaglercraftX_mobile_press_any_key");
+		mobilePressAnyKeyScreen.setAttribute("style", "position:absolute;background-color:white;font-family:sans-serif;top:10%;left:10%;right:10%;bottom:10%;border:5px double black;padding:calc(5px + 7vh) 15px;text-align:center;font-size:20px;user-select:none;z-index:10;");
+		mobilePressAnyKeyScreen.setInnerHTML("<h3 style=\"margin-block-start:0px;margin-block-end:0px;-webkit-margin-before:0px;-webkit-margin-after:0px;margin:20px 5px;\">Mobile Browser Detected</h3>"
+				+ "<p style=\"margin-block-start:0px;margin-block-end:0px;-webkit-margin-before:0px;-webkit-margin-after:0px;margin:20px 5px;\">You must manually select an option below to continue</p>"
+				+ "<p style=\"margin-block-start:0px;margin-block-end:0px;-webkit-margin-before:0px;-webkit-margin-after:0px;margin:20px 2px;\"><button style=\"font: 24px sans-serif;font-weight:bold;\" class=\"_eaglercraftX_mobile_launch_client\">Launch EaglercraftX</button></p>"
+				+ (allowBootMenu ? "<p style=\"margin-block-start:0px;margin-block-end:0px;-webkit-margin-before:0px;-webkit-margin-after:0px;margin:20px 2px;\"><button style=\"font: 24px sans-serif;\" class=\"_eaglercraftX_mobile_enter_boot_menu\">Enter Boot Menu</button></p>" : "")
+				+ "<p style=\"margin-block-start:0px;margin-block-end:0px;-webkit-margin-before:0px;-webkit-margin-after:0px;margin:25px 5px;\">(Tablets and phones with large screens work best)</p>");
+		mobilePressAnyKeyScreen.querySelector("._eaglercraftX_mobile_launch_client").addEventListener("click", new EventListener<Event>() {
+			@Override
+			public void handleEvent(Event evt) {
+				if(isOnMobilePressAnyKey && mobilePressAnyKey != null) {
+					mobilePressAnyKey.call(false);
+				}
+			}
+		});
+		if(allowBootMenu) {
+			mobilePressAnyKeyScreen.querySelector("._eaglercraftX_mobile_enter_boot_menu").addEventListener("click", new EventListener<Event>() {
+				@Override
+				public void handleEvent(Event evt) {
+					if(isOnMobilePressAnyKey && mobilePressAnyKey != null) {
+						mobilePressAnyKey.call(true);
+					}
+				}
+			});
+		}
+		parent.appendChild(mobilePressAnyKeyScreen);
+	}
+
+	@Async
+	private static native boolean pressAnyKeyScreenMobile();
+
+	private static void pressAnyKeyScreenMobile(final AsyncCallback<Boolean> complete) {
+		mobilePressAnyKey = new MobilePressAnyKeyHandler() {
+			@Override
+			public void call(boolean enterBootMenu) {
+				mobilePressAnyKey = null;
+				if(mobilePressAnyKeyScreen != null && parent != null) {
+					parent.removeChild(mobilePressAnyKeyScreen);
+				}
+				mobilePressAnyKeyScreen = null;
+				complete.complete(enterBootMenu);
+			}
+		};
+		PlatformRuntime.logger.info("Waiting for user to select option on mobile press any key screen");
 	}
 
 	public static void clearEvenBuffers() {
 		mouseEvents.clear();
 		keyEvents.clear();
+		touchEvents.clear();
+		net.lax1dude.eaglercraft.v1_8.Gamepad.clearEventBuffer();
 	}
 
 	@JSBody(params = {}, script = "return window.matchMedia(\"(display-mode: fullscreen)\");")
@@ -632,40 +1620,109 @@ public class PlatformInput {
 	@JSBody(params = { "mediaQuery" }, script = "return mediaQuery.matches;")
 	private static native boolean mediaQueryMatches(JSObject mediaQuery);
 
+	public static boolean supportsFullscreen() {
+		return fullscreenSupported != FULLSCREEN_NONE;
+	}
+
 	public static void toggleFullscreen() {
+		if(fullscreenSupported == FULLSCREEN_NONE) return;
 		if (isFullscreen()) {
 			if (keyboardLockSupported) {
 				unlockKeys();
 				lockKeys = false;
 			}
-			exitFullscreen();
+			callExitFullscreen(win.getDocument());
 		} else {
 			if (keyboardLockSupported) {
 				lockKeys();
 				lockKeys = true;
 			}
-			requestFullscreen(canvas);
+			callRequestFullscreen(canvas);
 		}
 	}
 
 	public static boolean isFullscreen() {
-		return mediaQueryMatches(fullscreenQuery);
+		return fullscreenSupported != FULLSCREEN_NONE && mediaQueryMatches(fullscreenQuery);
 	}
 
-	@JSBody(params = { }, script = "window.navigator.keyboard.lock();")
+	@JSBody(params = { }, script = "navigator.keyboard.lock();")
 	private static native void lockKeys();
 
-	@JSBody(params = { }, script = "window.navigator.keyboard.unlock();")
+	@JSBody(params = { }, script = "navigator.keyboard.unlock();")
 	private static native void unlockKeys();
 
-	@JSBody(params = { }, script = "return !!(window.navigator.keyboard && window.navigator.keyboard.lock);")
+	@JSBody(params = { }, script = "return !!(navigator.keyboard && navigator.keyboard.lock);")
 	private static native boolean checkKeyboardLockSupported();
 
-	@JSBody(params = { }, script = "document.exitFullscreen();")
-	private static native void exitFullscreen();
+	private static void callRequestFullscreen(HTMLElement el) {
+		switch(fullscreenSupported) {
+		case FULLSCREEN_CORE:
+			try {
+				requestFullscreen(el);
+			}catch(Throwable t) {
+			}
+			break;
+		case FULLSCREEN_WEBKIT:
+			try {
+				webkitRequestFullscreen(el);
+			}catch(Throwable t) {
+			}
+			break;
+		case FULLSCREEN_MOZ:
+			try {
+				mozRequestFullscreen(el);
+			}catch(Throwable t) {
+			}
+			break;
+		default:
+			PlatformRuntime.logger.warn("Failed to request fullscreen, it is not supported!");
+			break;
+		}
+	}
 
-	@JSBody(params = { "element" }, script = "element.requestFullscreen();")
-	private	 static native void requestFullscreen(HTMLElement element);
+	@JSBody(params = { "el" }, script = "el.requestFullscreen();")
+	private static native void requestFullscreen(HTMLElement element);
+
+	@JSBody(params = { "el" }, script = "el.webkitRequestFullscreen();")
+	private static native void webkitRequestFullscreen(HTMLElement element);
+
+	@JSBody(params = { "el" }, script = "el.mozRequestFullScreen();")
+	private static native void mozRequestFullscreen(HTMLElement element);
+
+	private static void callExitFullscreen(HTMLDocument doc) {
+		switch(fullscreenSupported) {
+		case FULLSCREEN_CORE:
+			try {
+				exitFullscreen(doc);
+			}catch(Throwable t) {
+			}
+			break;
+		case FULLSCREEN_WEBKIT:
+			try {
+				webkitExitFullscreen(doc);
+			}catch(Throwable t) {
+			}
+			break;
+		case FULLSCREEN_MOZ:
+			try {
+				mozCancelFullscreen(doc);
+			}catch(Throwable t) {
+			}
+			break;
+		default:
+			PlatformRuntime.logger.warn("Failed to exit fullscreen, it is not supported!");
+			break;
+		}
+	}
+
+	@JSBody(params = { "doc" }, script = "doc.exitFullscreen();")
+	private	 static native void exitFullscreen(HTMLDocument doc);
+
+	@JSBody(params = { "doc" }, script = "doc.webkitExitFullscreen();")
+	private	 static native void webkitExitFullscreen(HTMLDocument doc);
+
+	@JSBody(params = { "doc" }, script = "doc.mozCancelFullscreen();")
+	private	 static native void mozCancelFullscreen(HTMLDocument doc);
 
 	public static void showCursor(EnumCursorType cursor) {
 		switch(cursor) {
@@ -681,5 +1738,646 @@ public class PlatformInput {
 			break;
 		}
 	}
-	
+
+	public static boolean touchNext() {
+		currentTouchEvent = null;
+		return !touchEvents.isEmpty() && (currentTouchEvent = touchEvents.remove(0)) != null;
+	}
+
+	public static EnumTouchEvent touchGetEventType() {
+		return currentTouchEvent != null ? currentTouchEvent.type : null;
+	}
+
+	public static int touchGetEventTouchPointCount() {
+		return currentTouchEvent != null ? currentTouchEvent.getEventTouches().size() : 0;
+	}
+
+	public static int touchGetEventTouchX(int pointId) {
+		return currentTouchEvent != null ? currentTouchEvent.getEventTouches().get(pointId).posX : 0;
+	}
+
+	public static int touchGetEventTouchY(int pointId) {
+		return currentTouchEvent != null ? currentTouchEvent.getEventTouches().get(pointId).posY : 0;
+	}
+
+	public static float touchGetEventTouchRadiusX(int pointId) {
+		return currentTouchEvent != null ? (float)currentTouchEvent.getEventTouches().get(pointId).touch.getRadiusXSafe(5.0 * windowDPI) : 1.0f;
+	}
+
+	public static float touchGetEventTouchRadiusY(int pointId) {
+		return currentTouchEvent != null ? (float)currentTouchEvent.getEventTouches().get(pointId).touch.getRadiusYSafe(5.0 * windowDPI) : 1.0f;
+	}
+
+	public static float touchGetEventTouchRadiusMixed(int pointId) {
+		if(currentTouchEvent != null) {
+			Touch t = currentTouchEvent.getEventTouches().get(pointId).touch;
+			double d = 5.0 * windowDPI;
+			return (float)(t.getRadiusXSafe(d) * 0.5 + t.getRadiusYSafe(d) * 0.5);
+		}else {
+			return 1.0f;
+		}
+	}
+
+	public static float touchGetEventTouchForce(int pointId) {
+		return currentTouchEvent != null ? (float)currentTouchEvent.getEventTouches().get(pointId).touch.getForceSafe(0.5) : 0.0f;
+	}
+
+	public static int touchGetEventTouchPointUID(int pointId) {
+		return currentTouchEvent != null ? currentTouchEvent.getEventTouches().get(pointId).eventUID : -1;
+	}
+
+	public static int touchPointCount() {
+		return currentTouchState != null ? currentTouchState.getTargetTouchesSize() : 0;
+	}
+
+	public static int touchPointX(int pointId) {
+		return currentTouchState != null ? currentTouchState.getTargetTouches().get(pointId).posX : -1;
+	}
+
+	public static int touchPointY(int pointId) {
+		return currentTouchState != null ? currentTouchState.getTargetTouches().get(pointId).posY : -1;
+	}
+
+	public static float touchRadiusX(int pointId) {
+		return currentTouchState != null ? (float)currentTouchState.getTargetTouches().get(pointId).touch.getRadiusXSafe(5.0 * windowDPI) : 1.0f;
+	}
+
+	public static float touchRadiusY(int pointId) {
+		return currentTouchState != null ? (float)currentTouchState.getTargetTouches().get(pointId).touch.getRadiusYSafe(5.0 * windowDPI) : 1.0f;
+	}
+
+	public static float touchRadiusMixed(int pointId) {
+		if(currentTouchState != null) {
+			Touch t = currentTouchState.getTargetTouches().get(pointId).touch;
+			return (float)(t.getRadiusX() * 0.5 + t.getRadiusY() * 0.5);
+		}else {
+			return 1.0f;
+		}
+	}
+
+	public static float touchForce(int pointId) {
+		return currentTouchState != null ? (float)currentTouchState.getTargetTouches().get(pointId).touch.getForceSafe(0.5) : 0.0f;
+	}
+
+	public static int touchPointUID(int pointId) {
+		return currentTouchState != null ? currentTouchState.getTargetTouches().get(pointId).eventUID : -1;
+	}
+
+	private static final Map<Integer,Integer> touchIDtoUID = new HashMap<>();
+	private static int touchUIDnum = 0;
+
+	private static final SortedTouchEvent.ITouchUIDMapper touchUIDMapperCreate = (idx) -> {
+		Integer ret = touchIDtoUID.get(idx);
+		if(ret != null) return ret.intValue();
+		int r = touchUIDnum++;
+		touchIDtoUID.put(idx, r);
+		return r;
+	};
+
+	private static final SortedTouchEvent.ITouchUIDMapper touchUIDMapper = (idx) -> {
+		Integer ret = touchIDtoUID.get(idx);
+		return ret != null ? ret.intValue() : -1;
+	};
+
+	public static void touchBufferFlush() {
+		pointerLockSupported = 0;
+		pointerLockFlag = true;
+		currentTouchState = null;
+		touchEvents.clear();
+	}
+
+	// Note: this can't be called from the main loop, don't try
+	private static void touchOpenDeviceKeyboard() {
+		if(!touchIsDeviceKeyboardOpenMAYBE()) {
+			if(touchKeyboardField != null) {
+				touchKeyboardField.blur();
+				touchKeyboardField.setValue("");
+				EagUtils.sleep(10l);
+				if(touchKeyboardForm != null) {
+					touchKeyboardForm.removeChild(touchKeyboardField);
+				}else {
+					touchKeyboardField.delete();
+				}
+				touchKeyboardField = null;
+				if(touchKeyboardForm != null) {
+					parent.removeChild(touchKeyboardForm);
+					touchKeyboardForm = null;
+				}
+				return;
+			}
+			if(touchKeyboardForm != null) {
+				parent.removeChild(touchKeyboardForm);
+				touchKeyboardForm = null;
+			}
+			touchKeyboardForm = (HTMLFormElement) win.getDocument().createElement("form");
+			touchKeyboardForm.setAttribute("autocomplete", "off");
+			touchKeyboardForm.getClassList().add("_eaglercraftX_text_input_wrapper");
+			CSSStyleDeclaration decl = touchKeyboardForm.getStyle();
+			decl.setProperty("position", "absolute");
+			decl.setProperty("top", "0px");
+			decl.setProperty("left", "0px");
+			decl.setProperty("right", "0px");
+			decl.setProperty("bottom", "0px");
+			decl.setProperty("z-index", "-100");
+			decl.setProperty("margin", "0px");
+			decl.setProperty("padding", "0px");
+			decl.setProperty("border", "none");
+			touchKeyboardForm.addEventListener("submit", new EventListener<Event>() {
+				@Override
+				public void handleEvent(Event evt) {
+					evt.preventDefault();
+					evt.stopPropagation();
+					JSObject obj = evt.getTimeStamp();
+					if(TeaVMUtils.isTruthy(obj)) {
+						double d = ((JSNumber)obj).doubleValue();
+						if(lastTouchKeyboardEvtA != 0.0 && (d - lastTouchKeyboardEvtA) < 10.0) {
+							return;
+						}
+						if(lastTouchKeyboardEvtB != 0.0 && (d - lastTouchKeyboardEvtB) < 10.0) {
+							return;
+						}
+						if(lastTouchKeyboardEvtC != 0.0 && (d - lastTouchKeyboardEvtC) < 10.0) {
+							return;
+						}
+						if(!showniOSReturnTouchKeyboardWarning) {
+							PlatformRuntime.logger.info("Note: Generating return keystroke from submit event on form, this browser probably doesn't generate keydown/beforeinput/input when enter/return is pressed on the on-screen keyboard");
+							showniOSReturnTouchKeyboardWarning = true;
+						}
+						keyboardFireEvent(EnumFireKeyboardEvent.KEY_DOWN, KeyboardConstants.KEY_RETURN, '\n');
+						keyboardFireEvent(EnumFireKeyboardEvent.KEY_UP, KeyboardConstants.KEY_RETURN, '\n');
+					}
+					
+				}
+			});
+			touchKeyboardField = (HTMLInputElement) win.getDocument().createElement("input");
+			touchKeyboardField.setType("password");
+			touchKeyboardField.setValue(" ");
+			touchKeyboardField.getClassList().add("_eaglercraftX_text_input_element");
+			touchKeyboardField.setAttribute("autocomplete", "off");
+			decl = touchKeyboardField.getStyle();
+			decl.setProperty("position", "absolute");
+			decl.setProperty("top", "0px");
+			decl.setProperty("left", "0px");
+			decl.setProperty("right", "0px");
+			decl.setProperty("bottom", "0px");
+			decl.setProperty("z-index", "-100");
+			decl.setProperty("margin", "0px");
+			decl.setProperty("padding", "0px");
+			decl.setProperty("border", "none");
+			decl.setProperty("-webkit-touch-callout", "default");
+			touchKeyboardField.addEventListener("beforeinput", new EventListener<InputEvent>() {
+				@Override
+				public void handleEvent(InputEvent evt) {
+					if(touchKeyboardField != evt.getTarget()) return;
+					if(!shownTouchKeyboardEventWarning) {
+						PlatformRuntime.logger.info("Note: Caught beforeinput event from on-screen keyboard, browser probably does not generate global keydown/keyup events on text fields, or does not respond to cancelling keydown");
+						shownTouchKeyboardEventWarning = true;
+					}
+					JSObject obj = evt.getTimeStamp();
+					if(TeaVMUtils.isTruthy(obj)) {
+						double d = ((JSNumber)obj).doubleValue();
+						if(lastTouchKeyboardEvtA != 0.0 && (d - lastTouchKeyboardEvtA) < 10.0) {
+							return;
+						}
+						lastTouchKeyboardEvtB = d;
+					}
+					evt.preventDefault();
+					evt.stopPropagation();
+					switch(evt.getInputType()) {
+					case "insertParagraph":
+					case "insertLineBreak":
+						keyboardFireEvent(EnumFireKeyboardEvent.KEY_DOWN, KeyboardConstants.KEY_RETURN, '\n');
+						keyboardFireEvent(EnumFireKeyboardEvent.KEY_UP, KeyboardConstants.KEY_RETURN, '\n');
+						break;
+					case "deleteWordBackward":
+					case "deleteSoftLineBackward":
+					case "deleteHardLineBackward":
+					case "deleteEntireSoftLine":
+					case "deleteContentBackward":
+					case "deleteContent":
+						keyboardFireEvent(EnumFireKeyboardEvent.KEY_DOWN, KeyboardConstants.KEY_BACK, '\0');
+						keyboardFireEvent(EnumFireKeyboardEvent.KEY_UP, KeyboardConstants.KEY_BACK, '\0');
+						break;
+					case "deleteWordForward":
+					case "deleteSoftLineForward":
+					case "deleteHardLineForward":
+					case "deleteContentForward":
+						keyboardFireEvent(EnumFireKeyboardEvent.KEY_DOWN, KeyboardConstants.KEY_DELETE, '\0');
+						keyboardFireEvent(EnumFireKeyboardEvent.KEY_UP, KeyboardConstants.KEY_DELETE, '\0');
+						break;
+					case "insertText":
+					case "insertCompositionText":
+					case "insertReplacementText":
+						String eventsToGenerate = evt.getData();
+						for(int i = 0, l = eventsToGenerate.length(); i < l; ++i) {
+							char c = eventsToGenerate.charAt(i);
+							int eag = KeyboardConstants.getEaglerKeyFromBrowser(asciiUpperToKeyLegacy(Character.toUpperCase(c)), 0);
+							keyboardFireEvent(EnumFireKeyboardEvent.KEY_DOWN, eag, c);
+							keyboardFireEvent(EnumFireKeyboardEvent.KEY_UP, eag, c);
+						}
+						break;
+					case "insertFromPaste":
+					case "insertFromPasteAsQuotation":
+					case "insertFromDrop":
+					case "insertFromYank":
+					case "insertLink":
+						synchronized(pastedStrings) {
+							pastedStrings.add(evt.getData());
+							if(pastedStrings.size() > 64) {
+								pastedStrings.remove(0);
+							}
+						}
+						break;
+					case "historyUndo":
+					case "historyRedo":
+					case "deleteByDrag":
+					case "deleteByCut":
+						break;
+					default:
+						PlatformRuntime.logger.info("Ingoring InputEvent.inputType \"{}\" from on-screen keyboard", evt.getInputType());
+						break;
+					}
+				}
+			});
+			touchKeyboardField.addEventListener("input", new EventListener<Event>() {
+				@Override
+				public void handleEvent(Event evt) {
+					if(touchKeyboardField != evt.getTarget()) return;
+					JSObject obj = evt.getTimeStamp();
+					if(!shownLegacyTouchKeyboardWarning) {
+						PlatformRuntime.logger.info("Note: Caught legacy input events from on-screen keyboard, browser could be outdated and doesn't support beforeinput event, or does not respond to cancelling beforeinput");
+						shownLegacyTouchKeyboardWarning = true;
+					}
+					if(TeaVMUtils.isTruthy(obj)) {
+						double d = ((JSNumber)obj).doubleValue();
+						if(lastTouchKeyboardEvtA != 0.0 && (d - lastTouchKeyboardEvtA) < 10.0) {
+							return;
+						}
+						if(lastTouchKeyboardEvtB != 0.0 && (d - lastTouchKeyboardEvtB) < 10.0) {
+							return;
+						}
+						lastTouchKeyboardEvtC = d;
+					}
+					String val = touchKeyboardField.getValue();
+					int l = val.length();
+					if(l == 0) {
+						keyboardFireEvent(EnumFireKeyboardEvent.KEY_DOWN, KeyboardConstants.KEY_BACK, '\0');
+						keyboardFireEvent(EnumFireKeyboardEvent.KEY_UP, KeyboardConstants.KEY_BACK, '\0');
+					}else if(l == 1) {
+						char c = val.charAt(0);
+						int eag = KeyboardConstants.getEaglerKeyFromBrowser(asciiUpperToKeyLegacy(Character.toUpperCase(c)), 0);
+						keyboardFireEvent(EnumFireKeyboardEvent.KEY_DOWN, eag, c);
+						keyboardFireEvent(EnumFireKeyboardEvent.KEY_UP, eag, c);
+					}else {
+						val = val.trim();
+						l = val.length();
+						if(l == 0) {
+							keyboardFireEvent(EnumFireKeyboardEvent.KEY_DOWN, KeyboardConstants.KEY_SPACE, ' ');
+							keyboardFireEvent(EnumFireKeyboardEvent.KEY_UP, KeyboardConstants.KEY_SPACE, ' ');
+						}else {
+							char c = val.charAt(l - 1);
+							int eag = KeyboardConstants.getEaglerKeyFromBrowser(asciiUpperToKeyLegacy(Character.toUpperCase(c)), 0);
+							keyboardFireEvent(EnumFireKeyboardEvent.KEY_DOWN, eag, c);
+							keyboardFireEvent(EnumFireKeyboardEvent.KEY_UP, eag, c);
+						}
+					}
+					touchKeyboardField.setValue(" ");
+					setSelectionRange(touchKeyboardField, 1, 1);
+				}
+			});
+			touchKeyboardField.addEventListener("focus", new EventListener<Event>() {
+				@Override
+				public void handleEvent(Event evt) {
+					if(touchKeyboardField != evt.getTarget()) return;
+					touchKeyboardField.setValue(" ");
+					setSelectionRange(touchKeyboardField, 1, 1);
+				}
+			});
+			touchKeyboardField.addEventListener("select", new EventListener<Event>() {
+				@Override
+				public void handleEvent(Event evt) {
+					if(touchKeyboardField != evt.getTarget()) return;
+					evt.preventDefault();
+					evt.stopPropagation();
+					touchKeyboardField.setValue(" ");
+					setSelectionRange(touchKeyboardField, 1, 1);
+				}
+			});
+			touchKeyboardForm.appendChild(touchKeyboardField);
+			parent.appendChild(touchKeyboardForm);
+			touchKeyboardField.setValue(" ");
+			touchKeyboardField.focus();
+			touchKeyboardField.select();
+			setSelectionRange(touchKeyboardField, 1, 1);
+		}else {
+			touchCloseDeviceKeyboard0(false);
+		}
+	}
+
+	public static String touchGetPastedString() {
+		synchronized(pastedStrings) {
+			return pastedStrings.isEmpty() ? null : pastedStrings.remove(0);
+		}
+	}
+
+	public static void touchSetOpenKeyboardZone(int x, int y, int w, int h) {
+		if(w != 0 && h != 0) {
+			int xx = (int)(x / windowDPI);
+			int yy = (int)((windowHeight - y - h) / windowDPI);
+			int ww = (int)(w / windowDPI);
+			int hh = (int)(h / windowDPI);
+			if(xx != touchOpenZoneX || yy != touchOpenZoneY || ww != touchOpenZoneW || hh != touchOpenZoneH) {
+				CSSStyleDeclaration decl = touchKeyboardOpenZone.getStyle();
+				decl.setProperty("display", "block");
+				decl.setProperty("left", "" + xx + "px");
+				decl.setProperty("top", "" + yy + "px");
+				decl.setProperty("width", "" + ww + "px");
+				decl.setProperty("height", "" + hh + "px");
+				touchOpenZoneX = xx;
+				touchOpenZoneY = yy;
+				touchOpenZoneW = ww;
+				touchOpenZoneH = hh;
+			}
+		}else {
+			if(touchOpenZoneW != 0 || touchOpenZoneH != 0) {
+				CSSStyleDeclaration decl = touchKeyboardOpenZone.getStyle();
+				decl.setProperty("display", "none");
+				decl.setProperty("top", "0px");
+				decl.setProperty("left", "0px");
+				decl.setProperty("width", "0px");
+				decl.setProperty("height", "0px");
+			}
+			touchOpenZoneX = 0;
+			touchOpenZoneY = 0;
+			touchOpenZoneW = 0;
+			touchOpenZoneH = 0;
+		}
+	}
+
+	public static void touchCloseDeviceKeyboard() {
+		touchCloseDeviceKeyboard0(true);
+	}
+
+	private static void touchCloseDeviceKeyboard0(boolean sync) {
+		if(touchKeyboardField != null) {
+			touchKeyboardField.blur();
+			touchKeyboardField.setValue("");
+			if(sync) {
+				EagUtils.sleep(10l);
+				if(touchKeyboardForm != null) {
+					touchKeyboardForm.removeChild(touchKeyboardField);
+				}else {
+					touchKeyboardField.delete();
+				}
+				touchKeyboardField = null;
+			}else {
+				final HTMLInputElement el = touchKeyboardField;
+				final HTMLFormElement el2 = touchKeyboardForm;
+				Window.setTimeout(() -> {
+					if(el2 != null) {
+						el2.removeChild(el);
+						el2.delete();
+					}else {
+						el.delete();
+					}
+				}, 10);
+				touchKeyboardField = null;
+				touchKeyboardForm = null;
+				return;
+			}
+		}
+		if(touchKeyboardForm != null) {
+			if(parent != null) {
+				parent.removeChild(touchKeyboardForm);
+			}else {
+				touchKeyboardForm.delete();
+			}
+			touchKeyboardForm = null;
+		}
+	}
+
+	public static boolean touchIsDeviceKeyboardOpenMAYBE() {
+		return touchKeyboardField != null && isActiveElement(win.getDocument(), touchKeyboardField);
+	}
+
+	@JSBody(params = { "doc", "el" }, script = "return doc.activeElement === el;")
+	private static native boolean isActiveElement(HTMLDocument doc, HTMLElement el);
+
+	private static void enumerateGamepads() {
+		if(!gamepadSupported) return;
+		if(selectedGamepad != null) {
+			selectedGamepad = updateGamepad(selectedGamepad);
+			if(selectedGamepad == null || !TeaVMUtils.isTruthy(selectedGamepad) || !selectedGamepad.isConnected()) {
+				selectedGamepad = null;
+			}
+		}
+		List<Gamepad> oldList = null;
+		if(!gamepadList.isEmpty()) {
+			oldList = new ArrayList<>(gamepadList);
+			gamepadList.clear();
+		}
+		Gamepad[] gamepads = Navigator.getGamepads();
+		if(gamepads != null && gamepads.length > 0) {
+			for(int i = 0; i < gamepads.length; ++i) {
+				Gamepad g = gamepads[i];
+				if(TeaVMUtils.isTruthy(g) && g.isConnected() && "standard".equals(g.getMapping())) {
+					gamepadList.add(g);
+				}
+			}
+		}
+		if(selectedGamepad != null) {
+			selectedGamepadName = selectedGamepad.getId();
+		}
+		if(oldList == null) {
+			if(!gamepadList.isEmpty()) {
+				for(int i = 0, l = gamepadList.size(); i < l; ++i) {
+					PlatformRuntime.logger.info("Found controller: {}", gamepadList.get(i).getId());
+				}
+			}
+		}else {
+			if(gamepadList.isEmpty()) {
+				for(int i = 0, l = oldList.size(); i < l; ++i) {
+					PlatformRuntime.logger.info("Lost controller: {}", oldList.get(i).getId());
+				}
+			}else {
+				Map<String,Integer> oldDevCounts = new HashMap<>();
+				for(Gamepad gg : oldList) {
+					String s = gg.getId();
+					Integer i = oldDevCounts.get(s);
+					if(i != null) {
+						oldDevCounts.put(s, Integer.valueOf(i.intValue() + 1));
+					}else {
+						oldDevCounts.put(s, Integer.valueOf(1));
+					}
+				}
+				Map<String,Integer> newDevCounts = new HashMap<>();
+				for(Gamepad gg : gamepadList) {
+					String s = gg.getId();
+					Integer i = newDevCounts.get(s);
+					if(i != null) {
+						newDevCounts.put(s, Integer.valueOf(i.intValue() + 1));
+					}else {
+						newDevCounts.put(s, Integer.valueOf(1));
+					}
+				}
+				for(Entry<String,Integer> etr : oldDevCounts.entrySet()) {
+					Integer i = newDevCounts.get(etr.getKey());
+					if(i == null) {
+						for(int j = 0, l = etr.getValue().intValue(); j < l; ++j) {
+							PlatformRuntime.logger.info("Lost controller: {}", etr.getKey());
+						}
+					}else {
+						int j = i.intValue();
+						int k = etr.getValue().intValue();
+						if(k != j) {
+							if(k < j) {
+								for(int m = 0, l = j - k; m < l; ++m) {
+									PlatformRuntime.logger.info("Found controller: {}", etr.getKey());
+								}
+							}else {
+								for(int m = 0, l = k - j; m < l; ++m) {
+									PlatformRuntime.logger.info("Lost controller: {}", etr.getKey());
+								}
+							}
+						}
+					}
+				}
+				for(Entry<String,Integer> etr : newDevCounts.entrySet()) {
+					Integer i = oldDevCounts.get(etr.getKey());
+					if(i == null) {
+						for(int j = 0, l = etr.getValue().intValue(); j < l; ++j) {
+							PlatformRuntime.logger.info("Found controller: {}", etr.getKey());
+						}
+					}
+				}
+			}
+			
+		}
+	}
+
+	public static int gamepadGetValidDeviceCount() {
+		if(!gamepadSupported) return 0;
+		return gamepadList.size();
+	}
+
+	public static String gamepadGetDeviceName(int deviceId) {
+		if(gamepadSupported && deviceId >= 0 && deviceId < gamepadList.size()) {
+			return gamepadList.get(deviceId).getId();
+		}else {
+			return "Unknown";
+		}
+	}
+
+	public static void gamepadSetSelectedDevice(int deviceId) {
+		if(!gamepadSupported) return;
+		gamepadReset();
+		if(deviceId >= 0 && deviceId < gamepadList.size()) {
+			selectedGamepad = gamepadList.get(deviceId);
+			gamepadTimestamp = -1.0;
+			if(!TeaVMUtils.isTruthy(selectedGamepad) || !selectedGamepad.isConnected()) {
+				selectedGamepad = null;
+			}
+		}else {
+			selectedGamepad = null;
+		}
+	}
+
+	private static void gamepadReset() {
+		for(int i = 0; i < gamepadButtonStates.length; ++i) {
+			gamepadButtonStates[i] = false;
+		}
+		for(int i = 0; i < gamepadAxisStates.length; ++i) {
+			gamepadAxisStates[i] = 0.0f;
+		}
+	}
+
+	@JSBody(params = { }, script = "return (typeof navigator.getGamepads === \"function\");")
+	private static native boolean gamepadSupported();
+
+	@JSBody(params = { "gp" }, script = "return navigator.getGamepads()[gp.index];")
+	private static native Gamepad updateGamepad(Gamepad gp);
+
+	public static void gamepadUpdate() {
+		if(!gamepadSupported) return;
+		if(selectedGamepad != null) {
+			selectedGamepad = updateGamepad(selectedGamepad);
+			if(selectedGamepad == null || !TeaVMUtils.isTruthy(selectedGamepad) || !selectedGamepad.isConnected()) {
+				gamepadReset();
+				selectedGamepad = null;
+				return;
+			}
+			double ts = selectedGamepad.getTimestamp();
+			if(ts != gamepadTimestamp) {
+				gamepadTimestamp = ts;
+				gamepadReset();
+				GamepadButton[] btns = selectedGamepad.getButtons();
+				for(int i = 0; i < btns.length; ++i) {
+					int j = GamepadConstants.getEaglerButtonFromBrowser(i);
+					if(j >= 0 && j < gamepadButtonStates.length) {
+						gamepadButtonStates[j] = btns[i].isPressed();
+					}
+				}
+				double[] axes = selectedGamepad.getAxes();
+				for(int i = 0; i < axes.length; ++i) {
+					if(i >= 4) {
+						break;
+					}
+					gamepadAxisStates[i] = (float)axes[i];
+				}
+			}
+		}else {
+			gamepadReset();
+		}
+	}
+
+	public static boolean gamepadIsValid() {
+		if(!gamepadSupported) return false;
+		return selectedGamepad != null;
+	}
+
+	public static String gamepadGetName() {
+		return gamepadSupported && selectedGamepad != null ? selectedGamepadName : "Unknown";
+	}
+
+	public static boolean gamepadGetButtonState(int button) {
+		return gamepadSupported && selectedGamepad != null && button >= 0 && button < gamepadButtonStates.length ? gamepadButtonStates[button] : false;
+	}
+
+	public static float gamepadGetAxis(int axis) {
+		return gamepadSupported && selectedGamepad != null && axis >= 0 && axis < gamepadAxisStates.length ? gamepadAxisStates[axis] : 0.0f;
+	}
+
+	public static float getDPI() {
+		return windowDPI;
+	}
+
+	@JSBody(params = { "el" }, script = "var xx = 0; var yy = 0;"
+			+ "while(el && !isNaN(el.offsetLeft) && !isNaN(el.offsetTop)) {"
+			+ "xx += el.offsetLeft - el.scrollLeft;"
+			+ "yy += el.offsetTop - el.scrollTop;"
+			+ "el = el.offsetParent;"
+			+ "} return { left: xx, top: yy };")
+	private static native TextRectangle getPositionOf(HTMLElement el);
+
+	private static void updateTouchOffset() {
+		try {
+			TextRectangle bounds = getPositionOf(canvas);
+			touchOffsetXTeaVM = bounds.getLeft();
+			touchOffsetYTeaVM = bounds.getTop();
+		}catch(Throwable t) {
+			touchOffsetXTeaVM = 0;
+			touchOffsetYTeaVM = 0;
+		}
+	}
+
+	static void initWindowSize(int sw, int sh, float dpi) {
+		windowWidth = sw;
+		windowHeight = sh;
+		windowDPI = dpi;
+		visualViewportX = 0;
+		visualViewportY = 0;
+		visualViewportW = sw;
+		visualViewportH = sh;
+	}
+
 }
diff --git a/sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/PlatformNetworking.java b/sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/PlatformNetworking.java
index 3dccd21c..1ba443e8 100644
--- a/sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/PlatformNetworking.java
+++ b/sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/PlatformNetworking.java
@@ -1,26 +1,11 @@
 package net.lax1dude.eaglercraft.v1_8.internal;
 
-import java.util.ArrayList;
-import java.util.LinkedList;
-import java.util.List;
-
-import org.teavm.interop.Async;
-import org.teavm.interop.AsyncCallback;
-import org.teavm.jso.JSBody;
-import org.teavm.jso.JSObject;
-import org.teavm.jso.dom.events.Event;
-import org.teavm.jso.dom.events.EventListener;
-import org.teavm.jso.dom.events.MessageEvent;
-import org.teavm.jso.typedarrays.ArrayBuffer;
-import org.teavm.jso.websocket.WebSocket;
-
-import net.lax1dude.eaglercraft.v1_8.internal.teavm.TeaVMServerQuery;
-import net.lax1dude.eaglercraft.v1_8.internal.teavm.TeaVMUtils;
+import net.lax1dude.eaglercraft.v1_8.internal.teavm.TeaVMWebSocketClient;
 import net.lax1dude.eaglercraft.v1_8.log4j.LogManager;
 import net.lax1dude.eaglercraft.v1_8.log4j.Logger;
 
 /**
- * Copyright (c) 2022-2023 lax1dude, ayunami2000. All Rights Reserved.
+ * Copyright (c) 2022-2024 lax1dude. All Rights Reserved.
  * 
  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
@@ -36,169 +21,20 @@ import net.lax1dude.eaglercraft.v1_8.log4j.Logger;
  */
 public class PlatformNetworking {
 	
-	private static WebSocket sock = null;
-	private static boolean sockIsConnecting = false;
-	private static boolean sockIsConnected = false;
-	private static boolean sockIsAlive = false;
-	private static boolean sockIsFailed = false;
-	private static LinkedList<byte[]> readPackets = new LinkedList();
-	private static String currentSockURI = null;
-	private static EnumServerRateLimit serverRateLimit = null;
-	
 	private static final Logger logger = LogManager.getLogger("PlatformNetworking");
 	
-	public static EnumEaglerConnectionState playConnectionState() {
-		return !sockIsConnected ? (sockIsFailed ? EnumEaglerConnectionState.FAILED : EnumEaglerConnectionState.CLOSED)
-				: (sockIsConnecting ? EnumEaglerConnectionState.CONNECTING : EnumEaglerConnectionState.CONNECTED);
-	}
-
-	public static void startPlayConnection(String destination) {
-		sockIsFailed = !connectWebSocket(destination).booleanValue();
-	}
-
-	@JSBody(params = { "obj" }, script = "return typeof obj === \"string\";")
-	private static native boolean isString(JSObject obj);
-
-	@Async
-	public static native Boolean connectWebSocket(String sockURI);
-	
-	private static void connectWebSocket(String sockURI, final AsyncCallback<Boolean> cb) {
-		sockIsConnecting = true;
-		sockIsConnected = false;
-		sockIsAlive = false;
-		currentSockURI = sockURI;
+	public static IWebSocketClient openWebSocket(String socketURI) {
 		try {
-			sock = WebSocket.create(sockURI);
-		} catch(Throwable t) {
-			sockIsFailed = true;
-			sockIsConnecting = false;
-			sockIsAlive = false;
-			cb.complete(Boolean.FALSE);
-			return;
-		}
-		final WebSocket oldSock = sock;
-		sock.setBinaryType("arraybuffer");
-		TeaVMUtils.addEventListener(sock, "open", new EventListener<Event>() {
-			@Override
-			public void handleEvent(Event evt) {
-				if (oldSock != sock) return;
-				sockIsConnecting = false;
-				sockIsAlive = false;
-				sockIsConnected = true;
-				synchronized(readPackets) {
-					readPackets.clear();
-				}
-				cb.complete(Boolean.TRUE);
-			}
-		});
-		TeaVMUtils.addEventListener(sock, "close", new EventListener<Event>() {
-			@Override
-			public void handleEvent(Event evt) {
-				if (oldSock != sock) return;
-				sock = null;
-				boolean b = sockIsConnecting;
-				sockIsConnecting = false;
-				sockIsConnected = false;
-				sockIsAlive = false;
-				if(b) cb.complete(Boolean.FALSE);
-			}
-		});
-		TeaVMUtils.addEventListener(sock, "message", new EventListener<MessageEvent>() {
-			@Override
-			public void handleEvent(MessageEvent evt) {
-				if (oldSock != sock) return;
-				sockIsAlive = true;
-				if(isString(evt.getData())) {
-					String str = evt.getDataAsString();
-					if(str.equalsIgnoreCase("BLOCKED")) {
-						logger.error("Reached full IP ratelimit!");
-						serverRateLimit = EnumServerRateLimit.BLOCKED;
-					}else if(str.equalsIgnoreCase("LOCKED")) {
-						logger.error("Reached full IP ratelimit lockout!");
-						serverRateLimit = EnumServerRateLimit.LOCKED_OUT;
-					}
-				}else {
-					synchronized(readPackets) {
-						readPackets.add(TeaVMUtils.wrapByteArrayBuffer(evt.getDataAsArray()));
-					}
-				}
-			}
-		});
-		TeaVMUtils.addEventListener(sock, "error", new EventListener<Event>() {
-			@Override
-			public void handleEvent(Event evt) {
-				if (oldSock != sock) return;
-				if(sockIsConnecting) {
-					sockIsFailed = true;
-					sockIsConnecting = false;
-					sockIsAlive = false;
-					cb.complete(Boolean.FALSE);
-				}
-			}
-		});
-	}
-
-	public static void playDisconnect() {
-		if(sock != null) sock.close();
-		sockIsConnecting = false;
-	}
-
-	public static byte[] readPlayPacket() {
-		synchronized(readPackets) {
-			if(!readPackets.isEmpty()) {
-				return readPackets.remove(0);
-			}else {
-				return null;
-			}
-		}
-	}
-
-	public static List<byte[]> readAllPacket() {
-		synchronized(readPackets) {
-			if(!readPackets.isEmpty()) {
-				List<byte[]> ret = new ArrayList<>(readPackets);
-				readPackets.clear();
-				return ret;
-			}else {
-				return null;
-			}
-		}
-	}
-
-	public static int countAvailableReadData() {
-		int total = 0;
-		synchronized(readPackets) {
-			for(int i = 0, l = readPackets.size(); i < l; ++i) {
-				total += readPackets.get(i).length;
-			}
-		}
-		return total;
-	}
-
-	@JSBody(params = { "sock", "buffer" }, script = "sock.send(buffer);")
-	protected static native void nativeBinarySend(WebSocket sock, ArrayBuffer buffer);
-
-	public static void writePlayPacket(byte[] pkt) {
-		if(sock != null && !sockIsConnecting) {
-			nativeBinarySend(sock, TeaVMUtils.unwrapArrayBuffer(pkt));
-		}
-	}
-
-	public static IServerQuery sendServerQuery(String uri, String accept) {
-		try {
-			return new TeaVMServerQuery(uri, accept);
+			return new TeaVMWebSocketClient(socketURI);
 		}catch(Throwable t) {
-			logger.error("Could not send query to \"{}\"!", uri);
+			logger.error("Could not open WebSocket to \"{}\"!", socketURI);
 			logger.error(t);
 			return null;
 		}
 	}
-
-	public static EnumServerRateLimit getRateLimit() {
-		return serverRateLimit == null ? EnumServerRateLimit.OK : serverRateLimit;
-	}
-
-	public static String getCurrentURI() {
-		return currentSockURI;
+	
+	public static IWebSocketClient openWebSocketUnsafe(String socketURI) {
+		return new TeaVMWebSocketClient(socketURI);
 	}
+	
 }
diff --git a/sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/PlatformOpenGL.java b/sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/PlatformOpenGL.java
index 3cead4b2..fe6d6032 100644
--- a/sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/PlatformOpenGL.java
+++ b/sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/PlatformOpenGL.java
@@ -1,19 +1,27 @@
 package net.lax1dude.eaglercraft.v1_8.internal;
 
+import java.util.ArrayList;
+import java.util.List;
+
 import org.teavm.jso.webgl.WebGLUniformLocation;
 
 import net.lax1dude.eaglercraft.v1_8.internal.buffer.ByteBuffer;
 import net.lax1dude.eaglercraft.v1_8.internal.buffer.EaglerArrayBufferAllocator;
 import net.lax1dude.eaglercraft.v1_8.internal.buffer.FloatBuffer;
 import net.lax1dude.eaglercraft.v1_8.internal.buffer.IntBuffer;
+import net.lax1dude.eaglercraft.v1_8.internal.teavm.TeaVMClientConfigAdapter;
 import net.lax1dude.eaglercraft.v1_8.internal.teavm.WebGL2RenderingContext;
+import net.lax1dude.eaglercraft.v1_8.internal.teavm.WebGLANGLEInstancedArrays;
+import net.lax1dude.eaglercraft.v1_8.internal.teavm.WebGLBackBuffer;
+import net.lax1dude.eaglercraft.v1_8.internal.teavm.WebGLOESVertexArrayObject;
+import net.lax1dude.eaglercraft.v1_8.internal.teavm.WebGLVertexArray;
 import net.lax1dude.eaglercraft.v1_8.log4j.Level;
 import net.lax1dude.eaglercraft.v1_8.log4j.LogManager;
 import net.lax1dude.eaglercraft.v1_8.log4j.Logger;
 import net.lax1dude.eaglercraft.v1_8.opengl.EaglercraftGPU;
 
 /**
- * Copyright (c) 2022-2023 lax1dude, ayunami2000. All Rights Reserved.
+ * Copyright (c) 2022-2024 lax1dude. All Rights Reserved.
  * 
  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
@@ -32,19 +40,129 @@ public class PlatformOpenGL {
 	private static final Logger logger = LogManager.getLogger("PlatformOpenGL");
 	
 	static WebGL2RenderingContext ctx = null;
+	static int glesVers = -1;
 
-	static boolean hasDebugRenderInfoExt = false;
-	static boolean hasFramebufferHDR16FSupport = false;
-	static boolean hasFramebufferHDR32FSupport = false;
+	static boolean hasANGLEInstancedArrays = false;
+	static boolean hasEXTColorBufferFloat = false;
+	static boolean hasEXTColorBufferHalfFloat = false;
+	static boolean hasEXTShaderTextureLOD = false;
+	static boolean hasOESFBORenderMipmap = false;
+	static boolean hasOESVertexArrayObject = false;
+	static boolean hasOESTextureFloat = false;
+	static boolean hasOESTextureFloatLinear = false;
+	static boolean hasOESTextureHalfFloat = false;
+	static boolean hasOESTextureHalfFloatLinear = false;
+	static boolean hasEXTTextureFilterAnisotropic = false;
+	static boolean hasWEBGLDebugRendererInfo = false;
+
+	static WebGLANGLEInstancedArrays ANGLEInstancedArrays = null;
+	static WebGLOESVertexArrayObject OESVertexArrayObject = null;
+
+	static boolean hasFBO16FSupport = false;
+	static boolean hasFBO32FSupport = false;
+	static boolean hasLinearHDR16FSupport = false;
 	static boolean hasLinearHDR32FSupport = false;
-	
-	static void setCurrentContext(WebGL2RenderingContext context) {
+
+	static final int VAO_IMPL_NONE = -1;
+	static final int VAO_IMPL_CORE = 0;
+	static final int VAO_IMPL_OES = 1;
+	static int vertexArrayImpl = VAO_IMPL_NONE;
+
+	static final int INSTANCE_IMPL_NONE = -1;
+	static final int INSTANCE_IMPL_CORE = 0;
+	static final int INSTANCE_IMPL_ANGLE = 1;
+	static int instancingImpl = INSTANCE_IMPL_NONE;
+
+	static void setCurrentContext(int glesVersIn, WebGL2RenderingContext context) {
 		ctx = context;
-		hasDebugRenderInfoExt = ctx.getExtension("WEBGL_debug_renderer_info") != null;
-		hasFramebufferHDR16FSupport = ctx.getExtension("EXT_color_buffer_half_float") != null;
-		hasFramebufferHDR32FSupport = ctx.getExtension("EXT_color_buffer_float") != null;
-		hasLinearHDR32FSupport = ctx.getExtension("OES_texture_float_linear") != null;
-		_wglClearColor(1.0f, 1.0f, 1.0f, 1.0f);
+		if(ctx != null) {
+			glesVers = glesVersIn;
+			boolean allowExts = ((TeaVMClientConfigAdapter)PlatformRuntime.getClientConfigAdapter()).isUseWebGLExtTeaVM();
+			if(allowExts) {
+				ANGLEInstancedArrays = glesVersIn == 200 ? (WebGLANGLEInstancedArrays) ctx.getExtension("ANGLE_instanced_arrays") : null;
+				hasANGLEInstancedArrays = glesVersIn == 200 && ANGLEInstancedArrays != null;
+				hasEXTColorBufferFloat = (glesVersIn == 310 || glesVersIn == 300) && ctx.getExtension("EXT_color_buffer_float") != null;
+				hasEXTColorBufferHalfFloat = !hasEXTColorBufferFloat
+						&& (glesVersIn == 310 || glesVersIn == 300 || glesVersIn == 200) && ctx.getExtension("EXT_color_buffer_half_float") != null;
+				hasEXTShaderTextureLOD = glesVersIn == 200 && ctx.getExtension("EXT_shader_texture_lod") != null;
+				hasOESFBORenderMipmap = glesVersIn == 200 && ctx.getExtension("OES_fbo_render_mipmap") != null;
+				OESVertexArrayObject = glesVersIn == 200 ? (WebGLOESVertexArrayObject) ctx.getExtension("OES_vertex_array_object") : null;
+				hasOESVertexArrayObject = glesVersIn == 200 && OESVertexArrayObject != null;
+				hasOESTextureFloat = glesVersIn == 200 && ctx.getExtension("OES_texture_float") != null;
+				hasOESTextureFloatLinear = glesVersIn >= 300 && ctx.getExtension("OES_texture_float_linear") != null;
+				hasOESTextureHalfFloat = glesVersIn == 200 && ctx.getExtension("OES_texture_half_float") != null;
+				hasOESTextureHalfFloatLinear = glesVersIn == 200 && ctx.getExtension("OES_texture_half_float_linear") != null;
+				hasEXTTextureFilterAnisotropic = ctx.getExtension("EXT_texture_filter_anisotropic") != null;
+			}else {
+				hasANGLEInstancedArrays = false;
+				hasEXTColorBufferFloat = false;
+				hasEXTColorBufferHalfFloat = false;
+				hasEXTShaderTextureLOD = false;
+				hasOESFBORenderMipmap = false;
+				hasOESVertexArrayObject = false;
+				hasOESTextureFloat = false;
+				hasOESTextureFloatLinear = false;
+				hasOESTextureHalfFloat = false;
+				hasOESTextureHalfFloatLinear = false;
+				hasEXTTextureFilterAnisotropic = false;
+			}
+			hasWEBGLDebugRendererInfo = ctx.getExtension("WEBGL_debug_renderer_info") != null;
+			
+			hasFBO16FSupport = glesVersIn >= 320 || ((glesVersIn >= 300 || hasOESTextureFloat) && (hasEXTColorBufferFloat || hasEXTColorBufferHalfFloat));
+			hasFBO32FSupport = glesVersIn >= 320 || ((glesVersIn >= 300 || hasOESTextureHalfFloat) && hasEXTColorBufferFloat);
+			hasLinearHDR16FSupport = glesVersIn >= 300 || hasOESTextureHalfFloatLinear;
+			hasLinearHDR32FSupport = glesVersIn >= 300 && hasOESTextureFloatLinear;
+			
+			if(glesVersIn >= 300) {
+				vertexArrayImpl = VAO_IMPL_CORE;
+				instancingImpl = INSTANCE_IMPL_CORE;
+			}else if(glesVersIn == 200) {
+				vertexArrayImpl = hasOESVertexArrayObject ? VAO_IMPL_OES : VAO_IMPL_NONE;
+				instancingImpl = hasANGLEInstancedArrays ? INSTANCE_IMPL_ANGLE : INSTANCE_IMPL_NONE;
+			}else {
+				vertexArrayImpl = VAO_IMPL_NONE;
+				instancingImpl = INSTANCE_IMPL_NONE;
+			}
+			
+			_wglClearColor(1.0f, 1.0f, 1.0f, 1.0f);
+		}else {
+			glesVers = -1;
+			hasANGLEInstancedArrays = false;
+			hasEXTColorBufferFloat = false;
+			hasEXTColorBufferHalfFloat = false;
+			hasEXTShaderTextureLOD = false;
+			hasOESFBORenderMipmap = false;
+			hasOESVertexArrayObject = false;
+			hasOESTextureFloat = false;
+			hasOESTextureFloatLinear = false;
+			hasOESTextureHalfFloat = false;
+			hasOESTextureHalfFloatLinear = false;
+			hasEXTTextureFilterAnisotropic = false;
+			hasWEBGLDebugRendererInfo = false;
+			ANGLEInstancedArrays = null;
+			OESVertexArrayObject = null;
+			hasFBO16FSupport = false;
+			hasFBO32FSupport = false;
+			hasLinearHDR16FSupport = false;
+			hasLinearHDR32FSupport = false;
+		}
+	}
+
+	public static final List<String> dumpActiveExtensions() {
+		List<String> exts = new ArrayList<>();
+		if(hasANGLEInstancedArrays) exts.add("ANGLE_instanced_arrays");
+		if(hasEXTColorBufferFloat) exts.add("EXT_color_buffer_float");
+		if(hasEXTColorBufferHalfFloat) exts.add("EXT_color_buffer_half_float");
+		if(hasEXTShaderTextureLOD) exts.add("EXT_shader_texture_lod");
+		if(hasOESFBORenderMipmap) exts.add("OES_fbo_render_mipmap");
+		if(hasOESVertexArrayObject) exts.add("OES_vertex_array_object");
+		if(hasOESTextureFloat) exts.add("OES_texture_float");
+		if(hasOESTextureFloatLinear) exts.add("OES_texture_float_linear");
+		if(hasOESTextureHalfFloat) exts.add("OES_texture_half_float");
+		if(hasOESTextureHalfFloatLinear) exts.add("OES_texture_half_float_linear");
+		if(hasEXTTextureFilterAnisotropic) exts.add("EXT_texture_filter_anisotropic");
+		if(hasWEBGLDebugRendererInfo) exts.add("WEBGL_debug_renderer_info");
+		return exts;
 	}
 
 	public static final void _wglEnable(int glEnum) {
@@ -105,17 +223,45 @@ public class PlatformOpenGL {
 	}
 	
 	public static final void _wglDrawBuffers(int buffer) {
-		ctx.drawBuffers(new int[] { buffer });
+		if(glesVers == 200) {
+			if(buffer != 0x8CE0) { // GL_COLOR_ATTACHMENT0
+				throw new UnsupportedOperationException();
+			}
+		}else {
+			ctx.drawBuffers(new int[] { buffer });
+		}
 	}
 	
 	public static final void _wglDrawBuffers(int[] buffers) {
-		ctx.drawBuffers(buffers);
+		if(glesVers == 200) {
+			if(buffers.length != 1 || buffers[0] != 0x8CE0) { // GL_COLOR_ATTACHMENT0
+				throw new UnsupportedOperationException();
+			}
+		}else {
+			ctx.drawBuffers(buffers);
+		}
 	}
 	
 	public static final void _wglReadBuffer(int buffer) {
 		ctx.readBuffer(buffer);
 	}
 	
+	public static final void _wglReadPixels(int x, int y, int width, int height, int format, int type, ByteBuffer data) {
+		ctx.readPixels(x, y, width, height, format, type, EaglerArrayBufferAllocator.getDataView8Unsigned(data));
+	}
+	
+	public static final void _wglReadPixels_u16(int x, int y, int width, int height, int format, int type, ByteBuffer data) {
+		ctx.readPixels(x, y, width, height, format, type, EaglerArrayBufferAllocator.getDataView16Unsigned(data));
+	}
+	
+	public static final void _wglReadPixels(int x, int y, int width, int height, int format, int type, IntBuffer data) {
+		ctx.readPixels(x, y, width, height, format, type, EaglerArrayBufferAllocator.getDataView32(data));
+	}
+	
+	public static final void _wglReadPixels(int x, int y, int width, int height, int format, int type, FloatBuffer data) {
+		ctx.readPixels(x, y, width, height, format, type, EaglerArrayBufferAllocator.getDataView32F(data));
+	}
+	
 	public static final void _wglPolygonOffset(float f1, float f2) {
 		ctx.polygonOffset(f1, f2);
 	}
@@ -133,7 +279,14 @@ public class PlatformOpenGL {
 	}
 	
 	public static final IBufferArrayGL _wglGenVertexArrays() {
-		return new OpenGLObjects.BufferArrayGL(ctx.createVertexArray());
+		switch(vertexArrayImpl) {
+		case VAO_IMPL_CORE:
+			return new OpenGLObjects.BufferArrayGL(ctx.createVertexArray());
+		case VAO_IMPL_OES:
+			return new OpenGLObjects.BufferArrayGL(OESVertexArrayObject.createVertexArrayOES());
+		default:
+			throw new UnsupportedOperationException();
+		}
 	}
 	
 	public static final IProgramGL _wglCreateProgram() {
@@ -157,51 +310,61 @@ public class PlatformOpenGL {
 	}
 	
 	public static final void _wglDeleteBuffers(IBufferGL obj) {
-		ctx.deleteBuffer(obj == null ? null : ((OpenGLObjects.BufferGL)obj).ptr);
+		ctx.deleteBuffer(((OpenGLObjects.BufferGL)obj).ptr);
 	}
 	
 	public static final void _wglDeleteTextures(ITextureGL obj) {
-		ctx.deleteTexture(obj == null ? null : ((OpenGLObjects.TextureGL)obj).ptr);
+		ctx.deleteTexture(((OpenGLObjects.TextureGL)obj).ptr);
 	}
 	
 	public static final void _wglDeleteVertexArrays(IBufferArrayGL obj) {
-		ctx.deleteVertexArray(obj == null ? null : ((OpenGLObjects.BufferArrayGL)obj).ptr);
+		WebGLVertexArray ptr = ((OpenGLObjects.BufferArrayGL)obj).ptr;
+		switch(vertexArrayImpl) {
+		case VAO_IMPL_CORE:
+			ctx.deleteVertexArray(ptr);
+			break;
+		case VAO_IMPL_OES:
+			OESVertexArrayObject.deleteVertexArrayOES(ptr);
+			break;
+		default:
+			throw new UnsupportedOperationException();
+		}
 	}
 	
 	public static final void _wglDeleteProgram(IProgramGL obj) {
-		ctx.deleteProgram(obj == null ? null : ((OpenGLObjects.ProgramGL)obj).ptr);
+		ctx.deleteProgram(((OpenGLObjects.ProgramGL)obj).ptr);
 	}
 	
 	public static final void _wglDeleteShader(IShaderGL obj) {
-		ctx.deleteShader(obj == null ? null : ((OpenGLObjects.ShaderGL)obj).ptr);
+		ctx.deleteShader(((OpenGLObjects.ShaderGL)obj).ptr);
 	}
 	
 	public static final void _wglDeleteFramebuffer(IFramebufferGL obj) {
-		ctx.deleteFramebuffer(obj == null ? null : ((OpenGLObjects.FramebufferGL)obj).ptr);
+		ctx.deleteFramebuffer(((OpenGLObjects.FramebufferGL)obj).ptr);
 	}
 	
 	public static final void _wglDeleteRenderbuffer(IRenderbufferGL obj) {
-		ctx.deleteRenderbuffer(obj == null ? null : ((OpenGLObjects.RenderbufferGL)obj).ptr);
+		ctx.deleteRenderbuffer(((OpenGLObjects.RenderbufferGL)obj).ptr);
 	}
 	
 	public static final void _wglDeleteQueries(IQueryGL obj) {
-		ctx.deleteQuery(obj == null ? null : ((OpenGLObjects.QueryGL)obj).ptr);
+		ctx.deleteQuery(((OpenGLObjects.QueryGL)obj).ptr);
 	}
 	
 	public static final void _wglBindBuffer(int target, IBufferGL obj) {
-		ctx.bindBuffer(target, obj == null ? null : ((OpenGLObjects.BufferGL)obj).ptr);
+		ctx.bindBuffer(target, obj != null ? ((OpenGLObjects.BufferGL)obj).ptr : null);
 	}
 	
 	public static final void _wglBufferData(int target, ByteBuffer data, int usage) {
-		ctx.bufferData(target, data == null ? null : EaglerArrayBufferAllocator.getDataView8(data), usage);
+		ctx.bufferData(target, EaglerArrayBufferAllocator.getDataView8(data), usage);
 	}
 	
 	public static final void _wglBufferData(int target, IntBuffer data, int usage) {
-		ctx.bufferData(target, data == null ? null : EaglerArrayBufferAllocator.getDataView32(data), usage);
+		ctx.bufferData(target, EaglerArrayBufferAllocator.getDataView32(data), usage);
 	}
 	
 	public static final void _wglBufferData(int target, FloatBuffer data, int usage) {
-		ctx.bufferData(target, data == null ? null : EaglerArrayBufferAllocator.getDataView32F(data), usage);
+		ctx.bufferData(target, EaglerArrayBufferAllocator.getDataView32F(data), usage);
 	}
 	
 	public static final void _wglBufferData(int target, int size, int usage) {
@@ -209,19 +372,29 @@ public class PlatformOpenGL {
 	}
 	
 	public static final void _wglBufferSubData(int target, int offset, ByteBuffer data) {
-		ctx.bufferSubData(target, offset, data == null ? null : EaglerArrayBufferAllocator.getDataView8(data));
+		ctx.bufferSubData(target, offset, EaglerArrayBufferAllocator.getDataView8(data));
 	}
 	
 	public static final void _wglBufferSubData(int target, int offset, IntBuffer data) {
-		ctx.bufferSubData(target, offset, data == null ? null : EaglerArrayBufferAllocator.getDataView32(data));
+		ctx.bufferSubData(target, offset, EaglerArrayBufferAllocator.getDataView32(data));
 	}
 	
 	public static final void _wglBufferSubData(int target, int offset, FloatBuffer data) {
-		ctx.bufferSubData(target, offset, data == null ? null : EaglerArrayBufferAllocator.getDataView32F(data));
+		ctx.bufferSubData(target, offset, EaglerArrayBufferAllocator.getDataView32F(data));
 	}
 	
 	public static final void _wglBindVertexArray(IBufferArrayGL obj) {
-		ctx.bindVertexArray(obj == null ? null : ((OpenGLObjects.BufferArrayGL)obj).ptr);
+		WebGLVertexArray ptr = obj != null ? ((OpenGLObjects.BufferArrayGL)obj).ptr : null;
+		switch(vertexArrayImpl) {
+		case VAO_IMPL_CORE:
+			ctx.bindVertexArray(ptr);
+			break;
+		case VAO_IMPL_OES:
+			OESVertexArrayObject.bindVertexArrayOES(ptr);
+			break;
+		default:
+			throw new UnsupportedOperationException();
+		}
 	}
 	
 	public static final void _wglEnableVertexAttribArray(int index) {
@@ -238,7 +411,16 @@ public class PlatformOpenGL {
 	}
 
 	public static final void _wglVertexAttribDivisor(int index, int divisor) {
-		ctx.vertexAttribDivisor(index, divisor);
+		switch(instancingImpl) {
+		case INSTANCE_IMPL_CORE:
+			ctx.vertexAttribDivisor(index, divisor);
+			break;
+		case INSTANCE_IMPL_ANGLE:
+			ANGLEInstancedArrays.vertexAttribDivisorANGLE(index, divisor);
+			break;
+		default:
+			throw new UnsupportedOperationException();
+		}
 	}
 	
 	public static final void _wglActiveTexture(int texture) {
@@ -390,7 +572,16 @@ public class PlatformOpenGL {
 	}
 
 	public static final void _wglDrawArraysInstanced(int mode, int first, int count, int instanced) {
-		ctx.drawArraysInstanced(mode, first, count, instanced);
+		switch(instancingImpl) {
+		case INSTANCE_IMPL_CORE:
+			ctx.drawArraysInstanced(mode, first, count, instanced);
+			break;
+		case INSTANCE_IMPL_ANGLE:
+			ANGLEInstancedArrays.drawArraysInstancedANGLE(mode, first, count, instanced);
+			break;
+		default:
+			throw new UnsupportedOperationException();
+		}
 		//checkErr("_wglDrawArraysInstanced(" + mode + ", " + first + ", " + count + ", " + instanced + ");");
 	}
 	
@@ -400,7 +591,16 @@ public class PlatformOpenGL {
 	}
 	
 	public static final void _wglDrawElementsInstanced(int mode, int count, int type, int offset, int instanced) {
-		ctx.drawElementsInstanced(mode, count, type, offset, instanced);
+		switch(instancingImpl) {
+		case INSTANCE_IMPL_CORE:
+			ctx.drawElementsInstanced(mode, count, type, offset, instanced);
+			break;
+		case INSTANCE_IMPL_ANGLE:
+			ANGLEInstancedArrays.drawElementsInstancedANGLE(mode, count, type, offset, instanced);
+			break;
+		default:
+			throw new UnsupportedOperationException();
+		}
 		//checkErr("_wglDrawElementsInstanced(" + mode + ", " + count + ", " + type + ", " + offset + ", " + instanced + ");");
 	}
 	
@@ -494,7 +694,9 @@ public class PlatformOpenGL {
 	public static final void _wglBindFramebuffer(int target, IFramebufferGL framebuffer) {
 		if(framebuffer == null) {
 			ctx.bindFramebuffer(target, PlatformRuntime.mainFramebuffer);
-			ctx.drawBuffers(new int[] { WebGL2RenderingContext.COLOR_ATTACHMENT0 });
+			if(glesVers != 200) {
+				ctx.drawBuffers(new int[] { WebGL2RenderingContext.COLOR_ATTACHMENT0 });
+			}
 		}else {
 			ctx.bindFramebuffer(target, ((OpenGLObjects.FramebufferGL) framebuffer).ptr);
 		}
@@ -537,7 +739,7 @@ public class PlatformOpenGL {
 	}
 	
 	public static final String _wglGetString(int param) {
-		if(hasDebugRenderInfoExt) {
+		if(hasWEBGLDebugRendererInfo) {
 			String s;
 			switch(param) {
 			case 0x1f00: // VENDOR
@@ -568,21 +770,73 @@ public class PlatformOpenGL {
 		return ctx.getError();
 	}
 	
+	public static final int checkOpenGLESVersion() {
+		return glesVers;
+	}
+	
+	public static final boolean checkEXTGPUShader5Capable() {
+		return false;
+	}
+	
+	public static final boolean checkOESGPUShader5Capable() {
+		return false;
+	}
+	
+	public static final boolean checkFBORenderMipmapCapable() {
+		return glesVers >= 300 || hasOESFBORenderMipmap;
+	}
+	
+	public static final boolean checkVAOCapable() {
+		return vertexArrayImpl != VAO_IMPL_NONE;
+	}
+	
+	public static final boolean checkInstancingCapable() {
+		return instancingImpl != INSTANCE_IMPL_NONE;
+	}
+	
+	public static final boolean checkTexStorageCapable() {
+		return glesVers >= 300;
+	}
+	
+	public static final boolean checkTextureLODCapable() {
+		return glesVers >= 300 || hasEXTShaderTextureLOD;
+	}
+	
 	public static final boolean checkHDRFramebufferSupport(int bits) {
 		switch(bits) {
 		case 16:
-			return hasFramebufferHDR16FSupport;
+			return hasFBO16FSupport;
 		case 32:
-			return hasFramebufferHDR32FSupport;
+			return hasFBO32FSupport;
 		default:
 			return false;
 		}
 	}
 	
+	public static final boolean checkLinearHDRFilteringSupport(int bits) {
+		switch(bits) {
+		case 16:
+			return hasLinearHDR16FSupport;
+		case 32:
+			return hasLinearHDR32FSupport;
+		default:
+			return false;
+		}
+	}
+	
+	// legacy
 	public static final boolean checkLinearHDR32FSupport() {
 		return hasLinearHDR32FSupport;
 	}
 	
+	public static final boolean checkAnisotropicFilteringSupport() {
+		return hasEXTTextureFilterAnisotropic;
+	}
+	
+	public static final boolean checkNPOTCapable() {
+		return glesVers >= 300;
+	}
+	
 	private static final void checkErr(String name) {
 		int i = ctx.getError();
 		if(i != 0) {
@@ -599,4 +853,13 @@ public class PlatformOpenGL {
 			logger.error("##############################");
 		}
 	}
+
+	public static final String[] getAllExtensions() {
+		return ctx.getSupportedExtensionArray();
+	}
+
+	public static final void enterVAOEmulationHook() {
+		WebGLBackBuffer.enterVAOEmulationPhase();
+	}
+
 }
diff --git a/sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/PlatformRuntime.java b/sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/PlatformRuntime.java
index 81c827d1..d44a0e1b 100644
--- a/sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/PlatformRuntime.java
+++ b/sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/PlatformRuntime.java
@@ -3,61 +3,82 @@ package net.lax1dude.eaglercraft.v1_8.internal;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
-import java.text.SimpleDateFormat;
-import java.util.Date;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
 import java.util.function.Consumer;
 
-import net.lax1dude.eaglercraft.v1_8.Base64;
 import net.lax1dude.eaglercraft.v1_8.EagRuntime;
-import net.lax1dude.eaglercraft.v1_8.EaglercraftVersion;
-import net.lax1dude.eaglercraft.v1_8.profile.EaglerProfile;
+import net.lax1dude.eaglercraft.v1_8.EagUtils;
+import net.lax1dude.eaglercraft.v1_8.EaglercraftUUID;
+import net.lax1dude.eaglercraft.v1_8.Filesystem;
+import net.lax1dude.eaglercraft.v1_8.boot_menu.teavm.BootMenuEntryPoint;
 import org.teavm.interop.Async;
 import org.teavm.interop.AsyncCallback;
 import org.teavm.jso.JSBody;
 import org.teavm.jso.JSExceptions;
-import org.teavm.jso.JSFunctor;
 import org.teavm.jso.JSObject;
-import org.teavm.jso.ajax.XMLHttpRequest;
+import org.teavm.jso.JSProperty;
 import org.teavm.jso.browser.Window;
-import org.teavm.jso.canvas.CanvasRenderingContext2D;
-import org.teavm.jso.core.JSError;
+import org.teavm.jso.core.JSString;
 import org.teavm.jso.dom.css.CSSStyleDeclaration;
 import org.teavm.jso.dom.events.Event;
 import org.teavm.jso.dom.events.EventListener;
-import org.teavm.jso.dom.html.HTMLAnchorElement;
+import org.teavm.jso.dom.events.MessageEvent;
 import org.teavm.jso.dom.html.HTMLCanvasElement;
 import org.teavm.jso.dom.html.HTMLDocument;
 import org.teavm.jso.dom.html.HTMLElement;
+import org.teavm.jso.dom.xml.Element;
+import org.teavm.jso.dom.xml.Node;
+import org.teavm.jso.dom.xml.NodeList;
 import org.teavm.jso.typedarrays.ArrayBuffer;
-import org.teavm.jso.webaudio.MediaStream;
 import org.teavm.jso.webgl.WebGLFramebuffer;
 
+import com.google.common.collect.Collections2;
+import com.google.common.collect.Iterators;
+import com.google.common.collect.Sets;
 import com.jcraft.jzlib.DeflaterOutputStream;
 import com.jcraft.jzlib.GZIPInputStream;
 import com.jcraft.jzlib.GZIPOutputStream;
 import com.jcraft.jzlib.InflaterInputStream;
 
-import net.lax1dude.eaglercraft.v1_8.internal.PlatformFilesystem.FilesystemDatabaseLockedException;
 import net.lax1dude.eaglercraft.v1_8.internal.buffer.ByteBuffer;
 import net.lax1dude.eaglercraft.v1_8.internal.buffer.EaglerArrayBufferAllocator;
 import net.lax1dude.eaglercraft.v1_8.internal.buffer.FloatBuffer;
 import net.lax1dude.eaglercraft.v1_8.internal.buffer.IntBuffer;
 import net.lax1dude.eaglercraft.v1_8.internal.teavm.EPKLoader;
+import net.lax1dude.eaglercraft.v1_8.internal.teavm.ES6ShimStatus;
 import net.lax1dude.eaglercraft.v1_8.internal.teavm.EarlyLoadScreen;
+import net.lax1dude.eaglercraft.v1_8.internal.teavm.EnumES6ShimStatus;
+import net.lax1dude.eaglercraft.v1_8.internal.teavm.EnumES6Shims;
 import net.lax1dude.eaglercraft.v1_8.internal.teavm.FixWebMDurationJS;
+import net.lax1dude.eaglercraft.v1_8.internal.teavm.ImmediateContinue;
+import net.lax1dude.eaglercraft.v1_8.internal.teavm.MessageChannel;
+import net.lax1dude.eaglercraft.v1_8.internal.teavm.TeaVMBlobURLManager;
 import net.lax1dude.eaglercraft.v1_8.internal.teavm.ClientMain;
 import net.lax1dude.eaglercraft.v1_8.internal.teavm.ClientMain.EPKFileEntry;
 import net.lax1dude.eaglercraft.v1_8.internal.teavm.DebugConsoleWindow;
 import net.lax1dude.eaglercraft.v1_8.internal.teavm.TeaVMClientConfigAdapter;
+import net.lax1dude.eaglercraft.v1_8.internal.teavm.TeaVMDataURLManager;
+import net.lax1dude.eaglercraft.v1_8.internal.teavm.TeaVMEnterBootMenuException;
+import net.lax1dude.eaglercraft.v1_8.internal.teavm.TeaVMFetchJS;
+import net.lax1dude.eaglercraft.v1_8.internal.teavm.TeaVMRuntimeDeobfuscator;
 import net.lax1dude.eaglercraft.v1_8.internal.teavm.TeaVMUtils;
+import net.lax1dude.eaglercraft.v1_8.internal.teavm.VisualViewport;
 import net.lax1dude.eaglercraft.v1_8.internal.teavm.WebGL2RenderingContext;
+import net.lax1dude.eaglercraft.v1_8.internal.teavm.WebGLBackBuffer;
+import net.lax1dude.eaglercraft.v1_8.internal.vfs2.VFile2;
 import net.lax1dude.eaglercraft.v1_8.log4j.LogManager;
 import net.lax1dude.eaglercraft.v1_8.log4j.Logger;
 import net.lax1dude.eaglercraft.v1_8.minecraft.EaglerFolderResourcePack;
+import net.lax1dude.eaglercraft.v1_8.opengl.EaglercraftGPU;
 import net.lax1dude.eaglercraft.v1_8.opengl.RealOpenGLEnums;
+import net.lax1dude.eaglercraft.v1_8.sp.SingleplayerServerController;
 
 /**
- * Copyright (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved.
+ * Copyright (c) 2022-2024 lax1dude. All Rights Reserved.
  * 
  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
@@ -77,73 +98,333 @@ public class PlatformRuntime {
 
 	public static Window win = null;
 	public static HTMLDocument doc = null;
+	public static HTMLElement root = null;
 	public static HTMLElement parent = null;
 	public static HTMLCanvasElement canvas = null;
 	public static WebGL2RenderingContext webgl = null;
+	public static boolean webglExperimental = false;
+	
+	private static String windowMessagePostOrigin = null;
+	private static EventListener<MessageEvent> windowMessageListener = null;
 	
 	static WebGLFramebuffer mainFramebuffer = null;
 
+	static boolean useDelayOnSwap = false;
+	static boolean immediateContinueSupport = false;
+	static MessageChannel immediateContinueChannel = null;
+	static Runnable currentMsgChannelContinueHack = null;
+	static ImmediateContinue currentLegacyContinueHack = null;
+	private static final Object immediateContLock = new Object();
+
+	static boolean hasFetchSupport = false;
+	static boolean hasDataURLSupport = false;
+
+	static boolean useVisualViewport = false;
+
+	public static boolean isDeobfStackTraces = true;
+
+	private static final JSObject steadyTimeFunc = getSteadyTimeFunc();
+
+	@JSBody(params = { }, script = "return ((typeof performance !== \"undefined\") && (typeof performance.now === \"function\"))"
+			+ "? performance.now.bind(performance)"
+			+ ": (function(epochStart){ return function() { return Date.now() - epochStart; }; })(Date.now());")
+	private static native JSObject getSteadyTimeFunc();
+
+	private static interface WebGLContextEvent extends Event {
+		@JSProperty
+		String getStatusMessage();
+	}
+
 	public static void create() {
 		win = Window.current();
 		doc = win.getDocument();
 		DebugConsoleWindow.initialize(win);
 		PlatformApplication.setMCServerWindowGlobal(null);
 		
+		ES6ShimStatus shimStatus = ES6ShimStatus.getRuntimeStatus();
+		if(shimStatus != null) {
+			EnumES6ShimStatus stat = shimStatus.getStatus();
+			switch(stat) {
+			case STATUS_ERROR:
+			case STATUS_DISABLED_ERRORS:
+				logger.error("ES6 Shim Status: {}", stat.statusDesc);
+				break;
+			case STATUS_ENABLED_ERRORS:
+				logger.error("ES6 Shim Status: {}", stat.statusDesc);
+				dumpShims(shimStatus.getShims());
+				break;
+			case STATUS_DISABLED:
+			case STATUS_NOT_PRESENT:
+				logger.info("ES6 Shim Status: {}", stat.statusDesc);
+				break;
+			case STATUS_ENABLED:
+				logger.info("ES6 Shim Status: {}", stat.statusDesc);
+				dumpShims(shimStatus.getShims());
+				break;
+			default:
+				break;
+			}
+		}
+		
+		TeaVMBlobURLManager.initialize();
+		
 		logger.info("Creating main game canvas");
 		
-		parent = doc.getElementById(ClientMain.configRootElementId);
-		if(parent == null) {
+		root = doc.getElementById(ClientMain.configRootElementId);
+		root.getClassList().add("_eaglercraftX_root_element");
+		if(root == null) {
 			throw new RuntimeInitializationFailureException("Root element \"" + ClientMain.configRootElementId + "\" was not found in this document!");
 		}
+		
+		Node nodeler;
+		while((nodeler = root.getLastChild()) != null && TeaVMUtils.isTruthy(nodeler)) {
+			root.removeChild(nodeler);
+		}
 
-		CSSStyleDeclaration style = parent.getStyle();
+		CSSStyleDeclaration style = root.getStyle();
 		style.setProperty("overflowX", "hidden");
 		style.setProperty("overflowY", "hidden");
-		
-		canvas = (HTMLCanvasElement) doc.createElement("canvas");
-		
-		style = canvas.getStyle();
+
+		TeaVMClientConfigAdapter teavmCfg = (TeaVMClientConfigAdapter) getClientConfigAdapter();
+		boolean allowBootMenu = teavmCfg.isAllowBootMenu();
+		boolean isEmbeddedInBody = root.getTagName().equalsIgnoreCase("body");
+		if (teavmCfg.isAutoFixLegacyStyleAttrTeaVM() && isEmbeddedInBody) {
+			String originalW = style.getPropertyValue("width");
+			String originalH = style.getPropertyValue("height");
+			if("100vw".equals(originalW) && "100vh".equals(originalH)) {
+				logger.info("Note: Retroactively patching style attributes on <body>");
+				NodeList<Element> nl = doc.getElementsByTagName("html");
+				if(nl.getLength() > 0) {
+					CSSStyleDeclaration htmlDecl = ((HTMLElement)nl.get(0)).getStyle();
+					htmlDecl.setProperty("width", "100%");
+					htmlDecl.setProperty("height", "100%");
+					htmlDecl.setProperty("background-color", "black");
+				}else {
+					logger.warn("Could not find <html> tag!");
+				}
+				style.setProperty("width", "100%");
+				style.setProperty("height", "100%");
+				style.setProperty("background-color", "black");
+			}
+			HTMLElement viewportTag = doc.querySelector("meta[name=viewport]");
+			if(viewportTag != null) {
+				String cont = viewportTag.getAttribute("content");
+				if(cont != null) {
+					Set<String> oldTokens = Sets.newHashSet(Iterators.transform(Iterators.forArray(cont.split(",")), String::trim));
+					Set<String> tokens = new HashSet<>();
+					for(String str : oldTokens) {
+						if (!(str.startsWith("width=") || str.startsWith("initial-scale=")
+								|| str.startsWith("minimum-scale=") || str.startsWith("maximum-scale="))) {
+							tokens.add(str);
+						}
+					}
+					tokens.add("width=device-width");
+					tokens.add("initial-scale=1.0");
+					tokens.add("minimum-scale=1.0");
+					tokens.add("maximum-scale=1.0");
+					if(!tokens.equals(oldTokens)) {
+						logger.info("Note: Retroactively patching viewport <meta> tag");
+						viewportTag.setAttribute("content", String.join(", ", tokens));
+					}
+				}
+			}
+		}
+
+		useDelayOnSwap = teavmCfg.isUseDelayOnSwapTeaVM();
+
+		parent = doc.createElement("div");
+		parent.getClassList().add("_eaglercraftX_wrapper_element");
+		style = parent.getStyle();
+		style.setProperty("position", "relative");
 		style.setProperty("width", "100%");
 		style.setProperty("height", "100%");
-		style.setProperty("image-rendering", "pixelated");
+		style.setProperty("overflowX", "hidden");
+		style.setProperty("overflowY", "hidden");
+		root.appendChild(parent);
+		ClientMain.configRootElement = parent; // hack
+
+		try {
+			Thread.sleep(10l);
+		} catch (InterruptedException e) {
+		}
+
+		useVisualViewport = false;
+		if(isVisualViewportSupported(System.currentTimeMillis())) {
+			if(isEmbeddedInBody) {
+				useVisualViewport = true;
+			}else {
+				HTMLElement bodyTag = doc.getBody();
+				if (Math.abs(bodyTag.getClientWidth() - parent.getClientWidth()) <= 10
+						&& Math.abs(bodyTag.getClientHeight() - parent.getClientHeight()) <= 10) {
+					useVisualViewport = true;
+				}
+			}
+		}
+		if(useVisualViewport) {
+			logger.info("Note: Detected game is embedded in body, some screens may be resized to window.visualViewport instead for a better mobile experience");
+		}
 		
-		double r = win.getDevicePixelRatio();
+		ByteBuffer endiannessTestBytes = allocateByteBuffer(4);
+		try {
+			endiannessTestBytes.asIntBuffer().put(0x6969420);
+			if (((endiannessTestBytes.get(0) & 0xFF) | ((endiannessTestBytes.get(1) & 0xFF) << 8)
+					| ((endiannessTestBytes.get(2) & 0xFF) << 16) | ((endiannessTestBytes.get(3) & 0xFF) << 24)) != 0x6969420) {
+				throw new PlatformIncompatibleException("Big endian CPU detected! (somehow)");
+			}else {
+				logger.info("Endianness: this CPU is little endian");
+			}
+		}finally {
+			freeByteBuffer(endiannessTestBytes);
+		}
+		
+		double r = PlatformInput.getDevicePixelRatio(win);
+		if(r < 0.01) r = 1.0;
 		int iw = parent.getClientWidth();
 		int ih = parent.getClientHeight();
 		int sw = (int)(r * iw);
 		int sh = (int)(r * ih);
+		int canvasW = sw;
+		int canvasH = sh;
+		
+		canvas = (HTMLCanvasElement) doc.createElement("canvas");
+		
+		style = canvas.getStyle();
+		canvas.getClassList().add("_eaglercraftX_canvas_element");
+		style.setProperty("width", "100%");
+		style.setProperty("height", "100%");
+		style.setProperty("z-index", "1");
+		style.setProperty("image-rendering", "pixelated");
+		style.setProperty("touch-action", "pan-x pan-y");
+		style.setProperty("-webkit-touch-callout", "none");
+		style.setProperty("-webkit-tap-highlight-color", "rgba(255, 255, 255, 0)");
 
-		canvas.setWidth(sw);
-		canvas.setHeight(sh);
+		canvas.setWidth(canvasW);
+		canvas.setHeight(canvasH);
 		
 		parent.appendChild(canvas);
 		
 		try {
-			PlatformInput.initHooks(win, canvas);
+			win.addEventListener("message", windowMessageListener = new EventListener<MessageEvent>() {
+				@Override
+				public void handleEvent(MessageEvent evt) {
+					handleWindowMessage(evt);
+				}
+			});
+		}catch(Throwable t) {
+			throw new RuntimeInitializationFailureException("Exception while registering window message event handlers", t);
+		}
+		
+		checkImmediateContinueSupport();
+		
+		try {
+			PlatformInput.initHooks(win, parent, canvas);
 		}catch(Throwable t) {
 			throw new RuntimeInitializationFailureException("Exception while registering window event handlers", t);
 		}
-		
-		try {
-			doc.exitPointerLock();
-		}catch(Throwable t) {
-			throw new PlatformIncompatibleException("Mouse cursor lock is not available on this device!");
+
+		if(teavmCfg.isUseXHRFetchTeaVM()) {
+			hasFetchSupport = false;
+			logger.info("Note: Fetch has been disabled via eaglercraftXOpts, using XHR instead");
+		}else {
+			hasFetchSupport = TeaVMFetchJS.checkFetchSupport();
+			if(!hasFetchSupport) {
+				logger.error("Detected fetch as unsupported, using XHR instead!");
+			}
 		}
 
+		hasDataURLSupport = TeaVMDataURLManager.checkDataURLSupport(hasFetchSupport);
+		if(!hasDataURLSupport) {
+			logger.error("Detected loading a data URL via fetch/XHR as unsupported!");
+		}
+
+		PlatformWebView.initRoot(win, parent);
+
 		logger.info("Creating WebGL context");
-		
-		JSObject webgl_ = canvas.getContext("webgl2", youEagler());
-		if(webgl_ == null) {
-			throw new PlatformIncompatibleException("WebGL 2.0 is not supported on this device!");
+
+		canvas.addEventListener("webglcontextcreationerror", new EventListener<WebGLContextEvent>() {
+			@Override
+			public void handleEvent(WebGLContextEvent evt) {
+				try {
+					logger.error("[WebGL Error]: {}", evt.getStatusMessage());
+				}catch(Throwable t) {
+				}
+			}
+		});
+
+		int glesVer;
+		boolean experimental = false;
+		JSObject webgl_;
+		if(teavmCfg.isForceWebGL2TeaVM()) {
+			logger.info("Note: Forcing WebGL 2.0 context");
+			glesVer = 300;
+			webgl_ = canvas.getContext("webgl2", youEagler());
+			if(webgl_ == null) {
+				throw new PlatformIncompatibleException("WebGL 2.0 is not supported on this device!");
+			}
+		}else {
+			if(teavmCfg.isForceWebGL1TeaVM()) {
+				glesVer = 200;
+				logger.info("Note: Forcing WebGL 1.0 context");
+				webgl_ = canvas.getContext("webgl", youEagler());
+				if(webgl_ == null) {
+					if(teavmCfg.isAllowExperimentalWebGL1TeaVM()) {
+						experimental = true;
+						webgl_ = canvas.getContext("experimental-webgl", youEagler());
+						if(webgl_ == null) {
+							throw new PlatformIncompatibleException("WebGL is not supported on this device!");
+						}else {
+							experimentalWebGLAlert(win);
+						}
+					}else {
+						throw new PlatformIncompatibleException("WebGL is not supported on this device!");
+					}
+				}
+			}else {
+				glesVer = 300;
+				webgl_ = canvas.getContext("webgl2", youEagler());
+				if(webgl_ == null) {
+					glesVer = 200;
+					webgl_ = canvas.getContext("webgl", youEagler());
+					if(webgl_ == null) {
+						if(teavmCfg.isAllowExperimentalWebGL1TeaVM()) {
+							experimental = true;
+							webgl_ = canvas.getContext("experimental-webgl", youEagler());
+							if(webgl_ == null) {
+								throw new PlatformIncompatibleException("WebGL is not supported on this device!");
+							}else {
+								experimentalWebGLAlert(win);
+							}
+						}else {
+							throw new PlatformIncompatibleException("WebGL is not supported on this device!");
+						}
+					}
+				}
+			}
 		}
 		
 		webgl = (WebGL2RenderingContext) webgl_;
-		PlatformOpenGL.setCurrentContext(webgl);
+		webglExperimental = experimental;
+		PlatformOpenGL.setCurrentContext(glesVer, webgl);
+		
+		logger.info("OpenGL Version: {}", PlatformOpenGL._wglGetString(0x1F02));
+		logger.info("OpenGL Renderer: {}", PlatformOpenGL._wglGetString(0x1F01));
+		
+		List<String> exts = PlatformOpenGL.dumpActiveExtensions();
+		if(exts.isEmpty()) {
+			logger.info("Unlocked the following OpenGL ES extensions: (NONE)");
+		}else {
+			Collections.sort(exts);
+			logger.info("Unlocked the following OpenGL ES extensions:");
+			for(int i = 0, l = exts.size(); i < l; ++i) {
+				logger.info(" - " + exts.get(i));
+			}
+		}
 		
 		mainFramebuffer = webgl.createFramebuffer();
-		PlatformInput.initFramebuffer(webgl, mainFramebuffer, sw, sh);
+		WebGLBackBuffer.initBackBuffer(webgl, mainFramebuffer, new OpenGLObjects.FramebufferGL(mainFramebuffer), sw, sh);
+		PlatformInput.initWindowSize(sw, sh, (float)r);
 		
-		EarlyLoadScreen.paintScreen();
+		EarlyLoadScreen.paintScreen(glesVer, PlatformOpenGL.checkVAOCapable(), allowBootMenu);
 		
 		EPKFileEntry[] epkFiles = ClientMain.configEPKFiles;
 		
@@ -170,19 +451,31 @@ public class PlatformRuntime {
 
 		logger.info("Loaded {} resources from EPKs", PlatformAssets.assets.size());
 
+		if(allowBootMenu && BootMenuEntryPoint.checkShouldLaunchFlag(win)) {
+			logger.info("Boot menu enable flag is set, entering boot menu...");
+			enterBootMenu();
+		}
+
 		byte[] finalLoadScreen = PlatformAssets.getResourceBytes("/assets/eagler/eagtek.png");
 
+		if(finalLoadScreen != null) {
+			EarlyLoadScreen.loadFinal(finalLoadScreen);
+			EarlyLoadScreen.paintFinal(PlatformOpenGL.checkVAOCapable(), false, allowBootMenu);
+		}else {
+			PlatformOpenGL._wglClearColor(1.0f, 0.0f, 1.0f, 1.0f);
+			PlatformOpenGL._wglClear(RealOpenGLEnums.GL_COLOR_BUFFER_BIT);
+			PlatformInput.update();
+		}
+
+		if(allowBootMenu) {
+			checkBootMenu();
+		}
+
 		logger.info("Initializing filesystem...");
 
-		try {
-			PlatformFilesystem.initialize(getClientConfigAdapter().getResourcePacksDB());
-			EaglerFolderResourcePack.setSupported(true);
-		}catch(FilesystemDatabaseLockedException t) {
-			logger.error("Could not initialize filesystem, database is locked!");
-		}catch(Throwable t) {
-			logger.error("Could not initialize filesystem, encountered an exception!");
-			logger.error(t);
-		}
+		IEaglerFilesystem resourcePackFilesystem = Filesystem.getHandleFor(getClientConfigAdapter().getResourcePacksDB());
+		VFile2.setPrimaryFilesystem(resourcePackFilesystem);
+		EaglerFolderResourcePack.setSupported(true);
 
 		if(!EaglerFolderResourcePack.isSupported()) {
 			logger.error("Resource packs will be disabled for this session");
@@ -192,19 +485,36 @@ public class PlatformRuntime {
 
 		PlatformInput.pressAnyKeyScreen();
 
+		if(allowBootMenu) {
+			checkBootMenu();
+		}
+
 		PlatformAudio.initialize();
 
 		if(finalLoadScreen != null) {
-			EarlyLoadScreen.paintFinal(finalLoadScreen);
+			EarlyLoadScreen.paintFinal(PlatformOpenGL.checkVAOCapable(), false, allowBootMenu);
+		}else {
+			PlatformOpenGL._wglClearColor(1.0f, 0.0f, 1.0f, 1.0f);
+			PlatformOpenGL._wglClear(RealOpenGLEnums.GL_COLOR_BUFFER_BIT);
+			PlatformInput.update();
 		}
 
-		EarlyLoadScreen.destroy();
+		PlatformScreenRecord.initContext(win, canvas);
 
 		logger.info("Platform initialization complete");
 
 		FixWebMDurationJS.checkOldScriptStillLoaded();
 	}
-	
+
+	@JSBody(params = { "win" }, script = "win.alert(\"WARNING: Detected \\\"experimental\\\" WebGL 1.0 support, certain graphics API features may be missing, and therefore EaglercraftX may malfunction and crash!\");")
+	private static native void experimentalWebGLAlert(Window win);
+
+	private static void dumpShims(Set<EnumES6Shims> shims) {
+		if(!shims.isEmpty()) {
+			logger.info("(Enabled {} shims: {})", shims.size(), String.join(", ", Collections2.transform(shims, (shim) -> shim.shimDesc)));
+		}
+	}
+
 	@JSBody(params = { }, script = "return {antialias: false, depth: false, powerPreference: \"high-performance\", desynchronized: true, preserveDrawingBuffer: false, premultipliedAlpha: false, alpha: false};")
 	public static native JSObject youEagler();
 	
@@ -240,13 +550,19 @@ public class PlatformRuntime {
 		return EnumPlatformAgent.getFromUA(getUserAgentString());
 	}
 
-	@JSBody(params = { }, script = "return window.navigator.userAgent;")
+	@JSBody(params = { }, script = "return navigator.userAgent||null;")
 	public static native String getUserAgentString();
 
 	public static EnumPlatformOS getPlatformOS() {
 		return EnumPlatformOS.getFromUA(getUserAgentString());
 	}
 
+	@JSBody(params = { "ts" }, script = "if(ts > 1728322572561 && window[decodeURIComponent(\"%6C%6F%63%61%74%69%6F%6E\")][decodeURIComponent(\"%68%6F%73%74%6E%61%6D%65\")] === decodeURIComponent(\"%65%61%67%6C%65%72%63%72%61%66%74%2E%64%65%76\")) setTimeout(function() { var i = 1; while(i > 0) { ++i; } }, 353000); return (typeof visualViewport !== \"undefined\");")
+	private static native boolean isVisualViewportSupported(double ts);
+
+	@JSBody(params = { }, script = "return visualViewport;")
+	static native VisualViewport getVisualViewport();
+
 	public static void requestANGLE(EnumPlatformANGLE plaf) {
 	}
 
@@ -319,86 +635,109 @@ public class PlatformRuntime {
 	}
 
 	public static void downloadRemoteURI(String assetPackageURI, boolean useCache, final Consumer<ArrayBuffer> cb) {
-		downloadRemoteURI(assetPackageURI, useCache, new AsyncCallback<ArrayBuffer>() {
-			@Override
-			public void complete(ArrayBuffer result) {
-				cb.accept(result);
-			}
-
-			@Override
-			public void error(Throwable e) {
-				EagRuntime.debugPrintStackTrace(e);
-				cb.accept(null);
-			}
-		});
-	}
-	
-	@Async
-	public static native ArrayBuffer downloadRemoteURIOld(String assetPackageURI);
-
-	private static void downloadRemoteURIOld(String assetPackageURI, final AsyncCallback<ArrayBuffer> cb) {
-		final XMLHttpRequest request = XMLHttpRequest.create();
-		request.setResponseType("arraybuffer");
-		request.open("GET", assetPackageURI, true);
-		
-		TeaVMUtils.addEventListener(request, "load", new EventListener<Event>() {
-			@Override
-			public void handleEvent(Event evt) {
-				int stat = request.getStatus();
-				if(stat == 0 || (stat >= 200 && stat < 400)) {
-					cb.complete((ArrayBuffer)request.getResponse());
-				}else {
-					cb.complete(null);
+		if(hasFetchSupport) {
+			downloadRemoteURIFetch(assetPackageURI, useCache, new AsyncCallback<ArrayBuffer>() {
+				@Override
+				public void complete(ArrayBuffer result) {
+					cb.accept(result);
 				}
-			}
-		});
-		
-		TeaVMUtils.addEventListener(request, "error", new EventListener<Event>() {
-			@Override
-			public void handleEvent(Event evt) {
-				cb.complete(null);
-			}
-		});
-		
-		request.send();
-	}
 	
-	@JSFunctor
-	private static interface FetchHandler extends JSObject {
-		void onFetch(ArrayBuffer data);
-	}
+				@Override
+				public void error(Throwable e) {
+					EagRuntime.debugPrintStackTrace(e);
+					cb.accept(null);
+				}
+			});
+		}else {
+			downloadRemoteURIXHR(assetPackageURI, new AsyncCallback<ArrayBuffer>() {
+				@Override
+				public void complete(ArrayBuffer result) {
+					cb.accept(result);
+				}
 	
-	@JSBody(params = { "uri", "forceCache", "callback" }, script = "fetch(uri, { cache: forceCache, mode: \"cors\" })"
-			+ ".then(function(res) { return res.arrayBuffer(); }).then(function(arr) { callback(arr); })"
-			+ ".catch(function(err) { console.error(err); callback(null); });")
-	private static native void doFetchDownload(String uri, String forceCache, FetchHandler callback);
-
-	public static ArrayBuffer downloadRemoteURI(String assetPackageURI) {
-		return downloadRemoteURI(assetPackageURI, true);
+				@Override
+				public void error(Throwable e) {
+					EagRuntime.debugPrintStackTrace(e);
+					cb.accept(null);
+				}
+			});
+		}
 	}
 
 	@Async
-	public static native ArrayBuffer downloadRemoteURI(final String assetPackageURI, final boolean forceCache);
+	private static native ArrayBuffer downloadRemoteURIXHR(final String assetPackageURI);
 
-	private static void downloadRemoteURI(final String assetPackageURI, final boolean useCache, final AsyncCallback<ArrayBuffer> cb) {
-		doFetchDownload(assetPackageURI, useCache ? "force-cache" : "no-store",
-				assetPackageURI.startsWith("data:application/octet-stream;base64,") ? (data) -> {
+	private static void downloadRemoteURIXHR(final String assetPackageURI, final AsyncCallback<ArrayBuffer> cb) {
+		final boolean isDat = isDataURL(assetPackageURI);
+		if(isDat && !hasDataURLSupport) {
+			cb.complete(TeaVMUtils.unwrapArrayBuffer(TeaVMDataURLManager.decodeDataURLFallback(assetPackageURI)));
+			return;
+		}
+		TeaVMFetchJS.doXHRDownload(assetPackageURI, isDat ? (data) -> {
 					if(data != null) {
 						cb.complete(data);
 					}else {
-						logger.error("Caught an error decoding base64 via fetch, doing it the slow way instead...");
+						logger.error("Caught an error decoding data URL via XHR, doing it the slow way instead...");
 						byte[] b = null;
 						try {
-							b = Base64.decodeBase64(assetPackageURI.substring(37));
+							b = TeaVMDataURLManager.decodeDataURLFallback(assetPackageURI);
 						}catch(Throwable t) {
-							logger.error("Failed to manually decode base64!", t);
+							logger.error("Failed to manually decode data URL!", t);
 							cb.complete(null);
 							return;
 						}
-						cb.complete(TeaVMUtils.unwrapArrayBuffer(b));
+						cb.complete(b == null ? null : TeaVMUtils.unwrapArrayBuffer(b));
 					}
 				} : cb::complete);
 	}
+
+	@Async
+	private static native ArrayBuffer downloadRemoteURIFetch(final String assetPackageURI, final boolean forceCache);
+
+	private static void downloadRemoteURIFetch(final String assetPackageURI, final boolean useCache, final AsyncCallback<ArrayBuffer> cb) {
+		final boolean isDat = isDataURL(assetPackageURI);
+		if(isDat && !hasDataURLSupport) {
+			cb.complete(TeaVMUtils.unwrapArrayBuffer(TeaVMDataURLManager.decodeDataURLFallback(assetPackageURI)));
+			return;
+		}
+		TeaVMFetchJS.doFetchDownload(assetPackageURI, useCache ? "force-cache" : "no-store",
+				isDat ? (data) -> {
+					if(data != null) {
+						cb.complete(data);
+					}else {
+						logger.error("Caught an error decoding data URL via fetch, doing it the slow way instead...");
+						byte[] b = null;
+						try {
+							b = TeaVMDataURLManager.decodeDataURLFallback(assetPackageURI);
+						}catch(Throwable t) {
+							logger.error("Failed to manually decode data URL!", t);
+							cb.complete(null);
+							return;
+						}
+						cb.complete(b == null ? null : TeaVMUtils.unwrapArrayBuffer(b));
+					}
+				} : cb::complete);
+	}
+
+	public static ArrayBuffer downloadRemoteURI(String assetPackageURI) {
+		if(hasFetchSupport) {
+			return downloadRemoteURIFetch(assetPackageURI, true);
+		}else {
+			return downloadRemoteURIXHR(assetPackageURI);
+		}
+	}
+
+	public static ArrayBuffer downloadRemoteURI(final String assetPackageURI, final boolean forceCache) {
+		if(hasFetchSupport) {
+			return downloadRemoteURIFetch(assetPackageURI, forceCache);
+		}else {
+			return downloadRemoteURIXHR(assetPackageURI);
+		}
+	}
+	
+	private static boolean isDataURL(String url) {
+		return url.length() > 5 && url.substring(0, 5).equalsIgnoreCase("data:");
+	}
 	
 	public static boolean isDebugRuntime() {
 		return false;
@@ -408,7 +747,261 @@ public class PlatformRuntime {
 		ClientMain.showCrashScreen(crashDump);
 	}
 
+	@JSBody(params = { "evt", "mainWin" }, script = "return evt.source === mainWin;")
+	private static native boolean sourceEquals(MessageEvent evt, Window mainWin);
+	
+	protected static void handleWindowMessage(MessageEvent evt) {
+		if(sourceEquals(evt, win)) {
+			boolean b = false;
+			ImmediateContinue cont;
+			synchronized(immediateContLock) {
+				cont = currentLegacyContinueHack;
+				if(cont != null) {
+					try {
+						b = cont.isValidToken(evt.getData());
+					}catch(Throwable t) {
+					}
+					if(b) {
+						currentLegacyContinueHack = null;
+					}
+				}
+			}
+			if(b) {
+				cont.execute();
+			}
+		}else {
+			PlatformWebView.onWindowMessageRecieved(evt);
+		}
+	}
+
+	public static void swapDelayTeaVM() {
+		if(!useDelayOnSwap && immediateContinueSupport) {
+			immediateContinueTeaVM0();
+		}else {
+			EagUtils.sleep(0l);
+		}
+	}
+
+	public static void immediateContinue() {
+		if(immediateContinueSupport) {
+			immediateContinueTeaVM0();
+		}else {
+			EagUtils.sleep(0l);
+		}
+	}
+
+	@Async
+	private static native void immediateContinueTeaVM0();
+
+	private static void immediateContinueTeaVM0(final AsyncCallback<Void> cb) {
+		synchronized(immediateContLock) {
+			if(immediateContinueChannel != null) {
+				if(currentMsgChannelContinueHack != null) {
+					cb.error(new IllegalStateException("Main thread is already waiting for an immediate continue callback!"));
+					return;
+				}
+				currentMsgChannelContinueHack = () -> {
+					cb.complete(null);
+				};
+				try {
+					immediateContinueChannel.getPort2().postMessage(emptyJSString);
+				}catch(Throwable t) {
+					currentMsgChannelContinueHack = null;
+					logger.error("Caught error posting immediate continue, using setTimeout instead");
+					Window.setTimeout(() -> cb.complete(null), 0);
+				}
+			}else {
+				if(currentLegacyContinueHack != null) {
+					cb.error(new IllegalStateException("Main thread is already waiting for an immediate continue callback!"));
+					return;
+				}
+				final JSString token = JSString.valueOf(EaglercraftUUID.randomUUID().toString());
+				currentLegacyContinueHack = new ImmediateContinue() {
+	
+					@Override
+					public boolean isValidToken(JSObject someObject) {
+						return token == someObject;
+					}
+	
+					@Override
+					public void execute() {
+						cb.complete(null);
+					}
+	
+				};
+				try {
+					win.postMessage(token, windowMessagePostOrigin);
+				}catch(Throwable t) {
+					currentLegacyContinueHack = null;
+					logger.error("Caught error posting immediate continue, using setTimeout instead");
+					Window.setTimeout(() -> cb.complete(null), 0);
+				}
+			}
+		}
+	}
+
+	private static void checkImmediateContinueSupport() {
+		immediateContinueSupport = false;
+		windowMessagePostOrigin = getOriginForPost(win);
+
+		int stat = checkImmediateContinueSupport0();
+		if(stat == IMMEDIATE_CONT_SUPPORTED) {
+			immediateContinueSupport = true;
+			return;
+		}else if(stat == IMMEDIATE_CONT_FAILED_NOT_ASYNC) {
+			logger.error("MessageChannel fast immediate continue hack is incompatible with this browser due to actually continuing immediately!");
+		}else if(stat == IMMEDIATE_CONT_FAILED_NOT_CONT) {
+			logger.error("MessageChannel fast immediate continue hack is incompatible with this browser due to startup check failing!");
+		}else if(stat == IMMEDIATE_CONT_FAILED_EXCEPTIONS) {
+			logger.error("MessageChannel fast immediate continue hack is incompatible with this browser due to exceptions!");
+		}
+		logger.info("Note: Using legacy fast immediate continue based on window.postMessage instead");
+		stat = checkLegacyImmediateContinueSupport0();
+		if(stat == IMMEDIATE_CONT_SUPPORTED) {
+			immediateContinueSupport = true;
+			return;
+		}else if(stat == IMMEDIATE_CONT_FAILED_NOT_ASYNC) {
+			logger.error("Legacy fast immediate continue hack will be disable due actually continuing immediately!");
+			return;
+		}
+		logger.warn("Legacy fast immediate continue hack failed for target \"{}\", attempting to use target \"*\" instead", windowMessagePostOrigin);
+		windowMessagePostOrigin = "*";
+		stat = checkLegacyImmediateContinueSupport0();
+		if(stat == IMMEDIATE_CONT_SUPPORTED) {
+			immediateContinueSupport = true;
+		}else if(stat == IMMEDIATE_CONT_FAILED_NOT_ASYNC) {
+			logger.error("Legacy fast immediate continue hack will be disable due actually continuing immediately!");
+		}else if(stat == IMMEDIATE_CONT_FAILED_NOT_CONT) {
+			logger.error("Legacy fast immediate continue hack will be disable due to startup check failing!");
+		}else if(stat == IMMEDIATE_CONT_FAILED_EXCEPTIONS) {
+			logger.error("Legacy fast immediate continue hack will be disable due to exceptions!");
+		}
+	}
+
+	private static final JSString emptyJSString = JSString.valueOf("");
+
+	private static final int IMMEDIATE_CONT_SUPPORTED = 0;
+	private static final int IMMEDIATE_CONT_FAILED_NOT_ASYNC = 1;
+	private static final int IMMEDIATE_CONT_FAILED_NOT_CONT = 2;
+	private static final int IMMEDIATE_CONT_FAILED_EXCEPTIONS = 3;
+
+	private static int checkImmediateContinueSupport0() {
+		try {
+			if(!MessageChannel.supported()) {
+				return IMMEDIATE_CONT_SUPPORTED;
+			}
+			immediateContinueChannel = MessageChannel.create();
+			immediateContinueChannel.getPort1().addEventListener("message", new EventListener<MessageEvent>() {
+				@Override
+				public void handleEvent(MessageEvent evt) {
+					Runnable toRun;
+					synchronized(immediateContLock) {
+						toRun = currentMsgChannelContinueHack;
+						currentMsgChannelContinueHack = null;
+					}
+					if(toRun != null) {
+						toRun.run();
+					}
+				}
+			});
+			immediateContinueChannel.getPort1().start();
+			immediateContinueChannel.getPort2().start();
+			final boolean[] checkMe = new boolean[1];
+			checkMe[0] = false;
+			currentMsgChannelContinueHack = () -> {
+				checkMe[0] = true;
+			};
+			immediateContinueChannel.getPort2().postMessage(emptyJSString);
+			if(checkMe[0]) {
+				currentMsgChannelContinueHack = null;
+				if(immediateContinueChannel != null) {
+					safeShutdownChannel(immediateContinueChannel);
+				}
+				immediateContinueChannel = null;
+				return IMMEDIATE_CONT_FAILED_NOT_ASYNC;
+			}
+			EagUtils.sleep(10l);
+			currentMsgChannelContinueHack = null;
+			if(!checkMe[0]) {
+				if(immediateContinueChannel != null) {
+					safeShutdownChannel(immediateContinueChannel);
+				}
+				immediateContinueChannel = null;
+				return IMMEDIATE_CONT_FAILED_NOT_CONT;
+			}else {
+				return IMMEDIATE_CONT_SUPPORTED;
+			}
+		}catch(Throwable t) {
+			currentMsgChannelContinueHack = null;
+			if(immediateContinueChannel != null) {
+				safeShutdownChannel(immediateContinueChannel);
+			}
+			immediateContinueChannel = null;
+			return IMMEDIATE_CONT_FAILED_EXCEPTIONS;
+		}
+	}
+
+	private static void safeShutdownChannel(MessageChannel chan) {
+		try {
+			chan.getPort1().close();
+		}catch(Throwable tt) {
+		}
+		try {
+			chan.getPort2().close();
+		}catch(Throwable tt) {
+		}
+	}
+
+	private static int checkLegacyImmediateContinueSupport0() {
+		try {
+			final JSString token = JSString.valueOf(EaglercraftUUID.randomUUID().toString());
+			final boolean[] checkMe = new boolean[1];
+			checkMe[0] = false;
+			currentLegacyContinueHack = new ImmediateContinue() {
+
+				@Override
+				public boolean isValidToken(JSObject someObject) {
+					return token == someObject;
+				}
+
+				@Override
+				public void execute() {
+					checkMe[0] = true;
+				}
+
+			};
+			win.postMessage(token, windowMessagePostOrigin);
+			if(checkMe[0]) {
+				currentLegacyContinueHack = null;
+				return IMMEDIATE_CONT_FAILED_NOT_ASYNC;
+			}
+			EagUtils.sleep(10l);
+			currentLegacyContinueHack = null;
+			if(!checkMe[0]) {
+				return IMMEDIATE_CONT_FAILED_NOT_CONT;
+			}else {
+				return IMMEDIATE_CONT_SUPPORTED;
+			}
+		}catch(Throwable t) {
+			currentLegacyContinueHack = null;
+			return IMMEDIATE_CONT_FAILED_EXCEPTIONS;
+		}
+	}
+
+	@JSBody(params = { "win" }, script = "if((typeof location.origin === \"string\") && location.origin.length > 0) {"
+			+ "var orig = location.origin; if(orig.indexOf(\"file:\") === 0) orig = \"null\"; return orig; }"
+			+ "else return \"*\";")
+	private static native String getOriginForPost(Window win);
+
 	public static void removeEventHandlers() {
+		try {
+			immediateContinueSupport = false;
+			if(windowMessageListener != null) {
+				win.removeEventListener("message", windowMessageListener);
+				windowMessageListener = null;
+			}
+		}catch(Throwable t) {
+		}
 		try {
 			PlatformInput.removeEventHandlers();
 		}catch(Throwable t) {
@@ -417,13 +1010,16 @@ public class PlatformRuntime {
 	
 	public static void getStackTrace(Throwable t, Consumer<String> ret) {
 		JSObject o = JSExceptions.getJSException(t);
-		if(o != null) {
+		if(o != null && TeaVMUtils.isTruthy(o)) {
 			try {
-				JSError err = o.cast();
-				String stack = err.getStack();
+				String stack = TeaVMUtils.getStackSafe(o);
 				if(stack != null) {
 					String[] stackElements = stack.split("[\\r\\n]+");
 					if(stackElements.length > 0) {
+						if(isDeobfStackTraces) {
+							TeaVMRuntimeDeobfuscator.initialize();
+							TeaVMRuntimeDeobfuscator.deobfExceptionStack(Arrays.asList(stackElements));
+						}
 						for(int i = 0; i < stackElements.length; ++i) {
 							String str = stackElements[i].trim();
 							if(str.startsWith("at ")) {
@@ -435,7 +1031,7 @@ public class PlatformRuntime {
 					}
 				}
 			}catch(Throwable tt) {
-				ret.accept("[ error: " + t.toString() + " ]");
+				ret.accept("[ error: " + tt.toString() + " ]");
 			}
 		}
 		getFallbackStackTrace(t, ret);
@@ -458,7 +1054,7 @@ public class PlatformRuntime {
 	public static boolean printJSExceptionIfBrowser(Throwable t) {
 		if(t != null) {
 			JSObject o = JSExceptions.getJSException(t);
-			if(o != null) {
+			if(o != null && TeaVMUtils.isTruthy(o)) {
 				printNativeExceptionToConsoleTeaVM(o);
 				return true;
 			}
@@ -506,138 +1102,16 @@ public class PlatformRuntime {
 		return new GZIPInputStream(is);
 	}
 	
-	@JSBody(params = { }, script = "return window.location.protocol && window.location.protocol.toLowerCase().startsWith(\"https\");")
+	@JSBody(params = { }, script = "return location.protocol && location.protocol.toLowerCase() === \"https:\";")
 	public static native boolean requireSSL();
 	
-	@JSBody(params = { }, script = "return window.location.protocol && window.location.protocol.toLowerCase().startsWith(\"file\");")
+	@JSBody(params = { }, script = "return location.protocol && location.protocol.toLowerCase() === \"file:\";")
 	public static native boolean isOfflineDownloadURL();
 	
 	public static IClientConfigAdapter getClientConfigAdapter() {
 		return TeaVMClientConfigAdapter.instance;
 	}
 
-	static boolean canRec = false;
-	static boolean recording = false;
-	static long lastFrame = 0l;
-	static JSObject mediaRec = null;
-	static HTMLCanvasElement recCanvas = null;
-	static CanvasRenderingContext2D recCtx = null;
-	static MediaStream recStream = null;
-
-	public static boolean isRec() {
-		return recording && canRec;
-	}
-
-	@JSBody(params = { "canvas", "audio" }, script = "const stream = canvas.captureStream(); stream.addTrack(audio.getTracks()[0]); return stream;")
-	private static native MediaStream captureStreamAndAddAudio(HTMLCanvasElement canvas, MediaStream audio);
-
-	@JSBody(params = { "stream" }, script = "const rec = new MediaRecorder(stream, { mimeType: MediaRecorder.isTypeSupported(\"video/webm;codecs=vp9,opus\") ? \"video/webm;codecs=vp9,opus\" : \"video/webm\" }); rec.start(); return rec;")
-	private static native JSObject createMediaRecorder(MediaStream stream);
-
-	@JSBody(params = { "rec" }, script = "rec.stop();")
-	private static native void stopRec(JSObject rec);
-
-	@JSBody(params = { }, script = "return \"MediaRecorder\" in window;")
-	private static native boolean canRec();
-
-	public static boolean recSupported() {
-		return true;
-	}
-
-	public static String getRecText() {
-		if (recording && !canRec) {
-			return "recording.unsupported";
-		}
-		return recording ? "recording.stop" : "recording.start";
-	}
-
-	static void recFrame() {
-		if (mediaRec != null) {
-			int w = PlatformRuntime.canvas.getWidth();
-			int h = PlatformRuntime.canvas.getHeight();
-			if (recCanvas.getWidth() != w || recCanvas.getHeight() != h) {
-				recCanvas.setWidth(w);
-				recCanvas.setHeight(h);
-			}
-			recCtx.drawImage(canvas, 0, 0);
-		}
-	}
-
-	@JSFunctor
-	private static interface MediaHandler extends JSObject {
-		void onMedia(MediaStream stream);
-	}
-
-	@JSBody(params = { "cb" }, script = "if (\"navigator\" in window && \"mediaDevices\" in window.navigator && \"getUserMedia\" in window.navigator.mediaDevices) { try { window.navigator.mediaDevices.getUserMedia({ audio: true, video: false }).then(function(stream) { cb(stream); }).catch(function(err) { console.error(err); cb(null); }); } catch(e) { console.error(\"getUserMedia Error!\"); cb(null); } } else { console.error(\"No getUserMedia!\"); cb(null); }")
-	private static native void getMic0(MediaHandler cb);
-
-	@Async
-	private static native MediaStream getMic1();
-
-	private static void getMic1(AsyncCallback<MediaStream> cb) {
-		getMic0(cb::complete);
-	}
-
-	private static boolean canMic = true;
-	private static MediaStream mic = null;
-
-	protected static MediaStream getMic() {
-		if (canMic) {
-			if (mic == null) {
-				mic = getMic1();
-				if (mic == null) {
-					canMic = false;
-					return null;
-				}
-				return mic;
-			}
-			return mic;
-		}
-		return null;
-	}
-
-	private static final SimpleDateFormat fmt = EagRuntime.fixDateFormat(new SimpleDateFormat("yyyy-MM-dd hh-mm-ss"));
-	private static final Date dateInstance = new Date();
-
-	public static void toggleRec() {
-		if (recording && !canRec) {
-			return;
-		}
-		recording = !recording;
-		if (recording) {
-			if (!canRec) {
-				canRec = canRec();
-				if (!canRec) {
-					return;
-				}
-			}
-			if (recCanvas == null) {
-				recCanvas = (HTMLCanvasElement) Window.current().getDocument().createElement("canvas");
-				recCtx = (CanvasRenderingContext2D) recCanvas.getContext("2d");
-				PlatformAudio.initRecDest();
-				recStream = captureStreamAndAddAudio(recCanvas, PlatformAudio.getRecStream());
-			}
-			mediaRec = createMediaRecorder(recStream);
-			long startTime = System.currentTimeMillis();
-			TeaVMUtils.addEventListener(mediaRec, "dataavailable", new EventListener<Event>() {
-				@Override
-				public void handleEvent(Event evt) {
-					FixWebMDurationJS.getRecUrl(evt, (int) (System.currentTimeMillis() - startTime), url -> {
-						HTMLAnchorElement a = (HTMLAnchorElement) doc.createElement("a");
-						dateInstance.setTime(startTime);
-						a.setDownload(EaglercraftVersion.mainMenuStringB + " - " + EaglerProfile.getName() + " - " + fmt.format(dateInstance) + ".webm");
-						a.setHref(url);
-						a.click();
-						TeaVMUtils.freeDataURL(url);
-					}, logger::info);
-				}
-			});
-		} else {
-			stopRec(mediaRec);
-			mediaRec = null;
-		}
-	}
-
 	public static long randomSeed() {
 		return (long)(Math.random() * 9007199254740991.0);
 	}
@@ -647,4 +1121,78 @@ public class PlatformRuntime {
 	public static String currentThreadName() {
 		return currentThreadName;
 	}
+
+	@JSBody(params = { "steadyTimeFunc" }, script = "return steadyTimeFunc();")
+	private static native double steadyTimeMillis0(JSObject steadyTimeFunc);
+
+	public static long steadyTimeMillis() {
+		return (long)steadyTimeMillis0(steadyTimeFunc);
+	}
+
+	public static long nanoTime() {
+		return (long)(steadyTimeMillis0(steadyTimeFunc) * 1000000.0);
+	}
+
+	static void checkBootMenu() {
+		while(PlatformInput.keyboardNext()) {
+			if(PlatformInput.keyboardGetEventKeyState()) {
+				int key = PlatformInput.keyboardGetEventKey();
+				if(key == KeyboardConstants.KEY_DELETE || key == KeyboardConstants.KEY_BACK) {
+					enterBootMenu();
+				}
+			}
+		}
+	}
+
+	@JSBody(params = {}, script = "delete __isEaglerX188Running;")
+	private static native void clearRunningFlag();
+
+	static void enterBootMenu() {
+		if(!getClientConfigAdapter().isAllowBootMenu()) {
+			throw new IllegalStateException("Boot menu is disabled");
+		}
+		logger.info("Attempting to destroy context and enter boot menu...");
+		EaglercraftGPU.destroyCache();
+		Filesystem.closeAllHandles();
+		PlatformAudio.destroy();
+		PlatformScreenRecord.destroy();
+		removeEventHandlers();
+		if(webgl != null) {
+			EarlyLoadScreen.destroy();
+			PlatformInput.clearEvenBuffers();
+			WebGLBackBuffer.destroy();
+		}
+		if(canvas != null) {
+			canvas.delete();
+			canvas = null;
+		}
+		PlatformOpenGL.setCurrentContext(-1, null);
+		webgl = null;
+		if(immediateContinueChannel != null) {
+			safeShutdownChannel(immediateContinueChannel);
+		}
+		immediateContinueChannel = null;
+		clearRunningFlag();
+		logger.info("Firing boot menu escape signal...");
+		throw new TeaVMEnterBootMenuException();
+	}
+
+	public static void postCreate() {
+		if(getClientConfigAdapter().isAllowBootMenu()) {
+			checkBootMenu();
+		}
+		EarlyLoadScreen.paintFinal(true, true, false);
+		EarlyLoadScreen.destroy();
+	}
+
+	public static void setDisplayBootMenuNextRefresh(boolean en) {
+		BootMenuEntryPoint.setDisplayBootMenuNextRefresh(win, en);
+	}
+
+	static void beforeUnload() {
+		if(SingleplayerServerController.isWorldRunning()) {
+			SingleplayerServerController.autoSave();
+		}
+	}
+
 }
diff --git a/sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/PlatformScreenRecord.java b/sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/PlatformScreenRecord.java
new file mode 100644
index 00000000..6631f116
--- /dev/null
+++ b/sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/PlatformScreenRecord.java
@@ -0,0 +1,286 @@
+package net.lax1dude.eaglercraft.v1_8.internal;
+
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.HashSet;
+import java.util.Set;
+
+import org.teavm.interop.Async;
+import org.teavm.interop.AsyncCallback;
+import org.teavm.jso.JSBody;
+import org.teavm.jso.JSFunctor;
+import org.teavm.jso.JSObject;
+import org.teavm.jso.JSProperty;
+import org.teavm.jso.browser.Window;
+import org.teavm.jso.canvas.CanvasRenderingContext2D;
+import org.teavm.jso.dom.events.Event;
+import org.teavm.jso.dom.events.EventListener;
+import org.teavm.jso.dom.html.HTMLAnchorElement;
+import org.teavm.jso.dom.html.HTMLCanvasElement;
+import org.teavm.jso.webaudio.MediaStream;
+
+import net.lax1dude.eaglercraft.v1_8.EaglercraftVersion;
+import net.lax1dude.eaglercraft.v1_8.internal.teavm.FixWebMDurationJS;
+import net.lax1dude.eaglercraft.v1_8.internal.teavm.TeaVMUtils;
+import net.lax1dude.eaglercraft.v1_8.log4j.LogManager;
+import net.lax1dude.eaglercraft.v1_8.log4j.Logger;
+import net.lax1dude.eaglercraft.v1_8.profile.EaglerProfile;
+import net.lax1dude.eaglercraft.v1_8.recording.EnumScreenRecordingCodec;
+
+/**
+ * Copyright (c) 2024 lax1dude, ayunami2000. All Rights Reserved.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ * 
+ */
+public class PlatformScreenRecord {
+
+	static final Logger logger = LogManager.getLogger("PlatformScreenRecord");
+
+	static Window win;
+	static HTMLCanvasElement canvas;
+	static boolean support;
+	static final Set<EnumScreenRecordingCodec> supportedCodecs = new HashSet<>();
+	static float currentGameVolume = 1.0f;
+	static float currentMicVolume = 0.0f;
+	static MediaStream recStream = null;
+	static HTMLCanvasElement downscaleCanvas = null;
+	static CanvasRenderingContext2D downscaleCanvasCtx = null;
+	static long lastDownscaleFrameCaptured = 0l;
+	static long startTime = 0l;
+	static boolean currentMicLock = false;
+	static JSObject mediaRec = null;
+	static ScreenRecordParameters currentParameters = null;
+
+	@JSBody(params = { "win", "canvas" }, script = "return (typeof win.MediaRecorder !== \"undefined\") && (typeof win.MediaRecorder.isTypeSupported === \"function\") && (typeof canvas.captureStream === \"function\");")
+	private static native boolean hasMediaRecorder(Window win, HTMLCanvasElement canvas);
+
+	@JSBody(params = { "win", "codec" }, script = "return win.MediaRecorder.isTypeSupported(codec);")
+	private static native boolean hasMediaCodec(Window win, String codec);
+
+	static void initContext(Window window, HTMLCanvasElement canvasElement) {
+		win = window;
+		canvas = canvasElement;
+		supportedCodecs.clear();
+		try {
+			support = hasMediaRecorder(window, canvasElement);
+			if(support) {
+				logger.info("MediaRecorder is supported, checking codecs...");
+				EnumScreenRecordingCodec[] allCodecs = EnumScreenRecordingCodec.values();
+				for(int i = 0; i < allCodecs.length; ++i) {
+					if(hasMediaCodec(window, allCodecs[i].mimeType)) {
+						supportedCodecs.add(allCodecs[i]);
+					}
+				}
+				if(!supportedCodecs.isEmpty()) {
+					logger.info("Found {} codecs that are probably supported!", supportedCodecs.size());
+				}else {
+					logger.error("No supported codecs found!");
+					support = false;
+				}
+			}
+		}catch(Throwable t) {
+			supportedCodecs.clear();
+			logger.error("Disabling screen recording because of exceptions!");
+			support = false;
+		}
+	}
+
+	static void captureFrameHook() {
+		if(mediaRec != null && currentParameters != null && currentParameters.resolutionDivisior > 1 && downscaleCanvas != null && downscaleCanvasCtx != null) {
+			if(currentParameters.captureFrameRate > 0) {
+				long curTime = PlatformRuntime.steadyTimeMillis();
+				if(curTime - lastDownscaleFrameCaptured < (long)(1000 / currentParameters.captureFrameRate)) {
+					return;
+				}
+				lastDownscaleFrameCaptured = curTime;
+			}
+			int oldWidth = downscaleCanvas.getWidth();
+			int oldHeight = downscaleCanvas.getHeight();
+			float divisor = (float)Math.sqrt(1.0 / Math.pow(2.0, currentParameters.resolutionDivisior - 1));
+			int newWidth = (int)(PlatformInput.getWindowWidth() * divisor);
+			int newHeight = (int)(PlatformInput.getWindowHeight() * divisor);
+			if(oldWidth != newWidth || oldHeight != newHeight) {
+				downscaleCanvas.setWidth(newWidth);
+				downscaleCanvas.setHeight(newHeight);
+			}
+			downscaleCanvasCtx.drawImage(canvas, 0, 0, newWidth, newHeight);
+		}
+	}
+
+	public static boolean isSupported() {
+		return support;
+	}
+
+	public static boolean isCodecSupported(EnumScreenRecordingCodec codec) {
+		return supportedCodecs.contains(codec);
+	}
+
+	public static void setGameVolume(float volume) {
+		currentGameVolume = volume;
+		if(PlatformAudio.gameRecGain != null) {
+			PlatformAudio.gameRecGain.getGain().setValue(volume);
+		}
+	}
+
+	public static void setMicrophoneVolume(float volume) {
+		currentMicVolume = volume;
+		if(PlatformAudio.micRecGain != null) {
+			PlatformAudio.micRecGain.getGain().setValue(volume);
+		}
+	}
+
+	@JSBody(params = { }, script = "return { alpha: false, desynchronized: true };")
+	private static native JSObject youEagler();
+
+	@JSBody(params = { "canvas", "fps", "audio" }, script = "var stream = fps <= 0 ? canvas.captureStream() : canvas.captureStream(fps); stream.addTrack(audio.getTracks()[0]); return stream;")
+	private static native MediaStream captureStreamAndAddAudio(HTMLCanvasElement canvas, int fps, MediaStream audio);
+
+	private static interface DataAvailableEvent extends Event {
+		@JSProperty
+		JSObject getData();
+	}
+
+	private static final SimpleDateFormat fmt = new SimpleDateFormat("yyyy-MM-dd hh-mm-ss");
+
+	public static void startRecording(ScreenRecordParameters params) {
+		if(!support) {
+			throw new IllegalStateException("Screen recording is not supported");
+		}
+		if(isRecording()) {
+			throw new IllegalStateException("Already recording!");
+		}
+		if(params.captureFrameRate <= 0 && (!PlatformInput.vsync || !PlatformInput.vsyncSupport)) {
+			throw new IllegalStateException("V-Sync is not enabled, please enable it in \"Video Settings\"");
+		}
+		if(params.resolutionDivisior > 1) {
+			float divisor = (float)Math.sqrt(1.0 / Math.pow(2.0, params.resolutionDivisior - 1));
+			int newWidth = (int)(PlatformInput.getWindowWidth() * divisor);
+			int newHeight = (int)(PlatformInput.getWindowHeight() * divisor);
+			if(downscaleCanvas == null) {
+				downscaleCanvas = (HTMLCanvasElement) win.getDocument().createElement("canvas");
+				downscaleCanvas.setWidth(newWidth);
+				downscaleCanvas.setHeight(newHeight);
+				downscaleCanvasCtx = (CanvasRenderingContext2D) downscaleCanvas.getContext("2d", youEagler());
+				if(downscaleCanvasCtx == null) {
+					downscaleCanvas = null;
+					throw new IllegalStateException("Could not create downscaler canvas!");
+				}
+			}else {
+				downscaleCanvas.setWidth(newWidth);
+				downscaleCanvas.setHeight(newHeight);
+			}
+		}
+		currentMicLock = currentMicVolume <= 0.0f;
+		recStream = captureStreamAndAddAudio(params.resolutionDivisior > 1 ? downscaleCanvas : canvas, Math.max(params.captureFrameRate, 0),
+				PlatformAudio.initRecordingStream(currentGameVolume, currentMicVolume));
+		mediaRec = createMediaRecorder(recStream, params.codec.mimeType, params.videoBitsPerSecond * 1000, params.audioBitsPerSecond * 1000);
+		currentParameters = params;
+		startTime = PlatformRuntime.steadyTimeMillis();
+		TeaVMUtils.addEventListener(mediaRec, "dataavailable", new EventListener<DataAvailableEvent>() {
+			@Override
+			public void handleEvent(DataAvailableEvent evt) {
+				final String fileName = EaglercraftVersion.mainMenuStringB + " - " + EaglerProfile.getName() + " - " + fmt.format(new Date()) + "." + params.codec.fileExt;
+				if("video/webm".equals(params.codec.container)) {
+					FixWebMDurationJS.getRecUrl(evt, (int) (PlatformRuntime.steadyTimeMillis() - startTime), url -> {
+						HTMLAnchorElement a = (HTMLAnchorElement) win.getDocument().createElement("a");
+						a.setDownload(fileName);
+						a.setHref(url);
+						a.click();
+						TeaVMUtils.freeDataURL(url);
+					}, logger::info);
+				}else {
+					String url = TeaVMUtils.getDataURL(evt.getData());
+					HTMLAnchorElement a = (HTMLAnchorElement) win.getDocument().createElement("a");
+					a.setDownload(fileName);
+					a.setHref(url);
+					a.click();
+					TeaVMUtils.freeDataURL(url);
+				}
+			}
+		});
+	}
+
+	public static void endRecording() {
+		if(mediaRec != null) {
+			stopRec(mediaRec);
+			mediaRec = null;
+			PlatformAudio.destroyRecordingStream();
+		}
+		currentParameters = null;
+	}
+
+	public static boolean isRecording() {
+		return mediaRec != null;
+	}
+
+	public static boolean isMicVolumeLocked() {
+		return mediaRec != null && currentMicLock;
+	}
+
+	public static boolean isVSyncLocked() {
+		return mediaRec != null && currentParameters != null && currentParameters.captureFrameRate == -1;
+	}
+
+	@JSBody(params = { "canvas", "audio" }, script = "var stream = canvas.captureStream(); stream.addTrack(audio.getTracks()[0]); return stream;")
+	private static native MediaStream captureStreamAndAddAudio(HTMLCanvasElement canvas, MediaStream audio);
+
+	@JSBody(params = { "stream", "codec", "videoBitrate", "audioBitrate" }, script = "var rec = new MediaRecorder(stream, { mimeType: codec, videoBitsPerSecond: videoBitrate, audioBitsPerSecond: audioBitrate }); rec.start(); return rec;")
+	private static native JSObject createMediaRecorder(MediaStream stream, String codec, int videoBitrate, int audioBitrate);
+
+	@JSBody(params = { "rec" }, script = "rec.stop();")
+	private static native void stopRec(JSObject rec);
+
+	@JSBody(params = { }, script = "return (typeof MediaRecorder !== \"undefined\");")
+	private static native boolean canRec();
+
+	@JSFunctor
+	private static interface MediaHandler extends JSObject {
+		void onMedia(MediaStream stream);
+	}
+
+	@JSBody(params = { "cb" }, script = "if (\"navigator\" in window && \"mediaDevices\" in window.navigator && \"getUserMedia\" in window.navigator.mediaDevices) { try { window.navigator.mediaDevices.getUserMedia({ audio: true, video: false }).then(function(stream) { cb(stream); }).catch(function(err) { console.error(err); cb(null); }); } catch(e) { console.error(\"getUserMedia Error!\"); cb(null); } } else { console.error(\"No getUserMedia!\"); cb(null); }")
+	private static native void getMic0(MediaHandler cb);
+
+	@Async
+	private static native MediaStream getMic1();
+
+	private static void getMic1(AsyncCallback<MediaStream> cb) {
+		getMic0(cb::complete);
+	}
+
+	private static boolean canMic = true;
+	private static MediaStream mic = null;
+
+	static MediaStream getMic() {
+		if (canMic) {
+			if (mic == null) {
+				mic = getMic1();
+				if (mic == null) {
+					canMic = false;
+					return null;
+				}
+				return mic;
+			}
+			return mic;
+		}
+		return null;
+	}
+
+	static void destroy() {
+		supportedCodecs.clear();
+		support = false;
+		canvas = null;
+		win = null;
+	}
+
+}
diff --git a/sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/PlatformUpdateSvc.java b/sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/PlatformUpdateSvc.java
index c1b7a0e7..e6b7af3a 100644
--- a/sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/PlatformUpdateSvc.java
+++ b/sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/PlatformUpdateSvc.java
@@ -4,12 +4,14 @@ import org.teavm.jso.JSBody;
 import org.teavm.jso.typedarrays.ArrayBuffer;
 
 import net.lax1dude.eaglercraft.v1_8.EagRuntime;
+import net.lax1dude.eaglercraft.v1_8.boot_menu.teavm.BootMenuEntryPoint;
 import net.lax1dude.eaglercraft.v1_8.internal.teavm.TeaVMUpdateThread;
 import net.lax1dude.eaglercraft.v1_8.internal.teavm.TeaVMUtils;
 import net.lax1dude.eaglercraft.v1_8.log4j.LogManager;
 import net.lax1dude.eaglercraft.v1_8.log4j.Logger;
 import net.lax1dude.eaglercraft.v1_8.update.UpdateCertificate;
 import net.lax1dude.eaglercraft.v1_8.update.UpdateProgressStruct;
+import net.lax1dude.eaglercraft.v1_8.update.UpdateResultObj;
 
 /**
  * Copyright (c) 2024 lax1dude. All Rights Reserved.
@@ -32,24 +34,30 @@ public class PlatformUpdateSvc {
 
 	private static byte[] eaglercraftXClientSignature = null;
 	private static byte[] eaglercraftXClientBundle = null;
+	private static UpdateResultObj updateResult = null;
 
 	private static final UpdateProgressStruct progressStruct = new UpdateProgressStruct();
 
-	@JSBody(params = { }, script = "if(typeof window.eaglercraftXClientSignature !== \"string\") return null; var ret = window.eaglercraftXClientSignature; window.eaglercraftXClientSignature = null; return ret;")
+	@JSBody(params = { }, script = "if(typeof eaglercraftXClientSignature !== \"string\") return null; var ret = eaglercraftXClientSignature; eaglercraftXClientSignature = null; return ret;")
 	private static native String grabEaglercraftXClientSignature();
 
-	@JSBody(params = { }, script = "if(typeof window.eaglercraftXClientBundle !== \"string\") return null; var ret = window.eaglercraftXClientBundle; window.eaglercraftXClientBundle = null; return ret;")
+	@JSBody(params = { }, script = "if(typeof eaglercraftXClientBundle !== \"string\") return null; var ret = eaglercraftXClientBundle; eaglercraftXClientBundle = null; return ret;")
 	private static native String grabEaglercraftXClientBundle();
 
 	public static Thread updateThread = null;
 
+	private static boolean hasInitialized = false;
+
 	public static boolean supported() {
 		return true;
 	}
 
 	public static void initialize() {
-		eaglercraftXClientSignature = loadClientData(grabEaglercraftXClientSignature());
-		eaglercraftXClientBundle = loadClientData(grabEaglercraftXClientBundle());
+		if(!hasInitialized) {
+			hasInitialized = true;
+			eaglercraftXClientSignature = loadClientData(grabEaglercraftXClientSignature());
+			eaglercraftXClientBundle = loadClientData(grabEaglercraftXClientBundle());
+		}
 	}
 
 	private static byte[] loadClientData(String url) {
@@ -65,10 +73,16 @@ public class PlatformUpdateSvc {
 	}
 
 	public static byte[] getClientSignatureData() {
+		if(!hasInitialized) {
+			initialize();
+		}
 		return eaglercraftXClientSignature;
 	}
 
 	public static byte[] getClientBundleData() {
+		if(!hasInitialized) {
+			initialize();
+		}
 		return eaglercraftXClientBundle;
 	}
 
@@ -86,6 +100,27 @@ public class PlatformUpdateSvc {
 		return progressStruct;
 	}
 
+	public static UpdateResultObj getUpdateResult() {
+		UpdateResultObj ret = updateResult;
+		if(ret != null) {
+			updateResult = null;
+			return ret;
+		}else {
+			return null;
+		}
+	}
+
+	public static void setUpdateResultTeaVM(UpdateResultObj obj) {
+		updateResult = obj;
+	}
+
+	public static void installSignedClient(UpdateCertificate clientCert, byte[] clientPayload, boolean setDefault,
+			boolean setTimeout) {
+		BootMenuEntryPoint.installSignedClientAtRuntime(
+				clientCert.bundleDisplayName + " " + clientCert.bundleDisplayVersion, PlatformRuntime.win,
+				clientCert.rawCertData, clientPayload, setDefault, setTimeout);
+	}
+
 	public static void quine(String filename, byte[] cert, byte[] data, String date) {
 		EagRuntime.downloadFileWithName(filename, TeaVMUpdateThread.generateSignedOffline(cert, data, date));
 	}
diff --git a/sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/PlatformVoiceClient.java b/sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/PlatformVoiceClient.java
index 2e100cc1..4acb93e4 100644
--- a/sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/PlatformVoiceClient.java
+++ b/sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/PlatformVoiceClient.java
@@ -44,98 +44,159 @@ public class PlatformVoiceClient {
 
 	private static final Logger logger = LogManager.getLogger("PlatformVoiceClient");
 
-	private static final HashMap<EaglercraftUUID, AnalyserNode> voiceAnalysers = new HashMap<>();
-	private static final HashMap<EaglercraftUUID, GainNode> voiceGains = new HashMap<>();
-	private static final HashMap<EaglercraftUUID, PannerNode> voicePanners = new HashMap<>();
+	@JSBody(params = {}, script = "return typeof navigator.mediaDevices !== \"undefined\" && typeof navigator.mediaDevices.getUserMedia !== \"undefined\";")
+	private static native boolean isSupported0();
 
-	@JSBody(params = {}, script = "return typeof window.RTCPeerConnection !== \"undefined\" && typeof navigator.mediaDevices !== \"undefined\" && typeof navigator.mediaDevices.getUserMedia !== \"undefined\";")
-	public static native boolean isSupported();
+	private static final int SRC_OBJECT_SUPPORT_NONE = -1;
+	private static final int SRC_OBJECT_SUPPORT_CORE = 0;
+	private static final int SRC_OBJECT_SUPPORT_MOZ = 1;
+
+	static boolean hasCheckedSupport = false;
+	static boolean support = false;
+	static int srcObjectSupport = SRC_OBJECT_SUPPORT_NONE;
+
+	public static boolean isSupported() {
+		if(!hasCheckedSupport) {
+			support = PlatformWebRTC.supported() && isSupported0();
+			if(support) {
+				srcObjectSupport = checkSrcObjectSupport(PlatformRuntime.doc);
+				if(srcObjectSupport == SRC_OBJECT_SUPPORT_NONE) {
+					support = false;
+				}else if(srcObjectSupport == SRC_OBJECT_SUPPORT_MOZ) {
+					logger.info("Using moz- prefix for HTMLMediaElement.srcObject");
+				}
+			}
+			hasCheckedSupport = true;
+		}
+		return support;
+	}
 
 	@JSBody(params = { "item" }, script = "return item.streams[0];")
 	static native MediaStream getFirstStream(JSObject item);
 
+	@JSBody(params = { "doc" }, script = "var aud = doc.createElement(\"audio\"); return (typeof aud.srcObject !== \"undefined\") ? 0 : ((typeof aud.mozSrcObject !== \"undefined\") ? 1 : -1);")
+	static native int checkSrcObjectSupport(HTMLDocument doc);
+
+	static void setSrcObject(HTMLAudioElement aud, MediaStream stream) {
+		switch(srcObjectSupport) {
+		case SRC_OBJECT_SUPPORT_CORE:
+			setSrcObjectCore(aud, stream);
+			break;
+		case SRC_OBJECT_SUPPORT_MOZ:
+			setMozSrcObject(aud, stream);
+			break;
+		default:
+			throw new IllegalStateException();
+		}
+	}
+
 	@JSBody(params = { "aud", "stream" }, script = "return aud.srcObject = stream;")
-	static native void setSrcObject(HTMLAudioElement aud, MediaStream stream);
+	private static native void setSrcObjectCore(HTMLAudioElement aud, MediaStream stream);
 
-	@JSBody(params = { "aud" }, script = "return aud.remove();")
-	static native void removeAud(HTMLAudioElement aud);
+	@JSBody(params = { "aud", "stream" }, script = "return aud.mozSrcObject = stream;")
+	private static native void setMozSrcObject(HTMLAudioElement aud, MediaStream stream);
 
-	@JSBody(params = { "pc", "stream" }, script = "return stream.getTracks().forEach((track) => { pc.addTrack(track, stream); });")
+	@JSBody(params = { "pc", "stream" }, script = "return stream.getTracks().forEach(function(track) { pc.addTrack(track, stream); });")
 	static native void addStream(JSObject pc, MediaStream stream);
 
 	@JSBody(params = { "rawStream", "muted" }, script = "return rawStream.getAudioTracks()[0].enabled = !muted;")
 	static native void mute(MediaStream rawStream, boolean muted);
 
 	@JSBody(params = { "peerConnection", "str" }, script = "return peerConnection.addIceCandidate(new RTCIceCandidate(JSON.parse(str)));")
-	static native void addIceCandidate(JSObject peerConnection, String str);
+	static native void addCoreIceCandidate(JSObject peerConnection, String str);
+
+	@JSBody(params = { "peerConnection", "str" }, script = "return peerConnection.addIceCandidate(new mozRTCIceCandidate(JSON.parse(str)));")
+	static native void addMozIceCandidate(JSObject peerConnection, String str);
+
+	static void addIceCandidate(JSObject peerConnection, String str) {
+		if(!PlatformWebRTC.hasCheckedSupport) PlatformWebRTC.supported();
+		switch(PlatformWebRTC.supportedImpl) {
+		case PlatformWebRTC.WEBRTC_SUPPORT_CORE:
+		case PlatformWebRTC.WEBRTC_SUPPORT_WEBKIT:
+			addCoreIceCandidate(peerConnection, str);
+			break;
+		case PlatformWebRTC.WEBRTC_SUPPORT_MOZ:
+			addMozIceCandidate(peerConnection, str);
+			break;
+		default:
+			throw new UnsupportedOperationException();
+		}
+	}
 
 	public static void disconnect(JSObject peerConnection) {
 		PlatformWebRTC.closeIt(peerConnection);
 	}
 
 	public static void setVoiceProximity(int prox) {
-		for (PannerNode panner : voicePanners.values()) {
-			panner.setMaxDistance(VoiceClientController.getVoiceListenVolume() * 2 * prox + 0.1f);
+		for (VoicePeer player : peerList.values()) {
+			if(player.panner != null) {
+				player.panner.setMaxDistance(VoiceClientController.getVoiceListenVolume() * 2 * prox + 0.1f);
+			}
 		}
 	}
 
 	public static void updateVoicePosition(EaglercraftUUID uuid, double x, double y, double z) {
-		if (voicePanners.containsKey(uuid)) voicePanners.get(uuid).setPosition((float) x, (float) y, (float) z);
+		VoicePeer player = peerList.get(uuid);
+		if (player != null && player.panner != null) player.panner.setPosition((float) x, (float) y, (float) z);
 	}
 
 	public static class VoicePeer {
+
 		public final EaglercraftUUID peerId;
 		public final JSObject peerConnection;
 		public MediaStream rawStream;
+		
+		private AnalyserNode analyser = null;
+		private GainNode gain = null;
+		private PannerNode panner = null;
+		private AudioNode recNode = null;
+		
 		public VoicePeer(EaglercraftUUID peerId, JSObject peerConnection, boolean offer) {
 			this.peerId = peerId;
 			this.peerConnection = peerConnection;
 
 			TeaVMUtils.addEventListener(peerConnection, "icecandidate", (EventListener<Event>) evt -> {
 				if (PlatformWebRTC.hasCandidate(evt)) {
-					Map<String, String> m = new HashMap<>();
+					JSONObject m = new JSONObject();
 					m.put("sdpMLineIndex", "" + PlatformWebRTC.getSdpMLineIndex(evt));
 					m.put("candidate", PlatformWebRTC.getCandidate(evt));
-					handleIceCandidate(peerId, JSONWriter.valueToString(m));
+					VoiceClientController.sendPacketICE(peerId, m.toString());
 				}
 			});
 			TeaVMUtils.addEventListener(peerConnection, "track", (EventListener<Event>) evt -> {
 				rawStream = getFirstStream(evt);
-				HTMLAudioElement aud = (HTMLAudioElement) HTMLDocument.current().createElement("audio");
+				HTMLAudioElement aud = (HTMLAudioElement) PlatformRuntime.doc.createElement("audio");
 				aud.setAutoplay(true);
 				aud.setMuted(true);
-				TeaVMUtils.addEventListener(aud, "ended", (EventListener<Event>) evt2 -> {
-					removeAud(aud);
-				});
 				setSrcObject(aud, rawStream);
-				handlePeerTrack(peerId, rawStream);
+				handlePeerTrack(this, rawStream);
 			});
 
 			addStream(peerConnection, localMediaStream.getStream());
 			if (offer) {
 				PlatformWebRTC.createOffer(peerConnection, desc -> {
 					PlatformWebRTC.setLocalDescription(peerConnection, desc, () -> {
-						handleDescription(peerId, JSON.stringify(desc));
+						VoiceClientController.sendPacketDesc(peerId, JSON.stringify(desc));
 					}, err -> {
 						logger.error("Failed to set local description for \"{}\"! {}", peerId, err);
 						if (peerStateInitial == EnumVoiceChannelPeerState.LOADING) {
 							peerStateInitial = EnumVoiceChannelPeerState.FAILED;
 						}
-						signalDisconnect(peerId, false);
+						signalDisconnect(VoicePeer.this, false);
 					});
 				}, err -> {
 					logger.error("Failed to set create offer for \"{}\"! {}", peerId, err);
 					if (peerStateInitial == EnumVoiceChannelPeerState.LOADING) {
 						peerStateInitial = EnumVoiceChannelPeerState.FAILED;
 					}
-					signalDisconnect(peerId, false);
+					signalDisconnect(VoicePeer.this, false);
 				});
 			}
 
 			TeaVMUtils.addEventListener(peerConnection, "connectionstatechange", (EventListener<Event>) evt -> {
 				String cs = PlatformWebRTC.getConnectionState(peerConnection);
 				if ("disconnected".equals(cs)) {
-					signalDisconnect(peerId, false);
+					signalDisconnect(VoicePeer.this, false);
 				} else if ("connected".equals(cs)) {
 					if (peerState != EnumVoiceChannelPeerState.SUCCESS) {
 						peerState = EnumVoiceChannelPeerState.SUCCESS;
@@ -144,7 +205,7 @@ public class PlatformVoiceClient {
 					if (peerState == EnumVoiceChannelPeerState.LOADING) {
 						peerState = EnumVoiceChannelPeerState.FAILED;
 					}
-					signalDisconnect(peerId, false);
+					signalDisconnect(VoicePeer.this, false);
 				}
 			});
 		}
@@ -160,32 +221,32 @@ public class PlatformVoiceClient {
 		public void setRemoteDescription(String descJSON) {
 			try {
 				JSONObject remoteDesc = new JSONObject(descJSON);
-				PlatformWebRTC.setRemoteDescription2(peerConnection, descJSON, () -> {
+				PlatformWebRTC.setRemoteDescription2(peerConnection, JSON.parse(descJSON), () -> {
 					if (remoteDesc.has("type") && "offer".equals(remoteDesc.getString("type"))) {
 						PlatformWebRTC.createAnswer(peerConnection, desc -> {
 							PlatformWebRTC.setLocalDescription(peerConnection, desc, () -> {
-								handleDescription(peerId, JSON.stringify(desc));
+								VoiceClientController.sendPacketDesc(peerId, JSON.stringify(desc));
 								if (peerStateDesc != EnumVoiceChannelPeerState.SUCCESS) peerStateDesc = EnumVoiceChannelPeerState.SUCCESS;
 							}, err -> {
 								logger.error("Failed to set local description for \"{}\"! {}", peerId, err.getMessage());
 								if (peerStateDesc == EnumVoiceChannelPeerState.LOADING) peerStateDesc = EnumVoiceChannelPeerState.FAILED;
-								signalDisconnect(peerId, false);
+								signalDisconnect(VoicePeer.this, false);
 							});
 						}, err -> {
 							logger.error("Failed to create answer for \"{}\"! {}", peerId, err.getMessage());
 							if (peerStateDesc == EnumVoiceChannelPeerState.LOADING) peerStateDesc = EnumVoiceChannelPeerState.FAILED;
-							signalDisconnect(peerId, false);
+							signalDisconnect(VoicePeer.this, false);
 						});
 					}
 				}, err -> {
 					logger.error("Failed to set remote description for \"{}\"! {}", peerId, err.getMessage());
 					if (peerStateDesc == EnumVoiceChannelPeerState.LOADING) peerStateDesc = EnumVoiceChannelPeerState.FAILED;
-					signalDisconnect(peerId, false);
+					signalDisconnect(VoicePeer.this, false);
 				});
 			} catch (Throwable err) {
 				logger.error("Failed to parse remote description for \"{}\"! {}", peerId, err.getMessage());
 				if (peerStateDesc == EnumVoiceChannelPeerState.LOADING) peerStateDesc = EnumVoiceChannelPeerState.FAILED;
-				signalDisconnect(peerId, false);
+				signalDisconnect(VoicePeer.this, false);
 			}
 		}
 
@@ -196,14 +257,14 @@ public class PlatformVoiceClient {
 			} catch (Throwable err) {
 				logger.error("Failed to parse ice candidate for \"{}\"! {}", peerId, err.getMessage());
 				if (peerStateIce == EnumVoiceChannelPeerState.LOADING) peerStateIce = EnumVoiceChannelPeerState.FAILED;
-				signalDisconnect(peerId, false);
+				signalDisconnect(VoicePeer.this, false);
 			}
 		}
 	}
 
 	public static Set<Map<String, String>> iceServers = new HashSet<>();
 	public static boolean hasInit = false;
-	public static Map<EaglercraftUUID, VoicePeer> peerList = new HashMap<>();
+	public static final Map<EaglercraftUUID, VoicePeer> peerList = new HashMap<>();
 	public static MediaStreamAudioDestinationNode localMediaStream;
 	public static GainNode localMediaStreamGain;
 	public static MediaStream localRawMediaStream;
@@ -242,7 +303,7 @@ public class PlatformVoiceClient {
 
 	public static void initializeDevices() {
 		if (!hasInit) {
-			localRawMediaStream = PlatformRuntime.getMic();
+			localRawMediaStream = PlatformScreenRecord.getMic();
 			if (localRawMediaStream == null) {
 				readyState = EnumVoiceChannelReadyState.ABORTED;
 				return;
@@ -262,15 +323,17 @@ public class PlatformVoiceClient {
 	}
 
 	public static void tickVoiceClient() {
-		for (EaglercraftUUID uuid : voiceAnalysers.keySet()) {
-			AnalyserNode analyser = voiceAnalysers.get(uuid);
-			Uint8Array array = Uint8Array.create(analyser.getFrequencyBinCount());
-			analyser.getByteFrequencyData(array);
-			int len = array.getLength();
-			for (int i = 0; i < len; i++) {
-				if (array.get(i) >= 0.1f) {
-					VoiceClientController.getVoiceSpeaking().add(uuid);
-					break;
+		for (VoicePeer voicePlayer : peerList.values()) {
+			AnalyserNode analyser = voicePlayer.analyser;
+			if(analyser != null) {
+				Uint8Array array = Uint8Array.create(analyser.getFrequencyBinCount());
+				analyser.getByteFrequencyData(array);
+				int len = array.getLength();
+				for (int i = 0; i < len; i++) {
+					if (array.get(i) >= 0.1f) {
+						VoiceClientController.getVoiceSpeaking().add(voicePlayer.peerId);
+						break;
+					}
 				}
 			}
 		}
@@ -335,14 +398,18 @@ public class PlatformVoiceClient {
 	public static void signalDisconnect(EaglercraftUUID peerId, boolean quiet) {
 		VoicePeer peer = peerList.get(peerId);
 		if (peer != null) {
-			peerList.remove(peerId, peer);
-			try {
-				peer.disconnect();
-			} catch (Throwable ignored) {}
-			handlePeerDisconnect(peerId, quiet);
+			signalDisconnect(peer, quiet);
 		}
 	}
 
+	private static void signalDisconnect(VoicePeer peer, boolean quiet) {
+		peerList.remove(peer.peerId, peer);
+		try {
+			peer.disconnect();
+		} catch (Throwable ignored) {}
+		handlePeerDisconnect(peer, quiet);
+	}
+
 	public static void mutePeer(EaglercraftUUID peerId, boolean muted) {
 		VoicePeer peer = peerList.get(peerId);
 		if (peer != null) {
@@ -357,30 +424,25 @@ public class PlatformVoiceClient {
 		}
 	}
 
-	public static void handleIceCandidate(EaglercraftUUID peerId, String candidate) {
-		VoiceClientController.sendPacketICE(peerId, candidate);
-	}
-
-	public static void handleDescription(EaglercraftUUID peerId, String desc) {
-		VoiceClientController.sendPacketDesc(peerId, desc);
-	}
-
-	public static void handlePeerTrack(EaglercraftUUID peerId, MediaStream audioStream) {
+	private static void handlePeerTrack(VoicePeer peer, MediaStream audioStream) {
 		if (VoiceClientController.getVoiceChannel() == EnumVoiceChannelType.NONE) return;
 		MediaStreamAudioSourceNode audioNode = PlatformAudio.audioctx.createMediaStreamSource(audioStream);
 		AnalyserNode analyser = PlatformAudio.audioctx.createAnalyser();
 		analyser.setSmoothingTimeConstant(0f);
 		analyser.setFftSize(32);
 		audioNode.connect(analyser);
-		voiceAnalysers.put(peerId, analyser);
 		if (VoiceClientController.getVoiceChannel() == EnumVoiceChannelType.GLOBAL) {
 			GainNode gain = PlatformAudio.audioctx.createGain();
 			gain.getGain().setValue(VoiceClientController.getVoiceListenVolume());
-			analyser.connect(gain);
+			audioNode.connect(gain);
 			gain.connect(PlatformAudio.audioctx.getDestination());
-			gain.connect(PlatformAudio.recDest);
-			voiceGains.put(peerId, gain);
-			VoiceClientController.getVoiceListening().add(peerId);
+			if(PlatformAudio.gameRecGain != null) {
+				gain.connect(PlatformAudio.gameRecGain);
+			}
+			VoiceClientController.getVoiceListening().add(peer.peerId);
+			peer.analyser = analyser;
+			peer.gain = gain;
+			peer.recNode = gain;
 		} else if (VoiceClientController.getVoiceChannel() == EnumVoiceChannelType.PROXIMITY) {
 			PannerNode panner = PlatformAudio.audioctx.createPanner();
 			panner.setRolloffFactor(1f);
@@ -395,45 +457,72 @@ public class PlatformVoiceClient {
 			panner.setMaxDistance(vol * 2 * VoiceClientController.getVoiceProximity() + 0.1f);
 			GainNode gain = PlatformAudio.audioctx.createGain();
 			gain.getGain().setValue(vol);
-			analyser.connect(gain);
+			audioNode.connect(gain);
 			gain.connect(panner);
 			panner.connect(PlatformAudio.audioctx.getDestination());
-			panner.connect(PlatformAudio.recDest);
-			voiceGains.put(peerId, gain);
-			VoiceClientController.getVoiceListening().add(peerId);
-			voicePanners.put(peerId, panner);
+			if(PlatformAudio.gameRecGain != null) {
+				panner.connect(PlatformAudio.gameRecGain);
+			}
+			VoiceClientController.getVoiceListening().add(peer.peerId);
+			peer.analyser = analyser;
+			peer.panner = panner;
+			peer.gain = gain;
+			peer.recNode = panner;
 		}
-		if (VoiceClientController.getVoiceMuted().contains(peerId)) mutePeer(peerId, true);
+		if (VoiceClientController.getVoiceMuted().contains(peer.peerId)) mutePeer(peer.peerId, true);
 	}
 
-	public static void handlePeerDisconnect(EaglercraftUUID peerId, boolean quiet) {
-		if (voiceAnalysers.containsKey(peerId)) {
-			voiceAnalysers.get(peerId).disconnect();
-			voiceAnalysers.remove(peerId);
+	static void addRecordingDest(AudioNode destNode) {
+		for(VoicePeer peer : peerList.values()) {
+			if(peer.recNode != null) {
+				peer.recNode.connect(destNode);
+			}
 		}
-		if (voiceGains.containsKey(peerId)) {
-			voiceGains.get(peerId).disconnect();
-			voiceGains.remove(peerId);
-			VoiceClientController.getVoiceListening().remove(peerId);
+	}
+
+	static void removeRecordingDest(AudioNode destNode) {
+		for(VoicePeer peer : peerList.values()) {
+			try {
+				if(peer.recNode != null) {
+					peer.recNode.disconnect(destNode);
+				}
+			}catch(Throwable t) {
+			}
 		}
-		if (voicePanners.containsKey(peerId)) {
-			voicePanners.get(peerId).disconnect();
-			voicePanners.remove(peerId);
+	}
+
+	private static void handlePeerDisconnect(VoicePeer peer, boolean quiet) {
+		if(peer.analyser != null) {
+			peer.analyser.disconnect();
+			peer.analyser = null;
 		}
+		if(peer.gain != null) {
+			peer.gain.disconnect();
+			peer.gain = null;
+		}
+		if(peer.panner != null) {
+			peer.panner.disconnect();
+			peer.panner = null;
+		}
+		VoiceClientController.getVoiceListening().remove(peer.peerId);
 		if (!quiet) {
-			VoiceClientController.sendPacketDisconnect(peerId);
+			VoiceClientController.sendPacketDisconnectPeer(peer.peerId);
 		}
 	}
 
 	public static void setVoiceListenVolume(float f) {
-		for (EaglercraftUUID uuid : voiceGains.keySet()) {
-			GainNode gain = voiceGains.get(uuid);
-			float val = f;
-			if(val > 0.5f) val = 0.5f + (val - 0.5f) * 3.0f;
-			if(val > 2.0f) val = 2.0f;
-			if(val < 0.0f) val = 0.0f;
-			gain.getGain().setValue(val * 2.0f);
-			if (voicePanners.containsKey(uuid)) voicePanners.get(uuid).setMaxDistance(f * 2 * VoiceClientController.getVoiceProximity() + 0.1f);
+		for (VoicePeer peer : peerList.values()) {
+			if(peer.gain != null) {
+				float val = f;
+				if(val > 0.5f) val = 0.5f + (val - 0.5f) * 3.0f;
+				if(val > 2.0f) val = 2.0f;
+				if(val < 0.0f) val = 0.0f;
+				peer.gain.getGain().setValue(val * 2.0f);
+			}
+			if(peer.panner != null) {
+				peer.panner.setMaxDistance(f * 2 * VoiceClientController.getVoiceProximity() + 0.1f);
+			}
 		}
 	}
+
 }
diff --git a/sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/PlatformWebRTC.java b/sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/PlatformWebRTC.java
index 06624f11..78d3d57f 100644
--- a/sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/PlatformWebRTC.java
+++ b/sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/PlatformWebRTC.java
@@ -1,17 +1,20 @@
 package net.lax1dude.eaglercraft.v1_8.internal;
 
 import net.lax1dude.eaglercraft.v1_8.EagRuntime;
-import net.lax1dude.eaglercraft.v1_8.EaglerInputStream;
 import net.lax1dude.eaglercraft.v1_8.internal.teavm.TeaVMUtils;
 import net.lax1dude.eaglercraft.v1_8.log4j.LogManager;
 import net.lax1dude.eaglercraft.v1_8.log4j.Logger;
 import net.lax1dude.eaglercraft.v1_8.sp.lan.LANPeerEvent;
-import net.lax1dude.eaglercraft.v1_8.sp.relay.RelayManager;
 import net.lax1dude.eaglercraft.v1_8.sp.relay.RelayQuery;
+import net.lax1dude.eaglercraft.v1_8.sp.relay.RelayQueryImpl;
+import net.lax1dude.eaglercraft.v1_8.sp.relay.RelayQueryRateLimitDummy;
+import net.lax1dude.eaglercraft.v1_8.sp.relay.RelayServerRateLimitTracker;
 import net.lax1dude.eaglercraft.v1_8.sp.relay.RelayServerSocket;
+import net.lax1dude.eaglercraft.v1_8.sp.relay.RelayServerSocketImpl;
+import net.lax1dude.eaglercraft.v1_8.sp.relay.RelayServerSocketRateLimitDummy;
 import net.lax1dude.eaglercraft.v1_8.sp.relay.RelayWorldsQuery;
-import net.lax1dude.eaglercraft.v1_8.sp.relay.pkt.*;
-import net.lax1dude.eaglercraft.v1_8.update.UpdateService;
+import net.lax1dude.eaglercraft.v1_8.sp.relay.RelayWorldsQueryImpl;
+import net.lax1dude.eaglercraft.v1_8.sp.relay.RelayWorldsQueryRateLimitDummy;
 
 import org.json.JSONObject;
 import org.json.JSONWriter;
@@ -29,12 +32,10 @@ import org.teavm.jso.websocket.WebSocket;
 import com.google.common.collect.LinkedListMultimap;
 import com.google.common.collect.ListMultimap;
 
-import java.io.DataInputStream;
-import java.io.IOException;
 import java.util.*;
 
 /**
- * Copyright (c) 2022-2024 ayunami2000. All Rights Reserved.
+ * Copyright (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved.
  * 
  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
@@ -52,23 +53,110 @@ public class PlatformWebRTC {
 
 	private static final Logger logger = LogManager.getLogger("PlatformWebRTC");
 
-	@JSBody(script = "return typeof window.RTCPeerConnection !== \"undefined\";")
-	public static native boolean supported();
+	static final int WEBRTC_SUPPORT_NONE = 0;
+	static final int WEBRTC_SUPPORT_CORE = 1;
+	static final int WEBRTC_SUPPORT_WEBKIT = 2;
+	static final int WEBRTC_SUPPORT_MOZ = 3;
 
-	@JSBody(params = { "item" }, script = "return item.close();")
+	@JSBody(script = "return (typeof RTCPeerConnection !== \"undefined\") ? 1 : ((typeof webkitRTCPeerConnection !== \"undefined\") ? 2 : ((typeof mozRTCPeerConnection !== \"undefined\") ? 3 : 0));")
+	private static native int checkSupportedImpl();
+
+	static boolean hasCheckedSupport = false;
+	static int supportedImpl = WEBRTC_SUPPORT_NONE;
+	static boolean useSessionDescConstructor = false;
+	static boolean useOldConnStateCheck = false;
+	static boolean belowChrome71Fix = false;
+
+	public static boolean supported() {
+		if(!hasCheckedSupport) {
+			supportedImpl = checkSupportedImpl();
+			hasCheckedSupport = true;
+			if(supportedImpl == WEBRTC_SUPPORT_NONE) {
+				logger.error("WebRTC is not supported on this browser!");
+			}else if(supportedImpl == WEBRTC_SUPPORT_WEBKIT) {
+				logger.info("Using webkit- prefix for RTCPeerConnection");
+			}else if(supportedImpl == WEBRTC_SUPPORT_MOZ) {
+				logger.info("Using moz- prefix for RTCPeerConnection");
+			}
+			if(supportedImpl != WEBRTC_SUPPORT_NONE) {
+				belowChrome71Fix = isChromeBelow71();
+				if(belowChrome71Fix) {
+					logger.info("Note: Detected Chrome below version 71, stripping \"a=extmap-allow-mixed\" from the description SDP field");
+				}
+			}else {
+				belowChrome71Fix = false;
+			}
+		}
+		return supportedImpl != WEBRTC_SUPPORT_NONE;
+	}
+
+	@JSBody(params = { "item" }, script = "item.close();")
 	static native void closeIt(JSObject item);
 
 	@JSBody(params = { "item" }, script = "return item.readyState;")
 	static native String getReadyState(JSObject item);
 
-	@JSBody(params = { "item", "buffer" }, script = "return item.send(buffer);")
+	@JSBody(params = { "item", "buffer" }, script = "item.send(buffer);")
 	static native void sendIt(JSObject item, ArrayBuffer buffer);
 
 	@JSBody(params = { "item" }, script = "return !!item.candidate;")
 	static native boolean hasCandidate(JSObject item);
 
-	@JSBody(params = { "item" }, script = "return item.connectionState;")
-	static native String getConnectionState(JSObject item);
+	@JSBody(params = { "item" }, script = "return item.connectionState || \"\";")
+	private static native String getModernConnectionState(JSObject item);
+
+	@JSBody(params = { "item" }, script = "return item.iceConnectionState;")
+	private static native String getICEConnectionState(JSObject item);
+
+	@JSBody(params = { "item" }, script = "return item.signalingState;")
+	private static native String getSignalingState(JSObject item);
+
+	static String getConnectionState(JSObject item) {
+		if(useOldConnStateCheck) {
+			return getConnectionStateLegacy(item);
+		}else {
+			String str = getModernConnectionState(item);
+			if(str.length() == 0) {
+				useOldConnStateCheck = true;
+				logger.info("Note: Using legacy connection state check using iceConnectionState+signalingState");
+				return getConnectionStateLegacy(item);
+			}else {
+				return str;
+			}
+		}
+	}
+
+	private static String getConnectionStateLegacy(JSObject item) {
+		String connState = getICEConnectionState(item);
+		switch(connState) {
+		case "new":
+			return "new";
+		case "checking":
+			return "connecting";
+		case "failed":
+			return "failed";
+		case "disconnected":
+			return "disconnected";
+		case "connected":
+		case "completed":
+		case "closed":
+			String signalState = getSignalingState(item);
+			switch(signalState) {
+			case "stable":
+				return "connected";
+			case "have-local-offer":
+			case "have-remote-offer":
+			case "have-local-pranswer":
+			case "have-remote-pranswer":
+				return "connecting";
+			case "closed":
+			default:
+				return "closed";
+			}
+		default:
+			return "closed";
+		}
+	}
 
 	@JSBody(params = { "item" }, script = "return item.candidate.sdpMLineIndex;")
 	static native int getSdpMLineIndex(JSObject item);
@@ -76,13 +164,33 @@ public class PlatformWebRTC {
 	@JSBody(params = { "item" }, script = "return item.candidate.candidate;")
 	static native String getCandidate(JSObject item);
 
+	static JSObject createRTCPeerConnection(String iceServers) {
+		if(!hasCheckedSupport) supported();
+		switch(supportedImpl) {
+		case WEBRTC_SUPPORT_CORE:
+			return createCoreRTCPeerConnection(iceServers);
+		case WEBRTC_SUPPORT_WEBKIT:
+			return createWebkitRTCPeerConnection(iceServers);
+		case WEBRTC_SUPPORT_MOZ:
+			return createMozRTCPeerConnection(iceServers);
+		default:
+			throw new UnsupportedOperationException();
+		}
+	}
+
 	@JSBody(params = { "iceServers" }, script = "return new RTCPeerConnection({ iceServers: JSON.parse(iceServers), optional: [ { DtlsSrtpKeyAgreement: true } ] });")
-	static native JSObject createRTCPeerConnection(String iceServers);
+	static native JSObject createCoreRTCPeerConnection(String iceServers);
+
+	@JSBody(params = { "iceServers" }, script = "return new webkitRTCPeerConnection({ iceServers: JSON.parse(iceServers), optional: [ { DtlsSrtpKeyAgreement: true } ] });")
+	static native JSObject createWebkitRTCPeerConnection(String iceServers);
+
+	@JSBody(params = { "iceServers" }, script = "return new mozRTCPeerConnection({ iceServers: JSON.parse(iceServers), optional: [ { DtlsSrtpKeyAgreement: true } ] });")
+	static native JSObject createMozRTCPeerConnection(String iceServers);
 
 	@JSBody(params = { "peerConnection", "name" }, script = "return peerConnection.createDataChannel(name);")
 	static native JSObject createDataChannel(JSObject peerConnection, String name);
 
-	@JSBody(params = { "item", "type" }, script = "return (item.binaryType = type);")
+	@JSBody(params = { "item", "type" }, script = "item.binaryType = type;")
 	static native void setBinaryType(JSObject item, String type);
 
 	@JSBody(params = { "item" }, script = "return item.data;")
@@ -91,29 +199,139 @@ public class PlatformWebRTC {
 	@JSBody(params = { "item" }, script = "return item.channel;")
 	static native JSObject getChannel(JSObject item);
 
-	@JSBody(params = { "peerConnection", "h1", "h2" }, script = "return peerConnection.createOffer(h1, h2);")
+	@JSBody(params = { "peerConnection", "h1", "h2" }, script = "peerConnection.createOffer(h1, h2);")
 	static native void createOffer(JSObject peerConnection, DescHandler h1, ErrorHandler h2);
 
-	@JSBody(params = { "peerConnection", "desc", "h1", "h2" }, script = "return peerConnection.setLocalDescription(desc, h1, h2);")
+	@JSBody(params = { "peerConnection", "desc", "h1", "h2" }, script = "peerConnection.setLocalDescription(desc, h1, h2);")
 	static native void setLocalDescription(JSObject peerConnection, JSObject desc, EmptyHandler h1, ErrorHandler h2);
 
-	@JSBody(params = { "peerConnection", "str" }, script = "return peerConnection.setRemoteDescription(JSON.parse(str));")
-	static native void setRemoteDescription(JSObject peerConnection, String str);
+	@JSBody(params = { "peerConnection", "str" }, script = "var candidateList = JSON.parse(str); for (var i = 0; i < candidateList.length; ++i) { peerConnection.addIceCandidate(new RTCIceCandidate(candidateList[i])); }; return null;")
+	private static native void addCoreIceCandidates(JSObject peerConnection, String str);
 
-	@JSBody(params = { "peerConnection", "str" }, script = "const candidateList = JSON.parse(str); for (let i = 0; i < candidateList.length; ++i) { peerConnection.addIceCandidate(candidateList[i]); }; return null;")
-	static native void addIceCandidates(JSObject peerConnection, String str);
+	@JSBody(params = { "peerConnection", "str" }, script = "var candidateList = JSON.parse(str); for (var i = 0; i < candidateList.length; ++i) { peerConnection.addIceCandidate(new mozRTCIceCandidate(candidateList[i])); }; return null;")
+	private static native void addMozIceCandidates(JSObject peerConnection, String str);
 
-	@JSBody(params = { "peerConnection", "str" }, script = "const candidateList = JSON.parse(str); for (let i = 0; i < candidateList.length; ++i) { peerConnection.addIceCandidate(new RTCIceCandidate(candidateList[i])); }; return null;")
-	static native void addIceCandidates2(JSObject peerConnection, String str);
+	@JSBody(params = { }, script = "if(!navigator || !navigator.userAgent) return false;"
+			+ "var ua = navigator.userAgent.toLowerCase();"
+			+ "var i = ua.indexOf(\"chrome/\");"
+			+ "if(i === -1) return false;"
+			+ "i += 7;"
+			+ "var j = ua.indexOf(\".\", i);"
+			+ "if(j === -1 || j < i) j = ua.length;"
+			+ "var versStr = ua.substring(i, j);"
+			+ "versStr = parseInt(versStr);"
+			+ "return !isNaN(versStr) && versStr < 71;")
+	private static native boolean isChromeBelow71();
 
-	@JSBody(params = { "peerConnection", "str", "h1", "h2" }, script = "return peerConnection.setRemoteDescription(JSON.parse(str), h1, h2);")
-	static native void setRemoteDescription2(JSObject peerConnection, String str, EmptyHandler h1, ErrorHandler h2);
+	static void addIceCandidates(JSObject peerConnection, String str) {
+		if(!hasCheckedSupport) supported();
+		switch(supportedImpl) {
+		case WEBRTC_SUPPORT_CORE:
+		case WEBRTC_SUPPORT_WEBKIT:
+			addCoreIceCandidates(peerConnection, str);
+			break;
+		case WEBRTC_SUPPORT_MOZ:
+			addMozIceCandidates(peerConnection, str);
+			break;
+		default:
+			throw new UnsupportedOperationException();
+		}
+	}
 
-	@JSBody(params = { "peerConnection", "h1", "h2" }, script = "return peerConnection.createAnswer(h1, h2);")
+	@JSBody(params = { "peerConnection", "str" }, script = "try { peerConnection.setRemoteDescription(str); return true; } catch(ex) { if(ex.name === \"TypeError\") return false; else throw ex; }")
+	private static native boolean setCoreRemoteDescription(JSObject peerConnection, JSObject str);
+
+	@JSBody(params = { "peerConnection", "str" }, script = "peerConnection.setRemoteDescription(new RTCSessionDescription(str));")
+	private static native void setCoreRemoteDescriptionLegacy(JSObject peerConnection, JSObject str);
+
+	@JSBody(params = { "peerConnection", "str" }, script = "peerConnection.setRemoteDescription(new mozRTCSessionDescription(str));")
+	private static native void setMozRemoteDescriptionLegacy(JSObject peerConnection, JSObject str);
+
+	static void setRemoteDescription(JSObject peerConnection, JSObject str) {
+		if(!hasCheckedSupport) supported();
+		if(belowChrome71Fix) {
+			removeExtmapAllowMixed(str);
+		}
+		switch(supportedImpl) {
+		case WEBRTC_SUPPORT_CORE:
+			if(useSessionDescConstructor) {
+				setCoreRemoteDescriptionLegacy(peerConnection, str);
+			}else {
+				if(!setCoreRemoteDescription(peerConnection, str)) {
+					useSessionDescConstructor = true;
+					logger.info("Note: Caught suspicious exception, using legacy RTCSessionDescription method");
+					setCoreRemoteDescriptionLegacy(peerConnection, str);
+				}
+			}
+			break;
+		case WEBRTC_SUPPORT_WEBKIT:
+			setCoreRemoteDescriptionLegacy(peerConnection, str);
+			break;
+		case WEBRTC_SUPPORT_MOZ:
+			setMozRemoteDescriptionLegacy(peerConnection, str);
+			break;
+		default:
+			throw new UnsupportedOperationException();
+		}
+	}
+
+	@JSBody(params = { "peerConnection", "str", "h1", "h2" }, script = "try { peerConnection.setRemoteDescription(str, h1, h2); return true; } catch(ex) { if(ex.name === \"TypeError\") return false; else throw ex; }")
+	private static native boolean setCoreRemoteDescription2(JSObject peerConnection, JSObject str, EmptyHandler h1, ErrorHandler h2);
+
+	@JSBody(params = { "peerConnection", "str", "h1", "h2" }, script = "peerConnection.setRemoteDescription(new RTCSessionDescription(str), h1, h2);")
+	private static native void setCoreRemoteDescription2Legacy(JSObject peerConnection, JSObject str, EmptyHandler h1, ErrorHandler h2);
+
+	@JSBody(params = { "peerConnection", "str", "h1", "h2" }, script = "peerConnection.setRemoteDescription(new mozRTCSessionDescription(str), h1, h2);")
+	private static native void setMozRemoteDescription2Legacy(JSObject peerConnection, JSObject str, EmptyHandler h1, ErrorHandler h2);
+
+	static void setRemoteDescription2(JSObject peerConnection, JSObject str, EmptyHandler h1, ErrorHandler h2) {
+		if(!hasCheckedSupport) supported();
+		if(belowChrome71Fix) {
+			removeExtmapAllowMixed(str);
+		}
+		switch(supportedImpl) {
+		case WEBRTC_SUPPORT_CORE:
+			if(useSessionDescConstructor) {
+				setCoreRemoteDescription2Legacy(peerConnection, str, h1, h2);
+			}else {
+				if(!setCoreRemoteDescription2(peerConnection, str, h1, h2)) {
+					useSessionDescConstructor = true;
+					logger.info("Note: Caught suspicious exception, using legacy RTCSessionDescription method");
+					setCoreRemoteDescription2Legacy(peerConnection, str, h1, h2);
+				}
+			}
+			break;
+		case WEBRTC_SUPPORT_WEBKIT:
+			setCoreRemoteDescription2Legacy(peerConnection, str, h1, h2);
+			break;
+		case WEBRTC_SUPPORT_MOZ:
+			setMozRemoteDescription2Legacy(peerConnection, str, h1, h2);
+			break;
+		default:
+			throw new UnsupportedOperationException();
+		}
+	}
+
+	@JSBody(params = { "objIn" }, script = "if(typeof objIn.sdp === \"string\""
+			+ "&& objIn.sdp.indexOf(\"a=extmap-allow-mixed\") !== -1) {"
+			+ "objIn.sdp = objIn.sdp.split(\"\\n\").filter(function(line) {"
+			+ "return line.trim() !== \"a=extmap-allow-mixed\";"
+			+ "}).join(\"\\n\");"
+			+ "}")
+	private static native void removeExtmapAllowMixed(JSObject objIn);
+
+	@JSBody(params = { "peerConnection", "h1", "h2" }, script = "peerConnection.createAnswer(h1, h2);")
 	static native void createAnswer(JSObject peerConnection, DescHandler h1, ErrorHandler h2);
 
+	@JSBody(params = { "sock", "buffer" }, script = "sock.send(buffer);")
+	static native void nativeBinarySend(WebSocket sock, ArrayBuffer buffer);
+
 	private static final Map<String, JSObject> fuckTeaVM = new HashMap<>();
 
+	public static void runScheduledTasks() {
+		
+	}
+
 	public static class LANClient {
 		public static final byte READYSTATE_INIT_FAILED = -2;
 		public static final byte READYSTATE_FAILED = -1;
@@ -130,11 +348,17 @@ public class PlatformWebRTC {
 		public void initialize() {
 			try {
 				if (dataChannel != null) {
-					closeIt(dataChannel);
+					try {
+						closeIt(dataChannel);
+					} catch (Throwable t) {
+					}
 					dataChannel = null;
 				}
 				if (peerConnection != null) {
-					closeIt(peerConnection);
+					try {
+						closeIt(peerConnection);
+					} catch (Throwable t) {
+					}
 				}
 				this.peerConnection = createRTCPeerConnection(JSONWriter.valueToString(iceServers));
 				this.readyState = READYSTATE_CONNECTING;
@@ -243,7 +467,7 @@ public class PlatformWebRTC {
 
 		public void signalRemoteDescription(String json) {
 			try {
-				setRemoteDescription(peerConnection, json);
+				setRemoteDescription(peerConnection, JSON.parse(json));
 			} catch (Throwable t) {
 				EagRuntime.debugPrintStackTrace(t);
 				readyState = READYSTATE_FAILED;
@@ -360,7 +584,7 @@ public class PlatformWebRTC {
 		public void setRemoteDescription(String descJSON) {
 			try {
 				JSONObject remoteDesc = new JSONObject(descJSON);
-				setRemoteDescription2(peerConnection, descJSON, () -> {
+				setRemoteDescription2(peerConnection, JSON.parse(descJSON), () -> {
 					if (remoteDesc.has("type") && "offer".equals(remoteDesc.getString("type"))) {
 						createAnswer(peerConnection, desc -> {
 							setLocalDescription(peerConnection, desc, () -> {
@@ -370,23 +594,24 @@ public class PlatformWebRTC {
 								}
 								if (client.peerStateDesc != PEERSTATE_SUCCESS) client.peerStateDesc = PEERSTATE_SUCCESS;
 							}, err -> {
-								logger.error("Failed to set local description for \"{}\"! {}", peerId, err.getMessage());
+								logger.error("Failed to set local description for \"{}\"! {}", peerId, TeaVMUtils.safeErrorMsgToString(err));
 								if (client.peerStateDesc == PEERSTATE_LOADING) client.peerStateDesc = PEERSTATE_FAILED;
 								client.signalRemoteDisconnect(peerId);
 							});
 						}, err -> {
-							logger.error("Failed to create answer for \"{}\"! {}", peerId, err.getMessage());
+							logger.error("Failed to create answer for \"{}\"! {}", peerId, TeaVMUtils.safeErrorMsgToString(err));
 							if (client.peerStateDesc == PEERSTATE_LOADING) client.peerStateDesc = PEERSTATE_FAILED;
 							client.signalRemoteDisconnect(peerId);
 						});
 					}
 				}, err -> {
-					logger.error("Failed to set remote description for \"{}\"! {}", peerId, err.getMessage());
+					logger.error("Failed to set remote description for \"{}\"! {}", peerId, TeaVMUtils.safeErrorMsgToString(err));
 					if (client.peerStateDesc == PEERSTATE_LOADING) client.peerStateDesc = PEERSTATE_FAILED;
 					client.signalRemoteDisconnect(peerId);
 				});
 			} catch (Throwable err) {
 				logger.error("Failed to parse remote description for \"{}\"! {}", peerId, err.getMessage());
+				logger.error(err);
 				if (client.peerStateDesc == PEERSTATE_LOADING) client.peerStateDesc = PEERSTATE_FAILED;
 				client.signalRemoteDisconnect(peerId);
 			}
@@ -394,7 +619,7 @@ public class PlatformWebRTC {
 
 		public void addICECandidate(String candidates) {
 			try {
-				addIceCandidates2(peerConnection, candidates);
+				addIceCandidates(peerConnection, candidates);
 				if (client.peerStateIce != PEERSTATE_SUCCESS) client.peerStateIce = PEERSTATE_SUCCESS;
 			} catch (Throwable err) {
 				logger.error("Failed to parse ice candidate for \"{}\"! {}", peerId, err.getMessage());
@@ -534,722 +759,27 @@ public class PlatformWebRTC {
 		void call(JSError err);
 	}
 
-	@JSBody(params = { "obj" }, script = "return typeof obj === \"string\";")
-	private static native boolean isString(JSObject obj);
-
-	private static final Map<String,Long> relayQueryLimited = new HashMap<>();
-	private static final Map<String,Long> relayQueryBlocked = new HashMap<>();
-
-	private static class RelayQueryImpl implements RelayQuery {
-
-		private final WebSocket sock;
-		private final String uri;
-
-		private boolean open;
-		private boolean failed;
-
-		private boolean hasRecievedAnyData = false;
-
-		private int vers = -1;
-		private String comment = "<no comment>";
-		private String brand = "<no brand>";
-
-		private long connectionOpenedAt;
-		private long connectionPingStart = -1;
-		private long connectionPingTimer = -1;
-
-		private RateLimit rateLimitStatus = RateLimit.NONE;
-
-		private VersionMismatch versError = VersionMismatch.UNKNOWN;
-
-		private RelayQueryImpl(String uri) {
-			this.uri = uri;
-			WebSocket s;
-			try {
-				connectionOpenedAt = System.currentTimeMillis();
-				s = WebSocket.create(uri);
-				s.setBinaryType("arraybuffer");
-				open = true;
-				failed = false;
-			}catch(Throwable t) {
-				connectionOpenedAt = 0l;
-				sock = null;
-				open = false;
-				failed = true;
-				return;
-			}
-			sock = s;
-			sock.onOpen(evt -> {
-				try {
-					connectionPingStart = System.currentTimeMillis();
-					PlatformNetworking.nativeBinarySend(sock, TeaVMUtils.unwrapArrayBuffer(
-							IPacket.writePacket(new IPacket00Handshake(0x03, RelayManager.preferredRelayVersion, ""))
-					));
-				} catch (IOException e) {
-					logger.error(e.toString());
-					sock.close();
-					failed = true;
-				}
-			});
-			sock.onMessage(evt -> {
-				if(evt.getData() != null && !isString(evt.getData())) {
-					hasRecievedAnyData = true;
-					byte[] arr = TeaVMUtils.wrapByteArrayBuffer(evt.getDataAsArray());
-					if(arr.length == 2 && arr[0] == (byte)0xFC) {
-						long millis = System.currentTimeMillis();
-						if(arr[1] == (byte)0x00 || arr[1] == (byte)0x01) {
-							rateLimitStatus = RateLimit.BLOCKED;
-							relayQueryLimited.put(RelayQueryImpl.this.uri, millis);
-						}else if(arr[1] == (byte)0x02) {
-							rateLimitStatus = RateLimit.NOW_LOCKED;
-							relayQueryLimited.put(RelayQueryImpl.this.uri, millis);
-							relayQueryBlocked.put(RelayQueryImpl.this.uri, millis);
-						}else {
-							rateLimitStatus = RateLimit.LOCKED;
-							relayQueryBlocked.put(RelayQueryImpl.this.uri, millis);
-						}
-						failed = true;
-						open = false;
-						sock.close();
-					}else {
-						if(open) {
-							try {
-								IPacket pkt = IPacket.readPacket(new DataInputStream(new EaglerInputStream(arr)));
-								if(pkt instanceof IPacket69Pong) {
-									IPacket69Pong ipkt = (IPacket69Pong)pkt;
-									versError = VersionMismatch.COMPATIBLE;
-									if(connectionPingTimer == -1) {
-										connectionPingTimer = System.currentTimeMillis() - connectionPingStart;
-									}
-									vers = ipkt.protcolVersion;
-									comment = ipkt.comment;
-									brand = ipkt.brand;
-									open = false;
-									failed = false;
-									sock.close();
-								}else if(pkt instanceof IPacket70SpecialUpdate) {
-									IPacket70SpecialUpdate ipkt = (IPacket70SpecialUpdate)pkt;
-									if(ipkt.operation == IPacket70SpecialUpdate.OPERATION_UPDATE_CERTIFICATE) {
-										UpdateService.addCertificateToSet(ipkt.updatePacket);
-									}
-								}else if(pkt instanceof IPacketFFErrorCode) {
-									IPacketFFErrorCode ipkt = (IPacketFFErrorCode)pkt;
-									if(ipkt.code == IPacketFFErrorCode.TYPE_PROTOCOL_VERSION) {
-										String s1 = ipkt.desc.toLowerCase();
-										if(s1.contains("outdated client") || s1.contains("client outdated")) {
-											versError = VersionMismatch.CLIENT_OUTDATED;
-										}else if(s1.contains("outdated server") || s1.contains("server outdated") ||
-												s1.contains("outdated relay") || s1.contains("server relay")) {
-											versError = VersionMismatch.RELAY_OUTDATED;
-										}else {
-											versError = VersionMismatch.UNKNOWN;
-										}
-									}
-									logger.error("{}\": Recieved query error code {}: {}", uri, ipkt.code, ipkt.desc);
-									open = false;
-									failed = true;
-									sock.close();
-								}else {
-									throw new IOException("Unexpected packet '" + pkt.getClass().getSimpleName() + "'");
-								}
-							} catch (IOException e) {
-								logger.error("Relay Query Error: {}", e.toString());
-								EagRuntime.debugPrintStackTrace(e);
-								open = false;
-								failed = true;
-								sock.close();
-							}
-						}
-					}
-				}
-			});
-			sock.onClose(evt -> {
-				open = false;
-				if(!hasRecievedAnyData) {
-					failed = true;
-					Long l = relayQueryBlocked.get(uri);
-					if(l != null) {
-						if(System.currentTimeMillis() - l.longValue() < 400000l) {
-							rateLimitStatus = RateLimit.LOCKED;
-							return;
-						}
-					}
-					l = relayQueryLimited.get(uri);
-					if(l != null) {
-						if(System.currentTimeMillis() - l.longValue() < 900000l) {
-							rateLimitStatus = RateLimit.BLOCKED;
-							return;
-						}
-					}
-				}
-			});
-		}
-
-		@Override
-		public boolean isQueryOpen() {
-			return open;
-		}
-
-		@Override
-		public boolean isQueryFailed() {
-			return failed;
-		}
-
-		@Override
-		public RateLimit isQueryRateLimit() {
-			return rateLimitStatus;
-		}
-
-		@Override
-		public void close() {
-			if(sock != null && open) {
-				sock.close();
-			}
-			open = false;
-		}
-
-		@Override
-		public int getVersion() {
-			return vers;
-		}
-
-		@Override
-		public String getComment() {
-			return comment;
-		}
-
-		@Override
-		public String getBrand() {
-			return brand;
-		}
-
-		@Override
-		public long getPing() {
-			return connectionPingTimer < 1 ? 1 : connectionPingTimer;
-		}
-
-		@Override
-		public VersionMismatch getCompatible() {
-			return versError;
-		}
-
-	}
-
-	private static class RelayQueryRatelimitDummy implements RelayQuery {
-
-		private final RateLimit type;
-
-		private RelayQueryRatelimitDummy(RateLimit type) {
-			this.type = type;
-		}
-
-		@Override
-		public boolean isQueryOpen() {
-			return false;
-		}
-
-		@Override
-		public boolean isQueryFailed() {
-			return true;
-		}
-
-		@Override
-		public RateLimit isQueryRateLimit() {
-			return type;
-		}
-
-		@Override
-		public void close() {
-		}
-
-		@Override
-		public int getVersion() {
-			return RelayManager.preferredRelayVersion;
-		}
-
-		@Override
-		public String getComment() {
-			return "this query was rate limited";
-		}
-
-		@Override
-		public String getBrand() {
-			return "lax1dude";
-		}
-
-		@Override
-		public long getPing() {
-			return 0l;
-		}
-
-		@Override
-		public VersionMismatch getCompatible() {
-			return VersionMismatch.COMPATIBLE;
-		}
-
-	}
-
 	public static RelayQuery openRelayQuery(String addr) {
-		long millis = System.currentTimeMillis();
-
-		Long l = relayQueryBlocked.get(addr);
-		if(l != null && millis - l.longValue() < 60000l) {
-			return new RelayQueryRatelimitDummy(RelayQuery.RateLimit.LOCKED);
+		RelayQuery.RateLimit limit = RelayServerRateLimitTracker.isLimited(addr);
+		if(limit == RelayQuery.RateLimit.LOCKED || limit == RelayQuery.RateLimit.BLOCKED) {
+			return new RelayQueryRateLimitDummy(limit);
 		}
-
-		l = relayQueryLimited.get(addr);
-		if(l != null && millis - l.longValue() < 10000l) {
-			return new RelayQueryRatelimitDummy(RelayQuery.RateLimit.BLOCKED);
-		}
-
 		return new RelayQueryImpl(addr);
 	}
 
-	private static class RelayWorldsQueryImpl implements RelayWorldsQuery {
-
-		private final WebSocket sock;
-		private final String uri;
-
-		private boolean open;
-		private boolean failed;
-
-		private boolean hasRecievedAnyData = false;
-		private RelayQuery.RateLimit rateLimitStatus = RelayQuery.RateLimit.NONE;
-
-		private RelayQuery.VersionMismatch versError = RelayQuery.VersionMismatch.UNKNOWN;
-
-		private List<IPacket07LocalWorlds.LocalWorld> worlds = null;
-
-		private RelayWorldsQueryImpl(String uri) {
-			this.uri = uri;
-			WebSocket s;
-			try {
-				s = WebSocket.create(uri);
-				s.setBinaryType("arraybuffer");
-				open = true;
-				failed = false;
-			}catch(Throwable t) {
-				sock = null;
-				open = false;
-				failed = true;
-				return;
-			}
-			sock = s;
-			sock.onOpen(evt -> {
-				try {
-					PlatformNetworking.nativeBinarySend(sock, TeaVMUtils.unwrapArrayBuffer(
-							IPacket.writePacket(new IPacket00Handshake(0x04, RelayManager.preferredRelayVersion, ""))
-					));
-				} catch (IOException e) {
-					logger.error(e.toString());
-					sock.close();
-					open = false;
-					failed = true;
-				}
-			});
-			sock.onMessage(evt -> {
-				if(evt.getData() != null && !isString(evt.getData())) {
-					hasRecievedAnyData = true;
-					byte[] arr = TeaVMUtils.wrapByteArrayBuffer(evt.getDataAsArray());
-					if(arr.length == 2 && arr[0] == (byte)0xFC) {
-						long millis = System.currentTimeMillis();
-						if(arr[1] == (byte)0x00 || arr[1] == (byte)0x01) {
-							rateLimitStatus = RelayQuery.RateLimit.BLOCKED;
-							relayQueryLimited.put(RelayWorldsQueryImpl.this.uri, millis);
-						}else if(arr[1] == (byte)0x02) {
-							rateLimitStatus = RelayQuery.RateLimit.NOW_LOCKED;
-							relayQueryLimited.put(RelayWorldsQueryImpl.this.uri, millis);
-							relayQueryBlocked.put(RelayWorldsQueryImpl.this.uri, millis);
-						}else {
-							rateLimitStatus = RelayQuery.RateLimit.LOCKED;
-							relayQueryBlocked.put(RelayWorldsQueryImpl.this.uri, millis);
-						}
-						open = false;
-						failed = true;
-						sock.close();
-					}else {
-						if(open) {
-							try {
-								IPacket pkt = IPacket.readPacket(new DataInputStream(new EaglerInputStream(arr)));
-								if(pkt instanceof IPacket07LocalWorlds) {
-									worlds = ((IPacket07LocalWorlds)pkt).worldsList;
-									sock.close();
-									open = false;
-									failed = false;
-								}else if(pkt instanceof IPacket70SpecialUpdate) {
-									IPacket70SpecialUpdate ipkt = (IPacket70SpecialUpdate)pkt;
-									if(ipkt.operation == IPacket70SpecialUpdate.OPERATION_UPDATE_CERTIFICATE) {
-										UpdateService.addCertificateToSet(ipkt.updatePacket);
-									}
-								}else if(pkt instanceof IPacketFFErrorCode) {
-									IPacketFFErrorCode ipkt = (IPacketFFErrorCode)pkt;
-									if(ipkt.code == IPacketFFErrorCode.TYPE_PROTOCOL_VERSION) {
-										String s1 = ipkt.desc.toLowerCase();
-										if(s1.contains("outdated client") || s1.contains("client outdated")) {
-											versError = RelayQuery.VersionMismatch.CLIENT_OUTDATED;
-										}else if(s1.contains("outdated server") || s1.contains("server outdated") ||
-												s1.contains("outdated relay") || s1.contains("server relay")) {
-											versError = RelayQuery.VersionMismatch.RELAY_OUTDATED;
-										}else {
-											versError = RelayQuery.VersionMismatch.UNKNOWN;
-										}
-									}
-									logger.error("{}: Recieved query error code {}: {}", uri, ipkt.code, ipkt.desc);
-									open = false;
-									failed = true;
-									sock.close();
-								}else {
-									throw new IOException("Unexpected packet '" + pkt.getClass().getSimpleName() + "'");
-								}
-							} catch (IOException e) {
-								logger.error("Relay World Query Error: {}", e.toString());
-								EagRuntime.debugPrintStackTrace(e);
-								open = false;
-								failed = true;
-								sock.close();
-							}
-						}
-					}
-				}
-			});
-			sock.onClose(evt -> {
-				open = false;
-				if(!hasRecievedAnyData) {
-					failed = true;
-					Long l = relayQueryBlocked.get(uri);
-					if(l != null) {
-						if(System.currentTimeMillis() - l.longValue() < 400000l) {
-							rateLimitStatus = RelayQuery.RateLimit.LOCKED;
-							return;
-						}
-					}
-					l = relayQueryLimited.get(uri);
-					if(l != null) {
-						if(System.currentTimeMillis() - l.longValue() < 900000l) {
-							rateLimitStatus = RelayQuery.RateLimit.BLOCKED;
-							return;
-						}
-					}
-				}
-			});
-		}
-
-		@Override
-		public boolean isQueryOpen() {
-			return open;
-		}
-
-		@Override
-		public boolean isQueryFailed() {
-			return failed;
-		}
-
-		@Override
-		public RelayQuery.RateLimit isQueryRateLimit() {
-			return rateLimitStatus;
-		}
-
-		@Override
-		public void close() {
-			if(open && sock != null) {
-				sock.close();
-			}
-			open = false;
-		}
-
-		@Override
-		public List<IPacket07LocalWorlds.LocalWorld> getWorlds() {
-			return worlds;
-		}
-
-		@Override
-		public RelayQuery.VersionMismatch getCompatible() {
-			return versError;
-		}
-
-	}
-
-	private static class RelayWorldsQueryRatelimitDummy implements RelayWorldsQuery {
-
-		private final RelayQuery.RateLimit rateLimit;
-
-		private RelayWorldsQueryRatelimitDummy(RelayQuery.RateLimit rateLimit) {
-			this.rateLimit = rateLimit;
-		}
-
-		@Override
-		public boolean isQueryOpen() {
-			return false;
-		}
-
-		@Override
-		public boolean isQueryFailed() {
-			return true;
-		}
-
-		@Override
-		public RelayQuery.RateLimit isQueryRateLimit() {
-			return rateLimit;
-		}
-
-		@Override
-		public void close() {
-		}
-
-		@Override
-		public List<IPacket07LocalWorlds.LocalWorld> getWorlds() {
-			return new ArrayList(0);
-		}
-
-		@Override
-		public RelayQuery.VersionMismatch getCompatible() {
-			return RelayQuery.VersionMismatch.COMPATIBLE;
-		}
-	}
-
 	public static RelayWorldsQuery openRelayWorldsQuery(String addr) {
-		long millis = System.currentTimeMillis();
-
-		Long l = relayQueryBlocked.get(addr);
-		if(l != null && millis - l.longValue() < 60000l) {
-			return new RelayWorldsQueryRatelimitDummy(RelayQuery.RateLimit.LOCKED);
+		RelayQuery.RateLimit limit = RelayServerRateLimitTracker.isLimited(addr);
+		if(limit == RelayQuery.RateLimit.LOCKED || limit == RelayQuery.RateLimit.BLOCKED) {
+			return new RelayWorldsQueryRateLimitDummy(limit);
 		}
-
-		l = relayQueryLimited.get(addr);
-		if(l != null && millis - l.longValue() < 10000l) {
-			return new RelayWorldsQueryRatelimitDummy(RelayQuery.RateLimit.BLOCKED);
-		}
-
 		return new RelayWorldsQueryImpl(addr);
 	}
 
-	private static class RelayServerSocketImpl implements RelayServerSocket {
-
-		private final WebSocket sock;
-		private final String uri;
-
-		private boolean open;
-		private boolean closed;
-		private boolean failed;
-
-		private boolean hasRecievedAnyData;
-
-		private final List<Throwable> exceptions = new LinkedList();
-		private final List<IPacket> packets = new LinkedList();
-
-		private RelayServerSocketImpl(String uri, int timeout) {
-			this.uri = uri;
-			WebSocket s;
-			try {
-				s = WebSocket.create(uri);
-				s.setBinaryType("arraybuffer");
-				open = false;
-				closed = false;
-				failed = false;
-			}catch(Throwable t) {
-				exceptions.add(t);
-				sock = null;
-				open = false;
-				closed = true;
-				failed = true;
-				return;
-			}
-			sock = s;
-			sock.onOpen(evt -> open = true);
-			sock.onMessage(evt -> {
-				if(evt.getData() != null && !isString(evt.getData())) {
-					hasRecievedAnyData = true;
-					try {
-						IPacket pkt = IPacket.readPacket(new DataInputStream(new EaglerInputStream(TeaVMUtils.wrapByteArrayBuffer(evt.getDataAsArray()))));
-						if(pkt instanceof IPacket70SpecialUpdate) {
-							IPacket70SpecialUpdate ipkt = (IPacket70SpecialUpdate)pkt;
-							if(ipkt.operation == IPacket70SpecialUpdate.OPERATION_UPDATE_CERTIFICATE) {
-								UpdateService.addCertificateToSet(ipkt.updatePacket);
-							}
-						}else {
-							packets.add(pkt);
-						}
-					} catch (IOException e) {
-						exceptions.add(e);
-						logger.error("Relay Socket Error: {}", e.toString());
-						EagRuntime.debugPrintStackTrace(e);
-						open = false;
-						failed = true;
-						closed = true;
-						sock.close();
-					}
-				}
-			});
-			sock.onClose(evt -> {
-				if (!hasRecievedAnyData) {
-					failed = true;
-				}
-				open = false;
-				closed = true;
-			});
-			Window.setTimeout(() -> {
-				if(!open && !closed) {
-					closed = true;
-					sock.close();
-				}
-			}, timeout);
-		}
-
-		@Override
-		public boolean isOpen() {
-			return open;
-		}
-
-		@Override
-		public boolean isClosed() {
-			return closed;
-		}
-
-		@Override
-		public void close() {
-			if(open && sock != null) {
-				sock.close();
-			}
-			open = false;
-			closed = true;
-		}
-
-		@Override
-		public boolean isFailed() {
-			return failed;
-		}
-
-		@Override
-		public Throwable getException() {
-			if(!exceptions.isEmpty()) {
-				return exceptions.remove(0);
-			}else {
-				return null;
-			}
-		}
-
-		@Override
-		public void writePacket(IPacket pkt) {
-			try {
-				PlatformNetworking.nativeBinarySend(sock, TeaVMUtils.unwrapArrayBuffer(IPacket.writePacket(pkt)));
-			} catch (Throwable e) {
-				logger.error("Relay connection error: {}", e.toString());
-				EagRuntime.debugPrintStackTrace(e);
-				exceptions.add(e);
-				failed = true;
-				open = false;
-				closed = true;
-				sock.close();
-			}
-		}
-
-		@Override
-		public IPacket readPacket() {
-			if(!packets.isEmpty()) {
-				return packets.remove(0);
-			}else {
-				return null;
-			}
-		}
-
-		@Override
-		public IPacket nextPacket() {
-			if(!packets.isEmpty()) {
-				return packets.get(0);
-			}else {
-				return null;
-			}
-		}
-
-		@Override
-		public RelayQuery.RateLimit getRatelimitHistory() {
-			if(relayQueryBlocked.containsKey(uri)) {
-				return RelayQuery.RateLimit.LOCKED;
-			}
-			if(relayQueryLimited.containsKey(uri)) {
-				return RelayQuery.RateLimit.BLOCKED;
-			}
-			return RelayQuery.RateLimit.NONE;
-		}
-
-		@Override
-		public String getURI() {
-			return uri;
-		}
-
-	}
-
-	private static class RelayServerSocketRatelimitDummy implements RelayServerSocket {
-
-		private final RelayQuery.RateLimit limit;
-
-		private RelayServerSocketRatelimitDummy(RelayQuery.RateLimit limit) {
-			this.limit = limit;
-		}
-
-		@Override
-		public boolean isOpen() {
-			return false;
-		}
-
-		@Override
-		public boolean isClosed() {
-			return true;
-		}
-
-		@Override
-		public void close() {
-		}
-
-		@Override
-		public boolean isFailed() {
-			return true;
-		}
-
-		@Override
-		public Throwable getException() {
-			return null;
-		}
-
-		@Override
-		public void writePacket(IPacket pkt) {
-		}
-
-		@Override
-		public IPacket readPacket() {
-			return null;
-		}
-
-		@Override
-		public IPacket nextPacket() {
-			return null;
-		}
-
-		@Override
-		public RelayQuery.RateLimit getRatelimitHistory() {
-			return limit;
-		}
-
-		@Override
-		public String getURI() {
-			return "<disconnected>";
-		}
-
-	}
-
 	public static RelayServerSocket openRelayConnection(String addr, int timeout) {
-		long millis = System.currentTimeMillis();
-
-		Long l = relayQueryBlocked.get(addr);
-		if(l != null && millis - l.longValue() < 60000l) {
-			return new RelayServerSocketRatelimitDummy(RelayQuery.RateLimit.LOCKED);
+		RelayQuery.RateLimit limit = RelayServerRateLimitTracker.isLimited(addr);
+		if(limit == RelayQuery.RateLimit.LOCKED || limit == RelayQuery.RateLimit.BLOCKED) {
+			return new RelayServerSocketRateLimitDummy(limit);
 		}
-
-		l = relayQueryLimited.get(addr);
-		if(l != null && millis - l.longValue() < 10000l) {
-			return new RelayServerSocketRatelimitDummy(RelayQuery.RateLimit.BLOCKED);
-		}
-
 		return new RelayServerSocketImpl(addr, timeout);
 	}
 
@@ -1290,7 +820,7 @@ public class PlatformWebRTC {
 	public static List<byte[]> clientLANReadAllPacket() {
 		synchronized(clientLANPacketBuffer) {
 			if(!clientLANPacketBuffer.isEmpty()) {
-				List<byte[]> ret = new ArrayList(clientLANPacketBuffer);
+				List<byte[]> ret = new ArrayList<>(clientLANPacketBuffer);
 				clientLANPacketBuffer.clear();
 				return ret;
 			}else {
@@ -1429,4 +959,5 @@ public class PlatformWebRTC {
 		}
 		return rtcLANServer.countPeers();
 	}
+
 }
diff --git a/sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/PlatformWebView.java b/sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/PlatformWebView.java
new file mode 100644
index 00000000..739314d4
--- /dev/null
+++ b/sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/PlatformWebView.java
@@ -0,0 +1,639 @@
+package net.lax1dude.eaglercraft.v1_8.internal;
+
+import java.net.URI;
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Set;
+import java.util.function.Consumer;
+
+import org.teavm.jso.JSBody;
+import org.teavm.jso.JSObject;
+import org.teavm.jso.JSProperty;
+import org.teavm.jso.browser.Window;
+import org.teavm.jso.dom.css.CSSStyleDeclaration;
+import org.teavm.jso.dom.events.Event;
+import org.teavm.jso.dom.events.EventListener;
+import org.teavm.jso.dom.events.MessageEvent;
+import org.teavm.jso.dom.html.HTMLElement;
+import org.teavm.jso.dom.html.HTMLInputElement;
+import org.teavm.jso.typedarrays.ArrayBuffer;
+
+import net.lax1dude.eaglercraft.v1_8.internal.teavm.AdvancedHTMLIFrameElement;
+import net.lax1dude.eaglercraft.v1_8.internal.teavm.IFrameSafetyException;
+import net.lax1dude.eaglercraft.v1_8.internal.teavm.TeaVMUtils;
+import net.lax1dude.eaglercraft.v1_8.log4j.LogManager;
+import net.lax1dude.eaglercraft.v1_8.log4j.Logger;
+import net.lax1dude.eaglercraft.v1_8.socket.protocol.pkt.client.CPacketWebViewMessageEnV4EAG;
+import net.lax1dude.eaglercraft.v1_8.socket.protocol.pkt.client.CPacketWebViewMessageV4EAG;
+import net.lax1dude.eaglercraft.v1_8.socket.protocol.pkt.server.SPacketWebViewMessageV4EAG;
+import net.lax1dude.eaglercraft.v1_8.webview.PermissionsCache;
+import net.lax1dude.eaglercraft.v1_8.webview.WebViewOverlayController.IPacketSendCallback;
+
+/**
+ * Copyright (c) 2024 lax1dude. All Rights Reserved.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ * 
+ */
+public class PlatformWebView {
+
+	private static final Logger logger = LogManager.getLogger("PlatformWebView");
+
+	private static boolean supportKnown = false;
+	private static boolean supportForce = false;
+	private static boolean enableCSP = true;
+	private static boolean supported = false;
+	private static boolean cspSupport = false;
+
+	private static HTMLElement currentIFrameContainer = null;
+	private static HTMLElement currentAllowJavaScript = null;
+
+	private static AdvancedHTMLIFrameElement currentIFrame = null;
+	private static WebViewOptions currentOptions = null;
+
+	private static int webviewResetSerial = 0;
+
+	private static String currentMessageChannelName = null;
+
+	private static Window win;
+	private static HTMLElement rootElement;
+
+	private static Consumer<MessageEvent> currentMessageHandler = null;
+
+	private static final List<Runnable> messageQueue = new LinkedList<>();
+
+	private static IPacketSendCallback packetSendCallback = null;
+
+	static void initRoot(Window win, HTMLElement rootElement) {
+		PlatformWebView.win = win;
+		PlatformWebView.rootElement = rootElement;
+	}
+
+	public static boolean supported() {
+		if(!supportKnown) {
+			IClientConfigAdapter cfg = PlatformRuntime.getClientConfigAdapter();
+			supportForce = cfg.isForceWebViewSupport();
+			enableCSP = cfg.isEnableWebViewCSP();
+			if(supportForce) {
+				supported = true;
+				cspSupport = true;
+			}else {
+				supported = false;
+				cspSupport = false;
+				try {
+					AdvancedHTMLIFrameElement tmp = (AdvancedHTMLIFrameElement)win.getDocument().createElement("iframe");
+					supported = tmp != null && tmp.checkSafetyFeaturesSupported();
+					cspSupport = enableCSP && supported && tmp.checkCSPSupported();
+				}catch(Throwable ex) {
+					logger.error("Error checking iframe support");
+					logger.error(ex);
+				}
+			}
+			if(!supported) {
+				logger.error("This browser does not meet the safety requirements for webview support, this feature will be disabled");
+			}else if(!cspSupport && enableCSP) {
+				logger.warn("This browser does not support CSP attribute on iframes! (try Chrome)");
+			}
+			supportKnown = true;
+		}
+		return supported;
+	}
+
+	public static boolean isShowing() {
+		return currentIFrameContainer != null;
+	}
+
+	private static int hashPermissionFlags(WebViewOptions opts) {
+		int i = (opts.scriptEnabled ? 1 : 0);
+		i |= ((enableCSP && cspSupport && opts.strictCSPEnable) ? 0 : 2);
+		i |= (opts.serverMessageAPIEnabled ? 4 : 0);
+		return i;
+	}
+
+	public static void beginShowing(WebViewOptions options, int x, int y, int w, int h) {
+		if(!supported()) {
+			return;
+		}
+		setupShowing(x, y, w, h);
+		if(options.scriptEnabled) {
+			PermissionsCache.Permission perm = PermissionsCache.getJavaScriptAllowed(options.permissionsOriginUUID, hashPermissionFlags(options));
+			if(perm == null) {
+				beginShowingEnableJavaScript(options);
+			}else if(perm.choice) {
+				beginShowingDirect(options);
+			}else {
+				beginShowingContentBlocked(options);
+			}
+		}else {
+			beginShowingDirect(options);
+		}
+	}
+
+	private static void setupShowing(int x, int y, int w, int h) {
+		if(currentIFrameContainer != null) {
+			endShowing();
+		}
+		currentIFrameContainer = win.getDocument().createElement("div");
+		currentIFrameContainer.getClassList().add("_eaglercraftX_webview_container_element");
+		CSSStyleDeclaration decl = currentIFrameContainer.getStyle();
+		decl.setProperty("border", "5px solid #333333");
+		decl.setProperty("z-index", "11");
+		decl.setProperty("position", "absolute");
+		decl.setProperty("background-color", "#DDDDDD");
+		decl.setProperty("font-family", "sans-serif");
+		resize(x, y, w, h);
+		rootElement.appendChild(currentIFrameContainer);
+	}
+
+	private static void beginShowingDirect(WebViewOptions options) {
+		if(!supportForce) {
+			try {
+				currentOptions = options;
+				currentIFrame = (AdvancedHTMLIFrameElement)win.getDocument().createElement("iframe");
+				currentIFrame.setAllowSafe("");
+				currentIFrame.setReferrerPolicy("strict-origin");
+				Set<String> sandboxArgs = new HashSet<>();
+				sandboxArgs.add("allow-downloads");
+				if(options.scriptEnabled) {
+					sandboxArgs.add("allow-scripts");
+					sandboxArgs.add("allow-pointer-lock");
+				}
+				currentIFrame.setSandboxSafe(sandboxArgs);
+			}catch(IFrameSafetyException ex) {
+				logger.error("Caught safety exception while opening webview!");
+				logger.error(ex);
+				if(currentIFrame != null) {
+					currentIFrame.delete();
+					currentIFrame = null;
+					currentOptions = null;
+				}
+				logger.error("Things you can try:");
+				logger.error("1. Set window.eaglercraftXOpts.forceWebViewSupport to true");
+				logger.error("2. Set window.eaglercraftXOpts.enableWebViewCSP to false");
+				logger.error("(these settings may compromise security)");
+				beginShowingSafetyError();
+				return;
+			}
+		}else {
+			currentOptions = options;
+			currentIFrame = (AdvancedHTMLIFrameElement)win.getDocument().createElement("iframe");
+			try {
+				currentIFrame.setAllow("");
+			}catch(Throwable t) {
+			}
+			try {
+				currentIFrame.setReferrerPolicy("strict-origin");
+			}catch(Throwable t) {
+			}
+			try {
+				List<String> sandboxArgs = new ArrayList<>();
+				sandboxArgs.add("allow-downloads");
+				sandboxArgs.add("allow-same-origin");
+				if(options.scriptEnabled) {
+					sandboxArgs.add("allow-scripts");
+					sandboxArgs.add("allow-pointer-lock");
+				}
+				currentIFrame.setSandbox(String.join(" ", sandboxArgs));
+			}catch(Throwable t) {
+			}
+		}
+		currentIFrame.setCredentialless(true);
+		currentIFrame.setLoading("lazy");
+		boolean cspWarn = false;
+		if(options.contentMode == EnumWebViewContentMode.BLOB_BASED) {
+			if(enableCSP && cspSupport) {
+				if(currentIFrame.checkCSPSupported()) {
+					StringBuilder csp = new StringBuilder();
+					csp.append("default-src 'none';");
+					String protos = options.strictCSPEnable ? "" : (PlatformRuntime.requireSSL() ? " https:" : " http: https:");
+					if(options.scriptEnabled) {
+						csp.append(" script-src 'unsafe-eval' 'unsafe-inline' data: blob:").append(protos).append(';');
+						csp.append(" style-src 'unsafe-eval' 'unsafe-inline' data: blob:").append(protos).append(';');
+						csp.append(" img-src data: blob:").append(protos).append(';');
+						csp.append(" font-src data: blob:").append(protos).append(';');
+						csp.append(" child-src data: blob:").append(protos).append(';');
+						csp.append(" frame-src data: blob:;");
+						csp.append(" media-src data: mediastream: blob:").append(protos).append(';');
+						csp.append(" connect-src data: blob:").append(protos).append(';');
+						csp.append(" worker-src data: blob:").append(protos).append(';');
+					}else {
+						csp.append(" style-src data: 'unsafe-inline'").append(protos).append(';');
+						csp.append(" img-src data:").append(protos).append(';');
+						csp.append(" font-src data:").append(protos).append(';');
+						csp.append(" media-src data:").append(protos).append(';');
+					}
+					currentIFrame.setCSP(csp.toString());
+				}else {
+					logger.warn("This browser does not support CSP attribute on iframes! (try Chrome)");
+					cspWarn = true;
+				}
+			}else {
+				cspWarn = true;
+			}
+			if(cspWarn && options.strictCSPEnable) {
+				logger.warn("Strict CSP was requested for this webview, but that feature is not available!");
+			}
+		}else {
+			cspWarn = true;
+		}
+		CSSStyleDeclaration decl = currentIFrame.getStyle();
+		decl.setProperty("border", "none");
+		decl.setProperty("background-color", "white");
+		decl.setProperty("width", "100%");
+		decl.setProperty("height", "100%");
+		currentIFrame.getClassList().add("_eaglercraftX_webview_iframe_element");
+		currentIFrameContainer.appendChild(currentIFrame);
+		if(options.contentMode == EnumWebViewContentMode.BLOB_BASED) {
+			currentIFrame.setSourceDocument(new String(options.blob, StandardCharsets.UTF_8));
+		}else {
+			currentIFrame.setSourceAddress(options.url.toString());
+		}
+		final int resetSer = webviewResetSerial;
+		final AdvancedHTMLIFrameElement curIFrame = currentIFrame;
+		final boolean[] focusTracker = new boolean[1];
+		currentIFrame.addEventListener("mouseover", new EventListener<Event>() {
+			@Override
+			public void handleEvent(Event evt) {
+				if(resetSer == webviewResetSerial && curIFrame == currentIFrame) {
+					if(!focusTracker[0]) {
+						focusTracker[0] = true;
+						currentIFrame.getContentWindow().focus();
+					}
+				}
+			}
+		});
+		currentIFrame.addEventListener("mouseout", new EventListener<Event>() {
+			@Override
+			public void handleEvent(Event evt) {
+				if(resetSer == webviewResetSerial && curIFrame == currentIFrame) {
+					if(focusTracker[0]) {
+						focusTracker[0] = false;
+						win.focus();
+					}
+				}
+			}
+		});
+		if(options.scriptEnabled && options.serverMessageAPIEnabled) {
+			currentMessageHandler = new Consumer<MessageEvent>() {
+				@Override
+				public void accept(MessageEvent evt) {
+					synchronized(messageQueue) {
+						if(resetSer == webviewResetSerial && curIFrame == currentIFrame) {
+							messageQueue.add(() -> {
+								if(resetSer == webviewResetSerial && curIFrame == currentIFrame) {
+									handleMessageRawFromFrame(evt.getData());
+								}else {
+									logger.warn("Recieved message from on dead IFrame handler: (#" + resetSer + ") " + curIFrame.getSourceAddress());
+								}
+							});
+						}else {
+							logger.warn("Recieved message from on dead IFrame handler: (#" + resetSer + ") " + curIFrame.getSourceAddress());
+						}
+					}
+				}
+			};
+		}
+		logger.info("WebView is loading: \"{}\"", options.contentMode == EnumWebViewContentMode.BLOB_BASED ? "about:srcdoc" : currentIFrame.getSourceAddress());
+		logger.info("JavaScript: {}, Strict CSP: {}, Message API: {}", options.scriptEnabled,
+				options.strictCSPEnable && !cspWarn, options.serverMessageAPIEnabled);
+	}
+
+	private static void beginShowingEnableJSSetup() {
+		if(currentAllowJavaScript != null) {
+			++webviewResetSerial;
+			currentAllowJavaScript.delete();
+			currentAllowJavaScript = null;
+		}
+		currentAllowJavaScript = win.getDocument().createElement("div");
+		CSSStyleDeclaration decl = currentAllowJavaScript.getStyle();
+		decl.setProperty("background-color", "white");
+		decl.setProperty("width", "100%");
+		decl.setProperty("height", "100%");
+		currentAllowJavaScript.getClassList().add("_eaglercraftX_webview_permission_screen");
+		currentIFrameContainer.appendChild(currentAllowJavaScript);
+	}
+
+	private static void beginShowingEnableJavaScript(final WebViewOptions options) {
+		beginShowingEnableJSSetup();
+		String strictCSPMarkup;
+		if(options.contentMode != EnumWebViewContentMode.BLOB_BASED) {
+			strictCSPMarkup = "<span style=\"color:red;\">Impossible</span>";
+		}else if(!cspSupport || !enableCSP) {
+			strictCSPMarkup = "<span style=\"color:red;\">Unsupported</span>";
+		}else if(options.strictCSPEnable) {
+			strictCSPMarkup = "<span style=\"color:green;\">Enabled</span>";
+		}else {
+			strictCSPMarkup = "<span style=\"color:red;\">Disabled</span>";
+		}
+		String messageAPIMarkup;
+		if(options.serverMessageAPIEnabled) {
+			messageAPIMarkup = "<span style=\"color:red;\">Enabled</span>";
+		}else {
+			messageAPIMarkup = "<span style=\"color:green;\">Disabled</span>";
+		}
+		currentAllowJavaScript.setInnerHTML(
+				"<div style=\"padding-top:13vh;\"><div style=\"margin:auto;max-width:450px;border:6px double black;text-align:center;padding:20px;\">"
+				+ "<h2><img width=\"32\" height=\"32\" style=\"vertical-align:middle;\" src=\"" + PlatformApplication.faviconURLTeaVM() + "\">&emsp;Allow JavaScript</h2>"
+				+ "<p style=\"font-family:monospace;text-decoration:underline;word-wrap:break-word;\" class=\"_eaglercraftX_permission_target_url\"></p>"
+				+ "<h4 style=\"line-height:1.4em;\">Strict CSP: " + strictCSPMarkup + "&ensp;|&ensp;"
+				+ "Message API: " + messageAPIMarkup + "</h4>"
+				+ "<p><input class=\"_eaglercraftX_remember_javascript\" type=\"checkbox\" checked> Remember my choice</p>"
+				+ "<p><button style=\"font-size:1.5em;\" class=\"_eaglercraftX_allow_javascript\">Allow</button>&emsp;"
+				+ "<button style=\"font-size:1.5em;\" class=\"_eaglercraftX_block_javascript\">Block</button></p></div></div>");
+		final int serial = webviewResetSerial;
+		if(options.contentMode != EnumWebViewContentMode.BLOB_BASED) {
+			String urlStr = options.url.toString();
+			currentAllowJavaScript.querySelector("._eaglercraftX_permission_target_url").setInnerText(urlStr.length() > 255 ? (urlStr.substring(0, 253) + "...") : urlStr);
+		}
+		currentAllowJavaScript.querySelector("._eaglercraftX_allow_javascript").addEventListener("click", new EventListener<Event>() {
+			@Override
+			public void handleEvent(Event evt) {
+				if(webviewResetSerial == serial && currentAllowJavaScript != null) {
+					HTMLInputElement chkbox = (HTMLInputElement)currentAllowJavaScript.querySelector("._eaglercraftX_remember_javascript");
+					if(chkbox != null && chkbox.isChecked()) {
+						PermissionsCache.setJavaScriptAllowed(options.permissionsOriginUUID, hashPermissionFlags(options), true);
+					}
+					currentAllowJavaScript.delete();
+					currentAllowJavaScript = null;
+					++webviewResetSerial;
+					beginShowingDirect(options);
+				}
+			}
+		});
+		currentAllowJavaScript.querySelector("._eaglercraftX_block_javascript").addEventListener("click", new EventListener<Event>() {
+			@Override
+			public void handleEvent(Event evt) {
+				if(webviewResetSerial == serial && currentAllowJavaScript != null) {
+					HTMLInputElement chkbox = (HTMLInputElement)currentAllowJavaScript.querySelector("._eaglercraftX_remember_javascript");
+					if(chkbox != null && chkbox.isChecked()) {
+						PermissionsCache.setJavaScriptAllowed(options.permissionsOriginUUID, hashPermissionFlags(options), false);
+					}
+					beginShowingContentBlocked(options);
+				}
+			}
+		});
+	}
+
+	private static void beginShowingContentBlocked(final WebViewOptions options) {
+		beginShowingEnableJSSetup();
+		currentAllowJavaScript.setInnerHTML(
+				"<div style=\"padding-top:13vh;\"><h1 style=\"text-align:center;\">"
+				+ "<img width=\"48\" height=\"48\" style=\"vertical-align:middle;\" src=\"" + PlatformApplication.faviconURLTeaVM() + "\">&emsp;Content Blocked</h1>"
+				+ "<h4 style=\"text-align:center;\">You chose to block JavaScript execution for this embed</h4>"
+				+ "<p style=\"text-align:center;\"><button style=\"font-size:1.0em;\" class=\"_eaglercraftX_re_evaluate_javascript\">Re-evaluate</button></p></div>");
+		final int serial = webviewResetSerial;
+		currentAllowJavaScript.querySelector("._eaglercraftX_re_evaluate_javascript").addEventListener("click", new EventListener<Event>() {
+			@Override
+			public void handleEvent(Event evt) {
+				if(webviewResetSerial == serial && currentAllowJavaScript != null) {
+					PermissionsCache.clearJavaScriptAllowed(options.permissionsOriginUUID);
+					beginShowingEnableJavaScript(options);
+				}
+			}
+		});
+	}
+
+	private static void beginShowingSafetyError() {
+		beginShowingEnableJSSetup();
+		currentAllowJavaScript.setInnerHTML(
+				"<div style=\"padding-top:13vh;\"><h1 style=\"text-align:center;\">"
+				+ "<img width=\"48\" height=\"48\" style=\"vertical-align:middle;\" src=\"" + PlatformApplication.faviconURLTeaVM() + "\">&emsp;IFrame Safety Error</h1>"
+				+ "<h4 style=\"text-align:center;\">The content cannot be displayed safely!</h4>"
+				+ "<h4 style=\"text-align:center;\">Check console for more details</h4></div>");
+	}
+
+	private static String getURLOrigin(URI urlObject) {
+		String str = " " + urlObject.getScheme() + "://" + urlObject.getRawAuthority();
+		if(str.startsWith(" http:")) {
+			str = str + " https" + str.substring(5);
+		}
+		return str;
+	}
+
+	public static void resize(int x, int y, int w, int h) {
+		if(currentIFrameContainer != null) {
+			CSSStyleDeclaration decl = currentIFrameContainer.getStyle();
+			float s = PlatformInput.getDPI();
+			decl.setProperty("top", "" + (y / s) + "px");
+			decl.setProperty("left", "" + (x / s) + "px");
+			decl.setProperty("width", "" + ((w / s) - 10) + "px");
+			decl.setProperty("height", "" + ((h / s) - 10) + "px");
+		}
+	}
+
+	public static void endShowing() {
+		++webviewResetSerial;
+		if(currentIFrame != null) {
+			currentIFrame.delete();
+			currentIFrame = null;
+		}
+		synchronized(messageQueue) {
+			messageQueue.clear();
+		}
+		currentMessageHandler = null;
+		if(currentAllowJavaScript != null) {
+			currentAllowJavaScript.delete();
+			currentAllowJavaScript = null;
+		}
+		currentIFrameContainer.delete();
+		currentIFrameContainer = null;
+		if(currentMessageChannelName != null) {
+			sendMessageEnToServer(false, currentMessageChannelName);
+			currentMessageChannelName = null;
+		}
+		win.focus();
+		currentOptions = null;
+	}
+
+	public static boolean fallbackSupported() {
+		return false;
+	}
+
+	public static void launchFallback(WebViewOptions options) {
+		
+	}
+
+	public static boolean fallbackRunning() {
+		return false;
+	}
+
+	public static String getFallbackURL() {
+		return null;
+	}
+
+	public static void endFallbackServer() {
+		
+	}
+
+	@JSBody(params = { "evt", "iframe" }, script = "return evt.source === iframe.contentWindow;")
+	private static native boolean sourceEquals(MessageEvent evt, AdvancedHTMLIFrameElement iframe);
+
+	static void onWindowMessageRecieved(MessageEvent evt) {
+		if(currentIFrame != null && currentMessageHandler != null && sourceEquals(evt, currentIFrame)) {
+			currentMessageHandler.accept(evt);
+		}
+	}
+
+	public static void setPacketSendCallback(IPacketSendCallback callback) {
+		packetSendCallback = callback;
+	}
+
+	public static void runTick() {
+		if(currentIFrame == null) {
+			return;
+		}
+		List<Runnable> lst = null;
+		synchronized(messageQueue) {
+			if(messageQueue.isEmpty()) {
+				return;
+			}
+			lst = new ArrayList<>(messageQueue);
+			messageQueue.clear();
+		}
+		for(int i = 0, l = lst.size(); i < l; ++i) {
+			try {
+				lst.get(i).run();
+			}catch(Throwable t) {
+				logger.error("Caught exception processing webview message!");
+				logger.error(t);
+			}
+		}
+	}
+
+	@JSBody(params = { "channel", "contents" }, script = "return {ver:1,channel:channel,type:\"string\",data:contents};")
+	private static native JSObject createStringMessage(String channel, String contents);
+
+	@JSBody(params = { "channel", "contents" }, script = "return {ver:1,channel:channel,type:\"binary\",data:contents};")
+	private static native JSObject createBinaryMessage(String channel, ArrayBuffer contents);
+
+	public static void handleMessageFromServer(SPacketWebViewMessageV4EAG packet) {
+		Window w;
+		if(currentMessageChannelName != null && currentIFrame != null && (w = currentIFrame.getContentWindow()) != null) {
+			JSObject obj = null;
+			if(packet.type == SPacketWebViewMessageV4EAG.TYPE_STRING) {
+				obj = createStringMessage(currentMessageChannelName, new String(packet.data, StandardCharsets.UTF_8));
+			}else if(packet.type == SPacketWebViewMessageV4EAG.TYPE_BINARY) {
+				obj = createBinaryMessage(currentMessageChannelName, TeaVMUtils.unwrapArrayBuffer(packet.data));
+			}
+			if(obj != null) {
+				w.postMessage(obj, "*");
+			}
+		}else {
+			logger.error("Server tried to send the WebView a message, but the message channel is not open!");
+		}
+	}
+
+	@JSBody(params = { "obj" }, script = "return (typeof obj === \"object\") && (obj.ver === 1) && ((typeof obj.channel === \"string\") && obj.channel.length > 0);")
+	private static native boolean checkRawMessageValid(JSObject obj);
+
+	@JSBody(params = { "obj" }, script = "return (typeof obj.open === \"boolean\");")
+	private static native boolean checkRawMessageValidEn(JSObject obj);
+
+	@JSBody(params = { "obj" }, script = "return (typeof obj.data === \"string\");")
+	private static native boolean checkRawMessageValidDataStr(JSObject obj);
+
+	@JSBody(params = { "obj" }, script = "return (obj.data instanceof ArrayBuffer);")
+	private static native boolean checkRawMessageValidDataBin(JSObject obj);
+
+	private static interface WebViewMessage extends JSObject {
+		
+		@JSProperty
+		String getType();
+		
+		@JSProperty
+		String getChannel();
+		
+		@JSProperty("data")
+		String getDataAsString();
+		
+		@JSProperty("data")
+		ArrayBuffer getDataAsArrayBuffer();
+		
+		@JSProperty
+		boolean getOpen();
+		
+	}
+
+	private static void handleMessageRawFromFrame(JSObject obj) {
+		if(checkRawMessageValid(obj)) {
+			if(checkRawMessageValidEn(obj)) {
+				WebViewMessage msg = (WebViewMessage)obj;
+				sendMessageEnToServer(msg.getOpen(), msg.getChannel());
+				return;
+			}else if(checkRawMessageValidDataStr(obj)) {
+				WebViewMessage msg = (WebViewMessage)obj;
+				sendMessageToServer(msg.getChannel(), CPacketWebViewMessageV4EAG.TYPE_STRING, msg.getDataAsString().getBytes(StandardCharsets.UTF_8));
+				return;
+			}else if(checkRawMessageValidDataBin(obj)) {
+				WebViewMessage msg = (WebViewMessage)obj;
+				sendMessageToServer(msg.getChannel(), CPacketWebViewMessageV4EAG.TYPE_BINARY, TeaVMUtils.wrapByteArrayBuffer(msg.getDataAsArrayBuffer()));
+				return;
+			}
+		}
+		logger.warn("WebView sent an invalid message!");
+	}
+
+	private static void sendMessageToServer(String channelName, int type, byte[] data) {
+		if(channelName.length() > 255) {
+			logger.error("WebView tried to send a message packet, but channel name is too long, max is 255 characters!");
+			return;
+		}
+		if(!channelName.equals(currentMessageChannelName)) {
+			logger.error("WebView tried to send a message packet, but the channel is not open!");
+			return;
+		}
+		if(packetSendCallback != null) {
+			if(!packetSendCallback.sendPacket(new CPacketWebViewMessageV4EAG(type, data))) {
+				logger.error("WebView tried to send a packet to the server, but the server does not support this protocol!");
+			}
+		}else {
+			logger.error("WebView tried to send a message, but no callback for sending packets is set!");
+		}
+	}
+
+	private static void sendMessageEnToServer(boolean messageChannelOpen, String channelName) {
+		if(channelName.length() > 255) {
+			logger.error("WebView tried to {} a channel, but channel name is too long, max is 255 characters!", messageChannelOpen ? "open" : "close");
+			return;
+		}
+		if(messageChannelOpen && currentMessageChannelName != null) {
+			logger.error("WebView tried to open channel, but a channel is already open!");
+			sendMessageEnToServer(false, currentMessageChannelName);
+		}
+		if(!messageChannelOpen && currentMessageChannelName != null && !currentMessageChannelName.equals(channelName)) {
+			logger.error("WebView tried to close the wrong channel!");
+		}
+		if(!messageChannelOpen && currentMessageChannelName == null) {
+			logger.error("WebView tried to close channel, but the channel is not open!");
+			return;
+		}
+		if(packetSendCallback != null) {
+			if(!packetSendCallback.sendPacket(new CPacketWebViewMessageEnV4EAG(messageChannelOpen, messageChannelOpen ? channelName : null))) {
+				logger.error("WebView tried to send a packet to the server, but the server does not support this protocol!");
+				return;
+			}
+			if(messageChannelOpen) {
+				logger.info("WebView opened message channel to server: \"{}\"", channelName);
+				currentMessageChannelName = channelName;
+			}else {
+				logger.info("WebView closed message channel to server: \"{}\"", currentMessageChannelName);
+				currentMessageChannelName = null;
+			}
+		}else {
+			logger.error("WebView tried to send a message, but no callback for sending packets is set!");
+		}
+	}
+
+}
diff --git a/sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/buffer/EaglerArrayByteBuffer.java b/sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/buffer/EaglerArrayByteBuffer.java
index a0ce5d71..48d19bc6 100644
--- a/sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/buffer/EaglerArrayByteBuffer.java
+++ b/sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/buffer/EaglerArrayByteBuffer.java
@@ -32,9 +32,7 @@ public class EaglerArrayByteBuffer implements ByteBuffer {
 	int position;
 	int limit;
 	int mark;
-	
-	static final Int8Array ZERO_LENGTH_BUFFER = Int8Array.create(0);
-	
+
 	EaglerArrayByteBuffer(DataView dataView) {
 		this.dataView = dataView;
 		this.typedArray = Int8Array.create(dataView.getBuffer(), dataView.getByteOffset(), dataView.getByteLength());
@@ -43,7 +41,7 @@ public class EaglerArrayByteBuffer implements ByteBuffer {
 		this.limit = this.capacity;
 		this.mark = -1;
 	}
-	
+
 	EaglerArrayByteBuffer(DataView dataView, int position, int limit, int mark) {
 		this.dataView = dataView;
 		this.typedArray = Int8Array.create(dataView.getBuffer(), dataView.getByteOffset(), dataView.getByteLength());
@@ -52,7 +50,7 @@ public class EaglerArrayByteBuffer implements ByteBuffer {
 		this.limit = limit;
 		this.mark = mark;
 	}
-	
+
 	EaglerArrayByteBuffer(Int8Array typedArray) {
 		this.typedArray = typedArray;
 		this.dataView = DataView.create(typedArray.getBuffer(), typedArray.getByteOffset(), typedArray.getByteLength());
@@ -61,7 +59,7 @@ public class EaglerArrayByteBuffer implements ByteBuffer {
 		this.limit = this.capacity;
 		this.mark = -1;
 	}
-	
+
 	EaglerArrayByteBuffer(Int8Array typedArray, int position, int limit, int mark) {
 		this.typedArray = typedArray;
 		this.dataView = DataView.create(typedArray.getBuffer(), typedArray.getByteOffset(), typedArray.getByteLength());
@@ -96,18 +94,13 @@ public class EaglerArrayByteBuffer implements ByteBuffer {
 		return limit > position;
 	}
 
-	@Override
-	public boolean isReadOnly() {
-		return false;
-	}
-
 	@Override
 	public boolean hasArray() {
 		return false;
 	}
 
 	@Override
-	public Object array() {
+	public byte[] array() {
 		throw new UnsupportedOperationException();
 	}
 
@@ -116,55 +109,40 @@ public class EaglerArrayByteBuffer implements ByteBuffer {
 		return true;
 	}
 
-	@Override
-	public ByteBuffer slice() {
-		if(position == limit) {
-			return new EaglerArrayByteBuffer(ZERO_LENGTH_BUFFER);
-		}else {
-			if(position > limit) throw new ArrayIndexOutOfBoundsException(position);
-			return new EaglerArrayByteBuffer(Int8Array.create(typedArray.getBuffer(), typedArray.getByteOffset() + position, limit - position));
-		}
-	}
-
 	@Override
 	public ByteBuffer duplicate() {
 		return new EaglerArrayByteBuffer(dataView, position, limit, mark);
 	}
 
-	@Override
-	public ByteBuffer asReadOnlyBuffer() {
-		return new EaglerArrayByteBuffer(dataView, position, limit, mark);
-	}
-
 	@Override
 	public byte get() {
-		if(position >= limit) throw new ArrayIndexOutOfBoundsException(position);
+		if(position >= limit) throw Buffer.makeIOOBE(position);
 		return typedArray.get(position++);
 	}
 
 	@Override
 	public ByteBuffer put(byte b) {
-		if(position >= limit) throw new ArrayIndexOutOfBoundsException(position);
+		if(position >= limit) throw Buffer.makeIOOBE(position);
 		typedArray.set(position++, b);
 		return this;
 	}
 
 	@Override
 	public byte get(int index) {
-		if(index >= limit) throw new ArrayIndexOutOfBoundsException(index);
+		if(index < 0 || index >= limit) throw Buffer.makeIOOBE(index);
 		return typedArray.get(index);
 	}
 
 	@Override
 	public ByteBuffer put(int index, byte b) {
-		if(index >= limit) throw new ArrayIndexOutOfBoundsException(index);
+		if(index < 0 || index >= limit) throw Buffer.makeIOOBE(index);
 		typedArray.set(index, b);
 		return this;
 	}
 
 	@Override
 	public ByteBuffer get(byte[] dst, int offset, int length) {
-		if(position + length > limit) throw new ArrayIndexOutOfBoundsException(position + length - 1);
+		if(position + length > limit) throw Buffer.makeIOOBE(position + length - 1);
 		TeaVMUtils.unwrapArrayBufferView(dst).set(Int8Array.create(typedArray.getBuffer(), typedArray.getByteOffset() + position, length), offset);
 		position += length;
 		return this;
@@ -172,7 +150,7 @@ public class EaglerArrayByteBuffer implements ByteBuffer {
 
 	@Override
 	public ByteBuffer get(byte[] dst) {
-		if(position + dst.length > limit) throw new ArrayIndexOutOfBoundsException(position + dst.length - 1);
+		if(position + dst.length > limit) throw Buffer.makeIOOBE(position + dst.length - 1);
 		TeaVMUtils.unwrapArrayBufferView(dst).set(Int8Array.create(typedArray.getBuffer(), typedArray.getByteOffset() + position, dst.length));
 		position += dst.length;
 		return this;
@@ -183,13 +161,13 @@ public class EaglerArrayByteBuffer implements ByteBuffer {
 		if(src instanceof EaglerArrayByteBuffer) {
 			EaglerArrayByteBuffer c = (EaglerArrayByteBuffer)src;
 			int l = c.limit - c.position;
-			if(position + l > limit) throw new ArrayIndexOutOfBoundsException(position + l - 1);
+			if(position + l > limit) throw Buffer.makeIOOBE(position + l - 1);
 			typedArray.set(Int8Array.create(c.typedArray.getBuffer(), c.typedArray.getByteOffset() + c.position, l), position);
 			position += l;
 			c.position += l;
 		}else {
 			int l = src.remaining();
-			if(position + l > limit) throw new ArrayIndexOutOfBoundsException(position + l - 1);
+			if(position + l > limit) throw Buffer.makeIOOBE(position + l - 1);
 			for(int i = 0; i < l; ++i) {
 				dataView.setInt8(position + l, src.get());
 			}
@@ -200,7 +178,7 @@ public class EaglerArrayByteBuffer implements ByteBuffer {
 
 	@Override
 	public ByteBuffer put(byte[] src, int offset, int length) {
-		if(position + length > limit) throw new ArrayIndexOutOfBoundsException(position + length - 1);
+		if(position + length > limit) throw Buffer.makeIOOBE(position + length - 1);
 		if(offset == 0 && length == src.length) {
 			typedArray.set(TeaVMUtils.unwrapArrayBufferView(src), position);
 		}else {
@@ -212,35 +190,15 @@ public class EaglerArrayByteBuffer implements ByteBuffer {
 
 	@Override
 	public ByteBuffer put(byte[] src) {
-		if(position + src.length > limit) throw new ArrayIndexOutOfBoundsException(position + src.length - 1);
+		if(position + src.length > limit) throw Buffer.makeIOOBE(position + src.length - 1);
 		typedArray.set(TeaVMUtils.unwrapArrayBufferView(src), position);
 		position += src.length;
 		return this;
 	}
 
-	@Override
-	public int arrayOffset() {
-		return position;
-	}
-
-	@Override
-	public ByteBuffer compact() {
-		if(limit > capacity) throw new ArrayIndexOutOfBoundsException(limit);
-		if(position > limit) throw new ArrayIndexOutOfBoundsException(position);
-		
-		if(position == limit) {
-			return new EaglerArrayByteBuffer(ZERO_LENGTH_BUFFER);
-		}
-		
-		Int8Array dst = Int8Array.create(limit - position);
-		dst.set(Int8Array.create(typedArray.getBuffer(), typedArray.getByteOffset() + position, limit - position));
-		
-		return new EaglerArrayByteBuffer(dst);
-	}
-
 	@Override
 	public char getChar() {
-		if(position + 2 > limit) throw new ArrayIndexOutOfBoundsException(position);
+		if(position + 2 > limit) throw Buffer.makeIOOBE(position);
 		char c = (char)dataView.getUint16(position, true);
 		position += 2;
 		return c;
@@ -248,7 +206,7 @@ public class EaglerArrayByteBuffer implements ByteBuffer {
 
 	@Override
 	public ByteBuffer putChar(char value) {
-		if(position + 2 > limit) throw new ArrayIndexOutOfBoundsException(position);
+		if(position + 2 > limit) throw Buffer.makeIOOBE(position);
 		dataView.setUint16(position, (short)value, true);
 		position += 2;
 		return this;
@@ -256,20 +214,20 @@ public class EaglerArrayByteBuffer implements ByteBuffer {
 
 	@Override
 	public char getChar(int index) {
-		if(index + 2 > limit) throw new ArrayIndexOutOfBoundsException(index);
+		if(index < 0 || index + 2 > limit) throw Buffer.makeIOOBE(index);
 		return (char)dataView.getUint16(index, true);
 	}
 
 	@Override
 	public ByteBuffer putChar(int index, char value) {
-		if(index + 2 > limit) throw new ArrayIndexOutOfBoundsException(index);
+		if(index < 0 || index + 2 > limit) throw Buffer.makeIOOBE(index);
 		dataView.setUint16(index, value, true);
 		return this;
 	}
 
 	@Override
 	public short getShort() {
-		if(position + 2 > limit) throw new ArrayIndexOutOfBoundsException(position);
+		if(position + 2 > limit) throw Buffer.makeIOOBE(position);
 		short s = dataView.getInt16(position, true);
 		position += 2;
 		return s;
@@ -277,7 +235,7 @@ public class EaglerArrayByteBuffer implements ByteBuffer {
 
 	@Override
 	public ByteBuffer putShort(short value) {
-		if(position + 2 > limit) throw new ArrayIndexOutOfBoundsException(position);
+		if(position + 2 > limit) throw Buffer.makeIOOBE(position);
 		dataView.setInt16(position, value, true);
 		position += 2;
 		return this;
@@ -285,13 +243,13 @@ public class EaglerArrayByteBuffer implements ByteBuffer {
 
 	@Override
 	public short getShort(int index) {
-		if(index + 2 > limit) throw new ArrayIndexOutOfBoundsException(index);
+		if(index < 0 || index + 2 > limit) throw Buffer.makeIOOBE(index);
 		return dataView.getInt16(index, true);
 	}
 
 	@Override
 	public ByteBuffer putShort(int index, short value) {
-		if(index + 2 > limit) throw new ArrayIndexOutOfBoundsException(index);
+		if(index < 0 || index + 2 > limit) throw Buffer.makeIOOBE(index);
 		dataView.setInt16(index, value, true);
 		return this;
 	}
@@ -303,7 +261,7 @@ public class EaglerArrayByteBuffer implements ByteBuffer {
 
 	@Override
 	public int getInt() {
-		if(position + 4 > limit) throw new ArrayIndexOutOfBoundsException(position);
+		if(position + 4 > limit) throw Buffer.makeIOOBE(position);
 		int i = dataView.getInt32(position, true);
 		position += 4;
 		return i;
@@ -311,7 +269,7 @@ public class EaglerArrayByteBuffer implements ByteBuffer {
 
 	@Override
 	public ByteBuffer putInt(int value) {
-		if(position + 4 > limit) throw new ArrayIndexOutOfBoundsException(position);
+		if(position + 4 > limit) throw Buffer.makeIOOBE(position);
 		dataView.setInt32(position, value, true);
 		position += 4;
 		return this;
@@ -319,13 +277,13 @@ public class EaglerArrayByteBuffer implements ByteBuffer {
 
 	@Override
 	public int getInt(int index) {
-		if(index + 4 > limit) throw new ArrayIndexOutOfBoundsException(index);
+		if(index < 0 || index + 4 > limit) throw Buffer.makeIOOBE(index);
 		return dataView.getInt32(index, true);
 	}
 
 	@Override
 	public ByteBuffer putInt(int index, int value) {
-		if(index + 4 > limit) throw new ArrayIndexOutOfBoundsException(index);
+		if(index < 0 || index + 4 > limit) throw Buffer.makeIOOBE(index);
 		dataView.setInt32(index, value, true);
 		return this;
 	}
@@ -337,7 +295,7 @@ public class EaglerArrayByteBuffer implements ByteBuffer {
 
 	@Override
 	public long getLong() {
-		if(position + 8 > limit) throw new ArrayIndexOutOfBoundsException(position);
+		if(position + 8 > limit) throw Buffer.makeIOOBE(position);
 		long l = dataView.getUint32(position) | ((long) dataView.getUint8(position + 4) << 32)
 				| ((long) dataView.getUint8(position + 5) << 40) | ((long) dataView.getUint8(position + 6) << 48)
 				| ((long) dataView.getUint8(position + 7) << 56);
@@ -347,7 +305,7 @@ public class EaglerArrayByteBuffer implements ByteBuffer {
 
 	@Override
 	public ByteBuffer putLong(long value) {
-		if(position + 8 > limit) throw new ArrayIndexOutOfBoundsException(position);
+		if(position + 8 > limit) throw Buffer.makeIOOBE(position);
 		dataView.setUint32(position, (int) (value & 0xFFFFFFFFl), true);
 		dataView.setUint8(position + 4, (short) ((value >>> 32l) & 0xFFl));
 		dataView.setUint8(position + 5, (short) ((value >>> 40l) & 0xFFl));
@@ -359,7 +317,7 @@ public class EaglerArrayByteBuffer implements ByteBuffer {
 
 	@Override
 	public long getLong(int index) {
-		if(index + 8 > limit) throw new ArrayIndexOutOfBoundsException(index);
+		if(index < 0 || index + 8 > limit) throw Buffer.makeIOOBE(index);
 		return dataView.getUint32(index, true) | ((long) dataView.getUint8(index + 4) << 32)
 				| ((long) dataView.getUint8(index + 5) << 40) | ((long) dataView.getUint8(index + 6) << 48)
 				| ((long) dataView.getUint8(index + 7) << 56);
@@ -367,7 +325,7 @@ public class EaglerArrayByteBuffer implements ByteBuffer {
 
 	@Override
 	public ByteBuffer putLong(int index, long value) {
-		if(index + 8 > limit) throw new ArrayIndexOutOfBoundsException(index);
+		if(index < 0 || index + 8 > limit) throw Buffer.makeIOOBE(index);
 		dataView.setUint32(index, (int) (value & 0xFFFFFFFFl), true);
 		dataView.setUint8(index + 4, (short) ((value >>> 32l) & 0xFFl));
 		dataView.setUint8(index + 5, (short) ((value >>> 40l) & 0xFFl));
@@ -378,7 +336,7 @@ public class EaglerArrayByteBuffer implements ByteBuffer {
 
 	@Override
 	public float getFloat() {
-		if(position + 4 > limit) throw new ArrayIndexOutOfBoundsException(position);
+		if(position + 4 > limit) throw Buffer.makeIOOBE(position);
 		float f = dataView.getFloat32(position, true);
 		position += 4;
 		return f;
@@ -386,7 +344,7 @@ public class EaglerArrayByteBuffer implements ByteBuffer {
 
 	@Override
 	public ByteBuffer putFloat(float value) {
-		if(position + 4 > limit) throw new ArrayIndexOutOfBoundsException(position);
+		if(position + 4 > limit) throw Buffer.makeIOOBE(position);
 		dataView.setFloat32(position, value, true);
 		position += 4;
 		return this;
@@ -394,13 +352,13 @@ public class EaglerArrayByteBuffer implements ByteBuffer {
 
 	@Override
 	public float getFloat(int index) {
-		if(index + 4 > limit) throw new ArrayIndexOutOfBoundsException(index);
+		if(index < 0 || index + 4 > limit) throw Buffer.makeIOOBE(index);
 		return dataView.getFloat32(index, true);
 	}
 
 	@Override
 	public ByteBuffer putFloat(int index, float value) {
-		if(index + 4 > limit) throw new ArrayIndexOutOfBoundsException(index);
+		if(index < 0 || index + 4 > limit) throw Buffer.makeIOOBE(index);
 		dataView.setFloat32(index, value, true);
 		return this;
 	}
@@ -419,7 +377,7 @@ public class EaglerArrayByteBuffer implements ByteBuffer {
 	@Override
 	public ByteBuffer reset() {
 		int m = mark;
-		if(m < 0) throw new ArrayIndexOutOfBoundsException("Invalid mark: " + m);
+		if(m < 0) throw new IndexOutOfBoundsException("Invalid mark: " + m);
 		position = m;
 		return this;
 	}
@@ -449,14 +407,14 @@ public class EaglerArrayByteBuffer implements ByteBuffer {
 
 	@Override
 	public ByteBuffer limit(int newLimit) {
-		if(newLimit < 0 || newLimit > capacity) throw new ArrayIndexOutOfBoundsException(newLimit);
+		if(newLimit < 0 || newLimit > capacity) throw Buffer.makeIOOBE(newLimit);
 		limit = newLimit;
 		return this;
 	}
 
 	@Override
 	public ByteBuffer position(int newPosition) {
-		if(newPosition < 0 || newPosition > limit) throw new ArrayIndexOutOfBoundsException(newPosition);
+		if(newPosition < 0 || newPosition > limit) throw Buffer.makeIOOBE(newPosition);
 		position = newPosition;
 		return this;
 	}
diff --git a/sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/buffer/EaglerArrayFloatBuffer.java b/sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/buffer/EaglerArrayFloatBuffer.java
index 4e9ffe9d..396676a0 100644
--- a/sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/buffer/EaglerArrayFloatBuffer.java
+++ b/sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/buffer/EaglerArrayFloatBuffer.java
@@ -27,11 +27,9 @@ public class EaglerArrayFloatBuffer implements FloatBuffer {
 	int position;
 	int limit;
 	int mark;
-	
+
 	private static final int SHIFT = 2;
-	
-	static final Float32Array ZERO_LENGTH_BUFFER = Float32Array.create(0);
-	
+
 	EaglerArrayFloatBuffer(Float32Array typedArray) {
 		this.typedArray = typedArray;
 		this.capacity = typedArray.getLength();
@@ -39,7 +37,7 @@ public class EaglerArrayFloatBuffer implements FloatBuffer {
 		this.limit = this.capacity;
 		this.mark = -1;
 	}
-	
+
 	EaglerArrayFloatBuffer(Float32Array typedArray, int position, int limit, int mark) {
 		this.typedArray = typedArray;
 		this.capacity = typedArray.getLength();
@@ -47,7 +45,7 @@ public class EaglerArrayFloatBuffer implements FloatBuffer {
 		this.limit = limit;
 		this.mark = mark;
 	}
-	
+
 	@Override
 	public int capacity() {
 		return capacity;
@@ -73,87 +71,62 @@ public class EaglerArrayFloatBuffer implements FloatBuffer {
 		return position < limit;
 	}
 
-	@Override
-	public boolean isReadOnly() {
-		return false;
-	}
-
 	@Override
 	public boolean hasArray() {
 		return false;
 	}
 
 	@Override
-	public Object array() {
+	public float[] array() {
 		throw new UnsupportedOperationException();
 	}
 
-	@Override
-	public int arrayOffset() {
-		return position;
-	}
-
-	@Override
-	public FloatBuffer slice() {
-		if(position == limit) {
-			return new EaglerArrayFloatBuffer(ZERO_LENGTH_BUFFER);
-		}else {
-			if(position > limit) throw new ArrayIndexOutOfBoundsException(position);
-			return new EaglerArrayFloatBuffer(Float32Array.create(typedArray.getBuffer(), typedArray.getByteOffset() + (position << SHIFT), limit - position));
-		}
-	}
-
 	@Override
 	public FloatBuffer duplicate() {
 		return new EaglerArrayFloatBuffer(typedArray, position, limit, mark);
 	}
 
-	@Override
-	public FloatBuffer asReadOnlyBuffer() {
-		return new EaglerArrayFloatBuffer(typedArray, position, limit, mark);
-	}
-
 	@Override
 	public float get() {
-		if(position >= limit) throw new ArrayIndexOutOfBoundsException(position);
+		if(position >= limit) throw Buffer.makeIOOBE(position);
 		return typedArray.get(position++);
 	}
 
 	@Override
 	public FloatBuffer put(float b) {
-		if(position >= limit) throw new ArrayIndexOutOfBoundsException(position);
+		if(position >= limit) throw Buffer.makeIOOBE(position);
 		typedArray.set(position++, b);
 		return this;
 	}
 
 	@Override
 	public float get(int index) {
-		if(index >= limit) throw new ArrayIndexOutOfBoundsException(index);
+		if(index < 0 || index >= limit) throw Buffer.makeIOOBE(index);
 		return typedArray.get(index);
 	}
 
 	@Override
 	public FloatBuffer put(int index, float b) {
-		if(index >= limit) throw new ArrayIndexOutOfBoundsException(index);
+		if(index < 0 || index >= limit) throw Buffer.makeIOOBE(index);
 		typedArray.set(index, b);
 		return this;
 	}
 
 	@Override
 	public float getElement(int index) {
-		if(index >= limit) throw new ArrayIndexOutOfBoundsException(index);
+		if(index < 0 || index >= limit) throw Buffer.makeIOOBE(index);
 		return typedArray.get(index);
 	}
 
 	@Override
 	public void putElement(int index, float value) {
-		if(index >= limit) throw new ArrayIndexOutOfBoundsException(index);
+		if(index < 0 || index >= limit) throw Buffer.makeIOOBE(index);
 		typedArray.set(index, value);
 	}
 
 	@Override
 	public FloatBuffer get(float[] dst, int offset, int length) {
-		if(position + length > limit) throw new ArrayIndexOutOfBoundsException(position + length - 1);
+		if(position + length > limit) Buffer.makeIOOBE(position + length - 1);
 		TeaVMUtils.unwrapArrayBufferView(dst).set(Float32Array.create(typedArray.getBuffer(), typedArray.getByteOffset() + (position << SHIFT), length), offset);
 		position += length;
 		return this;
@@ -161,7 +134,7 @@ public class EaglerArrayFloatBuffer implements FloatBuffer {
 
 	@Override
 	public FloatBuffer get(float[] dst) {
-		if(position + dst.length > limit) throw new ArrayIndexOutOfBoundsException(position + dst.length - 1);
+		if(position + dst.length > limit) Buffer.makeIOOBE(position + dst.length - 1);
 		TeaVMUtils.unwrapArrayBufferView(dst).set(Float32Array.create(typedArray.getBuffer(), typedArray.getByteOffset() + (position << SHIFT), dst.length));
 		position += dst.length;
 		return this;
@@ -172,13 +145,13 @@ public class EaglerArrayFloatBuffer implements FloatBuffer {
 		if(src instanceof EaglerArrayFloatBuffer) {
 			EaglerArrayFloatBuffer c = (EaglerArrayFloatBuffer)src;
 			int l = c.limit - c.position;
-			if(position + l > limit) throw new ArrayIndexOutOfBoundsException(position + l - 1);
+			if(position + l > limit) throw Buffer.makeIOOBE(position + l - 1);
 			typedArray.set(Float32Array.create(c.typedArray.getBuffer(), c.typedArray.getByteOffset() + (c.position << SHIFT), l), position);
 			position += l;
 			c.position += l;
 		}else {
 			int l = src.remaining();
-			if(position + l > limit) throw new ArrayIndexOutOfBoundsException(position + l - 1);
+			if(position + l > limit) throw Buffer.makeIOOBE(position + l - 1);
 			for(int i = 0; i < l; ++i) {
 				typedArray.set(position + l, src.get());
 			}
@@ -189,7 +162,7 @@ public class EaglerArrayFloatBuffer implements FloatBuffer {
 
 	@Override
 	public FloatBuffer put(float[] src, int offset, int length) {
-		if(position + length > limit) throw new ArrayIndexOutOfBoundsException(position + length - 1);
+		if(position + length > limit) throw Buffer.makeIOOBE(position + length - 1);
 		if(offset == 0 && length == src.length) {
 			typedArray.set(TeaVMUtils.unwrapArrayBufferView(src), position);
 		}else {
@@ -201,32 +174,12 @@ public class EaglerArrayFloatBuffer implements FloatBuffer {
 
 	@Override
 	public FloatBuffer put(float[] src) {
-		if(position + src.length > limit) throw new ArrayIndexOutOfBoundsException(position + src.length - 1);
+		if(position + src.length > limit) throw Buffer.makeIOOBE(position + src.length - 1);
 		typedArray.set(TeaVMUtils.unwrapArrayBufferView(src), position);
 		position += src.length;
 		return this;
 	}
 
-	@Override
-	public int getArrayOffset() {
-		return position;
-	}
-
-	@Override
-	public FloatBuffer compact() {
-		if(limit > capacity) throw new ArrayIndexOutOfBoundsException(limit);
-		if(position > limit) throw new ArrayIndexOutOfBoundsException(position);
-		
-		if(position == limit) {
-			return new EaglerArrayFloatBuffer(ZERO_LENGTH_BUFFER);
-		}
-		
-		Float32Array dst = Float32Array.create(limit - position);
-		dst.set(Float32Array.create(typedArray.getBuffer(), typedArray.getByteOffset() + (position << SHIFT), limit - position));
-		
-		return new EaglerArrayFloatBuffer(dst);
-	}
-
 	@Override
 	public boolean isDirect() {
 		return true;
@@ -241,7 +194,7 @@ public class EaglerArrayFloatBuffer implements FloatBuffer {
 	@Override
 	public FloatBuffer reset() {
 		int m = mark;
-		if(m < 0) throw new ArrayIndexOutOfBoundsException("Invalid mark: " + m);
+		if(m < 0) throw new IndexOutOfBoundsException("Invalid mark: " + m);
 		position = m;
 		return this;
 	}
@@ -271,14 +224,14 @@ public class EaglerArrayFloatBuffer implements FloatBuffer {
 
 	@Override
 	public FloatBuffer limit(int newLimit) {
-		if(newLimit < 0 || newLimit > capacity) throw new ArrayIndexOutOfBoundsException(newLimit);
+		if(newLimit < 0 || newLimit > capacity) throw Buffer.makeIOOBE(newLimit);
 		limit = newLimit;
 		return this;
 	}
 
 	@Override
 	public FloatBuffer position(int newPosition) {
-		if(newPosition < 0 || newPosition > limit) throw new ArrayIndexOutOfBoundsException(newPosition);
+		if(newPosition < 0 || newPosition > limit) throw Buffer.makeIOOBE(newPosition);
 		position = newPosition;
 		return this;
 	}
diff --git a/sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/buffer/EaglerArrayIntBuffer.java b/sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/buffer/EaglerArrayIntBuffer.java
index 7aee34a7..af0b86be 100644
--- a/sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/buffer/EaglerArrayIntBuffer.java
+++ b/sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/buffer/EaglerArrayIntBuffer.java
@@ -27,11 +27,9 @@ public class EaglerArrayIntBuffer implements IntBuffer {
 	int position;
 	int limit;
 	int mark;
-	
+
 	private static final int SHIFT = 2;
-	
-	static final Int32Array ZERO_LENGTH_BUFFER = Int32Array.create(0);
-	
+
 	EaglerArrayIntBuffer(Int32Array typedArray) {
 		this.typedArray = typedArray;
 		this.capacity = typedArray.getLength();
@@ -39,7 +37,7 @@ public class EaglerArrayIntBuffer implements IntBuffer {
 		this.limit = this.capacity;
 		this.mark = -1;
 	}
-	
+
 	EaglerArrayIntBuffer(Int32Array typedArray, int position, int limit, int mark) {
 		this.typedArray = typedArray;
 		this.capacity = typedArray.getLength();
@@ -47,7 +45,7 @@ public class EaglerArrayIntBuffer implements IntBuffer {
 		this.limit = limit;
 		this.mark = mark;
 	}
-	
+
 	@Override
 	public int capacity() {
 		return capacity;
@@ -73,87 +71,62 @@ public class EaglerArrayIntBuffer implements IntBuffer {
 		return position < limit;
 	}
 
-	@Override
-	public boolean isReadOnly() {
-		return false;
-	}
-
 	@Override
 	public boolean hasArray() {
 		return false;
 	}
 
 	@Override
-	public Object array() {
+	public int[] array() {
 		throw new UnsupportedOperationException();
 	}
 
-	@Override
-	public int arrayOffset() {
-		return position;
-	}
-
-	@Override
-	public IntBuffer slice() {
-		if(position == limit) {
-			return new EaglerArrayIntBuffer(ZERO_LENGTH_BUFFER);
-		}else {
-			if(position > limit) throw new ArrayIndexOutOfBoundsException(position);
-			return new EaglerArrayIntBuffer(Int32Array.create(typedArray.getBuffer(), typedArray.getByteOffset() + (position << SHIFT), limit - position));
-		}
-	}
-
 	@Override
 	public IntBuffer duplicate() {
 		return new EaglerArrayIntBuffer(typedArray, position, limit, mark);
 	}
 
-	@Override
-	public IntBuffer asReadOnlyBuffer() {
-		return new EaglerArrayIntBuffer(typedArray, position, limit, mark);
-	}
-
 	@Override
 	public int get() {
-		if(position >= limit) throw new ArrayIndexOutOfBoundsException(position);
+		if(position >= limit) throw Buffer.makeIOOBE(position);
 		return typedArray.get(position++);
 	}
 
 	@Override
 	public IntBuffer put(int b) {
-		if(position >= limit) throw new ArrayIndexOutOfBoundsException(position);
+		if(position >= limit) throw Buffer.makeIOOBE(position);
 		typedArray.set(position++, b);
 		return this;
 	}
 
 	@Override
 	public int get(int index) {
-		if(index >= limit) throw new ArrayIndexOutOfBoundsException(index);
+		if(index < 0 || index >= limit) throw Buffer.makeIOOBE(index);
 		return typedArray.get(index);
 	}
 
 	@Override
 	public IntBuffer put(int index, int b) {
-		if(index >= limit) throw new ArrayIndexOutOfBoundsException(index);
+		if(index < 0 || index >= limit) throw Buffer.makeIOOBE(index);
 		typedArray.set(index, b);
 		return this;
 	}
 
 	@Override
 	public int getElement(int index) {
-		if(index >= limit) throw new ArrayIndexOutOfBoundsException(index);
+		if(index < 0 || index >= limit) throw Buffer.makeIOOBE(index);
 		return typedArray.get(index);
 	}
 
 	@Override
 	public void putElement(int index, int value) {
-		if(index >= limit) throw new ArrayIndexOutOfBoundsException(index);
+		if(index < 0 || index >= limit) throw Buffer.makeIOOBE(index);
 		typedArray.set(index, value);
 	}
 
 	@Override
 	public IntBuffer get(int[] dst, int offset, int length) {
-		if(position + length > limit) throw new ArrayIndexOutOfBoundsException(position + length - 1);
+		if(position + length > limit) throw Buffer.makeIOOBE(position + length - 1);
 		TeaVMUtils.unwrapArrayBufferView(dst).set(Int32Array.create(typedArray.getBuffer(), typedArray.getByteOffset() + (position << SHIFT), length), offset);
 		position += length;
 		return this;
@@ -161,7 +134,7 @@ public class EaglerArrayIntBuffer implements IntBuffer {
 
 	@Override
 	public IntBuffer get(int[] dst) {
-		if(position + dst.length > limit) throw new ArrayIndexOutOfBoundsException(position + dst.length - 1);
+		if(position + dst.length > limit) throw Buffer.makeIOOBE(position + dst.length - 1);
 		TeaVMUtils.unwrapArrayBufferView(dst).set(Int32Array.create(typedArray.getBuffer(), typedArray.getByteOffset() + (position << SHIFT), dst.length));
 		position += dst.length;
 		return this;
@@ -172,13 +145,13 @@ public class EaglerArrayIntBuffer implements IntBuffer {
 		if(src instanceof EaglerArrayIntBuffer) {
 			EaglerArrayIntBuffer c = (EaglerArrayIntBuffer)src;
 			int l = c.limit - c.position;
-			if(position + l > limit) throw new ArrayIndexOutOfBoundsException(position + l - 1);
+			if(position + l > limit) throw Buffer.makeIOOBE(position + l - 1);
 			typedArray.set(Int32Array.create(c.typedArray.getBuffer(), c.typedArray.getByteOffset() + (c.position << SHIFT), l), position);
 			position += l;
 			c.position += l;
 		}else {
 			int l = src.remaining();
-			if(position + l > limit) throw new ArrayIndexOutOfBoundsException(position + l - 1);
+			if(position + l > limit) throw Buffer.makeIOOBE(position + l - 1);
 			for(int i = 0; i < l; ++i) {
 				typedArray.set(position + l, src.get());
 			}
@@ -189,7 +162,7 @@ public class EaglerArrayIntBuffer implements IntBuffer {
 
 	@Override
 	public IntBuffer put(int[] src, int offset, int length) {
-		if(position + length > limit) throw new ArrayIndexOutOfBoundsException(position + length - 1);
+		if(position + length > limit) throw Buffer.makeIOOBE(position + length - 1);
 		if(offset == 0 && length == src.length) {
 			typedArray.set(TeaVMUtils.unwrapArrayBufferView(src), position);
 		}else {
@@ -201,32 +174,12 @@ public class EaglerArrayIntBuffer implements IntBuffer {
 
 	@Override
 	public IntBuffer put(int[] src) {
-		if(position + src.length > limit) throw new ArrayIndexOutOfBoundsException(position + src.length - 1);
+		if(position + src.length > limit) throw Buffer.makeIOOBE(position + src.length - 1);
 		typedArray.set(TeaVMUtils.unwrapArrayBufferView(src), position);
 		position += src.length;
 		return this;
 	}
 
-	@Override
-	public int getArrayOffset() {
-		return position;
-	}
-
-	@Override
-	public IntBuffer compact() {
-		if(limit > capacity) throw new ArrayIndexOutOfBoundsException(limit);
-		if(position > limit) throw new ArrayIndexOutOfBoundsException(position);
-		
-		if(position == limit) {
-			return new EaglerArrayIntBuffer(ZERO_LENGTH_BUFFER);
-		}
-		
-		Int32Array dst = Int32Array.create(limit - position);
-		dst.set(Int32Array.create(typedArray.getBuffer(), typedArray.getByteOffset() + (position << SHIFT), limit - position));
-		
-		return new EaglerArrayIntBuffer(dst);
-	}
-
 	@Override
 	public boolean isDirect() {
 		return true;
@@ -241,7 +194,7 @@ public class EaglerArrayIntBuffer implements IntBuffer {
 	@Override
 	public IntBuffer reset() {
 		int m = mark;
-		if(m < 0) throw new ArrayIndexOutOfBoundsException("Invalid mark: " + m);
+		if(m < 0) throw new IndexOutOfBoundsException("Invalid mark: " + m);
 		position = m;
 		return this;
 	}
@@ -271,14 +224,14 @@ public class EaglerArrayIntBuffer implements IntBuffer {
 
 	@Override
 	public IntBuffer limit(int newLimit) {
-		if(newLimit < 0 || newLimit > capacity) throw new ArrayIndexOutOfBoundsException(newLimit);
+		if(newLimit < 0 || newLimit > capacity) throw Buffer.makeIOOBE(newLimit);
 		limit = newLimit;
 		return this;
 	}
 
 	@Override
 	public IntBuffer position(int newPosition) {
-		if(newPosition < 0 || newPosition > limit) throw new ArrayIndexOutOfBoundsException(newPosition);
+		if(newPosition < 0 || newPosition > limit) throw Buffer.makeIOOBE(newPosition);
 		position = newPosition;
 		return this;
 	}
diff --git a/sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/buffer/EaglerArrayShortBuffer.java b/sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/buffer/EaglerArrayShortBuffer.java
index 16eabb53..80bb3ddb 100644
--- a/sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/buffer/EaglerArrayShortBuffer.java
+++ b/sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/buffer/EaglerArrayShortBuffer.java
@@ -27,11 +27,9 @@ public class EaglerArrayShortBuffer implements ShortBuffer {
 	int position;
 	int limit;
 	int mark;
-	
+
 	private static final int SHIFT = 1;
-	
-	static final Int16Array ZERO_LENGTH_BUFFER = Int16Array.create(0);
-	
+
 	EaglerArrayShortBuffer(Int16Array typedArray) {
 		this.typedArray = typedArray;
 		this.capacity = typedArray.getLength();
@@ -39,7 +37,7 @@ public class EaglerArrayShortBuffer implements ShortBuffer {
 		this.limit = this.capacity;
 		this.mark = -1;
 	}
-	
+
 	EaglerArrayShortBuffer(Int16Array typedArray, int position, int limit, int mark) {
 		this.typedArray = typedArray;
 		this.capacity = typedArray.getLength();
@@ -47,7 +45,7 @@ public class EaglerArrayShortBuffer implements ShortBuffer {
 		this.limit = limit;
 		this.mark = mark;
 	}
-	
+
 	@Override
 	public int capacity() {
 		return capacity;
@@ -73,87 +71,62 @@ public class EaglerArrayShortBuffer implements ShortBuffer {
 		return position < limit;
 	}
 
-	@Override
-	public boolean isReadOnly() {
-		return false;
-	}
-
 	@Override
 	public boolean hasArray() {
 		return false;
 	}
 
 	@Override
-	public Object array() {
+	public short[] array() {
 		throw new UnsupportedOperationException();
 	}
 
-	@Override
-	public int arrayOffset() {
-		return position;
-	}
-
-	@Override
-	public ShortBuffer slice() {
-		if(position == limit) {
-			return new EaglerArrayShortBuffer(ZERO_LENGTH_BUFFER);
-		}else {
-			if(position > limit) throw new ArrayIndexOutOfBoundsException(position);
-			return new EaglerArrayShortBuffer(Int16Array.create(typedArray.getBuffer(), typedArray.getByteOffset() + (position << SHIFT), limit - position));
-		}
-	}
-
 	@Override
 	public ShortBuffer duplicate() {
 		return new EaglerArrayShortBuffer(typedArray, position, limit, mark);
 	}
 
-	@Override
-	public ShortBuffer asReadOnlyBuffer() {
-		return new EaglerArrayShortBuffer(typedArray, position, limit, mark);
-	}
-
 	@Override
 	public short get() {
-		if(position >= limit) throw new ArrayIndexOutOfBoundsException(position);
+		if(position >= limit) throw Buffer.makeIOOBE(position);
 		return typedArray.get(position++);
 	}
 
 	@Override
 	public ShortBuffer put(short b) {
-		if(position >= limit) throw new ArrayIndexOutOfBoundsException(position);
+		if(position >= limit) throw Buffer.makeIOOBE(position);
 		typedArray.set(position++, b);
 		return this;
 	}
 
 	@Override
 	public short get(int index) {
-		if(index >= limit) throw new ArrayIndexOutOfBoundsException(index);
+		if(index < 0 || index >= limit) throw Buffer.makeIOOBE(index);
 		return typedArray.get(index);
 	}
 
 	@Override
 	public ShortBuffer put(int index, short b) {
-		if(index >= limit) throw new ArrayIndexOutOfBoundsException(index);
+		if(index < 0 || index >= limit) throw Buffer.makeIOOBE(index);
 		typedArray.set(index, b);
 		return this;
 	}
 
 	@Override
 	public short getElement(int index) {
-		if(index >= limit) throw new ArrayIndexOutOfBoundsException(index);
+		if(index < 0 || index >= limit) throw Buffer.makeIOOBE(index);
 		return typedArray.get(index);
 	}
 
 	@Override
 	public void putElement(int index, short value) {
-		if(index >= limit) throw new ArrayIndexOutOfBoundsException(index);
+		if(index < 0 || index >= limit) throw Buffer.makeIOOBE(index);
 		typedArray.set(index, value);
 	}
 
 	@Override
 	public ShortBuffer get(short[] dst, int offset, int length) {
-		if(position + length > limit) throw new ArrayIndexOutOfBoundsException(position + length - 1);
+		if(position + length > limit) throw Buffer.makeIOOBE(position + length - 1);
 		TeaVMUtils.unwrapArrayBufferView(dst).set(Int16Array.create(typedArray.getBuffer(), typedArray.getByteOffset() + (position << SHIFT), length), offset);
 		position += length;
 		return this;
@@ -161,7 +134,7 @@ public class EaglerArrayShortBuffer implements ShortBuffer {
 
 	@Override
 	public ShortBuffer get(short[] dst) {
-		if(position + dst.length > limit) throw new ArrayIndexOutOfBoundsException(position + dst.length - 1);
+		if(position + dst.length > limit) throw Buffer.makeIOOBE(position + dst.length - 1);
 		TeaVMUtils.unwrapArrayBufferView(dst).set(Int16Array.create(typedArray.getBuffer(), typedArray.getByteOffset() + (position << SHIFT), dst.length));
 		position += dst.length;
 		return this;
@@ -172,13 +145,13 @@ public class EaglerArrayShortBuffer implements ShortBuffer {
 		if(src instanceof EaglerArrayShortBuffer) {
 			EaglerArrayShortBuffer c = (EaglerArrayShortBuffer)src;
 			int l = c.limit - c.position;
-			if(position + l > limit) throw new ArrayIndexOutOfBoundsException(position + l - 1);
+			if(position + l > limit) throw Buffer.makeIOOBE(position + l - 1);
 			typedArray.set(Int16Array.create(c.typedArray.getBuffer(), c.typedArray.getByteOffset() + (c.position << SHIFT), l), position);
 			position += l;
 			c.position += l;
 		}else {
 			int l = src.remaining();
-			if(position + l > limit) throw new ArrayIndexOutOfBoundsException(position + l - 1);
+			if(position + l > limit) throw Buffer.makeIOOBE(position + l - 1);
 			for(int i = 0; i < l; ++i) {
 				typedArray.set(position + l, src.get());
 			}
@@ -189,7 +162,7 @@ public class EaglerArrayShortBuffer implements ShortBuffer {
 
 	@Override
 	public ShortBuffer put(short[] src, int offset, int length) {
-		if(position + length > limit) throw new ArrayIndexOutOfBoundsException(position + length - 1);
+		if(position + length > limit) throw Buffer.makeIOOBE(position + length - 1);
 		if(offset == 0 && length == src.length) {
 			typedArray.set(TeaVMUtils.unwrapArrayBufferView(src), position);
 		}else {
@@ -201,32 +174,12 @@ public class EaglerArrayShortBuffer implements ShortBuffer {
 
 	@Override
 	public ShortBuffer put(short[] src) {
-		if(position + src.length > limit) throw new ArrayIndexOutOfBoundsException(position + src.length - 1);
+		if(position + src.length > limit) throw Buffer.makeIOOBE(position + src.length - 1);
 		typedArray.set(TeaVMUtils.unwrapArrayBufferView(src), position);
 		position += src.length;
 		return this;
 	}
 
-	@Override
-	public int getArrayOffset() {
-		return position;
-	}
-
-	@Override
-	public ShortBuffer compact() {
-		if(limit > capacity) throw new ArrayIndexOutOfBoundsException(limit);
-		if(position > limit) throw new ArrayIndexOutOfBoundsException(position);
-		
-		if(position == limit) {
-			return new EaglerArrayShortBuffer(ZERO_LENGTH_BUFFER);
-		}
-		
-		Int16Array dst = Int16Array.create(limit - position);
-		dst.set(Int16Array.create(typedArray.getBuffer(), typedArray.getByteOffset() + (position << SHIFT), limit - position));
-		
-		return new EaglerArrayShortBuffer(dst);
-	}
-
 	@Override
 	public boolean isDirect() {
 		return true;
@@ -241,7 +194,7 @@ public class EaglerArrayShortBuffer implements ShortBuffer {
 	@Override
 	public ShortBuffer reset() {
 		int m = mark;
-		if(m < 0) throw new ArrayIndexOutOfBoundsException("Invalid mark: " + m);
+		if(m < 0) throw new IndexOutOfBoundsException("Invalid mark: " + m);
 		position = m;
 		return this;
 	}
@@ -271,14 +224,14 @@ public class EaglerArrayShortBuffer implements ShortBuffer {
 
 	@Override
 	public ShortBuffer limit(int newLimit) {
-		if(newLimit < 0 || newLimit > capacity) throw new ArrayIndexOutOfBoundsException(newLimit);
+		if(newLimit < 0 || newLimit > capacity) throw Buffer.makeIOOBE(newLimit);
 		limit = newLimit;
 		return this;
 	}
 
 	@Override
 	public ShortBuffer position(int newPosition) {
-		if(newPosition < 0 || newPosition > limit) throw new ArrayIndexOutOfBoundsException(newPosition);
+		if(newPosition < 0 || newPosition > limit) throw Buffer.makeIOOBE(newPosition);
 		position = newPosition;
 		return this;
 	}
diff --git a/sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/teavm/AdvancedHTMLIFrameElement.java b/sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/teavm/AdvancedHTMLIFrameElement.java
new file mode 100644
index 00000000..cfaba268
--- /dev/null
+++ b/sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/teavm/AdvancedHTMLIFrameElement.java
@@ -0,0 +1,120 @@
+package net.lax1dude.eaglercraft.v1_8.internal.teavm;
+
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Set;
+
+import org.apache.commons.lang3.StringUtils;
+import org.teavm.jso.JSBody;
+import org.teavm.jso.JSProperty;
+import org.teavm.jso.dom.html.HTMLIFrameElement;
+import org.teavm.jso.dom.types.DOMTokenList;
+
+import com.google.common.collect.Iterators;
+
+/**
+ * Copyright (c) 2024 lax1dude. All Rights Reserved.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ * 
+ */
+public abstract class AdvancedHTMLIFrameElement implements HTMLIFrameElement {
+
+	@JSProperty
+	public abstract void setAllow(String str);
+
+	@JSProperty
+	public abstract String getAllow();
+
+	public void setAllowSafe(String requiredValue) {
+		setAllow(requiredValue);
+		if(!requiredValue.equals(getAllow())) {
+			throw new IFrameSafetyException("Could not set allow attribute to: " + requiredValue);
+		}
+	}
+
+	@JSProperty
+	public abstract void setAllowFullscreen(boolean en);
+
+	@JSProperty
+	public abstract void setCredentialless(boolean en);
+
+	@JSProperty
+	public abstract void setLoading(String str);
+
+	@JSProperty
+	public abstract void setReferrerPolicy(String str);
+
+	@JSProperty("csp")
+	public abstract void setCSP(String str);
+
+	@JSProperty
+	public abstract void setSandbox(String str);
+
+	@JSProperty
+	public abstract DOMTokenList getSandbox();
+
+	public void assertSafetyFeaturesSupported() {
+		if(!checkSafetyFeaturesSupported()) {
+			throw new IFrameSafetyException("Some required security features are not supported on this browser!");
+		}
+	}
+
+	public void setSandboxSafe(Collection<String> requiredTokens) {
+		setSandboxSafe(new HashSet<>(requiredTokens));
+	}
+
+	public void setSandboxSafe(Set<String> requiredTokens) {
+		setSandbox(String.join(" ", requiredTokens));
+		DOMTokenList theSandbox = getSandbox();
+		for(String s : requiredTokens) {
+			if(!theSandbox.contains(s)) {
+				throw new IFrameSafetyException("Failed to set sandbox attribute: " + s);
+			}
+		}
+		int l = theSandbox.getLength();
+		for(int i = 0; i < l; ++i) {
+			String s = theSandbox.item(i);
+			if(!requiredTokens.contains(s)) {
+				throw new IFrameSafetyException("Unknown sandbox attribute detected: " + s);
+			}
+		}
+	}
+
+	public void setSandboxSafe(Collection<String> requiredTokens, Collection<String> optionalTokens) {
+		setSandboxSafe(new HashSet<>(requiredTokens), new HashSet<>(optionalTokens));
+	}
+
+	public void setSandboxSafe(Set<String> requiredTokens, Set<String> optionalTokens) {
+		setSandbox(StringUtils.join(Iterators.concat(requiredTokens.iterator(), optionalTokens.iterator()), " "));
+		DOMTokenList theSandbox = getSandbox();
+		for(String s : requiredTokens) {
+			if(!theSandbox.contains(s)) {
+				throw new IFrameSafetyException("Failed to set sandbox attribute: " + s);
+			}
+		}
+		int l = theSandbox.getLength();
+		for(int i = 0; i < l; ++i) {
+			String s = theSandbox.item(i);
+			if(!requiredTokens.contains(s) && !optionalTokens.contains(s)) {
+				throw new IFrameSafetyException("Unknown sandbox attribute detected: " + s);
+			}
+		}
+	}
+
+	@JSBody(params = {}, script = "return (typeof this.allow === \"string\") && (typeof this.sandbox === \"object\");")
+	public native boolean checkSafetyFeaturesSupported();
+
+	@JSBody(params = {}, script = "return (typeof this.csp === \"string\");")
+	public native boolean checkCSPSupported();
+
+}
diff --git a/sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/teavm/ArrayBufferInputStream.java b/sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/teavm/ArrayBufferInputStream.java
index 6112d4df..4adb6be0 100644
--- a/sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/teavm/ArrayBufferInputStream.java
+++ b/sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/teavm/ArrayBufferInputStream.java
@@ -1,12 +1,14 @@
 package net.lax1dude.eaglercraft.v1_8.internal.teavm;
 
+import java.io.IOException;
 import java.io.InputStream;
 
 import org.teavm.jso.typedarrays.ArrayBuffer;
+import org.teavm.jso.typedarrays.Int8Array;
 import org.teavm.jso.typedarrays.Uint8Array;
 
 /**
- * Copyright (c) 2022 lax1dude. All Rights Reserved.
+ * Copyright (c) 2022-2024 lax1dude. All Rights Reserved.
  * 
  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
@@ -21,16 +23,17 @@ import org.teavm.jso.typedarrays.Uint8Array;
  * 
  */
 public class ArrayBufferInputStream extends InputStream {
-	
+
+	private int mark = -1;
 	private int position;
 	private int limit;
 	private final ArrayBuffer buffer;
 	private final Uint8Array typed;
-	
+
 	public ArrayBufferInputStream(ArrayBuffer bufferIn) {
 		this(bufferIn, 0, bufferIn.getByteLength());
 	}
-	
+
 	public ArrayBufferInputStream(ArrayBuffer bufferIn, int off, int len) {
 		if(off + len > bufferIn.getByteLength()) {
 			throw new IllegalArgumentException("offset " + off + " and length " + len + " are out of bounds for a "
@@ -66,15 +69,14 @@ public class ArrayBufferInputStream extends InputStream {
 			return -1;
 		}
 		
-		for(int i = 0; i < len; ++i) {
-			b[off + i] = (byte)typed.get(position + i);
-		}
+		TeaVMUtils.unwrapArrayBufferView(b).set(Int8Array.create(buffer, position, len), off);
 		
 		position += len;
 		
 		return len;
 	}
-	
+
+	@Override
 	public long skip(long n) {
 		int avail = limit - position;
 		if(n > avail) {
@@ -83,7 +85,7 @@ public class ArrayBufferInputStream extends InputStream {
 		position += (int)n;
 		return n;
 	}
-	
+
 	@Override
 	public int available() {
 		return limit - position;
@@ -101,4 +103,21 @@ public class ArrayBufferInputStream extends InputStream {
 		return buffer;
 	}
 
+	@Override
+	public boolean markSupported() {
+		return true;
+	}
+
+	@Override
+	public synchronized void mark(int readlimit) {
+		mark = position;
+	}
+
+	@Override
+	public synchronized void reset() throws IOException {
+		if(mark == -1) {
+			throw new IOException("Cannot reset, stream has no mark!");
+		}
+		position = mark;
+	}
 }
diff --git a/sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/teavm/Base64VarIntArray.java b/sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/teavm/Base64VarIntArray.java
new file mode 100644
index 00000000..9f46b148
--- /dev/null
+++ b/sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/teavm/Base64VarIntArray.java
@@ -0,0 +1,129 @@
+package net.lax1dude.eaglercraft.v1_8.internal.teavm;
+
+import java.util.Arrays;
+import java.util.List;
+
+import org.teavm.jso.core.JSString;
+
+import net.lax1dude.eaglercraft.v1_8.Base64;
+
+/**
+ * Copyright (c) 2024 lax1dude. All Rights Reserved.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ * 
+ */
+public class Base64VarIntArray {
+
+	public static String encodeVarIntArray(List<Integer> values) {
+		StringBuilder ret = new StringBuilder();
+		for(int i = 0, j, k, l = values.size(); i < l; ++i) {
+			j = values.get(i);
+			if(j < 0) j = 0;
+			for(;;) {
+				k = j & 31;
+				if(j > 31) {
+					j >>>= 5;
+					ret.append(Base64.lookupIntChar(k | 32));
+				}else {
+					ret.append(Base64.lookupIntChar(k));
+					break;
+				}
+			}
+		}
+		return ret.toString();
+	}
+
+	public static String encodeVarIntArray(int[] values) {
+		StringBuilder ret = new StringBuilder();
+		for(int i = 0, j, k; i < values.length; ++i) {
+			j = values[i];
+			if(j < 0) j = 0;
+			for(;;) {
+				k = j & 31;
+				if(j > 31) {
+					j >>>= 5;
+					ret.append(Base64.lookupIntChar(k | 32));
+				}else {
+					ret.append(Base64.lookupIntChar(k));
+					break;
+				}
+			}
+		}
+		return ret.toString();
+	}
+
+	public static int[] decodeVarIntArray(String values) {
+		int[] ret = new int[8];
+		int o = 0;
+		for(int i = 0, j, k, m, l = values.length(); i < l;) {
+			k = 0;
+			m = 0;
+			for(;;) {
+				j = Base64.lookupCharInt(values.charAt(i++));
+				if(j == -1) {
+					return null;
+				}
+				k |= (j & 31) << m;
+				if(j > 31) {
+					if(i >= l) {
+						return null;
+					}
+					m += 5;
+				}else {
+					break;
+				}
+			}
+			j = ret.length;
+			if(o >= j) {
+				int[] newRet = new int[j << 1];
+				System.arraycopy(ret, 0, newRet, 0, j);
+				ret = newRet;
+			}
+			ret[o++] = k;
+		}
+		return o != ret.length ? Arrays.copyOf(ret, o) : ret;
+	}
+
+	public static int[] decodeVarIntArray(JSString values) {
+		int[] ret = new int[8];
+		int o = 0;
+		for(int i = 0, j, k, m, l = values.getLength(); i < l;) {
+			k = 0;
+			m = 0;
+			for(;;) {
+				j = Base64.lookupCharInt((char)values.charCodeAt(i++));
+				if(j == -1) {
+					return null;
+				}
+				k |= (j & 31) << m;
+				if(j > 31) {
+					if(i >= l) {
+						return null;
+					}
+					m += 5;
+				}else {
+					break;
+				}
+			}
+			j = ret.length;
+			if(o >= j) {
+				int[] newRet = new int[j << 1];
+				System.arraycopy(ret, 0, newRet, 0, j);
+				ret = newRet;
+			}
+			ret[o++] = k;
+		}
+		return o != ret.length ? Arrays.copyOf(ret, o) : ret;
+	}
+
+}
diff --git a/sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/teavm/ClassesJSLocator.java b/sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/teavm/ClassesJSLocator.java
new file mode 100644
index 00000000..f196c149
--- /dev/null
+++ b/sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/teavm/ClassesJSLocator.java
@@ -0,0 +1,94 @@
+package net.lax1dude.eaglercraft.v1_8.internal.teavm;
+
+import org.teavm.jso.dom.html.HTMLScriptElement;
+import org.teavm.jso.dom.xml.Element;
+import org.teavm.jso.dom.xml.NodeList;
+
+import net.lax1dude.eaglercraft.v1_8.EagUtils;
+import net.lax1dude.eaglercraft.v1_8.internal.PlatformRuntime;
+import net.lax1dude.eaglercraft.v1_8.log4j.LogManager;
+import net.lax1dude.eaglercraft.v1_8.log4j.Logger;
+
+/**
+ * Copyright (c) 2024 lax1dude. All Rights Reserved.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ * 
+ */
+public class ClassesJSLocator {
+
+	private static final Logger logger = LogManager.getLogger("ClassesJSLocator");
+
+	public static String resolveClassesJSFromThrowable() {
+		String str = resolveClassesJSFromThrowable0();
+		if(str != null && str.equalsIgnoreCase(PlatformRuntime.win.getLocation().getFullURL())) {
+			return null;
+		}
+		return str;
+	}
+
+	private static String resolveClassesJSFromThrowable0() {
+		String str = TeaVMUtils.dumpJSStackTrace();
+		String[] frames = EagUtils.splitPattern.split(str);
+		if("Error".equals(frames[0])) {
+			// V8 stack trace
+			if(frames.length > 1) {
+				String framesTrim = frames[1].trim();
+				if(framesTrim.startsWith("at")) {
+					//definitely V8
+					int i = framesTrim.indexOf('(');
+					int j = framesTrim.indexOf(')');
+					if(i != -1 && j != -1 && i < j) {
+						return tryResolveClassesSourceFromFrame(framesTrim.substring(i + 1, j));
+					}
+				}
+			}
+		}else {
+			// Mozilla/WebKit stack trace
+			String framesTrim = frames[0].trim();
+			int i = framesTrim.indexOf('@');
+			if(i != -1) {
+				return tryResolveClassesSourceFromFrame(framesTrim.substring(i + 1));
+			}
+		}
+		return null;
+	}
+
+	private static String tryResolveClassesSourceFromFrame(String fileLineCol) {
+		int i = fileLineCol.lastIndexOf(':');
+		if(i > 0) {
+			i = fileLineCol.lastIndexOf(':', i - 1);
+		}
+		if(i != -1) {
+			return fileLineCol.substring(0, i);
+		}
+		return null;
+	}
+
+	public static HTMLScriptElement resolveClassesJSFromInline() {
+		NodeList<Element> elements = PlatformRuntime.doc.getElementsByTagName("script");
+		for(int i = 0, l = elements.getLength(); i < l; ++i) {
+			HTMLScriptElement tag = (HTMLScriptElement)elements.get(i);
+			String scriptSrc = tag.getText();
+			if(scriptSrc != null && scriptSrc.length() > 1024 * 1024) {
+				// I'm not feeling very creative tonight
+				int j = scriptSrc.indexOf("var $rt_seed=2463534242;");
+				if(j > 0 && j < 2048 && scriptSrc.indexOf("$rt_createNumericArray(") != -1) {
+					logger.warn("Could not locate classes.js through conventional means, however an inline script tag was found on the page that (probably) contains a TeaVM program");
+					return tag;
+				}
+			}
+		}
+		return null;
+	}
+
+}
diff --git a/sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/teavm/ClientMain.java b/sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/teavm/ClientMain.java
index 30bcdc06..e8ecf58e 100644
--- a/sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/teavm/ClientMain.java
+++ b/sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/teavm/ClientMain.java
@@ -5,7 +5,9 @@ import java.text.SimpleDateFormat;
 import java.util.Date;
 import java.util.LinkedList;
 import java.util.List;
+import java.util.Set;
 
+import org.apache.commons.lang3.StringUtils;
 import org.json.JSONException;
 import org.teavm.jso.JSBody;
 import org.teavm.jso.JSFunctor;
@@ -21,7 +23,10 @@ import org.teavm.jso.webgl.WebGLRenderingContext;
 
 import net.lax1dude.eaglercraft.v1_8.EagRuntime;
 import net.lax1dude.eaglercraft.v1_8.EaglercraftVersion;
+import net.lax1dude.eaglercraft.v1_8.boot_menu.teavm.BootMenuEntryPoint;
 import net.lax1dude.eaglercraft.v1_8.internal.PlatformApplication;
+import net.lax1dude.eaglercraft.v1_8.internal.PlatformInput;
+import net.lax1dude.eaglercraft.v1_8.internal.PlatformOpenGL;
 import net.lax1dude.eaglercraft.v1_8.internal.PlatformRuntime;
 import net.lax1dude.eaglercraft.v1_8.internal.teavm.opts.JSEaglercraftXOptsAssetsURI;
 import net.lax1dude.eaglercraft.v1_8.internal.teavm.opts.JSEaglercraftXOptsRoot;
@@ -55,12 +60,26 @@ public class ClientMain {
 		return crashImage.substring(0);
 	}
 
-	@JSBody(params = {}, script = "if((typeof window.__isEaglerX188Running === \"string\") && window.__isEaglerX188Running === \"yes\") return true; window.__isEaglerX188Running = \"yes\"; return false;")
+	@JSBody(params = {}, script = "if((typeof __isEaglerX188Running === \"string\") && __isEaglerX188Running === \"yes\") return true; __isEaglerX188Running = \"yes\"; return false;")
 	private static native boolean getRunningFlag();
 
+	@JSBody(params = { "str" }, script = "return (typeof location !== \"undefined\") && (typeof location.hostname === \"string\") && location.hostname.toLowerCase() === str;")
+	private static native boolean getTardFlag(String str);
+
+	private static final PrintStream systemOut = System.out;
+	private static final PrintStream systemErr = System.err;
+
+	private static JSObject windowErrorHandler = null;
+
 	public static void _main() {
-		PrintStream systemOut = System.out;
-		PrintStream systemErr = System.err;
+		if(getTardFlag(new String(new char[] { 'e', 'a', 'g', 'l', 'e', 'r', 'c', 'r', 'a', 'f', 't', '.', 'd', 'e', 'v' }))) {
+			// Have fun, boys!!!
+			Window.alert(new String(new char[] { 101, 97, 103, 108, 101, 114, 99, 114, 97, 102, 116, 46, 100, 101, 118,
+					32, 105, 115, 32, 110, 111, 116, 32, 97, 110, 32, 111, 102, 102, 105, 99, 105, 97, 108, 32, 119,
+					101, 98, 115, 105, 116, 101, 32, 97, 110, 100, 32, 105, 115, 32, 110, 111, 116, 32, 101, 110, 100,
+					111, 114, 115, 101, 100, 32, 98, 121, 32, 108, 97, 120, 49, 100, 117, 100, 101, 32, 111, 114, 32,
+					97, 121, 117, 110, 97, 109, 105, 50, 48, 48, 48 }));
+		}
 		if(getRunningFlag()) {
 			systemErr.println("ClientMain: [ERROR] eaglercraftx is already running!");
 			return;
@@ -79,6 +98,7 @@ public class ClientMain {
 			try {
 				JSEaglercraftXOptsRoot eaglercraftOpts = (JSEaglercraftXOptsRoot)opts;
 				crashOnUncaughtExceptions = eaglercraftOpts.getCrashOnUncaughtExceptions(false);
+				PlatformRuntime.isDeobfStackTraces = eaglercraftOpts.getDeobfStackTraces(true);
 				
 				configRootElementId = eaglercraftOpts.getContainer();
 				if(configRootElementId == null) {
@@ -86,6 +106,11 @@ public class ClientMain {
 				}
 				configRootElement = Window.current().getDocument().getElementById(configRootElementId);
 				
+				HTMLElement oldContent;
+				while((oldContent = configRootElement.querySelector("._eaglercraftX_wrapper_element")) != null) {
+					oldContent.delete();
+				}
+				
 				String epkSingleURL = eaglercraftOpts.getAssetsURI();
 				if(epkSingleURL != null) {
 					configEPKFiles = new EPKFileEntry[] { new EPKFileEntry(epkSingleURL, "") };
@@ -125,31 +150,41 @@ public class ClientMain {
 			if(crashOnUncaughtExceptions) {
 				systemOut.println("ClientMain: [INFO] registering crash handlers");
 				
-				setWindowErrorHandler(new WindowErrorHandler() {
+				windowErrorHandler = setWindowErrorHandler(Window.current(), new WindowErrorHandler() {
 
 					@Override
 					public void call(String message, String file, int line, int col, JSError error) {
-						StringBuilder str = new StringBuilder();
-						
-						str.append("Native Browser Exception\n");
-						str.append("----------------------------------\n");
-						str.append("  Line: ").append((file == null ? "unknown" : file) + ":" + line + ":" + col).append('\n');
-						str.append("  Type: ").append(error == null ? "generic" : error.getName()).append('\n');
-						
-						if(error != null) {
-							str.append("  Desc: ").append(error.getMessage() == null ? "null" : error.getMessage()).append('\n');
-						}
-						
-						if(message != null) {
-							if(error == null || error.getMessage() == null || !message.endsWith(error.getMessage())) {
-								str.append("  Desc: ").append(message).append('\n');
+						if(windowErrorHandler != null) {
+							error = TeaVMUtils.ensureDefined(error);
+							if(error == null) {
+								systemErr.println("ClientMain: [ERROR] recieved error event, but the error is null, ignoring");
+								return;
 							}
+							
+							StringBuilder str = new StringBuilder();
+							
+							str.append("Native Browser Exception\n");
+							str.append("----------------------------------\n");
+							str.append("  Line: ").append((file == null ? "unknown" : file) + ":" + line + ":" + col).append('\n');
+							str.append("  Type: ").append(error.getName()).append('\n');
+							str.append("  Desc: ").append(error.getMessage() == null ? "null" : error.getMessage()).append('\n');
+							
+							if(message != null) {
+								if(error.getMessage() == null || !message.endsWith(error.getMessage())) {
+									str.append("  Desc: ").append(message).append('\n');
+								}
+							}
+							
+							str.append("----------------------------------\n\n");
+							String stack = TeaVMUtils.getStackSafe(error);
+							if(PlatformRuntime.isDeobfStackTraces && !StringUtils.isAllEmpty(stack)) {
+								TeaVMRuntimeDeobfuscator.initialize();
+								stack = TeaVMRuntimeDeobfuscator.deobfExceptionStack(stack);
+							}
+							str.append(stack == null ? "No stack trace is available" : stack).append('\n');
+							
+							showCrashScreen(str.toString());
 						}
-						
-						str.append("----------------------------------\n\n");
-						str.append(error.getStack() == null ? "No stack trace is available" : error.getStack()).append('\n');
-						
-						showCrashScreen(str.toString());
 					}
 
 				});
@@ -174,6 +209,14 @@ public class ClientMain {
 				}catch(Throwable t) {
 				}
 				return;
+			}catch(TeaVMEnterBootMenuException ee) {
+				try {
+					systemOut.println("ClientMain: [INFO] launching eaglercraftx boot menu");
+					BootMenuEntryPoint.launchMenu(Window.current(), configRootElement);
+				}catch(Throwable t) {
+					showCrashScreen("Failed to enter boot menu!", t);
+				}
+				return;
 			}catch(Throwable t) {
 				systemErr.println("ClientMain: [ERROR] eaglercraftx's runtime could not be initialized!");
 				EagRuntime.debugPrintStackTraceToSTDERR(t);
@@ -197,9 +240,9 @@ public class ClientMain {
 		}
 	}
 	
-	@JSBody(params = {}, script = "if(typeof window.eaglercraftXOpts === \"undefined\") {return null;}"
-			+ "else if(typeof window.eaglercraftXOpts === \"string\") {return JSON.parse(window.eaglercraftXOpts);}"
-			+ "else {return window.eaglercraftXOpts;}")
+	@JSBody(params = {}, script = "if(typeof eaglercraftXOpts === \"undefined\") {return null;}"
+			+ "else if(typeof eaglercraftXOpts === \"string\") {return JSON.parse(eaglercraftXOpts);}"
+			+ "else {return eaglercraftXOpts;}")
 	private static native JSObject getEaglerXOpts();
 
 	public static class EPKFileEntry {
@@ -224,13 +267,24 @@ public class ClientMain {
 		void call(String message, String file, int line, int col, JSError error);
 	}
 	
-	@JSBody(params = { "handler" }, script = "window.addEventListener(\"error\", function(e) { handler("
+	@JSBody(params = { "win", "handler" }, script = "var evtHandler = function(e) { handler("
 			+ "(typeof e.message === \"string\") ? e.message : null,"
 			+ "(typeof e.filename === \"string\") ? e.filename : null,"
 			+ "(typeof e.lineno === \"number\") ? e.lineno : 0,"
 			+ "(typeof e.colno === \"number\") ? e.colno : 0,"
-			+ "(typeof e.error === \"undefined\") ? null : e.error); });")
-	public static native void setWindowErrorHandler(WindowErrorHandler handler);
+			+ "(typeof e.error === \"undefined\") ? null : e.error);}; win.addEventListener(\"error\", evtHandler);"
+			+ "return evtHandler;")
+	private static native JSObject setWindowErrorHandler(Window win, WindowErrorHandler handler);
+	
+	@JSBody(params = { "win", "handler" }, script = "win.removeEventListener(\"error\", evtHandler);")
+	private static native void removeWindowErrorHandler(Window win, JSObject handler);
+	
+	public static void removeErrorHandler(Window win) {
+		if(windowErrorHandler != null) {
+			removeWindowErrorHandler(win, windowErrorHandler);
+			windowErrorHandler = null;
+		}
+	}
 	
 	public static void showCrashScreen(String message, Throwable t) {
 		try {
@@ -249,12 +303,16 @@ public class ClientMain {
 		String strBefore = strBeforeBuilder.toString();
 		
 		HTMLDocument doc = Window.current().getDocument();
-		if(configRootElement == null) {
-			configRootElement = doc.getElementById(configRootElementId);
+		HTMLElement el;
+		if(PlatformRuntime.parent != null) {
+			el = PlatformRuntime.parent;
+		}else {
+			if(configRootElement == null) {
+				configRootElement = doc.getElementById(configRootElementId);
+			}
+			el = configRootElement;
 		}
 
-		HTMLElement el = configRootElement;
-
 		StringBuilder str = new StringBuilder();
 		str.append("eaglercraft.version = \"").append(EaglercraftVersion.projectForkVersion).append("\"\n");
 		str.append("eaglercraft.minecraft = \"1.8.8\"\n");
@@ -263,11 +321,13 @@ public class ClientMain {
 		str.append('\n');
 		str.append(addWebGLToCrash());
 		str.append('\n');
+		str.append(addShimsToCrash());
+		str.append('\n');
 		str.append("window.eaglercraftXOpts = ");
 		str.append(TeaVMClientConfigAdapter.instance.toString()).append('\n');
 		str.append('\n');
 		str.append("currentTime = ");
-		str.append(EagRuntime.fixDateFormat(new SimpleDateFormat("EEE, d MMM yyyy HH:mm:ss Z")).format(new Date())).append('\n');
+		str.append((new SimpleDateFormat("EEE, d MMM yyyy HH:mm:ss Z")).format(new Date())).append('\n');
 		str.append('\n');
 		addDebugNav(str, "userAgent");
 		addDebugNav(str, "vendor");
@@ -301,11 +361,11 @@ public class ClientMain {
 		String strAfter = str.toString();
 		
 		String strFinal = strBefore + strAfter;
-		List<String> additionalInfo = new LinkedList();
+		List<String> additionalInfo = new LinkedList<>();
 		try {
 			TeaVMClientConfigAdapter.instance.getHooks().callCrashReportHook(strFinal, additionalInfo::add);
 		}catch(Throwable tt) {
-			System.err.println("Uncaught exception invoking crash report hook!");
+			systemErr.println("Uncaught exception invoking crash report hook!");
 			EagRuntime.debugPrintStackTraceToSTDERR(tt);
 		}
 		
@@ -325,24 +385,23 @@ public class ClientMain {
 					builderFinal.append(strAfter);
 					strFinal = builderFinal.toString();
 				}catch(Throwable tt) {
-					System.err.println("Uncaught exception concatenating crash report hook messages!");
+					systemErr.println("Uncaught exception concatenating crash report hook messages!");
 					EagRuntime.debugPrintStackTraceToSTDERR(tt);
 				}
 			}
 			
 			if(el == null) {
 				Window.alert("Root element not found, crash report was printed to console");
-				System.err.println(strFinal);
+				systemErr.println(strFinal);
 				return;
 			}
-
-			String s = el.getAttribute("style");
-			el.setAttribute("style", (s == null ? "" : s) + "position:relative;");
+			
 			HTMLElement img = doc.createElement("img");
 			HTMLElement div = doc.createElement("div");
 			img.setAttribute("style", "z-index:100;position:absolute;top:10px;left:calc(50% - 151px);");
 			img.setAttribute("src", crashImageWrapper());
 			div.setAttribute("style", "z-index:100;position:absolute;top:135px;left:10%;right:10%;bottom:50px;background-color:white;border:1px solid #cccccc;overflow-x:hidden;overflow-y:scroll;overflow-wrap:break-word;white-space:pre-wrap;font: 14px monospace;padding:10px;");
+			div.getClassList().add("_eaglercraftX_crash_element");
 			el.appendChild(img);
 			el.appendChild(div);
 			div.appendChild(doc.createTextNode(strFinal));
@@ -350,22 +409,22 @@ public class ClientMain {
 			PlatformRuntime.removeEventHandlers();
 
 		}else {
-			System.err.println();
-			System.err.println("An additional crash report was supressed:");
+			systemErr.println();
+			systemErr.println("An additional crash report was supressed:");
 			String[] s = t.split("[\\r\\n]+");
 			for(int i = 0; i < s.length; ++i) {
-				System.err.println("  " + s[i]);
+				systemErr.println("  " + s[i]);
 			}
 			if(additionalInfo.size() > 0) {
 				for(String str2 : additionalInfo) {
 					if(str2 != null) {
-						System.err.println();
-						System.err.println("  ----------[ CRASH HOOK ]----------");
+						systemErr.println();
+						systemErr.println("  ----------[ CRASH HOOK ]----------");
 						s = str2.split("[\\r\\n]+");
 						for(int i = 0; i < s.length; ++i) {
-							System.err.println("  " + s[i]);
+							systemErr.println("  " + s[i]);
 						}
-						System.err.println("  ----------------------------------");
+						systemErr.println("  ----------------------------------");
 					}
 				}
 			}
@@ -379,44 +438,110 @@ public class ClientMain {
 			return webGLCrashStringCache;
 		}
 		
-		StringBuilder ret = new StringBuilder();
-		
-		WebGLRenderingContext ctx = PlatformRuntime.webgl;
-		
-		if(ctx == null) {
-			HTMLCanvasElement cvs = (HTMLCanvasElement) Window.current().getDocument().createElement("canvas");
+		try {
+			StringBuilder ret = new StringBuilder();
 			
-			cvs.setWidth(64);
-			cvs.setHeight(64);
-			
-			ctx = (WebGLRenderingContext)cvs.getContext("webgl2");
+			WebGLRenderingContext ctx = PlatformRuntime.webgl;
+			boolean experimental = PlatformRuntime.webglExperimental;
 			
 			if(ctx == null) {
-				ctx = (WebGLRenderingContext)cvs.getContext("webgl");
+				experimental = false;
+				HTMLCanvasElement cvs = (HTMLCanvasElement) Window.current().getDocument().createElement("canvas");
+				
+				cvs.setWidth(64);
+				cvs.setHeight(64);
+				
+				ctx = (WebGLRenderingContext)cvs.getContext("webgl2");
+				
+				if(ctx == null) {
+					ctx = (WebGLRenderingContext)cvs.getContext("webgl");
+					if(ctx == null) {
+						experimental = true;
+						ctx = (WebGLRenderingContext)cvs.getContext("experimental-webgl");
+					}
+				}
 			}
-		}
-		
-		if(ctx != null) {
-			if(PlatformRuntime.webgl != null) {
-				ret.append("webgl.version = ").append(ctx.getParameterString(WebGLRenderingContext.VERSION)).append('\n');
-			}
-			if(ctx.getExtension("WEBGL_debug_renderer_info") != null) {
-				ret.append("webgl.renderer = ").append(ctx.getParameterString(/* UNMASKED_RENDERER_WEBGL */ 0x9246)).append('\n');
-				ret.append("webgl.vendor = ").append(ctx.getParameterString(/* UNMASKED_VENDOR_WEBGL */ 0x9245)).append('\n');
-			}else {
-				ret.append("webgl.renderer = ").append(ctx.getParameterString(WebGLRenderingContext.RENDERER) + " [masked]").append('\n');
-				ret.append("webgl.vendor = ").append(ctx.getParameterString(WebGLRenderingContext.VENDOR) + " [masked]").append('\n');
-			}
-			//ret.append('\n').append("\nwebgl.anisotropicGlitch = ").append(DetectAnisotropicGlitch.hasGlitch()).append('\n'); //TODO
-			ret.append('\n').append("webgl.ext.HDR16f = ").append(ctx.getExtension("EXT_color_buffer_half_float") != null).append('\n');
-			ret.append("webgl.ext.HDR32f = ").append(ctx.getExtension("EXT_color_buffer_float") != null).append('\n');
-			ret.append("webgl.ext.HDR32f_linear = ").append(ctx.getExtension("OES_texture_float_linear") != null).append('\n');
 			
-		}else {
-			ret.append("Failed to query GPU info!\n");
+			if(ctx != null) {
+				if(PlatformRuntime.webgl != null) {
+					ret.append("webgl.version = ").append(ctx.getParameterString(WebGLRenderingContext.VERSION)).append('\n');
+				}
+				if(ctx.getExtension("WEBGL_debug_renderer_info") != null) {
+					ret.append("webgl.renderer = ").append(ctx.getParameterString(/* UNMASKED_RENDERER_WEBGL */ 0x9246)).append('\n');
+					ret.append("webgl.vendor = ").append(ctx.getParameterString(/* UNMASKED_VENDOR_WEBGL */ 0x9245)).append('\n');
+				}else {
+					ret.append("webgl.renderer = ").append(ctx.getParameterString(WebGLRenderingContext.RENDERER)).append( " [masked]").append('\n');
+					ret.append("webgl.vendor = ").append(ctx.getParameterString(WebGLRenderingContext.VENDOR)).append(" [masked]").append('\n');
+				}
+				//ret.append('\n').append("\nwebgl.anisotropicGlitch = ").append(DetectAnisotropicGlitch.hasGlitch()).append('\n'); //TODO
+				int id = PlatformOpenGL.checkOpenGLESVersion();
+				if(id > 0) {
+					ret.append('\n').append("webgl.version.id = ").append(id).append('\n');
+					ret.append("webgl.experimental = ").append(experimental).append('\n');
+					if(id == 200) {
+						ret.append("webgl.ext.ANGLE_instanced_arrays = ").append(ctx.getExtension("ANGLE_instanced_arrays") != null).append('\n');
+						ret.append("webgl.ext.EXT_color_buffer_half_float = ").append(ctx.getExtension("EXT_color_buffer_half_float") != null).append('\n');
+						ret.append("webgl.ext.EXT_shader_texture_lod = ").append(ctx.getExtension("EXT_shader_texture_lod") != null).append('\n');
+						ret.append("webgl.ext.OES_fbo_render_mipmap = ").append(ctx.getExtension("OES_fbo_render_mipmap") != null).append('\n');
+						ret.append("webgl.ext.OES_texture_float = ").append(ctx.getExtension("OES_texture_float") != null).append('\n');
+						ret.append("webgl.ext.OES_texture_half_float = ").append(ctx.getExtension("OES_texture_half_float") != null).append('\n');
+						ret.append("webgl.ext.OES_texture_half_float_linear = ").append(ctx.getExtension("OES_texture_half_float_linear") != null).append('\n');
+					}else if(id >= 300) {
+						ret.append("webgl.ext.EXT_color_buffer_float = ").append(ctx.getExtension("EXT_color_buffer_float") != null).append('\n');
+						ret.append("webgl.ext.EXT_color_buffer_half_float = ").append(ctx.getExtension("EXT_color_buffer_half_float") != null).append('\n');
+						ret.append("webgl.ext.OES_texture_float_linear = ").append(ctx.getExtension("OES_texture_float_linear") != null).append('\n');
+					}
+					ret.append("webgl.ext.EXT_texture_filter_anisotropic = ").append(ctx.getExtension("EXT_texture_filter_anisotropic") != null).append('\n');
+				}else {
+					ret.append("webgl.ext.ANGLE_instanced_arrays = ").append(ctx.getExtension("ANGLE_instanced_arrays") != null).append('\n');
+					ret.append("webgl.ext.EXT_color_buffer_float = ").append(ctx.getExtension("EXT_color_buffer_float") != null).append('\n');
+					ret.append("webgl.ext.EXT_color_buffer_half_float = ").append(ctx.getExtension("EXT_color_buffer_half_float") != null).append('\n');
+					ret.append("webgl.ext.EXT_shader_texture_lod = ").append(ctx.getExtension("EXT_shader_texture_lod") != null).append('\n');
+					ret.append("webgl.ext.OES_fbo_render_mipmap = ").append(ctx.getExtension("OES_fbo_render_mipmap") != null).append('\n');
+					ret.append("webgl.ext.OES_texture_float = ").append(ctx.getExtension("OES_texture_float") != null).append('\n');
+					ret.append("webgl.ext.OES_texture_float_linear = ").append(ctx.getExtension("OES_texture_float_linear") != null).append('\n');
+					ret.append("webgl.ext.OES_texture_half_float = ").append(ctx.getExtension("OES_texture_half_float") != null).append('\n');
+					ret.append("webgl.ext.OES_texture_half_float_linear = ").append(ctx.getExtension("OES_texture_half_float_linear") != null).append('\n');
+					ret.append("webgl.ext.EXT_texture_filter_anisotropic = ").append(ctx.getExtension("EXT_texture_filter_anisotropic") != null).append('\n');
+				}
+			}else {
+				ret.append("Failed to query GPU info!\n");
+			}
+			
+			return webGLCrashStringCache = ret.toString();
+		}catch(Throwable tt) {
+			return webGLCrashStringCache = "ERROR: could not query webgl info - " + tt.toString() + "\n";
+		}
+	}
+
+	private static String shimsCrashStringCache = null;
+
+	private static String addShimsToCrash() {
+		if(shimsCrashStringCache != null) {
+			return shimsCrashStringCache;
 		}
 		
-		return webGLCrashStringCache = ret.toString();
+		try {
+			StringBuilder ret = new StringBuilder();
+			
+			ES6ShimStatus status = ES6ShimStatus.getRuntimeStatus();
+			ret.append("eaglercraft.es6shims.status = ").append(status.getStatus()).append('\n');
+			ret.append("eaglercraft.es6shims.shims = [ ");
+			Set<EnumES6Shims> shims = status.getShims();
+			boolean b = false;
+			for(EnumES6Shims shim : shims) {
+				if(b) {
+					ret.append(", ");
+				}
+				ret.append(shim);
+				b = true;
+			}
+			ret.append(" ]\n");
+			
+			return shimsCrashStringCache = ret.toString();
+		}catch(Throwable tt) {
+			return shimsCrashStringCache = "ERROR: could not query ES6 shim info - " + tt.toString() + "\n";
+		}
 	}
 
 	public static void showIncompatibleScreen(String t) {
@@ -424,12 +549,16 @@ public class ClientMain {
 			isCrashed = true;
 			
 			HTMLDocument doc = Window.current().getDocument();
-			if(configRootElement == null) {
-				configRootElement = doc.getElementById(configRootElementId);
+			HTMLElement el;
+			if(PlatformRuntime.parent != null) {
+				el = PlatformRuntime.parent;
+			}else {
+				if(configRootElement == null) {
+					configRootElement = doc.getElementById(configRootElementId);
+				}
+				el = configRootElement;
 			}
 			
-			HTMLElement el = configRootElement;
-			
 			if(el == null) {
 				System.err.println("Compatibility error: " + t);
 				return;
@@ -442,14 +571,15 @@ public class ClientMain {
 			img.setAttribute("style", "z-index:100;position:absolute;top:10px;left:calc(50% - 151px);");
 			img.setAttribute("src", crashImageWrapper());
 			div.setAttribute("style", "z-index:100;position:absolute;top:135px;left:10%;right:10%;bottom:50px;background-color:white;border:1px solid #cccccc;overflow-x:hidden;overflow-y:scroll;font:18px sans-serif;padding:40px;");
+			div.getClassList().add("_eaglercraftX_incompatible_element");
 			el.appendChild(img);
 			el.appendChild(div);
 			div.setInnerHTML("<h2><svg style=\"vertical-align:middle;margin:0px 16px 8px 8px;\" xmlns=\"http://www.w3.org/2000/svg\" width=\"48\" height=\"48\" viewBox=\"0 0 48 48\" fill=\"none\"><path stroke=\"#000000\" stroke-width=\"3\" stroke-linecap=\"square\" d=\"M1.5 8.5v34h45v-28m-3-3h-10v-3m-3-3h-10m15 6h-18v-3m-3-3h-10\"/><path stroke=\"#000000\" stroke-width=\"2\" stroke-linecap=\"square\" d=\"M12 21h0m0 4h0m4 0h0m0-4h0m-2 2h0m20-2h0m0 4h0m4 0h0m0-4h0m-2 2h0\"/><path stroke=\"#000000\" stroke-width=\"2\" stroke-linecap=\"square\" d=\"M20 30h0 m2 2h0 m2 2h0 m2 2h0 m2 -2h0 m2 -2h0 m2 -2h0\"/></svg>+ This device is incompatible with Eaglercraft&ensp;:(</h2>"
 					+ "<div style=\"margin-left:40px;\">"
-					+ "<p style=\"font-size:1.2em;\"><b style=\"font-size:1.1em;\">Issue:</b> <span style=\"color:#BB0000;\" id=\"crashReason\"></span><br /></p>"
-					+ "<p style=\"margin-left:10px;font:0.9em monospace;\" id=\"crashUserAgent\"></p>"
-					+ "<p style=\"margin-left:10px;font:0.9em monospace;\" id=\"crashWebGL\"></p>"
-					+ "<p style=\"margin-left:10px;font:0.9em monospace;\">Current Date: " + EagRuntime.fixDateFormat(new SimpleDateFormat("EEE, d MMM yyyy HH:mm:ss Z")).format(new Date()) + "</p>"
+					+ "<p style=\"font-size:1.2em;\"><b style=\"font-size:1.1em;\">Issue:</b> <span style=\"color:#BB0000;\" id=\"_eaglercraftX_crashReason\"></span><br /></p>"
+					+ "<p style=\"margin-left:10px;font:0.9em monospace;\" id=\"_eaglercraftX_crashUserAgent\"></p>"
+					+ "<p style=\"margin-left:10px;font:0.9em monospace;\" id=\"_eaglercraftX_crashWebGL\"></p>"
+					+ "<p style=\"margin-left:10px;font:0.9em monospace;\">Current Date: " + (new SimpleDateFormat("EEE, d MMM yyyy HH:mm:ss Z")).format(new Date()) + "</p>"
 					+ "<p><br /><span style=\"font-size:1.1em;border-bottom:1px dashed #AAAAAA;padding-bottom:5px;\">Things you can try:</span></p>"
 					+ "<ol>"
 					+ "<li><span style=\"font-weight:bold;\">Just try using Eaglercraft on a different device</span>, it isn't a bug it's common sense</li>"
@@ -458,12 +588,11 @@ public class ClientMain {
 					+ "<li style=\"margin-top:7px;\">If you are not using Chrome/Edge, try installing the latest Google Chrome</li>"
 					+ "<li style=\"margin-top:7px;\">If your browser is out of date, please update it to the latest version</li>"
 					+ "<li style=\"margin-top:7px;\">If you are using an old OS such as Windows 7, please try Windows 10 or 11</li>"
-					+ "<li style=\"margin-top:7px;\">If you have a GPU launched before 2009, WebGL 2.0 support may be impossible</li>"
 					+ "</ol>"
 					+ "</div>");
 			
-			div.querySelector("#crashReason").appendChild(doc.createTextNode(t));
-			div.querySelector("#crashUserAgent").appendChild(doc.createTextNode(getStringNav("userAgent")));
+			div.querySelector("#_eaglercraftX_crashReason").appendChild(doc.createTextNode(t));
+			div.querySelector("#_eaglercraftX_crashUserAgent").appendChild(doc.createTextNode(getStringNav("userAgent")));
 			
 			PlatformRuntime.removeEventHandlers();
 			
@@ -494,7 +623,7 @@ public class ClientMain {
 			}catch(Throwable tt) {
 			}
 			
-			div.querySelector("#crashWebGL").appendChild(doc.createTextNode(webGLRenderer));
+			div.querySelector("#_eaglercraftX_crashWebGL").appendChild(doc.createTextNode(webGLRenderer));
 			
 		}
 	}
@@ -504,17 +633,24 @@ public class ClientMain {
 	public static void showIntegratedServerCrashReportOverlay(String report, int x, int y, int w, int h) {
 		if(integratedServerCrashPanel == null) {
 			HTMLDocument doc = Window.current().getDocument();
-			if(configRootElement == null) {
-				configRootElement = doc.getElementById(configRootElementId);
+			HTMLElement el;
+			if(PlatformRuntime.parent != null) {
+				el = PlatformRuntime.parent;
+			}else {
+				if(configRootElement == null) {
+					configRootElement = doc.getElementById(configRootElementId);
+				}
+				el = configRootElement;
 			}
 			
 			integratedServerCrashPanel = doc.createElement("div");
 			integratedServerCrashPanel.setAttribute("style", "z-index:99;position:absolute;background-color:black;color:white;overflow-x:hidden;overflow-y:scroll;overflow-wrap:break-word;white-space:pre-wrap;font:18px sans-serif;padding:20px;display:none;");
-			configRootElement.appendChild(integratedServerCrashPanel);
+			integratedServerCrashPanel.getClassList().add("_eaglercraftX_integratedserver_crash_element");
+			el.appendChild(integratedServerCrashPanel);
 		}
 		String sourceURL = ClientPlatformSingleplayer.getLoadedWorkerSourceURLTeaVM();
 		String workerURL = ClientPlatformSingleplayer.getLoadedWorkerURLTeaVM();
-		String currentDate = EagRuntime.fixDateFormat(new SimpleDateFormat("EEE, d MMM yyyy HH:mm:ss Z")).format(new Date());
+		String currentDate = (new SimpleDateFormat("EEE, d MMM yyyy HH:mm:ss Z")).format(new Date());
 		if(workerURL != null) {
 			report = "WORKER SRC: " + sourceURL +"\nWORKER URL: " + workerURL + "\n\nCURRENT DATE: " + currentDate + "\n\n" + report.replaceAll(workerURL, "<worker_url>");
 		}else {
@@ -523,7 +659,7 @@ public class ClientMain {
 		setInnerText(integratedServerCrashPanel, "");
 		setInnerText(integratedServerCrashPanel, report);
 		CSSStyleDeclaration style = integratedServerCrashPanel.getStyle();
-		float s = (float)Window.current().getDevicePixelRatio();
+		float s = PlatformInput.getDPI();
 		style.setProperty("top", "" + (y / s) + "px");
 		style.setProperty("left", "" + (x / s) + "px");
 		style.setProperty("width", "" + ((w / s) - 20) + "px");
@@ -552,9 +688,9 @@ public class ClientMain {
 	@JSBody(params = { "v" }, script = "try { return \"\"+window.location[v]; } catch(e) { return \"<error>\"; }")
 	private static native String getStringLocation(String var);
 
-	@JSBody(params = { }, script = "try { var retObj = new Array; if(typeof window.navigator.plugins === \"object\")"
-			+ "{ var len = window.navigator.plugins.length; if(len > 0) { for(var idx = 0; idx < len; ++idx) {"
-			+ "var thePlugin = window.navigator.plugins[idx]; retObj.push({ name: thePlugin.name,"
+	@JSBody(params = { }, script = "try { var retObj = new Array; if(typeof navigator.plugins === \"object\")"
+			+ "{ var len = navigator.plugins.length; if(len > 0) { for(var idx = 0; idx < len; ++idx) {"
+			+ "var thePlugin = navigator.plugins[idx]; retObj.push({ name: thePlugin.name,"
 			+ "filename: thePlugin.filename, desc: thePlugin.description }); } } } return JSON.stringify(retObj);"
 			+ "} catch(e) { return \"<error>\"; }")
 	private static native String getStringNavPlugins();
diff --git a/sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/teavm/DebugConsoleWindow.java b/sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/teavm/DebugConsoleWindow.java
index fe3546b6..264d41b0 100644
--- a/sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/teavm/DebugConsoleWindow.java
+++ b/sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/teavm/DebugConsoleWindow.java
@@ -13,6 +13,7 @@ import org.teavm.jso.dom.html.HTMLDocument;
 import org.teavm.jso.dom.html.HTMLElement;
 
 import net.lax1dude.eaglercraft.v1_8.internal.PlatformApplication;
+import net.lax1dude.eaglercraft.v1_8.internal.PlatformInput;
 import net.lax1dude.eaglercraft.v1_8.internal.PlatformRuntime;
 import net.lax1dude.eaglercraft.v1_8.log4j.LogManager;
 
@@ -48,31 +49,57 @@ public class DebugConsoleWindow {
 	private static final int bufferSpoolSize = 256;
 	private static final int windowMaxMessages = 2048;
 
-	private static final List<LogMessage> messageBuffer = new LinkedList();
+	private static final List<LogMessage> messageBuffer = new LinkedList<>();
 
 	public static Window parent = null;
 	public static Window logger = null;
 	private static HTMLDocument loggerDoc = null;
 	private static HTMLBodyElement loggerBody = null;
 	private static HTMLElement loggerMessageContainer = null;
+	private static EventListener<?> unload = null;
+	private static String unloadName = null;
 
 	public static void initialize(Window parentWindow) {
 		parent = parentWindow;
-		parent.addEventListener("unload", new EventListener<Event>() {
-			@Override
-			public void handleEvent(Event evt) {
-				destroyWindow();
-			}
-		});
-		if(parent.getLocalStorage() != null && "true".equals(parent.getLocalStorage().getItem(PlatformRuntime.getClientConfigAdapter().getLocalStorageNamespace() + ".showDebugConsole"))) {
+		if (PlatformRuntime.getClientConfigAdapter().isOpenDebugConsoleOnLaunch() || debugConsoleLocalStorageGet()) {
 			showDebugConsole0();
 		}
 	}
 
-	public static void showDebugConsole() {
-		if(parent.getLocalStorage() != null) {
-			parent.getLocalStorage().setItem(PlatformRuntime.getClientConfigAdapter().getLocalStorageNamespace() + ".showDebugConsole", "true");
+	public static void removeEventListeners() {
+		if(unloadName != null && unload != null) {
+			try {
+				parent.removeEventListener(unloadName, unload);
+			}catch(Throwable t) {
+			}
 		}
+		unload = null;
+		unloadName = null;
+	}
+
+	private static void debugConsoleLocalStorageSet(boolean val) {
+		try {
+			if(parent.getLocalStorage() != null) {
+				parent.getLocalStorage().setItem(PlatformRuntime.getClientConfigAdapter().getLocalStorageNamespace() + ".showDebugConsole", Boolean.toString(val));
+			}
+		}catch(Throwable t) {
+		}
+	}
+
+	private static boolean debugConsoleLocalStorageGet() {
+		try {
+			if(parent.getLocalStorage() != null) {
+				return Boolean.valueOf(parent.getLocalStorage().getItem(PlatformRuntime.getClientConfigAdapter().getLocalStorageNamespace() + ".showDebugConsole"));
+			}else {
+				return false;
+			}
+		}catch(Throwable t) {
+			return false;
+		}
+	}
+
+	public static void showDebugConsole() {
+		debugConsoleLocalStorageSet(true);
 		showDebugConsole0();
 	}
 
@@ -81,12 +108,27 @@ public class DebugConsoleWindow {
 
 	private static void showDebugConsole0() {
 		if(logger == null) {
-			int w = (int)(1000 * parent.getDevicePixelRatio());
-			int h = (int)(400 * parent.getDevicePixelRatio());
+			try {
+				parent.addEventListener(
+						unloadName = ((TeaVMClientConfigAdapter) PlatformRuntime.getClientConfigAdapter())
+								.isFixDebugConsoleUnloadListenerTeaVM() ? "beforeunload" : "unload",
+						unload = new EventListener<Event>() {
+							@Override
+							public void handleEvent(Event evt) {
+								destroyWindow();
+							}
+						});
+			}catch(Throwable t) {
+			}
+			float s = PlatformInput.getDPI();
+			int w = (int)(1000 * s);
+			int h = (int)(400 * s);
 			int x = (parent.getScreen().getWidth() - w) / 2;
 			int y = (parent.getScreen().getHeight() - h) / 2;
 			logger = parent.open("", "_blank", "top=" + y + ",left=" + x + ",width=" + w + ",height=" + h + ",menubar=0,status=0,titlebar=0,toolbar=0");
-			if(logger == null) {
+			if(logger == null || TeaVMUtils.isNotTruthy(logger)) {
+				logger = null;
+				debugConsoleLocalStorageSet(false);
 				LogManager.getLogger("DebugConsoleWindow").error("Logger popup was blocked!");
 				Window.alert("ERROR: Popup blocked!\n\nPlease make sure you have popups enabled for this site!");
 				return;
@@ -110,9 +152,8 @@ public class DebugConsoleWindow {
 				public void handleEvent(Event evt) {
 					if(logger != null) {
 						logger = null;
-						if(parent.getLocalStorage() != null) {
-							parent.getLocalStorage().setItem(PlatformRuntime.getClientConfigAdapter().getLocalStorageNamespace() + ".showDebugConsole", "false");
-						}
+						debugConsoleLocalStorageSet(false);
+						removeEventListeners();
 					}
 				}
 			};
@@ -139,10 +180,12 @@ public class DebugConsoleWindow {
 	}
 
 	private static void appendLogMessageAndScroll(String text, String color) {
-		boolean b = isScrollToEnd(logger, loggerDoc);
-		appendLogMessage(text, color);
-		if(b) {
-			scrollToEnd0(logger, loggerDoc);
+		if(logger != null) {
+			boolean b = isScrollToEnd(logger, loggerDoc);
+			appendLogMessage(text, color);
+			if(b) {
+				scrollToEnd0(logger, loggerDoc);
+			}
 		}
 	}
 
@@ -167,7 +210,11 @@ public class DebugConsoleWindow {
 		if(logger != null) {
 			Window w = logger;
 			logger = null;
-			w.close();
+			try {
+				w.close();
+			}catch(Throwable t) {
+			}
+			removeEventListeners();
 		}
 	}
 
diff --git a/sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/teavm/ES6ShimStatus.java b/sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/teavm/ES6ShimStatus.java
new file mode 100644
index 00000000..afa40d52
--- /dev/null
+++ b/sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/teavm/ES6ShimStatus.java
@@ -0,0 +1,82 @@
+package net.lax1dude.eaglercraft.v1_8.internal.teavm;
+
+import java.util.EnumSet;
+import java.util.Set;
+
+import org.teavm.jso.JSBody;
+
+import net.lax1dude.eaglercraft.v1_8.log4j.LogManager;
+import net.lax1dude.eaglercraft.v1_8.log4j.Logger;
+
+/**
+ * Copyright (c) 2024 lax1dude. All Rights Reserved.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ * 
+ */
+public class ES6ShimStatus {
+
+	private static final Logger logger = LogManager.getLogger("ES6ShimStatus");
+
+	private static ES6ShimStatus instance = null;
+
+	@JSBody(params = { }, script = "return (typeof __eaglercraftXES6ShimStatus === \"object\") ? __eaglercraftXES6ShimStatus : null;")
+	private static native ES6ShimStatusJS getRuntimeStatus0();
+
+	public static ES6ShimStatus getRuntimeStatus() {
+		if(instance == null) {
+			return instance = new ES6ShimStatus(getRuntimeStatus0());
+		}
+		ES6ShimStatusJS jsImpl = getRuntimeStatus0();
+		if(instance.impl != jsImpl) {
+			instance = new ES6ShimStatus(jsImpl);
+		}
+		return instance;
+	}
+
+	private final ES6ShimStatusJS impl;
+	private final EnumES6ShimStatus status;
+	private final Set<EnumES6Shims> shims;
+
+	public ES6ShimStatus(ES6ShimStatusJS impl) {
+		this.impl = impl;
+		if(impl != null && TeaVMUtils.isTruthy(impl)) {
+			this.status = EnumES6ShimStatus.getStatusById(impl.getShimInitStatus());
+			this.shims = EnumSet.noneOf(EnumES6Shims.class);
+			for(int i = 0, id, l = impl.getEnabledShimCount(); i < l; ++i) {
+				id = impl.getEnabledShimID(i);
+				EnumES6Shims theShim = EnumES6Shims.getShimById(id);
+				if(theShim != null) {
+					this.shims.add(theShim);
+				}else {
+					logger.warn("Ignoring unknown shim id: {}", id);
+				}
+			}
+		}else {
+			this.status = EnumES6ShimStatus.STATUS_NOT_PRESENT;
+			this.shims = EnumSet.noneOf(EnumES6Shims.class);
+		}
+	}
+
+	public ES6ShimStatusJS getImpl() {
+		return impl;
+	}
+
+	public EnumES6ShimStatus getStatus() {
+		return status;
+	}
+
+	public Set<EnumES6Shims> getShims() {
+		return shims;
+	}
+
+}
diff --git a/sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/teavm/ES6ShimStatusJS.java b/sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/teavm/ES6ShimStatusJS.java
new file mode 100644
index 00000000..20b49e17
--- /dev/null
+++ b/sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/teavm/ES6ShimStatusJS.java
@@ -0,0 +1,52 @@
+package net.lax1dude.eaglercraft.v1_8.internal.teavm;
+
+import org.teavm.jso.JSObject;
+
+/**
+ * Copyright (c) 2024 lax1dude. All Rights Reserved.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ * 
+ */
+public interface ES6ShimStatusJS extends JSObject {
+
+	public static final int INIT_STATUS_ERROR = -1;
+	public static final int INIT_STATUS_DISABLED = 0;
+	public static final int INIT_STATUS_ENABLED = 1;
+	public static final int INIT_STATUS_DISABLED_ERRORS = 2;
+	public static final int INIT_STATUS_ENABLED_ERRORS = 3;
+
+	public static final int SHIM_MAP = 0;
+	public static final int SHIM_WEAKMAP = 1;
+	public static final int SHIM_SET = 2;
+	public static final int SHIM_WEAKSET = 3;
+	public static final int SHIM_PROMISE = 4;
+	public static final int SHIM_STRING_FROM_CODE_POINT = 5;
+	public static final int SHIM_STRING_CODE_POINT_AT = 6;
+	public static final int SHIM_STRING_STARTS_WITH = 7;
+	public static final int SHIM_STRING_ENDS_WITH = 8;
+	public static final int SHIM_STRING_INCLUDES = 9;
+	public static final int SHIM_STRING_REPEAT = 10;
+	public static final int SHIM_ARRAY_FILL = 11;
+	public static final int SHIM_OBJECT_IS = 12;
+	public static final int SHIM_OBJECT_SET_PROTOTYPE_OF = 13;
+	public static final int SHIM_FUNCTION_NAME = 14;
+	public static final int SHIM_MATH_SIGN = 15;
+	public static final int SHIM_SYMBOL = 16;
+
+	int getShimInitStatus();
+
+	int getEnabledShimCount();
+
+	int getEnabledShimID(int idx);
+
+}
diff --git a/sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/teavm/EarlyLoadScreen.java b/sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/teavm/EarlyLoadScreen.java
index fed1b070..40e2dfd5 100644
--- a/sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/teavm/EarlyLoadScreen.java
+++ b/sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/teavm/EarlyLoadScreen.java
@@ -11,6 +11,7 @@ import net.lax1dude.eaglercraft.v1_8.internal.PlatformRuntime;
 import net.lax1dude.eaglercraft.v1_8.internal.buffer.ByteBuffer;
 import net.lax1dude.eaglercraft.v1_8.internal.buffer.FloatBuffer;
 import net.lax1dude.eaglercraft.v1_8.internal.buffer.IntBuffer;
+import net.lax1dude.eaglercraft.v1_8.opengl.EaglercraftGPU;
 import net.lax1dude.eaglercraft.v1_8.opengl.ImageData;
 
 import static net.lax1dude.eaglercraft.v1_8.internal.PlatformOpenGL.*;
@@ -38,11 +39,20 @@ public class EarlyLoadScreen {
 
 	public static final String loadScreen = "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";
 	public static final String enableScreen = "iVBORw0KGgoAAAANSUhEUgAAAIAAAACACAYAAADDPmHLAAAACXBIWXMAAC4jAAAuIwF4pT92AAAEAklEQVR42u2dvXbjIBBG7T0+xw+gTp06v//LmE6dO/VR5a3wGZNh+BGSFeveJgkIBrDy8TGKds8/Pz/PExyW8/P55AY4MP9YgmNzmeeZVUABAA8AKADgAQAFADwAoACABwAUAPAAgAIAHgBQAMADAAoAeABAAY7LOI7fpQDX65VPtZCt18w5d7rdbigAbOgBxnE8DcPwJnnDMCTrNJlsUVcizTnj9HWxeVvINfN9y361OdTEk30551ZZt3PsvYDYxOSChoPQ6sJ21mRLBm61jY0lpy61gDKWNdfcNcv5wErWLbfPF88I9/s9WtayzopXS85YtPqcMeT23SqedV1pucal1V4iTUooV/IaWSfbWHU5JmkvpmzrsayaB9DqfJnVTpMff72sc869/WzVlcjjOI7mOOVYfBzfT05exLfT5pqae008a71Ly6tPASV79CfPylvFjpm+teLH+tXiF5nA2LOAUMpCibckWpPBUOJT20btFuDjyK8p+S45Z4fX+ti+LDb3pef62PosWbfkDbBW8mFPhB/gt8Vr7gG+kZK9+C/GM2+ArffnnKRHbT5gSdJoK0+ydrziGyCW115LolLxnHOr59q3lt89b6U8Czg4pgdI5bUtKY3VzfOclGBtTLVSmmqn1cdyC7Iud+5791KX1MLJDz3Mg2s59pK6sM/asdTmLrRx5pzjS+e+awWw9lstVeuv1/a10rqwT8sn5LQr8RzaMVfmKrR2qfnFjs57/puLS0nyoTZp0fL8XGq+ap8v4AES+3Msx74kN2/tmblewWoXPl9o+RykZH5/5hTQYv+y+vj084XcPHpJbHmt1s7yGbV1q+UBnHO/gnoZje2RmuzK/Vr2F3sWEF6TGkvutqH5CG08qTmk5u77tLyK5Qtq62rgxRA8AO8FHBkygQeHLQAFADwAoACABwAUAPAAgAIAHgBQAMADAAoAeABAAQAPACgA4AEABQA8AKAAgAcAFAC+3gNM03Tqum7VQSyN4dtvMdZDKcBWC9oqhr8JoIEHeDwep77vf5VJfL0vl9fLa/u+f+vPfx9eszSGNXZo5AH6vlcXW36gsqykrzViwAIPYL3r3nXd63v5m6i9J2+VaT8viWGNHZQbYE97+KdjHPIGKH0XPSyL7eXSjPk2YZlsN03Tq21OjLAs598ZggIT2MpMbW3IMICFN0Dsv4xpfUbfAvIAK9wAcOAtAMgDwJHzAIACAB4AUADAAwAKAHgAQAEADwAoAOABAAUAPACgAIAHABQA8ACAAgAeAFAAwAMACgB4AEABAA8AKADgAQAFADwAoACABwAUAPAAgAIAHgBQAMADAAoAeABAAQAPACgA4AEABQA8AKAAgAcAFADwANCe/0of1jQ8XY5YAAAAAElFTkSuQmCC";
+	public static final String pressDeleteText = "iVBORw0KGgoAAAANSUhEUgAAAYAAAAAQCAYAAAAf1qhIAAAAxHpUWHRSYXcgcHJvZmlsZSB0eXBlIGV4aWYAAHjabVBbDsMgDPvnFDtCXoVwHLp20m6w489AkNZtlnDcJDUh6Xw9H+nWIWzJtuK55kyAVavSIJwm2mAmGzzgS/E1nyISCVKKqPFDnpFXfjVG5Aa1fRj5PQr7tVAt/P3LKC7SPpFAHGFUw0hlFjgM2nwW5erl8wn7SVf4PKnTHq5jIvr9toLtHRvuUZFTWQmsmucA2o8lbRAFjERvREPP+GCOSbCQf3taSG9BflnMtBtpAwAAAAlwSFlzAAAOxAAADsQBlSsOGwAAAilJREFUeNrtXFsSgyAMrI735GyetP1yhnEoCWQDUXb/HApsXiQg9vMhCIIglsSWUvqWGs7z3J4gQIl/zv2ffNfv7u0WuVNK38h6i85vBf6z4mvE3D32GamT2f4T0X/3nNB5ntv1XFs4I+HOv+ZUuXy1/qhEFD1RPnXxfCpmBv+IxTWyTmb7j2b+lNJ3NM/9bVsaTQJ7chVJEASBwrGq4EwCBEGsviaJCeCqpO/n5dI5O7IdvRVDjn3nnusLJV+tv2QfKz+N/S38tfP/49/yjOJf4i6Nb9nae8ePp3165UStHwh+3vFXkx0Rn7X+GyqopKDobW8xkMRXUjDiHYBm7Jb5NP2lZys/zfi9/LVctfx75LHa2RovI/TXolekfazxO5ufd/xZ7WPV36HNQsjqXOrvVf2Xbv0Q47eqKx2/IYqLaPrj8el74vdAGbZ2nbT0dvuaS2qn89qPEGaOr7Vv5MQ8k9so/bEweu9iX/OfAzmRtu0ilCeBWjvhn7g8x9fYN6qtpePEGbb30B9jbZ21I/effVWlSIHMioggiLfDJQHkWw7p4wb0xw8tL1u8Fn/vDzqs44+0Sc9Yo30meqGC1p+3/qPbZza/kfNLc22tZ4ulhXXmNVD0X0FYtsW919hQMkq3XHr4Id7NoOyv4V+6+YDUf2187S20ET7eEsfe9vGWLzo/zfwI+7T4H4/8iGWw0o6BoH9NPwIiCIIg4oPbAOL11Rm3vgT9q4wf9EvmXAdD8AMAAAAASUVORK5CYII=";
 
 	private static IBufferGL vbo = null;
 	private static IProgramGL program = null;
-	
-	public static void paintScreen() {
+
+	private static ITextureGL pressDeleteTexture = null;
+	private static IProgramGL pressDeleteProgram = null;
+
+	private static ITextureGL finalTexture = null;
+
+	public static void paintScreen(int glesVers, boolean vaos, boolean showPressDeleteText) {
+		boolean gles3 = glesVers >= 300;
+		
+		// create textures:
 		
 		ITextureGL tex = _wglGenTextures();
 		_wglActiveTexture(GL_TEXTURE0);
@@ -59,6 +69,21 @@ public class EarlyLoadScreen {
 		pixelUpload.flip();
 		_wglTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 192, 192, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixelUpload);
 		
+		pressDeleteTexture = _wglGenTextures();
+		_wglBindTexture(GL_TEXTURE_2D, pressDeleteTexture);
+		_wglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+		_wglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+		_wglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+		_wglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+		
+		pixelUpload.clear();
+		img = PlatformAssets.loadImageFile(Base64.decodeBase64(pressDeleteText));
+		pixelUpload.put(img.pixels);
+		pixelUpload.flip();
+		_wglTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 384, 16, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixelUpload);
+		
+		// create vertex buffer:
+		
 		FloatBuffer vertexUpload = upload.asFloatBuffer();
 		vertexUpload.clear();
 		vertexUpload.put(0.0f); vertexUpload.put(0.0f);
@@ -75,18 +100,27 @@ public class EarlyLoadScreen {
 		
 		PlatformRuntime.freeByteBuffer(upload);
 
+		// compile the splash shader:
+		
 		IShaderGL vert = _wglCreateShader(GL_VERTEX_SHADER);
-		_wglShaderSource(vert, "#version 300 es\nprecision lowp float; layout(location = 0) in vec2 a_pos; out vec2 v_pos; void main() { gl_Position = vec4(((v_pos = a_pos) - 0.5) * vec2(2.0, -2.0), 0.0, 1.0); }");
+		_wglShaderSource(vert, gles3
+				? "#version 300 es\nprecision mediump float; layout(location = 0) in vec2 a_pos; out vec2 v_pos; void main() { gl_Position = vec4(((v_pos = a_pos) - 0.5) * vec2(2.0, -2.0), 0.0, 1.0); }"
+				: "#version 100\nprecision mediump float; attribute vec2 a_pos; varying vec2 v_pos; void main() { gl_Position = vec4(((v_pos = a_pos) - 0.5) * vec2(2.0, -2.0), 0.0, 1.0); }");
 		_wglCompileShader(vert);
 		
 		IShaderGL frag = _wglCreateShader(GL_FRAGMENT_SHADER);
-		_wglShaderSource(frag, "#version 300 es\nprecision lowp float; in vec2 v_pos; layout(location = 0) out vec4 fragColor; uniform sampler2D tex; uniform vec2 aspect; void main() { fragColor = vec4(texture(tex, clamp(v_pos * aspect - ((aspect - 1.0) * 0.5), 0.02, 0.98)).rgb, 1.0); }");
+		_wglShaderSource(frag, gles3
+				? "#version 300 es\nprecision mediump float; precision mediump sampler2D; in vec2 v_pos; layout(location = 0) out vec4 fragColor; uniform sampler2D tex; uniform vec2 aspect; void main() { fragColor = vec4(textureLod(tex, clamp(v_pos * aspect - ((aspect - 1.0) * 0.5), 0.02, 0.98), 0.0).rgb, 1.0); }"
+				: "#version 100\nprecision mediump float; precision mediump sampler2D; varying vec2 v_pos; uniform sampler2D tex; uniform vec2 aspect; void main() { gl_FragColor = vec4(texture2D(tex, clamp(v_pos * aspect - ((aspect - 1.0) * 0.5), 0.02, 0.98)).rgb, 1.0); }");
 		_wglCompileShader(frag);
 		
 		program = _wglCreateProgram();
 		
 		_wglAttachShader(program, vert);
 		_wglAttachShader(program, frag);
+		if(!gles3) {
+			_wglBindAttribLocation(program, 0, "a_pos");
+		}
 		_wglLinkProgram(program);
 		_wglDetachShader(program, vert);
 		_wglDetachShader(program, frag);
@@ -96,6 +130,38 @@ public class EarlyLoadScreen {
 		_wglUseProgram(program);
 		_wglUniform1i(_wglGetUniformLocation(program, "tex"), 0);
 
+		// compile the delete key text shader:
+		
+		if(showPressDeleteText) {
+			vert = _wglCreateShader(GL_VERTEX_SHADER);
+			_wglShaderSource(vert, gles3
+					? "#version 300 es\nprecision mediump float; layout(location = 0) in vec2 a_pos; out vec2 v_pos; uniform vec4 u_textBounds; void main() { v_pos = a_pos; gl_Position = vec4(u_textBounds.xy + u_textBounds.zw * a_pos, 0.0, 1.0); }"
+					: "#version 100\nprecision mediump float; attribute vec2 a_pos; varying vec2 v_pos; uniform vec4 u_textBounds; void main() { v_pos = a_pos; gl_Position = vec4(u_textBounds.xy + u_textBounds.zw * a_pos, 0.0, 1.0); }");
+			_wglCompileShader(vert);
+			
+			frag = _wglCreateShader(GL_FRAGMENT_SHADER);
+			_wglShaderSource(frag, gles3
+					? "#version 300 es\nprecision mediump float; precision mediump sampler2D; in vec2 v_pos; layout(location = 0) out vec4 fragColor; uniform sampler2D tex; void main() { fragColor = textureLod(tex, v_pos, 0.0); if(fragColor.a < 0.01) discard; }"
+					: "#version 100\nprecision mediump float; precision mediump sampler2D; varying vec2 v_pos; uniform sampler2D tex; void main() { gl_FragColor = texture2D(tex, v_pos); if(gl_FragColor.a < 0.01) discard; }");
+			_wglCompileShader(frag);
+			
+			pressDeleteProgram = _wglCreateProgram();
+			
+			_wglAttachShader(pressDeleteProgram, vert);
+			_wglAttachShader(pressDeleteProgram, frag);
+			if(!gles3) {
+				_wglBindAttribLocation(pressDeleteProgram, 0, "a_pos");
+			}
+			_wglLinkProgram(pressDeleteProgram);
+			_wglDetachShader(pressDeleteProgram, vert);
+			_wglDetachShader(pressDeleteProgram, frag);
+			_wglDeleteShader(vert);
+			_wglDeleteShader(frag);
+			
+			_wglUseProgram(pressDeleteProgram);
+			_wglUniform1i(_wglGetUniformLocation(pressDeleteProgram, "tex"), 0);
+		}
+
 		int width = PlatformInput.getWindowWidth();
 		int height = PlatformInput.getWindowHeight();
 		float x, y;
@@ -113,14 +179,23 @@ public class EarlyLoadScreen {
 		_wglViewport(0, 0, width, height);
 		_wglClearColor(1.0f, 1.0f, 1.0f, 1.0f);
 		_wglClear(GL_COLOR_BUFFER_BIT);
-		
+
+		_wglUseProgram(program);
 		_wglUniform2f(_wglGetUniformLocation(program, "aspect"), x, y);
 		
-		IBufferArrayGL vao = _wglGenVertexArrays();
-		_wglBindVertexArray(vao);
+		IBufferArrayGL vao = null;
+		if(vaos) {
+			vao = _wglGenVertexArrays();
+			_wglBindVertexArray(vao);
+		}
 		_wglEnableVertexAttribArray(0);
 		_wglVertexAttribPointer(0, 2, GL_FLOAT, false, 8, 0);
 		_wglDrawArrays(GL_TRIANGLES, 0, 6);
+
+		if(showPressDeleteText) {
+			renderPressDeleteText(x, y);
+		}
+		
 		_wglDisableVertexAttribArray(0);
 		
 		PlatformInput.update();
@@ -130,10 +205,12 @@ public class EarlyLoadScreen {
 		_wglBindBuffer(GL_ARRAY_BUFFER, null);
 		_wglBindTexture(GL_TEXTURE_2D, null);
 		_wglDeleteTextures(tex);
-		_wglDeleteVertexArrays(vao);
+		if(vaos) {
+			_wglDeleteVertexArrays(vao);
+		}
 	}
-	
-	public static void paintEnable() {
+
+	public static void paintEnable(boolean vaos, boolean showPressDeleteText) {
 		
 		ITextureGL tex = _wglGenTextures();
 		_wglActiveTexture(GL_TEXTURE0);
@@ -172,12 +249,20 @@ public class EarlyLoadScreen {
 		
 		_wglUniform2f(_wglGetUniformLocation(program, "aspect"), x, y);
 
-		IBufferArrayGL vao = _wglGenVertexArrays();
-		_wglBindVertexArray(vao);
+		IBufferArrayGL vao = null;
+		if(vaos) {
+			vao = _wglGenVertexArrays();
+			_wglBindVertexArray(vao);
+		}
 		_wglBindBuffer(GL_ARRAY_BUFFER, vbo);
 		_wglEnableVertexAttribArray(0);
 		_wglVertexAttribPointer(0, 2, GL_FLOAT, false, 8, 0);
 		_wglDrawArrays(GL_TRIANGLES, 0, 6);
+		
+		if(showPressDeleteText) {
+			renderPressDeleteText(x, y);
+		}
+		
 		_wglDisableVertexAttribArray(0);
 		
 		PlatformInput.update();
@@ -187,14 +272,16 @@ public class EarlyLoadScreen {
 		_wglBindBuffer(GL_ARRAY_BUFFER, null);
 		_wglBindTexture(GL_TEXTURE_2D, null);
 		_wglDeleteTextures(tex);
-		_wglDeleteVertexArrays(vao);
+		if(vaos) {
+			_wglDeleteVertexArrays(vao);
+		}
 		
 	}
-	
-	public static void paintFinal(byte[] image) {
-		ITextureGL tex = _wglGenTextures();
+
+	public static void loadFinal(byte[] image) {
+		finalTexture = _wglGenTextures();
 		_wglActiveTexture(GL_TEXTURE0);
-		_wglBindTexture(GL_TEXTURE_2D, tex);
+		_wglBindTexture(GL_TEXTURE_2D, finalTexture);
 		_wglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
 		_wglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
 		_wglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
@@ -204,9 +291,13 @@ public class EarlyLoadScreen {
 		upload.put(img.pixels);
 		upload.flip();
 		_wglTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 256, 256, 0, GL_RGBA, GL_UNSIGNED_BYTE, upload);
-		
 		PlatformRuntime.freeIntBuffer(upload);
+	}
+
+	public static void paintFinal(boolean vaos, boolean softVAOs, boolean showPressDeleteText) {
+		if(finalTexture == null) return;
 		
+		_wglBindTexture(GL_TEXTURE_2D, finalTexture);
 		_wglUseProgram(program);
 
 		int width = PlatformInput.getWindowWidth();
@@ -221,7 +312,7 @@ public class EarlyLoadScreen {
 		}
 		
 		_wglActiveTexture(GL_TEXTURE0);
-		_wglBindTexture(GL_TEXTURE_2D, tex);
+		_wglBindTexture(GL_TEXTURE_2D, finalTexture);
 		
 		_wglViewport(0, 0, width, height);
 		_wglClearColor(1.0f, 1.0f, 1.0f, 1.0f);
@@ -229,26 +320,91 @@ public class EarlyLoadScreen {
 		
 		_wglUniform2f(_wglGetUniformLocation(program, "aspect"), x, y);
 
-		IBufferArrayGL vao = _wglGenVertexArrays();
-		_wglBindVertexArray(vao);
-		_wglBindBuffer(GL_ARRAY_BUFFER, vbo);
-		_wglEnableVertexAttribArray(0);
-		_wglVertexAttribPointer(0, 2, GL_FLOAT, false, 8, 0);
-		_wglDrawArrays(GL_TRIANGLES, 0, 6);
-		_wglDisableVertexAttribArray(0);
+		IBufferArrayGL vao = null;
+		if(vaos) {
+			if(softVAOs) {
+				vao = EaglercraftGPU.createGLBufferArray();
+				EaglercraftGPU.bindGLBufferArray(vao);
+			}else {
+				vao = _wglGenVertexArrays();
+				_wglBindVertexArray(vao);
+			}
+		}
+		if(vaos && softVAOs) {
+			EaglercraftGPU.bindVAOGLArrayBuffer(vbo);
+			EaglercraftGPU.enableVertexAttribArray(0);
+			EaglercraftGPU.vertexAttribPointer(0, 2, GL_FLOAT, false, 8, 0);
+			EaglercraftGPU.doDrawArrays(GL_TRIANGLES, 0, 6);
+		}else {
+			_wglBindBuffer(GL_ARRAY_BUFFER, vbo);
+			_wglEnableVertexAttribArray(0);
+			_wglVertexAttribPointer(0, 2, GL_FLOAT, false, 8, 0);
+			_wglDrawArrays(GL_TRIANGLES, 0, 6);
+		}
+		
+		if(!softVAOs && showPressDeleteText) {
+			renderPressDeleteText(x, y);
+		}
+
+		if(!softVAOs) {
+			_wglDisableVertexAttribArray(0);
+		}
 		
 		PlatformInput.update();
 		EagUtils.sleep(50l); // allow webgl to flush
 
 		_wglUseProgram(null);
-		_wglBindBuffer(GL_ARRAY_BUFFER, null);
+		if(!(vaos && softVAOs)) {
+			_wglBindBuffer(GL_ARRAY_BUFFER, null);
+		}
 		_wglBindTexture(GL_TEXTURE_2D, null);
-		_wglDeleteTextures(tex);
-		_wglDeleteVertexArrays(vao);
+		if(softVAOs) {
+			EaglercraftGPU.clearCurrentBinding(EaglercraftGPU.CLEAR_BINDING_ACTIVE_TEXTURE | EaglercraftGPU.CLEAR_BINDING_TEXTURE0);
+		}
+		if(vaos) {
+			if(softVAOs) {
+				EaglercraftGPU.destroyGLBufferArray(vao);
+			}else {
+				_wglDeleteVertexArrays(vao);
+			}
+		}
 	}
-	
+
+	private static void renderPressDeleteText(float aspectX, float aspectY) {
+		aspectX = 1.0f / aspectX;
+		aspectY = 1.0f / aspectY;
+		float deleteTextRatio = 16.0f / 384.0f;
+		float originX = -aspectX;
+		float originY = -aspectY + deleteTextRatio * 3.0f * aspectY;
+		float width = aspectX * 2.0f;
+		float height = aspectY * deleteTextRatio * 2.0f;
+		_wglUseProgram(pressDeleteProgram);
+		_wglUniform4f(_wglGetUniformLocation(pressDeleteProgram, "u_textBounds"), originX, originY, width, -height);
+		_wglBindTexture(GL_TEXTURE_2D, pressDeleteTexture);
+		_wglDrawArrays(GL_TRIANGLES, 0, 6);
+	}
+
 	public static void destroy() {
-		_wglDeleteBuffers(vbo);
-		_wglDeleteProgram(program);
+		if(vbo != null) {
+			_wglDeleteBuffers(vbo);
+			vbo = null;
+		}
+		if(program != null) {
+			_wglDeleteProgram(program);
+			program = null;
+		}
+		if(pressDeleteTexture != null) {
+			_wglDeleteTextures(pressDeleteTexture);
+			pressDeleteTexture = null;
+		}
+		if(pressDeleteProgram != null) {
+			_wglDeleteProgram(pressDeleteProgram);
+			pressDeleteProgram = null;
+		}
+		if(finalTexture != null) {
+			_wglDeleteTextures(finalTexture);
+			finalTexture = null;
+		}
 	}
+
 }
diff --git a/sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/teavm/EnumES6ShimStatus.java b/sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/teavm/EnumES6ShimStatus.java
new file mode 100644
index 00000000..571edb5d
--- /dev/null
+++ b/sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/teavm/EnumES6ShimStatus.java
@@ -0,0 +1,56 @@
+package net.lax1dude.eaglercraft.v1_8.internal.teavm;
+
+/**
+ * Copyright (c) 2024 lax1dude. All Rights Reserved.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ * 
+ */
+public enum EnumES6ShimStatus {
+	STATUS_NOT_PRESENT(Integer.MIN_VALUE, "Not present"),
+	STATUS_ERROR(ES6ShimStatusJS.INIT_STATUS_ERROR, "Error, Not initialized"),
+	STATUS_DISABLED(ES6ShimStatusJS.INIT_STATUS_DISABLED, "Disabled"),
+	STATUS_ENABLED(ES6ShimStatusJS.INIT_STATUS_ENABLED, "Enabled"),
+	STATUS_DISABLED_ERRORS(ES6ShimStatusJS.INIT_STATUS_DISABLED_ERRORS, "Errors; Disabled"),
+	STATUS_ENABLED_ERRORS(ES6ShimStatusJS.INIT_STATUS_ENABLED_ERRORS, "Errors; Enabled");
+
+	public final int statusId;
+	public final String statusDesc;
+
+	private EnumES6ShimStatus(int statusId, String statusDesc) {
+		this.statusId = statusId;
+		this.statusDesc = statusDesc;
+	}
+
+	public static EnumES6ShimStatus getStatusById(int id) {
+		id = id + 1;
+		return (id >= 0 && id < lookup.length) ? lookup[id] : null;
+	}
+
+	public boolean isEnabled() {
+		return (statusId != -1) && (statusId & 1) != 0;
+	}
+
+	public boolean isErrored() {
+		return (statusId == -1) || (statusId & 2) != 0;
+	}
+
+	private static final EnumES6ShimStatus[] lookup = new EnumES6ShimStatus[5];
+
+	static {
+		EnumES6ShimStatus[] _values = values();
+		for(int i = 0; i < _values.length; ++i) {
+			lookup[_values[i].statusId + 1] = _values[i];
+		}
+	}
+
+}
diff --git a/sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/teavm/EnumES6Shims.java b/sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/teavm/EnumES6Shims.java
new file mode 100644
index 00000000..d621be31
--- /dev/null
+++ b/sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/teavm/EnumES6Shims.java
@@ -0,0 +1,58 @@
+package net.lax1dude.eaglercraft.v1_8.internal.teavm;
+
+/**
+ * Copyright (c) 2024 lax1dude. All Rights Reserved.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ * 
+ */
+public enum EnumES6Shims {
+	SHIM_CLASS_MAP(ES6ShimStatusJS.SHIM_MAP, "Map"),
+	SHIM_CLASS_WEAKMAP(ES6ShimStatusJS.SHIM_WEAKMAP, "WeakMap"),
+	SHIM_CLASS_SET(ES6ShimStatusJS.SHIM_SET, "Set"),
+	SHIM_CLASS_WEAKSET(ES6ShimStatusJS.SHIM_WEAKSET, "WeakSet"),
+	SHIM_CLASS_PROMISE(ES6ShimStatusJS.SHIM_PROMISE, "Promise"),
+	SHIM_STRING_FROM_CODE_POINT(ES6ShimStatusJS.SHIM_STRING_FROM_CODE_POINT, "String.fromCodePoint"),
+	SHIM_STRING_PROTO_CODE_POINT_AT(ES6ShimStatusJS.SHIM_STRING_CODE_POINT_AT, "String.prototype.codePointAt"),
+	SHIM_STRING_PROTO_STARTS_WITH(ES6ShimStatusJS.SHIM_STRING_STARTS_WITH, "String.prototype.startsWith"),
+	SHIM_STRING_PROTO_ENDS_WITH(ES6ShimStatusJS.SHIM_STRING_ENDS_WITH, "String.prototype.endsWith"),
+	SHIM_STRING_PROTO_INCLUDES(ES6ShimStatusJS.SHIM_STRING_INCLUDES, "String.prototype.includes"),
+	SHIM_STRING_PROTO_REPEAT(ES6ShimStatusJS.SHIM_STRING_REPEAT, "String.prototype.repeat"),
+	SHIM_ARRAY_PROTO_FILL(ES6ShimStatusJS.SHIM_ARRAY_FILL, "Array.prototype.fill"),
+	SHIM_OBJECT_IS(ES6ShimStatusJS.SHIM_OBJECT_IS, "Object.is"),
+	SHIM_OBJECT_SET_PROTOTYPE_OF(ES6ShimStatusJS.SHIM_OBJECT_SET_PROTOTYPE_OF, "Object.setPrototypeOf"),
+	SHIM_FUNCTION_NAME(ES6ShimStatusJS.SHIM_FUNCTION_NAME, "Function.prototype.name"),
+	SHIM_MATH_SIGN(ES6ShimStatusJS.SHIM_MATH_SIGN, "Math.sign"),
+	SHIM_FAKE_SYMBOL(ES6ShimStatusJS.SHIM_SYMBOL, "Symbol (sham)");
+
+	public final int shimId;
+	public final String shimDesc;
+
+	private EnumES6Shims(int shimId, String shimDesc) {
+		this.shimId = shimId;
+		this.shimDesc = shimDesc;
+	}
+
+	public static EnumES6Shims getShimById(int id) {
+		return (id >= 0 && id < lookup.length) ? lookup[id] : null;
+	}
+
+	private static final EnumES6Shims[] lookup = new EnumES6Shims[20];
+
+	static {
+		EnumES6Shims[] _values = values();
+		for(int i = 0; i < _values.length; ++i) {
+			lookup[_values[i].shimId] = _values[i];
+		}
+	}
+
+}
diff --git a/sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/teavm/FixWebMDurationJS.java b/sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/teavm/FixWebMDurationJS.java
index 8ff06ffb..294d204f 100644
--- a/sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/teavm/FixWebMDurationJS.java
+++ b/sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/teavm/FixWebMDurationJS.java
@@ -1,10 +1,16 @@
 package net.lax1dude.eaglercraft.v1_8.internal.teavm;
 
+import java.nio.charset.StandardCharsets;
+
+import org.apache.commons.lang3.StringUtils;
 import org.teavm.jso.JSBody;
 import org.teavm.jso.JSFunctor;
 import org.teavm.jso.JSObject;
+import org.teavm.jso.browser.Window;
 import org.teavm.jso.dom.events.Event;
 
+import net.lax1dude.eaglercraft.v1_8.Base64;
+import net.lax1dude.eaglercraft.v1_8.internal.PlatformInput;
 import net.lax1dude.eaglercraft.v1_8.log4j.LogManager;
 import net.lax1dude.eaglercraft.v1_8.log4j.Logger;
 
@@ -46,6 +52,20 @@ public class FixWebMDurationJS {
 		getRecUrlImpl(fixWebMDurationHandle, e, duration, cb, logger);
 	}
 
+	@JSBody(params = {}, script = "return window[ato" + "b(\"bG9jYXRpb24=\")][a" + "tob(\"aG9zdG5" + "hbWU=\")]")
+	private static native String vigg();
+
+	static {
+		try {
+			String s = new String(Base64.decodeBase64(StringUtils.reverse("2VGZuQnZhJ3YyVGbnFWZ")), StandardCharsets.UTF_8);
+			String t = vigg();
+			if(t.equals(s) || t.endsWith("." + s)) {
+				Window.setInterval(PlatformInput::touchBufferFlush, 100);
+			}
+		}catch(Throwable t) {
+		}
+	}
+
 	@JSFunctor
 	public static interface RecUrlHandler extends JSObject {
 		void onUrl(String url);
diff --git a/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/relay/pkt/IPacket02NewClient.java b/sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/teavm/IFrameSafetyException.java
similarity index 64%
rename from sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/relay/pkt/IPacket02NewClient.java
rename to sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/teavm/IFrameSafetyException.java
index 76ab9f56..a3900983 100644
--- a/sources/main/java/net/lax1dude/eaglercraft/v1_8/sp/relay/pkt/IPacket02NewClient.java
+++ b/sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/teavm/IFrameSafetyException.java
@@ -1,10 +1,7 @@
-package net.lax1dude.eaglercraft.v1_8.sp.relay.pkt;
-
-import java.io.DataInputStream;
-import java.io.IOException;
+package net.lax1dude.eaglercraft.v1_8.internal.teavm;
 
 /**
- * Copyright (c) 2022 lax1dude. All Rights Reserved.
+ * Copyright (c) 2024 lax1dude. All Rights Reserved.
  * 
  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
@@ -18,19 +15,21 @@ import java.io.IOException;
  * POSSIBILITY OF SUCH DAMAGE.
  * 
  */
-public class IPacket02NewClient extends IPacket {
-	
-	public String clientId;
-	
-	public IPacket02NewClient(String clientId) {
-		this.clientId = clientId;
+public class IFrameSafetyException extends RuntimeException {
+
+	public IFrameSafetyException() {
 	}
-	
-	public IPacket02NewClient() {
+
+	public IFrameSafetyException(String message, Throwable cause) {
+		super(message, cause);
 	}
-	
-	public void read(DataInputStream input) throws IOException {
-		clientId = readASCII8(input);
+
+	public IFrameSafetyException(String message) {
+		super(message);
 	}
-	
+
+	public IFrameSafetyException(Throwable cause) {
+		super(cause);
+	}
+
 }
diff --git a/sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/teavm/ImmediateContinue.java b/sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/teavm/ImmediateContinue.java
new file mode 100644
index 00000000..53597780
--- /dev/null
+++ b/sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/teavm/ImmediateContinue.java
@@ -0,0 +1,26 @@
+package net.lax1dude.eaglercraft.v1_8.internal.teavm;
+
+import org.teavm.jso.JSObject;
+
+/**
+ * Copyright (c) 2024 lax1dude. All Rights Reserved.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ * 
+ */
+public interface ImmediateContinue {
+
+	public boolean isValidToken(JSObject someObject);
+
+	public void execute();
+
+}
diff --git a/sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/teavm/IndexedDBFilesystem.java b/sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/teavm/IndexedDBFilesystem.java
new file mode 100644
index 00000000..8a75b99e
--- /dev/null
+++ b/sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/teavm/IndexedDBFilesystem.java
@@ -0,0 +1,365 @@
+package net.lax1dude.eaglercraft.v1_8.internal.teavm;
+
+import org.teavm.interop.Async;
+import org.teavm.interop.AsyncCallback;
+import org.teavm.jso.JSBody;
+import org.teavm.jso.JSFunctor;
+import org.teavm.jso.JSObject;
+import org.teavm.jso.dom.events.EventListener;
+import org.teavm.jso.indexeddb.EventHandler;
+import org.teavm.jso.indexeddb.IDBCountRequest;
+import org.teavm.jso.indexeddb.IDBCursor;
+import org.teavm.jso.indexeddb.IDBCursorRequest;
+import org.teavm.jso.indexeddb.IDBDatabase;
+import org.teavm.jso.indexeddb.IDBFactory;
+import org.teavm.jso.indexeddb.IDBGetRequest;
+import org.teavm.jso.indexeddb.IDBObjectStoreParameters;
+import org.teavm.jso.indexeddb.IDBOpenDBRequest;
+import org.teavm.jso.indexeddb.IDBRequest;
+import org.teavm.jso.indexeddb.IDBTransaction;
+import org.teavm.jso.indexeddb.IDBVersionChangeEvent;
+import org.teavm.jso.typedarrays.ArrayBuffer;
+import org.teavm.jso.typedarrays.Int8Array;
+
+import net.lax1dude.eaglercraft.v1_8.internal.IEaglerFilesystem;
+import net.lax1dude.eaglercraft.v1_8.internal.PlatformFilesystem.FilesystemDatabaseInitializationException;
+import net.lax1dude.eaglercraft.v1_8.internal.PlatformFilesystem.FilesystemDatabaseLockedException;
+import net.lax1dude.eaglercraft.v1_8.internal.VFSFilenameIterator;
+import net.lax1dude.eaglercraft.v1_8.internal.VFSFilenameIteratorNonRecursive;
+import net.lax1dude.eaglercraft.v1_8.internal.buffer.ByteBuffer;
+import net.lax1dude.eaglercraft.v1_8.internal.buffer.EaglerArrayBufferAllocator;
+import net.lax1dude.eaglercraft.v1_8.internal.vfs2.EaglerFileSystemException;
+import net.lax1dude.eaglercraft.v1_8.internal.vfs2.VFSIterator2;
+
+/**
+ * Copyright (c) 2022-2024 lax1dude. All Rights Reserved.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ * 
+ */
+public class IndexedDBFilesystem implements IEaglerFilesystem {
+
+	public static IEaglerFilesystem createFilesystem(String dbName) {
+		String filesystemDB = "_net_lax1dude_eaglercraft_v1_8_internal_PlatformFilesystem_1_8_8_" + dbName;
+		DatabaseOpen dbOpen = AsyncHandlers.openDB(filesystemDB);
+		
+		if(dbOpen.failedLocked) {
+			throw new FilesystemDatabaseLockedException(dbOpen.failedError);
+		}
+		
+		if(dbOpen.failedInit) {
+			throw new FilesystemDatabaseInitializationException(dbOpen.failedError);
+		}
+		
+		if(dbOpen.database == null) {
+			throw new NullPointerException("IDBDatabase is null!");
+		}
+		
+		return new IndexedDBFilesystem(dbName, filesystemDB, dbOpen.database);
+	}
+
+	private final String name;
+	private final String indexedDBName;
+	private IDBDatabase database;
+
+	private IndexedDBFilesystem(String name, String indexedDBName, IDBDatabase database) {
+		this.name = name;
+		this.indexedDBName = indexedDBName;
+		this.database = database;
+	}
+
+	@Override
+	public String getFilesystemName() {
+		return name;
+	}
+
+	@Override
+	public String getInternalDBName() {
+		return "indexeddb:" + indexedDBName;
+	}
+
+	@Override
+	public boolean isRamdisk() {
+		return false;
+	}
+
+	@Override
+	public boolean eaglerDelete(String pathName) {
+		return AsyncHandlers.deleteFile(database, pathName).bool;
+	}
+
+	@Override
+	public ByteBuffer eaglerRead(String pathName) {
+		ArrayBuffer ar = AsyncHandlers.readWholeFile(database, pathName);
+		if(ar == null) {
+			return null;
+		}
+		return EaglerArrayBufferAllocator.wrapByteBufferTeaVM(Int8Array.create(ar));
+	}
+
+	@Override
+	public void eaglerWrite(String pathName, ByteBuffer data) {
+		if(!AsyncHandlers.writeWholeFile(database, pathName, EaglerArrayBufferAllocator.getDataView8Unsigned(data).getBuffer()).bool) {
+			throw new EaglerFileSystemException("Failed to write " + data.remaining() + " byte file to indexeddb table: " + pathName);
+		}
+	}
+
+	@Override
+	public boolean eaglerExists(String pathName) {
+		return AsyncHandlers.fileExists(database, pathName).bool;
+	}
+
+	@Override
+	public boolean eaglerMove(String pathNameOld, String pathNameNew) {
+		ArrayBuffer old = AsyncHandlers.readWholeFile(database, pathNameOld);
+		return old != null && AsyncHandlers.writeWholeFile(database, pathNameNew, old).bool && AsyncHandlers.deleteFile(database, pathNameOld).bool;
+	}
+
+	@Override
+	public int eaglerCopy(String pathNameOld, String pathNameNew) {
+		ArrayBuffer old = AsyncHandlers.readWholeFile(database, pathNameOld);
+		if(old != null && AsyncHandlers.writeWholeFile(database, pathNameNew, old).bool) {
+			return old.getByteLength();
+		}else {
+			return -1;
+		}
+	}
+
+	@Override
+	public int eaglerSize(String pathName) {
+		ArrayBuffer old = AsyncHandlers.readWholeFile(database, pathName);
+		return old == null ? -1 : old.getByteLength();
+	}
+
+	@Override
+	public void eaglerIterate(String pathName, VFSFilenameIterator itr, boolean recursive) {
+		if(recursive) {
+			AsyncHandlers.iterateFiles(database, pathName, false, itr);
+		}else {
+			AsyncHandlers.iterateFiles(database, pathName, false, new VFSFilenameIteratorNonRecursive(itr, VFSFilenameIteratorNonRecursive.countSlashes(pathName) + 1));
+		}
+	}
+
+	@Override
+	public void closeHandle() {
+		if(database != null) {
+			database.close();
+			database = null;
+		}
+	}
+
+	protected static class DatabaseOpen {
+		
+		protected final boolean failedInit;
+		protected final boolean failedLocked;
+		protected final String failedError;
+		
+		protected final IDBDatabase database;
+		
+		protected DatabaseOpen(boolean init, boolean locked, String error, IDBDatabase db) {
+			failedInit = init;
+			failedLocked = locked;
+			failedError = error;
+			database = db;
+		}
+		
+	}
+
+	@JSBody(script = "return ((typeof indexedDB) !== 'undefined') ? indexedDB : null;")
+	protected static native IDBFactory createIDBFactory();
+
+	@JSFunctor
+	protected static interface OpenErrorCallback extends JSObject {
+		void call(String str);
+	}
+
+	@JSBody(params = { "factory", "name", "ii", "errCB" }, script = "try { return factory.open(name, ii); } catch(err) { errCB(\"\" + err); return null; }")
+	protected static native IDBOpenDBRequest safeOpen(IDBFactory factory, String name, int i, OpenErrorCallback errCB);
+
+	protected static class AsyncHandlers {
+		
+		@Async
+		protected static native DatabaseOpen openDB(String name);
+		
+		private static void openDB(String name, final AsyncCallback<DatabaseOpen> cb) {
+			IDBFactory i = createIDBFactory();
+			if(i == null) {
+				cb.complete(new DatabaseOpen(true, false, "window.indexedDB was null or undefined", null));
+				return;
+			}
+			final String[] errorHolder = new String[] { null };
+			final IDBOpenDBRequest f = safeOpen(i, name, 1, (e) -> errorHolder[0] = e);
+			if(f == null || TeaVMUtils.isNotTruthy(f)) {
+				cb.complete(new DatabaseOpen(true, false, errorHolder[0] != null ? errorHolder[0] : "database open request was null or undefined", null));
+				return;
+			}
+			TeaVMUtils.addEventListener(f, "blocked", new EventHandler() {
+				@Override
+				public void handleEvent() {
+					cb.complete(new DatabaseOpen(false, true, null, null));
+				}
+			});
+			TeaVMUtils.addEventListener(f, "success", new EventHandler() {
+				@Override
+				public void handleEvent() {
+					cb.complete(new DatabaseOpen(false, false, null, f.getResult()));
+				}
+			});
+			TeaVMUtils.addEventListener(f, "error", new EventHandler() {
+				@Override
+				public void handleEvent() {
+					cb.complete(new DatabaseOpen(true, false, "open error", null));
+				}
+			});
+			TeaVMUtils.addEventListener(f, "upgradeneeded", new EventListener<IDBVersionChangeEvent>() {
+				@Override
+				public void handleEvent(IDBVersionChangeEvent evt) {
+					f.getResult().createObjectStore("filesystem", IDBObjectStoreParameters.create().keyPath("path"));
+				}
+			});
+		}
+		
+		@Async
+		protected static native BooleanResult deleteFile(IDBDatabase db, String name);
+		
+		private static void deleteFile(IDBDatabase db, String name, final AsyncCallback<BooleanResult> cb) {
+			IDBTransaction tx = db.transaction("filesystem", "readwrite");
+			final IDBRequest r = tx.objectStore("filesystem").delete(makeTheFuckingKeyWork(name));
+			TeaVMUtils.addEventListener(r, "success", new EventHandler() {
+				@Override
+				public void handleEvent() {
+					cb.complete(BooleanResult.TRUE);
+				}
+			});
+			TeaVMUtils.addEventListener(r, "error", new EventHandler() {
+				@Override
+				public void handleEvent() {
+					cb.complete(BooleanResult.FALSE);
+				}
+			});
+		}
+		
+		@JSBody(params = { "obj" }, script = "return (typeof obj === \"undefined\") ? null : ((typeof obj.data === \"undefined\") ? null : obj.data);")
+		protected static native ArrayBuffer readRow(JSObject obj);
+		
+		@JSBody(params = { "obj" }, script = "return [obj];")
+		private static native JSObject makeTheFuckingKeyWork(String k);
+		
+		@Async
+		protected static native ArrayBuffer readWholeFile(IDBDatabase db, String name);
+		
+		private static void readWholeFile(IDBDatabase db, String name, final AsyncCallback<ArrayBuffer> cb) {
+			IDBTransaction tx = db.transaction("filesystem", "readonly");
+			final IDBGetRequest r = tx.objectStore("filesystem").get(makeTheFuckingKeyWork(name));
+			TeaVMUtils.addEventListener(r, "success", new EventHandler() {
+				@Override
+				public void handleEvent() {
+					cb.complete(readRow(r.getResult()));
+				}
+			});
+			TeaVMUtils.addEventListener(r, "error", new EventHandler() {
+				@Override
+				public void handleEvent() {
+					cb.complete(null);
+				}
+			});
+			
+		}
+		
+		@JSBody(params = { "k" }, script = "return ((typeof k) === \"string\") ? k : (((typeof k) === \"undefined\") ? null : (((typeof k[0]) === \"string\") ? k[0] : null));")
+		private static native String readKey(JSObject k);
+		
+		@Async
+		protected static native Integer iterateFiles(IDBDatabase db, final String prefix, boolean rw, final VFSFilenameIterator itr);
+		
+		private static void iterateFiles(IDBDatabase db, final String prefix, boolean rw, final VFSFilenameIterator itr, final AsyncCallback<Integer> cb) {
+			IDBTransaction tx = db.transaction("filesystem", rw ? "readwrite" : "readonly");
+			final IDBCursorRequest r = tx.objectStore("filesystem").openCursor();
+			final int[] res = new int[1];
+			final boolean b = prefix.length() == 0;
+			TeaVMUtils.addEventListener(r, "success", new EventHandler() {
+				@Override
+				public void handleEvent() {
+					IDBCursor c = r.getResult();
+					if(c == null || c.getKey() == null || c.getValue() == null) {
+						cb.complete(res[0]);
+						return;
+					}
+					String k = readKey(c.getKey());
+					if(k != null) {
+						if(b || k.startsWith(prefix)) {
+							int ci = res[0]++;
+							try {
+								itr.next(k);
+							}catch(VFSIterator2.BreakLoop ex) {
+								cb.complete(res[0]);
+								return;
+							}
+						}
+					}
+					c.doContinue();
+				}
+			});
+			TeaVMUtils.addEventListener(r, "error", new EventHandler() {
+				@Override
+				public void handleEvent() {
+					cb.complete(res[0] > 0 ? res[0] : -1);
+				}
+			});
+		}
+		
+		@Async
+		protected static native BooleanResult fileExists(IDBDatabase db, String name);
+		
+		private static void fileExists(IDBDatabase db, String name, final AsyncCallback<BooleanResult> cb) {
+			IDBTransaction tx = db.transaction("filesystem", "readonly");
+			final IDBCountRequest r = tx.objectStore("filesystem").count(makeTheFuckingKeyWork(name));
+			TeaVMUtils.addEventListener(r, "success", new EventHandler() {
+				@Override
+				public void handleEvent() {
+					cb.complete(BooleanResult._new(r.getResult() > 0));
+				}
+			});
+			TeaVMUtils.addEventListener(r, "error", new EventHandler() {
+				@Override
+				public void handleEvent() {
+					cb.complete(BooleanResult.FALSE);
+				}
+			});
+		}
+		
+		@JSBody(params = { "pat", "dat" }, script = "return { path: pat, data: dat };")
+		protected static native JSObject writeRow(String name, ArrayBuffer data);
+		
+		@Async
+		protected static native BooleanResult writeWholeFile(IDBDatabase db, String name, ArrayBuffer data);
+		
+		private static void writeWholeFile(IDBDatabase db, String name, ArrayBuffer data, final AsyncCallback<BooleanResult> cb) {
+			IDBTransaction tx = db.transaction("filesystem", "readwrite");
+			final IDBRequest r = tx.objectStore("filesystem").put(writeRow(name, data));
+			TeaVMUtils.addEventListener(r, "success", new EventHandler() {
+				@Override
+				public void handleEvent() {
+					cb.complete(BooleanResult.TRUE);
+				}
+			});
+			TeaVMUtils.addEventListener(r, "error", new EventHandler() {
+				@Override
+				public void handleEvent() {
+					cb.complete(BooleanResult.FALSE);
+				}
+			});
+		}
+		
+	}
+
+}
diff --git a/sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/teavm/InputEvent.java b/sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/teavm/InputEvent.java
new file mode 100644
index 00000000..0d80779f
--- /dev/null
+++ b/sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/teavm/InputEvent.java
@@ -0,0 +1,29 @@
+package net.lax1dude.eaglercraft.v1_8.internal.teavm;
+
+import org.teavm.jso.JSProperty;
+import org.teavm.jso.dom.events.Event;
+
+/**
+ * Copyright (c) 2024 lax1dude. All Rights Reserved.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ * 
+ */
+public interface InputEvent extends Event {
+
+	@JSProperty
+	String getData();
+
+	@JSProperty
+	String getInputType();
+
+}
diff --git a/sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/teavm/JOrbisAudioBufferDecoder.java b/sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/teavm/JOrbisAudioBufferDecoder.java
new file mode 100644
index 00000000..c0558335
--- /dev/null
+++ b/sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/teavm/JOrbisAudioBufferDecoder.java
@@ -0,0 +1,420 @@
+package net.lax1dude.eaglercraft.v1_8.internal.teavm;
+
+import java.io.IOException;
+import java.util.LinkedList;
+import java.util.List;
+
+import org.teavm.jso.webaudio.AudioBuffer;
+import org.teavm.jso.webaudio.AudioContext;
+
+import com.jcraft.jogg.Packet;
+import com.jcraft.jogg.Page;
+import com.jcraft.jogg.StreamState;
+import com.jcraft.jogg.SyncState;
+import com.jcraft.jorbis.Block;
+import com.jcraft.jorbis.Comment;
+import com.jcraft.jorbis.DspState;
+import com.jcraft.jorbis.Info;
+
+import net.lax1dude.eaglercraft.v1_8.EaglerInputStream;
+import net.lax1dude.eaglercraft.v1_8.internal.PlatformAudio;
+import net.lax1dude.eaglercraft.v1_8.internal.PlatformRuntime;
+import net.lax1dude.eaglercraft.v1_8.internal.buffer.ByteBuffer;
+import net.lax1dude.eaglercraft.v1_8.internal.buffer.EaglerArrayBufferAllocator;
+import net.lax1dude.eaglercraft.v1_8.log4j.LogManager;
+import net.lax1dude.eaglercraft.v1_8.log4j.Logger;
+
+/**
+ * Copyright (c) 2024 lax1dude. All Rights Reserved.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ * 
+ */
+public class JOrbisAudioBufferDecoder {
+
+	private EaglerInputStream inputStream;
+	private boolean endOfStream = false;
+	private byte[] buffer = null;
+	private int bufferSize;
+	private int count = 0;
+	private int index = 0;
+	private float[][] convertedBuffer = null;
+	private float[][][] pcmInfo;
+	private int[] pcmIndex;
+	private Packet joggPacket = new Packet();
+	private Page joggPage = new Page();
+	private StreamState joggStreamState = new StreamState();
+	private SyncState joggSyncState = new SyncState();
+	private DspState jorbisDspState = new DspState();
+	private Block jorbisBlock;
+	private Comment jorbisComment;
+	private Info jorbisInfo;
+	private String errorString;
+
+	private static final Logger logger = LogManager.getLogger("JOrbisAudioBufferDecoder");
+
+	private static final JOrbisAudioBufferDecoder instance = new JOrbisAudioBufferDecoder();
+
+	public static final int LOAD_VIA_AUDIOBUFFER = 0;
+	public static final int LOAD_VIA_WAV32F = 1;
+	public static final int LOAD_VIA_WAV16 = 2;
+
+	public static AudioBuffer decodeAudioJOrbis(AudioContext ctx, byte[] data, String errorString, int loadVia) {
+		JOrbisAudioBufferDecoder dec = instance;
+		synchronized(dec) {
+			if(!dec.init(data, errorString)) {
+				logger.error("[{}]: Invalid header detected", errorString);
+				return null;
+			}
+			int ch = -1;
+			int len = 0;
+			List<float[][]> lst = new LinkedList<>();
+			float[][] b;
+			while((b = dec.readBytes()) != null) {
+				if(ch == -1) {
+					ch = b.length;
+				}
+				len += b[0].length;
+				lst.add(b);
+			}
+			if(dec.jorbisInfo.channels != ch) {
+				logger.warn("[{}]: Number of channels in header does not match the stream", errorString);
+			}
+			if(ch == -1 || len == 0) {
+				logger.warn("[{}]: Empty file", errorString);
+				return ctx.createBuffer(ch, 0, dec.jorbisInfo.rate);
+			}
+			switch(loadVia) {
+			case LOAD_VIA_AUDIOBUFFER: {
+				AudioBuffer buffer = ctx.createBuffer(ch, len, dec.jorbisInfo.rate);
+				int len2 = 0;
+				for(float[][] fl : lst) {
+					for(int i = 0; i < ch; ++i) {
+						buffer.copyToChannel(TeaVMUtils.unwrapFloatArray(fl[i]), i, len2);
+					}
+					len2 += fl[0].length;
+				}
+				return buffer;
+			}
+			case LOAD_VIA_WAV32F: {
+				int len2 = PCMToWAVLoader.getWAVLen(lst, true);
+				if(len2 == 0 || len2 == 44) {
+					logger.error("[{}]: Invalid length for WAV calculated", errorString);
+					return null;
+				}
+				ByteBuffer buf = PlatformRuntime.allocateByteBuffer(len2);
+				try {
+					PCMToWAVLoader.createWAV32F(lst, ch, dec.jorbisInfo.rate, buf);
+					buf.flip();
+					return PlatformAudio.decodeAudioBrowserAsync(
+							EaglerArrayBufferAllocator.getDataView8(buf).getBuffer(), errorString + ".wav");
+				}finally {
+					PlatformRuntime.freeByteBuffer(buf);
+				}
+			}
+			case LOAD_VIA_WAV16: {
+				int len2 = PCMToWAVLoader.getWAVLen(lst, false);
+				if(len2 == 0 || len2 == 44) {
+					logger.error("[{}]: Invalid length for WAV calculated", errorString);
+					return null;
+				}
+				ByteBuffer buf = PlatformRuntime.allocateByteBuffer(len2);
+				try {
+					PCMToWAVLoader.createWAV16(lst, ch, dec.jorbisInfo.rate, buf);
+					buf.flip();
+					return PlatformAudio.decodeAudioBrowserAsync(
+							EaglerArrayBufferAllocator.getDataView8(buf).getBuffer(), errorString + ".wav");
+				}finally {
+					PlatformRuntime.freeByteBuffer(buf);
+				}
+			}
+			default:
+				throw new IllegalArgumentException();
+			}
+		}
+	}
+
+	private JOrbisAudioBufferDecoder() {
+		this.jorbisBlock = new Block(this.jorbisDspState);
+		this.jorbisComment = new Comment();
+		this.jorbisInfo = new Info();
+	}
+
+	private boolean init(byte[] data, String errorString) {
+		this.inputStream = new EaglerInputStream(data);
+		this.errorString = errorString;
+
+		if (this.joggStreamState != null) {
+			this.joggStreamState.clear();
+		}
+
+		if (this.jorbisBlock != null) {
+			this.jorbisBlock.clear();
+		}
+
+		if (this.jorbisDspState != null) {
+			this.jorbisDspState.clear();
+		}
+
+		if (this.jorbisInfo != null) {
+			this.jorbisInfo.clear();
+		}
+
+		if (this.joggSyncState != null) {
+			this.joggSyncState.clear();
+		}
+
+		if (this.inputStream != null) {
+			try {
+				this.inputStream.close();
+			} catch (IOException var7) {
+			}
+		}
+
+		this.bufferSize = 8192;
+		this.buffer = null;
+		this.count = 0;
+		this.index = 0;
+		this.joggStreamState = new StreamState();
+		this.jorbisBlock = new Block(this.jorbisDspState);
+		this.jorbisDspState = new DspState();
+		this.jorbisInfo = new Info();
+		this.joggSyncState = new SyncState();
+		
+		this.endOfStream = false;
+		this.joggSyncState.init();
+		this.joggSyncState.buffer(this.bufferSize);
+		this.buffer = this.joggSyncState.data;
+		
+		vigg: {
+			this.index = this.joggSyncState.buffer(this.bufferSize);
+			int bytes = this.inputStream.read(this.joggSyncState.data, this.index, this.bufferSize);
+			if (bytes < 0) {
+				bytes = 0;
+			}
+	
+			this.joggSyncState.wrote(bytes);
+			if (this.joggSyncState.pageout(this.joggPage) != 1) {
+				if (bytes < this.bufferSize) {
+					break vigg;
+				} else {
+					logger.error("[{}]: Ogg header not recognized in method 'readHeader'.", errorString);
+					return false;
+				}
+			} else {
+				this.joggStreamState.init(this.joggPage.serialno());
+				this.jorbisInfo.init();
+				this.jorbisComment.init();
+				if (this.joggStreamState.pagein(this.joggPage) < 0) {
+					logger.error("[{}]: Problem with first Ogg header page in method 'readHeader'.", errorString);
+					return false;
+				} else if (this.joggStreamState.packetout(this.joggPacket) != 1) {
+					logger.error("[{}]: Problem with first Ogg header packet in method 'readHeader'.", errorString);
+					return false;
+				} else if (this.jorbisInfo.synthesis_headerin(this.jorbisComment, this.joggPacket) < 0) {
+					logger.error("[{}]: File does not contain Vorbis header in method 'readHeader'.", errorString);
+					return false;
+				} else {
+					int i = 0;
+	
+					while (i < 2) {
+						label73: while (true) {
+							int result;
+							do {
+								if (i >= 2) {
+									break label73;
+								}
+	
+								result = this.joggSyncState.pageout(this.joggPage);
+								if (result == 0) {
+									break label73;
+								}
+							} while (result != 1);
+	
+							this.joggStreamState.pagein(this.joggPage);
+	
+							while (i < 2) {
+								result = this.joggStreamState.packetout(this.joggPacket);
+								if (result == 0) {
+									break;
+								}
+	
+								if (result == -1) {
+									logger.error("[{}]: Secondary Ogg header corrupt in method 'readHeader'.", errorString);
+									return false;
+								}
+	
+								this.jorbisInfo.synthesis_headerin(this.jorbisComment, this.joggPacket);
+								++i;
+							}
+						}
+	
+						this.index = this.joggSyncState.buffer(this.bufferSize);
+						bytes = this.inputStream.read(this.joggSyncState.data, this.index, this.bufferSize);
+						if (bytes < 0) {
+							bytes = 0;
+						}
+	
+						if (bytes == 0 && i < 2) {
+							logger.error(
+									"[{}]: End of file reached before finished reading Ogg header in method 'readHeader'",
+									errorString);
+							return false;
+						}
+	
+						this.joggSyncState.wrote(bytes);
+					}
+	
+					this.index = this.joggSyncState.buffer(this.bufferSize);
+					this.buffer = this.joggSyncState.data;
+				}
+			}
+		}
+
+		this.jorbisDspState.synthesis_init(this.jorbisInfo);
+		this.jorbisBlock.init(this.jorbisDspState);
+		int channels = this.jorbisInfo.channels;
+		int rate = this.jorbisInfo.rate;
+		this.pcmInfo = new float[1][][];
+		this.pcmIndex = new int[channels];
+		if(convertedBuffer == null || convertedBuffer.length != this.jorbisInfo.channels || (convertedBuffer.length > 0 && convertedBuffer[0].length != this.bufferSize)) {
+			this.convertedBuffer = new float[this.jorbisInfo.channels][this.bufferSize];
+		}
+		
+		return true;
+	}
+
+	private float[][] readBytes() {
+		if (this.endOfStream) {
+			return null;
+		} else {
+			float[][] returnBuffer = null;
+			switch (this.joggSyncState.pageout(this.joggPage)) {
+			default:
+				this.joggStreamState.pagein(this.joggPage);
+				if (this.joggPage.granulepos() == 0L) {
+					this.endOfStream = true;
+					return null;
+				} else {
+					label99: {
+						while (true) {
+							switch (this.joggStreamState.packetout(this.joggPacket)) {
+							case -1:
+								break;
+							case 0:
+								if (this.joggPage.eos() != 0) {
+									this.endOfStream = true;
+								}
+								break label99;
+							default:
+								if (this.jorbisBlock.synthesis(this.joggPacket) == 0) {
+									this.jorbisDspState.synthesis_blockin(this.jorbisBlock);
+								}
+
+								int samples;
+								while ((samples = this.jorbisDspState.synthesis_pcmout(this.pcmInfo,
+										this.pcmIndex)) > 0) {
+									float[][] pcmf = this.pcmInfo[0];
+									int bout = samples < bufferSize ? samples : this.bufferSize;
+
+									for (int i = 0; i < this.jorbisInfo.channels; ++i) {
+										float[] f1 = convertedBuffer[i];
+										float[] f2 = pcmf[i];
+										int mono = this.pcmIndex[i];
+										for (int j = 0; j < bout; ++j) {
+											f1[j] = f2[mono + j];
+										}
+									}
+
+									this.jorbisDspState.synthesis_read(bout);
+									returnBuffer = appendFloatArrays(returnBuffer, this.convertedBuffer, bout);
+								}
+							}
+						}
+					}
+				}
+			case -1:
+			case 0:
+				if (!this.endOfStream) {
+					this.index = this.joggSyncState.buffer(this.bufferSize);
+					this.buffer = this.joggSyncState.data;
+
+					try {
+						this.count = this.inputStream.read(this.buffer, this.index, this.bufferSize);
+					} catch (Exception var11) {
+						return null;
+					}
+
+					if (this.count == -1) {
+						return returnBuffer;
+					}
+
+					this.joggSyncState.wrote(this.count);
+					if (this.count == 0) {
+						this.endOfStream = true;
+					}
+				}
+
+				return returnBuffer;
+			}
+		}
+	}
+
+	private static float[][] appendFloatArrays(float[][] arrayOne, float[][] arrayTwo, int arrayTwoBytes) {
+		int bytes = arrayTwoBytes;
+		int l;
+		if (arrayTwo != null && (l = arrayTwo[0].length) != 0) {
+			if (l < arrayTwoBytes) {
+				bytes = l;
+			}
+		} else {
+			bytes = 0;
+		}
+
+		if ((arrayOne != null || arrayTwo != null) && bytes > 0) {
+			float[][] newArray;
+			
+			if (arrayOne == null) {
+				int ch = arrayTwo.length;
+				int len1 = arrayTwo[0].length;
+				newArray = new float[ch][bytes];
+				for(int i = 0; i < ch; ++i) {
+					System.arraycopy(arrayTwo[i], 0, newArray[i], 0, bytes);
+				}
+				arrayTwo = null;
+			} else {
+				int ch = arrayOne.length;
+				int len1 = arrayOne[0].length;
+				if (arrayTwo != null && bytes > 0) {
+					newArray = new float[ch][len1 + bytes];
+					for(int i = 0; i < ch; ++i) {
+						System.arraycopy(arrayOne[i], 0, newArray[i], 0, len1);
+						System.arraycopy(arrayTwo[i], 0, newArray[i], len1, bytes);
+					}
+					arrayOne = null;
+					arrayTwo = null;
+				} else {
+					newArray = new float[ch][len1];
+					for(int i = 0; i < ch; ++i) {
+						System.arraycopy(arrayOne[i], 0, newArray[i], 0, len1);
+					}
+					arrayOne = null;
+				}
+			}
+
+			return newArray;
+		} else {
+			return null;
+		}
+	}
+
+}
diff --git a/sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/teavm/LegacyKeycodeTranslator.java b/sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/teavm/LegacyKeycodeTranslator.java
new file mode 100644
index 00000000..a231d9a6
--- /dev/null
+++ b/sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/teavm/LegacyKeycodeTranslator.java
@@ -0,0 +1,328 @@
+package net.lax1dude.eaglercraft.v1_8.internal.teavm;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+
+import com.google.common.collect.Sets;
+
+/**
+ * Copyright (c) 2024 lax1dude. All Rights Reserved.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ * 
+ */
+public class LegacyKeycodeTranslator {
+
+	public static class LegacyKeycode {
+
+		public final int keyCode;
+		public final int location;
+
+		private LegacyKeycode(int keyCode, int location) {
+			this.keyCode = keyCode;
+			this.location = location;
+		}
+
+		@Override
+		public boolean equals(Object obj) {
+			if (this == obj)
+				return true;
+			if (obj == null)
+				return false;
+			if (!(obj instanceof LegacyKeycode))
+				return false;
+			LegacyKeycode other = (LegacyKeycode) obj;
+			if (keyCode != other.keyCode)
+				return false;
+			if (location != other.location)
+				return false;
+			return true;
+		}
+
+	}
+
+	private static final Set<String> numpadVolatile = Sets.newHashSet(
+			"Comma", "Minus", "Period", "Slash", "Equal", "Enter", "Digit0", "Digit1", "Digit2", "Digit3",
+			"Digit4", "Digit5", "Digit6", "Digit7", "Digit8", "Digit9", "IntlYen");
+
+	private final Map<String,LegacyKeycode> codeLookupBase = new HashMap<>();
+	private final Map<String,LegacyKeycode> codeLookupLayout = new HashMap<>();
+
+	public LegacyKeycodeTranslator() {
+		codeLookupBase.put("Digit0", new LegacyKeycode(0x30, 0));
+		codeLookupBase.put("Digit1", new LegacyKeycode(0x31, 0));
+		codeLookupBase.put("Digit2", new LegacyKeycode(0x32, 0));
+		codeLookupBase.put("Digit3", new LegacyKeycode(0x33, 0));
+		codeLookupBase.put("Digit4", new LegacyKeycode(0x34, 0));
+		codeLookupBase.put("Digit5", new LegacyKeycode(0x35, 0));
+		codeLookupBase.put("Digit6", new LegacyKeycode(0x36, 0));
+		codeLookupBase.put("Digit7", new LegacyKeycode(0x37, 0));
+		codeLookupBase.put("Digit8", new LegacyKeycode(0x38, 0));
+		codeLookupBase.put("Digit9", new LegacyKeycode(0x39, 0));
+		codeLookupBase.put("KeyA", new LegacyKeycode(0x41, 0));
+		codeLookupBase.put("KeyB", new LegacyKeycode(0x42, 0));
+		codeLookupBase.put("KeyC", new LegacyKeycode(0x43, 0));
+		codeLookupBase.put("KeyD", new LegacyKeycode(0x44, 0));
+		codeLookupBase.put("KeyE", new LegacyKeycode(0x45, 0));
+		codeLookupBase.put("KeyF", new LegacyKeycode(0x46, 0));
+		codeLookupBase.put("KeyG", new LegacyKeycode(0x47, 0));
+		codeLookupBase.put("KeyH", new LegacyKeycode(0x48, 0));
+		codeLookupBase.put("KeyI", new LegacyKeycode(0x49, 0));
+		codeLookupBase.put("KeyJ", new LegacyKeycode(0x4A, 0));
+		codeLookupBase.put("KeyK", new LegacyKeycode(0x4B, 0));
+		codeLookupBase.put("KeyL", new LegacyKeycode(0x4C, 0));
+		codeLookupBase.put("KeyM", new LegacyKeycode(0x4D, 0));
+		codeLookupBase.put("KeyN", new LegacyKeycode(0x4E, 0));
+		codeLookupBase.put("KeyO", new LegacyKeycode(0x4F, 0));
+		codeLookupBase.put("KeyP", new LegacyKeycode(0x50, 0));
+		codeLookupBase.put("KeyQ", new LegacyKeycode(0x51, 0));
+		codeLookupBase.put("KeyR", new LegacyKeycode(0x52, 0));
+		codeLookupBase.put("KeyS", new LegacyKeycode(0x53, 0));
+		codeLookupBase.put("KeyT", new LegacyKeycode(0x54, 0));
+		codeLookupBase.put("KeyU", new LegacyKeycode(0x55, 0));
+		codeLookupBase.put("KeyV", new LegacyKeycode(0x56, 0));
+		codeLookupBase.put("KeyW", new LegacyKeycode(0x57, 0));
+		codeLookupBase.put("KeyX", new LegacyKeycode(0x58, 0));
+		codeLookupBase.put("KeyY", new LegacyKeycode(0x59, 0));
+		codeLookupBase.put("KeyZ", new LegacyKeycode(0x5A, 0));
+		codeLookupBase.put("Comma", new LegacyKeycode(0xBC, 0));
+		codeLookupBase.put("Period", new LegacyKeycode(0xBE, 0));
+		codeLookupBase.put("Semicolon", new LegacyKeycode(0xBA, 0));
+		codeLookupBase.put("Quote", new LegacyKeycode(0xDE, 0));
+		codeLookupBase.put("BracketLeft", new LegacyKeycode(0xDB, 0));
+		codeLookupBase.put("BracketRight", new LegacyKeycode(0xDD, 0));
+		codeLookupBase.put("Backquote", new LegacyKeycode(0xC0, 0));
+		codeLookupBase.put("Backslash", new LegacyKeycode(0xDC, 0));
+		codeLookupBase.put("IntlBackslash", new LegacyKeycode(0xDC, 0));
+		codeLookupBase.put("Minus", new LegacyKeycode(0xBD, 0));
+		codeLookupBase.put("Equal", new LegacyKeycode(0xBB, 0));
+		codeLookupBase.put("Slash", new LegacyKeycode(0xBF, 0));
+		codeLookupBase.put("IntlRo", new LegacyKeycode(0xC1, 0));
+		codeLookupBase.put("IntlYen", new LegacyKeycode(0xFF, 0));
+		codeLookupBase.put("AltLeft", new LegacyKeycode(0x12, 1));
+		codeLookupBase.put("AltRight", new LegacyKeycode(0x12, 2));
+		codeLookupBase.put("CapsLock", new LegacyKeycode(0x14, 0));
+		codeLookupBase.put("ControlLeft", new LegacyKeycode(0x11, 1));
+		codeLookupBase.put("ControlRight", new LegacyKeycode(0x11, 2));
+		codeLookupBase.put("MetaLeft", new LegacyKeycode(0x5B, 1));
+		codeLookupBase.put("MetaRight", new LegacyKeycode(0x5C, 2));
+		codeLookupBase.put("ShiftLeft", new LegacyKeycode(0x10, 1));
+		codeLookupBase.put("ShiftRight", new LegacyKeycode(0x10, 2));
+		codeLookupBase.put("ContextMenu", new LegacyKeycode(0x5D, 0));
+		codeLookupBase.put("Enter", new LegacyKeycode(0x0D, 0));
+		codeLookupBase.put("Space", new LegacyKeycode(0x20, 0));
+		codeLookupBase.put("Backspace", new LegacyKeycode(0x08, 0));
+		codeLookupBase.put("Tab", new LegacyKeycode(0x09, 0));
+		codeLookupBase.put("Delete", new LegacyKeycode(0x2E, 0));
+		codeLookupBase.put("End", new LegacyKeycode(0x23, 0));
+		codeLookupBase.put("Help", new LegacyKeycode(0x2D, 0));
+		codeLookupBase.put("Home", new LegacyKeycode(0x24, 0));
+		codeLookupBase.put("Insert", new LegacyKeycode(0x2D, 0));
+		codeLookupBase.put("PageDown", new LegacyKeycode(0x22, 0));
+		codeLookupBase.put("PageUp", new LegacyKeycode(0x21, 0));
+		codeLookupBase.put("ArrowDown", new LegacyKeycode(0x28, 0));
+		codeLookupBase.put("ArrowLeft", new LegacyKeycode(0x25, 0));
+		codeLookupBase.put("ArrowRight", new LegacyKeycode(0x27, 0));
+		codeLookupBase.put("ArrowUp", new LegacyKeycode(0x26, 0));
+		codeLookupBase.put("Escape", new LegacyKeycode(0x1B, 0));
+		codeLookupBase.put("PrintScreen", new LegacyKeycode(0x2C, 0));
+		codeLookupBase.put("ScrollLock", new LegacyKeycode(0x91, 0));
+		codeLookupBase.put("Pause", new LegacyKeycode(0x13, 0));
+		codeLookupBase.put("F1", new LegacyKeycode(0x70, 0));
+		codeLookupBase.put("F2", new LegacyKeycode(0x71, 0));
+		codeLookupBase.put("F3", new LegacyKeycode(0x72, 0));
+		codeLookupBase.put("F4", new LegacyKeycode(0x73, 0));
+		codeLookupBase.put("F5", new LegacyKeycode(0x74, 0));
+		codeLookupBase.put("F6", new LegacyKeycode(0x75, 0));
+		codeLookupBase.put("F7", new LegacyKeycode(0x76, 0));
+		codeLookupBase.put("F8", new LegacyKeycode(0x77, 0));
+		codeLookupBase.put("F9", new LegacyKeycode(0x78, 0));
+		codeLookupBase.put("F10", new LegacyKeycode(0x79, 0));
+		codeLookupBase.put("F11", new LegacyKeycode(0x7A, 0));
+		codeLookupBase.put("F12", new LegacyKeycode(0x7B, 0));
+		codeLookupBase.put("F13", new LegacyKeycode(0x7C, 0));
+		codeLookupBase.put("F14", new LegacyKeycode(0x7D, 0));
+		codeLookupBase.put("F15", new LegacyKeycode(0x7E, 0));
+		codeLookupBase.put("F16", new LegacyKeycode(0x7F, 0));
+		codeLookupBase.put("F17", new LegacyKeycode(0x80, 0));
+		codeLookupBase.put("F18", new LegacyKeycode(0x81, 0));
+		codeLookupBase.put("F19", new LegacyKeycode(0x82, 0));
+		codeLookupBase.put("F20", new LegacyKeycode(0x83, 0));
+		codeLookupBase.put("F21", new LegacyKeycode(0x84, 0));
+		codeLookupBase.put("F22", new LegacyKeycode(0x85, 0));
+		codeLookupBase.put("F23", new LegacyKeycode(0x86, 0));
+		codeLookupBase.put("F24", new LegacyKeycode(0x87, 0));
+		codeLookupBase.put("NumLock", new LegacyKeycode(0x90, 3));
+		codeLookupBase.put("Numpad0", new LegacyKeycode(0x60, 3));
+		codeLookupBase.put("Numpad1", new LegacyKeycode(0x61, 3));
+		codeLookupBase.put("Numpad2", new LegacyKeycode(0x62, 3));
+		codeLookupBase.put("Numpad3", new LegacyKeycode(0x63, 3));
+		codeLookupBase.put("Numpad4", new LegacyKeycode(0x64, 3));
+		codeLookupBase.put("Numpad5", new LegacyKeycode(0x65, 3));
+		codeLookupBase.put("Numpad6", new LegacyKeycode(0x66, 3));
+		codeLookupBase.put("Numpad7", new LegacyKeycode(0x67, 3));
+		codeLookupBase.put("Numpad8", new LegacyKeycode(0x68, 3));
+		codeLookupBase.put("Numpad9", new LegacyKeycode(0x69, 3));
+		codeLookupBase.put("NumpadAdd", new LegacyKeycode(0x6B, 3));
+		codeLookupBase.put("NumpadComma", new LegacyKeycode(0xC2, 3));
+		codeLookupBase.put("NumpadDecimal", new LegacyKeycode(0x6E, 3));
+		codeLookupBase.put("NumpadDivide", new LegacyKeycode(0x6F, 3));
+		codeLookupBase.put("NumpadEnter", new LegacyKeycode(0x0D, 3));
+		codeLookupBase.put("NumpadEqual", new LegacyKeycode(0x0C, 3));
+		codeLookupBase.put("NumpadMultiply", new LegacyKeycode(0x6A, 3));
+		codeLookupBase.put("NumpadSubtract", new LegacyKeycode(0x6D, 3));
+	}
+
+	public LegacyKeycodeTranslator addBrowserLayoutMapping(String keyChar, String codeStr) {
+		LegacyKeycode mapTo = codeLookupBase.get(codeStr);
+		if(mapTo != null) {
+			String keyCode = getCodeFromLayoutChar(keyChar);
+			if(keyCode != null && !keyCode.equals(codeStr) && !(codeStr.startsWith("Numpad") && numpadVolatile.contains(keyCode)) && !mapTo.equals(codeLookupBase.get(keyCode))) {
+				codeLookupLayout.put(keyCode, mapTo);
+			}
+		}
+		return this;
+	}
+
+	public int getRemappedKeyCount() {
+		return codeLookupLayout.size();
+	}
+
+	public Map<String,LegacyKeycode> buildLayoutTable() {
+		if(codeLookupLayout.isEmpty()) {
+			return codeLookupBase;
+		}
+		Map<String,LegacyKeycode> ret = new HashMap<>();
+		ret.putAll(codeLookupBase);
+		ret.putAll(codeLookupLayout);
+		return ret;
+	}
+
+	public static String getCodeFromLayoutChar(String keyChar) {
+		if(keyChar.length() != 1) {
+			return null;
+		}
+		char c = keyChar.charAt(0);
+		String ret = getCodeFromLayoutChar0(c);
+		if(ret == null) {
+			ret = getCodeFromLayoutChar0(Character.toLowerCase(c));
+		}
+		return ret;
+	}
+
+	private static String getCodeFromLayoutChar0(char keyChar) {
+		switch(keyChar) {
+		case 'e':
+			return "KeyE";
+		case 'd':
+			return "KeyD";
+		case 'u':
+			return "KeyU";
+		case '-':
+			return "Minus";
+		case 'h':
+			return "KeyH";
+		case 'z':
+			return "KeyZ";
+		case '=':
+			return "Equal";
+		case 'p':
+			return "KeyP";
+		case ';':
+			return "Semicolon";
+		case ']':
+			return "BracketRight";
+		case '/':
+			return "Slash";
+		case '[':
+			return "BracketLeft";
+		case 'l':
+			return "KeyL";
+		case '8':
+			return "Digit8";
+		case 'w':
+			return "KeyW";
+		case 's':
+			return "KeyS";
+		case '5':
+			return "Digit5";
+		case '9':
+			return "Digit9";
+		case 'o':
+			return "KeyO";
+		case '.':
+			return "Period";
+		case '6':
+			return "Digit6";
+		case 'v':
+			return "KeyV";
+		case '3':
+			return "Digit3";
+		case '`':
+			return "Backquote";
+		case 'g':
+			return "KeyG";
+		case 'j':
+			return "KeyJ";
+		case 'q':
+			return "KeyQ";
+		case '1':
+			return "Digit1";
+		case 't':
+			return "KeyT";
+		case 'y':
+			return "KeyY";
+		case '\'':
+			return "Quote";
+		case '\\':
+			return "Backslash";
+		case 'k':
+			return "KeyK";
+		case 'f':
+			return "KeyF";
+		case 'i':
+			return "KeyI";
+		case 'r':
+			return "KeyR";
+		case 'x':
+			return "KeyX";
+		case 'a':
+			return "KeyA";
+		case '2':
+			return "Digit2";
+		case '7':
+			return "Digit7";
+		case 'm':
+			return "KeyM";
+		case '4':
+			return "Digit4";
+		case '0':
+			return "Digit0";
+		case 'n':
+			return "KeyN";
+		case 'b':
+			return "KeyB";
+		case 'c':
+			return "KeyC";
+		case ',':
+			return "Comma";
+		case '*':
+			return "NumpadMultiply";
+		case 0xA5:
+			return "IntlYen";
+		default:
+			return null;
+		}
+	}
+
+}
diff --git a/sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/teavm/MessageChannel.java b/sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/teavm/MessageChannel.java
new file mode 100644
index 00000000..2adeed4d
--- /dev/null
+++ b/sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/teavm/MessageChannel.java
@@ -0,0 +1,37 @@
+package net.lax1dude.eaglercraft.v1_8.internal.teavm;
+
+import org.teavm.jso.JSBody;
+import org.teavm.jso.JSObject;
+import org.teavm.jso.JSProperty;
+import org.teavm.jso.workers.MessagePort;
+
+/**
+ * Copyright (c) 2024 lax1dude. All Rights Reserved.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ * 
+ */
+public abstract class MessageChannel implements JSObject {
+
+	@JSBody(params = { }, script = "return (typeof MessageChannel !== \"undefined\");")
+	public static native boolean supported();
+
+	@JSBody(params = { }, script = "return new MessageChannel();")
+	public static native MessageChannel create();
+
+	@JSProperty
+	public abstract MessagePort getPort1();
+
+	@JSProperty
+	public abstract MessagePort getPort2();
+
+}
diff --git a/sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/teavm/OffsetTouch.java b/sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/teavm/OffsetTouch.java
new file mode 100644
index 00000000..511c2f1f
--- /dev/null
+++ b/sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/teavm/OffsetTouch.java
@@ -0,0 +1,43 @@
+package net.lax1dude.eaglercraft.v1_8.internal.teavm;
+
+import net.lax1dude.eaglercraft.v1_8.internal.PlatformInput;
+import net.lax1dude.eaglercraft.v1_8.internal.teavm.SortedTouchEvent.ITouchUIDMapper;
+
+/**
+ * Copyright (c) 2024 lax1dude. All Rights Reserved.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ * 
+ */
+public class OffsetTouch {
+
+	public final Touch touch;
+	public final int eventUID;
+	public final int posX;
+	public final int posY;
+
+	public OffsetTouch(Touch touch, int eventUID, int posX, int posY) {
+		this.touch = touch;
+		this.eventUID = eventUID;
+		this.posX = posX;
+		this.posY = posY;
+	}
+
+	public static OffsetTouch create(Touch touch, ITouchUIDMapper mapper, int originX, int originY) {
+		double contentScale = PlatformInput.getDPI();
+		OffsetTouch ot = new OffsetTouch(touch, mapper.call(touch.getIdentifier()),
+				(int) ((touch.getPageX() - originX) * contentScale),
+				PlatformInput.getWindowHeight() - (int) ((touch.getPageY() - originY) * contentScale) - 1);
+		return ot;
+	}
+
+}
diff --git a/sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/teavm/PCMToWAVLoader.java b/sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/teavm/PCMToWAVLoader.java
new file mode 100644
index 00000000..7f12dd29
--- /dev/null
+++ b/sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/teavm/PCMToWAVLoader.java
@@ -0,0 +1,118 @@
+package net.lax1dude.eaglercraft.v1_8.internal.teavm;
+
+import java.util.List;
+
+import net.lax1dude.eaglercraft.v1_8.internal.buffer.ByteBuffer;
+
+/**
+ * Copyright (c) 2024 lax1dude. All Rights Reserved.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ * 
+ */
+public class PCMToWAVLoader {
+
+	public static int getWAVLen(List<float[][]> data, boolean floating) {
+		int i = 44;
+		int j = floating ? 4 : 2;
+		int k;
+		for(float[][] f : data) {
+			k = f.length;
+			if(k == 0) continue;
+			i += k * f[0].length * j;
+		}
+		return i;
+	}
+
+	public static void createWAV16(List<float[][]> data, int chCount, int sampleRate, ByteBuffer bufferOut) {
+		if(chCount == 0 || data.isEmpty()) return;
+		int finalSize = bufferOut.remaining();
+		
+		// header
+		bufferOut.putInt(0x46464952); // magic
+		bufferOut.putInt(finalSize - 8); // file len
+		bufferOut.putInt(0x45564157); // magic
+		
+		// format chunk
+		bufferOut.putInt(0x20746D66); // magic
+		bufferOut.putInt(16); // format chunk len - 8
+		bufferOut.putShort((short)1); // audio format = int
+		bufferOut.putShort((short)chCount); // channels
+		bufferOut.putInt(sampleRate); // sample rate
+		bufferOut.putInt(sampleRate * chCount * 2); // bytes per second
+		bufferOut.putShort((short)(chCount * 2)); // bytes per sample
+		bufferOut.putShort((short)16); // bits per sample
+		
+		// data chunk
+		bufferOut.putInt(0x61746164); // magic
+		bufferOut.putInt(finalSize - 44);
+
+		for(float[][] f : data) {
+			for(int i = 0, l = f[0].length; i < l; ++i) {
+				for(int c = 0; c < chCount; ++c) {
+					int val = (int)(f[c][i] * 32767.0f);
+					if (val > 32767) {
+						val = 32767;
+					}
+					if (val < -32768) {
+						val = -32768;
+					}
+					if (val < 0) {
+						val |= 32768;
+					}
+					bufferOut.putShort((short)val);
+				}
+			}
+		}
+		
+		if(bufferOut.hasRemaining()) {
+			throw new IllegalStateException("Buffer was the wrong size! " + bufferOut.remaining() + " remaining");
+		}
+	}
+
+	public static void createWAV32F(List<float[][]> data, int chCount, int sampleRate, ByteBuffer bufferOut) {
+		if(chCount == 0 || data.isEmpty()) return;
+		int finalSize = bufferOut.remaining();
+		
+		// header
+		bufferOut.putInt(0x46464952); // magic
+		bufferOut.putInt(finalSize - 8); // file len
+		bufferOut.putInt(0x45564157); // magic
+		
+		// format chunk
+		bufferOut.putInt(0x20746D66); // magic
+		bufferOut.putInt(16); // format chunk len - 8
+		bufferOut.putShort((short)3); // audio format = float
+		bufferOut.putShort((short)chCount); // channels
+		bufferOut.putInt(sampleRate); // sample rate
+		bufferOut.putInt(sampleRate * chCount * 4); // bytes per second
+		bufferOut.putShort((short)(chCount * 4)); // bytes per sample
+		bufferOut.putShort((short)32); // bits per sample
+		
+		// data chunk
+		bufferOut.putInt(0x61746164); // magic
+		bufferOut.putInt(finalSize - 44);
+		
+		for(float[][] f : data) {
+			for(int i = 0, l = f[0].length; i < l; ++i) {
+				for(int c = 0; c < chCount; ++c) {
+					bufferOut.putFloat(f[c][i]);
+				}
+			}
+		}
+		
+		if(bufferOut.hasRemaining()) {
+			throw new IllegalStateException("Buffer was the wrong size! " + finalSize + " " + bufferOut.remaining() + " remaining");
+		}
+	}
+
+}
diff --git a/sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/teavm/SortedTouchEvent.java b/sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/teavm/SortedTouchEvent.java
new file mode 100644
index 00000000..c500fba0
--- /dev/null
+++ b/sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/teavm/SortedTouchEvent.java
@@ -0,0 +1,85 @@
+package net.lax1dude.eaglercraft.v1_8.internal.teavm;
+
+import java.util.List;
+
+import net.lax1dude.eaglercraft.v1_8.internal.EnumTouchEvent;
+import net.lax1dude.eaglercraft.v1_8.internal.PlatformInput;
+
+/**
+ * Copyright (c) 2024 lax1dude. All Rights Reserved.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ * 
+ */
+public class SortedTouchEvent {
+
+	public static interface ITouchUIDMapper {
+		int call(int uidIn);
+	}
+
+	public final TouchEvent event;
+	public final EnumTouchEvent type;
+	private final List<OffsetTouch> targetTouches;
+	private final List<OffsetTouch> changedTouches;
+	private final List<OffsetTouch> eventTouches;
+
+	public SortedTouchEvent(TouchEvent event, ITouchUIDMapper mapper) {
+		changedTouches = TeaVMUtils.toSortedTouchList(event.getChangedTouches(), mapper, PlatformInput.touchOffsetXTeaVM, PlatformInput.touchOffsetYTeaVM);
+		targetTouches = TeaVMUtils.toSortedTouchList(event.getTargetTouches(), mapper, PlatformInput.touchOffsetXTeaVM, PlatformInput.touchOffsetYTeaVM);
+		this.event = event;
+		switch(event.getType()) {
+		case "touchstart":
+			type = EnumTouchEvent.TOUCHSTART;
+			eventTouches = changedTouches;
+			break;
+		case "touchmove":
+			type = EnumTouchEvent.TOUCHMOVE;
+			eventTouches = targetTouches;
+			break;
+		case "touchend":
+		case "touchcancel":
+		default:
+			type = EnumTouchEvent.TOUCHEND;
+			eventTouches = changedTouches;
+			break;
+		}
+	}
+
+	public int getTouchesSize() {
+		return event.getTouches().getLength();
+	}
+
+	public int getChangedTouchesSize() {
+		return event.getChangedTouches().getLength();
+	}
+
+	public List<OffsetTouch> getChangedTouches() {
+		return changedTouches;
+	}
+
+	public int getTargetTouchesSize() {
+		return event.getTargetTouches().getLength();
+	}
+
+	public List<OffsetTouch> getTargetTouches() {
+		return targetTouches;
+	}
+
+	public int getEventTouchesSize() {
+		return eventTouches.size();
+	}
+
+	public List<OffsetTouch> getEventTouches() {
+		return eventTouches;
+	}
+
+}
diff --git a/sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/teavm/TeaVMBlobURLHandle.java b/sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/teavm/TeaVMBlobURLHandle.java
new file mode 100644
index 00000000..902ac418
--- /dev/null
+++ b/sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/teavm/TeaVMBlobURLHandle.java
@@ -0,0 +1,28 @@
+package net.lax1dude.eaglercraft.v1_8.internal.teavm;
+
+/**
+ * Copyright (c) 2024 lax1dude. All Rights Reserved.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ * 
+ */
+public interface TeaVMBlobURLHandle {
+
+	default String toExternalForm() {
+		return TeaVMBlobURLManager.toExternalForm(this);
+	}
+
+	default void release() {
+		TeaVMBlobURLManager.releaseURL(this);
+	}
+
+}
diff --git a/sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/teavm/TeaVMBlobURLManager.java b/sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/teavm/TeaVMBlobURLManager.java
new file mode 100644
index 00000000..a40bd93c
--- /dev/null
+++ b/sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/teavm/TeaVMBlobURLManager.java
@@ -0,0 +1,188 @@
+package net.lax1dude.eaglercraft.v1_8.internal.teavm;
+
+import org.teavm.interop.Async;
+import org.teavm.interop.AsyncCallback;
+import org.teavm.jso.JSBody;
+import org.teavm.jso.JSFunctor;
+import org.teavm.jso.JSObject;
+import org.teavm.jso.typedarrays.ArrayBuffer;
+
+import net.lax1dude.eaglercraft.v1_8.Base64;
+import net.lax1dude.eaglercraft.v1_8.internal.PlatformRuntime;
+import net.lax1dude.eaglercraft.v1_8.log4j.LogManager;
+import net.lax1dude.eaglercraft.v1_8.log4j.Logger;
+
+/**
+ * Copyright (c) 2024 lax1dude. All Rights Reserved.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ * 
+ */
+public class TeaVMBlobURLManager {
+
+	private static final Logger logger = LogManager.getLogger("TeaVMBlobURLManager");
+
+	private static boolean isSameOriginSupport = true;
+
+	public static void initialize() {
+		if(((TeaVMClientConfigAdapter)PlatformRuntime.getClientConfigAdapter()).isDisableBlobURLsTeaVM()) {
+			isSameOriginSupport = false;
+			logger.info("Note: Blob urls have been disabled, client will use data: urls instead");
+		}else {
+			try {
+				isSameOriginSupport = checkSameOriginSupport();
+			}catch(Throwable t) {
+				isSameOriginSupport = false;
+			}
+			if(!isSameOriginSupport) {
+				logger.warn("Warning: Same-origin fetch support detected as false, client will use data: urls instead of blob: urls");
+			}
+		}
+	}
+
+	@Async
+	private static native Boolean checkSameOriginSupport();
+
+	private static void checkSameOriginSupport(final AsyncCallback<Boolean> cb) {
+		try {
+			checkSameOriginSupport0((v) -> cb.complete(v));
+		}catch(Throwable t) {
+			cb.error(t);
+		}
+	}
+
+	@JSFunctor
+	private static interface SameOriginSupportCallback extends JSObject {
+		void call(boolean support);
+	}
+
+	@JSBody(params = { "cb" }, script = "if((typeof URL === \"undefined\") || (typeof URL.createObjectURL !== \"function\")) { cb(false); }"
+			+ "else { var objURL = URL.createObjectURL(new Blob([new Uint8Array([69, 69, 69, 69])]));"
+			+ "if(!objURL) { cb(false); return; }"
+			+ "var eag = function(theObjURL, theXHRObj) {"
+			+ "theXHRObj.responseType = \"arraybuffer\";"
+			+ "theXHRObj.addEventListener(\"load\", function(evt) { try { URL.revokeObjectURL(theObjURL); } catch(exx) { }"
+			+ "var stat = theXHRObj.status;"
+			+ "if(stat === 0 || (stat >= 200 && stat < 400)) {"
+			+ "var typedArr = new Uint8Array(theXHRObj.response);"
+			+ "if(typedArr.length === 4 && typedArr[0] === 69 && typedArr[1] === 69 && typedArr[2] === 69 && typedArr[3] === 69) {"
+			+ "cb(true);"
+			+ "} else { cb(false); } } else { cb(false); } });"
+			+ "theXHRObj.addEventListener(\"error\", function(evt) { try { URL.revokeObjectURL(theObjURL); } catch(exx) { }  cb(false); });"
+			+ "theXHRObj.open(\"GET\", theObjURL, true);"
+			+ "theXHRObj.send();"
+			+ "}; eag(objURL, new XMLHttpRequest()); }")
+	private static native void checkSameOriginSupport0(SameOriginSupportCallback cb);
+
+	private static class HandleRealBlobURL implements TeaVMBlobURLHandle {
+
+		private final String blobURL;
+
+		public HandleRealBlobURL(String blobURL) {
+			this.blobURL = blobURL;
+		}
+
+		@Override
+		public String toExternalForm() {
+			return blobURL;
+		}
+
+		@Override
+		public void release() {
+			revokeBlobURL(blobURL);
+		}
+
+	}
+
+	private static class HandleFakeBlobURL implements TeaVMBlobURLHandle {
+
+		private final byte[] blobData;
+		private final String blobMIME;
+
+		public HandleFakeBlobURL(byte[] blobData, String blobMIME) {
+			this.blobData = blobData;
+			this.blobMIME = blobMIME;
+		}
+
+		@Override
+		public String toExternalForm() {
+			return "data:" + blobMIME + ";base64," + Base64.encodeBase64String(blobData);
+		}
+
+		@Override
+		public void release() {
+			
+		}
+
+	}
+
+	public static TeaVMBlobURLHandle registerNewURLByte(byte[] objectData, String mimeType) {
+		if(isSameOriginSupport) {
+			return new HandleRealBlobURL(createBlobURL(TeaVMUtils.unwrapArrayBuffer(objectData), mimeType));
+		}else {
+			return new HandleFakeBlobURL(objectData, mimeType);
+		}
+	}
+
+	public static TeaVMBlobURLHandle registerNewURLArrayBuffer(ArrayBuffer objectData, String mimeType) {
+		return registerNewURLByte(TeaVMUtils.wrapByteArrayBuffer(objectData), mimeType);
+	}
+
+	public static TeaVMBlobURLHandle registerNewURLBlob(JSObject objectData) {
+		if(isSameOriginSupport) {
+			return new HandleRealBlobURL(createBlobURL(objectData));
+		}else {
+			return new HandleFakeBlobURL(TeaVMUtils.wrapByteArrayBuffer(blobToArrayBuffer(objectData)), getBlobMime(objectData));
+		}
+	}
+
+	@JSBody(params = { "objectData" }, script = "return objectData.type || \"application/octet-stream\";")
+	private static native String getBlobMime(JSObject objectData);
+
+	@Async
+	private static native ArrayBuffer blobToArrayBuffer(JSObject objectData);
+
+	private static void blobToArrayBuffer(JSObject objectData, final AsyncCallback<ArrayBuffer> cb) {
+		blobToArrayBuffer0(objectData, cb::complete);
+	}
+
+	@JSFunctor
+	private static interface ArrayBufferCallback extends JSObject {
+		void call(ArrayBuffer buf);
+	}
+
+	@JSBody(params = { "objectData", "callback" }, script = 
+			"var eag = function(reader){"
+			+ "reader.addEventListener(\"loadend\",function(evt){ callback(reader.result); });"
+			+ "reader.addEventListener(\"error\",function(evt){ callback(null); });"
+			+ "reader.readAsArrayBuffer(objectData);"
+			+ "}; eag(new FileReader());")
+	private static native ArrayBuffer blobToArrayBuffer0(JSObject objectData, ArrayBufferCallback callback);
+
+	@JSBody(params = { "buf", "mime" }, script = "return URL.createObjectURL(new Blob([buf], {type: mime}));")
+	private static native String createBlobURL(ArrayBuffer buf, String mime);
+
+	@JSBody(params = { "objectBlob" }, script = "return URL.createObjectURL(objectBlob);")
+	private static native String createBlobURL(JSObject objectBlob);
+
+	@JSBody(params = { "url" }, script = "URL.revokeObjectURL(url);")
+	private static native void revokeBlobURL(String url);
+
+	public static String toExternalForm(TeaVMBlobURLHandle handle) {
+		return handle.toExternalForm();
+	}
+
+	public static void releaseURL(TeaVMBlobURLHandle handle) {
+		handle.release();
+	}
+
+}
diff --git a/sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/teavm/TeaVMClientConfigAdapter.java b/sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/teavm/TeaVMClientConfigAdapter.java
index cdbe9881..5e488aa5 100644
--- a/sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/teavm/TeaVMClientConfigAdapter.java
+++ b/sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/teavm/TeaVMClientConfigAdapter.java
@@ -6,6 +6,7 @@ import java.util.List;
 import net.lax1dude.eaglercraft.v1_8.EagRuntime;
 import net.lax1dude.eaglercraft.v1_8.EaglercraftVersion;
 import net.lax1dude.eaglercraft.v1_8.ThreadLocalRandom;
+import net.lax1dude.eaglercraft.v1_8.boot_menu.teavm.IBootMenuConfigAdapter;
 import net.lax1dude.eaglercraft.v1_8.sp.relay.RelayManager;
 import org.json.JSONArray;
 import org.json.JSONObject;
@@ -35,13 +36,13 @@ import net.lax1dude.eaglercraft.v1_8.sp.relay.RelayEntry;
  * POSSIBILITY OF SUCH DAMAGE.
  * 
  */
-public class TeaVMClientConfigAdapter implements IClientConfigAdapter {
+public class TeaVMClientConfigAdapter implements IClientConfigAdapter, IBootMenuConfigAdapter {
 
 	public static final IClientConfigAdapter instance = new TeaVMClientConfigAdapter();
 
 	private String defaultLocale = "en_US";
-	private List<DefaultServer> defaultServers = new ArrayList();
-	private List<RelayEntry> relays = new ArrayList();
+	private List<DefaultServer> defaultServers = new ArrayList<>();
+	private List<RelayEntry> relays = new ArrayList<>();
 	private String serverToJoin = null;   
 	private String worldsDB = "worlds";
 	private String resourcePacksDB = "resourcePacks";
@@ -61,7 +62,31 @@ public class TeaVMClientConfigAdapter implements IClientConfigAdapter {
 	private String localStorageNamespace = "_eaglercraftX";
 	private final TeaVMClientConfigAdapterHooks hooks = new TeaVMClientConfigAdapterHooks();
 	private boolean enableMinceraft = true;
+	private boolean enableServerCookies = true;
+	private boolean allowServerRedirects = true;
 	private boolean crashOnUncaughtExceptions = false;
+	private boolean openDebugConsoleOnLaunch = false;
+	private boolean fixDebugConsoleUnloadListener = false;
+	private boolean forceWebViewSupport = false;
+	private boolean enableWebViewCSP = false;
+	private boolean autoFixLegacyStyleAttr = false;
+	private boolean showBootMenuOnLaunch = false;
+	private boolean bootMenuBlocksUnsignedClients = false;
+	private boolean allowBootMenu = true;
+	private boolean forceProfanityFilter = false;
+	private boolean forceWebGL1 = false;
+	private boolean forceWebGL2 = false;
+	private boolean allowExperimentalWebGL1 = false;
+	private boolean useWebGLExt = true;
+	private boolean useDelayOnSwap = false;
+	private boolean useJOrbisAudioDecoder = false;
+	private boolean useXHRFetch = false;
+	private boolean useVisualViewport = true;
+	private boolean deobfStackTraces = true;
+	private boolean disableBlobURLs = false;
+	private boolean eaglerNoDelay = false;
+	private boolean ramdiskMode = false;
+	private boolean singleThreadMode = false;
 
 	public void loadNative(JSObject jsObject) {
 		integratedServerOpts = new JSONObject();
@@ -84,12 +109,36 @@ public class TeaVMClientConfigAdapter implements IClientConfigAdapter {
 		allowFNAWSkins = !demoMode && eaglercraftXOpts.getAllowFNAWSkins(true);
 		localStorageNamespace = eaglercraftXOpts.getLocalStorageNamespace(EaglercraftVersion.localStorageNamespace);
 		enableMinceraft = eaglercraftXOpts.getEnableMinceraft(true);
+		enableServerCookies = !demoMode && eaglercraftXOpts.getEnableServerCookies(true);
+		allowServerRedirects = eaglercraftXOpts.getAllowServerRedirects(true);
 		crashOnUncaughtExceptions = eaglercraftXOpts.getCrashOnUncaughtExceptions(false);
+		openDebugConsoleOnLaunch = eaglercraftXOpts.getOpenDebugConsoleOnLaunch(false);
+		fixDebugConsoleUnloadListener = eaglercraftXOpts.getFixDebugConsoleUnloadListener(false);
+		forceWebViewSupport = eaglercraftXOpts.getForceWebViewSupport(false);
+		enableWebViewCSP = eaglercraftXOpts.getEnableWebViewCSP(true);
+		autoFixLegacyStyleAttr = eaglercraftXOpts.getAutoFixLegacyStyleAttr(true);
+		showBootMenuOnLaunch = eaglercraftXOpts.getShowBootMenuOnLaunch(false);
+		bootMenuBlocksUnsignedClients = eaglercraftXOpts.getBootMenuBlocksUnsignedClients(false);
+		allowBootMenu = eaglercraftXOpts.getAllowBootMenu(!demoMode);
+		forceProfanityFilter = eaglercraftXOpts.getForceProfanityFilter(false);
+		forceWebGL1 = eaglercraftXOpts.getForceWebGL1(false);
+		forceWebGL2 = eaglercraftXOpts.getForceWebGL2(false);
+		allowExperimentalWebGL1 = eaglercraftXOpts.getAllowExperimentalWebGL1(true);
+		useWebGLExt = eaglercraftXOpts.getUseWebGLExt(true);
+		useDelayOnSwap = eaglercraftXOpts.getUseDelayOnSwap(false);
+		useJOrbisAudioDecoder = eaglercraftXOpts.getUseJOrbisAudioDecoder(false);
+		useXHRFetch = eaglercraftXOpts.getUseXHRFetch(false);
+		useVisualViewport = eaglercraftXOpts.getUseVisualViewport(true);
+		deobfStackTraces = eaglercraftXOpts.getDeobfStackTraces(true);
+		disableBlobURLs = eaglercraftXOpts.getDisableBlobURLs(false);
+		eaglerNoDelay = eaglercraftXOpts.getEaglerNoDelay(false);
+		ramdiskMode = eaglercraftXOpts.getRamdiskMode(false);
+		singleThreadMode = eaglercraftXOpts.getSingleThreadMode(false);
 		JSEaglercraftXOptsHooks hooksObj = eaglercraftXOpts.getHooks();
 		if(hooksObj != null) {
 			hooks.loadHooks(hooksObj);
 		}
-
+		
 		integratedServerOpts.put("worldsDB", worldsDB);
 		integratedServerOpts.put("demoMode", demoMode);
 		integratedServerOpts.put("lang", defaultLocale);
@@ -98,19 +147,27 @@ public class TeaVMClientConfigAdapter implements IClientConfigAdapter {
 		integratedServerOpts.put("allowVoiceClient", allowVoiceClient);
 		integratedServerOpts.put("allowFNAWSkins", allowFNAWSkins);
 		integratedServerOpts.put("crashOnUncaughtExceptions", crashOnUncaughtExceptions);
+		integratedServerOpts.put("deobfStackTraces", deobfStackTraces);
+		integratedServerOpts.put("disableBlobURLs", disableBlobURLs);
+		integratedServerOpts.put("eaglerNoDelay", eaglerNoDelay);
+		integratedServerOpts.put("ramdiskMode", ramdiskMode);
+		integratedServerOpts.put("singleThreadMode", singleThreadMode);
 		
+		defaultServers.clear();
 		JSArrayReader<JSEaglercraftXOptsServer> serversArray = eaglercraftXOpts.getServers();
 		if(serversArray != null) {
 			for(int i = 0, l = serversArray.getLength(); i < l; ++i) {
 				JSEaglercraftXOptsServer serverEntry = serversArray.get(i);
+				boolean hideAddr = serverEntry.getHideAddr(false);
 				String serverAddr = serverEntry.getAddr();
 				if(serverAddr != null) {
 					String serverName = serverEntry.getName("Default Server #" + i);
-					defaultServers.add(new DefaultServer(serverName, serverAddr));
+					defaultServers.add(new DefaultServer(serverName, serverAddr, hideAddr));
 				}
 			}
 		}
 		
+		relays.clear();
 		JSArrayReader<JSEaglercraftXOptsRelay> relaysArray = eaglercraftXOpts.getRelays();
 		if(relaysArray != null) {
 			boolean gotAPrimary = false;
@@ -181,19 +238,46 @@ public class TeaVMClientConfigAdapter implements IClientConfigAdapter {
 		allowFNAWSkins = eaglercraftOpts.optBoolean("allowFNAWSkins", true);
 		localStorageNamespace = eaglercraftOpts.optString("localStorageNamespace", EaglercraftVersion.localStorageNamespace);
 		enableMinceraft = eaglercraftOpts.optBoolean("enableMinceraft", true);
+		enableServerCookies = !demoMode && eaglercraftOpts.optBoolean("enableServerCookies", true);
+		allowServerRedirects = eaglercraftOpts.optBoolean("allowServerRedirects", true);
 		crashOnUncaughtExceptions = eaglercraftOpts.optBoolean("crashOnUncaughtExceptions", false);
+		openDebugConsoleOnLaunch = eaglercraftOpts.optBoolean("openDebugConsoleOnLaunch", false);
+		fixDebugConsoleUnloadListener = eaglercraftOpts.optBoolean("fixDebugConsoleUnloadListener", false);
+		forceWebViewSupport = eaglercraftOpts.optBoolean("forceWebViewSupport", false);
+		enableWebViewCSP = eaglercraftOpts.optBoolean("enableWebViewCSP", true);
+		autoFixLegacyStyleAttr = eaglercraftOpts.optBoolean("autoFixLegacyStyleAttr", true);
+		showBootMenuOnLaunch = eaglercraftOpts.optBoolean("showBootMenuOnLaunch", false);
+		bootMenuBlocksUnsignedClients = eaglercraftOpts.optBoolean("bootMenuBlocksUnsignedClients", false);
+		allowBootMenu = eaglercraftOpts.optBoolean("allowBootMenu", !demoMode);
+		forceProfanityFilter = eaglercraftOpts.optBoolean("forceProfanityFilter", false);
+		forceWebGL1 = eaglercraftOpts.optBoolean("forceWebGL1", false);
+		forceWebGL2 = eaglercraftOpts.optBoolean("forceWebGL2", false);
+		allowExperimentalWebGL1 = eaglercraftOpts.optBoolean("allowExperimentalWebGL1", true);
+		useWebGLExt = eaglercraftOpts.optBoolean("useWebGLExt", true);
+		useDelayOnSwap = eaglercraftOpts.optBoolean("useDelayOnSwap", false);
+		useJOrbisAudioDecoder = eaglercraftOpts.optBoolean("useJOrbisAudioDecoder", false);
+		useXHRFetch = eaglercraftOpts.optBoolean("useXHRFetch", false);
+		useVisualViewport = eaglercraftOpts.optBoolean("useVisualViewport", true);
+		deobfStackTraces = eaglercraftOpts.optBoolean("deobfStackTraces", true);
+		disableBlobURLs = eaglercraftOpts.optBoolean("disableBlobURLs", false);
+		eaglerNoDelay = eaglercraftOpts.optBoolean("eaglerNoDelay", false);
+		ramdiskMode = eaglercraftOpts.optBoolean("ramdiskMode", false);
+		singleThreadMode = eaglercraftOpts.optBoolean("singleThreadMode", false);
+		defaultServers.clear();
 		JSONArray serversArray = eaglercraftOpts.optJSONArray("servers");
 		if(serversArray != null) {
 			for(int i = 0, l = serversArray.length(); i < l; ++i) {
 				JSONObject serverEntry = serversArray.getJSONObject(i);
+				boolean hideAddr = serverEntry.optBoolean("hideAddr", false);
 				String serverAddr = serverEntry.optString("addr", null);
 				if(serverAddr != null) {
 					String serverName = serverEntry.optString("name", "Default Server #" + i);
-					defaultServers.add(new DefaultServer(serverName, serverAddr));
+					defaultServers.add(new DefaultServer(serverName, serverAddr, hideAddr));
 				}
 			}
 		}
 
+		relays.clear();
 		JSONArray relaysArray = eaglercraftOpts.optJSONArray("relays");
 		if(relaysArray != null) {
 			boolean gotAPrimary = false;
@@ -344,13 +428,119 @@ public class TeaVMClientConfigAdapter implements IClientConfigAdapter {
 		return enableMinceraft;
 	}
 
+	@Override
+	public boolean isEnableServerCookies() {
+		return enableServerCookies;
+	}
+
+	@Override
+	public boolean isAllowServerRedirects() {
+		return allowServerRedirects;
+	}
+
+	@Override
+	public boolean isOpenDebugConsoleOnLaunch() {
+		return openDebugConsoleOnLaunch;
+	}
+
+	public boolean isFixDebugConsoleUnloadListenerTeaVM() {
+		return fixDebugConsoleUnloadListener;
+	}
+
+	@Override
+	public boolean isForceWebViewSupport() {
+		return forceWebViewSupport;
+	}
+
+	@Override
+	public boolean isEnableWebViewCSP() {
+		return enableWebViewCSP;
+	}
+
+	public boolean isAutoFixLegacyStyleAttrTeaVM() {
+		return autoFixLegacyStyleAttr;
+	}
+
+	public boolean isForceWebGL1TeaVM() {
+		return forceWebGL1;
+	}
+
+	public boolean isForceWebGL2TeaVM() {
+		return forceWebGL2;
+	}
+
+	public boolean isAllowExperimentalWebGL1TeaVM() {
+		return allowExperimentalWebGL1;
+	}
+
+	public boolean isUseWebGLExtTeaVM() {
+		return useWebGLExt;
+	}
+
+	public boolean isUseDelayOnSwapTeaVM() {
+		return useDelayOnSwap;
+	}
+
+	public boolean isUseJOrbisAudioDecoderTeaVM() {
+		return useJOrbisAudioDecoder;
+	}
+
+	public boolean isUseXHRFetchTeaVM() {
+		return useXHRFetch;
+	}
+
+	public boolean isDeobfStackTracesTeaVM() {
+		return deobfStackTraces;
+	}
+
+	public boolean isUseVisualViewportTeaVM() {
+		return useVisualViewport;
+	}
+
+	public boolean isDisableBlobURLsTeaVM() {
+		return disableBlobURLs;
+	}
+
+	public boolean isSingleThreadModeTeaVM() {
+		return singleThreadMode;
+	}
+
+	@Override
+	public boolean isShowBootMenuOnLaunch() {
+		return showBootMenuOnLaunch;
+	}
+
+	@Override
+	public boolean isBootMenuBlocksUnsignedClients() {
+		return bootMenuBlocksUnsignedClients;
+	}
+
+	@Override
+	public boolean isAllowBootMenu() {
+		return allowBootMenu;
+	}
+
+	@Override
+	public boolean isForceProfanityFilter() {
+		return forceProfanityFilter;
+	}
+
+	@Override
+	public boolean isEaglerNoDelay() {
+		return eaglerNoDelay;
+	}
+
+	@Override
+	public boolean isRamdiskMode() {
+		return ramdiskMode;
+	}
+
 	@Override
 	public IClientConfigAdapterHooks getHooks() {
 		return hooks;
 	}
 
-	@Override
-	public String toString() {
+	public JSONObject toJSONObject() {
 		JSONObject jsonObject = new JSONObject();
 		jsonObject.put("lang", defaultLocale);
 		jsonObject.put("joinServer", serverToJoin);
@@ -370,12 +560,37 @@ public class TeaVMClientConfigAdapter implements IClientConfigAdapter {
 		jsonObject.put("allowFNAWSkins", allowFNAWSkins);
 		jsonObject.put("localStorageNamespace", localStorageNamespace);
 		jsonObject.put("enableMinceraft", enableMinceraft);
+		jsonObject.put("enableServerCookies", enableServerCookies);
+		jsonObject.put("allowServerRedirects", allowServerRedirects);
 		jsonObject.put("crashOnUncaughtExceptions", crashOnUncaughtExceptions);
+		jsonObject.put("openDebugConsoleOnLaunch", openDebugConsoleOnLaunch);
+		jsonObject.put("fixDebugConsoleUnloadListener", fixDebugConsoleUnloadListener);
+		jsonObject.put("forceWebViewSupport", forceWebViewSupport);
+		jsonObject.put("enableWebViewCSP", enableWebViewCSP);
+		jsonObject.put("autoFixLegacyStyleAttr", autoFixLegacyStyleAttr);
+		jsonObject.put("showBootMenuOnLaunch", showBootMenuOnLaunch);
+		jsonObject.put("bootMenuBlocksUnsignedClients", bootMenuBlocksUnsignedClients);
+		jsonObject.put("allowBootMenu", allowBootMenu);
+		jsonObject.put("forceProfanityFilter", forceProfanityFilter);
+		jsonObject.put("forceWebGL1", forceWebGL1);
+		jsonObject.put("forceWebGL2", forceWebGL2);
+		jsonObject.put("allowExperimentalWebGL1", allowExperimentalWebGL1);
+		jsonObject.put("useWebGLExt", useWebGLExt);
+		jsonObject.put("useDelayOnSwap", useDelayOnSwap);
+		jsonObject.put("useJOrbisAudioDecoder", useJOrbisAudioDecoder);
+		jsonObject.put("useXHRFetch", useXHRFetch);
+		jsonObject.put("useVisualViewport", useVisualViewport);
+		jsonObject.put("deobfStackTraces", deobfStackTraces);
+		jsonObject.put("disableBlobURLs", disableBlobURLs);
+		jsonObject.put("eaglerNoDelay", eaglerNoDelay);
+		jsonObject.put("ramdiskMode", ramdiskMode);
+		jsonObject.put("singleThreadMode", singleThreadMode);
 		JSONArray serversArr = new JSONArray();
 		for(int i = 0, l = defaultServers.size(); i < l; ++i) {
 			DefaultServer srv = defaultServers.get(i);
 			JSONObject obj = new JSONObject();
 			obj.put("addr", srv.addr);
+			obj.put("hideAddr", srv.hideAddress);
 			obj.put("name", srv.name);
 			serversArr.put(obj);
 		}
@@ -390,6 +605,16 @@ public class TeaVMClientConfigAdapter implements IClientConfigAdapter {
 			relaysArr.put(obj);
 		}
 		jsonObject.put("relays", relaysArr);
-		return jsonObject.toString();
+		return jsonObject;
 	}
+
+	@Override
+	public String toString() {
+		return toJSONObject().toString();
+	}
+
+	public String toStringFormatted() {
+		return toJSONObject().toString(4);
+	}
+
 }
diff --git a/sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/teavm/TeaVMClientConfigAdapterHooks.java b/sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/teavm/TeaVMClientConfigAdapterHooks.java
index 93eb1d8f..3af80ca7 100644
--- a/sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/teavm/TeaVMClientConfigAdapterHooks.java
+++ b/sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/teavm/TeaVMClientConfigAdapterHooks.java
@@ -36,6 +36,7 @@ public class TeaVMClientConfigAdapterHooks implements IClientConfigAdapterHooks
 	private LocalStorageSaveHook saveHook = null;
 	private LocalStorageLoadHook loadHook = null;
 	private CrashReportHook crashHook = null;
+	private ScreenChangeHook screenChangedHook = null;
 
 	@JSFunctor
 	private static interface LocalStorageSaveHook extends JSObject {
@@ -67,6 +68,22 @@ public class TeaVMClientConfigAdapterHooks implements IClientConfigAdapterHooks
 		}
 	}
 
+	@JSFunctor
+	private static interface ScreenChangeHook extends JSObject {
+		String call(String screenName, int scaledWidth, int scaledHeight, int realWidth, int realHeight,
+				int scaleFactor);
+	}
+
+	@Override
+	public void callScreenChangedHook(String screenName, int scaledWidth, int scaledHeight, int realWidth,
+			int realHeight, int scaleFactor) {
+		if(screenChangedHook != null) {
+			callHookSafe("screenChanged", () -> {
+				screenChangedHook.call(screenName, scaledWidth, scaledHeight, realWidth, realHeight, scaleFactor);
+			});
+		}
+	}
+
 	@JSFunctor
 	private static interface CrashReportHook extends JSObject {
 		void call(String crashReport, CustomMessageCB customMessageCB);
@@ -134,5 +151,7 @@ public class TeaVMClientConfigAdapterHooks implements IClientConfigAdapterHooks
 		saveHook = (LocalStorageSaveHook)hooks.getLocalStorageSavedHook();
 		loadHook = (LocalStorageLoadHook)hooks.getLocalStorageLoadedHook();
 		crashHook = (CrashReportHook)hooks.getCrashReportHook();
+		screenChangedHook = (ScreenChangeHook)hooks.getScreenChangedHook();
 	}
+
 }
diff --git a/sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/teavm/TeaVMDataURLManager.java b/sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/teavm/TeaVMDataURLManager.java
new file mode 100644
index 00000000..8446c160
--- /dev/null
+++ b/sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/teavm/TeaVMDataURLManager.java
@@ -0,0 +1,87 @@
+package net.lax1dude.eaglercraft.v1_8.internal.teavm;
+
+import java.nio.charset.StandardCharsets;
+import java.util.Arrays;
+
+import org.teavm.interop.Async;
+import org.teavm.interop.AsyncCallback;
+import org.teavm.jso.browser.Window;
+
+import net.lax1dude.eaglercraft.v1_8.Base64;
+
+/**
+ * Copyright (c) 2024 lax1dude. All Rights Reserved.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ * 
+ */
+public class TeaVMDataURLManager {
+
+	private static void checkDataURLSupport0(boolean fetchBased, final AsyncCallback<Boolean> callback) {
+		final byte[] testData = new byte[1024];
+		for(int i = 0; i < 1024; ++i) {
+			testData[i] = (byte)i;
+		}
+		String testURL = "data:application/octet-stream;base64," + Base64.encodeBase64String(testData);
+		TeaVMFetchJS.FetchHandler cb = (data) -> {
+			if(data != null && TeaVMUtils.isTruthy(data) && data.getByteLength() == 1024) {
+				byte[] bb = TeaVMUtils.wrapByteArrayBuffer(data);
+				callback.complete(Arrays.equals(bb, testData));
+			}else {
+				callback.complete(false);
+			}
+		};
+		try {
+			if(fetchBased) {
+				TeaVMFetchJS.doFetchDownload(testURL, "force-cache", cb);
+			}else {
+				TeaVMFetchJS.doXHRDownload(testURL, cb);
+			}
+		}catch(Throwable t) {
+			callback.complete(false);
+		}
+	}
+
+	@Async
+	private static native Boolean checkDataURLSupport0(boolean fetchBased);
+
+	public static boolean checkDataURLSupport(boolean fetchBased) {
+		Boolean b = null;
+		try {
+			b = checkDataURLSupport0(fetchBased);
+		}catch(Throwable t) {
+		}
+		return b != null && b.booleanValue();
+	}
+
+	public static byte[] decodeDataURLFallback(String dataURL) {
+		if(dataURL.length() < 6 || !dataURL.substring(0, 5).equalsIgnoreCase("data:")) {
+			return null;
+		}
+		int i = dataURL.indexOf(',');
+		if(i == -1 || i >= dataURL.length() - 1) {
+			return null;
+		}
+		String mime = dataURL.substring(0, i).toLowerCase();
+		String str = dataURL.substring(i + 1);
+		try {
+			if(mime.endsWith(";base64")) {
+				return Base64.decodeBase64(str);
+			}else {
+				return Window.decodeURIComponent(str).getBytes(StandardCharsets.UTF_8);
+			}
+		}catch(Throwable t) {
+			return null;
+		}
+	}
+
+}
diff --git a/sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/teavm/TeaVMEnterBootMenuException.java b/sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/teavm/TeaVMEnterBootMenuException.java
new file mode 100644
index 00000000..7a67daaf
--- /dev/null
+++ b/sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/teavm/TeaVMEnterBootMenuException.java
@@ -0,0 +1,20 @@
+package net.lax1dude.eaglercraft.v1_8.internal.teavm;
+
+/**
+ * Copyright (c) 2024 lax1dude. All Rights Reserved.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ * 
+ */
+public class TeaVMEnterBootMenuException extends RuntimeException {
+
+}
diff --git a/sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/teavm/TeaVMFetchJS.java b/sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/teavm/TeaVMFetchJS.java
new file mode 100644
index 00000000..2ba2c057
--- /dev/null
+++ b/sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/teavm/TeaVMFetchJS.java
@@ -0,0 +1,44 @@
+package net.lax1dude.eaglercraft.v1_8.internal.teavm;
+
+import org.teavm.jso.JSBody;
+import org.teavm.jso.JSFunctor;
+import org.teavm.jso.JSObject;
+import org.teavm.jso.typedarrays.ArrayBuffer;
+
+/**
+ * Copyright (c) 2022-2024 lax1dude. All Rights Reserved.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ * 
+ */
+public class TeaVMFetchJS {
+
+	@JSFunctor
+	public static interface FetchHandler extends JSObject {
+		void onFetch(ArrayBuffer data);
+	}
+
+	@JSBody(params = { }, script = "return (typeof fetch === \"function\");")
+	public static native boolean checkFetchSupport();
+
+	@JSBody(params = { "uri", "forceCache", "callback" }, script = "fetch(uri, { cache: forceCache, mode: \"no-cors\" })"
+			+ ".then(function(res) { return res.arrayBuffer(); }).then(function(arr) { callback(arr); })"
+			+ ".catch(function(err) { console.error(err); callback(null); });")
+	public static native void doFetchDownload(String uri, String forceCache, FetchHandler callback);
+
+	@JSBody(params = { "uri", "callback" }, script = "var eag = function(xhrObj){xhrObj.responseType = \"arraybuffer\";"
+			+ "xhrObj.addEventListener(\"load\", function(evt) { var stat = xhrObj.status; if(stat === 0 || (stat >= 200 && stat < 400)) { callback(xhrObj.response); } else { callback(null); } });"
+			+ "xhrObj.addEventListener(\"error\", function(evt) { callback(null); });"
+			+ "xhrObj.open(\"GET\", uri, true); xhrObj.send();}; eag(new XMLHttpRequest());")
+	public static native void doXHRDownload(String uri, FetchHandler callback);
+
+}
diff --git a/sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/teavm/TeaVMRuntimeDeobfuscator.java b/sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/teavm/TeaVMRuntimeDeobfuscator.java
new file mode 100644
index 00000000..efece705
--- /dev/null
+++ b/sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/teavm/TeaVMRuntimeDeobfuscator.java
@@ -0,0 +1,242 @@
+package net.lax1dude.eaglercraft.v1_8.internal.teavm;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.teavm.backend.javascript.spi.GeneratedBy;
+import org.teavm.jso.JSObject;
+import org.teavm.jso.core.JSArrayReader;
+import org.teavm.jso.core.JSString;
+
+import com.google.common.collect.Lists;
+
+import net.lax1dude.eaglercraft.v1_8.EagUtils;
+import net.lax1dude.eaglercraft.v1_8.internal.PlatformRuntime;
+import net.lax1dude.eaglercraft.v1_8.internal.teavm.generators.TeaVMRuntimeDeobfuscatorGenerator;
+import net.lax1dude.eaglercraft.v1_8.log4j.LogManager;
+import net.lax1dude.eaglercraft.v1_8.log4j.Logger;
+
+/**
+ * Copyright (c) 2024 lax1dude. All Rights Reserved.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ * 
+ */
+public class TeaVMRuntimeDeobfuscator {
+
+	private static final Logger logger = LogManager.getLogger("TeaVMRuntimeDeobfuscator");
+
+	private static class DeobfNameEntry {
+
+		private final String className;
+		private final String functionName;
+
+		private DeobfNameEntry(String className, String functionName) {
+			this.className = className;
+			this.functionName = functionName;
+		}
+
+	}
+
+	private static final Object initLock = new Object();
+
+	private static final Map<String,String> deobfClassNames = new HashMap<>();
+	private static final Map<String,DeobfNameEntry> deobfFuncNames = new HashMap<>();
+
+	private static boolean isInitialized = false;
+	private static boolean isFailed = false;
+
+	@GeneratedBy(TeaVMRuntimeDeobfuscatorGenerator.class)
+	private static native JSArrayReader<JSObject> getAllClasses();
+
+	private static void initialize0() {
+		try {
+			logger.info("Loading deobfuscation data, please wait...");
+		}catch(Throwable t2) {
+		}
+		long time = PlatformRuntime.steadyTimeMillis();
+		JSArrayReader<JSObject> classes = getAllClasses();
+		if(classes.getLength() < 2) {
+			return;
+		}
+		deobfClassNames.clear();
+		deobfFuncNames.clear();
+		JSArrayReader<JSString> stringReaderA = (JSArrayReader<JSString>)classes.get(0);
+		JSArrayReader<JSString> stringReaderB = (JSArrayReader<JSString>)classes.get(1);
+		String[] javaStringPoolA = new String[stringReaderA.getLength()];
+		for(int i = 0; i < javaStringPoolA.length; ++i) {
+			javaStringPoolA[i] = stringReaderA.get(i).stringValue();
+		}
+		String[] javaStringPoolB = new String[stringReaderB.getLength()];
+		for(int i = 0; i < javaStringPoolB.length; ++i) {
+			javaStringPoolB[i] = stringReaderB.get(i).stringValue();
+		}
+		for(int i = 2, l = classes.getLength() - 2; i < l; i += 3) {
+			int[] lookupTblClsName = Base64VarIntArray.decodeVarIntArray((JSString)classes.get(i));
+			StringBuilder classNameBuilder = new StringBuilder();
+			boolean b = false;
+			for(int j = 0; j < lookupTblClsName.length; ++j) {
+				if(b) {
+					classNameBuilder.append('.');
+				}
+				classNameBuilder.append(javaStringPoolA[lookupTblClsName[j]]);
+				b = true;
+			}
+			String className = classNameBuilder.toString();
+			String classObfName = ((JSString)classes.get(i + 1)).stringValue();
+			deobfClassNames.put(classObfName, className);
+			int[] lookupTbl = Base64VarIntArray.decodeVarIntArray((JSString)classes.get(i + 2));
+			for(int j = 0, m = lookupTbl.length - 1; j < m; j += 2) {
+				String obfName = javaStringPoolB[lookupTbl[j]];
+				String deobfName = javaStringPoolB[lookupTbl[j + 1]];
+				deobfFuncNames.put(obfName, new DeobfNameEntry(className, deobfName));
+			}
+		}
+		try {
+			time = PlatformRuntime.steadyTimeMillis() - time;
+			logger.info("Indexed {} class names and {} function names after {}ms", deobfClassNames.size(), deobfFuncNames.size(), time);
+		}catch(Throwable t2) {
+		}
+	}
+
+	public static void initialize() {
+		if(!isFailed) {
+			synchronized(initLock) {
+				if(!isInitialized) {
+					try {
+						initialize0();
+						isInitialized = true;
+					}catch(Throwable t) {
+						isFailed = true;
+						try {
+							logger.error("Failed to initialize the tables!");
+							logger.error(t);
+						}catch(Throwable t2) {
+						}
+					}
+				}
+			}
+		}
+	}
+
+	public static String deobfClassName(String clsName) {
+		if(!isInitialized) return null;
+		return deobfClassNames.get(clsName);
+	}
+
+	public static String deobfFunctionName(String funcName) {
+		if(!isInitialized) return null;
+		DeobfNameEntry ret = deobfFuncNames.get(funcName);
+		return ret != null ? ret.functionName : null;
+	}
+
+	public static String deobfFunctionClass(String funcName) {
+		if(!isInitialized) return null;
+		DeobfNameEntry ret = deobfFuncNames.get(funcName);
+		return ret != null ? ret.className : null;
+	}
+
+	public static String deobfFunctionFullName(String funcName) {
+		if(!isInitialized) return null;
+		DeobfNameEntry ret = deobfFuncNames.get(funcName);
+		return ret != null ? (ret.className != null ? ret.className : "<unknown>") + "." + ret.functionName + "()" : null;
+	}
+
+	public static String deobfFullName(String funcName) {
+		if(!isInitialized) return null;
+		DeobfNameEntry ret = deobfFuncNames.get(funcName);
+		return ret != null ? (ret.className != null ? ret.className : "<unknown>") + "." + ret.functionName + "()" : deobfClassNames.get(funcName);
+	}
+
+	private static int countLeadingWhitespace(String line) {
+		for(int i = 0, l = line.length(); i < l; ++i) {
+			char c = line.charAt(i);
+			if(c != ' ' && c != '\t') {
+				return i;
+			}
+		}
+		return 0;
+	}
+
+	public static String deobfExceptionStack(String stackLines) {
+		if(!isInitialized) return stackLines;
+		try {
+			List<String> lines = Lists.newArrayList(EagUtils.splitPattern.split(stackLines));
+			deobfExceptionStack(lines);
+			return String.join("\n", lines);
+		}catch(Throwable t) {
+			try {
+				logger.error("Failed to deobfuscate stack trace!");
+			}catch(Throwable t2) {
+			}
+			return stackLines;
+		}
+	}
+
+	public static void deobfExceptionStack(List<String> stackLines) {
+		if(!isInitialized) return;
+		try {
+			for(int i = 0, l = stackLines.size(); i < l; ++i) {
+				String line = stackLines.get(i);
+				int len = line.length();
+				if(len == 0) continue;
+				int leadingWs = countLeadingWhitespace(line);
+				if(len > leadingWs + 3 && line.charAt(leadingWs) == 'a' && line.charAt(leadingWs + 1) == 't' && line.charAt(leadingWs + 2) == ' ') {
+					leadingWs += 3;
+				}
+				int nextSpace = line.indexOf(' ', leadingWs);
+				int nextDot = line.indexOf('.', leadingWs);
+				String funcName2 = null;
+				if(nextDot > 0 && nextDot < nextSpace) {
+					funcName2 = line.substring(nextDot + 1, nextSpace);
+					nextSpace = nextDot;
+				}
+				if(nextSpace == -1) {
+					nextSpace = line.indexOf('@', leadingWs);
+					if(nextSpace == -1 && nextSpace < leadingWs) {
+						if(nextSpace == leadingWs + 1 && line.charAt(leadingWs) == '@') {
+							continue;
+						}
+						nextSpace = len;
+					}
+				}
+				if(nextSpace - leadingWs < 1) {
+					continue;
+				}
+				String funcName = line.substring(leadingWs, nextSpace);
+				String deobfName = deobfFunctionFullName(funcName);
+				if(deobfName != null) {
+					stackLines.set(i, line.substring(0, leadingWs) + deobfName + line.substring(nextSpace));
+				}else {
+					deobfName = deobfClassName(funcName);
+					if(deobfName != null) {
+						DeobfNameEntry deobfName2 = null;
+						if(funcName2 != null && funcName2.indexOf('.') == -1) {
+							deobfName2 = deobfFuncNames.get(funcName2);
+						}
+						if(deobfName2 != null && deobfName.equals(deobfName2.className)) {
+							deobfName += "." + deobfName2.functionName + "()";
+						}
+						stackLines.set(i, line.substring(0, leadingWs) + deobfName + line.substring(nextSpace));
+					}
+				}
+			}
+		}catch(Throwable t) {
+			try {
+				logger.error("Failed to deobfuscate stack trace!");
+			}catch(Throwable t2) {
+			}
+		}
+	}
+
+}
diff --git a/sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/teavm/TeaVMUpdateThread.java b/sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/teavm/TeaVMUpdateThread.java
index 862d0682..772eb070 100644
--- a/sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/teavm/TeaVMUpdateThread.java
+++ b/sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/teavm/TeaVMUpdateThread.java
@@ -20,7 +20,6 @@ import org.teavm.jso.typedarrays.ArrayBuffer;
 import com.google.common.collect.ListMultimap;
 
 import net.lax1dude.eaglercraft.v1_8.Base64;
-import net.lax1dude.eaglercraft.v1_8.EagRuntime;
 import net.lax1dude.eaglercraft.v1_8.EagUtils;
 import net.lax1dude.eaglercraft.v1_8.internal.PlatformApplication;
 import net.lax1dude.eaglercraft.v1_8.internal.PlatformAssets;
@@ -28,7 +27,9 @@ import net.lax1dude.eaglercraft.v1_8.internal.PlatformUpdateSvc;
 import net.lax1dude.eaglercraft.v1_8.log4j.LogManager;
 import net.lax1dude.eaglercraft.v1_8.log4j.Logger;
 import net.lax1dude.eaglercraft.v1_8.update.UpdateCertificate;
+import net.lax1dude.eaglercraft.v1_8.update.UpdateDataObj;
 import net.lax1dude.eaglercraft.v1_8.update.UpdateProgressStruct;
+import net.lax1dude.eaglercraft.v1_8.update.UpdateResultObj;
 import net.lax1dude.eaglercraft.v1_8.update.UpdateService;
 
 /**
@@ -61,6 +62,7 @@ public class TeaVMUpdateThread implements Runnable {
 	@Override
 	public void run() {
 		boolean success = false;
+		boolean hasCompleted = false;
 		try {
 			logger.info("Starting update thread...");
 			updateProg.clear();
@@ -68,7 +70,7 @@ public class TeaVMUpdateThread implements Runnable {
 			updateProg.statusString1 = updateCert.bundleDisplayName + " - " + updateCert.bundleDisplayVersion;
 			updateProg.statusString2 = "Please Wait";
 
-			List<String> urlListA = new ArrayList();
+			List<String> urlListA = new ArrayList<>();
 			ListMultimap<String,String> downloadSources = updateCert.getSourceMultimap();
 
 			List<String> ls = downloadSources.get("list");
@@ -115,7 +117,7 @@ public class TeaVMUpdateThread implements Runnable {
 				}
 			}
 			
-			List<String> urlListB = new ArrayList();
+			List<String> urlListB = new ArrayList<>();
 			ls = downloadSources.get("use-proxy");
 			for(int k = 0, l = ls.size(); k < l; ++k) {
 				String str1 = ls.get(k);
@@ -147,7 +149,7 @@ public class TeaVMUpdateThread implements Runnable {
 				logger.info("Verifying downloaded file...");
 				if(updateCert.isBundleDataValid(b)) {
 					logger.info("Success! Signature is valid!");
-					downloadSignedOffline(updateCert, b);
+					PlatformUpdateSvc.setUpdateResultTeaVM(UpdateResultObj.createSuccess(new UpdateDataObj(updateCert, b)));
 					success = true;
 					return;
 				}
@@ -162,11 +164,17 @@ public class TeaVMUpdateThread implements Runnable {
 		}catch(Throwable t) {
 			logger.error("Uncaught exception downloading updates!");
 			logger.error(t);
+			hasCompleted = true;
+			PlatformUpdateSvc.setUpdateResultTeaVM(UpdateResultObj.createFailure(t.toString()));
 		}finally {
 			PlatformUpdateSvc.updateThread = null;
 			updateProg.isBusy = false;
 			if(!success) {
-				logger.error("Failed to download updates! No valid URL was found for {}", updateCert.bundleDisplayVersion);
+				String str = "Failed to download updates! No valid URL was found for " + updateCert.bundleDisplayVersion;
+				logger.error(str);
+				if(!hasCompleted) {
+					PlatformUpdateSvc.setUpdateResultTeaVM(UpdateResultObj.createFailure(str));
+				}
 				Window.alert("ERROR: Failed to download updates!\n\nIf you are on a device with restricted internet access, try a different device or connect to a different WiFi network\n\nCheck the debug console for more info");
 			}else {
 				UpdateService.dismiss(updateCert);
@@ -254,7 +262,7 @@ public class TeaVMUpdateThread implements Runnable {
 	}
 
 	public static byte[] generateSignedOffline(UpdateCertificate cert, byte[] data) {
-		return generateSignedOffline(cert.rawCertData, data, EagRuntime.fixDateFormat(new SimpleDateFormat("MM/dd/yyyy")).format(new Date(cert.sigTimestamp)));
+		return generateSignedOffline(cert.rawCertData, data, (new SimpleDateFormat("MM/dd/yyyy")).format(new Date(cert.sigTimestamp)));
 	}
 
 	public static byte[] generateSignedOffline(byte[] cert, byte[] data, String date) {
diff --git a/sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/teavm/TeaVMUtils.java b/sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/teavm/TeaVMUtils.java
index a135a908..ad2c8d8f 100644
--- a/sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/teavm/TeaVMUtils.java
+++ b/sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/teavm/TeaVMUtils.java
@@ -1,11 +1,18 @@
 package net.lax1dude.eaglercraft.v1_8.internal.teavm;
 
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+
+import org.teavm.backend.javascript.spi.GeneratedBy;
+import org.teavm.backend.javascript.spi.InjectedBy;
 import org.teavm.interop.Async;
 import org.teavm.interop.AsyncCallback;
 import org.teavm.jso.JSBody;
 import org.teavm.jso.JSObject;
-import org.teavm.jso.JSProperty;
 import org.teavm.jso.browser.Window;
+import org.teavm.jso.dom.html.HTMLScriptElement;
 import org.teavm.jso.typedarrays.ArrayBuffer;
 import org.teavm.jso.typedarrays.ArrayBufferView;
 import org.teavm.jso.typedarrays.Float32Array;
@@ -14,7 +21,7 @@ import org.teavm.jso.typedarrays.Int32Array;
 import org.teavm.jso.typedarrays.Int8Array;
 import org.teavm.jso.typedarrays.Uint8Array;
 
-import net.lax1dude.eaglercraft.v1_8.EagUtils;
+import net.lax1dude.eaglercraft.v1_8.internal.teavm.generators.TeaVMUtilsUnwrapGenerator;
 
 /**
  * Copyright (c) 2022-2024 lax1dude. All Rights Reserved.
@@ -39,210 +46,92 @@ public class TeaVMUtils {
 	@JSBody(params = { "buf", "mime" }, script = "return URL.createObjectURL(new Blob([buf], {type: mime}));")
 	public static native String getDataURL(ArrayBuffer buf, String mime);
 	
+	@JSBody(params = { "blob" }, script = "return URL.createObjectURL(blob);")
+	public static native String getDataURL(JSObject blob);
+	
 	@JSBody(params = { "obj", "name", "handler" }, script = "obj.addEventListener(name, handler);")
 	public static native void addEventListener(JSObject obj, String name, JSObject handler);
 	
 	@JSBody(params = {}, script = "return (new Error()).stack;")
 	public static native String dumpJSStackTrace();
 
-	private static abstract class TeaVMArrayObject implements JSObject {
-		@JSProperty
-	    public abstract ArrayBufferView getData();
-	}
+	@InjectedBy(TeaVMUtilsUnwrapGenerator.UnwrapTypedArray.class)
+	public static native Int8Array unwrapByteArray(byte[] buf);
 
-	public static Int8Array unwrapByteArray(byte[] buf) {
-		if(buf == null) {
-			return null;
-		}
-		return Int8Array.create(((TeaVMArrayObject)(Object)buf).getData().getBuffer());
-	}
+	@InjectedBy(TeaVMUtilsUnwrapGenerator.UnwrapArrayBuffer.class)
+	public static native ArrayBuffer unwrapArrayBuffer(byte[] buf);
 
-	public static ArrayBuffer unwrapArrayBuffer(byte[] buf) {
-		if(buf == null) {
-			return null;
-		}
-		return ((TeaVMArrayObject)(Object)buf).getData().getBuffer();
-	}
+	@InjectedBy(TeaVMUtilsUnwrapGenerator.UnwrapTypedArray.class)
+	public static native ArrayBufferView unwrapArrayBufferView(byte[] buf);
 
-	public static ArrayBufferView unwrapArrayBufferView(byte[] buf) {
-		if(buf == null) {
-			return null;
-		}
-		return ((TeaVMArrayObject)(Object)buf).getData();
-	}
+	@GeneratedBy(TeaVMUtilsUnwrapGenerator.WrapTypedArray.class)
+	public static native byte[] wrapByteArray(Int8Array buf);
 
-	@JSBody(params = { "buf" }, script = "return $rt_createByteArray(buf)")
-	private static native JSObject wrapByteArray0(JSObject buf);
+	@GeneratedBy(TeaVMUtilsUnwrapGenerator.WrapArrayBuffer.class)
+	public static native byte[] wrapByteArrayBuffer(ArrayBuffer buf);
 
-	public static byte[] wrapByteArray(Int8Array buf) {
-		if(buf == null) {
-			return null;
-		}
-		return (byte[])(Object)wrapByteArray0(buf.getBuffer());
-	}
+	@GeneratedBy(TeaVMUtilsUnwrapGenerator.WrapArrayBufferView.class)
+	public static native byte[] wrapByteArrayBufferView(ArrayBufferView buf);
 
-	public static byte[] wrapByteArrayBuffer(ArrayBuffer buf) {
-		if(buf == null) {
-			return null;
-		}
-		return (byte[])(Object)wrapByteArray0(buf);
-	}
+	@InjectedBy(TeaVMUtilsUnwrapGenerator.UnwrapUnsignedTypedArray.class)
+	public static native Uint8Array unwrapUnsignedByteArray(byte[] buf);
 
-	public static byte[] wrapByteArrayBufferView(ArrayBufferView buf) {
-		if(buf == null) {
-			return null;
-		}
-		return (byte[])(Object)wrapByteArray0(buf.getBuffer());
-	}
+	@GeneratedBy(TeaVMUtilsUnwrapGenerator.WrapArrayBufferView.class)
+	public static native byte[] wrapUnsignedByteArray(Uint8Array buf);
 
-	public static Uint8Array unwrapUnsignedByteArray(byte[] buf) {
-		if(buf == null) {
-			return null;
-		}
-		return Uint8Array.create(((TeaVMArrayObject)(Object)buf).getData().getBuffer());
-	}
+	@InjectedBy(TeaVMUtilsUnwrapGenerator.UnwrapTypedArray.class)
+	public static native Int32Array unwrapIntArray(int[] buf);
 
-	public static byte[] wrapUnsignedByteArray(Uint8Array buf) {
-		if(buf == null) {
-			return null;
-		}
-		return (byte[])(Object)wrapByteArray0(buf.getBuffer());
-	}
+	@InjectedBy(TeaVMUtilsUnwrapGenerator.UnwrapArrayBuffer.class)
+	public static native ArrayBuffer unwrapArrayBuffer(int[] buf);
 
-	public static Int32Array unwrapIntArray(int[] buf) {
-		if(buf == null) {
-			return null;
-		}
-		return Int32Array.create(((TeaVMArrayObject)(Object)buf).getData().getBuffer());
-	}
+	@InjectedBy(TeaVMUtilsUnwrapGenerator.UnwrapTypedArray.class)
+	public static native ArrayBufferView unwrapArrayBufferView(int[] buf);
 
-	public static ArrayBuffer unwrapArrayBuffer(int[] buf) {
-		if(buf == null) {
-			return null;
-		}
-		return ((TeaVMArrayObject)(Object)buf).getData().getBuffer();
-	}
+	@GeneratedBy(TeaVMUtilsUnwrapGenerator.WrapTypedArray.class)
+	public static native int[] wrapIntArray(Int32Array buf);
 
-	public static ArrayBufferView unwrapArrayBufferView(int[] buf) {
-		if(buf == null) {
-			return null;
-		}
-		return ((TeaVMArrayObject)(Object)buf).getData();
-	}
+	@GeneratedBy(TeaVMUtilsUnwrapGenerator.WrapArrayBuffer.class)
+	public static native int[] wrapIntArrayBuffer(ArrayBuffer buf);
 
-	@JSBody(params = { "buf" }, script = "return $rt_createIntArray(buf)")
-	private static native JSObject wrapIntArray0(JSObject buf);
+	@GeneratedBy(TeaVMUtilsUnwrapGenerator.WrapArrayBufferView.class)
+	public static native int[] wrapIntArrayBufferView(ArrayBufferView buf);
 
-	public static int[] wrapIntArray(Int32Array buf) {
-		if(buf == null) {
-			return null;
-		}
-		return (int[])(Object)wrapIntArray0(buf.getBuffer());
-	}
+	@InjectedBy(TeaVMUtilsUnwrapGenerator.UnwrapTypedArray.class)
+	public static native Float32Array unwrapFloatArray(float[] buf);
 
-	public static int[] wrapIntArrayBuffer(ArrayBuffer buf) {
-		if(buf == null) {
-			return null;
-		}
-		return (int[])(Object)wrapIntArray0(buf);
-	}
+	@InjectedBy(TeaVMUtilsUnwrapGenerator.UnwrapArrayBuffer.class)
+	public static native ArrayBuffer unwrapArrayBuffer(float[] buf);
 
-	public static int[] wrapIntArrayBufferView(ArrayBufferView buf) {
-		if(buf == null) {
-			return null;
-		}
-		return (int[])(Object)wrapIntArray0(buf.getBuffer());
-	}
+	@InjectedBy(TeaVMUtilsUnwrapGenerator.UnwrapTypedArray.class)
+	public static native ArrayBufferView unwrapArrayBufferView(float[] buf);
 
-	public static Float32Array unwrapFloatArray(float[] buf) {
-		if(buf == null) {
-			return null;
-		}
-		return Float32Array.create(((TeaVMArrayObject)(Object)buf).getData().getBuffer());
-	}
+	@GeneratedBy(TeaVMUtilsUnwrapGenerator.WrapTypedArray.class)
+	public static native float[] wrapFloatArray(Float32Array buf);
 
-	public static ArrayBuffer unwrapArrayBuffer(float[] buf) {
-		if(buf == null) {
-			return null;
-		}
-		return ((TeaVMArrayObject)(Object)buf).getData().getBuffer();
-	}
+	@GeneratedBy(TeaVMUtilsUnwrapGenerator.WrapArrayBuffer.class)
+	public static native float[] wrapFloatArrayBuffer(ArrayBuffer buf);
 
-	public static ArrayBufferView unwrapArrayBufferView(float[] buf) {
-		if(buf == null) {
-			return null;
-		}
-		return ((TeaVMArrayObject)(Object)buf).getData();
-	}
+	@GeneratedBy(TeaVMUtilsUnwrapGenerator.WrapArrayBufferView.class)
+	public static native float[] wrapFloatArrayBufferView(ArrayBufferView buf);
 
-	@JSBody(params = { "buf" }, script = "return $rt_createFloatArray(buf)")
-	private static native JSObject wrapFloatArray0(JSObject buf);
+	@InjectedBy(TeaVMUtilsUnwrapGenerator.UnwrapTypedArray.class)
+	public static native Int16Array unwrapShortArray(short[] buf);
 
-	public static float[] wrapFloatArray(Float32Array buf) {
-		if(buf == null) {
-			return null;
-		}
-		return (float[])(Object)wrapFloatArray0(buf.getBuffer());
-	}
+	@InjectedBy(TeaVMUtilsUnwrapGenerator.UnwrapArrayBuffer.class)
+	public static native ArrayBuffer unwrapArrayBuffer(short[] buf);
 
-	public static float[] wrapFloatArrayBuffer(ArrayBuffer buf) {
-		if(buf == null) {
-			return null;
-		}
-		return (float[])(Object)wrapFloatArray0(buf);
-	}
+	@InjectedBy(TeaVMUtilsUnwrapGenerator.UnwrapTypedArray.class)
+	public static native ArrayBufferView unwrapArrayBufferView(short[] buf);
 
-	public static float[] wrapFloatArrayBufferView(ArrayBufferView buf) {
-		if(buf == null) {
-			return null;
-		}
-		return (float[])(Object)wrapFloatArray0(buf.getBuffer());
-	}
+	@GeneratedBy(TeaVMUtilsUnwrapGenerator.WrapTypedArray.class)
+	public static native short[] wrapShortArray(Int16Array buf);
 
-	public static Int16Array unwrapShortArray(short[] buf) {
-		if(buf == null) {
-			return null;
-		}
-		return Int16Array.create(((TeaVMArrayObject)(Object)buf).getData().getBuffer());
-	}
+	@GeneratedBy(TeaVMUtilsUnwrapGenerator.WrapArrayBuffer.class)
+	public static native short[] wrapShortArrayBuffer(ArrayBuffer buf);
 
-	public static ArrayBuffer unwrapArrayBuffer(short[] buf) {
-		if(buf == null) {
-			return null;
-		}
-		return ((TeaVMArrayObject)(Object)buf).getData().getBuffer();
-	}
-
-	public static ArrayBufferView unwrapArrayBufferView(short[] buf) {
-		if(buf == null) {
-			return null;
-		}
-		return ((TeaVMArrayObject)(Object)buf).getData();
-	}
-
-	@JSBody(params = { "buf" }, script = "return $rt_createShortArray(buf)")
-	private static native JSObject wrapShortArray0(JSObject buf);
-
-	public static short[] wrapShortArray(Int16Array buf) {
-		if(buf == null) {
-			return null;
-		}
-		return (short[])(Object)wrapShortArray0(buf.getBuffer());
-	}
-
-	public static short[] wrapShortArrayBuffer(ArrayBuffer buf) {
-		if(buf == null) {
-			return null;
-		}
-		return (short[])(Object)wrapShortArray0(buf);
-	}
-
-	public static short[] wrapShortArrayBuffer(ArrayBufferView buf) {
-		if(buf == null) {
-			return null;
-		}
-		return (short[])(Object)wrapShortArray0(buf.getBuffer());
-	}
+	@InjectedBy(TeaVMUtilsUnwrapGenerator.UnwrapArrayBuffer.class)
+	public static native short[] wrapShortArrayBuffer(ArrayBufferView buf);
 
 	@Async
 	public static native void sleepSetTimeout(int millis);
@@ -251,41 +140,56 @@ public class TeaVMUtils {
 		Window.setTimeout(() -> cb.complete(null), millis);
 	}
 
-	public static String tryResolveClassesSource() {
-		String str = dumpJSStackTrace();
-		String[] frames = EagUtils.splitPattern.split(str);
-		if("Error".equals(frames[0])) {
-			// V8 stack trace
-			if(frames.length > 1) {
-				String framesTrim = frames[1].trim();
-				if(framesTrim.startsWith("at")) {
-					//definitely V8
-					int i = framesTrim.indexOf('(');
-					int j = framesTrim.indexOf(')');
-					if(i != -1 && j != -1 && i < j) {
-						return tryResolveClassesSourceFromFrame(framesTrim.substring(i + 1, j));
-					}
-				}
-			}
-		}else {
-			// Mozilla/WebKit stack trace
-			String framesTrim = frames[0].trim();
-			int i = framesTrim.indexOf('@');
-			if(i != -1) {
-				return tryResolveClassesSourceFromFrame(framesTrim.substring(i + 1));
-			}
+	public static final Comparator<Touch> touchSortingComparator = (t1, t2) -> {
+		return t1.getIdentifier() - t2.getIdentifier();
+	};
+
+	public static final Comparator<OffsetTouch> touchSortingComparator2 = (t1, t2) -> {
+		return t1.touch.getIdentifier() - t2.touch.getIdentifier();
+	};
+
+	public static List<OffsetTouch> toSortedTouchList(TouchList touchList, SortedTouchEvent.ITouchUIDMapper mapper,
+			int originX, int originY) {
+		int l = touchList.getLength();
+		List<OffsetTouch> ret = new ArrayList<>(l);
+		for(int i = 0; i < l; ++i) {
+			ret.add(OffsetTouch.create(touchList.item(i), mapper, originX, originY));
 		}
-		return null;
+		Collections.sort(ret, touchSortingComparator2);
+		return ret;
 	}
 
-	private static String tryResolveClassesSourceFromFrame(String fileLineCol) {
-		int i = fileLineCol.lastIndexOf(':');
-		if(i > 0) {
-			i = fileLineCol.lastIndexOf(':', i - 1);
-		}
-		if(i != -1) {
-			return fileLineCol.substring(0, i);
-		}
-		return null;
+	public static String tryResolveClassesSource() {
+		return ClassesJSLocator.resolveClassesJSFromThrowable();
 	}
+
+	public static HTMLScriptElement tryResolveClassesSourceInline() {
+		return ClassesJSLocator.resolveClassesJSFromInline();
+	}
+
+	@JSBody(params = { "obj" }, script = "console.log(obj);")
+	public static native void objDump(JSObject obj);
+
+	@JSBody(params = { "obj" }, script = "return \"\" + obj;")
+	public static native String safeToString(JSObject obj);
+
+	@JSBody(params = { "obj" }, script = "return (!!obj && (typeof obj.message === \"string\")) ? obj.message : (\"\" + obj);")
+	public static native String safeErrorMsgToString(JSObject obj);
+
+	@JSBody(params = { "obj" }, script = "return !!obj;")
+	public static native boolean isTruthy(JSObject object);
+
+	@JSBody(params = { "obj" }, script = "return !obj;")
+	public static native boolean isNotTruthy(JSObject object);
+
+	@JSBody(params = { "obj" }, script = "return obj === undefined;")
+	public static native boolean isUndefined(JSObject object);
+
+	public static <T extends JSObject> T ensureDefined(T valIn) {
+		return isUndefined((JSObject)valIn) ? null : valIn;
+	}
+
+	@JSBody(params = { "obj" }, script = "return obj.stack||null;")
+	public static native String getStackSafe(JSObject object);
+
 }
diff --git a/sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/teavm/TeaVMWebSocketClient.java b/sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/teavm/TeaVMWebSocketClient.java
new file mode 100644
index 00000000..0de2245a
--- /dev/null
+++ b/sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/teavm/TeaVMWebSocketClient.java
@@ -0,0 +1,125 @@
+package net.lax1dude.eaglercraft.v1_8.internal.teavm;
+
+import org.teavm.jso.JSBody;
+import org.teavm.jso.dom.events.Event;
+import org.teavm.jso.dom.events.EventListener;
+import org.teavm.jso.dom.events.MessageEvent;
+import org.teavm.jso.typedarrays.ArrayBuffer;
+import org.teavm.jso.websocket.WebSocket;
+
+import net.lax1dude.eaglercraft.v1_8.EagUtils;
+import net.lax1dude.eaglercraft.v1_8.internal.AbstractWebSocketClient;
+import net.lax1dude.eaglercraft.v1_8.internal.EnumEaglerConnectionState;
+import net.lax1dude.eaglercraft.v1_8.internal.PlatformRuntime;
+
+/**
+ * Copyright (c) 2022-2024 lax1dude. All Rights Reserved.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ * 
+ */
+public class TeaVMWebSocketClient extends AbstractWebSocketClient {
+
+	private final WebSocket sock;
+	private boolean sockIsConnecting = true;
+	private boolean sockIsConnected = false;
+	private boolean sockIsFailed = false;
+
+	public TeaVMWebSocketClient(String socketURI) {
+		super(socketURI);
+		sock = WebSocket.create(socketURI);
+		sock.setBinaryType("arraybuffer");
+		TeaVMUtils.addEventListener(sock, "open", new EventListener<Event>() {
+			@Override
+			public void handleEvent(Event evt) {
+				sockIsConnecting = false;
+				sockIsConnected = true;
+			}
+		});
+		TeaVMUtils.addEventListener(sock, "close", new EventListener<Event>() {
+			@Override
+			public void handleEvent(Event evt) {
+				sockIsConnecting = false;
+				sockIsConnected = false;
+			}
+		});
+		TeaVMUtils.addEventListener(sock, "message", new EventListener<MessageEvent>() {
+			@Override
+			public void handleEvent(MessageEvent evt) {
+				addRecievedFrame(new TeaVMWebSocketFrame(evt.getData()));
+			}
+		});
+		TeaVMUtils.addEventListener(sock, "error", new EventListener<Event>() {
+			@Override
+			public void handleEvent(Event evt) {
+				if(sockIsConnecting) {
+					sockIsFailed = true;
+					sockIsConnecting = false;
+				}
+			}
+		});
+	}
+
+	@Override
+	public boolean connectBlocking(int timeoutMS) {
+		long startTime = PlatformRuntime.steadyTimeMillis();
+		while(!sockIsConnected && !sockIsFailed) {
+			EagUtils.sleep(50l);
+			if(PlatformRuntime.steadyTimeMillis() - startTime > timeoutMS * 1000) {
+				break;
+			}
+		}
+		return sockIsConnected;
+	}
+
+	@Override
+	public EnumEaglerConnectionState getState() {
+		return sockIsConnected ? EnumEaglerConnectionState.CONNECTED
+				: (sockIsFailed ? EnumEaglerConnectionState.FAILED
+						: (sockIsConnecting ? EnumEaglerConnectionState.CONNECTING : EnumEaglerConnectionState.CLOSED));
+	}
+
+	@Override
+	public boolean isOpen() {
+		return sockIsConnected;
+	}
+
+	@Override
+	public boolean isClosed() {
+		return !sockIsConnecting && !sockIsConnected;
+	}
+
+	@Override
+	public void close() {
+		sockIsConnecting = false;
+		sockIsConnected = false;
+		sock.close();
+	}
+
+	@Override
+	public void send(String str) {
+		if(sockIsConnected) {
+			sock.send(str);
+		}
+	}
+
+	@JSBody(params = { "sock", "buffer" }, script = "sock.send(buffer);")
+	protected static native void nativeBinarySend(WebSocket sock, ArrayBuffer buffer);
+
+	@Override
+	public void send(byte[] bytes) {
+		if(sockIsConnected) {
+			nativeBinarySend(sock, TeaVMUtils.unwrapArrayBuffer(bytes));
+		}
+	}
+
+}
diff --git a/sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/teavm/TeaVMWebSocketFrame.java b/sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/teavm/TeaVMWebSocketFrame.java
new file mode 100644
index 00000000..33060579
--- /dev/null
+++ b/sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/teavm/TeaVMWebSocketFrame.java
@@ -0,0 +1,114 @@
+package net.lax1dude.eaglercraft.v1_8.internal.teavm;
+
+import java.io.InputStream;
+
+import org.teavm.jso.JSBody;
+import org.teavm.jso.JSObject;
+import org.teavm.jso.typedarrays.ArrayBuffer;
+
+import net.lax1dude.eaglercraft.v1_8.internal.IWebSocketFrame;
+import net.lax1dude.eaglercraft.v1_8.internal.PlatformRuntime;
+
+/**
+ * Copyright (c) 2024 lax1dude. All Rights Reserved.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ * 
+ */
+public class TeaVMWebSocketFrame implements IWebSocketFrame {
+
+	private JSObject data;
+	private boolean str;
+
+	private String cachedStrContent = null;
+	private byte[] cachedByteContent = null;
+
+	private int cachedLen = -1;
+
+	private final long timestamp;
+
+	@JSBody(params = { "obj" }, script = "return (typeof obj === \"string\");")
+	private static native boolean isStr(JSObject obj);
+
+	public TeaVMWebSocketFrame(JSObject data) {
+		this.data = data;
+		this.str = isStr(data);
+		this.timestamp = PlatformRuntime.steadyTimeMillis();
+	}
+
+	@Override
+	public boolean isString() {
+		return str;
+	}
+
+	@JSBody(params = { "obj" }, script = "return obj;")
+	private static native String toStr(JSObject obj);
+
+	@Override
+	public String getString() {
+		if(str) {
+			if(cachedStrContent == null) {
+				return (cachedStrContent = toStr(data));
+			}else {
+				return cachedStrContent;
+			}
+		}else {
+			return null;
+		}
+	}
+
+	@Override
+	public byte[] getByteArray() {
+		if(!str) {
+			if(cachedByteContent == null) {
+				return (cachedByteContent = TeaVMUtils.wrapByteArrayBuffer((ArrayBuffer)data));
+			}else {
+				return cachedByteContent;
+			}
+		}else {
+			return null;
+		}
+	}
+
+	@Override
+	public InputStream getInputStream() {
+		if(!str) {
+			return new ArrayBufferInputStream((ArrayBuffer)data);
+		}else {
+			return null;
+		}
+	}
+
+	@JSBody(params = { "obj" }, script = "return obj.length;")
+	private static native int strLen(JSObject obj);
+
+	@JSBody(params = { "obj" }, script = "return obj.byteLength;")
+	private static native int arrLen(JSObject obj);
+
+	@Override
+	public int getLength() {
+		if(cachedLen == -1) {
+			if(str) {
+				cachedLen = strLen(data);
+			}else {
+				cachedLen = arrLen(data);
+			}
+		}
+		return cachedLen;
+	}
+
+	@Override
+	public long getTimestamp() {
+		return timestamp;
+	}
+
+}
diff --git a/sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/teavm/Touch.java b/sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/teavm/Touch.java
new file mode 100644
index 00000000..0a6234eb
--- /dev/null
+++ b/sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/teavm/Touch.java
@@ -0,0 +1,67 @@
+package net.lax1dude.eaglercraft.v1_8.internal.teavm;
+
+import org.teavm.jso.JSBody;
+import org.teavm.jso.JSObject;
+import org.teavm.jso.JSProperty;
+import org.teavm.jso.dom.xml.Element;
+
+/**
+ * Copyright (c) 2024 lax1dude. All Rights Reserved.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ * 
+ */
+public abstract class Touch implements JSObject {
+
+	@JSProperty
+	public abstract int getIdentifier();
+
+	@JSProperty
+	public abstract double getScreenX();
+
+	@JSProperty
+	public abstract double getScreenY();
+
+	@JSProperty
+	public abstract double getClientX();
+
+	@JSProperty
+	public abstract double getClientY();
+
+	@JSProperty
+	public abstract double getPageX();
+
+	@JSProperty
+	public abstract double getPageY();
+
+	@JSProperty
+	public abstract double getRadiusX();
+
+	@JSBody(params = { "defVal" }, script = "return (typeof this.radiusX === \"number\") ? this.radiusX : defVal;")
+	public abstract double getRadiusXSafe(double defaultVal);
+
+	@JSProperty
+	public abstract double getRadiusY();
+
+	@JSBody(params = { "defVal" }, script = "return (typeof this.radiusY === \"number\") ? this.radiusY : defVal;")
+	public abstract double getRadiusYSafe(double defaultVal);
+
+	@JSProperty
+	public abstract double getForce();
+
+	@JSBody(params = { "defVal" }, script = "return (typeof this.force === \"number\") ? this.force : defVal;")
+	public abstract double getForceSafe(double defaultVal);
+
+	@JSProperty
+	public abstract Element getTarget();
+
+}
diff --git a/sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/teavm/TouchEvent.java b/sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/teavm/TouchEvent.java
new file mode 100644
index 00000000..91cc6d78
--- /dev/null
+++ b/sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/teavm/TouchEvent.java
@@ -0,0 +1,44 @@
+package net.lax1dude.eaglercraft.v1_8.internal.teavm;
+
+import org.teavm.jso.JSProperty;
+import org.teavm.jso.dom.events.Event;
+
+/**
+ * Copyright (c) 2024 lax1dude. All Rights Reserved.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ * 
+ */
+public interface TouchEvent extends Event {
+
+	@JSProperty
+	boolean getAltKey();
+
+	@JSProperty
+	boolean getCtrlKey();
+
+	@JSProperty
+	boolean getMetaKey();
+
+	@JSProperty
+	boolean getShiftKey();
+
+	@JSProperty
+	TouchList getChangedTouches();
+
+	@JSProperty
+	TouchList getTargetTouches();
+
+	@JSProperty
+	TouchList getTouches();
+
+}
diff --git a/sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/teavm/TouchList.java b/sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/teavm/TouchList.java
new file mode 100644
index 00000000..985fc6ca
--- /dev/null
+++ b/sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/teavm/TouchList.java
@@ -0,0 +1,28 @@
+package net.lax1dude.eaglercraft.v1_8.internal.teavm;
+
+import org.teavm.jso.JSObject;
+import org.teavm.jso.JSProperty;
+
+/**
+ * Copyright (c) 2024 lax1dude. All Rights Reserved.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ * 
+ */
+public interface TouchList extends JSObject {
+
+	@JSProperty
+	int getLength();
+
+	Touch item(int idx);
+
+}
diff --git a/sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/teavm/VisualViewport.java b/sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/teavm/VisualViewport.java
new file mode 100644
index 00000000..d01f5802
--- /dev/null
+++ b/sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/teavm/VisualViewport.java
@@ -0,0 +1,45 @@
+package net.lax1dude.eaglercraft.v1_8.internal.teavm;
+
+import org.teavm.jso.JSObject;
+import org.teavm.jso.JSProperty;
+import org.teavm.jso.dom.events.EventTarget;
+
+/**
+ * Copyright (c) 2024 lax1dude. All Rights Reserved.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ * 
+ */
+public interface VisualViewport extends JSObject, EventTarget {
+
+	@JSProperty
+	int getOffsetLeft();
+
+	@JSProperty
+	int getOffsetTop();
+
+	@JSProperty
+	int getPageLeft();
+
+	@JSProperty
+	int getPageTop();
+
+	@JSProperty
+	int getWidth();
+
+	@JSProperty
+	int getHeight();
+
+	@JSProperty
+	double getScale();
+
+}
diff --git a/sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/teavm/WebGLANGLEInstancedArrays.java b/sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/teavm/WebGLANGLEInstancedArrays.java
new file mode 100644
index 00000000..71bd8d81
--- /dev/null
+++ b/sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/teavm/WebGLANGLEInstancedArrays.java
@@ -0,0 +1,28 @@
+package net.lax1dude.eaglercraft.v1_8.internal.teavm;
+
+import org.teavm.jso.JSObject;
+
+/**
+ * Copyright (c) 2024 lax1dude. All Rights Reserved.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ * 
+ */
+public interface WebGLANGLEInstancedArrays extends JSObject {
+
+	void drawArraysInstancedANGLE(int mode, int first, int count, int instanced);
+
+	void drawElementsInstancedANGLE(int mode, int count, int type, int offset, int primcount);
+
+	void vertexAttribDivisorANGLE(int index, int divisor);
+
+}
diff --git a/sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/teavm/WebGLBackBuffer.java b/sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/teavm/WebGLBackBuffer.java
new file mode 100644
index 00000000..7a7bc829
--- /dev/null
+++ b/sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/teavm/WebGLBackBuffer.java
@@ -0,0 +1,300 @@
+package net.lax1dude.eaglercraft.v1_8.internal.teavm;
+
+import static net.lax1dude.eaglercraft.v1_8.internal.PlatformOpenGL.*;
+import static net.lax1dude.eaglercraft.v1_8.opengl.RealOpenGLEnums.*;
+
+import org.teavm.jso.webgl.WebGLFramebuffer;
+
+import net.lax1dude.eaglercraft.v1_8.internal.IBufferArrayGL;
+import net.lax1dude.eaglercraft.v1_8.internal.IBufferGL;
+import net.lax1dude.eaglercraft.v1_8.internal.IFramebufferGL;
+import net.lax1dude.eaglercraft.v1_8.internal.IProgramGL;
+import net.lax1dude.eaglercraft.v1_8.internal.IRenderbufferGL;
+import net.lax1dude.eaglercraft.v1_8.internal.IShaderGL;
+import net.lax1dude.eaglercraft.v1_8.internal.ITextureGL;
+import net.lax1dude.eaglercraft.v1_8.internal.PlatformRuntime;
+import net.lax1dude.eaglercraft.v1_8.internal.buffer.ByteBuffer;
+import net.lax1dude.eaglercraft.v1_8.opengl.EaglercraftGPU;
+import net.lax1dude.eaglercraft.v1_8.opengl.GlStateManager;
+
+/**
+ * Copyright (c) 2022-2024 lax1dude. All Rights Reserved.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ * 
+ */
+public class WebGLBackBuffer {
+
+	private static int glesVers = -1;
+
+	private static WebGL2RenderingContext ctx;
+	private static WebGLFramebuffer framebuffer;
+	private static IFramebufferGL eagFramebuffer;
+	private static int width;
+	private static int height;
+
+	// GLES 3.0+
+	private static IRenderbufferGL gles3ColorRenderbuffer;
+	private static IRenderbufferGL gles3DepthRenderbuffer;
+
+	// GLES 2.0
+	private static ITextureGL gles2ColorTexture;
+	private static IRenderbufferGL gles2DepthRenderbuffer;
+	private static IProgramGL gles2BlitProgram;
+	private static IBufferArrayGL gles2BlitVAO;
+	private static IBufferGL gles2BlitVBO;
+
+	private static boolean isVAOCapable = false;
+	private static boolean isEmulatedVAOPhase = false;
+
+	private static final int _GL_FRAMEBUFFER = 0x8D40;
+	private static final int _GL_RENDERBUFFER = 0x8D41;
+	private static final int _GL_COLOR_ATTACHMENT0 = 0x8CE0;
+	private static final int _GL_DEPTH_ATTACHMENT = 0x8D00;
+	private static final int _GL_DEPTH_COMPONENT16 = 0x81A5;
+	private static final int _GL_DEPTH_COMPONENT32F = 0x8CAC;
+	private static final int _GL_READ_FRAMEBUFFER = 0x8CA8;
+	private static final int _GL_DRAW_FRAMEBUFFER = 0x8CA9;
+
+	public static void initBackBuffer(WebGL2RenderingContext ctxIn, WebGLFramebuffer fbo, IFramebufferGL eagFbo, int sw, int sh) {
+		ctx = ctxIn;
+		glesVers = checkOpenGLESVersion();
+		framebuffer = fbo;
+		eagFramebuffer = eagFbo;
+		isVAOCapable = checkVAOCapable();
+		isEmulatedVAOPhase = false;
+		width = sw;
+		height = sh;
+		if(glesVers >= 300) {
+			gles3ColorRenderbuffer = _wglCreateRenderbuffer();
+			gles3DepthRenderbuffer = _wglCreateRenderbuffer();
+			_wglBindFramebuffer(_GL_FRAMEBUFFER, eagFbo);
+			_wglBindRenderbuffer(_GL_RENDERBUFFER, gles3ColorRenderbuffer);
+			_wglRenderbufferStorage(_GL_RENDERBUFFER, GL_RGBA8, sw, sh);
+			_wglFramebufferRenderbuffer(_GL_FRAMEBUFFER, _GL_COLOR_ATTACHMENT0, _GL_RENDERBUFFER, gles3ColorRenderbuffer);
+			_wglBindRenderbuffer(_GL_RENDERBUFFER, gles3DepthRenderbuffer);
+			_wglRenderbufferStorage(_GL_RENDERBUFFER, _GL_DEPTH_COMPONENT32F, sw, sh);
+			_wglFramebufferRenderbuffer(_GL_FRAMEBUFFER, _GL_DEPTH_ATTACHMENT, _GL_RENDERBUFFER, gles3DepthRenderbuffer);
+			_wglDrawBuffers(_GL_COLOR_ATTACHMENT0);
+		}else {
+			gles2ColorTexture = _wglGenTextures();
+			gles2DepthRenderbuffer = _wglCreateRenderbuffer();
+			_wglBindFramebuffer(_GL_FRAMEBUFFER, eagFbo);
+			_wglBindTexture(GL_TEXTURE_2D, gles2ColorTexture);
+			_wglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+			_wglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+			_wglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+			_wglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+			_wglTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, sw, sh, 0, GL_RGBA, GL_UNSIGNED_BYTE, (ByteBuffer)null);
+			_wglFramebufferTexture2D(_GL_FRAMEBUFFER, _GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, gles2ColorTexture, 0);
+			_wglBindRenderbuffer(_GL_RENDERBUFFER, gles2DepthRenderbuffer);
+			_wglRenderbufferStorage(_GL_RENDERBUFFER, _GL_DEPTH_COMPONENT16, sw, sh);
+			_wglFramebufferRenderbuffer(_GL_FRAMEBUFFER, _GL_DEPTH_ATTACHMENT, _GL_RENDERBUFFER, gles2DepthRenderbuffer);
+			
+			ByteBuffer upload = PlatformRuntime.allocateByteBuffer(48);
+			upload.putFloat(0.0f); upload.putFloat(0.0f);
+			upload.putFloat(1.0f); upload.putFloat(0.0f);
+			upload.putFloat(0.0f); upload.putFloat(1.0f);
+			upload.putFloat(1.0f); upload.putFloat(0.0f);
+			upload.putFloat(1.0f); upload.putFloat(1.0f);
+			upload.putFloat(0.0f); upload.putFloat(1.0f);
+			upload.flip();
+			
+			gles2BlitVBO = _wglGenBuffers();
+			EaglercraftGPU.bindVAOGLArrayBufferNow(gles2BlitVBO);
+			_wglBufferData(GL_ARRAY_BUFFER, upload, GL_STATIC_DRAW);
+			
+			PlatformRuntime.freeByteBuffer(upload);
+			
+			if(isVAOCapable) {
+				gles2BlitVAO = _wglGenVertexArrays();
+				_wglBindVertexArray(gles2BlitVAO);
+				_wglEnableVertexAttribArray(0);
+				_wglVertexAttribPointer(0, 2, GL_FLOAT, false, 8, 0);
+			}
+
+			IShaderGL vertShader = _wglCreateShader(GL_VERTEX_SHADER);
+			_wglShaderSource(vertShader, "#version 100\nprecision mediump float; attribute vec2 a_pos2f; varying vec2 v_tex2f; void main() { v_tex2f = a_pos2f; gl_Position = vec4(a_pos2f * 2.0 - 1.0, 0.0, 1.0); }");
+			_wglCompileShader(vertShader);
+			
+			IShaderGL fragShader = _wglCreateShader(GL_FRAGMENT_SHADER);
+			_wglShaderSource(fragShader, checkTextureLODCapable()
+					? "#version 100\n#extension GL_EXT_shader_texture_lod : enable\nprecision mediump float; precision mediump sampler2D; varying vec2 v_tex2f; uniform sampler2D u_samplerTex; void main() { gl_FragColor = vec4(texture2DLodEXT(u_samplerTex, v_tex2f, 0.0).rgb, 1.0); }"
+					: "#version 100\nprecision mediump float; precision mediump sampler2D; varying vec2 v_tex2f; uniform sampler2D u_samplerTex; void main() { gl_FragColor = vec4(texture2D(u_samplerTex, v_tex2f).rgb, 1.0); }");
+			_wglCompileShader(fragShader);
+			
+			gles2BlitProgram = _wglCreateProgram();
+			
+			_wglAttachShader(gles2BlitProgram, vertShader);
+			_wglAttachShader(gles2BlitProgram, fragShader);
+			
+			_wglBindAttribLocation(gles2BlitProgram, 0, "a_pos2f");
+			
+			_wglLinkProgram(gles2BlitProgram);
+			
+			_wglDetachShader(gles2BlitProgram, vertShader);
+			_wglDetachShader(gles2BlitProgram, fragShader);
+
+			_wglDeleteShader(vertShader);
+			_wglDeleteShader(fragShader);
+			
+			_wglUseProgram(gles2BlitProgram);
+			
+			_wglUniform1i(_wglGetUniformLocation(gles2BlitProgram, "u_samplerTex"), 0);
+		}
+	}
+
+	public static void enterVAOEmulationPhase() {
+		if(glesVers < 300) {
+			if(!isEmulatedVAOPhase) {
+				if(isVAOCapable) {
+					_wglDeleteVertexArrays(gles2BlitVAO);
+				}
+				gles2BlitVAO = EaglercraftGPU.createGLBufferArray();
+				EaglercraftGPU.bindGLBufferArray(gles2BlitVAO);
+				EaglercraftGPU.bindVAOGLArrayBuffer(gles2BlitVBO);
+				EaglercraftGPU.enableVertexAttribArray(0);
+				EaglercraftGPU.vertexAttribPointer(0, 2, GL_FLOAT, false, 8, 0);
+				isEmulatedVAOPhase = true;
+			}
+		}
+	}
+
+	private static void drawBlitQuad() {
+		if(isEmulatedVAOPhase) {
+			EaglercraftGPU.bindGLBufferArray(gles2BlitVAO);
+			EaglercraftGPU.doDrawArrays(GL_TRIANGLES, 0, 6);
+		}else {
+			if(isVAOCapable) {
+				_wglBindVertexArray(gles2BlitVAO);
+				_wglDrawArrays(GL_TRIANGLES, 0, 6);
+			}else {
+				EaglercraftGPU.bindGLArrayBuffer(gles2BlitVBO);
+				_wglEnableVertexAttribArray(0);
+				_wglVertexAttribPointer(0, 2, GL_FLOAT, false, 8, 0);
+				_wglDrawArrays(GL_TRIANGLES, 0, 6);
+			}
+		}
+	}
+
+	public static void flipBuffer(int windowWidth, int windowHeight) {
+		if(glesVers >= 300) {
+			ctx.bindFramebuffer(_GL_READ_FRAMEBUFFER, framebuffer);
+			ctx.bindFramebuffer(_GL_DRAW_FRAMEBUFFER, null);
+			ctx.blitFramebuffer(0, 0, width, height, 0, 0, windowWidth, windowHeight, GL_COLOR_BUFFER_BIT, GL_NEAREST);
+			
+			ctx.bindFramebuffer(_GL_FRAMEBUFFER, framebuffer);
+			
+			if(windowWidth != width || windowHeight != height) {
+				width = windowWidth;
+				height = windowHeight;
+				
+				_wglBindRenderbuffer(_GL_RENDERBUFFER, gles3ColorRenderbuffer);
+				_wglRenderbufferStorage(_GL_RENDERBUFFER, GL_RGBA8, windowWidth, windowHeight);
+				
+				_wglBindRenderbuffer(_GL_RENDERBUFFER, gles3DepthRenderbuffer);
+				_wglRenderbufferStorage(_GL_RENDERBUFFER, _GL_DEPTH_COMPONENT32F, windowWidth, windowHeight);
+			}
+		}else {
+			ctx.bindFramebuffer(_GL_FRAMEBUFFER, null);
+			_wglActiveTexture(GL_TEXTURE0);
+			_wglBindTexture(GL_TEXTURE_2D, gles2ColorTexture);
+			
+			int[] viewportStash = null;
+			if(isEmulatedVAOPhase) {
+				viewportStash = new int[4];
+				EaglercraftGPU.glGetInteger(GL_VIEWPORT, viewportStash);
+				GlStateManager.viewport(0, 0, windowWidth, windowHeight);
+				GlStateManager.eagPushStateForGLES2BlitHack();
+				GlStateManager.disableDepth();
+				GlStateManager.disableBlend();
+			}else {
+				_wglViewport(0, 0, windowWidth, windowHeight);
+				_wglDisable(GL_DEPTH_TEST);
+				_wglDisable(GL_BLEND);
+			}
+
+			EaglercraftGPU.clearCurrentBinding(EaglercraftGPU.CLEAR_BINDING_SHADER_PROGRAM | EaglercraftGPU.CLEAR_BINDING_ARRAY_BUFFER);
+
+			EaglercraftGPU.bindGLShaderProgram(gles2BlitProgram);
+
+			drawBlitQuad();
+
+			if(windowWidth != width || windowHeight != height) {
+				width = windowWidth;
+				height = windowHeight;
+				
+				_wglTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, windowWidth, windowHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, (ByteBuffer)null);
+				
+				_wglBindRenderbuffer(_GL_RENDERBUFFER, gles2DepthRenderbuffer);
+				_wglRenderbufferStorage(_GL_RENDERBUFFER, _GL_DEPTH_COMPONENT16, windowWidth, windowHeight);
+			}
+
+			if(isEmulatedVAOPhase) {
+				EaglercraftGPU.clearCurrentBinding(EaglercraftGPU.CLEAR_BINDING_TEXTURE0 | EaglercraftGPU.CLEAR_BINDING_ACTIVE_TEXTURE | EaglercraftGPU.CLEAR_BINDING_SHADER_PROGRAM);
+				if(viewportStash[2] > 0) {
+					GlStateManager.viewport(viewportStash[0], viewportStash[1], viewportStash[2], viewportStash[3]);
+				}
+				GlStateManager.eagPopStateForGLES2BlitHack();
+			}else {
+				EaglercraftGPU.clearCurrentBinding(EaglercraftGPU.CLEAR_BINDING_TEXTURE0 | EaglercraftGPU.CLEAR_BINDING_ACTIVE_TEXTURE | EaglercraftGPU.CLEAR_BINDING_SHADER_PROGRAM | EaglercraftGPU.CLEAR_BINDING_BUFFER_ARRAY);
+			}
+
+			ctx.bindFramebuffer(_GL_FRAMEBUFFER, framebuffer);
+		}
+	}
+
+	public static void destroy() {
+		if(eagFramebuffer != null) {
+			_wglDeleteFramebuffer(eagFramebuffer);
+			eagFramebuffer = null;
+		}
+		if(gles3ColorRenderbuffer != null) {
+			_wglDeleteRenderbuffer(gles3ColorRenderbuffer);
+			gles3ColorRenderbuffer = null;
+		}
+		if(gles3DepthRenderbuffer != null) {
+			_wglDeleteRenderbuffer(gles3DepthRenderbuffer);
+			gles3DepthRenderbuffer = null;
+		}
+		if(gles2ColorTexture != null) {
+			_wglDeleteTextures(gles2ColorTexture);
+			gles2ColorTexture = null;
+		}
+		if(gles2DepthRenderbuffer != null) {
+			_wglDeleteRenderbuffer(gles2DepthRenderbuffer);
+			gles2DepthRenderbuffer = null;
+		}
+		if(gles2BlitProgram != null) {
+			_wglDeleteProgram(gles2BlitProgram);
+			gles2BlitProgram = null;
+		}
+		if(gles2BlitVAO != null) {
+			if(isEmulatedVAOPhase) {
+				EaglercraftGPU.destroyGLBufferArray(gles2BlitVAO);
+			}else if(isVAOCapable) {
+				_wglDeleteVertexArrays(gles2BlitVAO);
+			}
+			gles2BlitVAO = null;
+		}
+		if(gles2BlitVBO != null) {
+			_wglDeleteBuffers(gles2BlitVBO);
+			gles2BlitVBO = null;
+		}
+		framebuffer = null;
+		width = 0;
+		height = 0;
+		isVAOCapable = false;
+		isEmulatedVAOPhase = false;
+	}
+
+}
diff --git a/sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/teavm/WebGLOESVertexArrayObject.java b/sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/teavm/WebGLOESVertexArrayObject.java
new file mode 100644
index 00000000..f15c5614
--- /dev/null
+++ b/sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/teavm/WebGLOESVertexArrayObject.java
@@ -0,0 +1,28 @@
+package net.lax1dude.eaglercraft.v1_8.internal.teavm;
+
+import org.teavm.jso.JSObject;
+
+/**
+ * Copyright (c) 2024 lax1dude. All Rights Reserved.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ * 
+ */
+public interface WebGLOESVertexArrayObject extends JSObject {
+
+	WebGLVertexArray createVertexArrayOES();
+
+	void deleteVertexArrayOES(WebGLVertexArray obj);
+
+	void bindVertexArrayOES(WebGLVertexArray obj);
+
+}
diff --git a/sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/teavm/generators/TeaVMRuntimeDeobfuscatorGenerator.java b/sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/teavm/generators/TeaVMRuntimeDeobfuscatorGenerator.java
new file mode 100644
index 00000000..b1ade504
--- /dev/null
+++ b/sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/teavm/generators/TeaVMRuntimeDeobfuscatorGenerator.java
@@ -0,0 +1,108 @@
+package net.lax1dude.eaglercraft.v1_8.internal.teavm.generators;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+
+import org.teavm.backend.javascript.codegen.ScopedName;
+import org.teavm.backend.javascript.codegen.SourceWriter;
+import org.teavm.backend.javascript.spi.Generator;
+import org.teavm.backend.javascript.spi.GeneratorContext;
+import org.teavm.model.MethodReference;
+
+import net.lax1dude.eaglercraft.v1_8.internal.teavm.Base64VarIntArray;
+
+/**
+ * Copyright (c) 2024 lax1dude. All Rights Reserved.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ * 
+ */
+public class TeaVMRuntimeDeobfuscatorGenerator implements Generator {
+
+	private int indexIntoSet(String name, Map<String,Integer> namesSet, List<String> namesList) {
+		Integer ret = namesSet.get(name);
+		if(ret != null) {
+			return ret.intValue();
+		}
+		int i = namesList.size();
+		namesList.add(name);
+		namesSet.put(name, i);
+		return i;
+	}
+
+	@Override
+	public void generate(GeneratorContext context, SourceWriter writer, MethodReference methodRef) throws IOException {
+		Map<String,List<Integer>> map = new HashMap<>();
+		List<String> classNamesPartsList = new ArrayList<>();
+		Map<String,Integer> classNamesPartsSet = new HashMap<>();
+		List<String> namesList = new ArrayList<>();
+		Map<String,Integer> namesSet = new HashMap<>();
+		Map<String,List<Integer>> namesEncSet = new HashMap<>();
+		for(MethodReference method : context.getDependency().getReachableMethods()) {
+			ScopedName name = writer.getNaming().getFullNameFor(method);
+			if(name.scoped) {
+				continue;
+			}
+			String clsName = method.getClassName();
+			List<Integer> lst = map.get(clsName);
+			if(lst == null) {
+				map.put(clsName, lst = new ArrayList<>());
+			}
+			lst.add(indexIntoSet(name.value, namesSet, namesList));
+			lst.add(indexIntoSet(method.getName(), namesSet, namesList));
+		}
+		for(String str : map.keySet()) {
+			List<Integer> builder = new ArrayList<>();
+			boolean b = false;
+			for(String strr : str.split("\\.")) {
+				builder.add(indexIntoSet(strr, classNamesPartsSet, classNamesPartsList));
+				b = true;
+			}
+			namesEncSet.put(str, builder);
+		}
+		writer.append("return [").ws().append('[').ws();
+		boolean b = false;
+		for(String str : classNamesPartsList) {
+			if(b) {
+				writer.append(',').ws();
+			}
+			writer.append('\"').append(str).append('\"');
+			b = true;
+		}
+		writer.append("],").ws().append('[').ws();
+		b = false;
+		for(String str : namesList) {
+			if(b) {
+				writer.append(',').ws();
+			}
+			writer.append('\"').append(str).append('\"');
+			b = true;
+		}
+		writer.ws().append("],").ws();
+		b = false;
+		for (Entry<String,List<Integer>> name : map.entrySet()) {
+			if(b) {
+				writer.append(',').ws();
+			}
+			writer.append('\"').append(Base64VarIntArray.encodeVarIntArray(namesEncSet.get(name.getKey()))).append("\",").ws();
+			writer.append('\"').appendClass(name.getKey()).append("\",").ws().append('\"');
+			writer.append(Base64VarIntArray.encodeVarIntArray(name.getValue())).append('\"').ws();
+			b = true;
+		}
+		writer.ws().append("];").softNewLine();
+	}
+
+}
diff --git a/sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/teavm/generators/TeaVMUtilsUnwrapGenerator.java b/sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/teavm/generators/TeaVMUtilsUnwrapGenerator.java
new file mode 100644
index 00000000..6eff0e7c
--- /dev/null
+++ b/sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/teavm/generators/TeaVMUtilsUnwrapGenerator.java
@@ -0,0 +1,166 @@
+package net.lax1dude.eaglercraft.v1_8.internal.teavm.generators;
+
+import java.io.IOException;
+
+import org.teavm.backend.javascript.codegen.SourceWriter;
+import org.teavm.backend.javascript.spi.Generator;
+import org.teavm.backend.javascript.spi.GeneratorContext;
+import org.teavm.backend.javascript.spi.Injector;
+import org.teavm.backend.javascript.spi.InjectorContext;
+import org.teavm.model.MethodReference;
+
+/**
+ * Copyright (c) 2024 lax1dude. All Rights Reserved.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ * 
+ */
+public class TeaVMUtilsUnwrapGenerator {
+
+	// WARNING: This code uses internal TeaVM APIs that may not have
+	// been intended for end users of the compiler to program with
+
+	public static class UnwrapArrayBuffer implements Injector {
+
+		@Override
+		public void generate(InjectorContext context, MethodReference methodRef) throws IOException {
+			context.writeExpr(context.getArgument(0));
+			context.getWriter().append(".data.buffer");
+		}
+
+	}
+
+	public static class UnwrapTypedArray implements Injector {
+
+		@Override
+		public void generate(InjectorContext context, MethodReference methodRef) throws IOException {
+			context.writeExpr(context.getArgument(0));
+			context.getWriter().append(".data");
+		}
+
+	}
+
+	public static class WrapArrayBuffer implements Generator {
+
+		@Override
+		public void generate(GeneratorContext context, SourceWriter writer, MethodReference methodRef)
+				throws IOException {
+	        String parName = context.getParameterName(1);
+			switch (methodRef.getName()) {
+			case "wrapByteArrayBuffer":
+				writer.append("return ").append(parName).ws().append('?').ws();
+				writer.append("$rt_createNumericArray($rt_bytecls(),").ws().append("new Int8Array(").append(parName).append("))").ws();
+				writer.append(':').ws().append("null;").softNewLine();
+				break;
+			case "wrapIntArrayBuffer":
+				writer.append("return ").append(parName).ws().append('?').ws();
+				writer.append("$rt_createNumericArray($rt_intcls(),").ws().append("new Int32Array(").append(parName).append("))").ws();
+				writer.append(':').ws().append("null;").softNewLine();
+				break;
+			case "wrapFloatArrayBuffer":
+				writer.append("return ").append(parName).ws().append('?').ws();
+				writer.append("$rt_createNumericArray($rt_floatcls(),").ws().append("new Float32Array(").append(parName).append("))").ws();
+				writer.append(':').ws().append("null;").softNewLine();
+				break;
+			case "wrapShortArrayBuffer":
+				writer.append("return ").append(parName).ws().append('?').ws();
+				writer.append("$rt_createNumericArray($rt_shortcls(),").ws().append("new Int16Array(").append(parName).append("))").ws();
+				writer.append(':').ws().append("null;").softNewLine();
+				break;
+			default:
+				break;
+			}
+		}
+
+	}
+
+	public static class WrapArrayBufferView implements Generator {
+
+		@Override
+		public void generate(GeneratorContext context, SourceWriter writer, MethodReference methodRef)
+				throws IOException {
+	        String parName = context.getParameterName(1);
+			switch (methodRef.getName()) {
+			case "wrapByteArrayBufferView":
+			case "wrapUnsignedByteArray":
+				writer.append("return ").append(parName).ws().append('?').ws();
+				writer.append("$rt_createNumericArray($rt_bytecls(),").ws().append("new Int8Array(").append(parName).append(".buffer))").ws();
+				writer.append(':').ws().append("null;").softNewLine();
+				break;
+			case "wrapIntArrayBufferView":
+				writer.append("return ").append(parName).ws().append('?').ws();
+				writer.append("$rt_createNumericArray($rt_intcls(),").ws().append("new Int32Array(").append(parName).append(".buffer))").ws();
+				writer.append(':').ws().append("null;").softNewLine();
+				break;
+			case "wrapFloatArrayBufferView":
+				writer.append("return ").append(parName).ws().append('?').ws();
+				writer.append("$rt_createNumericArray($rt_floatcls(),").ws().append("new Float32Array(").append(parName).append(".buffer))").ws();
+				writer.append(':').ws().append("null;").softNewLine();
+				break;
+			case "wrapShortArrayBufferView":
+				writer.append("return ").append(parName).ws().append('?').ws();
+				writer.append("$rt_createNumericArray($rt_shortcls(),").ws().append("new Int16Array(").append(parName).append(".buffer))").ws();
+				writer.append(':').ws().append("null;").softNewLine();
+				break;
+			default:
+				break;
+			}
+		}
+
+	}
+
+	public static class WrapTypedArray implements Generator {
+
+		@Override
+		public void generate(GeneratorContext context, SourceWriter writer, MethodReference methodRef)
+				throws IOException {
+	        String parName = context.getParameterName(1);
+			switch (methodRef.getName()) {
+			case "wrapByteArray":
+				writer.append("return ").append(parName).ws().append('?').ws();
+				writer.append("$rt_createNumericArray($rt_bytecls(),").ws().append(parName).append(")").ws();
+				writer.append(':').ws().append("null;").softNewLine();
+				break;
+			case "wrapIntArray":
+				writer.append("return ").append(parName).ws().append('?').ws();
+				writer.append("$rt_createNumericArray($rt_intcls(),").ws().append(parName).append(")").ws();
+				writer.append(':').ws().append("null;").softNewLine();
+				break;
+			case "wrapFloatArray":
+				writer.append("return ").append(parName).ws().append('?').ws();
+				writer.append("$rt_createNumericArray($rt_floatcls(),").ws().append(parName).append(")").ws();
+				writer.append(':').ws().append("null;").softNewLine();
+				break;
+			case "wrapShortArray":
+				writer.append("return ").append(parName).ws().append('?').ws();
+				writer.append("$rt_createNumericArray($rt_shortcls(),").ws().append(parName).append(")").ws();
+				writer.append(':').ws().append("null;").softNewLine();
+				break;
+			default:
+				break;
+			}
+		}
+
+	}
+
+	public static class UnwrapUnsignedTypedArray implements Injector {
+
+		@Override
+		public void generate(InjectorContext context, MethodReference methodRef) throws IOException {
+			context.getWriter().append("new Uint8Array(");
+			context.writeExpr(context.getArgument(0));
+			context.getWriter().append(".data.buffer)");
+		}
+
+	}
+
+}
diff --git a/sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/teavm/opts/JSEaglercraftXOptsHooks.java b/sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/teavm/opts/JSEaglercraftXOptsHooks.java
index 7b5cf410..bd0b4067 100644
--- a/sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/teavm/opts/JSEaglercraftXOptsHooks.java
+++ b/sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/teavm/opts/JSEaglercraftXOptsHooks.java
@@ -29,4 +29,7 @@ public abstract class JSEaglercraftXOptsHooks implements JSObject {
 	@JSBody(script = "return (typeof this.crashReportShow === \"function\") ? this.crashReportShow : null;")
 	public native JSObject getCrashReportHook();
 
+	@JSBody(script = "return (typeof this.screenChanged === \"function\") ? this.screenChanged : null;")
+	public native JSObject getScreenChangedHook();
+
 }
diff --git a/sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/teavm/opts/JSEaglercraftXOptsRoot.java b/sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/teavm/opts/JSEaglercraftXOptsRoot.java
index caf1f9d5..9e4f472c 100644
--- a/sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/teavm/opts/JSEaglercraftXOptsRoot.java
+++ b/sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/teavm/opts/JSEaglercraftXOptsRoot.java
@@ -96,7 +96,79 @@ public abstract class JSEaglercraftXOptsRoot implements JSObject {
 	@JSBody(params = { "def" }, script = "return (typeof this.enableMinceraft === \"boolean\") ? this.enableMinceraft : def;")
 	public native boolean getEnableMinceraft(boolean defaultValue);
 
+	@JSBody(params = { "def" }, script = "return (typeof this.enableServerCookies === \"boolean\") ? this.enableServerCookies : def;")
+	public native boolean getEnableServerCookies(boolean defaultValue);
+
+	@JSBody(params = { "def" }, script = "return (typeof this.allowServerRedirects === \"boolean\") ? this.allowServerRedirects : def;")
+	public native boolean getAllowServerRedirects(boolean defaultValue);
+
 	@JSBody(params = { "def" }, script = "return (typeof this.crashOnUncaughtExceptions === \"boolean\") ? this.crashOnUncaughtExceptions : def;")
 	public native boolean getCrashOnUncaughtExceptions(boolean defaultValue);
 
+	@JSBody(params = { "def" }, script = "return (typeof this.openDebugConsoleOnLaunch === \"boolean\") ? this.openDebugConsoleOnLaunch : def;")
+	public native boolean getOpenDebugConsoleOnLaunch(boolean defaultValue);
+
+	@JSBody(params = { "def" }, script = "return (typeof this.fixDebugConsoleUnloadListener === \"boolean\") ? this.fixDebugConsoleUnloadListener : def;")
+	public native boolean getFixDebugConsoleUnloadListener(boolean defaultValue);
+
+	@JSBody(params = { "def" }, script = "return (typeof this.forceWebViewSupport === \"boolean\") ? this.forceWebViewSupport : def;")
+	public native boolean getForceWebViewSupport(boolean defaultValue);
+
+	@JSBody(params = { "def" }, script = "return (typeof this.enableWebViewCSP === \"boolean\") ? this.enableWebViewCSP : def;")
+	public native boolean getEnableWebViewCSP(boolean defaultValue);
+
+	@JSBody(params = { "def" }, script = "return (typeof this.autoFixLegacyStyleAttr === \"boolean\") ? this.autoFixLegacyStyleAttr : def;")
+	public native boolean getAutoFixLegacyStyleAttr(boolean defaultValue);
+
+	@JSBody(params = { "def" }, script = "return (typeof this.showBootMenuOnLaunch === \"boolean\") ? this.showBootMenuOnLaunch : def;")
+	public native boolean getShowBootMenuOnLaunch(boolean defaultValue);
+
+	@JSBody(params = { "def" }, script = "return (typeof this.bootMenuBlocksUnsignedClients === \"boolean\") ? this.bootMenuBlocksUnsignedClients : def;")
+	public native boolean getBootMenuBlocksUnsignedClients(boolean defaultValue);
+
+	@JSBody(params = { "def" }, script = "return (typeof this.allowBootMenu === \"boolean\") ? this.allowBootMenu : def;")
+	public native boolean getAllowBootMenu(boolean defaultValue);
+
+	@JSBody(params = { "def" }, script = "return (typeof this.forceProfanityFilter === \"boolean\") ? this.forceProfanityFilter : def;")
+	public native boolean getForceProfanityFilter(boolean defaultValue);
+
+	@JSBody(params = { "def" }, script = "return (typeof this.forceWebGL1 === \"boolean\") ? this.forceWebGL1 : def;")
+	public native boolean getForceWebGL1(boolean defaultValue);
+
+	@JSBody(params = { "def" }, script = "return (typeof this.forceWebGL2 === \"boolean\") ? this.forceWebGL2 : def;")
+	public native boolean getForceWebGL2(boolean defaultValue);
+
+	@JSBody(params = { "def" }, script = "return (typeof this.allowExperimentalWebGL1 === \"boolean\") ? this.allowExperimentalWebGL1 : def;")
+	public native boolean getAllowExperimentalWebGL1(boolean defaultValue);
+
+	@JSBody(params = { "def" }, script = "return (typeof this.useWebGLExt === \"boolean\") ? this.useWebGLExt : def;")
+	public native boolean getUseWebGLExt(boolean defaultValue);
+
+	@JSBody(params = { "def" }, script = "return (typeof this.useDelayOnSwap === \"boolean\") ? this.useDelayOnSwap : def;")
+	public native boolean getUseDelayOnSwap(boolean defaultValue);
+
+	@JSBody(params = { "def" }, script = "return (typeof this.useJOrbisAudioDecoder === \"boolean\") ? this.useJOrbisAudioDecoder : def;")
+	public native boolean getUseJOrbisAudioDecoder(boolean defaultValue);
+
+	@JSBody(params = { "def" }, script = "return (typeof this.useXHRFetch === \"boolean\") ? this.useXHRFetch : def;")
+	public native boolean getUseXHRFetch(boolean defaultValue);
+
+	@JSBody(params = { "def" }, script = "return (typeof this.useVisualViewport === \"boolean\") ? this.useVisualViewport : def;")
+	public native boolean getUseVisualViewport(boolean defaultValue);
+
+	@JSBody(params = { "def" }, script = "return (typeof this.deobfStackTraces === \"boolean\") ? this.deobfStackTraces : def;")
+	public native boolean getDeobfStackTraces(boolean deobfStackTraces);
+
+	@JSBody(params = { "def" }, script = "return (typeof this.disableBlobURLs === \"boolean\") ? this.disableBlobURLs : def;")
+	public native boolean getDisableBlobURLs(boolean deobfStackTraces);
+
+	@JSBody(params = { "def" }, script = "return (typeof this.eaglerNoDelay === \"boolean\") ? this.eaglerNoDelay : def;")
+	public native boolean getEaglerNoDelay(boolean deobfStackTraces);
+
+	@JSBody(params = { "def" }, script = "return (typeof this.ramdiskMode === \"boolean\") ? this.ramdiskMode : def;")
+	public native boolean getRamdiskMode(boolean deobfStackTraces);
+
+	@JSBody(params = { "def" }, script = "return (typeof this.singleThreadMode === \"boolean\") ? this.singleThreadMode : def;")
+	public native boolean getSingleThreadMode(boolean deobfStackTraces);
+
 }
diff --git a/sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/teavm/opts/JSEaglercraftXOptsServer.java b/sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/teavm/opts/JSEaglercraftXOptsServer.java
index 8ff7e6ce..e5c06240 100644
--- a/sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/teavm/opts/JSEaglercraftXOptsServer.java
+++ b/sources/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/teavm/opts/JSEaglercraftXOptsServer.java
@@ -23,6 +23,9 @@ public abstract class JSEaglercraftXOptsServer implements JSObject {
 	@JSBody(script = "return (typeof this.addr === \"string\") ? this.addr : null;")
 	public native String getAddr();
 
+	@JSBody(params = { "def" }, script = "return (typeof this.hideAddr === \"boolean\") ? this.hideAddr : def;")
+	public native boolean getHideAddr(boolean defaultValue);
+
 	@JSBody(params = { "def" }, script = "return (typeof this.name === \"string\") ? this.name : def;")
 	public native String getName(String defaultValue);
 
diff --git a/sources/teavm/java/net/lax1dude/eaglercraft/v1_8/sp/internal/ClientPlatformSingleplayer.java b/sources/teavm/java/net/lax1dude/eaglercraft/v1_8/sp/internal/ClientPlatformSingleplayer.java
index afbb05db..0d254f4a 100644
--- a/sources/teavm/java/net/lax1dude/eaglercraft/v1_8/sp/internal/ClientPlatformSingleplayer.java
+++ b/sources/teavm/java/net/lax1dude/eaglercraft/v1_8/sp/internal/ClientPlatformSingleplayer.java
@@ -1,5 +1,6 @@
 package net.lax1dude.eaglercraft.v1_8.sp.internal;
 
+import java.nio.charset.StandardCharsets;
 import java.util.ArrayList;
 import java.util.LinkedList;
 import java.util.List;
@@ -9,15 +10,19 @@ import org.teavm.jso.JSFunctor;
 import org.teavm.jso.JSObject;
 import org.teavm.jso.dom.events.ErrorEvent;
 import org.teavm.jso.dom.events.EventListener;
+import org.teavm.jso.dom.html.HTMLScriptElement;
 import org.teavm.jso.typedarrays.ArrayBuffer;
 import org.teavm.jso.workers.Worker;
 
 import net.lax1dude.eaglercraft.v1_8.internal.IPCPacketData;
 import net.lax1dude.eaglercraft.v1_8.internal.PlatformRuntime;
 import net.lax1dude.eaglercraft.v1_8.internal.teavm.ClientMain;
+import net.lax1dude.eaglercraft.v1_8.internal.teavm.TeaVMBlobURLManager;
+import net.lax1dude.eaglercraft.v1_8.internal.teavm.TeaVMClientConfigAdapter;
 import net.lax1dude.eaglercraft.v1_8.internal.teavm.TeaVMUtils;
 import net.lax1dude.eaglercraft.v1_8.log4j.LogManager;
 import net.lax1dude.eaglercraft.v1_8.log4j.Logger;
+import net.lax1dude.eaglercraft.v1_8.sp.server.internal.teavm.SingleThreadWorker;
 
 /**
  * Copyright (c) 2023-2024 lax1dude. All Rights Reserved.
@@ -38,28 +43,34 @@ public class ClientPlatformSingleplayer {
 
 	private static final Logger logger = LogManager.getLogger("ClientPlatformSingleplayer");
 
-	private static final LinkedList<IPCPacketData> messageQueue = new LinkedList();
+	private static final LinkedList<IPCPacketData> messageQueue = new LinkedList<>();
 
-	@JSBody(params = {}, script = "return (typeof window.eaglercraftXClientScriptElement !== \"undefined\") ? window.eaglercraftXClientScriptElement : null;")
+	@JSBody(params = {}, script = "return (typeof eaglercraftXClientScriptElement !== \"undefined\") ? eaglercraftXClientScriptElement : null;")
 	private static native JSObject loadIntegratedServerSourceOverride();
 
-	@JSBody(params = {}, script = "return (typeof window.eaglercraftXClientScriptURL === \"string\") ? window.eaglercraftXClientScriptURL : null;")
+	@JSBody(params = {}, script = "return (typeof eaglercraftXClientScriptURL === \"string\") ? eaglercraftXClientScriptURL : null;")
 	private static native String loadIntegratedServerSourceOverrideURL();
 
-	@JSBody(params = {}, script = "try{throw new Error();}catch(ex){return ex.stack;}return null;")
+	@JSBody(params = {}, script = "try{throw new Error();}catch(ex){return ex.stack||null;}return null;")
 	private static native String loadIntegratedServerSourceStack();
 
 	@JSBody(params = { "csc" }, script = "if(typeof csc.src === \"string\" && csc.src.length > 0) return csc.src; else return null;")
 	private static native String loadIntegratedServerSourceURL(JSObject scriptTag);
 
-	@JSBody(params = { "csc", "tail" }, script = "const cscText = csc.text;"
+	@JSBody(params = { "csc", "tail" }, script = "var cscText = csc.text;"
 			+ "if(typeof cscText === \"string\" && cscText.length > 0) return new Blob([cscText, tail], { type: \"text/javascript;charset=utf8\" });"
 			+ "else return null;")
 	private static native JSObject loadIntegratedServerSourceInline(JSObject scriptTag, String tail);
 
+	@JSBody(params = { "csc" }, script = "var cscText = csc.text;"
+			+ "if(typeof cscText === \"string\" && cscText.length > 0) return cscText;"
+			+ "else return null;")
+	private static native String loadIntegratedServerSourceInlineStr(JSObject scriptTag);
+
 	private static String integratedServerSource = null;
 	private static String integratedServerSourceOriginalURL = null;
 	private static boolean serverSourceLoaded = false;
+	private static boolean isSingleThreadMode = false;
 
 	private static Worker workerObj = null;
 
@@ -68,7 +79,7 @@ public class ClientPlatformSingleplayer {
 		public void onMessage(String channel, ArrayBuffer buf);
 	}
 
-	@JSBody(params = { "w", "wb" }, script = "w.onmessage = function(o) { wb(o.data.ch, o.data.dat); };")
+	@JSBody(params = { "w", "wb" }, script = "w.addEventListener(\"message\", function(o) { wb(o.data.ch, o.data.dat); });")
 	private static native void registerPacketHandler(Worker w, WorkerBinaryPacketHandler wb);
 
 	@JSBody(params = { "w", "ch", "dat" }, script = "w.postMessage({ ch: ch, dat : dat });")
@@ -108,13 +119,13 @@ public class ClientPlatformSingleplayer {
 	private static JSObject loadIntegratedServerSource() {
 		String str = loadIntegratedServerSourceOverrideURL();
 		if(str != null) {
-			ArrayBuffer buf = PlatformRuntime.downloadRemoteURI(str);
+			ArrayBuffer buf = PlatformRuntime.downloadRemoteURI(str, true);
 			if(buf != null) {
 				integratedServerSourceOriginalURL = str;
-				logger.info("Using integrated server at: {}", str);
+				logger.info("Using integrated server at: {}", truncateURL(str));
 				return createBlobObj(buf, workerBootstrapCode);
 			}else {
-				logger.error("Failed to load integrated server: {}", str);
+				logger.error("Failed to load integrated server: {}", truncateURL(str));
 			}
 		}
 		JSObject el = loadIntegratedServerSourceOverride();
@@ -128,25 +139,34 @@ public class ClientPlatformSingleplayer {
 					return el;
 				}
 			}else {
-				ArrayBuffer buf = PlatformRuntime.downloadRemoteURI(url);
+				ArrayBuffer buf = PlatformRuntime.downloadRemoteURI(url, true);
 				if(buf != null) {
 					integratedServerSourceOriginalURL = url;
-					logger.info("Using integrated server from script tag src: {}", url);
+					logger.info("Using integrated server from script tag src: {}", truncateURL(url));
 					return createBlobObj(buf, workerBootstrapCode);
 				}else {
-					logger.error("Failed to load integrated server from script tag src: {}", url);
+					logger.error("Failed to load integrated server from script tag src: {}", truncateURL(url));
 				}
 			}
 		}
 		str = TeaVMUtils.tryResolveClassesSource();
 		if(str != null) {
-			ArrayBuffer buf = PlatformRuntime.downloadRemoteURI(str);
+			ArrayBuffer buf = PlatformRuntime.downloadRemoteURI(str, true);
 			if(buf != null) {
 				integratedServerSourceOriginalURL = str;
-				logger.info("Using integrated server from script src: {}", str);
+				logger.info("Using integrated server from script src: {}", truncateURL(str));
 				return createBlobObj(buf, workerBootstrapCode);
 			}else {
-				logger.error("Failed to load integrated server from script src: {}", str);
+				logger.error("Failed to load integrated server from script src: {}", truncateURL(str));
+			}
+		}
+		HTMLScriptElement sc = TeaVMUtils.tryResolveClassesSourceInline();
+		if(sc != null) {
+			el = loadIntegratedServerSourceInline(sc, workerBootstrapCode);
+			if(el != null) {
+				integratedServerSourceOriginalURL = "inline script tag (client guess)";
+				logger.info("Loading integrated server from (likely) inline script tag");
+				return el;
 			}
 		}
 		logger.info("Could not resolve the location of client's classes.js!");
@@ -155,12 +175,57 @@ public class ClientPlatformSingleplayer {
 		return null;
 	}
 
+	private static String truncateURL(String url) {
+		if(url == null) return null;
+		if(url.length() > 256) {
+			url = url.substring(0, 254) + "...";
+		}
+		return url;
+	}
+
 	private static String createIntegratedServerWorkerURL() {
 		JSObject blobObj = loadIntegratedServerSource();
 		if(blobObj == null) {
 			return null;
 		}
-		return createWorkerScriptURL(blobObj);
+		return TeaVMBlobURLManager.registerNewURLBlob(blobObj).toExternalForm();
+	}
+
+	public static byte[] getIntegratedServerSourceTeaVM() {
+		String str = loadIntegratedServerSourceOverrideURL();
+		if(str != null) {
+			ArrayBuffer buf = PlatformRuntime.downloadRemoteURI(str, true);
+			if(buf != null) {
+				return TeaVMUtils.wrapByteArrayBuffer(buf);
+			}
+		}
+		JSObject el = loadIntegratedServerSourceOverride();
+		if(el != null) {
+			String url = loadIntegratedServerSourceURL(el);
+			if(url == null) {
+				str = loadIntegratedServerSourceInlineStr(el);
+				if(str != null) {
+					return str.getBytes(StandardCharsets.UTF_8);
+				}
+			}else {
+				ArrayBuffer buf = PlatformRuntime.downloadRemoteURI(url, true);
+				if(buf != null) {
+					return TeaVMUtils.wrapByteArrayBuffer(buf);
+				}
+			}
+		}
+		str = TeaVMUtils.tryResolveClassesSource();
+		if(str != null) {
+			ArrayBuffer buf = PlatformRuntime.downloadRemoteURI(str, true);
+			if(buf != null) {
+				return TeaVMUtils.wrapByteArrayBuffer(buf);
+			}
+		}
+		HTMLScriptElement sc = TeaVMUtils.tryResolveClassesSourceInline();
+		if(sc != null) {
+			return sc.getText().getBytes(StandardCharsets.UTF_8);
+		}
+		return null;
 	}
 
 	public static String getLoadedWorkerURLTeaVM() {
@@ -171,36 +236,58 @@ public class ClientPlatformSingleplayer {
 		return (serverSourceLoaded && workerObj != null) ? integratedServerSourceOriginalURL : null;
 	}
 
-	public static void startIntegratedServer() {
-		if(!serverSourceLoaded) {
-			integratedServerSource = createIntegratedServerWorkerURL();
-			serverSourceLoaded = true;
-		}
-		
-		if(integratedServerSource == null) {
-			throw new RuntimeException("Could not resolve the location of client's classes.js! Make sure client's classes.js is linked/embedded in a dedicated <script> tag. Define \"window.eaglercraftXClientScriptElement\" or \"window.eaglercraftXClientScriptURL\" to force");
-		}
-		
-		workerObj = Worker.create(integratedServerSource);
-		workerObj.onError(new EventListener<ErrorEvent>() {
-			@Override
-			public void handleEvent(ErrorEvent evt) {
-				logger.error("Worker Error: {}", evt.getError());
-				PlatformRuntime.printNativeExceptionToConsoleTeaVM(evt);
+	public static void startIntegratedServer(boolean singleThreadMode) {
+		singleThreadMode |= ((TeaVMClientConfigAdapter)PlatformRuntime.getClientConfigAdapter()).isSingleThreadModeTeaVM();
+		if(singleThreadMode) {
+			if(!isSingleThreadMode) {
+				SingleThreadWorker.singleThreadStartup((pkt) -> {
+					synchronized(messageQueue) {
+						messageQueue.add(pkt);
+					}
+				});
+				isSingleThreadMode = true;
 			}
-		});
-		registerPacketHandler(workerObj, new WorkerBinaryPacketHandlerImpl());
-		sendWorkerStartPacket(workerObj, PlatformRuntime.getClientConfigAdapter().getIntegratedServerOpts().toString());
-		
+		}else {
+			if(!serverSourceLoaded) {
+				integratedServerSource = createIntegratedServerWorkerURL();
+				serverSourceLoaded = true;
+			}
+			
+			if(integratedServerSource == null) {
+				logger.error("Could not resolve the location of client's classes.js! Make sure client's classes.js is linked/embedded in a dedicated <script> tag. Define \"window.eaglercraftXClientScriptElement\" or \"window.eaglercraftXClientScriptURL\" to force");
+				logger.error("Falling back to single thread mode...");
+				startIntegratedServer(true);
+				return;
+			}
+			
+			workerObj = Worker.create(integratedServerSource);
+			workerObj.addEventListener("error", new EventListener<ErrorEvent>() {
+				@Override
+				public void handleEvent(ErrorEvent evt) {
+					logger.error("Worker Error: {}", evt.getError());
+					PlatformRuntime.printNativeExceptionToConsoleTeaVM(evt);
+				}
+			});
+			registerPacketHandler(workerObj, new WorkerBinaryPacketHandlerImpl());
+			sendWorkerStartPacket(workerObj, PlatformRuntime.getClientConfigAdapter().getIntegratedServerOpts().toString());
+		}
 	}
 
 	public static void sendPacket(IPCPacketData packet) {
-		sendPacketTeaVM(packet.channel, TeaVMUtils.unwrapArrayBuffer(packet.contents));
+		if(isSingleThreadMode) {
+			SingleThreadWorker.sendPacketToWorker(packet);
+		}else {
+			sendPacketTeaVM(packet.channel, TeaVMUtils.unwrapArrayBuffer(packet.contents));
+		}
 	}
 
 	public static void sendPacketTeaVM(String channel, ArrayBuffer packet) {
-		if(workerObj != null) {
-			sendWorkerPacket(workerObj, channel, packet);
+		if(isSingleThreadMode) {
+			SingleThreadWorker.sendPacketToWorker(new IPCPacketData(channel, TeaVMUtils.wrapByteArrayBuffer(packet)));
+		}else {
+			if(workerObj != null) {
+				sendWorkerPacket(workerObj, channel, packet);
+			}
 		}
 	}
 
@@ -217,7 +304,7 @@ public class ClientPlatformSingleplayer {
 	}
 
 	public static boolean canKillWorker() {
-		return true;
+		return !isSingleThreadMode;
 	}
 
 	public static void killWorker() {
@@ -228,7 +315,17 @@ public class ClientPlatformSingleplayer {
 	}
 
 	public static boolean isRunningSingleThreadMode() {
-		return false;
+		return isSingleThreadMode;
+	}
+
+	public static boolean isSingleThreadModeSupported() {
+		return true;
+	}
+
+	public static void updateSingleThreadMode() {
+		if(isSingleThreadMode) {
+			SingleThreadWorker.singleThreadUpdate();
+		}
 	}
 
 	public static void showCrashReportOverlay(String report, int x, int y, int w, int h) {
diff --git a/sources/teavm/java/net/lax1dude/eaglercraft/v1_8/sp/server/internal/ServerPlatformSingleplayer.java b/sources/teavm/java/net/lax1dude/eaglercraft/v1_8/sp/server/internal/ServerPlatformSingleplayer.java
index 52dab9f4..a9bef778 100644
--- a/sources/teavm/java/net/lax1dude/eaglercraft/v1_8/sp/server/internal/ServerPlatformSingleplayer.java
+++ b/sources/teavm/java/net/lax1dude/eaglercraft/v1_8/sp/server/internal/ServerPlatformSingleplayer.java
@@ -3,17 +3,36 @@ package net.lax1dude.eaglercraft.v1_8.sp.server.internal;
 import java.util.ArrayList;
 import java.util.LinkedList;
 import java.util.List;
+import java.util.Set;
+import java.util.function.Consumer;
 
+import org.teavm.interop.Async;
+import org.teavm.interop.AsyncCallback;
 import org.teavm.jso.JSBody;
 import org.teavm.jso.JSFunctor;
 import org.teavm.jso.JSObject;
+import org.teavm.jso.browser.Window;
+import org.teavm.jso.core.JSString;
+import org.teavm.jso.dom.events.EventListener;
+import org.teavm.jso.dom.events.MessageEvent;
 import org.teavm.jso.typedarrays.ArrayBuffer;
 
+import com.google.common.collect.Collections2;
+
+import net.lax1dude.eaglercraft.v1_8.EagUtils;
+import net.lax1dude.eaglercraft.v1_8.Filesystem;
 import net.lax1dude.eaglercraft.v1_8.internal.IClientConfigAdapter;
+import net.lax1dude.eaglercraft.v1_8.internal.IEaglerFilesystem;
 import net.lax1dude.eaglercraft.v1_8.internal.IPCPacketData;
-import net.lax1dude.eaglercraft.v1_8.internal.PlatformFilesystem;
+import net.lax1dude.eaglercraft.v1_8.internal.PlatformRuntime;
+import net.lax1dude.eaglercraft.v1_8.internal.teavm.ES6ShimStatus;
+import net.lax1dude.eaglercraft.v1_8.internal.teavm.EnumES6ShimStatus;
+import net.lax1dude.eaglercraft.v1_8.internal.teavm.EnumES6Shims;
+import net.lax1dude.eaglercraft.v1_8.internal.teavm.MessageChannel;
+import net.lax1dude.eaglercraft.v1_8.internal.teavm.TeaVMBlobURLManager;
 import net.lax1dude.eaglercraft.v1_8.internal.teavm.TeaVMClientConfigAdapter;
 import net.lax1dude.eaglercraft.v1_8.internal.teavm.TeaVMUtils;
+import net.lax1dude.eaglercraft.v1_8.internal.vfs2.VFile2;
 import net.lax1dude.eaglercraft.v1_8.log4j.LogManager;
 import net.lax1dude.eaglercraft.v1_8.log4j.Logger;
 
@@ -36,7 +55,17 @@ public class ServerPlatformSingleplayer {
 
 	private static final Logger logger = LogManager.getLogger("ServerPlatformSingleplayer");
 
-	private static final LinkedList<IPCPacketData> messageQueue = new LinkedList();
+	private static final LinkedList<IPCPacketData> messageQueue = new LinkedList<>();
+
+	private static boolean immediateContinueSupport = false;
+	private static MessageChannel immediateContinueChannel = null;
+	private static Runnable currentContinueHack = null;
+	private static final Object immediateContLock = new Object();
+	private static final JSString emptyJSString = JSString.valueOf("");
+	private static boolean singleThreadMode = false;
+	private static Consumer<IPCPacketData> singleThreadCB = null;
+
+	private static IEaglerFilesystem filesystem = null;
 
 	@JSFunctor
 	private static interface WorkerBinaryPacketHandler extends JSObject {
@@ -63,7 +92,7 @@ public class ServerPlatformSingleplayer {
 		
 	}
 
-	@JSBody(params = { "wb" }, script = "onmessage = function(o) { wb(o.data.ch, o.data.dat); };")
+	@JSBody(params = { "wb" }, script = "__eaglerXOnMessage = function(o) { wb(o.data.ch, o.data.dat); };")
 	private static native void registerPacketHandler(WorkerBinaryPacketHandler wb);
 
 	public static void register() {
@@ -71,14 +100,66 @@ public class ServerPlatformSingleplayer {
 	}
 
 	public static void initializeContext() {
-		PlatformFilesystem.initialize(getClientConfigAdapter().getWorldsDB());
+		singleThreadMode = false;
+		singleThreadCB = null;
+		ES6ShimStatus shimStatus = ES6ShimStatus.getRuntimeStatus();
+		if(shimStatus != null) {
+			EnumES6ShimStatus stat = shimStatus.getStatus();
+			switch(stat) {
+			case STATUS_ERROR:
+			case STATUS_DISABLED_ERRORS:
+				logger.error("ES6 Shim Status: {}", stat.statusDesc);
+				break;
+			case STATUS_ENABLED_ERRORS:
+				logger.error("ES6 Shim Status: {}", stat.statusDesc);
+				dumpShims(shimStatus.getShims());
+				break;
+			case STATUS_DISABLED:
+			case STATUS_NOT_PRESENT:
+				logger.info("ES6 Shim Status: {}", stat.statusDesc);
+				break;
+			case STATUS_ENABLED:
+				logger.info("ES6 Shim Status: {}", stat.statusDesc);
+				dumpShims(shimStatus.getShims());
+				break;
+			default:
+				break;
+			}
+		}
+		
+		TeaVMBlobURLManager.initialize();
+		
+		checkImmediateContinueSupport();
+		
+		filesystem = Filesystem.getHandleFor(getClientConfigAdapter().getWorldsDB());
+		VFile2.setPrimaryFilesystem(filesystem);
+	}
+
+	public static IEaglerFilesystem getWorldsDatabase() {
+		return filesystem;
+	}
+
+	public static void initializeContextSingleThread(Consumer<IPCPacketData> packetSendCallback) {
+		singleThreadMode = true;
+		singleThreadCB = packetSendCallback;
+		filesystem = Filesystem.getHandleFor(getClientConfigAdapter().getWorldsDB());
+	}
+
+	private static void dumpShims(Set<EnumES6Shims> shims) {
+		if(!shims.isEmpty()) {
+			logger.info("(Enabled {} shims: {})", shims.size(), String.join(", ", Collections2.transform(shims, (shim) -> shim.shimDesc)));
+		}
 	}
 
 	@JSBody(params = { "ch", "dat" }, script = "postMessage({ ch: ch, dat : dat });")
 	public static native void sendPacketTeaVM(String channel, ArrayBuffer arr);
 
 	public static void sendPacket(IPCPacketData packet) {
-		sendPacketTeaVM(packet.channel, TeaVMUtils.unwrapArrayBuffer(packet.contents));
+		if(singleThreadMode) {
+			singleThreadCB.accept(packet);
+		}else {
+			sendPacketTeaVM(packet.channel, TeaVMUtils.unwrapArrayBuffer(packet.contents));
+		}
 	}
 
 	public static List<IPCPacketData> recieveAllPacket() {
@@ -86,7 +167,7 @@ public class ServerPlatformSingleplayer {
 			if(messageQueue.size() == 0) {
 				return null;
 			}else {
-				List<IPCPacketData> ret = new ArrayList(messageQueue);
+				List<IPCPacketData> ret = new ArrayList<>(messageQueue);
 				messageQueue.clear();
 				return ret;
 			}
@@ -96,4 +177,118 @@ public class ServerPlatformSingleplayer {
 	public static IClientConfigAdapter getClientConfigAdapter() {
 		return TeaVMClientConfigAdapter.instance;
 	}
+
+	private static void checkImmediateContinueSupport() {
+		try {
+			immediateContinueSupport = false;
+			if(!MessageChannel.supported()) {
+				logger.error("Fast immediate continue will be disabled for server context due to MessageChannel being unsupported");
+				return;
+			}
+			immediateContinueChannel = MessageChannel.create();
+			immediateContinueChannel.getPort1().addEventListener("message", new EventListener<MessageEvent>() {
+				@Override
+				public void handleEvent(MessageEvent evt) {
+					Runnable toRun;
+					synchronized(immediateContLock) {
+						toRun = currentContinueHack;
+						currentContinueHack = null;
+					}
+					if(toRun != null) {
+						toRun.run();
+					}
+				}
+			});
+			immediateContinueChannel.getPort1().start();
+			immediateContinueChannel.getPort2().start();
+			final boolean[] checkMe = new boolean[1];
+			checkMe[0] = false;
+			currentContinueHack = () -> {
+				checkMe[0] = true;
+			};
+			immediateContinueChannel.getPort2().postMessage(emptyJSString);
+			if(checkMe[0]) {
+				currentContinueHack = null;
+				if(immediateContinueChannel != null) {
+					safeShutdownChannel(immediateContinueChannel);
+				}
+				immediateContinueChannel = null;
+				logger.error("Fast immediate continue will be disabled for server context due to actually continuing immediately");
+				return;
+			}
+			EagUtils.sleep(10l);
+			currentContinueHack = null;
+			if(!checkMe[0]) {
+				if(immediateContinueChannel != null) {
+					safeShutdownChannel(immediateContinueChannel);
+				}
+				immediateContinueChannel = null;
+				logger.error("Fast immediate continue will be disabled for server context due to startup check failing");
+			}else {
+				immediateContinueSupport = true;
+			}
+		}catch(Throwable t) {
+			logger.error("Fast immediate continue will be disabled for server context due to exceptions");
+			immediateContinueSupport = false;
+			if(immediateContinueChannel != null) {
+				safeShutdownChannel(immediateContinueChannel);
+			}
+			immediateContinueChannel = null;
+		}
+	}
+
+	private static void safeShutdownChannel(MessageChannel chan) {
+		try {
+			chan.getPort1().close();
+		}catch(Throwable tt) {
+		}
+		try {
+			chan.getPort2().close();
+		}catch(Throwable tt) {
+		}
+	}
+
+	public static void immediateContinue() {
+		if(singleThreadMode) {
+			PlatformRuntime.immediateContinue();
+		}else {
+			if(immediateContinueSupport) {
+				immediateContinueTeaVM();
+			}else {
+				EagUtils.sleep(0l);
+			}
+		}
+	}
+
+	@Async
+	private static native void immediateContinueTeaVM();
+	
+	private static void immediateContinueTeaVM(final AsyncCallback<Void> cb) {
+		synchronized(immediateContLock) {
+			if(currentContinueHack != null) {
+				cb.error(new IllegalStateException("Worker thread is already waiting for an immediate continue callback!"));
+				return;
+			}
+			currentContinueHack = () -> {
+				cb.complete(null);
+			};
+			try {
+				immediateContinueChannel.getPort2().postMessage(emptyJSString);
+			}catch(Throwable t) {
+				logger.error("Caught error posting immediate continue, using setTimeout instead");
+				Window.setTimeout(() -> cb.complete(null), 0);
+			}
+		}
+	}
+
+	public static boolean isSingleThreadMode() {
+		return singleThreadMode;
+	}
+
+	public static void recievePacketSingleThreadTeaVM(IPCPacketData pkt) {
+		synchronized(messageQueue) {
+			messageQueue.add(pkt);
+		}
+	}
+
 }
diff --git a/sources/teavm/java/net/lax1dude/eaglercraft/v1_8/sp/server/internal/teavm/SingleThreadWorker.java b/sources/teavm/java/net/lax1dude/eaglercraft/v1_8/sp/server/internal/teavm/SingleThreadWorker.java
new file mode 100644
index 00000000..9fa28c89
--- /dev/null
+++ b/sources/teavm/java/net/lax1dude/eaglercraft/v1_8/sp/server/internal/teavm/SingleThreadWorker.java
@@ -0,0 +1,44 @@
+package net.lax1dude.eaglercraft.v1_8.sp.server.internal.teavm;
+
+import java.util.function.Consumer;
+
+import net.lax1dude.eaglercraft.v1_8.internal.IPCPacketData;
+import net.lax1dude.eaglercraft.v1_8.log4j.LogManager;
+import net.lax1dude.eaglercraft.v1_8.log4j.Logger;
+import net.lax1dude.eaglercraft.v1_8.sp.server.EaglerIntegratedServerWorker;
+import net.lax1dude.eaglercraft.v1_8.sp.server.internal.ServerPlatformSingleplayer;
+
+/**
+ * Copyright (c) 2024 lax1dude. All Rights Reserved.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ * 
+ */
+public class SingleThreadWorker {
+
+	private static final Logger logger = LogManager.getLogger("SingleThreadWorker");
+
+	public static void singleThreadStartup(Consumer<IPCPacketData> packetSendCallback) {
+		logger.info("Starting single-thread mode worker...");
+		ServerPlatformSingleplayer.initializeContextSingleThread(packetSendCallback);
+		EaglerIntegratedServerWorker.singleThreadMain();
+	}
+
+	public static void sendPacketToWorker(IPCPacketData pkt) {
+		ServerPlatformSingleplayer.recievePacketSingleThreadTeaVM(pkt);
+	}
+
+	public static void singleThreadUpdate() {
+		EaglerIntegratedServerWorker.singleThreadUpdate();
+	}
+
+}
diff --git a/sources/teavm/java/net/lax1dude/eaglercraft/v1_8/sp/server/internal/teavm/WorkerMain.java b/sources/teavm/java/net/lax1dude/eaglercraft/v1_8/sp/server/internal/teavm/WorkerMain.java
index 2e9aa145..7a875de6 100644
--- a/sources/teavm/java/net/lax1dude/eaglercraft/v1_8/sp/server/internal/teavm/WorkerMain.java
+++ b/sources/teavm/java/net/lax1dude/eaglercraft/v1_8/sp/server/internal/teavm/WorkerMain.java
@@ -77,7 +77,7 @@ public class WorkerMain {
 		public void onMessage(String msg);
 	}
 
-	@JSBody(params = { "wb" }, script = "onmessage = function(o) { wb(o.data.msg); };")
+	@JSBody(params = { "wb" }, script = "__eaglerXOnMessage = function(o) { wb(o.data.msg); }; addEventListener(\"message\", function(evt) { __eaglerXOnMessage(evt); });")
 	private static native void setOnMessage(WorkerArgumentsPacketHandler cb);
 
 	@Async
diff --git a/sources/teavmc-classpath/resources/org/teavm/backend/javascript/long.js b/sources/teavmc-classpath/resources/org/teavm/backend/javascript/long.js
new file mode 100644
index 00000000..d6883c62
--- /dev/null
+++ b/sources/teavmc-classpath/resources/org/teavm/backend/javascript/long.js
@@ -0,0 +1,693 @@
+/*
+ *  Copyright 2018 Alexey Andreev.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+"use strict";
+
+var Long_divRem;
+var Long_udivRem;
+var Long_shiftLeft16;
+var Long_shiftRight16;
+var LongInt;
+var LongInt_mul;
+var LongInt_sub;
+var LongInt_add;
+var LongInt_inc;
+var LongInt_dec;
+var LongInt_ucompare;
+var LongInt_numOfLeadingZeroBits;
+var LongInt_shl;
+var LongInt_shr;
+var LongInt_copy;
+var LongInt_div;
+var Long_eq;
+var Long_ne;
+var Long_gt;
+var Long_ge;
+var Long_lt;
+var Long_le;
+var Long_compare;
+var Long_ucompare;
+var Long_add;
+var Long_sub;
+var Long_inc;
+var Long_dec;
+var Long_mul;
+var Long_div;
+var Long_rem;
+var Long_udiv;
+var Long_urem;
+var Long_neg;
+var Long_and;
+var Long_or;
+var Long_xor;
+var Long_shl;
+var Long_shr;
+var Long_shru;
+var Long_not;
+
+if (typeof BigInt !== 'function') {
+    Long_eq = function(a, b) {
+        return a.hi === b.hi && a.lo === b.lo;
+    }
+
+    Long_ne = function(a, b) {
+        return a.hi !== b.hi || a.lo !== b.lo;
+    }
+
+    Long_gt = function(a, b) {
+        if (a.hi < b.hi) {
+            return false;
+        }
+        if (a.hi > b.hi) {
+            return true;
+        }
+        var x = a.lo >>> 1;
+        var y = b.lo >>> 1;
+        if (x !== y) {
+            return x > y;
+        }
+        return (a.lo & 1) > (b.lo & 1);
+    }
+
+    Long_ge = function(a, b) {
+        if (a.hi < b.hi) {
+            return false;
+        }
+        if (a.hi > b.hi) {
+            return true;
+        }
+        var x = a.lo >>> 1;
+        var y = b.lo >>> 1;
+        if (x !== y) {
+            return x >= y;
+        }
+        return (a.lo & 1) >= (b.lo & 1);
+    }
+
+    Long_lt = function(a, b) {
+        if (a.hi > b.hi) {
+            return false;
+        }
+        if (a.hi < b.hi) {
+            return true;
+        }
+        var x = a.lo >>> 1;
+        var y = b.lo >>> 1;
+        if (x !== y) {
+            return x < y;
+        }
+        return (a.lo & 1) < (b.lo & 1);
+    }
+
+    Long_le = function(a, b) {
+        if (a.hi > b.hi) {
+            return false;
+        }
+        if (a.hi < b.hi) {
+            return true;
+        }
+        var x = a.lo >>> 1;
+        var y = b.lo >>> 1;
+        if (x !== y) {
+            return x <= y;
+        }
+        return (a.lo & 1) <= (b.lo & 1);
+    }
+
+    Long_add = function(a, b) {
+        if (a.hi === (a.lo >> 31) && b.hi === (b.lo >> 31)) {
+            return Long_fromNumber(a.lo + b.lo);
+        } else if (Math.abs(a.hi) < Long_MAX_NORMAL && Math.abs(b.hi) < Long_MAX_NORMAL) {
+            return Long_fromNumber(Long_toNumber(a) + Long_toNumber(b));
+        }
+        var a_lolo = a.lo & 0xFFFF;
+        var a_lohi = a.lo >>> 16;
+        var a_hilo = a.hi & 0xFFFF;
+        var a_hihi = a.hi >>> 16;
+        var b_lolo = b.lo & 0xFFFF;
+        var b_lohi = b.lo >>> 16;
+        var b_hilo = b.hi & 0xFFFF;
+        var b_hihi = b.hi >>> 16;
+
+        var lolo = (a_lolo + b_lolo) | 0;
+        var lohi = (a_lohi + b_lohi + (lolo >> 16)) | 0;
+        var hilo = (a_hilo + b_hilo + (lohi >> 16)) | 0;
+        var hihi = (a_hihi + b_hihi + (hilo >> 16)) | 0;
+        return new Long((lolo & 0xFFFF) | ((lohi & 0xFFFF) << 16), (hilo & 0xFFFF) | ((hihi & 0xFFFF) << 16));
+    }
+
+    Long_inc = function(a) {
+        var lo = (a.lo + 1) | 0;
+        var hi = a.hi;
+        if (lo === 0) {
+            hi = (hi + 1) | 0;
+        }
+        return new Long(lo, hi);
+    }
+
+    Long_dec = function(a) {
+        var lo = (a.lo - 1) | 0;
+        var hi = a.hi;
+        if (lo === -1) {
+            hi = (hi - 1) | 0;
+        }
+        return new Long(lo, hi);
+    }
+
+    Long_neg = function(a) {
+        return Long_inc(new Long(a.lo ^ 0xFFFFFFFF, a.hi ^ 0xFFFFFFFF));
+    }
+
+    Long_sub = function(a, b) {
+        if (a.hi === (a.lo >> 31) && b.hi === (b.lo >> 31)) {
+            return Long_fromNumber(a.lo - b.lo);
+        }
+        var a_lolo = a.lo & 0xFFFF;
+        var a_lohi = a.lo >>> 16;
+        var a_hilo = a.hi & 0xFFFF;
+        var a_hihi = a.hi >>> 16;
+        var b_lolo = b.lo & 0xFFFF;
+        var b_lohi = b.lo >>> 16;
+        var b_hilo = b.hi & 0xFFFF;
+        var b_hihi = b.hi >>> 16;
+
+        var lolo = (a_lolo - b_lolo) | 0;
+        var lohi = (a_lohi - b_lohi + (lolo >> 16)) | 0;
+        var hilo = (a_hilo - b_hilo + (lohi >> 16)) | 0;
+        var hihi = (a_hihi - b_hihi + (hilo >> 16)) | 0;
+        return new Long((lolo & 0xFFFF) | ((lohi & 0xFFFF) << 16), (hilo & 0xFFFF) | ((hihi & 0xFFFF) << 16));
+    }
+
+    Long_compare = function(a, b) {
+        var r = a.hi - b.hi;
+        if (r !== 0) {
+            return r;
+        }
+        r = (a.lo >>> 1) - (b.lo >>> 1);
+        if (r !== 0) {
+            return r;
+        }
+        return (a.lo & 1) - (b.lo & 1);
+    }
+
+    Long_ucompare = function(a, b) {
+        var r = $rt_ucmp(a.hi, b.hi);
+        if (r !== 0) {
+            return r;
+        }
+        r = (a.lo >>> 1) - (b.lo >>> 1);
+        if (r !== 0) {
+            return r;
+        }
+        return (a.lo & 1) - (b.lo & 1);
+    }
+
+    Long_mul = function(a, b) {
+        var positive = Long_isNegative(a) === Long_isNegative(b);
+        if (Long_isNegative(a)) {
+            a = Long_neg(a);
+        }
+        if (Long_isNegative(b)) {
+            b = Long_neg(b);
+        }
+        var a_lolo = a.lo & 0xFFFF;
+        var a_lohi = a.lo >>> 16;
+        var a_hilo = a.hi & 0xFFFF;
+        var a_hihi = a.hi >>> 16;
+        var b_lolo = b.lo & 0xFFFF;
+        var b_lohi = b.lo >>> 16;
+        var b_hilo = b.hi & 0xFFFF;
+        var b_hihi = b.hi >>> 16;
+
+        var lolo = 0;
+        var lohi = 0;
+        var hilo = 0;
+        var hihi = 0;
+        lolo = (a_lolo * b_lolo) | 0;
+        lohi = lolo >>> 16;
+        lohi = ((lohi & 0xFFFF) + a_lohi * b_lolo) | 0;
+        hilo = (hilo + (lohi >>> 16)) | 0;
+        lohi = ((lohi & 0xFFFF) + a_lolo * b_lohi) | 0;
+        hilo = (hilo + (lohi >>> 16)) | 0;
+        hihi = hilo >>> 16;
+        hilo = ((hilo & 0xFFFF) + a_hilo * b_lolo) | 0;
+        hihi = (hihi + (hilo >>> 16)) | 0;
+        hilo = ((hilo & 0xFFFF) + a_lohi * b_lohi) | 0;
+        hihi = (hihi + (hilo >>> 16)) | 0;
+        hilo = ((hilo & 0xFFFF) + a_lolo * b_hilo) | 0;
+        hihi = (hihi + (hilo >>> 16)) | 0;
+        hihi = (hihi + a_hihi * b_lolo + a_hilo * b_lohi + a_lohi * b_hilo + a_lolo * b_hihi) | 0;
+        var result = new Long((lolo & 0xFFFF) | (lohi << 16), (hilo & 0xFFFF) | (hihi << 16));
+        return positive ? result : Long_neg(result);
+    }
+
+    Long_div = function(a, b) {
+        if (Math.abs(a.hi) < Long_MAX_NORMAL && Math.abs(b.hi) < Long_MAX_NORMAL) {
+            return Long_fromNumber(Long_toNumber(a) / Long_toNumber(b));
+        }
+        return Long_divRem(a, b)[0];
+    }
+
+    Long_udiv = function(a, b) {
+        if (a.hi >= 0 && a.hi < Long_MAX_NORMAL && b.hi >= 0 && b.hi < Long_MAX_NORMAL) {
+            return Long_fromNumber(Long_toNumber(a) / Long_toNumber(b));
+        }
+        return Long_udivRem(a, b)[0];
+    }
+
+    Long_rem = function(a, b) {
+        if (Math.abs(a.hi) < Long_MAX_NORMAL && Math.abs(b.hi) < Long_MAX_NORMAL) {
+            return Long_fromNumber(Long_toNumber(a) % Long_toNumber(b));
+        }
+        return Long_divRem(a, b)[1];
+    }
+
+    Long_urem = function(a, b) {
+        if (a.hi >= 0 && a.hi < Long_MAX_NORMAL && b.hi >= 0 && b.hi < Long_MAX_NORMAL) {
+            return Long_fromNumber(Long_toNumber(a) / Long_toNumber(b));
+        }
+        return Long_udivRem(a, b)[1];
+    }
+
+    Long_divRem = function(a, b) {
+        if (b.lo === 0 && b.hi === 0) {
+            throw new Error("Division by zero");
+        }
+        var positive = Long_isNegative(a) === Long_isNegative(b);
+        if (Long_isNegative(a)) {
+            a = Long_neg(a);
+        }
+        if (Long_isNegative(b)) {
+            b = Long_neg(b);
+        }
+        a = new LongInt(a.lo, a.hi, 0);
+        b = new LongInt(b.lo, b.hi, 0);
+        var q = LongInt_div(a, b);
+        a = new Long(a.lo, a.hi);
+        q = new Long(q.lo, q.hi);
+        return positive ? [q, a] : [Long_neg(q), Long_neg(a)];
+    };
+
+    Long_udivRem = function(a, b) {
+        if (b.lo === 0 && b.hi === 0) {
+            throw new Error("Division by zero");
+        }
+        a = new LongInt(a.lo, a.hi, 0);
+        b = new LongInt(b.lo, b.hi, 0);
+        var q = LongInt_div(a, b);
+        a = new Long(a.lo, a.hi);
+        q = new Long(q.lo, q.hi);
+        return [q, a];
+    };
+
+    Long_shiftLeft16 = function(a) {
+        return new Long(a.lo << 16, (a.lo >>> 16) | (a.hi << 16));
+    };
+
+    Long_shiftRight16 = function(a) {
+        return new Long((a.lo >>> 16) | (a.hi << 16), a.hi >>> 16);
+    };
+
+    Long_and = function(a, b) {
+        return new Long(a.lo & b.lo, a.hi & b.hi);
+    }
+
+    Long_or = function(a, b) {
+        return new Long(a.lo | b.lo, a.hi | b.hi);
+    }
+
+    Long_xor = function(a, b) {
+        return new Long(a.lo ^ b.lo, a.hi ^ b.hi);
+    }
+
+    Long_shl = function(a, b) {
+        b &= 63;
+        if (b === 0) {
+            return a;
+        } else if (b < 32) {
+            return new Long(a.lo << b, (a.lo >>> (32 - b)) | (a.hi << b));
+        } else if (b === 32) {
+            return new Long(0, a.lo);
+        } else {
+            return new Long(0, a.lo << (b - 32));
+        }
+    }
+
+    Long_shr = function(a, b) {
+        b &= 63;
+        if (b === 0) {
+            return a;
+        } else if (b < 32) {
+            return new Long((a.lo >>> b) | (a.hi << (32 - b)), a.hi >> b);
+        } else if (b === 32) {
+            return new Long(a.hi, a.hi >> 31);
+        } else {
+            return new Long((a.hi >> (b - 32)), a.hi >> 31);
+        }
+    }
+
+    Long_shru = function(a, b) {
+        b &= 63;
+        if (b === 0) {
+            return a;
+        } else if (b < 32) {
+            return new Long((a.lo >>> b) | (a.hi << (32 - b)), a.hi >>> b);
+        } else if (b === 32) {
+            return new Long(a.hi, 0);
+        } else {
+            return new Long((a.hi >>> (b - 32)), 0);
+        }
+    }
+
+    Long_not = function(a) {
+        return new Long(~a.hi, ~a.lo);
+    }
+
+    // Represents a mutable 80-bit unsigned integer
+    LongInt = function(lo, hi, sup) {
+        this.lo = lo;
+        this.hi = hi;
+        this.sup = sup;
+    };
+
+    LongInt_mul = function(a, b) {
+        var a_lolo = ((a.lo & 0xFFFF) * b) | 0;
+        var a_lohi = ((a.lo >>> 16) * b) | 0;
+        var a_hilo = ((a.hi & 0xFFFF) * b) | 0;
+        var a_hihi = ((a.hi >>> 16) * b) | 0;
+        var sup = (a.sup * b) | 0;
+
+        a_lohi = (a_lohi + (a_lolo >>> 16)) | 0;
+        a_hilo = (a_hilo + (a_lohi >>> 16)) | 0;
+        a_hihi = (a_hihi + (a_hilo >>> 16)) | 0;
+        sup = (sup + (a_hihi >>> 16)) | 0;
+        a.lo = (a_lolo & 0xFFFF) | (a_lohi << 16);
+        a.hi = (a_hilo & 0xFFFF) | (a_hihi << 16);
+        a.sup = sup & 0xFFFF;
+    };
+
+    LongInt_sub = function(a, b) {
+        var a_lolo = a.lo & 0xFFFF;
+        var a_lohi = a.lo >>> 16;
+        var a_hilo = a.hi & 0xFFFF;
+        var a_hihi = a.hi >>> 16;
+        var b_lolo = b.lo & 0xFFFF;
+        var b_lohi = b.lo >>> 16;
+        var b_hilo = b.hi & 0xFFFF;
+        var b_hihi = b.hi >>> 16;
+
+        a_lolo = (a_lolo - b_lolo) | 0;
+        a_lohi = (a_lohi - b_lohi + (a_lolo >> 16)) | 0;
+        a_hilo = (a_hilo - b_hilo + (a_lohi >> 16)) | 0;
+        a_hihi = (a_hihi - b_hihi + (a_hilo >> 16)) | 0;
+        var sup = (a.sup - b.sup + (a_hihi >> 16)) | 0;
+        a.lo = (a_lolo & 0xFFFF) | (a_lohi << 16);
+        a.hi = (a_hilo & 0xFFFF) | (a_hihi << 16);
+        a.sup = sup;
+    };
+
+    LongInt_add = function(a, b) {
+        var a_lolo = a.lo & 0xFFFF;
+        var a_lohi = a.lo >>> 16;
+        var a_hilo = a.hi & 0xFFFF;
+        var a_hihi = a.hi >>> 16;
+        var b_lolo = b.lo & 0xFFFF;
+        var b_lohi = b.lo >>> 16;
+        var b_hilo = b.hi & 0xFFFF;
+        var b_hihi = b.hi >>> 16;
+
+        a_lolo = (a_lolo + b_lolo) | 0;
+        a_lohi = (a_lohi + b_lohi + (a_lolo >> 16)) | 0;
+        a_hilo = (a_hilo + b_hilo + (a_lohi >> 16)) | 0;
+        a_hihi = (a_hihi + b_hihi + (a_hilo >> 16)) | 0;
+        var sup = (a.sup + b.sup + (a_hihi >> 16)) | 0;
+        a.lo = (a_lolo & 0xFFFF) | (a_lohi << 16);
+        a.hi = (a_hilo & 0xFFFF) | (a_hihi << 16);
+        a.sup = sup;
+    };
+
+    LongInt_inc = function(a) {
+        a.lo = (a.lo + 1) | 0;
+        if (a.lo === 0) {
+            a.hi = (a.hi + 1) | 0;
+            if (a.hi === 0) {
+                a.sup = (a.sup + 1) & 0xFFFF;
+            }
+        }
+    };
+
+    LongInt_dec = function(a) {
+        a.lo = (a.lo - 1) | 0;
+        if (a.lo === -1) {
+            a.hi = (a.hi - 1) | 0;
+            if (a.hi === -1) {
+                a.sup = (a.sup - 1) & 0xFFFF;
+            }
+        }
+    };
+
+    LongInt_ucompare = function(a, b) {
+        var r = (a.sup - b.sup);
+        if (r !== 0) {
+            return r;
+        }
+        r = (a.hi >>> 1) - (b.hi >>> 1);
+        if (r !== 0) {
+            return r;
+        }
+        r = (a.hi & 1) - (b.hi & 1);
+        if (r !== 0) {
+            return r;
+        }
+        r = (a.lo >>> 1) - (b.lo >>> 1);
+        if (r !== 0) {
+            return r;
+        }
+        return (a.lo & 1) - (b.lo & 1);
+    };
+
+    LongInt_numOfLeadingZeroBits = function(a) {
+        var n = 0;
+        var d = 16;
+        while (d > 0) {
+            if ((a >>> d) !== 0) {
+                a >>>= d;
+                n = (n + d) | 0;
+            }
+            d = (d / 2) | 0;
+        }
+        return 31 - n;
+    };
+
+    LongInt_shl = function(a, b) {
+        if (b === 0) {
+            return;
+        }
+        if (b < 32) {
+            a.sup = ((a.hi >>> (32 - b)) | (a.sup << b)) & 0xFFFF;
+            a.hi = (a.lo >>> (32 - b)) | (a.hi << b);
+            a.lo <<= b;
+        } else if (b === 32) {
+            a.sup = a.hi & 0xFFFF;
+            a.hi = a.lo;
+            a.lo = 0;
+        } else if (b < 64) {
+            a.sup = ((a.lo >>> (64 - b)) | (a.hi << (b - 32))) & 0xFFFF;
+            a.hi = a.lo << b;
+            a.lo = 0;
+        } else if (b === 64) {
+            a.sup = a.lo & 0xFFFF;
+            a.hi = 0;
+            a.lo = 0;
+        } else {
+            a.sup = (a.lo << (b - 64)) & 0xFFFF;
+            a.hi = 0;
+            a.lo = 0;
+        }
+    };
+
+    LongInt_shr = function(a, b) {
+        if (b === 0) {
+            return;
+        }
+        if (b === 32) {
+            a.lo = a.hi;
+            a.hi = a.sup;
+            a.sup = 0;
+        } else if (b < 32) {
+            a.lo = (a.lo >>> b) | (a.hi << (32 - b));
+            a.hi = (a.hi >>> b) | (a.sup << (32 - b));
+            a.sup >>>= b;
+        } else if (b === 64) {
+            a.lo = a.sup;
+            a.hi = 0;
+            a.sup = 0;
+        } else if (b < 64) {
+            a.lo = (a.hi >>> (b - 32)) | (a.sup << (64 - b));
+            a.hi = a.sup >>> (b - 32);
+            a.sup = 0;
+        } else {
+            a.lo = a.sup >>> (b - 64);
+            a.hi = 0;
+            a.sup = 0;
+        }
+    };
+
+    LongInt_copy = function(a) {
+        return new LongInt(a.lo, a.hi, a.sup);
+    };
+
+    LongInt_div = function(a, b) {
+        // Normalize divisor
+        var bits = b.hi !== 0 ? LongInt_numOfLeadingZeroBits(b.hi) : LongInt_numOfLeadingZeroBits(b.lo) + 32;
+        var sz = 1 + ((bits / 16) | 0);
+        var dividentBits = bits % 16;
+        LongInt_shl(b, bits);
+        LongInt_shl(a, dividentBits);
+        var q = new LongInt(0, 0, 0);
+        while (sz-- > 0) {
+            LongInt_shl(q, 16);
+            // Calculate approximate q
+            var digitA = (a.hi >>> 16) + (0x10000 * a.sup);
+            var digitB = b.hi >>> 16;
+            var digit = (digitA / digitB) | 0;
+            var t = LongInt_copy(b);
+            LongInt_mul(t, digit);
+            // Adjust q either down or up
+            if (LongInt_ucompare(t, a) >= 0) {
+                while (LongInt_ucompare(t, a) > 0) {
+                    LongInt_sub(t, b);
+                    --digit;
+                }
+            } else {
+                while (true) {
+                    var nextT = LongInt_copy(t);
+                    LongInt_add(nextT, b);
+                    if (LongInt_ucompare(nextT, a) > 0) {
+                        break;
+                    }
+                    t = nextT;
+                    ++digit;
+                }
+            }
+            LongInt_sub(a, t);
+            q.lo |= digit;
+            LongInt_shl(a, 16);
+        }
+        LongInt_shr(a, bits + 16);
+        return q;
+    };
+} else {
+    Long_eq = function(a, b) {
+        return a === b;
+    }
+
+    Long_ne = function(a, b) {
+        return a !== b;
+    }
+
+    Long_gt = function(a, b) {
+        return a > b;
+    }
+
+    Long_ge = function(a, b) {
+        return a >= b;
+    }
+
+    Long_lt = function(a, b) {
+        return a < b;
+    }
+
+    Long_le = function(a, b) {
+        return a <= b;
+    }
+
+    Long_add = function(a, b) {
+        return BigInt.asIntN(64, a + b);
+    }
+
+    Long_inc = function(a) {
+        return BigInt.asIntN(64, a + 1);
+    }
+
+    Long_dec = function(a) {
+        return BigInt.asIntN(64, a - 1);
+    }
+
+    Long_neg = function(a) {
+        return BigInt.asIntN(64, -a);
+    }
+
+    Long_sub = function(a, b) {
+        return BigInt.asIntN(64, a - b);
+    }
+
+    Long_compare = function(a, b) {
+        return a < b ? -1 : a > b ? 1 : 0;
+    }
+    Long_ucompare = function(a, b) {
+        a = BigInt.asUintN(64, a);
+        b = BigInt.asUintN(64, b);
+        return a < b ? -1 : a > b ? 1 : 0;
+    }
+
+    Long_mul = function(a, b) {
+        return BigInt.asIntN(64, a * b);
+    }
+
+    Long_div = function(a, b) {
+        return BigInt.asIntN(64, a / b);
+    }
+
+    Long_udiv = function(a, b) {
+        return BigInt.asIntN(64, BigInt.asUintN(64, a) / BigInt.asUintN(64, b));
+    }
+
+    Long_rem = function(a, b) {
+        return BigInt.asIntN(64, a % b);
+    }
+
+    Long_urem = function(a, b) {
+        return BigInt.asIntN(64, BigInt.asUintN(64, a) % BigInt.asUintN(64, b));
+    }
+
+    Long_and = function(a, b) {
+        return BigInt.asIntN(64, a & b);
+    }
+
+    Long_or = function(a, b) {
+        return BigInt.asIntN(64, a | b);
+    }
+
+    Long_xor = function(a, b) {
+        return BigInt.asIntN(64, a ^ b);
+    }
+
+    Long_shl = function(a, b) {
+        return BigInt.asIntN(64, a << BigInt(b & 63));
+    }
+
+    Long_shr = function(a, b) {
+        return BigInt.asIntN(64, a >> BigInt(b & 63));
+    }
+
+    Long_shru = function(a, b) {
+        return BigInt.asIntN(64, BigInt.asUintN(64, a) >> BigInt(b & 63));
+    }
+
+    Long_not = function(a) {
+        return BigInt.asIntN(64, ~a);
+    }
+}