From b9091e946635f7ae592e6a9ebe3708e2c8bdaf6b Mon Sep 17 00:00:00 2001 From: Michael Scire Date: Sat, 10 Nov 2018 00:11:38 -0800 Subject: [PATCH 01/33] fatal: Implement fatal:p, fatal:u stub. --- Makefile | 2 + stratosphere/Makefile | 2 +- stratosphere/fatal/Makefile | 159 ++++++++++++++++++ stratosphere/fatal/fatal.json | 87 ++++++++++ .../fatal/source/fatal_event_manager.cpp | 45 +++++ .../fatal/source/fatal_event_manager.hpp | 32 ++++ stratosphere/fatal/source/fatal_main.cpp | 97 +++++++++++ stratosphere/fatal/source/fatal_private.cpp | 25 +++ stratosphere/fatal/source/fatal_private.hpp | 33 ++++ stratosphere/fatal/source/fatal_types.hpp | 97 +++++++++++ stratosphere/fatal/source/fatal_user.cpp | 43 +++++ stratosphere/fatal/source/fatal_user.hpp | 43 +++++ 12 files changed, 664 insertions(+), 1 deletion(-) create mode 100644 stratosphere/fatal/Makefile create mode 100644 stratosphere/fatal/fatal.json create mode 100644 stratosphere/fatal/source/fatal_event_manager.cpp create mode 100644 stratosphere/fatal/source/fatal_event_manager.hpp create mode 100644 stratosphere/fatal/source/fatal_main.cpp create mode 100644 stratosphere/fatal/source/fatal_private.cpp create mode 100644 stratosphere/fatal/source/fatal_private.hpp create mode 100644 stratosphere/fatal/source/fatal_types.hpp create mode 100644 stratosphere/fatal/source/fatal_user.cpp create mode 100644 stratosphere/fatal/source/fatal_user.hpp diff --git a/Makefile b/Makefile index 7eeab49b6..18410a3af 100644 --- a/Makefile +++ b/Makefile @@ -40,11 +40,13 @@ dist: all mkdir atmosphere-$(AMSVER) mkdir atmosphere-$(AMSVER)/atmosphere mkdir -p atmosphere-$(AMSVER)/atmosphere/titles/0100000000000036 + mkdir -p atmosphere-$(AMSVER)/atmosphere/titles/0100000000000034 mkdir -p atmosphere-$(AMSVER)/atmosphere/titles/0100000000000032 cp fusee/fusee-secondary/fusee-secondary.bin atmosphere-$(AMSVER)/fusee-secondary.bin cp common/defaults/BCT.ini atmosphere-$(AMSVER)/BCT.ini cp common/defaults/loader.ini atmosphere-$(AMSVER)/atmosphere/loader.ini cp stratosphere/creport/creport.nsp atmosphere-$(AMSVER)/atmosphere/titles/0100000000000036/exefs.nsp + cp stratosphere/fatal/fatal.nsp atmosphere-$(AMSVER)/atmosphere/titles/0100000000000034/exefs.nsp cp stratosphere/set_mitm/set_mitm.nsp atmosphere-$(AMSVER)/atmosphere/titles/0100000000000032/exefs.nsp touch atmosphere-$(AMSVER)/atmosphere/titles/0100000000000032/boot2.flag cd atmosphere-$(AMSVER); zip -r ../atmosphere-$(AMSVER).zip ./*; cd ../; diff --git a/stratosphere/Makefile b/stratosphere/Makefile index 559327b9e..61e6a119c 100644 --- a/stratosphere/Makefile +++ b/stratosphere/Makefile @@ -1,4 +1,4 @@ -KIPS := loader pm sm boot fs_mitm set_mitm creport +KIPS := loader pm sm boot fs_mitm set_mitm creport fatal #TODO: boot2 ? diff --git a/stratosphere/fatal/Makefile b/stratosphere/fatal/Makefile new file mode 100644 index 000000000..c042e968d --- /dev/null +++ b/stratosphere/fatal/Makefile @@ -0,0 +1,159 @@ +#--------------------------------------------------------------------------------- +.SUFFIXES: +#--------------------------------------------------------------------------------- + +ifeq ($(strip $(DEVKITPRO)),) +$(error "Please set DEVKITPRO in your environment. export DEVKITPRO=/devkitpro") +endif + +TOPDIR ?= $(CURDIR) +include $(DEVKITPRO)/libnx/switch_rules + +#--------------------------------------------------------------------------------- +# TARGET is the name of the output +# BUILD is the directory where object files & intermediate files will be placed +# SOURCES is a list of directories containing source code +# DATA is a list of directories containing data files +# INCLUDES is a list of directories containing header files +# EXEFS_SRC is the optional input directory containing data copied into exefs, if anything this normally should only contain "main.npdm". +#--------------------------------------------------------------------------------- +TARGET := $(notdir $(CURDIR)) +BUILD := build +SOURCES := source +DATA := data +INCLUDES := include ../../common/include +EXEFS_SRC := exefs_src + +DEFINES := -DDISABLE_IPC + +#--------------------------------------------------------------------------------- +# options for code generation +#--------------------------------------------------------------------------------- +ARCH := -march=armv8-a -mtune=cortex-a57 -mtp=soft -fPIE + +CFLAGS := -g -Wall -O2 -ffunction-sections \ + $(ARCH) $(DEFINES) + +CFLAGS += $(INCLUDE) -D__SWITCH__ + +CXXFLAGS := $(CFLAGS) -fno-rtti -fno-exceptions -std=gnu++17 + +ASFLAGS := -g $(ARCH) +LDFLAGS = -specs=$(DEVKITPRO)/libnx/switch.specs -g $(ARCH) -Wl,-Map,$(notdir $*.map) + +LIBS := -lstratosphere -lnx + +#--------------------------------------------------------------------------------- +# list of directories containing libraries, this must be the top level containing +# include and lib +#--------------------------------------------------------------------------------- +LIBDIRS := $(PORTLIBS) $(LIBNX) $(CURDIR)/../libstratosphere + + +#--------------------------------------------------------------------------------- +# no real need to edit anything past this point unless you need to add additional +# rules for different file extensions +#--------------------------------------------------------------------------------- +ifneq ($(BUILD),$(notdir $(CURDIR))) +#--------------------------------------------------------------------------------- + +export OUTPUT := $(CURDIR)/$(TARGET) +export TOPDIR := $(CURDIR) + +export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \ + $(foreach dir,$(DATA),$(CURDIR)/$(dir)) + +export DEPSDIR := $(CURDIR)/$(BUILD) + +CFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c))) +CPPFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.cpp))) +SFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.s))) +BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*))) + +#--------------------------------------------------------------------------------- +# use CXX for linking C++ projects, CC for standard C +#--------------------------------------------------------------------------------- +ifeq ($(strip $(CPPFILES)),) +#--------------------------------------------------------------------------------- + export LD := $(CC) +#--------------------------------------------------------------------------------- +else +#--------------------------------------------------------------------------------- + export LD := $(CXX) +#--------------------------------------------------------------------------------- +endif +#--------------------------------------------------------------------------------- + +export OFILES := $(addsuffix .o,$(BINFILES)) \ + $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o) + +export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \ + $(foreach dir,$(LIBDIRS),-I$(dir)/include) \ + -I$(CURDIR)/$(BUILD) + +export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib) + +export BUILD_EXEFS_SRC := $(TOPDIR)/$(EXEFS_SRC) + +ifeq ($(strip $(CONFIG_JSON)),) + jsons := $(wildcard *.json) + ifneq (,$(findstring $(TARGET).json,$(jsons))) + export APP_JSON := $(TOPDIR)/$(TARGET).json + else + ifneq (,$(findstring config.json,$(jsons))) + export APP_JSON := $(TOPDIR)/config.json + endif + endif +else + export APP_JSON := $(TOPDIR)/$(CONFIG_JSON) +endif + +.PHONY: $(BUILD) clean all + +#--------------------------------------------------------------------------------- +all: $(BUILD) + +$(BUILD): + @[ -d $@ ] || mkdir -p $@ + @$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile + +#--------------------------------------------------------------------------------- +clean: + @echo clean ... + @rm -fr $(BUILD) $(TARGET).nsp $(TARGET).npdm $(TARGET).nso $(TARGET).elf + + +#--------------------------------------------------------------------------------- +else +.PHONY: all + +DEPENDS := $(OFILES:.o=.d) + +#--------------------------------------------------------------------------------- +# main targets +#--------------------------------------------------------------------------------- +all : $(OUTPUT).nsp + +ifeq ($(strip $(APP_JSON)),) +$(OUTPUT).nsp : $(OUTPUT).nso +else +$(OUTPUT).nsp : $(OUTPUT).nso $(OUTPUT).npdm +endif + +$(OUTPUT).nso : $(OUTPUT).elf + +$(OUTPUT).elf : $(OFILES) + +#--------------------------------------------------------------------------------- +# you need a rule like this for each extension you use as binary data +#--------------------------------------------------------------------------------- +%.bin.o : %.bin +#--------------------------------------------------------------------------------- + @echo $(notdir $<) + @$(bin2o) + +-include $(DEPENDS) + +#--------------------------------------------------------------------------------------- +endif +#--------------------------------------------------------------------------------------- diff --git a/stratosphere/fatal/fatal.json b/stratosphere/fatal/fatal.json new file mode 100644 index 000000000..2d4388785 --- /dev/null +++ b/stratosphere/fatal/fatal.json @@ -0,0 +1,87 @@ +{ + "name": "fatal", + "title_id": "0x0100000000000034", + "title_id_range_min": "0x0100000000000034", + "title_id_range_max": "0x0100000000000034", + "main_thread_stack_size": "0x00010000", + "main_thread_priority": 15, + "default_cpu_id": 3, + "process_category": 0, + "is_retail": true, + "pool_partition": 2, + "is_64_bit": true, + "address_space_type": 3, + "filesystem_access": { + "permissions": "0x0000000000100000" + }, + "service_access": ["bpc", "erpt:c", "fsp-srv", "gpio", "i2c", "lbl", "lm", "nvdrv:s", "pcv", "pl:u", "pm:info", "psm", "set", "set:sys", "spsm", "vi:m", "vi:s"], + "service_host": ["fatal:p", "fatal:u"], + "kernel_capabilities": [{ + "type": "kernel_flags", + "value": { + "highest_thread_priority": 63, + "lowest_thread_priority": 12, + "lowest_cpu_id": 0, + "highest_cpu_id": 3 + } + }, { + "type": "syscalls", + "value": { + "svcSetHeapSize": "0x01", + "svcSetMemoryPermission": "0x02", + "svcSetMemoryAttribute": "0x03", + "svcMapMemory": "0x04", + "svcUnmapMemory": "0x05", + "svcQueryMemory": "0x06", + "svcExitProcess": "0x07", + "svcCreateThread": "0x08", + "svcStartThread": "0x09", + "svcExitThread": "0x0a", + "svcSleepThread": "0x0b", + "svcGetThreadPriority": "0x0c", + "svcSetThreadPriority": "0x0d", + "svcGetThreadCoreMask": "0x0e", + "svcSetThreadCoreMask": "0x0f", + "svcGetCurrentProcessorNumber": "0x10", + "svcSignalEvent": "0x11", + "svcClearEvent": "0x12", + "svcMapSharedMemory": "0x13", + "svcUnmapSharedMemory": "0x14", + "svcCreateTransferMemory": "0x15", + "svcCloseHandle": "0x16", + "svcResetSignal": "0x17", + "svcWaitSynchronization": "0x18", + "svcCancelSynchronization": "0x19", + "svcArbitrateLock": "0x1a", + "svcArbitrateUnlock": "0x1b", + "svcWaitProcessWideKeyAtomic": "0x1c", + "svcSignalProcessWideKey": "0x1d", + "svcGetSystemTick": "0x1e", + "svcConnectToNamedPort": "0x1f", + "svcSendSyncRequestLight": "0x20", + "svcSendSyncRequest": "0x21", + "svcSendSyncRequestWithUserBuffer": "0x22", + "svcSendAsyncRequestWithUserBuffer": "0x23", + "svcGetProcessId": "0x24", + "svcGetThreadId": "0x25", + "svcBreak": "0x26", + "svcOutputDebugString": "0x27", + "svcReturnFromException": "0x28", + "svcGetInfo": "0x29", + "svcWaitForAddress": "0x34", + "svcSignalToAddress": "0x35", + "svcCreateSession": "0x40", + "svcAcceptSession": "0x41", + "svcReplyAndReceiveLight": "0x42", + "svcReplyAndReceive": "0x43", + "svcReplyAndReceiveWithUserBuffer": "0x44", + "svcCreateEvent": "0x45" + } + }, { + "type": "min_kernel_version", + "value": "0x0060" + }, { + "type": "handle_table_size", + "value": 128 + }] +} \ No newline at end of file diff --git a/stratosphere/fatal/source/fatal_event_manager.cpp b/stratosphere/fatal/source/fatal_event_manager.cpp new file mode 100644 index 000000000..faed8969b --- /dev/null +++ b/stratosphere/fatal/source/fatal_event_manager.cpp @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2018 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include "fatal_event_manager.hpp" + +FatalEventManager::FatalEventManager() { + /* Just create all the events. */ + for (size_t i = 0; i < FatalEventManager::NumFatalEvents; i++) { + if (R_FAILED(eventCreate(&this->events[i], true))) { + std::abort(); + } + } +} + +Result FatalEventManager::GetEvent(Handle *out) { + std::scoped_lock lk{this->lock}; + + /* Only allow GetEvent to succeed NumFatalEvents times. */ + if (this->events_gotten >= FatalEventManager::NumFatalEvents) { + return 0x8A3; + } + + *out = this->events[this->events_gotten++].revent; + return 0; +} + +void FatalEventManager::SignalEvents() { + for (size_t i = 0; i < FatalEventManager::NumFatalEvents; i++) { + eventFire(&this->events[i]); + } +} diff --git a/stratosphere/fatal/source/fatal_event_manager.hpp b/stratosphere/fatal/source/fatal_event_manager.hpp new file mode 100644 index 000000000..83e4e46dd --- /dev/null +++ b/stratosphere/fatal/source/fatal_event_manager.hpp @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2018 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once +#include +#include + +class FatalEventManager { + private: + static constexpr size_t NumFatalEvents = 3; + + HosMutex lock; + size_t events_gotten = 0; + Event events[3]; + public: + FatalEventManager(); + Result GetEvent(Handle *out); + void SignalEvents(); +}; diff --git a/stratosphere/fatal/source/fatal_main.cpp b/stratosphere/fatal/source/fatal_main.cpp new file mode 100644 index 000000000..2573eb7ad --- /dev/null +++ b/stratosphere/fatal/source/fatal_main.cpp @@ -0,0 +1,97 @@ +/* + * Copyright (c) 2018 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include +#include +#include + +#include +#include +#include + +#include "fatal_types.hpp" +#include "fatal_private.hpp" +#include "fatal_user.hpp" + +extern "C" { + extern u32 __start__; + + u32 __nx_applet_type = AppletType_None; + + #define INNER_HEAP_SIZE 0x20000 + size_t nx_inner_heap_size = INNER_HEAP_SIZE; + char nx_inner_heap[INNER_HEAP_SIZE]; + + void __libnx_initheap(void); + void __appInit(void); + void __appExit(void); +} + + +void __libnx_initheap(void) { + void* addr = nx_inner_heap; + size_t size = nx_inner_heap_size; + + /* Newlib */ + extern char* fake_heap_start; + extern char* fake_heap_end; + + fake_heap_start = (char*)addr; + fake_heap_end = (char*)addr + size; +} + +void __appInit(void) { + Result rc; + + rc = smInitialize(); + if (R_FAILED(rc)) { + fatalSimple(MAKERESULT(Module_Libnx, LibnxError_InitFail_SM)); + } + + rc = setsysInitialize(); + if (R_FAILED(rc)) { + fatalSimple(rc); + } + + CheckAtmosphereVersion(CURRENT_ATMOSPHERE_VERSION); +} + +void __appExit(void) { + /* Cleanup services. */ + setsysExit(); + smExit(); +} + +int main(int argc, char **argv) +{ + consoleDebugInit(debugDevice_SVC); + + /* TODO: What's a good timeout value to use here? */ + auto server_manager = new WaitableManager(1); + + /* TODO: Create services. */ + server_manager->AddWaitable(new ServiceServer("fatal:p", 4)); + server_manager->AddWaitable(new ServiceServer("fatal:u", 4)); + + /* Loop forever, servicing our services. */ + server_manager->Process(); + + delete server_manager; + + return 0; +} + diff --git a/stratosphere/fatal/source/fatal_private.cpp b/stratosphere/fatal/source/fatal_private.cpp new file mode 100644 index 000000000..b1e57322a --- /dev/null +++ b/stratosphere/fatal/source/fatal_private.cpp @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2018 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include "fatal_private.hpp" +#include "fatal_event_manager.hpp" + +static FatalEventManager g_EventManager; + +Result PrivateService::GetFatalEvent(Out out_h) { + return g_EventManager.GetEvent(out_h.GetHandlePointer()); +} diff --git a/stratosphere/fatal/source/fatal_private.hpp b/stratosphere/fatal/source/fatal_private.hpp new file mode 100644 index 000000000..22e247eae --- /dev/null +++ b/stratosphere/fatal/source/fatal_private.hpp @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2018 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once +#include +#include + +enum PrivateCmd { + Private_Cmd_GetFatalEvent = 0, +}; + +class PrivateService final : public IServiceObject { + private: + /* Actual commands. */ + Result GetFatalEvent(Out out_h); + public: + DEFINE_SERVICE_DISPATCH_TABLE { + MakeServiceCommandMeta(), + }; +}; diff --git a/stratosphere/fatal/source/fatal_types.hpp b/stratosphere/fatal/source/fatal_types.hpp new file mode 100644 index 000000000..3ca5b85fc --- /dev/null +++ b/stratosphere/fatal/source/fatal_types.hpp @@ -0,0 +1,97 @@ +/* + * Copyright (c) 2018 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once +#include +#include + +enum FatalResult : Result { + FatalResult_TooManyEvents = 0x8A3, + FatalResult_InRepairWithoutVolHeld = 0xAA3, + FatalResult_InRepairWithoutTimeReviserCartridge = 0xCA3, +}; + +struct Aarch64CpuContext { + using RegisterType = u64; + static constexpr size_t MaxStackTraceDepth = 0x20; + + /* Registers, exception context. N left names for these fields in fatal .rodata. */ + union { + RegisterType x[31]; + struct { + RegisterType _x[29]; + RegisterType fp; + RegisterType lr; + RegisterType sp; + RegisterType pc; + }; + }; + RegisterType pstate; + RegisterType afsr0; + RegisterType afsr1; + RegisterType esr; + RegisterType far; + + /* Misc. */ + RegisterType stack_trace[MaxStackTraceDepth]; + RegisterType start_address; + RegisterType register_set_flags; + u32 stack_trace_size; +}; + +struct Aarch32CpuContext { + using RegisterType = u32; + static constexpr size_t MaxStackTraceDepth = 0x20; + + /* Registers, exception context. N left names for these fields in fatal .rodata. */ + union { + RegisterType r[16]; + struct { + RegisterType _x[11]; + RegisterType fp; + RegisterType ip; + RegisterType sp; + RegisterType lr; + RegisterType pc; + }; + }; + RegisterType pstate; + RegisterType afsr0; + RegisterType afsr1; + RegisterType esr; + RegisterType far; + + /* Misc. Yes, stack_trace_size is really laid out differently than aarch64... */ + RegisterType stack_trace[MaxStackTraceDepth]; + u32 stack_trace_size; + RegisterType start_address; + RegisterType register_set_flags; +}; + +struct FatalCpuContext { + union { + Aarch64CpuContext aarch64_ctx; + Aarch64CpuContext aarch32_ctx; + }; + + bool is_aarch32; + u32 type; +}; + +static_assert(sizeof(Aarch64CpuContext) == 0x248, "Aarch64CpuContext definition!"); +static_assert(sizeof(Aarch32CpuContext) == 0xE0, "Aarch32CpuContext definition!"); +static_assert(sizeof(FatalCpuContext) == 0x250, "FatalCpuContext definition!"); +static_assert(std::is_pod_v, "FatalCpuContext definition!"); diff --git a/stratosphere/fatal/source/fatal_user.cpp b/stratosphere/fatal/source/fatal_user.cpp new file mode 100644 index 000000000..b97e2bb25 --- /dev/null +++ b/stratosphere/fatal/source/fatal_user.cpp @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2018 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include "fatal_user.hpp" + +Result UserService::ThrowFatalImpl(u32 error, u64 pid, FatalType policy, FatalCpuContext *context) { + /* TODO */ + return 0; +} + + +Result UserService::ThrowFatal(u32 error, PidDescriptor pid_desc) { + FatalCpuContext ctx = {0}; + return ThrowFatalImpl(error, pid_desc.pid, FatalType_ErrorReportAndErrorScreen, &ctx); +} + +Result UserService::ThrowFatalWithPolicy(u32 error, PidDescriptor pid_desc, FatalType policy) { + FatalCpuContext ctx = {0}; + return ThrowFatalImpl(error, pid_desc.pid, policy, &ctx); +} + +Result UserService::ThrowFatalWithCpuContext(u32 error, PidDescriptor pid_desc, FatalType policy, InBuffer _ctx) { + /* Require exactly one context passed in. */ + if (_ctx.num_elements != 1) { + return 0xF601; + } + + return ThrowFatalImpl(error, pid_desc.pid, policy, _ctx.buffer); +} \ No newline at end of file diff --git a/stratosphere/fatal/source/fatal_user.hpp b/stratosphere/fatal/source/fatal_user.hpp new file mode 100644 index 000000000..48e4f9591 --- /dev/null +++ b/stratosphere/fatal/source/fatal_user.hpp @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2018 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once +#include +#include + +#include "fatal_types.hpp" + +enum UserCmd { + User_Cmd_ThrowFatal = 0, + User_Cmd_ThrowFatalWithPolicy = 1, + User_Cmd_ThrowFatalWithCpuContext = 2, +}; + +class UserService final : public IServiceObject { + private: + Result ThrowFatalImpl(u32 error, u64 pid, FatalType policy, FatalCpuContext *context); + + /* Actual commands. */ + Result ThrowFatal(u32 error, PidDescriptor pid_desc); + Result ThrowFatalWithPolicy(u32 error, PidDescriptor pid_desc, FatalType policy); + Result ThrowFatalWithCpuContext(u32 error, PidDescriptor pid_desc, FatalType policy, InBuffer _ctx); + public: + DEFINE_SERVICE_DISPATCH_TABLE { + MakeServiceCommandMeta(), + MakeServiceCommandMeta(), + MakeServiceCommandMeta(), + }; +}; From 21b0f228b6ba81fbce9a2a9302b3098e2e061864 Mon Sep 17 00:00:00 2001 From: Michael Scire Date: Sat, 10 Nov 2018 00:54:12 -0800 Subject: [PATCH 02/33] fatal: Skeleton tasks, write ThrowFatalImpl. --- stratosphere/fatal/fatal.json | 2 +- .../fatal/source/fatal_event_manager.cpp | 9 ++- .../fatal/source/fatal_event_manager.hpp | 2 + stratosphere/fatal/source/fatal_main.cpp | 6 ++ stratosphere/fatal/source/fatal_private.cpp | 4 +- stratosphere/fatal/source/fatal_task.cpp | 55 ++++++++++++++++++ stratosphere/fatal/source/fatal_task.hpp | 31 ++++++++++ stratosphere/fatal/source/fatal_types.hpp | 6 ++ stratosphere/fatal/source/fatal_user.cpp | 56 ++++++++++++++++++- 9 files changed, 164 insertions(+), 7 deletions(-) create mode 100644 stratosphere/fatal/source/fatal_task.cpp create mode 100644 stratosphere/fatal/source/fatal_task.hpp diff --git a/stratosphere/fatal/fatal.json b/stratosphere/fatal/fatal.json index 2d4388785..9dc17d9a9 100644 --- a/stratosphere/fatal/fatal.json +++ b/stratosphere/fatal/fatal.json @@ -4,7 +4,7 @@ "title_id_range_min": "0x0100000000000034", "title_id_range_max": "0x0100000000000034", "main_thread_stack_size": "0x00010000", - "main_thread_priority": 15, + "main_thread_priority": 37, "default_cpu_id": 3, "process_category": 0, "is_retail": true, diff --git a/stratosphere/fatal/source/fatal_event_manager.cpp b/stratosphere/fatal/source/fatal_event_manager.cpp index faed8969b..4414941ce 100644 --- a/stratosphere/fatal/source/fatal_event_manager.cpp +++ b/stratosphere/fatal/source/fatal_event_manager.cpp @@ -15,8 +15,15 @@ */ #include +#include "fatal_types.hpp" #include "fatal_event_manager.hpp" +static FatalEventManager g_event_manager; + +FatalEventManager *GetEventManager() { + return &g_event_manager; +} + FatalEventManager::FatalEventManager() { /* Just create all the events. */ for (size_t i = 0; i < FatalEventManager::NumFatalEvents; i++) { @@ -31,7 +38,7 @@ Result FatalEventManager::GetEvent(Handle *out) { /* Only allow GetEvent to succeed NumFatalEvents times. */ if (this->events_gotten >= FatalEventManager::NumFatalEvents) { - return 0x8A3; + return FatalResult_TooManyEvents; } *out = this->events[this->events_gotten++].revent; diff --git a/stratosphere/fatal/source/fatal_event_manager.hpp b/stratosphere/fatal/source/fatal_event_manager.hpp index 83e4e46dd..e96ab0f63 100644 --- a/stratosphere/fatal/source/fatal_event_manager.hpp +++ b/stratosphere/fatal/source/fatal_event_manager.hpp @@ -30,3 +30,5 @@ class FatalEventManager { Result GetEvent(Handle *out); void SignalEvents(); }; + +FatalEventManager *GetEventManager(); \ No newline at end of file diff --git a/stratosphere/fatal/source/fatal_main.cpp b/stratosphere/fatal/source/fatal_main.cpp index 2573eb7ad..72b006d31 100644 --- a/stratosphere/fatal/source/fatal_main.cpp +++ b/stratosphere/fatal/source/fatal_main.cpp @@ -67,11 +67,17 @@ void __appInit(void) { fatalSimple(rc); } + rc = pminfoInitialize(); + if (R_FAILED(rc)) { + fatalSimple(rc); + } + CheckAtmosphereVersion(CURRENT_ATMOSPHERE_VERSION); } void __appExit(void) { /* Cleanup services. */ + pminfoExit(); setsysExit(); smExit(); } diff --git a/stratosphere/fatal/source/fatal_private.cpp b/stratosphere/fatal/source/fatal_private.cpp index b1e57322a..afa384662 100644 --- a/stratosphere/fatal/source/fatal_private.cpp +++ b/stratosphere/fatal/source/fatal_private.cpp @@ -18,8 +18,6 @@ #include "fatal_private.hpp" #include "fatal_event_manager.hpp" -static FatalEventManager g_EventManager; - Result PrivateService::GetFatalEvent(Out out_h) { - return g_EventManager.GetEvent(out_h.GetHandlePointer()); + return GetEventManager()->GetEvent(out_h.GetHandlePointer()); } diff --git a/stratosphere/fatal/source/fatal_task.cpp b/stratosphere/fatal/source/fatal_task.cpp new file mode 100644 index 000000000..eb10add15 --- /dev/null +++ b/stratosphere/fatal/source/fatal_task.cpp @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2018 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include "fatal_types.hpp" +#include "fatal_task.hpp" + +static constexpr size_t MaxTasks = 8; +static HosThread g_task_threads[MaxTasks]; +static size_t g_num_threads = 0; + + +static void RunTaskThreadFunc(void *arg) { + IFatalTask *task = reinterpret_cast(arg); + + Result rc = task->Run(); + if (R_FAILED(rc)) { + /* TODO: Log task failure, somehow? */ + } +} + +static void RunTask(IFatalTask *task) { + if (g_num_threads >= MaxTasks) { + std::abort(); + } + + HosThread *cur_thread = &g_task_threads[g_num_threads++]; + + cur_thread->Initialize(&RunTaskThreadFunc, task, 0x4000, 15); + cur_thread->Start(); +} + +void RunFatalTasks(FatalContext *ctx, u64 title_id, bool error_report, Event *erpt_event, Event *battery_event) { + /* TODO: RunTask(new ErrorReportTask(ctx, title_id, error_report, erpt_event); */ + /* TODO: RunTask(new PowerControlTask(ctx, title_id, battery_event); */ + /* TODO: RunTask(new ShowFatalTask(ctx, title_id, battery_event); */ + /* TODO: RunTask(new StopSoundTask(); */ + /* TODO: RunTask(new BacklightControlTask(); */ + /* TODO: RunTask(new AdjustClockTask(); */ + /* TODO: RunTask(new PowerButtonTask(erpt_event); */ + /* TODO: RunTask(new StateTransitionStop(); */ +} diff --git a/stratosphere/fatal/source/fatal_task.hpp b/stratosphere/fatal/source/fatal_task.hpp new file mode 100644 index 000000000..63d1ca43e --- /dev/null +++ b/stratosphere/fatal/source/fatal_task.hpp @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2018 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once +#include +#include +#include "fatal_types.hpp" + +class IFatalTask { + protected: + FatalContext *ctx; + u64 title_id; + public: + virtual Result Run() = 0; + virtual const char *GetName() const = 0; +}; + +void RunFatalTasks(FatalContext *ctx, u64 title_id, bool error_report, Event *erpt_event, Event *battery_event); diff --git a/stratosphere/fatal/source/fatal_types.hpp b/stratosphere/fatal/source/fatal_types.hpp index 3ca5b85fc..46fafeec4 100644 --- a/stratosphere/fatal/source/fatal_types.hpp +++ b/stratosphere/fatal/source/fatal_types.hpp @@ -19,6 +19,7 @@ #include enum FatalResult : Result { + FatalResult_AlreadyThrown = 0x6A3, FatalResult_TooManyEvents = 0x8A3, FatalResult_InRepairWithoutVolHeld = 0xAA3, FatalResult_InRepairWithoutTimeReviserCartridge = 0xCA3, @@ -91,6 +92,11 @@ struct FatalCpuContext { u32 type; }; +struct FatalContext { + u32 error_code; + FatalCpuContext cpu_ctx; +}; + static_assert(sizeof(Aarch64CpuContext) == 0x248, "Aarch64CpuContext definition!"); static_assert(sizeof(Aarch32CpuContext) == 0xE0, "Aarch32CpuContext definition!"); static_assert(sizeof(FatalCpuContext) == 0x250, "FatalCpuContext definition!"); diff --git a/stratosphere/fatal/source/fatal_user.cpp b/stratosphere/fatal/source/fatal_user.cpp index b97e2bb25..f683de4cc 100644 --- a/stratosphere/fatal/source/fatal_user.cpp +++ b/stratosphere/fatal/source/fatal_user.cpp @@ -16,9 +16,61 @@ #include #include "fatal_user.hpp" +#include "fatal_event_manager.hpp" +#include "fatal_task.hpp" -Result UserService::ThrowFatalImpl(u32 error, u64 pid, FatalType policy, FatalCpuContext *context) { - /* TODO */ +static bool g_thrown = false; + +static Result SetThrown() { + /* This should be fine, since fatal only has a single IPC thread. */ + if (g_thrown) { + return FatalResult_AlreadyThrown; + } + + g_thrown = true; + return 0; +} + +Result UserService::ThrowFatalImpl(u32 error, u64 pid, FatalType policy, FatalCpuContext *cpu_ctx) { + Result rc = 0; + FatalContext ctx; + ctx.error_code = error; + ctx.cpu_ctx = *cpu_ctx; + + /* Get title id. On failure, it'll be zero. */ + u64 title_id = 0; + pminfoGetTitleId(&title_id, pid); + + switch (policy) { + case FatalType_ErrorReport: + /* TODO: Don't write an error report. */ + case FatalType_ErrorReportAndErrorScreen: + case FatalType_ErrorScreen: + { + /* Ensure we only throw once. */ + if (R_FAILED((rc = SetThrown()))) { + return rc; + } + + /* Signal that fatal is about to happen. */ + GetEventManager()->SignalEvents(); + + /* Create events. */ + Event erpt_event; + Event battery_event; + if (R_FAILED(eventCreate(&erpt_event, true)) || R_FAILED(eventCreate(&battery_event, true))) { + std::abort(); + } + + /* Run tasks. */ + RunFatalTasks(&ctx, title_id, policy == FatalType_ErrorReportAndErrorScreen, &erpt_event, &battery_event); + } + break; + default: + /* N aborts here. Should we just return an error code? */ + std::abort(); + } + return 0; } From 4d1481e2eb269a8e66420371c16418f4c5355bac Mon Sep 17 00:00:00 2001 From: Michael Scire Date: Sat, 10 Nov 2018 01:04:40 -0800 Subject: [PATCH 03/33] fatal: Write ErrorReportTask --- stratosphere/fatal/source/fatal_main.cpp | 2 +- stratosphere/fatal/source/fatal_task.cpp | 19 ++++++----- stratosphere/fatal/source/fatal_task.hpp | 1 + .../fatal/source/fatal_task_error_report.cpp | 28 ++++++++++++++++ .../fatal/source/fatal_task_error_report.hpp | 32 +++++++++++++++++++ 5 files changed, 73 insertions(+), 9 deletions(-) create mode 100644 stratosphere/fatal/source/fatal_task_error_report.cpp create mode 100644 stratosphere/fatal/source/fatal_task_error_report.hpp diff --git a/stratosphere/fatal/source/fatal_main.cpp b/stratosphere/fatal/source/fatal_main.cpp index 72b006d31..ae8f0ce19 100644 --- a/stratosphere/fatal/source/fatal_main.cpp +++ b/stratosphere/fatal/source/fatal_main.cpp @@ -32,7 +32,7 @@ extern "C" { u32 __nx_applet_type = AppletType_None; - #define INNER_HEAP_SIZE 0x20000 + #define INNER_HEAP_SIZE 0x380000 size_t nx_inner_heap_size = INNER_HEAP_SIZE; char nx_inner_heap[INNER_HEAP_SIZE]; diff --git a/stratosphere/fatal/source/fatal_task.cpp b/stratosphere/fatal/source/fatal_task.cpp index eb10add15..a01ac6244 100644 --- a/stratosphere/fatal/source/fatal_task.cpp +++ b/stratosphere/fatal/source/fatal_task.cpp @@ -18,6 +18,9 @@ #include "fatal_types.hpp" #include "fatal_task.hpp" +#include "fatal_task_error_report.hpp" + + static constexpr size_t MaxTasks = 8; static HosThread g_task_threads[MaxTasks]; static size_t g_num_threads = 0; @@ -44,12 +47,12 @@ static void RunTask(IFatalTask *task) { } void RunFatalTasks(FatalContext *ctx, u64 title_id, bool error_report, Event *erpt_event, Event *battery_event) { - /* TODO: RunTask(new ErrorReportTask(ctx, title_id, error_report, erpt_event); */ - /* TODO: RunTask(new PowerControlTask(ctx, title_id, battery_event); */ - /* TODO: RunTask(new ShowFatalTask(ctx, title_id, battery_event); */ - /* TODO: RunTask(new StopSoundTask(); */ - /* TODO: RunTask(new BacklightControlTask(); */ - /* TODO: RunTask(new AdjustClockTask(); */ - /* TODO: RunTask(new PowerButtonTask(erpt_event); */ - /* TODO: RunTask(new StateTransitionStop(); */ + RunTask(new ErrorReportTask(ctx, title_id, error_report, erpt_event)); + /* TODO: RunTask(new PowerControlTask(ctx, title_id, battery_event)); */ + /* TODO: RunTask(new ShowFatalTask(ctx, title_id, battery_event)); */ + /* TODO: RunTask(new StopSoundTask()); */ + /* TODO: RunTask(new BacklightControlTask()); */ + /* TODO: RunTask(new AdjustClockTask()); */ + /* TODO: RunTask(new PowerButtonTask(erpt_event)); */ + /* TODO: RunTask(new StateTransitionStop()); */ } diff --git a/stratosphere/fatal/source/fatal_task.hpp b/stratosphere/fatal/source/fatal_task.hpp index 63d1ca43e..ef19fbbc1 100644 --- a/stratosphere/fatal/source/fatal_task.hpp +++ b/stratosphere/fatal/source/fatal_task.hpp @@ -24,6 +24,7 @@ class IFatalTask { FatalContext *ctx; u64 title_id; public: + IFatalTask(FatalContext *ctx, u64 tid) : ctx(ctx), title_id(tid) { } virtual Result Run() = 0; virtual const char *GetName() const = 0; }; diff --git a/stratosphere/fatal/source/fatal_task_error_report.cpp b/stratosphere/fatal/source/fatal_task_error_report.cpp new file mode 100644 index 000000000..72decd371 --- /dev/null +++ b/stratosphere/fatal/source/fatal_task_error_report.cpp @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2018 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include "fatal_task_error_report.hpp" + +Result ErrorReportTask::Run() { + if (this->create_report) { + /* Here, Nintendo creates an error report with erpt. AMS will not do that. */ + /* TODO: Should atmosphere log reports to to the SD card? */ + } + + /* Signal we're done with our job. */ + eventFire(this->erpt_event); +} \ No newline at end of file diff --git a/stratosphere/fatal/source/fatal_task_error_report.hpp b/stratosphere/fatal/source/fatal_task_error_report.hpp new file mode 100644 index 000000000..7ade00bcf --- /dev/null +++ b/stratosphere/fatal/source/fatal_task_error_report.hpp @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2018 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once +#include +#include +#include "fatal_task.hpp" + +class ErrorReportTask : public IFatalTask { + private: + bool create_report; + Event *erpt_event; + public: + ErrorReportTask(FatalContext *ctx, u64 title_id, bool error_report, Event *evt) : IFatalTask(ctx, title_id), create_report(error_report), erpt_event(evt) { } + virtual Result Run() override; + virtual const char *GetName() const override { + return "WriteErrorReport"; + } +}; \ No newline at end of file From b771c42f7ffea0c2d0217c7c360f979a96adab0d Mon Sep 17 00:00:00 2001 From: Michael Scire Date: Sat, 10 Nov 2018 01:19:52 -0800 Subject: [PATCH 04/33] fatal: Implement StateTransitionStopTask --- stratosphere/fatal/source/fatal_main.cpp | 14 ++++++--- stratosphere/fatal/source/fatal_task.cpp | 11 +++---- .../fatal/source/fatal_task_power.cpp | 24 +++++++++++++++ .../fatal/source/fatal_task_power.hpp | 29 +++++++++++++++++++ 4 files changed, 69 insertions(+), 9 deletions(-) create mode 100644 stratosphere/fatal/source/fatal_task_power.cpp create mode 100644 stratosphere/fatal/source/fatal_task_power.hpp diff --git a/stratosphere/fatal/source/fatal_main.cpp b/stratosphere/fatal/source/fatal_main.cpp index ae8f0ce19..211c22374 100644 --- a/stratosphere/fatal/source/fatal_main.cpp +++ b/stratosphere/fatal/source/fatal_main.cpp @@ -59,24 +59,30 @@ void __appInit(void) { rc = smInitialize(); if (R_FAILED(rc)) { - fatalSimple(MAKERESULT(Module_Libnx, LibnxError_InitFail_SM)); + std::abort(); } rc = setsysInitialize(); if (R_FAILED(rc)) { - fatalSimple(rc); + std::abort(); } rc = pminfoInitialize(); if (R_FAILED(rc)) { - fatalSimple(rc); + std::abort(); } - CheckAtmosphereVersion(CURRENT_ATMOSPHERE_VERSION); + rc = spsmInitialize(); + if (R_FAILED(rc)) { + std::abort(); + } + + /* fatal cannot throw fatal, so don't do: CheckAtmosphereVersion(CURRENT_ATMOSPHERE_VERSION); */ } void __appExit(void) { /* Cleanup services. */ + spsmExit(); pminfoExit(); setsysExit(); smExit(); diff --git a/stratosphere/fatal/source/fatal_task.cpp b/stratosphere/fatal/source/fatal_task.cpp index a01ac6244..9725d02f8 100644 --- a/stratosphere/fatal/source/fatal_task.cpp +++ b/stratosphere/fatal/source/fatal_task.cpp @@ -19,6 +19,7 @@ #include "fatal_task.hpp" #include "fatal_task_error_report.hpp" +#include "fatal_task_power.hpp" static constexpr size_t MaxTasks = 8; @@ -50,9 +51,9 @@ void RunFatalTasks(FatalContext *ctx, u64 title_id, bool error_report, Event *er RunTask(new ErrorReportTask(ctx, title_id, error_report, erpt_event)); /* TODO: RunTask(new PowerControlTask(ctx, title_id, battery_event)); */ /* TODO: RunTask(new ShowFatalTask(ctx, title_id, battery_event)); */ - /* TODO: RunTask(new StopSoundTask()); */ - /* TODO: RunTask(new BacklightControlTask()); */ - /* TODO: RunTask(new AdjustClockTask()); */ - /* TODO: RunTask(new PowerButtonTask(erpt_event)); */ - /* TODO: RunTask(new StateTransitionStop()); */ + /* TODO: RunTask(new StopSoundTask(ctx, title_id)); */ + /* TODO: RunTask(new BacklightControlTask(ctx, title_id)); */ + /* TODO: RunTask(new AdjustClockTask(ctx, title_id)); */ + /* TODO: RunTask(new PowerButtonTask(ctx, title_id, erpt_event)); */ + RunTask(new StateTransitionStopTask(ctx, title_id)); } diff --git a/stratosphere/fatal/source/fatal_task_power.cpp b/stratosphere/fatal/source/fatal_task_power.cpp new file mode 100644 index 000000000..59ffb062b --- /dev/null +++ b/stratosphere/fatal/source/fatal_task_power.cpp @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2018 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include "fatal_task_power.hpp" + +Result StateTransitionStopTask::Run() { + /* Nintendo ignores the output of this call... */ + spsmPutErrorState(); + return 0; +} diff --git a/stratosphere/fatal/source/fatal_task_power.hpp b/stratosphere/fatal/source/fatal_task_power.hpp new file mode 100644 index 000000000..e97f71978 --- /dev/null +++ b/stratosphere/fatal/source/fatal_task_power.hpp @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2018 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once +#include +#include +#include "fatal_task.hpp" + +class StateTransitionStopTask : public IFatalTask { + public: + StateTransitionStopTask(FatalContext *ctx, u64 title_id) : IFatalTask(ctx, title_id) { } + virtual Result Run() override; + virtual const char *GetName() const override { + return "StateTransitionStopTask"; + } +}; \ No newline at end of file From 13e5043d6406da4e53a88350636819116af72cb4 Mon Sep 17 00:00:00 2001 From: Michael Scire Date: Sat, 10 Nov 2018 01:41:47 -0800 Subject: [PATCH 05/33] fatal: Implement PowerButtonObserveTask --- stratosphere/fatal/source/fatal_task.cpp | 4 +-- .../fatal/source/fatal_task_power.cpp | 24 ++++++++++++++++++ .../fatal/source/fatal_task_power.hpp | 25 +++++++++++++++++++ 3 files changed, 51 insertions(+), 2 deletions(-) diff --git a/stratosphere/fatal/source/fatal_task.cpp b/stratosphere/fatal/source/fatal_task.cpp index 9725d02f8..381d3c176 100644 --- a/stratosphere/fatal/source/fatal_task.cpp +++ b/stratosphere/fatal/source/fatal_task.cpp @@ -49,11 +49,11 @@ static void RunTask(IFatalTask *task) { void RunFatalTasks(FatalContext *ctx, u64 title_id, bool error_report, Event *erpt_event, Event *battery_event) { RunTask(new ErrorReportTask(ctx, title_id, error_report, erpt_event)); - /* TODO: RunTask(new PowerControlTask(ctx, title_id, battery_event)); */ + /* TODO: RunTask(new PowerControlTask(ctx, title_id, erpt_event, battery_event)); */ /* TODO: RunTask(new ShowFatalTask(ctx, title_id, battery_event)); */ /* TODO: RunTask(new StopSoundTask(ctx, title_id)); */ /* TODO: RunTask(new BacklightControlTask(ctx, title_id)); */ /* TODO: RunTask(new AdjustClockTask(ctx, title_id)); */ - /* TODO: RunTask(new PowerButtonTask(ctx, title_id, erpt_event)); */ + RunTask(new PowerButtonObserveTask(ctx, title_id, erpt_event)); RunTask(new StateTransitionStopTask(ctx, title_id)); } diff --git a/stratosphere/fatal/source/fatal_task_power.cpp b/stratosphere/fatal/source/fatal_task_power.cpp index 59ffb062b..410fc158a 100644 --- a/stratosphere/fatal/source/fatal_task_power.cpp +++ b/stratosphere/fatal/source/fatal_task_power.cpp @@ -17,6 +17,30 @@ #include #include "fatal_task_power.hpp" +void PowerButtonObserveTask::WaitForPowerButton() { + /* Wait up to a second for error report generation to finish. */ + eventWait(this->erpt_event, TimeoutHelper::NsToTick(1000000000UL)); + + /* TODO: Force a reboot after some time if kiosk unit. */ + + BpcSleepButtonState state; + while (true) { + Result rc = bpcGetSleepButtonState(&state); + if (R_SUCCEEDED(rc) && state == BpcSleepButtonState_Held) { + bpcRebootSystem(); + return; + } + + /* Wait 100 ms between button checks. */ + svcSleepThread(TimeoutHelper::NsToTick(100000000UL)); + } +} + +Result PowerButtonObserveTask::Run() { + WaitForPowerButton(); + return 0; +} + Result StateTransitionStopTask::Run() { /* Nintendo ignores the output of this call... */ spsmPutErrorState(); diff --git a/stratosphere/fatal/source/fatal_task_power.hpp b/stratosphere/fatal/source/fatal_task_power.hpp index e97f71978..bdd5b7155 100644 --- a/stratosphere/fatal/source/fatal_task_power.hpp +++ b/stratosphere/fatal/source/fatal_task_power.hpp @@ -19,6 +19,31 @@ #include #include "fatal_task.hpp" +class PowerControlTask : public IFatalTask { + private: + Event *erpt_event; + Event *battery_event; + public: + PowerControlTask(FatalContext *ctx, u64 title_id, Event *er_evt, Event *bt_evt) : IFatalTask(ctx, title_id), erpt_event(er_evt), battery_event(bt_evt) { } + virtual Result Run() override; + virtual const char *GetName() const override { + return "PowerControlTask"; + } +}; + +class PowerButtonObserveTask : public IFatalTask { + private: + Event *erpt_event; + private: + void WaitForPowerButton(); + public: + PowerButtonObserveTask(FatalContext *ctx, u64 title_id, Event *er_evt) : IFatalTask(ctx, title_id), erpt_event(er_evt) { } + virtual Result Run() override; + virtual const char *GetName() const override { + return "PowerButtonObserveTask"; + } +}; + class StateTransitionStopTask : public IFatalTask { public: StateTransitionStopTask(FatalContext *ctx, u64 title_id) : IFatalTask(ctx, title_id) { } From 6f240b16656c855f8566a2ee2f14199452e85840 Mon Sep 17 00:00:00 2001 From: Michael Scire Date: Sat, 10 Nov 2018 01:47:02 -0800 Subject: [PATCH 06/33] fatal: Add missing bpcInitialize() call. --- stratosphere/fatal/source/fatal_main.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/stratosphere/fatal/source/fatal_main.cpp b/stratosphere/fatal/source/fatal_main.cpp index 211c22374..e9fb47c44 100644 --- a/stratosphere/fatal/source/fatal_main.cpp +++ b/stratosphere/fatal/source/fatal_main.cpp @@ -72,6 +72,11 @@ void __appInit(void) { std::abort(); } + rc = bpcInitialize(); + if (R_FAILED(rc)) { + std::abort(); + } + rc = spsmInitialize(); if (R_FAILED(rc)) { std::abort(); @@ -83,6 +88,7 @@ void __appInit(void) { void __appExit(void) { /* Cleanup services. */ spsmExit(); + bpcExit(); pminfoExit(); setsysExit(); smExit(); From 1228cd6903e5d5f5572fd431f18b12d0ada145f6 Mon Sep 17 00:00:00 2001 From: Michael Scire Date: Sat, 10 Nov 2018 02:21:29 -0800 Subject: [PATCH 07/33] fatal: misc cleanup, verified to reboot on hardware --- stratosphere/fatal/fatal.json | 5 +++-- stratosphere/fatal/source/fatal_event_manager.hpp | 2 +- stratosphere/fatal/source/fatal_task.cpp | 3 +++ .../fatal/source/fatal_task_error_report.cpp | 2 ++ stratosphere/fatal/source/fatal_user.cpp | 14 +++++++------- stratosphere/fatal/source/fatal_user.hpp | 2 +- 6 files changed, 17 insertions(+), 11 deletions(-) diff --git a/stratosphere/fatal/fatal.json b/stratosphere/fatal/fatal.json index 9dc17d9a9..380b2b85f 100644 --- a/stratosphere/fatal/fatal.json +++ b/stratosphere/fatal/fatal.json @@ -14,7 +14,7 @@ "filesystem_access": { "permissions": "0x0000000000100000" }, - "service_access": ["bpc", "erpt:c", "fsp-srv", "gpio", "i2c", "lbl", "lm", "nvdrv:s", "pcv", "pl:u", "pm:info", "psm", "set", "set:sys", "spsm", "vi:m", "vi:s"], + "service_access": ["bpc", "bpc:c", "erpt:c", "fsp-srv", "gpio", "i2c", "lbl", "lm", "nvdrv:s", "pcv", "pl:u", "pm:info", "psm", "set", "set:sys", "spsm", "vi:m", "vi:s"], "service_host": ["fatal:p", "fatal:u"], "kernel_capabilities": [{ "type": "kernel_flags", @@ -75,7 +75,8 @@ "svcReplyAndReceiveLight": "0x42", "svcReplyAndReceive": "0x43", "svcReplyAndReceiveWithUserBuffer": "0x44", - "svcCreateEvent": "0x45" + "svcCreateEvent": "0x45", + "svcReadWriteRegister": "0x4E" } }, { "type": "min_kernel_version", diff --git a/stratosphere/fatal/source/fatal_event_manager.hpp b/stratosphere/fatal/source/fatal_event_manager.hpp index e96ab0f63..6b0bd5f69 100644 --- a/stratosphere/fatal/source/fatal_event_manager.hpp +++ b/stratosphere/fatal/source/fatal_event_manager.hpp @@ -24,7 +24,7 @@ class FatalEventManager { HosMutex lock; size_t events_gotten = 0; - Event events[3]; + Event events[NumFatalEvents]; public: FatalEventManager(); Result GetEvent(Handle *out); diff --git a/stratosphere/fatal/source/fatal_task.cpp b/stratosphere/fatal/source/fatal_task.cpp index 381d3c176..407b78e8c 100644 --- a/stratosphere/fatal/source/fatal_task.cpp +++ b/stratosphere/fatal/source/fatal_task.cpp @@ -34,6 +34,9 @@ static void RunTaskThreadFunc(void *arg) { if (R_FAILED(rc)) { /* TODO: Log task failure, somehow? */ } + + /* Finish. */ + svcExitThread(); } static void RunTask(IFatalTask *task) { diff --git a/stratosphere/fatal/source/fatal_task_error_report.cpp b/stratosphere/fatal/source/fatal_task_error_report.cpp index 72decd371..111c4ce38 100644 --- a/stratosphere/fatal/source/fatal_task_error_report.cpp +++ b/stratosphere/fatal/source/fatal_task_error_report.cpp @@ -25,4 +25,6 @@ Result ErrorReportTask::Run() { /* Signal we're done with our job. */ eventFire(this->erpt_event); + + return 0; } \ No newline at end of file diff --git a/stratosphere/fatal/source/fatal_user.cpp b/stratosphere/fatal/source/fatal_user.cpp index f683de4cc..b21aefc29 100644 --- a/stratosphere/fatal/source/fatal_user.cpp +++ b/stratosphere/fatal/source/fatal_user.cpp @@ -58,7 +58,7 @@ Result UserService::ThrowFatalImpl(u32 error, u64 pid, FatalType policy, FatalCp /* Create events. */ Event erpt_event; Event battery_event; - if (R_FAILED(eventCreate(&erpt_event, true)) || R_FAILED(eventCreate(&battery_event, true))) { + if (R_FAILED(eventCreate(&erpt_event, false)) || R_FAILED(eventCreate(&battery_event, false))) { std::abort(); } @@ -85,11 +85,11 @@ Result UserService::ThrowFatalWithPolicy(u32 error, PidDescriptor pid_desc, Fata return ThrowFatalImpl(error, pid_desc.pid, policy, &ctx); } -Result UserService::ThrowFatalWithCpuContext(u32 error, PidDescriptor pid_desc, FatalType policy, InBuffer _ctx) { - /* Require exactly one context passed in. */ - if (_ctx.num_elements != 1) { - return 0xF601; +Result UserService::ThrowFatalWithCpuContext(u32 error, PidDescriptor pid_desc, FatalType policy, InBuffer _ctx) { + if (_ctx.num_elements < sizeof(FatalCpuContext)) { + FatalCpuContext ctx = {0}; + return ThrowFatalImpl(error, pid_desc.pid, policy, &ctx); + } else { + return ThrowFatalImpl(error, pid_desc.pid, policy, reinterpret_cast(_ctx.buffer)); } - - return ThrowFatalImpl(error, pid_desc.pid, policy, _ctx.buffer); } \ No newline at end of file diff --git a/stratosphere/fatal/source/fatal_user.hpp b/stratosphere/fatal/source/fatal_user.hpp index 48e4f9591..ab46a4a9e 100644 --- a/stratosphere/fatal/source/fatal_user.hpp +++ b/stratosphere/fatal/source/fatal_user.hpp @@ -33,7 +33,7 @@ class UserService final : public IServiceObject { /* Actual commands. */ Result ThrowFatal(u32 error, PidDescriptor pid_desc); Result ThrowFatalWithPolicy(u32 error, PidDescriptor pid_desc, FatalType policy); - Result ThrowFatalWithCpuContext(u32 error, PidDescriptor pid_desc, FatalType policy, InBuffer _ctx); + Result ThrowFatalWithCpuContext(u32 error, PidDescriptor pid_desc, FatalType policy, InBuffer _ctx); public: DEFINE_SERVICE_DISPATCH_TABLE { MakeServiceCommandMeta(), From aa86d1abfa7144fee538f3ffae638ad1004182ee Mon Sep 17 00:00:00 2001 From: Michael Scire Date: Sat, 10 Nov 2018 02:42:07 -0800 Subject: [PATCH 08/33] fatal: Implement PowerControlTask --- stratosphere/fatal/source/fatal_main.cpp | 6 ++ stratosphere/fatal/source/fatal_task.cpp | 2 +- .../fatal/source/fatal_task_power.cpp | 75 +++++++++++++++++++ .../fatal/source/fatal_task_power.hpp | 3 + 4 files changed, 85 insertions(+), 1 deletion(-) diff --git a/stratosphere/fatal/source/fatal_main.cpp b/stratosphere/fatal/source/fatal_main.cpp index e9fb47c44..e01cbd7e8 100644 --- a/stratosphere/fatal/source/fatal_main.cpp +++ b/stratosphere/fatal/source/fatal_main.cpp @@ -77,6 +77,11 @@ void __appInit(void) { std::abort(); } + rc = psmInitialize(); + if (R_FAILED(rc)) { + std::abort(); + } + rc = spsmInitialize(); if (R_FAILED(rc)) { std::abort(); @@ -88,6 +93,7 @@ void __appInit(void) { void __appExit(void) { /* Cleanup services. */ spsmExit(); + psmExit(); bpcExit(); pminfoExit(); setsysExit(); diff --git a/stratosphere/fatal/source/fatal_task.cpp b/stratosphere/fatal/source/fatal_task.cpp index 407b78e8c..43108e88b 100644 --- a/stratosphere/fatal/source/fatal_task.cpp +++ b/stratosphere/fatal/source/fatal_task.cpp @@ -52,7 +52,7 @@ static void RunTask(IFatalTask *task) { void RunFatalTasks(FatalContext *ctx, u64 title_id, bool error_report, Event *erpt_event, Event *battery_event) { RunTask(new ErrorReportTask(ctx, title_id, error_report, erpt_event)); - /* TODO: RunTask(new PowerControlTask(ctx, title_id, erpt_event, battery_event)); */ + RunTask(new PowerControlTask(ctx, title_id, erpt_event, battery_event)); /* TODO: RunTask(new ShowFatalTask(ctx, title_id, battery_event)); */ /* TODO: RunTask(new StopSoundTask(ctx, title_id)); */ /* TODO: RunTask(new BacklightControlTask(ctx, title_id)); */ diff --git a/stratosphere/fatal/source/fatal_task_power.cpp b/stratosphere/fatal/source/fatal_task_power.cpp index 410fc158a..2ebd2489e 100644 --- a/stratosphere/fatal/source/fatal_task_power.cpp +++ b/stratosphere/fatal/source/fatal_task_power.cpp @@ -17,6 +17,76 @@ #include #include "fatal_task_power.hpp" +bool PowerControlTask::TryShutdown() { + /* Set a timeout of 30 seconds. */ + TimeoutHelper timeout_helper(30000000000UL); + bool cancel_shutdown = false; + PsmBatteryVoltageState bv_state = PsmBatteryVoltageState_Normal; + + while (true) { + if (timeout_helper.TimedOut()) { + break; + } + + if (R_FAILED(psmGetBatteryVoltageState(&bv_state)) || bv_state == PsmBatteryVoltageState_NeedsShutdown) { + break; + } + + if (bv_state == PsmBatteryVoltageState_Normal) { + cancel_shutdown = true; + break; + } + + /* Query voltage state every 5 seconds, for 30 seconds. */ + svcSleepThread(5000000000UL); + } + + if (!cancel_shutdown) { + bpcShutdownSystem(); + return true; + } else { + return false; + } +} + +void PowerControlTask::MonitorBatteryState() { + PsmBatteryVoltageState bv_state = PsmBatteryVoltageState_Normal; + + /* Check the battery state, and shutdown on low voltage. */ + if (R_FAILED(psmGetBatteryVoltageState(&bv_state)) || bv_state == PsmBatteryVoltageState_NeedsShutdown) { + /* Wait a second for the error report task to finish. */ + eventWait(this->erpt_event, TimeoutHelper::NsToTick(1000000000UL)); + this->TryShutdown(); + return; + } + + /* Signal we've checked the battery at least once. */ + eventFire(this->battery_event); + + while (true) { + if (R_FAILED(psmGetBatteryVoltageState(&bv_state))) { + bv_state = PsmBatteryVoltageState_NeedsShutdown; + } + + switch (bv_state) { + case PsmBatteryVoltageState_NeedsShutdown: + case PsmBatteryVoltageState_NeedsSleep: + { + bool shutdown = this->TryShutdown(); + if (shutdown) { + return; + } + } + break; + default: + break; + } + + /* Query voltage state every 5 seconds. */ + svcSleepThread(5000000000UL); + } +} + void PowerButtonObserveTask::WaitForPowerButton() { /* Wait up to a second for error report generation to finish. */ eventWait(this->erpt_event, TimeoutHelper::NsToTick(1000000000UL)); @@ -36,6 +106,11 @@ void PowerButtonObserveTask::WaitForPowerButton() { } } +Result PowerControlTask::Run() { + MonitorBatteryState(); + return 0; +} + Result PowerButtonObserveTask::Run() { WaitForPowerButton(); return 0; diff --git a/stratosphere/fatal/source/fatal_task_power.hpp b/stratosphere/fatal/source/fatal_task_power.hpp index bdd5b7155..d31e78752 100644 --- a/stratosphere/fatal/source/fatal_task_power.hpp +++ b/stratosphere/fatal/source/fatal_task_power.hpp @@ -23,6 +23,9 @@ class PowerControlTask : public IFatalTask { private: Event *erpt_event; Event *battery_event; + private: + bool TryShutdown(); + void MonitorBatteryState(); public: PowerControlTask(FatalContext *ctx, u64 title_id, Event *er_evt, Event *bt_evt) : IFatalTask(ctx, title_id), erpt_event(er_evt), battery_event(bt_evt) { } virtual Result Run() override; From e96eaa3d7cfe9f2ac056be3ccad2a5e1e22ad9ae Mon Sep 17 00:00:00 2001 From: Michael Scire Date: Sat, 10 Nov 2018 03:05:14 -0800 Subject: [PATCH 09/33] fatal: Implement AdjustClockTask --- stratosphere/fatal/source/fatal_main.cpp | 6 +++ stratosphere/fatal/source/fatal_task.cpp | 3 +- .../fatal/source/fatal_task_clock.cpp | 45 +++++++++++++++++++ .../fatal/source/fatal_task_clock.hpp | 31 +++++++++++++ 4 files changed, 84 insertions(+), 1 deletion(-) create mode 100644 stratosphere/fatal/source/fatal_task_clock.cpp create mode 100644 stratosphere/fatal/source/fatal_task_clock.hpp diff --git a/stratosphere/fatal/source/fatal_main.cpp b/stratosphere/fatal/source/fatal_main.cpp index e01cbd7e8..d537eff42 100644 --- a/stratosphere/fatal/source/fatal_main.cpp +++ b/stratosphere/fatal/source/fatal_main.cpp @@ -77,6 +77,11 @@ void __appInit(void) { std::abort(); } + rc = pcvInitialize(); + if (R_FAILED(rc)) { + std::abort(); + } + rc = psmInitialize(); if (R_FAILED(rc)) { std::abort(); @@ -94,6 +99,7 @@ void __appExit(void) { /* Cleanup services. */ spsmExit(); psmExit(); + pcvExit(); bpcExit(); pminfoExit(); setsysExit(); diff --git a/stratosphere/fatal/source/fatal_task.cpp b/stratosphere/fatal/source/fatal_task.cpp index 43108e88b..1c474fa0f 100644 --- a/stratosphere/fatal/source/fatal_task.cpp +++ b/stratosphere/fatal/source/fatal_task.cpp @@ -19,6 +19,7 @@ #include "fatal_task.hpp" #include "fatal_task_error_report.hpp" +#include "fatal_task_clock.hpp" #include "fatal_task_power.hpp" @@ -56,7 +57,7 @@ void RunFatalTasks(FatalContext *ctx, u64 title_id, bool error_report, Event *er /* TODO: RunTask(new ShowFatalTask(ctx, title_id, battery_event)); */ /* TODO: RunTask(new StopSoundTask(ctx, title_id)); */ /* TODO: RunTask(new BacklightControlTask(ctx, title_id)); */ - /* TODO: RunTask(new AdjustClockTask(ctx, title_id)); */ + RunTask(new AdjustClockTask(ctx, title_id)); RunTask(new PowerButtonObserveTask(ctx, title_id, erpt_event)); RunTask(new StateTransitionStopTask(ctx, title_id)); } diff --git a/stratosphere/fatal/source/fatal_task_clock.cpp b/stratosphere/fatal/source/fatal_task_clock.cpp new file mode 100644 index 000000000..fe1bf93d7 --- /dev/null +++ b/stratosphere/fatal/source/fatal_task_clock.cpp @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2018 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include "fatal_task_clock.hpp" + + +Result AdjustClockTask::AdjustClock() { + /* Fatal sets the CPU to 1020MHz, the GPU to 307 MHz, and the EMC to 1331MHz. */ + constexpr u32 CPU_CLOCK_1020MHZ = 0x3CCBF700L; + constexpr u32 GPU_CLOCK_307MHZ = 0x124F8000L; + constexpr u32 EMC_CLOCK_1331MHZ = 0x4F588000L; + Result rc = 0; + + if (R_FAILED((rc = pcvSetClockRate(PcvModule_Cpu, CPU_CLOCK_1020MHZ)))) { + return rc; + } + + if (R_FAILED((rc = pcvSetClockRate(PcvModule_Gpu, GPU_CLOCK_307MHZ)))) { + return rc; + } + + if (R_FAILED((rc = pcvSetClockRate(PcvModule_Emc, EMC_CLOCK_1331MHZ)))) { + return rc; + } + + return rc; +} + +Result AdjustClockTask::Run() { + return AdjustClock(); +} \ No newline at end of file diff --git a/stratosphere/fatal/source/fatal_task_clock.hpp b/stratosphere/fatal/source/fatal_task_clock.hpp new file mode 100644 index 000000000..8ceba6945 --- /dev/null +++ b/stratosphere/fatal/source/fatal_task_clock.hpp @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2018 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once +#include +#include +#include "fatal_task.hpp" + +class AdjustClockTask : public IFatalTask { + private: + Result AdjustClock(); + public: + AdjustClockTask(FatalContext *ctx, u64 title_id) : IFatalTask(ctx, title_id) { } + virtual Result Run() override; + virtual const char *GetName() const override { + return "AdjustClockTask"; + } +}; \ No newline at end of file From 5649b6d63f5373bf27825386d5553a913413ba8c Mon Sep 17 00:00:00 2001 From: Michael Scire Date: Sat, 10 Nov 2018 03:16:13 -0800 Subject: [PATCH 10/33] fatal: Implement BacklightControlTask --- stratosphere/fatal/source/fatal_main.cpp | 6 ++++ stratosphere/fatal/source/fatal_task.cpp | 3 +- .../fatal/source/fatal_task_screen.cpp | 28 +++++++++++++++++ .../fatal/source/fatal_task_screen.hpp | 31 +++++++++++++++++++ 4 files changed, 67 insertions(+), 1 deletion(-) create mode 100644 stratosphere/fatal/source/fatal_task_screen.cpp create mode 100644 stratosphere/fatal/source/fatal_task_screen.hpp diff --git a/stratosphere/fatal/source/fatal_main.cpp b/stratosphere/fatal/source/fatal_main.cpp index d537eff42..e5f1065ce 100644 --- a/stratosphere/fatal/source/fatal_main.cpp +++ b/stratosphere/fatal/source/fatal_main.cpp @@ -82,6 +82,11 @@ void __appInit(void) { std::abort(); } + rc = lblInitialize(); + if (R_FAILED(rc)) { + std::abort(); + } + rc = psmInitialize(); if (R_FAILED(rc)) { std::abort(); @@ -99,6 +104,7 @@ void __appExit(void) { /* Cleanup services. */ spsmExit(); psmExit(); + lblExit(); pcvExit(); bpcExit(); pminfoExit(); diff --git a/stratosphere/fatal/source/fatal_task.cpp b/stratosphere/fatal/source/fatal_task.cpp index 1c474fa0f..51beefd7e 100644 --- a/stratosphere/fatal/source/fatal_task.cpp +++ b/stratosphere/fatal/source/fatal_task.cpp @@ -19,6 +19,7 @@ #include "fatal_task.hpp" #include "fatal_task_error_report.hpp" +#include "fatal_task_screen.hpp" #include "fatal_task_clock.hpp" #include "fatal_task_power.hpp" @@ -56,7 +57,7 @@ void RunFatalTasks(FatalContext *ctx, u64 title_id, bool error_report, Event *er RunTask(new PowerControlTask(ctx, title_id, erpt_event, battery_event)); /* TODO: RunTask(new ShowFatalTask(ctx, title_id, battery_event)); */ /* TODO: RunTask(new StopSoundTask(ctx, title_id)); */ - /* TODO: RunTask(new BacklightControlTask(ctx, title_id)); */ + RunTask(new BacklightControlTask(ctx, title_id)); RunTask(new AdjustClockTask(ctx, title_id)); RunTask(new PowerButtonObserveTask(ctx, title_id, erpt_event)); RunTask(new StateTransitionStopTask(ctx, title_id)); diff --git a/stratosphere/fatal/source/fatal_task_screen.cpp b/stratosphere/fatal/source/fatal_task_screen.cpp new file mode 100644 index 000000000..98e42859e --- /dev/null +++ b/stratosphere/fatal/source/fatal_task_screen.cpp @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2018 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include "fatal_task_screen.hpp" + + +void BacklightControlTask::TurnOnBacklight() { + lblSwitchBacklightOn(0); +} + +Result BacklightControlTask::Run() { + TurnOnBacklight(); + return 0; +} diff --git a/stratosphere/fatal/source/fatal_task_screen.hpp b/stratosphere/fatal/source/fatal_task_screen.hpp new file mode 100644 index 000000000..3ea9151ee --- /dev/null +++ b/stratosphere/fatal/source/fatal_task_screen.hpp @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2018 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once +#include +#include +#include "fatal_task.hpp" + +class BacklightControlTask : public IFatalTask { + private: + void TurnOnBacklight(); + public: + BacklightControlTask(FatalContext *ctx, u64 title_id) : IFatalTask(ctx, title_id) { } + virtual Result Run() override; + virtual const char *GetName() const override { + return "BacklightControlTask"; + } +}; \ No newline at end of file From 6335d21901a7cad7d11b545fe7398855af449174 Mon Sep 17 00:00:00 2001 From: Michael Scire Date: Sat, 10 Nov 2018 03:22:21 -0800 Subject: [PATCH 11/33] fatal: SleepThread takes ns, not ticks --- stratosphere/fatal/source/fatal_task_power.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stratosphere/fatal/source/fatal_task_power.cpp b/stratosphere/fatal/source/fatal_task_power.cpp index 2ebd2489e..88e934f53 100644 --- a/stratosphere/fatal/source/fatal_task_power.cpp +++ b/stratosphere/fatal/source/fatal_task_power.cpp @@ -102,7 +102,7 @@ void PowerButtonObserveTask::WaitForPowerButton() { } /* Wait 100 ms between button checks. */ - svcSleepThread(TimeoutHelper::NsToTick(100000000UL)); + svcSleepThread(100000000UL); } } From f8abd2b402ae4bebf6fea42490fe9c0b7934d771 Mon Sep 17 00:00:00 2001 From: Michael Scire Date: Sat, 10 Nov 2018 03:51:19 -0800 Subject: [PATCH 12/33] fatal: Implement the first half of StopSoundTask --- stratosphere/fatal/source/fatal_main.cpp | 6 ++ stratosphere/fatal/source/fatal_task.cpp | 3 +- .../fatal/source/fatal_task_sound.cpp | 58 +++++++++++++++++++ .../fatal/source/fatal_task_sound.hpp | 31 ++++++++++ 4 files changed, 97 insertions(+), 1 deletion(-) create mode 100644 stratosphere/fatal/source/fatal_task_sound.cpp create mode 100644 stratosphere/fatal/source/fatal_task_sound.hpp diff --git a/stratosphere/fatal/source/fatal_main.cpp b/stratosphere/fatal/source/fatal_main.cpp index e5f1065ce..9ed72b2e6 100644 --- a/stratosphere/fatal/source/fatal_main.cpp +++ b/stratosphere/fatal/source/fatal_main.cpp @@ -72,6 +72,11 @@ void __appInit(void) { std::abort(); } + rc = i2cInitialize(); + if (R_FAILED(rc)) { + std::abort(); + } + rc = bpcInitialize(); if (R_FAILED(rc)) { std::abort(); @@ -107,6 +112,7 @@ void __appExit(void) { lblExit(); pcvExit(); bpcExit(); + i2cExit(); pminfoExit(); setsysExit(); smExit(); diff --git a/stratosphere/fatal/source/fatal_task.cpp b/stratosphere/fatal/source/fatal_task.cpp index 51beefd7e..53c3c2853 100644 --- a/stratosphere/fatal/source/fatal_task.cpp +++ b/stratosphere/fatal/source/fatal_task.cpp @@ -20,6 +20,7 @@ #include "fatal_task_error_report.hpp" #include "fatal_task_screen.hpp" +#include "fatal_task_sound.hpp" #include "fatal_task_clock.hpp" #include "fatal_task_power.hpp" @@ -56,7 +57,7 @@ void RunFatalTasks(FatalContext *ctx, u64 title_id, bool error_report, Event *er RunTask(new ErrorReportTask(ctx, title_id, error_report, erpt_event)); RunTask(new PowerControlTask(ctx, title_id, erpt_event, battery_event)); /* TODO: RunTask(new ShowFatalTask(ctx, title_id, battery_event)); */ - /* TODO: RunTask(new StopSoundTask(ctx, title_id)); */ + RunTask(new StopSoundTask(ctx, title_id)); RunTask(new BacklightControlTask(ctx, title_id)); RunTask(new AdjustClockTask(ctx, title_id)); RunTask(new PowerButtonObserveTask(ctx, title_id, erpt_event)); diff --git a/stratosphere/fatal/source/fatal_task_sound.cpp b/stratosphere/fatal/source/fatal_task_sound.cpp new file mode 100644 index 000000000..9a08f331e --- /dev/null +++ b/stratosphere/fatal/source/fatal_task_sound.cpp @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2018 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include "fatal_task_sound.hpp" + + +void StopSoundTask::StopSound() { + /* Talk to the ALC5639 over I2C, and disable audio output. */ + I2cSession audio; + if (R_SUCCEEDED(i2cOpenSession(&audio, I2cDevice_AudioCodec))) { + struct { + u16 dev; + u8 val; + } __attribute__((packed)) cmd; + static_assert(sizeof(cmd) == 3, "I2C command definition!"); + + cmd.dev = 0xC801; + cmd.val = 200; + i2csessionSendAuto(&audio, &cmd, sizeof(cmd), I2cTransactionOption_All); + + cmd.dev = 0xC802; + cmd.val = 200; + i2csessionSendAuto(&audio, &cmd, sizeof(cmd), I2cTransactionOption_All); + + cmd.dev = 0xC802; + cmd.val = 200; + i2csessionSendAuto(&audio, &cmd, sizeof(cmd), I2cTransactionOption_All); + + for (u16 dev = 97; dev <= 102; dev++) { + cmd.dev = dev; + cmd.val = 0; + i2csessionSendAuto(&audio, &cmd, sizeof(cmd), I2cTransactionOption_All); + } + + i2csessionClose(&audio); + } + + /* TODO: Talk to the ALC5639 over GPIO */ +} + +Result StopSoundTask::Run() { + StopSound(); + return 0; +} \ No newline at end of file diff --git a/stratosphere/fatal/source/fatal_task_sound.hpp b/stratosphere/fatal/source/fatal_task_sound.hpp new file mode 100644 index 000000000..bbce20d4c --- /dev/null +++ b/stratosphere/fatal/source/fatal_task_sound.hpp @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2018 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once +#include +#include +#include "fatal_task.hpp" + +class StopSoundTask : public IFatalTask { + private: + void StopSound(); + public: + StopSoundTask(FatalContext *ctx, u64 title_id) : IFatalTask(ctx, title_id) { } + virtual Result Run() override; + virtual const char *GetName() const override { + return "SoundTask"; + } +}; \ No newline at end of file From 5d5f8ad3d5749c8f4b07e016439da1b60b1c4de1 Mon Sep 17 00:00:00 2001 From: Michael Scire Date: Sat, 10 Nov 2018 04:07:26 -0800 Subject: [PATCH 13/33] fatal: Finish StopSoundTask --- .../fatal/source/fatal_task_sound.cpp | 67 ++++++++++++------- .../fatal/source/fatal_task_sound.hpp | 2 +- 2 files changed, 42 insertions(+), 27 deletions(-) diff --git a/stratosphere/fatal/source/fatal_task_sound.cpp b/stratosphere/fatal/source/fatal_task_sound.cpp index 9a08f331e..2588b0ade 100644 --- a/stratosphere/fatal/source/fatal_task_sound.cpp +++ b/stratosphere/fatal/source/fatal_task_sound.cpp @@ -20,39 +20,54 @@ void StopSoundTask::StopSound() { /* Talk to the ALC5639 over I2C, and disable audio output. */ - I2cSession audio; - if (R_SUCCEEDED(i2cOpenSession(&audio, I2cDevice_AudioCodec))) { - struct { - u16 dev; - u8 val; - } __attribute__((packed)) cmd; - static_assert(sizeof(cmd) == 3, "I2C command definition!"); + { + I2cSession audio; + if (R_SUCCEEDED(i2cOpenSession(&audio, I2cDevice_AudioCodec))) { + struct { + u16 dev; + u8 val; + } __attribute__((packed)) cmd; + static_assert(sizeof(cmd) == 3, "I2C command definition!"); - cmd.dev = 0xC801; - cmd.val = 200; - i2csessionSendAuto(&audio, &cmd, sizeof(cmd), I2cTransactionOption_All); - - cmd.dev = 0xC802; - cmd.val = 200; - i2csessionSendAuto(&audio, &cmd, sizeof(cmd), I2cTransactionOption_All); - - cmd.dev = 0xC802; - cmd.val = 200; - i2csessionSendAuto(&audio, &cmd, sizeof(cmd), I2cTransactionOption_All); - - for (u16 dev = 97; dev <= 102; dev++) { - cmd.dev = dev; - cmd.val = 0; + cmd.dev = 0xC801; + cmd.val = 200; i2csessionSendAuto(&audio, &cmd, sizeof(cmd), I2cTransactionOption_All); + + cmd.dev = 0xC802; + cmd.val = 200; + i2csessionSendAuto(&audio, &cmd, sizeof(cmd), I2cTransactionOption_All); + + cmd.dev = 0xC802; + cmd.val = 200; + i2csessionSendAuto(&audio, &cmd, sizeof(cmd), I2cTransactionOption_All); + + for (u16 dev = 97; dev <= 102; dev++) { + cmd.dev = dev; + cmd.val = 0; + i2csessionSendAuto(&audio, &cmd, sizeof(cmd), I2cTransactionOption_All); + } + + i2csessionClose(&audio); } - - i2csessionClose(&audio); } - /* TODO: Talk to the ALC5639 over GPIO */ + /* Talk to the ALC5639 over GPIO, and disable audio output */ + { + GpioPadSession audio; + if (R_SUCCEEDED(gpioOpenSession(&audio, GpioPadName_AudioCodec))) { + /* Set direction output, sleep 200 ms so it can take effect. */ + gpioPadSetDirection(&audio, GpioDirection_Output); + svcSleepThread(200000000UL); + + /* Pull audio codec low. */ + gpioPadSetValue(&audio, GpioValue_Low); + + gpioPadClose(&audio); + } + } } Result StopSoundTask::Run() { StopSound(); return 0; -} \ No newline at end of file +} diff --git a/stratosphere/fatal/source/fatal_task_sound.hpp b/stratosphere/fatal/source/fatal_task_sound.hpp index bbce20d4c..a6feea049 100644 --- a/stratosphere/fatal/source/fatal_task_sound.hpp +++ b/stratosphere/fatal/source/fatal_task_sound.hpp @@ -28,4 +28,4 @@ class StopSoundTask : public IFatalTask { virtual const char *GetName() const override { return "SoundTask"; } -}; \ No newline at end of file +}; From 5f3187300dd440079a612ebf08be8c519af3fe8c Mon Sep 17 00:00:00 2001 From: Michael Scire Date: Sat, 10 Nov 2018 11:59:55 -0800 Subject: [PATCH 14/33] fatal: Skeleton ScreenDrawing code --- stratosphere/fatal/source/fatal_main.cpp | 17 ++++++++++++----- stratosphere/fatal/source/fatal_task.cpp | 2 +- stratosphere/fatal/source/fatal_task_screen.cpp | 14 ++++++++++++++ stratosphere/fatal/source/fatal_task_screen.hpp | 13 +++++++++++++ 4 files changed, 40 insertions(+), 6 deletions(-) diff --git a/stratosphere/fatal/source/fatal_main.cpp b/stratosphere/fatal/source/fatal_main.cpp index 9ed72b2e6..31cb4a798 100644 --- a/stratosphere/fatal/source/fatal_main.cpp +++ b/stratosphere/fatal/source/fatal_main.cpp @@ -32,10 +32,13 @@ extern "C" { u32 __nx_applet_type = AppletType_None; - #define INNER_HEAP_SIZE 0x380000 + #define INNER_HEAP_SIZE 0x3C0000 size_t nx_inner_heap_size = INNER_HEAP_SIZE; char nx_inner_heap[INNER_HEAP_SIZE]; + u32 __nx_nv_transfermem_size = 0x40000; + ViServiceType __nx_gfx_vi_service_type = ViServiceType_Manager; + void __libnx_initheap(void); void __appInit(void); void __appExit(void); @@ -120,18 +123,22 @@ void __appExit(void) { int main(int argc, char **argv) { - consoleDebugInit(debugDevice_SVC); - + /* TODO: Load settings from set:sys. */ + + /* TODO: Load shared font. */ + + /* TODO: Check whether we should throw fatal due to repair process... */ + /* TODO: What's a good timeout value to use here? */ auto server_manager = new WaitableManager(1); - + /* TODO: Create services. */ server_manager->AddWaitable(new ServiceServer("fatal:p", 4)); server_manager->AddWaitable(new ServiceServer("fatal:u", 4)); /* Loop forever, servicing our services. */ server_manager->Process(); - + delete server_manager; return 0; diff --git a/stratosphere/fatal/source/fatal_task.cpp b/stratosphere/fatal/source/fatal_task.cpp index 53c3c2853..39a1c82d1 100644 --- a/stratosphere/fatal/source/fatal_task.cpp +++ b/stratosphere/fatal/source/fatal_task.cpp @@ -56,7 +56,7 @@ static void RunTask(IFatalTask *task) { void RunFatalTasks(FatalContext *ctx, u64 title_id, bool error_report, Event *erpt_event, Event *battery_event) { RunTask(new ErrorReportTask(ctx, title_id, error_report, erpt_event)); RunTask(new PowerControlTask(ctx, title_id, erpt_event, battery_event)); - /* TODO: RunTask(new ShowFatalTask(ctx, title_id, battery_event)); */ + RunTask(new ShowFatalTask(ctx, title_id, battery_event)); RunTask(new StopSoundTask(ctx, title_id)); RunTask(new BacklightControlTask(ctx, title_id)); RunTask(new AdjustClockTask(ctx, title_id)); diff --git a/stratosphere/fatal/source/fatal_task_screen.cpp b/stratosphere/fatal/source/fatal_task_screen.cpp index 98e42859e..a28be3fa3 100644 --- a/stratosphere/fatal/source/fatal_task_screen.cpp +++ b/stratosphere/fatal/source/fatal_task_screen.cpp @@ -17,6 +17,20 @@ #include #include "fatal_task_screen.hpp" +Result ShowFatalTask::ShowFatal() { + Result rc = 0; + + /* TODO: Get graphics to work, draw fatal screen. */ + + return rc; +} + +Result ShowFatalTask::Run() { + /* Don't show the fatal error screen until we've verified the battery is okay. */ + eventWait(this->battery_event, U64_MAX); + + return ShowFatal(); +} void BacklightControlTask::TurnOnBacklight() { lblSwitchBacklightOn(0); diff --git a/stratosphere/fatal/source/fatal_task_screen.hpp b/stratosphere/fatal/source/fatal_task_screen.hpp index 3ea9151ee..a456a9860 100644 --- a/stratosphere/fatal/source/fatal_task_screen.hpp +++ b/stratosphere/fatal/source/fatal_task_screen.hpp @@ -19,6 +19,19 @@ #include #include "fatal_task.hpp" +class ShowFatalTask : public IFatalTask { + private: + Event *battery_event; + private: + Result ShowFatal(); + public: + ShowFatalTask(FatalContext *ctx, u64 title_id, Event *evt) : IFatalTask(ctx, title_id), battery_event(evt) { } + virtual Result Run() override; + virtual const char *GetName() const override { + return "ShowFatal"; + } +}; + class BacklightControlTask : public IFatalTask { private: void TurnOnBacklight(); From f914edeebdf14bc01a62343a13a8c1058b81eff7 Mon Sep 17 00:00:00 2001 From: Michael Scire Date: Sat, 10 Nov 2018 12:38:24 -0800 Subject: [PATCH 15/33] fatal: Implement configuration based on settings --- stratosphere/fatal/source/fatal_config.cpp | 64 +++++++++++++++++++ stratosphere/fatal/source/fatal_config.hpp | 34 ++++++++++ stratosphere/fatal/source/fatal_main.cpp | 13 +++- .../fatal/source/fatal_task_power.cpp | 9 ++- .../fatal/source/fatal_task_screen.cpp | 1 + stratosphere/fatal/source/fatal_user.cpp | 12 +++- 6 files changed, 128 insertions(+), 5 deletions(-) create mode 100644 stratosphere/fatal/source/fatal_config.cpp create mode 100644 stratosphere/fatal/source/fatal_config.hpp diff --git a/stratosphere/fatal/source/fatal_config.cpp b/stratosphere/fatal/source/fatal_config.cpp new file mode 100644 index 000000000..5583e7a0b --- /dev/null +++ b/stratosphere/fatal/source/fatal_config.cpp @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2018 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include "fatal_types.hpp" +#include "fatal_config.hpp" + +static FatalConfig g_fatal_config; + +static IEvent *g_fatal_settings_event = nullptr; + +FatalConfig *GetFatalConfig() { + return &g_fatal_config; +} + +static void UpdateLanguageCode() { + setGetLanguageCode(&GetFatalConfig()->language_code); +} + +IEvent *GetFatalSettingsEvent() { + if (g_fatal_settings_event == nullptr) { + Event evt; + if (R_FAILED(setsysBindFatalDirtyFlagEvent(&evt))) { + std::abort(); + } + g_fatal_settings_event = LoadReadOnlySystemEvent(evt.revent, [](u64 timeout) { + u64 flags_0, flags_1; + if (R_SUCCEEDED(setsysGetFatalDirtyFlags(&flags_0, &flags_1)) && (flags_0 & 1)) { + UpdateLanguageCode(); + } + return 0; + }, true); + } + + return g_fatal_settings_event; +} + +void InitializeFatalConfig() { + FatalConfig *config = GetFatalConfig(); + + memset(config, 0, sizeof(*config)); + setsysGetSerialNumber(config->serial_number); + setsysGetFirmwareVersion(&config->firmware_version); + UpdateLanguageCode(); + + setsysGetSettingsItemValue("fatal", "transition_to_fatal", &config->transition_to_fatal, sizeof(config->transition_to_fatal)); + setsysGetSettingsItemValue("fatal", "show_extra_info", &config->show_extra_info, sizeof(config->show_extra_info)); + setsysGetSettingsItemValue("fatal", "quest_reboot_interval_second", &config->quest_reboot_interval_second, sizeof(config->quest_reboot_interval_second)); + + setsysGetFlag(SetSysFlag_Quest, &config->quest_flag); +} diff --git a/stratosphere/fatal/source/fatal_config.hpp b/stratosphere/fatal/source/fatal_config.hpp new file mode 100644 index 000000000..105534bfc --- /dev/null +++ b/stratosphere/fatal/source/fatal_config.hpp @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2018 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once +#include +#include + +struct FatalConfig { + char serial_number[0x18]; + SetSysFirmwareVersion firmware_version; + u64 language_code; + u64 quest_reboot_interval_second; + bool transition_to_fatal; + bool show_extra_info; + bool quest_flag; +}; + +IEvent *GetFatalSettingsEvent(); +FatalConfig *GetFatalConfig(); + +void InitializeFatalConfig(); \ No newline at end of file diff --git a/stratosphere/fatal/source/fatal_main.cpp b/stratosphere/fatal/source/fatal_main.cpp index 31cb4a798..62324f6f1 100644 --- a/stratosphere/fatal/source/fatal_main.cpp +++ b/stratosphere/fatal/source/fatal_main.cpp @@ -26,6 +26,7 @@ #include "fatal_types.hpp" #include "fatal_private.hpp" #include "fatal_user.hpp" +#include "fatal_config.hpp" extern "C" { extern u32 __start__; @@ -65,6 +66,11 @@ void __appInit(void) { std::abort(); } + rc = setInitialize(); + if (R_FAILED(rc)) { + std::abort(); + } + rc = setsysInitialize(); if (R_FAILED(rc)) { std::abort(); @@ -118,13 +124,15 @@ void __appExit(void) { i2cExit(); pminfoExit(); setsysExit(); + setExit(); smExit(); } int main(int argc, char **argv) { - /* TODO: Load settings from set:sys. */ - + /* Load settings from set:sys. */ + InitializeFatalConfig(); + /* TODO: Load shared font. */ /* TODO: Check whether we should throw fatal due to repair process... */ @@ -135,6 +143,7 @@ int main(int argc, char **argv) /* TODO: Create services. */ server_manager->AddWaitable(new ServiceServer("fatal:p", 4)); server_manager->AddWaitable(new ServiceServer("fatal:u", 4)); + server_manager->AddWaitable(GetFatalSettingsEvent()); /* Loop forever, servicing our services. */ server_manager->Process(); diff --git a/stratosphere/fatal/source/fatal_task_power.cpp b/stratosphere/fatal/source/fatal_task_power.cpp index 88e934f53..a804d6ff5 100644 --- a/stratosphere/fatal/source/fatal_task_power.cpp +++ b/stratosphere/fatal/source/fatal_task_power.cpp @@ -16,6 +16,7 @@ #include #include "fatal_task_power.hpp" +#include "fatal_config.hpp" bool PowerControlTask::TryShutdown() { /* Set a timeout of 30 seconds. */ @@ -91,12 +92,16 @@ void PowerButtonObserveTask::WaitForPowerButton() { /* Wait up to a second for error report generation to finish. */ eventWait(this->erpt_event, TimeoutHelper::NsToTick(1000000000UL)); - /* TODO: Force a reboot after some time if kiosk unit. */ + /* Force a reboot after some time if kiosk unit. */ + const FatalConfig *config = GetFatalConfig(); + TimeoutHelper reboot_helper(config->quest_reboot_interval_second * 1000000000UL); BpcSleepButtonState state; while (true) { + + Result rc = bpcGetSleepButtonState(&state); - if (R_SUCCEEDED(rc) && state == BpcSleepButtonState_Held) { + if ((R_SUCCEEDED(rc) && state == BpcSleepButtonState_Held) || (config->quest_flag && reboot_helper.TimedOut())) { bpcRebootSystem(); return; } diff --git a/stratosphere/fatal/source/fatal_task_screen.cpp b/stratosphere/fatal/source/fatal_task_screen.cpp index a28be3fa3..5dcf40b04 100644 --- a/stratosphere/fatal/source/fatal_task_screen.cpp +++ b/stratosphere/fatal/source/fatal_task_screen.cpp @@ -16,6 +16,7 @@ #include #include "fatal_task_screen.hpp" +#include "fatal_config.hpp" Result ShowFatalTask::ShowFatal() { Result rc = 0; diff --git a/stratosphere/fatal/source/fatal_user.cpp b/stratosphere/fatal/source/fatal_user.cpp index b21aefc29..f5405267c 100644 --- a/stratosphere/fatal/source/fatal_user.cpp +++ b/stratosphere/fatal/source/fatal_user.cpp @@ -18,6 +18,7 @@ #include "fatal_user.hpp" #include "fatal_event_manager.hpp" #include "fatal_task.hpp" +#include "fatal_config.hpp" static bool g_thrown = false; @@ -37,6 +38,9 @@ Result UserService::ThrowFatalImpl(u32 error, u64 pid, FatalType policy, FatalCp ctx.error_code = error; ctx.cpu_ctx = *cpu_ctx; + /* Get config. */ + const FatalConfig *config = GetFatalConfig(); + /* Get title id. On failure, it'll be zero. */ u64 title_id = 0; pminfoGetTitleId(&title_id, pid); @@ -63,7 +67,13 @@ Result UserService::ThrowFatalImpl(u32 error, u64 pid, FatalType policy, FatalCp } /* Run tasks. */ - RunFatalTasks(&ctx, title_id, policy == FatalType_ErrorReportAndErrorScreen, &erpt_event, &battery_event); + if (config->transition_to_fatal) { + RunFatalTasks(&ctx, title_id, policy == FatalType_ErrorReportAndErrorScreen, &erpt_event, &battery_event); + } else { + /* If flag is not set, don't show the fatal screen. */ + return 0; + } + } break; default: From 29833539bbc7295c4162df66c3340bcfc5c428af Mon Sep 17 00:00:00 2001 From: Michael Scire Date: Sat, 10 Nov 2018 12:56:43 -0800 Subject: [PATCH 16/33] fatal: Split out fatal from User, stub CheckRepairStatus --- stratosphere/fatal/source/fatal_repair.cpp | 24 ++++++ stratosphere/fatal/source/fatal_repair.hpp | 21 +++++ stratosphere/fatal/source/fatal_throw.cpp | 93 ++++++++++++++++++++++ stratosphere/fatal/source/fatal_throw.hpp | 24 ++++++ stratosphere/fatal/source/fatal_user.cpp | 67 +--------------- stratosphere/fatal/source/fatal_user.hpp | 4 +- 6 files changed, 164 insertions(+), 69 deletions(-) create mode 100644 stratosphere/fatal/source/fatal_repair.cpp create mode 100644 stratosphere/fatal/source/fatal_repair.hpp create mode 100644 stratosphere/fatal/source/fatal_throw.cpp create mode 100644 stratosphere/fatal/source/fatal_throw.hpp diff --git a/stratosphere/fatal/source/fatal_repair.cpp b/stratosphere/fatal/source/fatal_repair.cpp new file mode 100644 index 000000000..b9fdefef8 --- /dev/null +++ b/stratosphere/fatal/source/fatal_repair.cpp @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2018 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include "fatal_types.hpp" +#include "fatal_repair.hpp" +#include "fatal_throw.hpp" + +void CheckRepairStatus() { + /* TODO */ +} diff --git a/stratosphere/fatal/source/fatal_repair.hpp b/stratosphere/fatal/source/fatal_repair.hpp new file mode 100644 index 000000000..a06d78c8f --- /dev/null +++ b/stratosphere/fatal/source/fatal_repair.hpp @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2018 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once +#include +#include + +void CheckRepairStatus(); \ No newline at end of file diff --git a/stratosphere/fatal/source/fatal_throw.cpp b/stratosphere/fatal/source/fatal_throw.cpp new file mode 100644 index 000000000..9650acb3d --- /dev/null +++ b/stratosphere/fatal/source/fatal_throw.cpp @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2018 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include "fatal_throw.hpp" +#include "fatal_event_manager.hpp" +#include "fatal_task.hpp" +#include "fatal_config.hpp" + +static bool g_thrown = false; + +static Result SetThrown() { + /* This should be fine, since fatal only has a single IPC thread. */ + if (g_thrown) { + return FatalResult_AlreadyThrown; + } + + g_thrown = true; + return 0; +} + +Result ThrowFatalForSelf(u32 error) { + u64 pid = 0; + FatalCpuContext ctx = {0}; + + svcGetProcessId(&pid, CUR_PROCESS_HANDLE); + return ThrowFatalImpl(error, pid, FatalType_ErrorScreen, &ctx); +} + +Result ThrowFatalImpl(u32 error, u64 pid, FatalType policy, FatalCpuContext *cpu_ctx) { + Result rc = 0; + FatalContext ctx; + ctx.error_code = error; + ctx.cpu_ctx = *cpu_ctx; + + /* Get config. */ + const FatalConfig *config = GetFatalConfig(); + + /* Get title id. On failure, it'll be zero. */ + u64 title_id = 0; + pminfoGetTitleId(&title_id, pid); + + switch (policy) { + case FatalType_ErrorReport: + /* TODO: Don't write an error report. */ + case FatalType_ErrorReportAndErrorScreen: + case FatalType_ErrorScreen: + { + /* Ensure we only throw once. */ + if (R_FAILED((rc = SetThrown()))) { + return rc; + } + + /* Signal that fatal is about to happen. */ + GetEventManager()->SignalEvents(); + + /* Create events. */ + Event erpt_event; + Event battery_event; + if (R_FAILED(eventCreate(&erpt_event, false)) || R_FAILED(eventCreate(&battery_event, false))) { + std::abort(); + } + + /* Run tasks. */ + if (config->transition_to_fatal) { + RunFatalTasks(&ctx, title_id, policy == FatalType_ErrorReportAndErrorScreen, &erpt_event, &battery_event); + } else { + /* If flag is not set, don't show the fatal screen. */ + return 0; + } + + } + break; + default: + /* N aborts here. Should we just return an error code? */ + std::abort(); + } + + return 0; +} diff --git a/stratosphere/fatal/source/fatal_throw.hpp b/stratosphere/fatal/source/fatal_throw.hpp new file mode 100644 index 000000000..1723f7b63 --- /dev/null +++ b/stratosphere/fatal/source/fatal_throw.hpp @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2018 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once +#include +#include + +#include "fatal_types.hpp" + +Result ThrowFatalForSelf(u32 error); +Result ThrowFatalImpl(u32 error, u64 pid, FatalType policy, FatalCpuContext *cpu_ctx); diff --git a/stratosphere/fatal/source/fatal_user.cpp b/stratosphere/fatal/source/fatal_user.cpp index f5405267c..98b081494 100644 --- a/stratosphere/fatal/source/fatal_user.cpp +++ b/stratosphere/fatal/source/fatal_user.cpp @@ -16,74 +16,9 @@ #include #include "fatal_user.hpp" +#include "fatal_throw.hpp" #include "fatal_event_manager.hpp" #include "fatal_task.hpp" -#include "fatal_config.hpp" - -static bool g_thrown = false; - -static Result SetThrown() { - /* This should be fine, since fatal only has a single IPC thread. */ - if (g_thrown) { - return FatalResult_AlreadyThrown; - } - - g_thrown = true; - return 0; -} - -Result UserService::ThrowFatalImpl(u32 error, u64 pid, FatalType policy, FatalCpuContext *cpu_ctx) { - Result rc = 0; - FatalContext ctx; - ctx.error_code = error; - ctx.cpu_ctx = *cpu_ctx; - - /* Get config. */ - const FatalConfig *config = GetFatalConfig(); - - /* Get title id. On failure, it'll be zero. */ - u64 title_id = 0; - pminfoGetTitleId(&title_id, pid); - - switch (policy) { - case FatalType_ErrorReport: - /* TODO: Don't write an error report. */ - case FatalType_ErrorReportAndErrorScreen: - case FatalType_ErrorScreen: - { - /* Ensure we only throw once. */ - if (R_FAILED((rc = SetThrown()))) { - return rc; - } - - /* Signal that fatal is about to happen. */ - GetEventManager()->SignalEvents(); - - /* Create events. */ - Event erpt_event; - Event battery_event; - if (R_FAILED(eventCreate(&erpt_event, false)) || R_FAILED(eventCreate(&battery_event, false))) { - std::abort(); - } - - /* Run tasks. */ - if (config->transition_to_fatal) { - RunFatalTasks(&ctx, title_id, policy == FatalType_ErrorReportAndErrorScreen, &erpt_event, &battery_event); - } else { - /* If flag is not set, don't show the fatal screen. */ - return 0; - } - - } - break; - default: - /* N aborts here. Should we just return an error code? */ - std::abort(); - } - - return 0; -} - Result UserService::ThrowFatal(u32 error, PidDescriptor pid_desc) { FatalCpuContext ctx = {0}; diff --git a/stratosphere/fatal/source/fatal_user.hpp b/stratosphere/fatal/source/fatal_user.hpp index ab46a4a9e..186a831d7 100644 --- a/stratosphere/fatal/source/fatal_user.hpp +++ b/stratosphere/fatal/source/fatal_user.hpp @@ -27,9 +27,7 @@ enum UserCmd { }; class UserService final : public IServiceObject { - private: - Result ThrowFatalImpl(u32 error, u64 pid, FatalType policy, FatalCpuContext *context); - + private: /* Actual commands. */ Result ThrowFatal(u32 error, PidDescriptor pid_desc); Result ThrowFatalWithPolicy(u32 error, PidDescriptor pid_desc, FatalType policy); From 893bad0db292588a0814f4c31206f04f4ed59b74 Mon Sep 17 00:00:00 2001 From: Michael Scire Date: Sat, 10 Nov 2018 13:15:48 -0800 Subject: [PATCH 17/33] fatal: Mostly implement CheckRepairStatus --- stratosphere/fatal/source/fatal_main.cpp | 6 +- stratosphere/fatal/source/fatal_repair.cpp | 64 +++++++++++++++++++++- 2 files changed, 66 insertions(+), 4 deletions(-) diff --git a/stratosphere/fatal/source/fatal_main.cpp b/stratosphere/fatal/source/fatal_main.cpp index 62324f6f1..130255c1b 100644 --- a/stratosphere/fatal/source/fatal_main.cpp +++ b/stratosphere/fatal/source/fatal_main.cpp @@ -27,6 +27,7 @@ #include "fatal_private.hpp" #include "fatal_user.hpp" #include "fatal_config.hpp" +#include "fatal_repair.hpp" extern "C" { extern u32 __start__; @@ -135,12 +136,13 @@ int main(int argc, char **argv) /* TODO: Load shared font. */ - /* TODO: Check whether we should throw fatal due to repair process... */ + /* Check whether we should throw fatal due to repair process. */ + CheckRepairStatus(); /* TODO: What's a good timeout value to use here? */ auto server_manager = new WaitableManager(1); - /* TODO: Create services. */ + /* Create services. */ server_manager->AddWaitable(new ServiceServer("fatal:p", 4)); server_manager->AddWaitable(new ServiceServer("fatal:u", 4)); server_manager->AddWaitable(GetFatalSettingsEvent()); diff --git a/stratosphere/fatal/source/fatal_repair.cpp b/stratosphere/fatal/source/fatal_repair.cpp index b9fdefef8..d4ff000f2 100644 --- a/stratosphere/fatal/source/fatal_repair.cpp +++ b/stratosphere/fatal/source/fatal_repair.cpp @@ -15,10 +15,70 @@ */ #include +#include #include "fatal_types.hpp" #include "fatal_repair.hpp" #include "fatal_throw.hpp" -void CheckRepairStatus() { - /* TODO */ +static bool InRepairWithoutVolHeld() { + if (GetRuntimeFirmwareVersion() < FirmwareVersion_300) { + return false; + } + + bool in_repair; + if (R_FAILED(setsysGetFlag(SetSysFlag_InRepairProcessEnable, &in_repair)) || !in_repair) { + return false; + } + + { + GpioPadSession vol_btn; + if (R_SUCCEEDED(gpioOpenSession(&vol_btn, GpioPadName_ButtonVolUp))) { + /* Ensure we close even on early return. */ + ON_SCOPE_EXIT { gpioPadClose(&vol_btn); }; + + /* Set direction input. */ + gpioPadSetDirection(&vol_btn, GpioDirection_Input); + + /* Ensure that we're holding the volume button for a full second. */ + TimeoutHelper timeout_helper(1000000000UL); + while (!timeout_helper.TimedOut()) { + GpioValue val; + if (R_FAILED(gpioPadGetValue(&vol_btn, &val)) || val != GpioValue_Low) { + return true; + } + + /* Sleep for 100 ms. */ + svcSleepThread(100000000UL); + } + } + } + + return false; +} + +static bool InRepairWithoutTimeReviserCartridge() { + if (GetRuntimeFirmwareVersion() < FirmwareVersion_500) { + return false; + } + + bool requires_time_reviser; + if (R_FAILED(setsysGetFlag(SetSysFlag_RequiresRunRepairTimeReviser, &requires_time_reviser)) || !requires_time_reviser) { + return false; + } + + /* TODO: if (!IsGamecardInserted()) { return true; } */ + + /* TODO: return GetGameCardAttribute(GetGameCardHandle()) & GameCardAttribute_Repair == GameCardAttribute_Repair; */ + + return false; +} + +void CheckRepairStatus() { + if (InRepairWithoutVolHeld()) { + ThrowFatalForSelf(FatalResult_InRepairWithoutVolHeld); + } + + if (InRepairWithoutTimeReviserCartridge()) { + ThrowFatalForSelf(FatalResult_InRepairWithoutTimeReviserCartridge); + } } From f7a7ce18476ddbdea51d392f61d3f6555c6a2c11 Mon Sep 17 00:00:00 2001 From: Michael Scire Date: Sat, 10 Nov 2018 13:17:13 -0800 Subject: [PATCH 18/33] fatal: Fix FatalType_ErrorReport fallthrough --- stratosphere/fatal/source/fatal_throw.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/stratosphere/fatal/source/fatal_throw.cpp b/stratosphere/fatal/source/fatal_throw.cpp index 9650acb3d..2eb617593 100644 --- a/stratosphere/fatal/source/fatal_throw.cpp +++ b/stratosphere/fatal/source/fatal_throw.cpp @@ -56,6 +56,7 @@ Result ThrowFatalImpl(u32 error, u64 pid, FatalType policy, FatalCpuContext *cpu switch (policy) { case FatalType_ErrorReport: /* TODO: Don't write an error report. */ + break; case FatalType_ErrorReportAndErrorScreen: case FatalType_ErrorScreen: { From caf9d11c8cc0e545f3c31ffcd81993f71592a4de Mon Sep 17 00:00:00 2001 From: Michael Scire Date: Sat, 10 Nov 2018 13:38:17 -0800 Subject: [PATCH 19/33] fatal: Finish CheckRepairStatus --- stratosphere/fatal/source/fatal_repair.cpp | 68 ++++++++++++++-------- 1 file changed, 45 insertions(+), 23 deletions(-) diff --git a/stratosphere/fatal/source/fatal_repair.cpp b/stratosphere/fatal/source/fatal_repair.cpp index d4ff000f2..432384cf7 100644 --- a/stratosphere/fatal/source/fatal_repair.cpp +++ b/stratosphere/fatal/source/fatal_repair.cpp @@ -32,25 +32,27 @@ static bool InRepairWithoutVolHeld() { { GpioPadSession vol_btn; - if (R_SUCCEEDED(gpioOpenSession(&vol_btn, GpioPadName_ButtonVolUp))) { - /* Ensure we close even on early return. */ - ON_SCOPE_EXIT { gpioPadClose(&vol_btn); }; - - /* Set direction input. */ - gpioPadSetDirection(&vol_btn, GpioDirection_Input); - - /* Ensure that we're holding the volume button for a full second. */ - TimeoutHelper timeout_helper(1000000000UL); - while (!timeout_helper.TimedOut()) { - GpioValue val; - if (R_FAILED(gpioPadGetValue(&vol_btn, &val)) || val != GpioValue_Low) { - return true; - } - - /* Sleep for 100 ms. */ - svcSleepThread(100000000UL); - } + if (R_FAILED(gpioOpenSession(&vol_btn, GpioPadName_ButtonVolUp))) { + return true; } + + /* Ensure we close even on early return. */ + ON_SCOPE_EXIT { gpioPadClose(&vol_btn); }; + + /* Set direction input. */ + gpioPadSetDirection(&vol_btn, GpioDirection_Input); + + /* Ensure that we're holding the volume button for a full second. */ + TimeoutHelper timeout_helper(1000000000UL); + while (!timeout_helper.TimedOut()) { + GpioValue val; + if (R_FAILED(gpioPadGetValue(&vol_btn, &val)) || val != GpioValue_Low) { + return true; + } + + /* Sleep for 100 ms. */ + svcSleepThread(100000000UL); + } } return false; @@ -66,11 +68,31 @@ static bool InRepairWithoutTimeReviserCartridge() { return false; } - /* TODO: if (!IsGamecardInserted()) { return true; } */ - - /* TODO: return GetGameCardAttribute(GetGameCardHandle()) & GameCardAttribute_Repair == GameCardAttribute_Repair; */ - - return false; + FsGameCardHandle gc_hnd; + u8 gc_attr; + { + FsDeviceOperator devop; + if (R_FAILED(fsOpenDeviceOperator(&devop))) { + return true; + } + + /* Ensure we close even on early return. */ + ON_SCOPE_EXIT { fsDeviceOperatorClose(&devop); }; + + /* Check that a gamecard is inserted. */ + bool inserted; + if (R_FAILED(fsDeviceOperatorIsGameCardInserted(&devop, &inserted)) || !inserted) { + return true; + } + + /* Check that we can retrieve the gamecard's attributes. */ + if (R_FAILED(fsDeviceOperatorGetGameCardHandle(&devop, &gc_hnd)) || R_FAILED(fsDeviceOperatorGetGameCardAttribute(&devop, &gc_hnd, &gc_attr))) { + return true; + } + } + + /* Check that the gamecard is a repair tool. */ + return (gc_attr & FsGameCardAttribute_Repair) == FsGameCardAttribute_Repair; } void CheckRepairStatus() { From 9f6ff2ed6ee4a023317bec1b8614621cdc34731c Mon Sep 17 00:00:00 2001 From: Michael Scire Date: Mon, 12 Nov 2018 22:26:13 -0800 Subject: [PATCH 20/33] Fatal: Implement basic background drawing. --- stratosphere/fatal/source/fatal_main.cpp | 4 +- .../fatal/source/fatal_task_screen.cpp | 151 +++++++++++++++++- .../fatal/source/fatal_task_screen.hpp | 7 + stratosphere/fatal/source/fatal_types.hpp | 1 + 4 files changed, 159 insertions(+), 4 deletions(-) diff --git a/stratosphere/fatal/source/fatal_main.cpp b/stratosphere/fatal/source/fatal_main.cpp index 130255c1b..58a270b49 100644 --- a/stratosphere/fatal/source/fatal_main.cpp +++ b/stratosphere/fatal/source/fatal_main.cpp @@ -39,8 +39,8 @@ extern "C" { char nx_inner_heap[INNER_HEAP_SIZE]; u32 __nx_nv_transfermem_size = 0x40000; - ViServiceType __nx_gfx_vi_service_type = ViServiceType_Manager; - + ViLayerFlags __nx_vi_stray_layer_flags = (ViLayerFlags)0; + void __libnx_initheap(void); void __appInit(void); void __appExit(void); diff --git a/stratosphere/fatal/source/fatal_task_screen.cpp b/stratosphere/fatal/source/fatal_task_screen.cpp index 5dcf40b04..7351e6022 100644 --- a/stratosphere/fatal/source/fatal_task_screen.cpp +++ b/stratosphere/fatal/source/fatal_task_screen.cpp @@ -18,11 +18,158 @@ #include "fatal_task_screen.hpp" #include "fatal_config.hpp" +Result ShowFatalTask::SetupDisplayInternal() { + Result rc; + ViDisplay display; + /* Try to open the display. */ + if (R_FAILED((rc = viOpenDisplay("Internal", &display)))) { + if (rc == 0xE72) { + return 0; + } else { + return rc; + } + } + /* Guarantee we close the display. */ + ON_SCOPE_EXIT { viCloseDisplay(&display); }; + + /* Turn on the screen. */ + if (R_FAILED((rc = viSetDisplayPowerState(&display, ViPowerState_On)))) { + return rc; + } + + /* Set alpha to 1.0f. */ + if (R_FAILED((rc = viSetDisplayAlpha(&display, 1.0f)))) { + return rc; + } + + return rc; +} + +Result ShowFatalTask::SetupDisplayExternal() { + Result rc; + ViDisplay display; + /* Try to open the display. */ + if (R_FAILED((rc = viOpenDisplay("External", &display)))) { + if (rc == 0xE72) { + return 0; + } else { + return rc; + } + } + /* Guarantee we close the display. */ + ON_SCOPE_EXIT { viCloseDisplay(&display); }; + + /* Set alpha to 1.0f. */ + if (R_FAILED((rc = viSetDisplayAlpha(&display, 1.0f)))) { + return rc; + } + + return rc; +} + +Result ShowFatalTask::PrepareScreenForDrawing() { + Result rc = 0; + + /* Connect to vi. */ + if (R_FAILED((rc = viInitialize(ViServiceType_Manager)))) { + return rc; + } + + /* Close other content. */ + viSetContentVisibility(false); + + /* Setup the two displays. */ + if (R_FAILED((rc = SetupDisplayInternal())) || R_FAILED((rc = SetupDisplayExternal()))) { + return rc; + } + + /* Open the default display. */ + if (R_FAILED((rc = viOpenDefaultDisplay(&this->display)))) { + return rc; + } + + /* Reset the display magnification to its default value. */ + u32 display_width, display_height; + if (R_FAILED((rc = viGetDisplayLogicalResolution(&this->display, &display_width, &display_height)))) { + return rc; + } + if (R_FAILED((rc = viSetDisplayMagnification(&this->display, 0, 0, display_width, display_height)))) { + return rc; + } + + /* Create layer to draw to. */ + if (R_FAILED((rc = viCreateLayer(&this->display, &this->layer)))) { + return rc; + } + + /* Setup the layer. */ + { + /* Display a layer of 1280 x 720 at 1.5x magnification */ + /* NOTE: N uses 2 (770x400) RGBA4444 buffers (tiled buffer + linear). */ + /* We use a single 1280x720 tiled RGB565 buffer. */ + constexpr u32 raw_width = 1280; + constexpr u32 raw_height = 720; + constexpr u32 layer_width = ((raw_width) * 3) / 2; + constexpr u32 layer_height = ((raw_height) * 3) / 2; + + const float layer_x = static_cast((display_width - layer_width) / 2); + const float layer_y = static_cast((display_height - layer_height) / 2); + u64 layer_z; + + if (R_FAILED((rc = viSetLayerSize(&this->layer, layer_width, layer_height)))) { + return rc; + } + + /* Set the layer's Z at display maximum, to be above everything else .*/ + /* NOTE: Fatal hardcodes 100 here. */ + if (R_SUCCEEDED((rc = viGetDisplayMaximumZ(&this->display, &layer_z)))) { + if (R_FAILED((rc = viSetLayerZ(&this->layer, layer_z)))) { + return rc; + } + } + + /* Center the layer in the screen. */ + if (R_FAILED((rc = viSetLayerPosition(&this->layer, layer_x, layer_y)))) { + return rc; + } + + /* Create framebuffer. */ + if (R_FAILED(rc = nwindowCreateFromLayer(&this->win, &this->layer))) { + return rc; + } + if (R_FAILED(rc = framebufferCreate(&this->fb, &this->win, raw_width, raw_height, PIXEL_FORMAT_RGB_565, 1))) { + return rc; + } + } + + + return rc; +} + Result ShowFatalTask::ShowFatal() { Result rc = 0; - /* TODO: Get graphics to work, draw fatal screen. */ - + if (R_FAILED((rc = PrepareScreenForDrawing()))) { + *(volatile u32 *)(0xCAFEBABE) = rc; + return rc; + } + + /* Dequeue a buffer. */ + u16 *tiled_buf = reinterpret_cast(framebufferBegin(&this->fb, NULL)); + if (tiled_buf == nullptr) { + return FatalResult_NullGfxBuffer; + } + + /* Draw a background. */ + for (size_t i = 0; i < this->fb.fb_size / sizeof(*tiled_buf); i++) { + tiled_buf[i] = 0x39C9; + } + + /* TODO: Actually draw meaningful shit here. */ + + /* Enqueue the buffer. */ + framebufferEnd(&fb); + return rc; } diff --git a/stratosphere/fatal/source/fatal_task_screen.hpp b/stratosphere/fatal/source/fatal_task_screen.hpp index a456a9860..bfaed2cea 100644 --- a/stratosphere/fatal/source/fatal_task_screen.hpp +++ b/stratosphere/fatal/source/fatal_task_screen.hpp @@ -22,7 +22,14 @@ class ShowFatalTask : public IFatalTask { private: Event *battery_event; + ViDisplay display; + ViLayer layer; + NWindow win; + Framebuffer fb; private: + Result SetupDisplayInternal(); + Result SetupDisplayExternal(); + Result PrepareScreenForDrawing(); Result ShowFatal(); public: ShowFatalTask(FatalContext *ctx, u64 title_id, Event *evt) : IFatalTask(ctx, title_id), battery_event(evt) { } diff --git a/stratosphere/fatal/source/fatal_types.hpp b/stratosphere/fatal/source/fatal_types.hpp index 46fafeec4..83abe9d0e 100644 --- a/stratosphere/fatal/source/fatal_types.hpp +++ b/stratosphere/fatal/source/fatal_types.hpp @@ -19,6 +19,7 @@ #include enum FatalResult : Result { + FatalResult_NullGfxBuffer = 0x4A3, FatalResult_AlreadyThrown = 0x6A3, FatalResult_TooManyEvents = 0x8A3, FatalResult_InRepairWithoutVolHeld = 0xAA3, From 8550f722ca6cec1d1ea040319b0cd35aab96680b Mon Sep 17 00:00:00 2001 From: Michael Scire Date: Tue, 13 Nov 2018 06:03:30 -0800 Subject: [PATCH 21/33] fatal: Implement basic text rendering. --- stratosphere/fatal/Makefile | 4 +- stratosphere/fatal/source/ams_logo.hpp | 1304 +++++++++++++++++ stratosphere/fatal/source/fatal_font.cpp | 149 ++ stratosphere/fatal/source/fatal_font.hpp | 35 + stratosphere/fatal/source/fatal_main.cpp | 14 +- stratosphere/fatal/source/fatal_task.cpp | 6 +- .../fatal/source/fatal_task_screen.cpp | 39 +- 7 files changed, 1541 insertions(+), 10 deletions(-) create mode 100644 stratosphere/fatal/source/ams_logo.hpp create mode 100644 stratosphere/fatal/source/fatal_font.cpp create mode 100644 stratosphere/fatal/source/fatal_font.hpp diff --git a/stratosphere/fatal/Makefile b/stratosphere/fatal/Makefile index c042e968d..4fba60450 100644 --- a/stratosphere/fatal/Makefile +++ b/stratosphere/fatal/Makefile @@ -34,14 +34,14 @@ ARCH := -march=armv8-a -mtune=cortex-a57 -mtp=soft -fPIE CFLAGS := -g -Wall -O2 -ffunction-sections \ $(ARCH) $(DEFINES) -CFLAGS += $(INCLUDE) -D__SWITCH__ +CFLAGS += $(INCLUDE) -D__SWITCH__ `freetype-config --cflags` CXXFLAGS := $(CFLAGS) -fno-rtti -fno-exceptions -std=gnu++17 ASFLAGS := -g $(ARCH) LDFLAGS = -specs=$(DEVKITPRO)/libnx/switch.specs -g $(ARCH) -Wl,-Map,$(notdir $*.map) -LIBS := -lstratosphere -lnx +LIBS := `freetype-config --libs` -lstratosphere -lnx #--------------------------------------------------------------------------------- # list of directories containing libraries, this must be the top level containing diff --git a/stratosphere/fatal/source/ams_logo.hpp b/stratosphere/fatal/source/ams_logo.hpp new file mode 100644 index 000000000..6d64bc5c3 --- /dev/null +++ b/stratosphere/fatal/source/ams_logo.hpp @@ -0,0 +1,1304 @@ +/* + * Copyright (c) 2018 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once +#define AMS_LOGO_WIDTH 0xA0 +#define AMS_LOGO_HEIGHT 0x80 + +static constexpr u16 AMS_LOGO_BIN[] = { + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39EA, 0x6B4F, 0x9494, 0xB597, 0xC619, 0xD69B, + 0xDEDB, 0xCE7A, 0xBDB8, 0x9CD4, 0x6B4F, 0x39EA, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x6B6F, 0xBDD8, 0xFFBF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xF79E, 0xB577, 0x5AED, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x630E, 0xD67A, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xC639, 0x5ACD, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x420A, 0xAD76, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0x9CD4, 0x39EA, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x528C, 0xDEDC, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xCE5A, 0x422B, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x5ACD, 0xEF5D, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xDEFC, 0x4A6C, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x528C, 0xEF7E, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xE6FC, 0x422B, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x420A, 0xDEDB, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xCE5A, 0x39EA, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0xBDD8, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xAD36, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x8C73, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0x7BF1, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x6B4F, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFBF, 0x5ACD, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x4A6C, 0xEF7E, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xE71C, 0x422B, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39EA, 0xD69B, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xC619, 0x39CA, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0xAD56, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0x94B4, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x8412, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0x7390, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x5AED, 0xFFBF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xF79E, 0x528C, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x422B, 0xE71D, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xDEBB, 0x39EA, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39CA, 0xC619, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xB577, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x9CD4, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0x8432, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x7390, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFDF, 0x630E, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x52AC, 0xF79E, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xEF5D, 0x4A4B, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x420A, 0xDEDC, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xCE5A, 0x39EA, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0xB597, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0x9CF5, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x8C32, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0x7BD1, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x630E, 0xFFDF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xF7BE, 0x52AD, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x4A4B, 0xEF5D, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xDEFC, 0x420A, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39EA, 0xCE7A, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xBDD8, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0xA515, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0x8C73, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x7BD1, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0x6B4F, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x5ACD, + 0xFFBF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xEF7E, + 0x4A6C, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x420A, 0xDEFC, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xD69B, 0x39EA, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0xBDF8, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xAD36, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x9493, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0x7BF1, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x6B4F, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFBF, 0x5ACD, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x4A6C, 0xF77E, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xE71D, 0x422B, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39EA, 0xD6BB, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xC619, 0x39CA, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0xAD56, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0x9CB4, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x8412, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0x7390, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x5AED, 0xFFBF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xF79E, 0x52AC, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x422B, 0xE73D, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xDEDC, 0x420A, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39EA, 0xC639, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xB597, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x9CD4, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0x8C32, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x7390, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFDF, 0x630E, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x52AC, 0xF79E, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xEF5D, 0x4A4B, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x420A, 0xDEDC, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xCE7A, 0x39EA, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0xBDD8, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xA515, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x8C52, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0x7BD1, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x630E, 0xFFDF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFBF, 0x5ACD, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x4A4B, 0xEF5D, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xDEFC, 0x420A, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39EA, + 0xCE7A, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xBDD8, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0xA515, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0x9473, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x7BD1, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0x6B4F, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x5ACD, 0xFFBF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xF77E, 0x4A6C, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x422B, 0xE71C, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xD6BB, 0x39EA, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0xBDF8, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xAD56, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x9493, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0x8412, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x6B4F, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFBF, 0x5AED, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x4A6C, 0xF77E, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xE71D, 0x422B, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39EA, 0xD6BB, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xC639, 0x39CA, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0xAD56, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0x9CD4, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x8432, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0x7390, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x630E, 0xFFDF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xF79E, 0x52AC, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x422B, 0xE73D, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xDEDC, 0x420A, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39EA, 0xB5FA, 0xD71E, 0xD71E, 0xDF3E, 0xDF3E, 0xE75E, 0xE77E, 0xE77F, 0xEF9F, 0xEF9F, 0xF7DF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xB597, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x6BD2, 0x8D9B, 0x8D9B, 0x8D9B, 0x8D9B, 0x8D9B, 0x8D9B, 0x8D9B, 0x8D9B, 0x8D9B, 0x8D9B, 0x8D9B, + 0x95BB, 0x9DFB, 0xAE3C, 0xB67C, 0xC6BD, 0xD6FE, 0xDF3E, 0xEF7F, 0xFFDF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0x8412, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x52EE, 0x8D7B, 0x8D9B, 0x8D9B, 0x8D9B, 0x8D9B, 0x8D9B, 0x8D9B, 0x8D9B, 0x8D9B, 0x8D9B, 0x8D9B, 0x8D9B, + 0x8D9B, 0x8D9B, 0x8D9B, 0x8D9B, 0x8D9B, 0x8D9B, 0x8D9B, 0x8D9B, 0x8D9B, 0x95DB, 0xA61C, 0xBE9D, 0xCEFD, 0xE75E, 0xF7BF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFDF, 0x5AEE, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x424B, 0x8539, 0x8D7B, 0x8D7B, 0x8D7B, 0x8D7B, 0x8D7B, 0x8D7B, 0x8D7B, 0x8D7B, 0x8D9B, 0x8D9B, 0x8D9B, 0x8D9B, + 0x8D9B, 0x8D9B, 0x8D9B, 0x8D9B, 0x8D9B, 0x8D9B, 0x8D9B, 0x8D9B, 0x8D9B, 0x8D9B, 0x8D9B, 0x8D9B, 0x8D9B, 0x8D9B, 0x8D9B, 0x9DDB, + 0xB65C, 0xCEFE, 0xEF9F, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xE73D, 0x422B, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39EA, 0x7CD7, 0x8D7B, 0x8D7B, 0x8D7B, 0x8D7B, 0x8D7B, 0x8D7B, 0x8D7B, 0x8D7B, 0x8D7B, 0x8D7B, 0x8D7B, 0x8D7B, 0x8D7B, + 0x8D7B, 0x8D7B, 0x8D7B, 0x8D7B, 0x8D7B, 0x8D9B, 0x8D9B, 0x8D9B, 0x8D9B, 0x8D9B, 0x8D9B, 0x8D9B, 0x8D9B, 0x8D9B, 0x8D9B, 0x8D9B, + 0x8D9B, 0x8D9B, 0x8D9B, 0x95BB, 0xA61C, 0xC6BD, 0xDF5E, 0xFFDF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xC639, 0x39EA, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x6BF4, 0x8D5B, 0x8D5B, 0x8D5B, 0x8D7B, 0x8D7B, 0x8D7B, 0x8D7B, 0x8D7B, 0x8D7B, 0x8D7B, 0x8D7B, 0x8D7B, 0x8D7B, 0x8D7B, + 0x8D7B, 0x8D7B, 0x8D7B, 0x8D7B, 0x8D7B, 0x8D7B, 0x8D7B, 0x8D7B, 0x8D7B, 0x8D7B, 0x8D7B, 0x8D7B, 0x8D7B, 0x8D7B, 0x8D9B, 0x8D9B, + 0x8D9B, 0x8D9B, 0x8D9B, 0x8D9B, 0x8D9B, 0x8D9B, 0x8D9B, 0x95BB, 0xAE3C, 0xD71E, 0xF7DF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xA515, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x5B30, 0x8D5A, 0x8D5A, 0x8D5A, 0x8D5A, 0x8D5B, 0x8D5B, 0x8D5B, 0x8D5B, 0x8D5B, 0x8D5B, 0x8D5B, 0x8D5B, 0x8D5B, 0x8D7B, 0x8D7B, + 0x8D7B, 0x8D7B, 0x8D7B, 0x8D7B, 0x8D7B, 0x8D7B, 0x8D7B, 0x8D7B, 0x8D7B, 0x8D7B, 0x8D7B, 0x8D7B, 0x8D7B, 0x8D7B, 0x8D7B, 0x8D7B, + 0x8D7B, 0x8D7B, 0x8D7B, 0x8D7B, 0x8D7B, 0x8D7B, 0x8D7B, 0x8D7B, 0x8D9B, 0x8D9B, 0x8D9B, 0xA5FC, 0xCEDD, 0xEF9F, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0x7390, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x4A6D, + 0x853A, 0x8D5A, 0x8D5A, 0x8D5A, 0x8D5A, 0x8D5A, 0x8D5A, 0x8D5A, 0x8D5A, 0x8D5A, 0x8D5A, 0x8D5A, 0x8D5A, 0x8D5A, 0x8D5B, 0x8D5B, + 0x8D5B, 0x8D5B, 0x8D5B, 0x8D5B, 0x8D5B, 0x8D5B, 0x8D5B, 0x8D5B, 0x8D7B, 0x8D7B, 0x8D7B, 0x8D7B, 0x8D7B, 0x8D7B, 0x8D7B, 0x8D7B, + 0x8D7B, 0x8D7B, 0x8D7B, 0x8D7B, 0x8D7B, 0x8D7B, 0x8D7B, 0x8D7B, 0x8D7B, 0x8D7B, 0x8D7B, 0x8D7B, 0x8D7B, 0x8D7B, 0xA5FC, 0xC6BD, + 0xEF9F, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xF79E, + 0x52AC, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x420B, 0x7CD8, + 0x8D3A, 0x8D3A, 0x8D3A, 0x8D3A, 0x8D3A, 0x8D3A, 0x8D3A, 0x8D3A, 0x8D5A, 0x8D5A, 0x8D5A, 0x8D5A, 0x8D5A, 0x8D5A, 0x8D5A, 0x8D5A, + 0x8D5A, 0x8D5A, 0x8D5A, 0x8D5A, 0x8D5A, 0x8D5A, 0x8D5A, 0x8D5A, 0x8D5B, 0x8D5B, 0x8D5B, 0x8D5B, 0x8D5B, 0x8D5B, 0x8D5B, 0x8D5B, + 0x8D5B, 0x8D7B, 0x8D7B, 0x8D7B, 0x8D7B, 0x8D7B, 0x8D7B, 0x8D7B, 0x8D7B, 0x8D7B, 0x8D7B, 0x8D7B, 0x8D7B, 0x8D7B, 0x8D7B, 0x8D7B, + 0x8D7B, 0xA5DC, 0xCEDD, 0xFFDF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xDEDC, 0x420A, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39EA, 0x7456, 0x8D3A, + 0x8D3A, 0x8D3A, 0x8D3A, 0x8D3A, 0x8D3A, 0x8D3A, 0x8D3A, 0x8D3A, 0x8D3A, 0x8D3A, 0x8D3A, 0x8D3A, 0x8D3A, 0x8D3A, 0x8D3A, 0x8D3A, + 0x8D3A, 0x8D5A, 0x8D5A, 0x8D5A, 0x8D5A, 0x8D5A, 0x8D5A, 0x8D5A, 0x8D5A, 0x8D5A, 0x8D5A, 0x8D5A, 0x8D5A, 0x8D5A, 0x8D5A, 0x8D5A, + 0x8D5A, 0x8D5B, 0x8D5B, 0x8D5B, 0x8D5B, 0x8D5B, 0x8D5B, 0x8D5B, 0x8D5B, 0x8D5B, 0x8D7B, 0x8D7B, 0x8D7B, 0x8D7B, 0x8D7B, 0x8D7B, + 0x8D7B, 0x8D7B, 0x8D7B, 0x8D7B, 0xAE3C, 0xDF3E, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xBDF8, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x6372, 0x851A, 0x851A, + 0x851A, 0x853A, 0x853A, 0x853A, 0x853A, 0x853A, 0x853A, 0x853A, 0x8D3A, 0x8D3A, 0x8D3A, 0x8D3A, 0x8D3A, 0x8D3A, 0x8D3A, 0x8D3A, + 0x8D3A, 0x8D3A, 0x8D3A, 0x8D3A, 0x8D3A, 0x8D3A, 0x8D3A, 0x8D3A, 0x8D3A, 0x8D3A, 0x8D5A, 0x8D5A, 0x8D5A, 0x8D5A, 0x8D5A, 0x8D5A, + 0x8D5A, 0x8D5A, 0x8D5A, 0x8D5A, 0x8D5A, 0x8D5A, 0x8D5A, 0x8D5A, 0x8D5A, 0x8D5A, 0x8D5B, 0x8D5B, 0x8D5B, 0x8D5B, 0x8D5B, 0x8D5B, + 0x8D5B, 0x8D5B, 0x8D5B, 0x8D5B, 0x8D7B, 0x8D7B, 0x9DDB, 0xCEDD, 0xFFDF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0x8C73, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x52EF, 0x851A, 0x851A, 0x851A, + 0x851A, 0x851A, 0x851A, 0x851A, 0x851A, 0x851A, 0x851A, 0x851A, 0x851A, 0x851A, 0x851A, 0x853A, 0x853A, 0x853A, 0x853A, 0x853A, + 0x853A, 0x8D3A, 0x8D3A, 0x8D3A, 0x8D3A, 0x8D3A, 0x8D3A, 0x8D3A, 0x8D3A, 0x8D3A, 0x8D3A, 0x8D3A, 0x8D3A, 0x8D3A, 0x8D3A, 0x8D3A, + 0x8D3A, 0x8D3A, 0x8D3A, 0x8D3A, 0x8D5A, 0x8D5A, 0x8D5A, 0x8D5A, 0x8D5A, 0x8D5A, 0x8D5A, 0x8D5A, 0x8D5A, 0x8D5A, 0x8D5A, 0x8D5A, + 0x8D5A, 0x8D5A, 0x8D5A, 0x8D5A, 0x8D5B, 0x8D5B, 0x8D5B, 0x8D5B, 0x8D7B, 0xB65C, 0xEF9F, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFDF, 0x632E, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x424C, 0x84F9, 0x851A, 0x851A, 0x851A, + 0x851A, 0x851A, 0x851A, 0x851A, 0x851A, 0x851A, 0x851A, 0x851A, 0x851A, 0x851A, 0x851A, 0x851A, 0x851A, 0x851A, 0x851A, 0x851A, + 0x851A, 0x851A, 0x851A, 0x851A, 0x853A, 0x853A, 0x853A, 0x853A, 0x853A, 0x853A, 0x853A, 0x8D3A, 0x8D3A, 0x8D3A, 0x8D3A, 0x8D3A, + 0x8D3A, 0x8D3A, 0x8D3A, 0x8D3A, 0x8D3A, 0x8D3A, 0x8D3A, 0x8D3A, 0x8D3A, 0x8D3A, 0x8D3A, 0x8D3A, 0x8D3A, 0x8D5A, 0x8D5A, 0x8D5A, + 0x8D5A, 0x8D5A, 0x8D5A, 0x8D5A, 0x8D5A, 0x8D5A, 0x8D5A, 0x8D5A, 0x8D5A, 0x8D5A, 0x8D5A, 0xAE1C, 0xDF3E, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xF77E, 0x4A6C, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x3A0A, 0x7C78, 0x84FA, 0x84FA, 0x84FA, 0x84FA, + 0x84FA, 0x84FA, 0x84FA, 0x84FA, 0x851A, 0x851A, 0x851A, 0x851A, 0x851A, 0x851A, 0x851A, 0x851A, 0x851A, 0x851A, 0x851A, 0x851A, + 0x851A, 0x851A, 0x851A, 0x851A, 0x851A, 0x851A, 0x851A, 0x851A, 0x851A, 0x851A, 0x851A, 0x851A, 0x851A, 0x853A, 0x853A, 0x853A, + 0x853A, 0x853A, 0x853A, 0x853A, 0x8D3A, 0x8D3A, 0x8D3A, 0x8D3A, 0x8D3A, 0x8D3A, 0x8D3A, 0x8D3A, 0x8D3A, 0x8D3A, 0x8D3A, 0x8D3A, + 0x8D3A, 0x8D3A, 0x8D3A, 0x8D3A, 0x8D3A, 0x8D3A, 0x8D5A, 0x8D5A, 0x8D5A, 0x8D5A, 0x8D5A, 0x8D5A, 0x8D5A, 0xA5DB, 0xD71E, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xCE7A, 0x39EA, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x6BD4, 0x84FA, 0x84FA, 0x84FA, 0x84FA, 0x84FA, + 0x84FA, 0x84FA, 0x84FA, 0x84FA, 0x84FA, 0x84FA, 0x84FA, 0x84FA, 0x84FA, 0x84FA, 0x84FA, 0x84FA, 0x84FA, 0x851A, 0x851A, 0x851A, + 0x851A, 0x851A, 0x851A, 0x851A, 0x851A, 0x851A, 0x851A, 0x851A, 0x851A, 0x851A, 0x851A, 0x851A, 0x851A, 0x851A, 0x851A, 0x851A, + 0x851A, 0x851A, 0x851A, 0x851A, 0x851A, 0x851A, 0x853A, 0x853A, 0x853A, 0x853A, 0x853A, 0x853A, 0x853A, 0x8D3A, 0x8D3A, 0x8D3A, + 0x8D3A, 0x8D3A, 0x8D3A, 0x8D3A, 0x8D3A, 0x8D3A, 0x8D3A, 0x8D3A, 0x8D3A, 0x8D3A, 0x8D3A, 0x8D3A, 0x8D3A, 0x8D3A, 0x8D3A, 0xA5DB, + 0xE73E, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xAD56, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x5B31, 0x84DA, 0x84DA, 0x84DA, 0x84FA, 0x84FA, 0x84FA, + 0x84FA, 0x84FA, 0x84FA, 0x84FA, 0x84FA, 0x84FA, 0x84FA, 0x84FA, 0x84FA, 0x84FA, 0x84FA, 0x84FA, 0x84FA, 0x84FA, 0x84FA, 0x84FA, + 0x84FA, 0x84FA, 0x84FA, 0x84FA, 0x84FA, 0x84FA, 0x84FA, 0x851A, 0x851A, 0x851A, 0x851A, 0x851A, 0x851A, 0x851A, 0x851A, 0x851A, + 0x851A, 0x851A, 0x851A, 0x851A, 0x851A, 0x851A, 0x851A, 0x851A, 0x851A, 0x851A, 0x851A, 0x851A, 0x851A, 0x851A, 0x851A, 0x851A, + 0x853A, 0x853A, 0x853A, 0x853A, 0x853A, 0x853A, 0x8D3A, 0x8D3A, 0x8D3A, 0x8D3A, 0x8D3A, 0x8D3A, 0x8D3A, 0x8D3A, 0x8D3A, 0x8D3A, + 0x8D3A, 0xA5DC, 0xE75E, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0x8412, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x4A8D, 0x84DA, 0x84DA, 0x84DA, 0x84DA, 0x84DA, 0x84DA, 0x84DA, + 0x84DA, 0x84DA, 0x84DA, 0x84DA, 0x84DA, 0x84DA, 0x84DA, 0x84FA, 0x84FA, 0x84FA, 0x84FA, 0x84FA, 0x84FA, 0x84FA, 0x84FA, 0x84FA, + 0x84FA, 0x84FA, 0x84FA, 0x84FA, 0x84FA, 0x84FA, 0x84FA, 0x84FA, 0x84FA, 0x84FA, 0x84FA, 0x84FA, 0x84FA, 0x84FA, 0x84FA, 0x84FA, + 0x851A, 0x851A, 0x851A, 0x851A, 0x851A, 0x851A, 0x851A, 0x851A, 0x851A, 0x851A, 0x851A, 0x851A, 0x851A, 0x851A, 0x851A, 0x851A, + 0x851A, 0x851A, 0x851A, 0x851A, 0x851A, 0x851A, 0x851A, 0x851A, 0x851A, 0x853A, 0x853A, 0x853A, 0x853A, 0x853A, 0x853A, 0x853A, + 0x8D3A, 0x8D3A, 0x8D3A, 0xB61C, 0xEF9F, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xF7BF, 0x5ACD, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x422B, 0x7C78, 0x84DA, 0x84DA, 0x84DA, 0x84DA, 0x84DA, 0x84DA, 0x84DA, + 0x84DA, 0x84DA, 0x84DA, 0x84DA, 0x84DA, 0x84DA, 0x84DA, 0x84DA, 0x84DA, 0x84DA, 0x84DA, 0x84DA, 0x84DA, 0x84DA, 0x84DA, 0x84DA, + 0x84FA, 0x84FA, 0x84FA, 0x84FA, 0x84FA, 0x84FA, 0x84FA, 0x84FA, 0x84FA, 0x84FA, 0x84FA, 0x84FA, 0x84FA, 0x84FA, 0x84FA, 0x84FA, + 0x84FA, 0x84FA, 0x84FA, 0x84FA, 0x84FA, 0x84FA, 0x84FA, 0x84FA, 0x84FA, 0x851A, 0x851A, 0x851A, 0x851A, 0x851A, 0x851A, 0x851A, + 0x851A, 0x851A, 0x851A, 0x851A, 0x851A, 0x851A, 0x851A, 0x851A, 0x851A, 0x851A, 0x851A, 0x851A, 0x851A, 0x851A, 0x851A, 0x851A, + 0x851A, 0x851A, 0x853A, 0x853A, 0x8D3A, 0xB65C, 0xF7BF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xE71C, 0x422B, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39CA, 0x6BF6, 0x84BA, 0x84BA, 0x84BA, 0x84BA, 0x84BA, 0x84BA, 0x84BA, 0x84BA, + 0x84DA, 0x84DA, 0x84DA, 0x84DA, 0x84DA, 0x84DA, 0x84DA, 0x84DA, 0x84DA, 0x84DA, 0x84DA, 0x84DA, 0x84DA, 0x84DA, 0x84DA, 0x84DA, + 0x84DA, 0x84DA, 0x84DA, 0x84DA, 0x84DA, 0x84DA, 0x84DA, 0x84DA, 0x84DA, 0x84FA, 0x84FA, 0x84FA, 0x84FA, 0x84FA, 0x84FA, 0x84FA, + 0x84FA, 0x84FA, 0x84FA, 0x84FA, 0x84FA, 0x84FA, 0x84FA, 0x84FA, 0x84FA, 0x84FA, 0x84FA, 0x84FA, 0x84FA, 0x84FA, 0x84FA, 0x84FA, + 0x84FA, 0x84FA, 0x851A, 0x851A, 0x851A, 0x851A, 0x851A, 0x851A, 0x851A, 0x851A, 0x851A, 0x851A, 0x851A, 0x851A, 0x851A, 0x851A, + 0x851A, 0x851A, 0x851A, 0x851A, 0x851A, 0x851A, 0x955B, 0xD6DE, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xBDF8, 0x39CA, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x6373, 0x7CBA, 0x7CBA, 0x7CBA, 0x7CBA, 0x7CBA, 0x7CBA, 0x7CBA, 0x84BA, 0x84BA, + 0x84BA, 0x84BA, 0x84BA, 0x84BA, 0x84BA, 0x84BA, 0x84BA, 0x84BA, 0x84BA, 0x84DA, 0x84DA, 0x84DA, 0x84DA, 0x84DA, 0x84DA, 0x84DA, + 0x84DA, 0x84DA, 0x84DA, 0x84DA, 0x84DA, 0x84DA, 0x84DA, 0x84DA, 0x84DA, 0x84DA, 0x84DA, 0x84DA, 0x84DA, 0x84DA, 0x84DA, 0x84DA, + 0x84DA, 0x84DA, 0x84DA, 0x84FA, 0x84FA, 0x84FA, 0x84FA, 0x84FA, 0x84FA, 0x84FA, 0x84FA, 0x84FA, 0x84FA, 0x84FA, 0x84FA, 0x84FA, + 0x84FA, 0x84FA, 0x84FA, 0x84FA, 0x84FA, 0x84FA, 0x84FA, 0x84FA, 0x84FA, 0x84FA, 0x84FA, 0x84FA, 0x851A, 0x851A, 0x851A, 0x851A, + 0x851A, 0x851A, 0x851A, 0x851A, 0x851A, 0x851A, 0x851A, 0x851A, 0xA5BB, 0xEF7F, 0xFFDF, 0xFFDF, 0xFFDF, 0xFFDF, 0xFFDF, 0xFFDF, + 0xFFDF, 0xFFDF, 0xFFDF, 0xFFDF, 0xFFDF, 0xFFDF, 0xFFDF, 0xFFDF, 0xFFDF, 0xFFDF, 0xFFDF, 0xFFDF, 0xFFDF, 0xFFDF, 0xFFDF, 0xFFDF, + 0xFFDF, 0xFFDF, 0xFFDF, 0xFFDF, 0xFFDF, 0xFFDF, 0xFFDF, 0xFFDF, 0xFFDF, 0xFFDF, 0xFFDF, 0xFFDF, 0xFFDF, 0xFFDF, 0xFFDF, 0xFFDF, + 0xFFDF, 0xFFDF, 0xFFDF, 0xFFDF, 0xFFDF, 0xFFDF, 0xFFDF, 0xFFDF, 0xFFDF, 0xFFDF, 0xFFDF, 0xFFDF, 0xFFDF, 0xFFDF, 0xFFDF, 0xFFDF, + 0xFFDF, 0xFFDF, 0xFFDF, 0xFFDF, 0xFFDF, 0xFFDF, 0xFFDF, 0xFFDF, 0xFFDF, 0x94D4, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x52F0, 0x7C9A, 0x7C9A, 0x7C9A, 0x7C9A, 0x7CBA, 0x7CBA, 0x7CBA, 0x7CBA, 0x7CBA, 0x7CBA, + 0x7CBA, 0x7CBA, 0x7CBA, 0x7CBA, 0x7CBA, 0x7CBA, 0x7CBA, 0x84BA, 0x84BA, 0x84BA, 0x84BA, 0x84BA, 0x84BA, 0x84BA, 0x84BA, 0x84BA, + 0x84BA, 0x84BA, 0x84BA, 0x84DA, 0x84DA, 0x84DA, 0x84DA, 0x84DA, 0x84DA, 0x84DA, 0x84DA, 0x84DA, 0x84DA, 0x84DA, 0x84DA, 0x84DA, + 0x84DA, 0x84DA, 0x84DA, 0x84DA, 0x84DA, 0x84DA, 0x84DA, 0x84DA, 0x84DA, 0x84DA, 0x84DA, 0x84DA, 0x84FA, 0x84FA, 0x84FA, 0x84FA, + 0x84FA, 0x84FA, 0x84FA, 0x84FA, 0x84FA, 0x84FA, 0x84FA, 0x84FA, 0x84FA, 0x84FA, 0x84FA, 0x84FA, 0x84FA, 0x84FA, 0x84FA, 0x84FA, + 0x84FA, 0x84FA, 0x84FA, 0x84FA, 0x84FA, 0x851A, 0x851A, 0x851A, 0x851A, 0x851A, 0xBE5D, 0xF7BF, 0xFFDF, 0xFFDF, 0xFFDF, 0xFFDF, + 0xFFDF, 0xFFDF, 0xFFDF, 0xFFDF, 0xFFDF, 0xFFDF, 0xFFDF, 0xFFDF, 0xFFDF, 0xFFDF, 0xFFDF, 0xFFDF, 0xFFDF, 0xFFDF, 0xFFDF, 0xFFDF, + 0xFFDF, 0xFFDF, 0xFFDF, 0xFFDF, 0xFFDF, 0xFFDF, 0xFFDF, 0xFFDF, 0xFFDF, 0xFFDF, 0xFFDF, 0xFFDF, 0xFFDF, 0xFFDF, 0xFFDF, 0xFFDF, + 0xFFDF, 0xFFDF, 0xFFDF, 0xFFDF, 0xFFDF, 0xFFDF, 0xFFDF, 0xFFDF, 0xFFDF, 0xFFDF, 0xFFDF, 0xFFDF, 0xFFDF, 0xFFDF, 0xFFDF, 0xFFDF, + 0xFFDF, 0xFFDF, 0xFFDF, 0xFFDF, 0xFFDF, 0xFFDF, 0xFFDF, 0xFFDF, 0xFFDF, 0xF7DF, 0x7390, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x424D, 0x7C79, 0x7C9A, 0x7C9A, 0x7C9A, 0x7C9A, 0x7C9A, 0x7C9A, 0x7C9A, 0x7C9A, 0x7C9A, 0x7C9A, + 0x7C9A, 0x7C9A, 0x7C9A, 0x7CBA, 0x7CBA, 0x7CBA, 0x7CBA, 0x7CBA, 0x7CBA, 0x7CBA, 0x7CBA, 0x7CBA, 0x7CBA, 0x7CBA, 0x7CBA, 0x7CBA, + 0x84BA, 0x84BA, 0x84BA, 0x84BA, 0x84BA, 0x84BA, 0x84BA, 0x84BA, 0x84BA, 0x84BA, 0x84BA, 0x84BA, 0x84DA, 0x84DA, 0x84DA, 0x84DA, + 0x84DA, 0x84DA, 0x84DA, 0x84DA, 0x84DA, 0x84DA, 0x84DA, 0x84DA, 0x84DA, 0x84DA, 0x84DA, 0x84DA, 0x84DA, 0x84DA, 0x84DA, 0x84DA, + 0x84DA, 0x84DA, 0x84DA, 0x84DA, 0x84DA, 0x84FA, 0x84FA, 0x84FA, 0x84FA, 0x84FA, 0x84FA, 0x84FA, 0x84FA, 0x84FA, 0x84FA, 0x84FA, + 0x84FA, 0x84FA, 0x84FA, 0x84FA, 0x84FA, 0x84FA, 0x84FA, 0x84FA, 0x84FA, 0x84FA, 0x84FA, 0x957B, 0xDF1E, 0xFFDF, 0xFFDF, 0xFFDF, + 0xFFDF, 0xFFDF, 0xFFDF, 0xFFDF, 0xFFDF, 0xFFDF, 0xFFDF, 0xFFDF, 0xFFDF, 0xFFDF, 0xFFDF, 0xFFDF, 0xFFDF, 0xFFDF, 0xFFDF, 0xFFDF, + 0xFFDF, 0xFFDF, 0xFFDF, 0xFFDF, 0xFFDF, 0xFFDF, 0xFFDF, 0xFFDF, 0xFFDF, 0xFFDF, 0xFFDF, 0xFFDF, 0xFFDF, 0xFFDF, 0xFFDF, 0xFFDF, + 0xFFDF, 0xFFDF, 0xFFDF, 0xFFDF, 0xFFDF, 0xFFDF, 0xFFDF, 0xFFDF, 0xFFDF, 0xFFDF, 0xFFDF, 0xFFDF, 0xFFDF, 0xFFDF, 0xFFDF, 0xFFDF, + 0xFFDF, 0xFFDF, 0xFFDF, 0xFFDF, 0xFFDF, 0xFFDF, 0xFFDF, 0xFFDF, 0xFFDF, 0xFFDF, 0xEF5D, 0x4A6C, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39EA, 0x7417, 0x7C9A, 0x7C9A, 0x7C9A, 0x7C9A, 0x7C9A, 0x7C9A, 0x7C9A, 0x7C9A, 0x7C9A, 0x7C9A, 0x7C9A, + 0x7C9A, 0x7C9A, 0x7C9A, 0x7C9A, 0x7C9A, 0x7C9A, 0x7C9A, 0x7C9A, 0x7C9A, 0x7C9A, 0x7C9A, 0x7C9A, 0x7CBA, 0x7CBA, 0x7CBA, 0x7CBA, + 0x7CBA, 0x7CBA, 0x7CBA, 0x7CBA, 0x7CBA, 0x7CBA, 0x7CBA, 0x7CBA, 0x7CBA, 0x7CBA, 0x84BA, 0x84BA, 0x84BA, 0x84BA, 0x84BA, 0x84BA, + 0x84BA, 0x84BA, 0x84BA, 0x84BA, 0x84BA, 0x84DA, 0x84DA, 0x84DA, 0x84DA, 0x84DA, 0x84DA, 0x84DA, 0x84DA, 0x84DA, 0x84DA, 0x84DA, + 0x84DA, 0x84DA, 0x84DA, 0x84DA, 0x84DA, 0x84DA, 0x84DA, 0x84DA, 0x84DA, 0x84DA, 0x84DA, 0x84DA, 0x84DA, 0x84DA, 0x84DA, 0x84FA, + 0x84FA, 0x84FA, 0x84FA, 0x84FA, 0x84FA, 0x84FA, 0x84FA, 0x84FA, 0x84FA, 0x84FA, 0x84FA, 0x84FA, 0x84FA, 0xB63C, 0xF7BF, 0xF7DF, + 0xF7DF, 0xF7DF, 0xF7DF, 0xF7DF, 0xF7DF, 0xF7DF, 0xF7DF, 0xF7DF, 0xF7DF, 0xF7DF, 0xF7DF, 0xF7DF, 0xF7DF, 0xF7DF, 0xF7DF, 0xF7DF, + 0xF7DF, 0xF7DF, 0xF7DF, 0xF7DF, 0xF7DF, 0xF7DF, 0xF7DF, 0xF7DF, 0xF7DF, 0xF7DF, 0xF7DF, 0xF7DF, 0xF7DF, 0xF7DF, 0xF7DF, 0xF7DF, + 0xF7DF, 0xF7DF, 0xF7DF, 0xF7DF, 0xF7DF, 0xF7DF, 0xF7DF, 0xF7DF, 0xF7DF, 0xF7DF, 0xF7DF, 0xF7DF, 0xF7DF, 0xF7DF, 0xF7DF, 0xF7DF, + 0xF7DF, 0xF7DF, 0xF7DF, 0xF7DF, 0xF7DF, 0xF7DF, 0xF7DF, 0xF7DF, 0xF7DF, 0xF7DF, 0xF7DF, 0xD6BB, 0x420A, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39CA, 0x63B5, 0x7C7A, 0x7C7A, 0x7C7A, 0x7C7A, 0x7C7A, 0x7C7A, 0x7C7A, 0x7C7A, 0x7C9A, 0x7C9A, 0x7C9A, 0x7C9A, + 0x7C9A, 0x7C9A, 0x7C9A, 0x7C9A, 0x7C9A, 0x7C9A, 0x7C9A, 0x7C9A, 0x7C9A, 0x7C9A, 0x7C9A, 0x7C9A, 0x7C9A, 0x7C9A, 0x7C9A, 0x7C9A, + 0x7C9A, 0x7C9A, 0x7C9A, 0x7C9A, 0x7C9A, 0x7CBA, 0x7CBA, 0x7CBA, 0x7CBA, 0x7CBA, 0x7CBA, 0x7CBA, 0x7CBA, 0x7CBA, 0x7CBA, 0x7CBA, + 0x7CBA, 0x7CBA, 0x7CBA, 0x84BA, 0x84BA, 0x84BA, 0x84BA, 0x84BA, 0x84BA, 0x84BA, 0x84BA, 0x84BA, 0x84BA, 0x84BA, 0x84BA, 0x84DA, + 0x84DA, 0x84DA, 0x84DA, 0x84DA, 0x84DA, 0x84DA, 0x84DA, 0x84DA, 0x84DA, 0x84DA, 0x84DA, 0x84DA, 0x84DA, 0x84DA, 0x84DA, 0x84DA, + 0x84DA, 0x84DA, 0x84DA, 0x84DA, 0x84DA, 0x84DA, 0x84DA, 0x84DA, 0x84FA, 0x84FA, 0x84FA, 0x84FA, 0x84FA, 0x84FA, 0x955B, 0xE73E, + 0xF7DF, 0xF7DF, 0xF7DF, 0xF7DF, 0xF7DF, 0xF7DF, 0xF7DF, 0xF7DF, 0xF7DF, 0xF7DF, 0xF7DF, 0xF7DF, 0xF7DF, 0xF7DF, 0xF7DF, 0xF7DF, + 0xF7DF, 0xF7DF, 0xF7DF, 0xF7DF, 0xF7DF, 0xF7DF, 0xF7DF, 0xF7DF, 0xF7DF, 0xF7DF, 0xF7DF, 0xF7DF, 0xF7DF, 0xF7DF, 0xF7DF, 0xF7DF, + 0xF7DF, 0xF7DF, 0xF7DF, 0xF7DF, 0xF7DF, 0xF7DF, 0xF7DF, 0xF7DF, 0xF7DF, 0xF7DF, 0xF7DF, 0xF7DF, 0xF7DF, 0xF7DF, 0xF7DF, 0xF7DF, + 0xF7DF, 0xF7DF, 0xF7DF, 0xF7DF, 0xF7DF, 0xF7DF, 0xF7DF, 0xF7DF, 0xF7DF, 0xF7DF, 0xF7DF, 0xF7DF, 0xB597, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x5B11, 0x7C79, 0x7C79, 0x7C79, 0x7C79, 0x7C79, 0x7C79, 0x7C79, 0x7C7A, 0x7C7A, 0x7C7A, 0x7C7A, 0x7C7A, 0x7C7A, + 0x7C7A, 0x7C7A, 0x7C7A, 0x7C7A, 0x7C7A, 0x7C7A, 0x7C9A, 0x7C9A, 0x7C9A, 0x7C9A, 0x7C9A, 0x7C9A, 0x7C9A, 0x7C9A, 0x7C9A, 0x7C9A, + 0x7C9A, 0x7C9A, 0x7C9A, 0x7C9A, 0x7C9A, 0x7C9A, 0x7C9A, 0x7C9A, 0x7C9A, 0x7C9A, 0x7C9A, 0x7C9A, 0x7C9A, 0x7C9A, 0x7C9A, 0x7CBA, + 0x7CBA, 0x7CBA, 0x7CBA, 0x7CBA, 0x7CBA, 0x7CBA, 0x7CBA, 0x7CBA, 0x7CBA, 0x7CBA, 0x7CBA, 0x7CBA, 0x84BA, 0x84BA, 0x84BA, 0x84BA, + 0x84BA, 0x84BA, 0x84BA, 0x84BA, 0x84BA, 0x84BA, 0x84BA, 0x84BA, 0x84DA, 0x84DA, 0x84DA, 0x84DA, 0x84DA, 0x84DA, 0x84DA, 0x84DA, + 0x84DA, 0x84DA, 0x84DA, 0x84DA, 0x84DA, 0x84DA, 0x84DA, 0x84DA, 0x84DA, 0x84DA, 0x84DA, 0x84DA, 0x84DA, 0x84DA, 0x84DA, 0x84FA, + 0xC69D, 0xF7BF, 0xF7BF, 0xF7BF, 0xF7BF, 0xF7BF, 0xF7BF, 0xF7BF, 0xF7BF, 0xF7BF, 0xF7BF, 0xF7BF, 0xF7BF, 0xF7BF, 0xF7BF, 0xF7BF, + 0xF7BF, 0xF7BF, 0xF7BF, 0xF7BF, 0xF7BF, 0xF7BF, 0xF7BF, 0xF7BF, 0xF7BF, 0xF7BF, 0xF7BF, 0xF7BF, 0xF7BF, 0xF7BF, 0xF7BF, 0xF7BF, + 0xF7BF, 0xF7BF, 0xF7BF, 0xF7BF, 0xF7BF, 0xF7BF, 0xF7BF, 0xF7BF, 0xF7BF, 0xF7BF, 0xF7BF, 0xF7BF, 0xF7BF, 0xF7BF, 0xF7BF, 0xF7BF, + 0xF7BF, 0xF7BF, 0xF7BF, 0xF7BF, 0xF7BF, 0xF7BF, 0xF7BF, 0xF7BF, 0xF7BF, 0xF7BF, 0xF7BF, 0xF7BF, 0xF7BF, 0x7C11, 0x39C9, 0x39C9, + 0x39C9, 0x424D, 0x7C59, 0x7C59, 0x7C59, 0x7C59, 0x7C79, 0x7C79, 0x7C79, 0x7C79, 0x7C79, 0x7C79, 0x7C79, 0x7C79, 0x7C79, 0x7C79, + 0x7C79, 0x7C79, 0x7C79, 0x7C7A, 0x7C7A, 0x7C7A, 0x7C7A, 0x7C7A, 0x7C7A, 0x7C7A, 0x7C7A, 0x7C7A, 0x7C7A, 0x7C7A, 0x7C7A, 0x7C9A, + 0x7C9A, 0x7C9A, 0x7C9A, 0x7C9A, 0x7C9A, 0x7C9A, 0x7C9A, 0x7C9A, 0x7C9A, 0x7C9A, 0x7C9A, 0x7C9A, 0x7C9A, 0x7C9A, 0x7C9A, 0x7C9A, + 0x7C9A, 0x7C9A, 0x7C9A, 0x7C9A, 0x7C9A, 0x7C9A, 0x7C9A, 0x7C9A, 0x7CBA, 0x7CBA, 0x7CBA, 0x7CBA, 0x7CBA, 0x7CBA, 0x7CBA, 0x7CBA, + 0x7CBA, 0x7CBA, 0x7CBA, 0x7CBA, 0x7CBA, 0x7CBA, 0x84BA, 0x84BA, 0x84BA, 0x84BA, 0x84BA, 0x84BA, 0x84BA, 0x84BA, 0x84BA, 0x84BA, + 0x84BA, 0x84DA, 0x84DA, 0x84DA, 0x84DA, 0x84DA, 0x84DA, 0x84DA, 0x84DA, 0x84DA, 0x84DA, 0x84DA, 0x84DA, 0x84DA, 0x84DA, 0x84DA, + 0x84DA, 0xA5BB, 0xEF7F, 0xF7BF, 0xF7BF, 0xF7BF, 0xF7BF, 0xF7BF, 0xF7BF, 0xF7BF, 0xF7BF, 0xF7BF, 0xF7BF, 0xF7BF, 0xF7BF, 0xF7BF, + 0xF7BF, 0xF7BF, 0xF7BF, 0xF7BF, 0xF7BF, 0xF7BF, 0xF7BF, 0xF7BF, 0xF7BF, 0xF7BF, 0xF7BF, 0xF7BF, 0xF7BF, 0xF7BF, 0xF7BF, 0xF7BF, + 0xF7BF, 0xF7BF, 0xF7BF, 0xF7BF, 0xF7BF, 0xF7BF, 0xF7BF, 0xF7BF, 0xF7BF, 0xF7BF, 0xF7BF, 0xF7BF, 0xF7BF, 0xF7BF, 0xF7BF, 0xF7BF, + 0xF7BF, 0xF7BF, 0xF7BF, 0xF7BF, 0xF7BF, 0xF7BF, 0xF7BF, 0xF7BF, 0xF7BF, 0xF7BF, 0xF7BF, 0xF7BF, 0xF7BF, 0xEF7E, 0x528C, 0x39C9, + 0x39C9, 0x6B95, 0x7C59, 0x7C59, 0x7C59, 0x7C59, 0x7C59, 0x7C59, 0x7C59, 0x7C59, 0x7C59, 0x7C59, 0x7C59, 0x7C59, 0x7C59, 0x7C79, + 0x7C79, 0x7C79, 0x7C79, 0x7C79, 0x7C79, 0x7C79, 0x7C79, 0x7C79, 0x7C79, 0x7C79, 0x7C79, 0x7C79, 0x7C79, 0x7C7A, 0x7C7A, 0x7C7A, + 0x7C7A, 0x7C7A, 0x7C7A, 0x7C7A, 0x7C7A, 0x7C7A, 0x7C7A, 0x7C7A, 0x7C9A, 0x7C9A, 0x7C9A, 0x7C9A, 0x7C9A, 0x7C9A, 0x7C9A, 0x7C9A, + 0x7C9A, 0x7C9A, 0x7C9A, 0x7C9A, 0x7C9A, 0x7C9A, 0x7C9A, 0x7C9A, 0x7C9A, 0x7C9A, 0x7C9A, 0x7C9A, 0x7C9A, 0x7C9A, 0x7C9A, 0x7C9A, + 0x7C9A, 0x7CBA, 0x7CBA, 0x7CBA, 0x7CBA, 0x7CBA, 0x7CBA, 0x7CBA, 0x7CBA, 0x7CBA, 0x7CBA, 0x7CBA, 0x7CBA, 0x7CBA, 0x7CBA, 0x84BA, + 0x84BA, 0x84BA, 0x84BA, 0x84BA, 0x84BA, 0x84BA, 0x84BA, 0x84BA, 0x84BA, 0x84BA, 0x84BA, 0x84DA, 0x84DA, 0x84DA, 0x84DA, 0x84DA, + 0x84DA, 0x84DA, 0x953B, 0xDF1E, 0xF7BF, 0xF7BF, 0xF7BF, 0xF7BF, 0xF7BF, 0xF7BF, 0xF7BF, 0xF7BF, 0xF7BF, 0xF7BF, 0xF7BF, 0xF7BF, + 0xF7BF, 0xF7BF, 0xF7BF, 0xF7BF, 0xF7BF, 0xF7BF, 0xF7BF, 0xF7BF, 0xF7BF, 0xF7BF, 0xF7BF, 0xF7BF, 0xF7BF, 0xF7BF, 0xF7BF, 0xF7BF, + 0xF7BF, 0xF7BF, 0xF7BF, 0xF7BF, 0xF7BF, 0xF7BF, 0xF7BF, 0xF7BF, 0xF7BF, 0xF7BF, 0xF7BF, 0xF7BF, 0xF7BF, 0xF7BF, 0xF7BF, 0xF7BF, + 0xF7BF, 0xF7BF, 0xF7BF, 0xF7BF, 0xF7BF, 0xF7BF, 0xF7BF, 0xF7BF, 0xF7BF, 0xF7BF, 0xF7BF, 0xF7BF, 0xF7BF, 0xF7BF, 0xAD77, 0x39C9, + 0x422C, 0x7C39, 0x7C59, 0x7C59, 0x7C59, 0x7C59, 0x7C59, 0x7C59, 0x7C59, 0x7C59, 0x7C59, 0x7C59, 0x7C59, 0x7C59, 0x7C59, 0x7C59, + 0x7C59, 0x7C59, 0x7C59, 0x7C59, 0x7C59, 0x7C59, 0x7C59, 0x7C59, 0x7C79, 0x7C79, 0x7C79, 0x7C79, 0x7C79, 0x7C79, 0x7C79, 0x7C79, + 0x7C79, 0x7C79, 0x7C79, 0x7C79, 0x7C79, 0x7C79, 0x7C7A, 0x7C7A, 0x7C7A, 0x7C7A, 0x7C7A, 0x7C7A, 0x7C7A, 0x7C7A, 0x7C7A, 0x7C7A, + 0x7C7A, 0x7C7A, 0x7C9A, 0x7C9A, 0x7C9A, 0x7C9A, 0x7C9A, 0x7C9A, 0x7C9A, 0x7C9A, 0x7C9A, 0x7C9A, 0x7C9A, 0x7C9A, 0x7C9A, 0x7C9A, + 0x7C9A, 0x7C9A, 0x7C9A, 0x7C9A, 0x7C9A, 0x7C9A, 0x7C9A, 0x7C9A, 0x7C9A, 0x7C9A, 0x7C9A, 0x7CBA, 0x7CBA, 0x7CBA, 0x7CBA, 0x7CBA, + 0x7CBA, 0x7CBA, 0x7CBA, 0x7CBA, 0x7CBA, 0x7CBA, 0x7CBA, 0x7CBA, 0x84BA, 0x84BA, 0x84BA, 0x84BA, 0x84BA, 0x84BA, 0x84BA, 0x84BA, + 0x84BA, 0x84BA, 0x84BA, 0x84DA, 0xBE7D, 0xF7BF, 0xF7BF, 0xF7BF, 0xF7BF, 0xF7BF, 0xF7BF, 0xF7BF, 0xF7BF, 0xF7BF, 0xF7BF, 0xF7BF, + 0xF7BF, 0xF7BF, 0xF7BF, 0xF7BF, 0xF7BF, 0xF7BF, 0xF7BF, 0xF7BF, 0xF7BF, 0xF7BF, 0xF7BF, 0xF7BF, 0xF7BF, 0xF7BF, 0xF7BF, 0xF7BF, + 0xF7BF, 0xF7BF, 0xF7BF, 0xF7BF, 0xF7BF, 0xF7BF, 0xF7BF, 0xF7BF, 0xF7BF, 0xF7BF, 0xF7BF, 0xF7BF, 0xF7BF, 0xF7BF, 0xF7BF, 0xF7BF, + 0xF7BF, 0xF7BF, 0xF7BF, 0xF7BF, 0xF7BF, 0xF7BF, 0xF7BF, 0xF7BF, 0xF7BF, 0xF7BF, 0xF7BF, 0xF7BF, 0xF7BF, 0xF7BF, 0xEF9E, 0x422B, + 0x52D0, 0x7439, 0x7439, 0x7439, 0x7C39, 0x7C39, 0x7C39, 0x7C39, 0x7C59, 0x7C59, 0x7C59, 0x7C59, 0x7C59, 0x7C59, 0x7C59, 0x7C59, + 0x7C59, 0x7C59, 0x7C59, 0x7C59, 0x7C59, 0x7C59, 0x7C59, 0x7C59, 0x7C59, 0x7C59, 0x7C59, 0x7C59, 0x7C59, 0x7C59, 0x7C59, 0x7C59, + 0x7C59, 0x7C59, 0x7C79, 0x7C79, 0x7C79, 0x7C79, 0x7C79, 0x7C79, 0x7C79, 0x7C79, 0x7C79, 0x7C79, 0x7C79, 0x7C79, 0x7C79, 0x7C7A, + 0x7C7A, 0x7C7A, 0x7C7A, 0x7C7A, 0x7C7A, 0x7C7A, 0x7C7A, 0x7C7A, 0x7C7A, 0x7C7A, 0x7C7A, 0x7C9A, 0x7C9A, 0x7C9A, 0x7C9A, 0x7C9A, + 0x7C9A, 0x7C9A, 0x7C9A, 0x7C9A, 0x7C9A, 0x7C9A, 0x7C9A, 0x7C9A, 0x7C9A, 0x7C9A, 0x7C9A, 0x7C9A, 0x7C9A, 0x7C9A, 0x7C9A, 0x7C9A, + 0x7C9A, 0x7C9A, 0x7C9A, 0x7C9A, 0x7CBA, 0x7CBA, 0x7CBA, 0x7CBA, 0x7CBA, 0x7CBA, 0x7CBA, 0x7CBA, 0x7CBA, 0x7CBA, 0x7CBA, 0x7CBA, + 0x7CBA, 0x7CBA, 0x84BA, 0x84BA, 0x84BA, 0xA5BC, 0xEF9F, 0xF7BF, 0xF7BF, 0xF7BF, 0xF7BF, 0xF7BF, 0xF7BF, 0xF7BF, 0xF7BF, 0xF7BF, + 0xF7BF, 0xF7BF, 0xF7BF, 0xF7BF, 0xF7BF, 0xF7BF, 0xF7BF, 0xF7BF, 0xF7BF, 0xF7BF, 0xF7BF, 0xF7BF, 0xF7BF, 0xF7BF, 0xF7BF, 0xF7BF, + 0xF7BF, 0xF7BF, 0xF7BF, 0xF7BF, 0xF7BF, 0xF7BF, 0xF7BF, 0xF7BF, 0xF7BF, 0xF7BF, 0xF7BF, 0xF7BF, 0xF7BF, 0xF7BF, 0xF7BF, 0xF7BF, + 0xF7BF, 0xF7BF, 0xF7BF, 0xF7BF, 0xF7BF, 0xF7BF, 0xF7BF, 0xF7BF, 0xF7BF, 0xF7BF, 0xF7BF, 0xF7BF, 0xF7BF, 0xF7BF, 0xF7BF, 0x73B0, + 0x5B33, 0x7439, 0x7439, 0x7439, 0x7439, 0x7439, 0x7439, 0x7439, 0x7439, 0x7439, 0x7439, 0x7439, 0x7439, 0x7C39, 0x7C39, 0x7C39, + 0x7C39, 0x7C39, 0x7C59, 0x7C59, 0x7C59, 0x7C59, 0x7C59, 0x7C59, 0x7C59, 0x7C59, 0x7C59, 0x7C59, 0x7C59, 0x7C59, 0x7C59, 0x7C59, + 0x7C59, 0x7C59, 0x7C59, 0x7C59, 0x7C59, 0x7C59, 0x7C59, 0x7C59, 0x7C59, 0x7C59, 0x7C59, 0x7C79, 0x7C79, 0x7C79, 0x7C79, 0x7C79, + 0x7C79, 0x7C79, 0x7C79, 0x7C79, 0x7C79, 0x7C79, 0x7C79, 0x7C79, 0x7C7A, 0x7C7A, 0x7C7A, 0x7C7A, 0x7C7A, 0x7C7A, 0x7C7A, 0x7C7A, + 0x7C7A, 0x7C7A, 0x7C7A, 0x7C7A, 0x7C9A, 0x7C9A, 0x7C9A, 0x7C9A, 0x7C9A, 0x7C9A, 0x7C9A, 0x7C9A, 0x7C9A, 0x7C9A, 0x7C9A, 0x7C9A, + 0x7C9A, 0x7C9A, 0x7C9A, 0x7C9A, 0x7C9A, 0x7C9A, 0x7C9A, 0x7C9A, 0x7C9A, 0x7C9A, 0x7C9A, 0x7C9A, 0x7C9A, 0x7CBA, 0x7CBA, 0x7CBA, + 0x7CBA, 0x7CBA, 0x7CBA, 0x7CBA, 0x7CBA, 0x7CBA, 0x9D5B, 0xE75F, 0xEF9F, 0xEF9F, 0xEF9F, 0xEF9F, 0xEF9F, 0xEF9F, 0xEF9F, 0xEF9F, + 0xEF9F, 0xEF9F, 0xEF9F, 0xEF9F, 0xEF9F, 0xEF9F, 0xEF9F, 0xEF9F, 0xEF9F, 0xEF9F, 0xEF9F, 0xEF9F, 0xEF9F, 0xEF9F, 0xEF9F, 0xEF9F, + 0xEF9F, 0xEF9F, 0xEF9F, 0xEF9F, 0xEF9F, 0xEF9F, 0xEF9F, 0xEF9F, 0xEF9F, 0xEF9F, 0xEF9F, 0xEF9F, 0xEF9F, 0xEF9F, 0xEF9F, 0xEF9F, + 0xEF9F, 0xEF9F, 0xEF9F, 0xEF9F, 0xEF9F, 0xEF9F, 0xEF9F, 0xEF9F, 0xEF9F, 0xEF9F, 0xEF9F, 0xEF9F, 0xEF9F, 0xEF9F, 0xEF9F, 0x94B4, + 0x6354, 0x7419, 0x7439, 0x7439, 0x7439, 0x7439, 0x7439, 0x7439, 0x7439, 0x7439, 0x7439, 0x7439, 0x7439, 0x7439, 0x7439, 0x7439, + 0x7439, 0x7439, 0x7439, 0x7439, 0x7439, 0x7439, 0x7C39, 0x7C39, 0x7C39, 0x7C39, 0x7C39, 0x7C59, 0x7C59, 0x7C59, 0x7C59, 0x7C59, + 0x7C59, 0x7C59, 0x7C59, 0x7C59, 0x7C59, 0x7C59, 0x7C59, 0x7C59, 0x7C59, 0x7C59, 0x7C59, 0x7C59, 0x7C59, 0x7C59, 0x7C59, 0x7C59, + 0x7C59, 0x7C59, 0x7C59, 0x7C59, 0x7C79, 0x7C79, 0x7C79, 0x7C79, 0x7C79, 0x7C79, 0x7C79, 0x7C79, 0x7C79, 0x7C79, 0x7C79, 0x7C79, + 0x7C79, 0x7C79, 0x7C7A, 0x7C7A, 0x7C7A, 0x7C7A, 0x7C7A, 0x7C7A, 0x7C7A, 0x7C7A, 0x7C7A, 0x7C7A, 0x7C7A, 0x7C9A, 0x7C9A, 0x7C9A, + 0x7C9A, 0x7C9A, 0x7C9A, 0x7C9A, 0x7C9A, 0x7C9A, 0x7C9A, 0x7C9A, 0x7C9A, 0x7C9A, 0x7C9A, 0x7C9A, 0x7C9A, 0x7C9A, 0x7C9A, 0x7C9A, + 0x7C9A, 0x7C9A, 0x7C9A, 0x7C9A, 0x7C9A, 0x7C9A, 0x7C9A, 0x8D1A, 0xDF1E, 0xEF9F, 0xEF9F, 0xEF9F, 0xEF9F, 0xEF9F, 0xEF9F, 0xEF9F, + 0xEF9F, 0xEF9F, 0xEF9F, 0xEF9F, 0xEF9F, 0xEF9F, 0xEF9F, 0xEF9F, 0xEF9F, 0xEF9F, 0xEF9F, 0xEF9F, 0xEF9F, 0xEF9F, 0xEF9F, 0xEF9F, + 0xEF9F, 0xEF9F, 0xEF9F, 0xEF9F, 0xEF9F, 0xEF9F, 0xEF9F, 0xEF9F, 0xEF9F, 0xEF9F, 0xEF9F, 0xEF9F, 0xEF9F, 0xEF9F, 0xEF9F, 0xEF9F, + 0xEF9F, 0xEF9F, 0xEF9F, 0xEF9F, 0xEF9F, 0xEF9F, 0xEF9F, 0xEF9F, 0xEF9F, 0xEF9F, 0xEF9F, 0xEF9F, 0xEF9F, 0xEF9F, 0xEF9F, 0x9CF5, + 0x5B33, 0x7419, 0x7419, 0x7419, 0x7419, 0x7419, 0x7419, 0x7419, 0x7419, 0x7419, 0x7419, 0x7439, 0x7439, 0x7439, 0x7439, 0x7439, + 0x7439, 0x7439, 0x7439, 0x7439, 0x7439, 0x7439, 0x7439, 0x7439, 0x7439, 0x7439, 0x7439, 0x7439, 0x7439, 0x7439, 0x7439, 0x7439, + 0x7C39, 0x7C39, 0x7C39, 0x7C39, 0x7C59, 0x7C59, 0x7C59, 0x7C59, 0x7C59, 0x7C59, 0x7C59, 0x7C59, 0x7C59, 0x7C59, 0x7C59, 0x7C59, + 0x7C59, 0x7C59, 0x7C59, 0x7C59, 0x7C59, 0x7C59, 0x7C59, 0x7C59, 0x7C59, 0x7C59, 0x7C59, 0x7C59, 0x7C59, 0x7C59, 0x7C79, 0x7C79, + 0x7C79, 0x7C79, 0x7C79, 0x7C79, 0x7C79, 0x7C79, 0x7C79, 0x7C79, 0x7C79, 0x7C79, 0x7C79, 0x7C7A, 0x7C7A, 0x7C7A, 0x7C7A, 0x7C7A, + 0x7C7A, 0x7C7A, 0x7C7A, 0x7C7A, 0x7C7A, 0x7C7A, 0x7C7A, 0x7C9A, 0x7C9A, 0x7C9A, 0x7C9A, 0x7C9A, 0x7C9A, 0x7C9A, 0x7C9A, 0x7C9A, + 0x7C9A, 0x7C9A, 0x7C9A, 0x7C9A, 0x7C9A, 0x7C9A, 0x7C9A, 0x7C9A, 0x84BA, 0xC69D, 0xEF9F, 0xEF9F, 0xEF9F, 0xEF9F, 0xEF9F, 0xEF9F, + 0xEF9F, 0xEF9F, 0xEF9F, 0xEF9F, 0xEF9F, 0xEF9F, 0xEF9F, 0xEF9F, 0xEF9F, 0xEF9F, 0xEF9F, 0xEF9F, 0xEF9F, 0xEF9F, 0xEF9F, 0xEF9F, + 0xEF9F, 0xEF9F, 0xEF9F, 0xEF9F, 0xEF9F, 0xEF9F, 0xEF9F, 0xEF9F, 0xEF9F, 0xEF9F, 0xEF9F, 0xEF9F, 0xEF9F, 0xEF9F, 0xEF9F, 0xEF9F, + 0xEF9F, 0xEF9F, 0xEF9F, 0xEF9F, 0xEF9F, 0xEF9F, 0xEF9F, 0xEF9F, 0xEF9F, 0xEF9F, 0xEF9F, 0xEF9F, 0xEF9F, 0xEF9F, 0xEF9F, 0x94B4, + 0x52D0, 0x7419, 0x7419, 0x7419, 0x7419, 0x7419, 0x7419, 0x7419, 0x7419, 0x7419, 0x7419, 0x7419, 0x7419, 0x7419, 0x7419, 0x7419, + 0x7419, 0x7419, 0x7419, 0x7419, 0x7439, 0x7439, 0x7439, 0x7439, 0x7439, 0x7439, 0x7439, 0x7439, 0x7439, 0x7439, 0x7439, 0x7439, + 0x7439, 0x7439, 0x7439, 0x7439, 0x7439, 0x7439, 0x7439, 0x7439, 0x7439, 0x7C39, 0x7C39, 0x7C39, 0x7C39, 0x7C39, 0x7C59, 0x7C59, + 0x7C59, 0x7C59, 0x7C59, 0x7C59, 0x7C59, 0x7C59, 0x7C59, 0x7C59, 0x7C59, 0x7C59, 0x7C59, 0x7C59, 0x7C59, 0x7C59, 0x7C59, 0x7C59, + 0x7C59, 0x7C59, 0x7C59, 0x7C59, 0x7C59, 0x7C59, 0x7C59, 0x7C79, 0x7C79, 0x7C79, 0x7C79, 0x7C79, 0x7C79, 0x7C79, 0x7C79, 0x7C79, + 0x7C79, 0x7C79, 0x7C79, 0x7C79, 0x7C7A, 0x7C7A, 0x7C7A, 0x7C7A, 0x7C7A, 0x7C7A, 0x7C7A, 0x7C7A, 0x7C7A, 0x7C7A, 0x7C7A, 0x7C7A, + 0x7C9A, 0x7C9A, 0x7C9A, 0x7C9A, 0x7C9A, 0x7C9A, 0x7C9A, 0x7C9A, 0x7C9A, 0x7C9A, 0xBE3C, 0xEF9F, 0xEF9F, 0xEF9F, 0xEF9F, 0xEF9F, + 0xEF9F, 0xEF9F, 0xEF9F, 0xEF9F, 0xEF9F, 0xEF9F, 0xEF9F, 0xEF9F, 0xEF9F, 0xEF9F, 0xEF9F, 0xEF9F, 0xEF9F, 0xEF9F, 0xEF9F, 0xEF9F, + 0xEF9F, 0xEF9F, 0xEF9F, 0xEF9F, 0xEF9F, 0xEF9F, 0xEF9F, 0xEF9F, 0xEF9F, 0xEF9F, 0xEF9F, 0xEF9F, 0xEF9F, 0xEF9F, 0xEF9F, 0xEF9F, + 0xEF9F, 0xEF9F, 0xEF9F, 0xEF9F, 0xEF9F, 0xEF9F, 0xEF9F, 0xEF9F, 0xEF9F, 0xEF9F, 0xEF9F, 0xEF9F, 0xEF9F, 0xEF9F, 0xEF9F, 0x73D1, + 0x422C, 0x73F9, 0x73F9, 0x73F9, 0x73F9, 0x7419, 0x7419, 0x7419, 0x7419, 0x7419, 0x7419, 0x7419, 0x7419, 0x7419, 0x7419, 0x7419, + 0x7419, 0x7419, 0x7419, 0x7419, 0x7419, 0x7419, 0x7419, 0x7419, 0x7419, 0x7419, 0x7419, 0x7419, 0x7419, 0x7419, 0x7439, 0x7439, + 0x7439, 0x7439, 0x7439, 0x7439, 0x7439, 0x7439, 0x7439, 0x7439, 0x7439, 0x7439, 0x7439, 0x7439, 0x7439, 0x7439, 0x7439, 0x7439, + 0x7439, 0x7439, 0x7C39, 0x7C39, 0x7C39, 0x7C39, 0x7C39, 0x7C59, 0x7C59, 0x7C59, 0x7C59, 0x7C59, 0x7C59, 0x7C59, 0x7C59, 0x7C59, + 0x7C59, 0x7C59, 0x7C59, 0x7C59, 0x7C59, 0x7C59, 0x7C59, 0x7C59, 0x7C59, 0x7C59, 0x7C59, 0x7C59, 0x7C59, 0x7C59, 0x7C59, 0x7C59, + 0x7C79, 0x7C79, 0x7C79, 0x7C79, 0x7C79, 0x7C79, 0x7C79, 0x7C79, 0x7C79, 0x7C79, 0x7C79, 0x7C79, 0x7C79, 0x7C79, 0x7C7A, 0x7C7A, + 0x7C7A, 0x7C7A, 0x7C7A, 0x7C7A, 0x7C7A, 0x7C7A, 0x7C7A, 0x7C7A, 0x7C7A, 0x7C9A, 0x7C9A, 0xADFC, 0xEF9F, 0xEF9F, 0xEF9F, 0xEF9F, + 0xEF9F, 0xEF9F, 0xEF9F, 0xEF9F, 0xEF9F, 0xEF9F, 0xEF9F, 0xEF9F, 0xEF9F, 0xEF9F, 0xEF9F, 0xEF9F, 0xEF9F, 0xEF9F, 0xEF9F, 0xEF9F, + 0xEF9F, 0xEF9F, 0xEF9F, 0xEF9F, 0xEF9F, 0xEF9F, 0xEF9F, 0xEF9F, 0xEF9F, 0xEF9F, 0xEF9F, 0xEF9F, 0xEF9F, 0xEF9F, 0xEF9F, 0xEF9F, + 0xEF9F, 0xEF9F, 0xEF9F, 0xEF9F, 0xEF9F, 0xEF9F, 0xEF9F, 0xEF9F, 0xEF9F, 0xEF9F, 0xEF9F, 0xEF9F, 0xEF9F, 0xEF9F, 0xE77E, 0x4A4B, + 0x39C9, 0x6375, 0x73F9, 0x73F9, 0x73F9, 0x73F9, 0x73F9, 0x73F9, 0x73F9, 0x73F9, 0x73F9, 0x73F9, 0x73F9, 0x73F9, 0x7419, 0x7419, + 0x7419, 0x7419, 0x7419, 0x7419, 0x7419, 0x7419, 0x7419, 0x7419, 0x7419, 0x7419, 0x7419, 0x7419, 0x7419, 0x7419, 0x7419, 0x7419, + 0x7419, 0x7419, 0x7419, 0x7419, 0x7419, 0x7419, 0x7419, 0x7439, 0x7439, 0x7439, 0x7439, 0x7439, 0x7439, 0x7439, 0x7439, 0x7439, + 0x7439, 0x7439, 0x7439, 0x7439, 0x7439, 0x7439, 0x7439, 0x7439, 0x7439, 0x7439, 0x7439, 0x7C39, 0x7C39, 0x7C39, 0x7C39, 0x7C39, + 0x7C59, 0x7C59, 0x7C59, 0x7C59, 0x7C59, 0x7C59, 0x7C59, 0x7C59, 0x7C59, 0x7C59, 0x7C59, 0x7C59, 0x7C59, 0x7C59, 0x7C59, 0x7C59, + 0x7C59, 0x7C59, 0x7C59, 0x7C59, 0x7C59, 0x7C59, 0x7C59, 0x7C59, 0x7C59, 0x7C79, 0x7C79, 0x7C79, 0x7C79, 0x7C79, 0x7C79, 0x7C79, + 0x7C79, 0x7C79, 0x7C79, 0x7C79, 0x7C79, 0x7C79, 0x7C79, 0x7C7A, 0x7C7A, 0x7C7A, 0x7C7A, 0x7C7A, 0xADBC, 0xE77F, 0xEF7F, 0xEF7F, + 0xEF7F, 0xEF7F, 0xEF7F, 0xEF7F, 0xEF7F, 0xEF7F, 0xEF7F, 0xEF7F, 0xEF7F, 0xEF7F, 0xEF7F, 0xEF7F, 0xEF7F, 0xEF7F, 0xEF7F, 0xEF7F, + 0xEF7F, 0xEF7F, 0xEF7F, 0xEF7F, 0xEF7F, 0xEF7F, 0xEF7F, 0xEF7F, 0xEF7F, 0xEF7F, 0xEF7F, 0xEF7F, 0xEF7F, 0xEF7F, 0xEF7F, 0xEF7F, + 0xEF7F, 0xEF7F, 0xEF7F, 0xEF7F, 0xEF7F, 0xEF7F, 0xEF7F, 0xEF7F, 0xEF7F, 0xEF7F, 0xEF7F, 0xEF7F, 0xEF7F, 0xEF7F, 0xAD97, 0x39C9, + 0x39C9, 0x422D, 0x73F9, 0x73F9, 0x73F9, 0x73F9, 0x73F9, 0x73F9, 0x73F9, 0x73F9, 0x73F9, 0x73F9, 0x73F9, 0x73F9, 0x73F9, 0x73F9, + 0x73F9, 0x73F9, 0x73F9, 0x73F9, 0x73F9, 0x73F9, 0x73F9, 0x7419, 0x7419, 0x7419, 0x7419, 0x7419, 0x7419, 0x7419, 0x7419, 0x7419, + 0x7419, 0x7419, 0x7419, 0x7419, 0x7419, 0x7419, 0x7419, 0x7419, 0x7419, 0x7419, 0x7419, 0x7419, 0x7419, 0x7419, 0x7419, 0x7419, + 0x7439, 0x7439, 0x7439, 0x7439, 0x7439, 0x7439, 0x7439, 0x7439, 0x7439, 0x7439, 0x7439, 0x7439, 0x7439, 0x7439, 0x7439, 0x7439, + 0x7439, 0x7439, 0x7439, 0x7439, 0x7439, 0x7C39, 0x7C39, 0x7C39, 0x7C39, 0x7C39, 0x7C59, 0x7C59, 0x7C59, 0x7C59, 0x7C59, 0x7C59, + 0x7C59, 0x7C59, 0x7C59, 0x7C59, 0x7C59, 0x7C59, 0x7C59, 0x7C59, 0x7C59, 0x7C59, 0x7C59, 0x7C59, 0x7C59, 0x7C59, 0x7C59, 0x7C59, + 0x7C59, 0x7C59, 0x7C59, 0x7C79, 0x7C79, 0x7C79, 0x7C79, 0x7C79, 0x7C79, 0x7C79, 0x7C79, 0x7C79, 0x7C79, 0x9D5B, 0xE77E, 0xE77F, + 0xE77F, 0xE77F, 0xE77F, 0xE77F, 0xE77F, 0xE77F, 0xE77F, 0xE77F, 0xE77F, 0xE77F, 0xE77F, 0xE77F, 0xE77F, 0xE77F, 0xE77F, 0xE77F, + 0xE77F, 0xE77F, 0xE77F, 0xE77F, 0xE77F, 0xE77F, 0xE77F, 0xE77F, 0xE77F, 0xE77F, 0xE77F, 0xE77F, 0xE77F, 0xE77F, 0xE77F, 0xE77F, + 0xE77F, 0xE77F, 0xE77F, 0xE77F, 0xE77F, 0xE77F, 0xE77F, 0xE77F, 0xE77F, 0xE77F, 0xE77F, 0xE77F, 0xE77F, 0xDF3E, 0x4A8C, 0x39C9, + 0x39C9, 0x39C9, 0x5AF2, 0x73D9, 0x73D9, 0x73D9, 0x73D9, 0x73F9, 0x73F9, 0x73F9, 0x73F9, 0x73F9, 0x73F9, 0x73F9, 0x73F9, 0x73F9, + 0x73F9, 0x73F9, 0x73F9, 0x73F9, 0x73F9, 0x73F9, 0x73F9, 0x73F9, 0x73F9, 0x73F9, 0x73F9, 0x73F9, 0x73F9, 0x73F9, 0x73F9, 0x73F9, + 0x73F9, 0x7419, 0x7419, 0x7419, 0x7419, 0x7419, 0x7419, 0x7419, 0x7419, 0x7419, 0x7419, 0x7419, 0x7419, 0x7419, 0x7419, 0x7419, + 0x7419, 0x7419, 0x7419, 0x7419, 0x7419, 0x7419, 0x7419, 0x7419, 0x7419, 0x7419, 0x7439, 0x7439, 0x7439, 0x7439, 0x7439, 0x7439, + 0x7439, 0x7439, 0x7439, 0x7439, 0x7439, 0x7439, 0x7439, 0x7439, 0x7439, 0x7439, 0x7439, 0x7439, 0x7439, 0x7439, 0x7C39, 0x7C39, + 0x7C39, 0x7C39, 0x7C39, 0x7C59, 0x7C59, 0x7C59, 0x7C59, 0x7C59, 0x7C59, 0x7C59, 0x7C59, 0x7C59, 0x7C59, 0x7C59, 0x7C59, 0x7C59, + 0x7C59, 0x7C59, 0x7C59, 0x7C59, 0x7C59, 0x7C59, 0x7C59, 0x7C59, 0x7C59, 0x7C59, 0x7C59, 0x7C59, 0x7C79, 0x7C79, 0x9D5B, 0xE75E, + 0xE77E, 0xE77E, 0xE77E, 0xE77E, 0xE77E, 0xE77E, 0xE77E, 0xE77E, 0xE77E, 0xE77E, 0xE77E, 0xE77E, 0xE77E, 0xE77E, 0xE77E, 0xE77E, + 0xE77E, 0xE77E, 0xE77E, 0xE77E, 0xE77E, 0xE77E, 0xE77E, 0xE77E, 0xE77E, 0xE77E, 0xE77E, 0xE77E, 0xE77E, 0xE77E, 0xE77E, 0xE77E, + 0xE77E, 0xE77E, 0xE77E, 0xE77E, 0xE77E, 0xE77E, 0xE77E, 0xE77E, 0xE77E, 0xE77E, 0xE77E, 0xE77E, 0xE77E, 0x8C73, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39CA, 0x6355, 0x73D9, 0x73D9, 0x73D9, 0x73D9, 0x73D9, 0x73D9, 0x73D9, 0x73D9, 0x73D9, 0x73D9, 0x73D9, 0x73D9, + 0x73D9, 0x73F9, 0x73F9, 0x73F9, 0x73F9, 0x73F9, 0x73F9, 0x73F9, 0x73F9, 0x73F9, 0x73F9, 0x73F9, 0x73F9, 0x73F9, 0x73F9, 0x73F9, + 0x73F9, 0x73F9, 0x73F9, 0x73F9, 0x73F9, 0x73F9, 0x73F9, 0x73F9, 0x73F9, 0x73F9, 0x7419, 0x7419, 0x7419, 0x7419, 0x7419, 0x7419, + 0x7419, 0x7419, 0x7419, 0x7419, 0x7419, 0x7419, 0x7419, 0x7419, 0x7419, 0x7419, 0x7419, 0x7419, 0x7419, 0x7419, 0x7419, 0x7419, + 0x7419, 0x7419, 0x7419, 0x7439, 0x7439, 0x7439, 0x7439, 0x7439, 0x7439, 0x7439, 0x7439, 0x7439, 0x7439, 0x7439, 0x7439, 0x7439, + 0x7439, 0x7439, 0x7439, 0x7439, 0x7439, 0x7439, 0x7439, 0x7C39, 0x7C39, 0x7C39, 0x7C39, 0x7C39, 0x7C59, 0x7C59, 0x7C59, 0x7C59, + 0x7C59, 0x7C59, 0x7C59, 0x7C59, 0x7C59, 0x7C59, 0x7C59, 0x7C59, 0x7C59, 0x7C59, 0x7C59, 0x7C59, 0x7C59, 0x7C59, 0x7C59, 0x94FB, + 0xDF3E, 0xE77E, 0xE77E, 0xE77E, 0xE77E, 0xE77E, 0xE77E, 0xE77E, 0xE77E, 0xE77E, 0xE77E, 0xE77E, 0xE77E, 0xE77E, 0xE77E, 0xE77E, + 0xE77E, 0xE77E, 0xE77E, 0xE77E, 0xE77E, 0xE77E, 0xE77E, 0xE77E, 0xE77E, 0xE77E, 0xE77E, 0xE77E, 0xE77E, 0xE77E, 0xE77E, 0xE77E, + 0xE77E, 0xE77E, 0xE77E, 0xE77E, 0xE77E, 0xE77E, 0xE77E, 0xE77E, 0xE77E, 0xE77E, 0xE77E, 0xE77E, 0xAD97, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x420B, 0x6B97, 0x73D9, 0x73D9, 0x73D9, 0x73D9, 0x73D9, 0x73D9, 0x73D9, 0x73D9, 0x73D9, 0x73D9, 0x73D9, + 0x73D9, 0x73D9, 0x73D9, 0x73D9, 0x73D9, 0x73D9, 0x73D9, 0x73D9, 0x73D9, 0x73D9, 0x73F9, 0x73F9, 0x73F9, 0x73F9, 0x73F9, 0x73F9, + 0x73F9, 0x73F9, 0x73F9, 0x73F9, 0x73F9, 0x73F9, 0x73F9, 0x73F9, 0x73F9, 0x73F9, 0x73F9, 0x73F9, 0x73F9, 0x73F9, 0x73F9, 0x73F9, + 0x73F9, 0x73F9, 0x73F9, 0x7419, 0x7419, 0x7419, 0x7419, 0x7419, 0x7419, 0x7419, 0x7419, 0x7419, 0x7419, 0x7419, 0x7419, 0x7419, + 0x7419, 0x7419, 0x7419, 0x7419, 0x7419, 0x7419, 0x7419, 0x7419, 0x7419, 0x7419, 0x7419, 0x7419, 0x7439, 0x7439, 0x7439, 0x7439, + 0x7439, 0x7439, 0x7439, 0x7439, 0x7439, 0x7439, 0x7439, 0x7439, 0x7439, 0x7439, 0x7439, 0x7439, 0x7439, 0x7439, 0x7439, 0x7439, + 0x7439, 0x7C39, 0x7C39, 0x7C39, 0x7C39, 0x7C39, 0x7C59, 0x7C59, 0x7C59, 0x7C59, 0x7C59, 0x7C59, 0x7C59, 0x7C59, 0x7C59, 0x7C59, + 0x8CFA, 0xDF3E, 0xE77E, 0xE77E, 0xE77E, 0xE77E, 0xE77E, 0xE77E, 0xE77E, 0xE77E, 0xE77E, 0xE77E, 0xE77E, 0xE77E, 0xE77E, 0xE77E, + 0xE77E, 0xE77E, 0xE77E, 0xE77E, 0xE77E, 0xE77E, 0xE77E, 0xE77E, 0xE77E, 0xE77E, 0xE77E, 0xE77E, 0xE77E, 0xE77E, 0xE77E, 0xE77E, + 0xE77E, 0xE77E, 0xE77E, 0xE77E, 0xE77E, 0xE77E, 0xE77E, 0xE77E, 0xE77E, 0xE77E, 0xE77E, 0xC67B, 0x420A, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x422D, 0x6BB8, 0x6BB9, 0x6BB9, 0x6BB9, 0x6BB9, 0x6BD9, 0x6BD9, 0x73D9, 0x73D9, 0x73D9, 0x73D9, + 0x73D9, 0x73D9, 0x73D9, 0x73D9, 0x73D9, 0x73D9, 0x73D9, 0x73D9, 0x73D9, 0x73D9, 0x73D9, 0x73D9, 0x73D9, 0x73D9, 0x73D9, 0x73D9, + 0x73D9, 0x73D9, 0x73D9, 0x73F9, 0x73F9, 0x73F9, 0x73F9, 0x73F9, 0x73F9, 0x73F9, 0x73F9, 0x73F9, 0x73F9, 0x73F9, 0x73F9, 0x73F9, + 0x73F9, 0x73F9, 0x73F9, 0x73F9, 0x73F9, 0x73F9, 0x73F9, 0x73F9, 0x73F9, 0x73F9, 0x73F9, 0x73F9, 0x7419, 0x7419, 0x7419, 0x7419, + 0x7419, 0x7419, 0x7419, 0x7419, 0x7419, 0x7419, 0x7419, 0x7419, 0x7419, 0x7419, 0x7419, 0x7419, 0x7419, 0x7419, 0x7419, 0x7419, + 0x7419, 0x7419, 0x7419, 0x7419, 0x7419, 0x7419, 0x7439, 0x7439, 0x7439, 0x7439, 0x7439, 0x7439, 0x7439, 0x7439, 0x7439, 0x7439, + 0x7439, 0x7439, 0x7439, 0x7439, 0x7439, 0x7439, 0x7439, 0x7439, 0x7439, 0x7439, 0x7C39, 0x7C39, 0x7C39, 0x7C39, 0x7C39, 0x7C59, + 0x7C59, 0x8CFA, 0xDF3E, 0xE75E, 0xE75E, 0xE75E, 0xE75E, 0xE75E, 0xE75E, 0xE75E, 0xE75E, 0xE75E, 0xE75E, 0xE75E, 0xE75E, 0xE75E, + 0xE75E, 0xE75E, 0xE75E, 0xE75E, 0xE75E, 0xE75E, 0xE75E, 0xE75E, 0xE75E, 0xE75E, 0xE75E, 0xE75E, 0xE75E, 0xE75E, 0xE75E, 0xE75E, + 0xE75E, 0xE75E, 0xE75E, 0xE75E, 0xE75E, 0xE75E, 0xE75E, 0xE75E, 0xE75E, 0xE75E, 0xDF1D, 0x52AD, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x4A90, 0x6BB9, 0x6BB9, 0x6BB9, 0x6BB9, 0x6BB9, 0x6BB9, 0x6BB9, 0x6BB9, 0x6BB9, 0x6BB9, + 0x6BB9, 0x6BB9, 0x6BB9, 0x6BD9, 0x6BD9, 0x73D9, 0x73D9, 0x73D9, 0x73D9, 0x73D9, 0x73D9, 0x73D9, 0x73D9, 0x73D9, 0x73D9, 0x73D9, + 0x73D9, 0x73D9, 0x73D9, 0x73D9, 0x73D9, 0x73D9, 0x73D9, 0x73D9, 0x73D9, 0x73D9, 0x73D9, 0x73D9, 0x73D9, 0x73F9, 0x73F9, 0x73F9, + 0x73F9, 0x73F9, 0x73F9, 0x73F9, 0x73F9, 0x73F9, 0x73F9, 0x73F9, 0x73F9, 0x73F9, 0x73F9, 0x73F9, 0x73F9, 0x73F9, 0x73F9, 0x73F9, + 0x73F9, 0x73F9, 0x73F9, 0x73F9, 0x73F9, 0x73F9, 0x7419, 0x7419, 0x7419, 0x7419, 0x7419, 0x7419, 0x7419, 0x7419, 0x7419, 0x7419, + 0x7419, 0x7419, 0x7419, 0x7419, 0x7419, 0x7419, 0x7419, 0x7419, 0x7419, 0x7419, 0x7419, 0x7419, 0x7419, 0x7419, 0x7419, 0x7439, + 0x7439, 0x7439, 0x7439, 0x7439, 0x7439, 0x7439, 0x7439, 0x7439, 0x7439, 0x7439, 0x7439, 0x7439, 0x7439, 0x7439, 0x7439, 0x7439, + 0x7439, 0x7439, 0x951B, 0xDF5E, 0xE75E, 0xE75E, 0xE75E, 0xE75E, 0xE75E, 0xE75E, 0xE75E, 0xE75E, 0xE75E, 0xE75E, 0xE75E, 0xE75E, + 0xE75E, 0xE75E, 0xE75E, 0xE75E, 0xE75E, 0xE75E, 0xE75E, 0xE75E, 0xE75E, 0xE75E, 0xE75E, 0xE75E, 0xE75E, 0xE75E, 0xE75E, 0xE75E, + 0xE75E, 0xE75E, 0xE75E, 0xE75E, 0xE75E, 0xE75E, 0xE75E, 0xE75E, 0xE75E, 0xE75E, 0x6B90, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x5AF3, 0x6BB9, 0x6BB9, 0x6BB9, 0x6BB9, 0x6BB9, 0x6BB9, 0x6BB9, 0x6BB9, 0x6BB9, + 0x6BB9, 0x6BB9, 0x6BB9, 0x6BB9, 0x6BB9, 0x6BB9, 0x6BB9, 0x6BB9, 0x6BB9, 0x6BB9, 0x6BB9, 0x6BB9, 0x6BB9, 0x6BD9, 0x6BD9, 0x73D9, + 0x73D9, 0x73D9, 0x73D9, 0x73D9, 0x73D9, 0x73D9, 0x73D9, 0x73D9, 0x73D9, 0x73D9, 0x73D9, 0x73D9, 0x73D9, 0x73D9, 0x73D9, 0x73D9, + 0x73D9, 0x73D9, 0x73D9, 0x73D9, 0x73D9, 0x73D9, 0x73F9, 0x73F9, 0x73F9, 0x73F9, 0x73F9, 0x73F9, 0x73F9, 0x73F9, 0x73F9, 0x73F9, + 0x73F9, 0x73F9, 0x73F9, 0x73F9, 0x73F9, 0x73F9, 0x73F9, 0x73F9, 0x73F9, 0x73F9, 0x73F9, 0x73F9, 0x73F9, 0x73F9, 0x73F9, 0x7419, + 0x7419, 0x7419, 0x7419, 0x7419, 0x7419, 0x7419, 0x7419, 0x7419, 0x7419, 0x7419, 0x7419, 0x7419, 0x7419, 0x7419, 0x7419, 0x7419, + 0x7419, 0x7419, 0x7419, 0x7419, 0x7419, 0x7419, 0x7419, 0x7419, 0x7439, 0x7439, 0x7439, 0x7439, 0x7439, 0x7439, 0x7439, 0x7439, + 0x7439, 0x7439, 0x7439, 0x9D3B, 0xDF5E, 0xE75E, 0xE75E, 0xE75E, 0xE75E, 0xE75E, 0xE75E, 0xE75E, 0xE75E, 0xE75E, 0xE75E, 0xE75E, + 0xE75E, 0xE75E, 0xE75E, 0xE75E, 0xE75E, 0xE75E, 0xE75E, 0xE75E, 0xE75E, 0xE75E, 0xE75E, 0xE75E, 0xE75E, 0xE75E, 0xE75E, 0xE75E, + 0xE75E, 0xE75E, 0xE75E, 0xE75E, 0xE75E, 0xE75E, 0xE75E, 0xE75E, 0xE75E, 0x94B4, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39EA, 0x6355, 0x6B99, 0x6B99, 0x6B99, 0x6B99, 0x6B99, 0x6BB9, 0x6BB9, 0x6BB9, + 0x6BB9, 0x6BB9, 0x6BB9, 0x6BB9, 0x6BB9, 0x6BB9, 0x6BB9, 0x6BB9, 0x6BB9, 0x6BB9, 0x6BB9, 0x6BB9, 0x6BB9, 0x6BB9, 0x6BB9, 0x6BB9, + 0x6BB9, 0x6BB9, 0x6BB9, 0x6BB9, 0x6BB9, 0x6BB9, 0x6BD9, 0x6BD9, 0x73D9, 0x73D9, 0x73D9, 0x73D9, 0x73D9, 0x73D9, 0x73D9, 0x73D9, + 0x73D9, 0x73D9, 0x73D9, 0x73D9, 0x73D9, 0x73D9, 0x73D9, 0x73D9, 0x73D9, 0x73D9, 0x73D9, 0x73D9, 0x73D9, 0x73D9, 0x73D9, 0x73F9, + 0x73F9, 0x73F9, 0x73F9, 0x73F9, 0x73F9, 0x73F9, 0x73F9, 0x73F9, 0x73F9, 0x73F9, 0x73F9, 0x73F9, 0x73F9, 0x73F9, 0x73F9, 0x73F9, + 0x73F9, 0x73F9, 0x73F9, 0x73F9, 0x73F9, 0x73F9, 0x73F9, 0x73F9, 0x7419, 0x7419, 0x7419, 0x7419, 0x7419, 0x7419, 0x7419, 0x7419, + 0x7419, 0x7419, 0x7419, 0x7419, 0x7419, 0x7419, 0x7419, 0x7419, 0x7419, 0x7419, 0x7419, 0x7419, 0x7419, 0x7419, 0x7419, 0x7419, + 0x7419, 0x7419, 0x7439, 0x7439, 0x9D5B, 0xDF5E, 0xDF5E, 0xDF5E, 0xDF5E, 0xDF5E, 0xDF5E, 0xDF5E, 0xDF5E, 0xDF5E, 0xDF5E, 0xDF5E, + 0xDF5E, 0xDF5E, 0xDF5E, 0xDF5E, 0xDF5E, 0xDF5E, 0xDF5E, 0xDF5E, 0xDF5E, 0xDF5E, 0xDF5E, 0xDF5E, 0xDF5E, 0xDF5E, 0xDF5E, 0xDF5E, + 0xDF5E, 0xDF5E, 0xDF5E, 0xDF5E, 0xDF5E, 0xDF5E, 0xDF5E, 0xDF5E, 0xB5B8, 0x39EA, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x420B, 0x6B77, 0x6B99, 0x6B99, 0x6B99, 0x6B99, 0x6B99, 0x6B99, 0x6B99, + 0x6B99, 0x6B99, 0x6B99, 0x6B99, 0x6B99, 0x6B99, 0x6BB9, 0x6BB9, 0x6BB9, 0x6BB9, 0x6BB9, 0x6BB9, 0x6BB9, 0x6BB9, 0x6BB9, 0x6BB9, + 0x6BB9, 0x6BB9, 0x6BB9, 0x6BB9, 0x6BB9, 0x6BB9, 0x6BB9, 0x6BB9, 0x6BB9, 0x6BB9, 0x6BB9, 0x6BB9, 0x6BB9, 0x6BB9, 0x6BB9, 0x6BD9, + 0x6BD9, 0x73D9, 0x73D9, 0x73D9, 0x73D9, 0x73D9, 0x73D9, 0x73D9, 0x73D9, 0x73D9, 0x73D9, 0x73D9, 0x73D9, 0x73D9, 0x73D9, 0x73D9, + 0x73D9, 0x73D9, 0x73D9, 0x73D9, 0x73D9, 0x73D9, 0x73D9, 0x73D9, 0x73D9, 0x73F9, 0x73F9, 0x73F9, 0x73F9, 0x73F9, 0x73F9, 0x73F9, + 0x73F9, 0x73F9, 0x73F9, 0x73F9, 0x73F9, 0x73F9, 0x73F9, 0x73F9, 0x73F9, 0x73F9, 0x73F9, 0x73F9, 0x73F9, 0x73F9, 0x73F9, 0x73F9, + 0x73F9, 0x73F9, 0x7419, 0x7419, 0x7419, 0x7419, 0x7419, 0x7419, 0x7419, 0x7419, 0x7419, 0x7419, 0x7419, 0x7419, 0x7419, 0x7419, + 0x7419, 0x7419, 0x7419, 0x7419, 0x7419, 0xA57B, 0xDF5E, 0xDF5E, 0xDF5E, 0xDF5E, 0xDF5E, 0xDF5E, 0xDF5E, 0xDF5E, 0xDF5E, 0xDF5E, + 0xDF5E, 0xDF5E, 0xDF5E, 0xDF5E, 0xDF5E, 0xDF5E, 0xDF5E, 0xDF5E, 0xDF5E, 0xDF5E, 0xDF5E, 0xDF5E, 0xDF5E, 0xDF5E, 0xDF5E, 0xDF5E, + 0xDF5E, 0xDF5E, 0xDF5E, 0xDF5E, 0xDF5E, 0xDF5E, 0xDF5E, 0xCE9B, 0x422B, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x4A4E, 0x6B78, 0x6B98, 0x6B98, 0x6B98, 0x6B98, 0x6B98, 0x6B98, + 0x6B98, 0x6B99, 0x6B99, 0x6B99, 0x6B99, 0x6B99, 0x6B99, 0x6B99, 0x6B99, 0x6B99, 0x6B99, 0x6B99, 0x6B99, 0x6B99, 0x6B99, 0x6BB9, + 0x6BB9, 0x6BB9, 0x6BB9, 0x6BB9, 0x6BB9, 0x6BB9, 0x6BB9, 0x6BB9, 0x6BB9, 0x6BB9, 0x6BB9, 0x6BB9, 0x6BB9, 0x6BB9, 0x6BB9, 0x6BB9, + 0x6BB9, 0x6BB9, 0x6BB9, 0x6BB9, 0x6BB9, 0x6BB9, 0x6BB9, 0x6BB9, 0x6BB9, 0x6BD9, 0x6BD9, 0x73D9, 0x73D9, 0x73D9, 0x73D9, 0x73D9, + 0x73D9, 0x73D9, 0x73D9, 0x73D9, 0x73D9, 0x73D9, 0x73D9, 0x73D9, 0x73D9, 0x73D9, 0x73D9, 0x73D9, 0x73D9, 0x73D9, 0x73D9, 0x73D9, + 0x73D9, 0x73D9, 0x73F9, 0x73F9, 0x73F9, 0x73F9, 0x73F9, 0x73F9, 0x73F9, 0x73F9, 0x73F9, 0x73F9, 0x73F9, 0x73F9, 0x73F9, 0x73F9, + 0x73F9, 0x73F9, 0x73F9, 0x73F9, 0x73F9, 0x73F9, 0x73F9, 0x73F9, 0x73F9, 0x73F9, 0x73F9, 0x7419, 0x7419, 0x7419, 0x7419, 0x7419, + 0x7419, 0x7419, 0x7419, 0x7419, 0x7419, 0x7419, 0xB5FC, 0xDF3E, 0xDF3E, 0xDF3E, 0xDF3E, 0xDF3E, 0xDF3E, 0xDF3E, 0xDF3E, 0xDF3E, + 0xDF3E, 0xDF3E, 0xDF3E, 0xDF3E, 0xDF3E, 0xDF3E, 0xDF3E, 0xDF3E, 0xDF3E, 0xDF3E, 0xDF3E, 0xDF3E, 0xDF3E, 0xDF3E, 0xDF3E, 0xDF3E, + 0xDF3E, 0xDF3E, 0xDF3E, 0xDF3E, 0xDF3E, 0xDF3E, 0xD71D, 0x5ACD, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x5291, 0x6B78, 0x6B78, 0x6B78, 0x6B78, 0x6B78, 0x6B78, + 0x6B98, 0x6B98, 0x6B98, 0x6B98, 0x6B98, 0x6B98, 0x6B98, 0x6B98, 0x6B98, 0x6B98, 0x6B98, 0x6B99, 0x6B99, 0x6B99, 0x6B99, 0x6B99, + 0x6B99, 0x6B99, 0x6B99, 0x6B99, 0x6B99, 0x6B99, 0x6B99, 0x6B99, 0x6B99, 0x6BB9, 0x6BB9, 0x6BB9, 0x6BB9, 0x6BB9, 0x6BB9, 0x6BB9, + 0x6BB9, 0x6BB9, 0x6BB9, 0x6BB9, 0x6BB9, 0x6BB9, 0x6BB9, 0x6BB9, 0x6BB9, 0x6BB9, 0x6BB9, 0x6BB9, 0x6BB9, 0x6BB9, 0x6BB9, 0x6BB9, + 0x6BB9, 0x6BB9, 0x6BD9, 0x6BD9, 0x73D9, 0x73D9, 0x73D9, 0x73D9, 0x73D9, 0x73D9, 0x73D9, 0x73D9, 0x73D9, 0x73D9, 0x73D9, 0x73D9, + 0x73D9, 0x73D9, 0x73D9, 0x73D9, 0x73D9, 0x73D9, 0x73D9, 0x73D9, 0x73D9, 0x73D9, 0x73D9, 0x73F9, 0x73F9, 0x73F9, 0x73F9, 0x73F9, + 0x73F9, 0x73F9, 0x73F9, 0x73F9, 0x73F9, 0x73F9, 0x73F9, 0x73F9, 0x73F9, 0x73F9, 0x73F9, 0x73F9, 0x73F9, 0x73F9, 0x73F9, 0x73F9, + 0x73F9, 0x73F9, 0x73F9, 0x73F9, 0x7419, 0x7419, 0x7419, 0xBE5C, 0xDF3E, 0xDF3E, 0xDF3E, 0xDF3E, 0xDF3E, 0xDF3E, 0xDF3E, 0xDF3E, + 0xDF3E, 0xDF3E, 0xDF3E, 0xDF3E, 0xDF3E, 0xDF3E, 0xDF3E, 0xDF3E, 0xDF3E, 0xDF3E, 0xDF3E, 0xDF3E, 0xDF3E, 0xDF3E, 0xDF3E, 0xDF3E, + 0xDF3E, 0xDF3E, 0xDF3E, 0xDF3E, 0xDF3E, 0xDF3E, 0x7C12, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39CA, 0x5AF3, 0x6B78, 0x6B78, 0x6B78, 0x6B78, 0x6B78, + 0x6B78, 0x6B78, 0x6B78, 0x6B78, 0x6B78, 0x6B78, 0x6B78, 0x6B78, 0x6B78, 0x6B98, 0x6B98, 0x6B98, 0x6B98, 0x6B98, 0x6B98, 0x6B98, + 0x6B98, 0x6B98, 0x6B98, 0x6B98, 0x6B99, 0x6B99, 0x6B99, 0x6B99, 0x6B99, 0x6B99, 0x6B99, 0x6B99, 0x6B99, 0x6B99, 0x6B99, 0x6B99, + 0x6B99, 0x6B99, 0x6BB9, 0x6BB9, 0x6BB9, 0x6BB9, 0x6BB9, 0x6BB9, 0x6BB9, 0x6BB9, 0x6BB9, 0x6BB9, 0x6BB9, 0x6BB9, 0x6BB9, 0x6BB9, + 0x6BB9, 0x6BB9, 0x6BB9, 0x6BB9, 0x6BB9, 0x6BB9, 0x6BB9, 0x6BB9, 0x6BB9, 0x6BB9, 0x6BB9, 0x6BD9, 0x6BD9, 0x73D9, 0x73D9, 0x73D9, + 0x73D9, 0x73D9, 0x73D9, 0x73D9, 0x73D9, 0x73D9, 0x73D9, 0x73D9, 0x73D9, 0x73D9, 0x73D9, 0x73D9, 0x73D9, 0x73D9, 0x73D9, 0x73D9, + 0x73D9, 0x73D9, 0x73D9, 0x73D9, 0x73F9, 0x73F9, 0x73F9, 0x73F9, 0x73F9, 0x73F9, 0x73F9, 0x73F9, 0x73F9, 0x73F9, 0x73F9, 0x73F9, + 0x73F9, 0x73F9, 0x73F9, 0x73F9, 0x73F9, 0x73F9, 0x73F9, 0x7C39, 0xCEBD, 0xDF3E, 0xDF3E, 0xDF3E, 0xDF3E, 0xDF3E, 0xDF3E, 0xDF3E, + 0xDF3E, 0xDF3E, 0xDF3E, 0xDF3E, 0xDF3E, 0xDF3E, 0xDF3E, 0xDF3E, 0xDF3E, 0xDF3E, 0xDF3E, 0xDF3E, 0xDF3E, 0xDF3E, 0xDF3E, 0xDF3E, + 0xDF3E, 0xDF3E, 0xDF3E, 0xDF3E, 0xDF3E, 0x9D16, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39EA, 0x6336, 0x6B78, 0x6B78, 0x6B78, 0x6B78, + 0x6B78, 0x6B78, 0x6B78, 0x6B78, 0x6B78, 0x6B78, 0x6B78, 0x6B78, 0x6B78, 0x6B78, 0x6B78, 0x6B78, 0x6B78, 0x6B78, 0x6B78, 0x6B78, + 0x6B78, 0x6B78, 0x6B98, 0x6B98, 0x6B98, 0x6B98, 0x6B98, 0x6B98, 0x6B98, 0x6B98, 0x6B98, 0x6B98, 0x6B98, 0x6B99, 0x6B99, 0x6B99, + 0x6B99, 0x6B99, 0x6B99, 0x6B99, 0x6B99, 0x6B99, 0x6B99, 0x6B99, 0x6B99, 0x6B99, 0x6B99, 0x6BB9, 0x6BB9, 0x6BB9, 0x6BB9, 0x6BB9, + 0x6BB9, 0x6BB9, 0x6BB9, 0x6BB9, 0x6BB9, 0x6BB9, 0x6BB9, 0x6BB9, 0x6BB9, 0x6BB9, 0x6BB9, 0x6BB9, 0x6BB9, 0x6BB9, 0x6BB9, 0x6BB9, + 0x6BB9, 0x6BB9, 0x6BB9, 0x6BB9, 0x6BB9, 0x6BD9, 0x6BD9, 0x73D9, 0x73D9, 0x73D9, 0x73D9, 0x73D9, 0x73D9, 0x73D9, 0x73D9, 0x73D9, + 0x73D9, 0x73D9, 0x73D9, 0x73D9, 0x73D9, 0x73D9, 0x73D9, 0x73D9, 0x73D9, 0x73D9, 0x73D9, 0x73D9, 0x73D9, 0x73D9, 0x73F9, 0x73F9, + 0x73F9, 0x73F9, 0x73F9, 0x73F9, 0x73F9, 0x73F9, 0x73F9, 0x73F9, 0x847A, 0xD6FE, 0xDF3E, 0xDF3E, 0xDF3E, 0xDF3E, 0xDF3E, 0xDF3E, + 0xDF3E, 0xDF3E, 0xDF3E, 0xDF3E, 0xDF3E, 0xDF3E, 0xDF3E, 0xDF3E, 0xDF3E, 0xDF3E, 0xDF3E, 0xDF3E, 0xDF3E, 0xDF3E, 0xDF3E, 0xDF3E, + 0xDF3E, 0xDF3E, 0xDF3E, 0xDF3E, 0xB619, 0x39EA, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x420C, 0x6358, 0x6B58, 0x6B58, 0x6B58, + 0x6B58, 0x6B58, 0x6B78, 0x6B78, 0x6B78, 0x6B78, 0x6B78, 0x6B78, 0x6B78, 0x6B78, 0x6B78, 0x6B78, 0x6B78, 0x6B78, 0x6B78, 0x6B78, + 0x6B78, 0x6B78, 0x6B78, 0x6B78, 0x6B78, 0x6B78, 0x6B78, 0x6B78, 0x6B78, 0x6B78, 0x6B78, 0x6B98, 0x6B98, 0x6B98, 0x6B98, 0x6B98, + 0x6B98, 0x6B98, 0x6B98, 0x6B98, 0x6B98, 0x6B98, 0x6B98, 0x6B99, 0x6B99, 0x6B99, 0x6B99, 0x6B99, 0x6B99, 0x6B99, 0x6B99, 0x6B99, + 0x6B99, 0x6B99, 0x6B99, 0x6B99, 0x6B99, 0x6BB9, 0x6BB9, 0x6BB9, 0x6BB9, 0x6BB9, 0x6BB9, 0x6BB9, 0x6BB9, 0x6BB9, 0x6BB9, 0x6BB9, + 0x6BB9, 0x6BB9, 0x6BB9, 0x6BB9, 0x6BB9, 0x6BB9, 0x6BB9, 0x6BB9, 0x6BB9, 0x6BB9, 0x6BB9, 0x6BB9, 0x6BB9, 0x6BB9, 0x6BD9, 0x6BD9, + 0x73D9, 0x73D9, 0x73D9, 0x73D9, 0x73D9, 0x73D9, 0x73D9, 0x73D9, 0x73D9, 0x73D9, 0x73D9, 0x73D9, 0x73D9, 0x73D9, 0x73D9, 0x73D9, + 0x73D9, 0x73D9, 0x73D9, 0x73D9, 0x73D9, 0x73D9, 0x73D9, 0x73F9, 0x73F9, 0x8CDA, 0xD71E, 0xD73E, 0xD73E, 0xD73E, 0xD73E, 0xD73E, + 0xD73E, 0xD73E, 0xD73E, 0xD73E, 0xD73E, 0xD73E, 0xD73E, 0xD73E, 0xD73E, 0xD73E, 0xD73E, 0xD73E, 0xD73E, 0xD73E, 0xD73E, 0xD73E, + 0xD73E, 0xD73E, 0xD73E, 0xCEBC, 0x4A6C, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x4A4F, 0x6B58, 0x6B58, 0x6B58, + 0x6B58, 0x6B58, 0x6B58, 0x6B58, 0x6B58, 0x6B58, 0x6B58, 0x6B58, 0x6B58, 0x6B58, 0x6B58, 0x6B58, 0x6B78, 0x6B78, 0x6B78, 0x6B78, + 0x6B78, 0x6B78, 0x6B78, 0x6B78, 0x6B78, 0x6B78, 0x6B78, 0x6B78, 0x6B78, 0x6B78, 0x6B78, 0x6B78, 0x6B78, 0x6B78, 0x6B78, 0x6B78, + 0x6B78, 0x6B78, 0x6B78, 0x6B78, 0x6B78, 0x6B98, 0x6B98, 0x6B98, 0x6B98, 0x6B98, 0x6B98, 0x6B98, 0x6B98, 0x6B98, 0x6B98, 0x6B98, + 0x6B99, 0x6B99, 0x6B99, 0x6B99, 0x6B99, 0x6B99, 0x6B99, 0x6B99, 0x6B99, 0x6B99, 0x6B99, 0x6B99, 0x6B99, 0x6B99, 0x6BB9, 0x6BB9, + 0x6BB9, 0x6BB9, 0x6BB9, 0x6BB9, 0x6BB9, 0x6BB9, 0x6BB9, 0x6BB9, 0x6BB9, 0x6BB9, 0x6BB9, 0x6BB9, 0x6BB9, 0x6BB9, 0x6BB9, 0x6BB9, + 0x6BB9, 0x6BB9, 0x6BB9, 0x6BB9, 0x6BB9, 0x6BB9, 0x6BB9, 0x6BD9, 0x6BD9, 0x73D9, 0x73D9, 0x73D9, 0x73D9, 0x73D9, 0x73D9, 0x73D9, + 0x73D9, 0x73D9, 0x73D9, 0x73D9, 0x73D9, 0x73D9, 0x73D9, 0x73D9, 0x73D9, 0x73D9, 0xA57B, 0xD71E, 0xD71E, 0xD71E, 0xD71E, 0xD71E, + 0xD71E, 0xD71E, 0xD71E, 0xD71E, 0xD71E, 0xD71E, 0xD71E, 0xD71E, 0xD71E, 0xD71E, 0xD71E, 0xD71E, 0xD71E, 0xD71E, 0xD71E, 0xD71E, + 0xD71E, 0xD71E, 0xD71D, 0x632F, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x52B2, 0x6358, 0x6358, + 0x6358, 0x6358, 0x6358, 0x6358, 0x6358, 0x6B58, 0x6B58, 0x6B58, 0x6B58, 0x6B58, 0x6B58, 0x6B58, 0x6B58, 0x6B58, 0x6B58, 0x6B58, + 0x6B58, 0x6B58, 0x6B58, 0x6B58, 0x6B58, 0x6B78, 0x6B78, 0x6B78, 0x6B78, 0x6B78, 0x6B78, 0x6B78, 0x6B78, 0x6B78, 0x6B78, 0x6B78, + 0x6B78, 0x6B78, 0x6B78, 0x6B78, 0x6B78, 0x6B78, 0x6B78, 0x6B78, 0x6B78, 0x6B78, 0x6B78, 0x6B78, 0x6B78, 0x6B78, 0x6B98, 0x6B98, + 0x6B98, 0x6B98, 0x6B98, 0x6B98, 0x6B98, 0x6B98, 0x6B98, 0x6B98, 0x6B98, 0x6B99, 0x6B99, 0x6B99, 0x6B99, 0x6B99, 0x6B99, 0x6B99, + 0x6B99, 0x6B99, 0x6B99, 0x6B99, 0x6B99, 0x6B99, 0x6B99, 0x6BB9, 0x6BB9, 0x6BB9, 0x6BB9, 0x6BB9, 0x6BB9, 0x6BB9, 0x6BB9, 0x6BB9, + 0x6BB9, 0x6BB9, 0x6BB9, 0x6BB9, 0x6BB9, 0x6BB9, 0x6BB9, 0x6BB9, 0x6BB9, 0x6BB9, 0x6BB9, 0x6BB9, 0x6BB9, 0x6BB9, 0x6BB9, 0x6BB9, + 0x6BB9, 0x6BD9, 0x73D9, 0x73D9, 0x73D9, 0x73D9, 0x73D9, 0x73D9, 0x73D9, 0x73D9, 0x73D9, 0xB61C, 0xD71E, 0xD71E, 0xD71E, 0xD71E, + 0xD71E, 0xD71E, 0xD71E, 0xD71E, 0xD71E, 0xD71E, 0xD71E, 0xD71E, 0xD71E, 0xD71E, 0xD71E, 0xD71E, 0xD71E, 0xD71E, 0xD71E, 0xD71E, + 0xD71E, 0xD71E, 0x8453, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39CA, 0x5AD4, 0x6338, + 0x6338, 0x6338, 0x6338, 0x6338, 0x6338, 0x6358, 0x6358, 0x6358, 0x6358, 0x6358, 0x6358, 0x6358, 0x6358, 0x6358, 0x6B58, 0x6B58, + 0x6B58, 0x6B58, 0x6B58, 0x6B58, 0x6B58, 0x6B58, 0x6B58, 0x6B58, 0x6B58, 0x6B58, 0x6B58, 0x6B58, 0x6B58, 0x6B58, 0x6B78, 0x6B78, + 0x6B78, 0x6B78, 0x6B78, 0x6B78, 0x6B78, 0x6B78, 0x6B78, 0x6B78, 0x6B78, 0x6B78, 0x6B78, 0x6B78, 0x6B78, 0x6B78, 0x6B78, 0x6B78, + 0x6B78, 0x6B78, 0x6B78, 0x6B78, 0x6B78, 0x6B78, 0x6B78, 0x6B98, 0x6B98, 0x6B98, 0x6B98, 0x6B98, 0x6B98, 0x6B98, 0x6B98, 0x6B98, + 0x6B98, 0x6B98, 0x6B99, 0x6B99, 0x6B99, 0x6B99, 0x6B99, 0x6B99, 0x6B99, 0x6B99, 0x6B99, 0x6B99, 0x6B99, 0x6B99, 0x6B99, 0x6B99, + 0x6B99, 0x6BB9, 0x6BB9, 0x6BB9, 0x6BB9, 0x6BB9, 0x6BB9, 0x6BB9, 0x6BB9, 0x6BB9, 0x6BB9, 0x6BB9, 0x6BB9, 0x6BB9, 0x6BB9, 0x6BB9, + 0x6BB9, 0x6BB9, 0x6BB9, 0x6BB9, 0x6BB9, 0x6BB9, 0x6BB9, 0x6BB9, 0x6BB9, 0x6BB9, 0x6BD9, 0x73F9, 0xC69D, 0xD71E, 0xD71E, 0xD71E, + 0xD71E, 0xD71E, 0xD71E, 0xD71E, 0xD71E, 0xD71E, 0xD71E, 0xD71E, 0xD71E, 0xD71E, 0xD71E, 0xD71E, 0xD71E, 0xD71E, 0xD71E, 0xD71E, + 0xD71E, 0xA557, 0x39CA, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39EB, 0x6317, + 0x6338, 0x6338, 0x6338, 0x6338, 0x6338, 0x6338, 0x6338, 0x6338, 0x6338, 0x6338, 0x6338, 0x6338, 0x6338, 0x6338, 0x6358, 0x6358, + 0x6358, 0x6358, 0x6358, 0x6358, 0x6358, 0x6358, 0x6358, 0x6B58, 0x6B58, 0x6B58, 0x6B58, 0x6B58, 0x6B58, 0x6B58, 0x6B58, 0x6B58, + 0x6B58, 0x6B58, 0x6B58, 0x6B58, 0x6B58, 0x6B58, 0x6B58, 0x6B58, 0x6B78, 0x6B78, 0x6B78, 0x6B78, 0x6B78, 0x6B78, 0x6B78, 0x6B78, + 0x6B78, 0x6B78, 0x6B78, 0x6B78, 0x6B78, 0x6B78, 0x6B78, 0x6B78, 0x6B78, 0x6B78, 0x6B78, 0x6B78, 0x6B78, 0x6B78, 0x6B78, 0x6B78, + 0x6B78, 0x6B98, 0x6B98, 0x6B98, 0x6B98, 0x6B98, 0x6B98, 0x6B98, 0x6B98, 0x6B98, 0x6B98, 0x6B98, 0x6B99, 0x6B99, 0x6B99, 0x6B99, + 0x6B99, 0x6B99, 0x6B99, 0x6B99, 0x6B99, 0x6B99, 0x6B99, 0x6B99, 0x6B99, 0x6B99, 0x6BB9, 0x6BB9, 0x6BB9, 0x6BB9, 0x6BB9, 0x6BB9, + 0x6BB9, 0x6BB9, 0x6BB9, 0x6BB9, 0x6BB9, 0x6BB9, 0x6BB9, 0x6BB9, 0x6BB9, 0x6BB9, 0x6BB9, 0x6BB9, 0x847A, 0xD6FD, 0xD71E, 0xD71E, + 0xD71E, 0xD71E, 0xD71E, 0xD71E, 0xD71E, 0xD71E, 0xD71E, 0xD71E, 0xD71E, 0xD71E, 0xD71E, 0xD71E, 0xD71E, 0xD71E, 0xD71E, 0xD71E, + 0xBE5B, 0x422B, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x422D, + 0x6318, 0x6338, 0x6338, 0x6338, 0x6338, 0x6338, 0x6338, 0x6338, 0x6338, 0x6338, 0x6338, 0x6338, 0x6338, 0x6338, 0x6338, 0x6338, + 0x6338, 0x6338, 0x6338, 0x6338, 0x6338, 0x6338, 0x6338, 0x6338, 0x6358, 0x6358, 0x6358, 0x6358, 0x6358, 0x6358, 0x6358, 0x6358, + 0x6B58, 0x6B58, 0x6B58, 0x6B58, 0x6B58, 0x6B58, 0x6B58, 0x6B58, 0x6B58, 0x6B58, 0x6B58, 0x6B58, 0x6B58, 0x6B58, 0x6B58, 0x6B58, + 0x6B58, 0x6B58, 0x6336, 0x5AF4, 0x52D3, 0x52B1, 0x4A70, 0x4A4E, 0x424E, 0x422D, 0x420C, 0x39EB, 0x39EA, 0x39EA, 0x39EA, 0x39EA, + 0x39EA, 0x39EB, 0x420B, 0x420C, 0x422C, 0x422D, 0x424D, 0x4A4E, 0x4A6F, 0x52B1, 0x52D2, 0x5AF4, 0x6315, 0x6356, 0x6B78, 0x6B98, + 0x6B98, 0x6B98, 0x6B98, 0x6B98, 0x6B98, 0x6B99, 0x6B99, 0x6B99, 0x6B99, 0x6B99, 0x6B99, 0x6B99, 0x6B99, 0x6B99, 0x6B99, 0x6B99, + 0x6B99, 0x6B99, 0x6B99, 0x6BB9, 0x6BB9, 0x6BB9, 0x6BB9, 0x6BB9, 0x6BB9, 0x6BB9, 0x6BB9, 0x6BB9, 0x6BB9, 0xA55B, 0xD71E, 0xD71E, + 0xD71E, 0xD71E, 0xD71E, 0xD71E, 0xD71E, 0xD71E, 0xD71E, 0xD71E, 0xD71E, 0xD71E, 0xD71E, 0xD71E, 0xD71E, 0xD71E, 0xD71E, 0xCEBC, + 0x528C, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x4A70, 0x6318, 0x6318, 0x6318, 0x6318, 0x6318, 0x6318, 0x6318, 0x6338, 0x6338, 0x6338, 0x6338, 0x6338, 0x6338, 0x6338, 0x6338, + 0x6338, 0x6338, 0x6338, 0x6338, 0x6338, 0x6338, 0x6338, 0x6338, 0x6338, 0x6338, 0x6338, 0x6338, 0x6338, 0x6338, 0x6338, 0x6338, + 0x6338, 0x6358, 0x6358, 0x6358, 0x6358, 0x6358, 0x6358, 0x6358, 0x6358, 0x6358, 0x6B58, 0x6337, 0x5AF4, 0x52B2, 0x4A6F, 0x422D, + 0x41EB, 0x39CA, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39EB, + 0x422D, 0x4A90, 0x52D2, 0x6315, 0x6378, 0x6B98, 0x6B98, 0x6B98, 0x6B98, 0x6B98, 0x6B98, 0x6B98, 0x6B98, 0x6B98, 0x6B99, 0x6B99, + 0x6B99, 0x6B99, 0x6B99, 0x6B99, 0x6B99, 0x6B99, 0x6B99, 0x6B99, 0x6B99, 0x6B99, 0x6B99, 0x6B99, 0x6B99, 0x6BB9, 0xBE3C, 0xD6FD, + 0xD6FD, 0xD6FD, 0xD6FD, 0xD6FD, 0xD6FD, 0xD6FD, 0xD6FD, 0xD6FD, 0xD6FD, 0xD6FD, 0xD6FD, 0xD6FD, 0xD6FD, 0xD6FD, 0xCEFD, 0x6B70, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39CA, 0x52B3, 0x6318, 0x6318, 0x6318, 0x6318, 0x6318, 0x6318, 0x6318, 0x6318, 0x6318, 0x6318, 0x6318, 0x6318, 0x6318, 0x6318, + 0x6318, 0x6338, 0x6338, 0x6338, 0x6338, 0x6338, 0x6338, 0x6338, 0x6338, 0x6338, 0x6338, 0x6338, 0x6338, 0x6338, 0x6338, 0x6338, + 0x6338, 0x6338, 0x6338, 0x6338, 0x6338, 0x6338, 0x6338, 0x5AD4, 0x5291, 0x422D, 0x39EA, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x3A0B, 0x424E, 0x52B1, 0x6315, 0x6B78, 0x6B78, 0x6B78, 0x6B78, 0x6B98, 0x6B98, 0x6B98, + 0x6B98, 0x6B98, 0x6B98, 0x6B98, 0x6B98, 0x6B98, 0x6B98, 0x6B98, 0x6B99, 0x6B99, 0x6B99, 0x6B99, 0x6B99, 0x6B99, 0x7C19, 0xCEDD, + 0xCEFD, 0xCEFD, 0xCEFD, 0xCEFD, 0xCEFD, 0xCEFD, 0xCEFD, 0xCEFD, 0xCEFD, 0xCEFD, 0xCEFD, 0xCEFD, 0xCEFD, 0xCEFD, 0x8C94, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39CA, 0x5AD6, 0x6318, 0x6318, 0x6318, 0x6318, 0x6318, 0x6318, 0x6318, 0x6318, 0x6318, 0x6318, 0x6318, 0x6318, 0x6318, + 0x6318, 0x6318, 0x6318, 0x6318, 0x6318, 0x6318, 0x6318, 0x6318, 0x6318, 0x6318, 0x6338, 0x6338, 0x6338, 0x6338, 0x6338, 0x6338, + 0x6338, 0x6338, 0x6317, 0x5AD4, 0x4A70, 0x420D, 0x39CA, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39EA, 0x424D, 0x52B1, 0x5B15, 0x6B78, 0x6B78, 0x6B78, + 0x6B78, 0x6B78, 0x6B78, 0x6B78, 0x6B78, 0x6B78, 0x6B98, 0x6B98, 0x6B98, 0x6B98, 0x6B98, 0x6B98, 0x6B98, 0x6B98, 0x6B98, 0x8CBA, + 0xCEFD, 0xCEFD, 0xCEFD, 0xCEFD, 0xCEFD, 0xCEFD, 0xCEFD, 0xCEFD, 0xCEFD, 0xCEFD, 0xCEFD, 0xCEFD, 0xCEFD, 0xA598, 0x39EA, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x41EC, 0x62F7, 0x62F8, 0x62F8, 0x62F8, 0x62F8, 0x62F8, 0x62F8, 0x62F8, 0x6318, 0x6318, 0x6318, 0x6318, 0x6318, + 0x6318, 0x6318, 0x6318, 0x6318, 0x6318, 0x6318, 0x6318, 0x6318, 0x6318, 0x6318, 0x6318, 0x6318, 0x6318, 0x6318, 0x6318, 0x5AF6, + 0x5291, 0x422D, 0x39CA, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39EA, 0x4A4E, 0x52D2, + 0x6337, 0x6B78, 0x6B78, 0x6B78, 0x6B78, 0x6B78, 0x6B78, 0x6B78, 0x6B78, 0x6B78, 0x6B78, 0x6B78, 0x6B78, 0x6B78, 0x6B78, 0x6B98, + 0xADBC, 0xCEFD, 0xCEFD, 0xCEFD, 0xCEFD, 0xCEFD, 0xCEFD, 0xCEFD, 0xCEFD, 0xCEFD, 0xCEFD, 0xCEFD, 0xBE5B, 0x424B, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x422E, 0x62F8, 0x62F8, 0x62F8, 0x62F8, 0x62F8, 0x62F8, 0x62F8, 0x62F8, 0x62F8, 0x62F8, 0x62F8, 0x62F8, + 0x62F8, 0x62F8, 0x62F8, 0x62F8, 0x6318, 0x6318, 0x6318, 0x6318, 0x6318, 0x6318, 0x6318, 0x6318, 0x5AD5, 0x4A70, 0x420C, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x420C, 0x5291, 0x6316, 0x6B78, 0x6B78, 0x6B78, 0x6B78, 0x6B78, 0x6B78, 0x6B78, 0x6B78, 0x6B78, 0x6B78, 0x6B78, 0x6B78, + 0x73B9, 0xC6BD, 0xCEFD, 0xCEFD, 0xCEFD, 0xCEFD, 0xCEFD, 0xCEFD, 0xCEFD, 0xCEFD, 0xCEFD, 0xCEDD, 0x5B0E, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x4A51, 0x62F8, 0x62F8, 0x62F8, 0x62F8, 0x62F8, 0x62F8, 0x62F8, 0x62F8, 0x62F8, 0x62F8, 0x62F8, + 0x62F8, 0x62F8, 0x62F8, 0x62F8, 0x62F8, 0x62F8, 0x62F8, 0x62F8, 0x62F8, 0x5AD6, 0x4A50, 0x39EB, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x3A0B, 0x5290, 0x6316, 0x6B58, 0x6B58, 0x6B78, 0x6B78, 0x6B78, 0x6B78, 0x6B78, 0x6B78, 0x6B78, + 0x6B78, 0x8CBA, 0xCEDD, 0xCEDD, 0xCEDD, 0xCEDD, 0xCEDD, 0xCEDD, 0xCEDD, 0xCEDD, 0xCEDD, 0x73D1, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39CA, 0x5294, 0x62D8, 0x62D8, 0x62D8, 0x62D8, 0x62D8, 0x62D8, 0x62D8, 0x62F8, 0x62F8, 0x62F8, + 0x62F8, 0x62F8, 0x62F8, 0x62F8, 0x62F8, 0x62F8, 0x5AD7, 0x5292, 0x420D, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39CA, 0x422D, 0x5AD3, 0x6358, 0x6B58, 0x6B58, 0x6B58, 0x6B58, 0x6B58, 0x6B58, + 0x6B58, 0x6B78, 0xB61C, 0xCEDD, 0xCEDD, 0xCEDD, 0xCEDD, 0xCEDD, 0xCEDD, 0xCEDD, 0x9516, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39EA, 0x5AB5, 0x5AD8, 0x5AD8, 0x5AD8, 0x5AD8, 0x5AD8, 0x5AD8, 0x62D8, 0x62D8, 0x62D8, + 0x62D8, 0x62D8, 0x62D8, 0x62D8, 0x5AB5, 0x4A2F, 0x39CA, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39EB, 0x4A90, 0x6316, 0x6B58, 0x6B58, 0x6B58, 0x6B58, + 0x6B58, 0x6B58, 0x73F9, 0xC6BD, 0xC6DD, 0xC6DD, 0xC6DD, 0xC6DD, 0xC6DD, 0xA598, 0x39EA, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39EB, 0x5274, 0x5AD8, 0x5AD8, 0x5AD8, 0x5AD8, 0x5AD8, 0x5AD8, 0x5AD8, 0x5AD8, + 0x5AD8, 0x5AD8, 0x5294, 0x420E, 0x39CA, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39CA, 0x422E, 0x5AF5, 0x6358, 0x6358, + 0x6358, 0x6358, 0x6358, 0x951B, 0xC6DD, 0xC6DD, 0xC6DD, 0xC6DD, 0x9D37, 0x420A, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39CA, 0x4A2F, 0x5A95, 0x5AB8, 0x5AB8, 0x5AB8, 0x5AB8, 0x5AB8, 0x5AB7, + 0x5273, 0x420C, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x422D, 0x5AD3, + 0x6338, 0x6338, 0x6338, 0x6B58, 0xB63C, 0xC6DD, 0xADD9, 0x6350, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39CA, 0x41EC, 0x420E, 0x4A30, 0x4A30, 0x422E, 0x39EB, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x420C, 0x4A70, 0x5291, 0x73B5, 0x6BB3, 0x52AD, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, + 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9, 0x39C9 +}; + +static_assert(sizeof(AMS_LOGO_BIN) == AMS_LOGO_WIDTH * AMS_LOGO_HEIGHT * sizeof(*AMS_LOGO_BIN), "Logo definition!"); \ No newline at end of file diff --git a/stratosphere/fatal/source/fatal_font.cpp b/stratosphere/fatal/source/fatal_font.cpp new file mode 100644 index 000000000..b81c65126 --- /dev/null +++ b/stratosphere/fatal/source/fatal_font.cpp @@ -0,0 +1,149 @@ +/* + * Copyright (c) 2018 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + + +#include +#include "fatal_types.hpp" + +#include +#include +#include + +#include +#include FT_FREETYPE_H + +#include "fatal_config.hpp" +#include "fatal_font.hpp" + +static u16 *g_fb = nullptr; +static u32 (*g_unswizzle_func)(u32, u32) = nullptr; +static u16 g_font_color = 0xFFFF; + +static PlFontData g_font; +static PlFontData g_fonts[PlSharedFontType_Total]; +static FT_Library g_library; +static FT_Face g_face; +static FT_Error g_ft_err = 0; + +static u16 Blend(u16 color, u16 bg, u8 alpha) { + const u32 c_r = RGB565_GET_R8(color); + const u32 c_g = RGB565_GET_G8(color); + const u32 c_b = RGB565_GET_B8(color); + const u32 b_r = RGB565_GET_R8(bg); + const u32 b_g = RGB565_GET_G8(bg); + const u32 b_b = RGB565_GET_B8(bg); + + const u32 r = ((alpha * c_r) + ((0xFF - alpha) * b_r)) / 0xFF; + const u32 g = ((alpha * c_g) + ((0xFF - alpha) * b_g)) / 0xFF; + const u32 b = ((alpha * c_b) + ((0xFF - alpha) * b_b)) / 0xFF; + + return RGB888_TO_RGB565(r, g, b); +} + +static void DrawGlyph(FT_Bitmap *bitmap, u32 x, u32 y) { + u8* imageptr = bitmap->buffer; + + if (bitmap->pixel_mode!=FT_PIXEL_MODE_GRAY) return; + + for (u32 tmpy = 0; tmpy < bitmap->rows; tmpy++) { + for (u32 tmpx = 0; tmpx < bitmap->width; tmpx++) { + /* Implement very simple blending, as the bitmap value is an alpha value. */ + u16 *ptr = &g_fb[g_unswizzle_func(x + tmpx, y + tmpy)]; + *ptr = Blend(g_font_color, *ptr, imageptr[tmpx]); + } + imageptr += bitmap->pitch; + } +} + +void FontManager::DrawString(u32 x, u32 y, const char *str) { + FT_UInt glyph_index; + FT_GlyphSlot slot = g_face->glyph; + + const size_t len = strlen(str); + + u32 cur_x = x, cur_y = y; + + for (u32 i = 0; i < len; ) { + u32 cur_char; + ssize_t unit_count = decode_utf8(&cur_char, reinterpret_cast(&str[i])); + if (unit_count <= 0) break; + i += unit_count; + + if (cur_char == '\n') { + cur_x = x; + cur_y += g_face->size->metrics.height >> 6; + continue; + } + + glyph_index = FT_Get_Char_Index(g_face, cur_char); + + g_ft_err = FT_Load_Glyph(g_face, glyph_index, FT_LOAD_DEFAULT); + + if (g_ft_err == 0) { + g_ft_err = FT_Render_Glyph(g_face->glyph, FT_RENDER_MODE_NORMAL); + } + + if (g_ft_err) { + return; + } + + DrawGlyph(&slot->bitmap, cur_x + slot->bitmap_left, cur_y - slot->bitmap_top); + + cur_x += slot->advance.x >> 6; + cur_y += slot->advance.y >> 6; + } +} + +void FontManager::DrawFormat(u32 x, u32 y, const char *format, ...) { + va_list va_arg; + va_start(va_arg, format); + + char char_buf[0x400]; + vsnprintf(char_buf, sizeof(char_buf), format, va_arg); + + DrawString(x, y, char_buf); +} + +void FontManager::SetFontColor(u16 color) { + g_font_color = color; +} + +void FontManager::ConfigureFontFramebuffer(u16 *fb, u32 (*unswizzle_func)(u32, u32)) { + g_fb = fb; + g_unswizzle_func = unswizzle_func; +} + +Result FontManager::InitializeSharedFont() { + Result rc; + size_t total_fonts = 0; + + if (R_FAILED((rc = plGetSharedFont(GetFatalConfig()->language_code, g_fonts, PlSharedFontType_Total, &total_fonts)))) { + return rc; + } + + if (R_FAILED((rc = plGetSharedFontByType(&g_font, PlSharedFontType_Standard)))) { + return rc; + } + + g_ft_err = FT_Init_FreeType(&g_library); + if (g_ft_err) return g_ft_err; + + g_ft_err = FT_New_Memory_Face(g_library, reinterpret_cast(g_font.address), g_font.size, 0, &g_face); + if (g_ft_err) return g_ft_err; + + g_ft_err = FT_Set_Char_Size(g_face, 0, 8*64, 300, 300); + return g_ft_err; +} \ No newline at end of file diff --git a/stratosphere/fatal/source/fatal_font.hpp b/stratosphere/fatal/source/fatal_font.hpp new file mode 100644 index 000000000..ab553a28a --- /dev/null +++ b/stratosphere/fatal/source/fatal_font.hpp @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2018 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once +#include +#include +#include + +#define RGB888_TO_RGB565(r, g, b) ((((r >> 3) << 11) & 0xF800) | (((g >> 2) << 5) & 0x7E0) | ((b >> 3) & 0x1F)) +#define RGB565_GET_R8(c) (((c >> 11) & 0x1F) << 3) +#define RGB565_GET_G8(c) (((c >> 5) & 0x3F) << 2) +#define RGB565_GET_B8(c) (((c >> 0) & 0x1F) << 3) + +class FontManager { + public: + static Result InitializeSharedFont(); + static void ConfigureFontFramebuffer(u16 *fb, u32 (*unswizzle_func)(u32, u32)); + + static void SetFontColor(u16 color); + static void DrawString(u32 x, u32 y, const char *str); + static void DrawFormat(u32 x, u32 y, const char *format, ...); +}; \ No newline at end of file diff --git a/stratosphere/fatal/source/fatal_main.cpp b/stratosphere/fatal/source/fatal_main.cpp index 58a270b49..292258a73 100644 --- a/stratosphere/fatal/source/fatal_main.cpp +++ b/stratosphere/fatal/source/fatal_main.cpp @@ -28,13 +28,14 @@ #include "fatal_user.hpp" #include "fatal_config.hpp" #include "fatal_repair.hpp" +#include "fatal_font.hpp" extern "C" { extern u32 __start__; u32 __nx_applet_type = AppletType_None; - #define INNER_HEAP_SIZE 0x3C0000 + #define INNER_HEAP_SIZE 0x280000 size_t nx_inner_heap_size = INNER_HEAP_SIZE; char nx_inner_heap[INNER_HEAP_SIZE]; @@ -112,11 +113,17 @@ void __appInit(void) { std::abort(); } + rc = plInitialize(); + if (R_FAILED(rc)) { + std::abort(); + } + /* fatal cannot throw fatal, so don't do: CheckAtmosphereVersion(CURRENT_ATMOSPHERE_VERSION); */ } void __appExit(void) { /* Cleanup services. */ + plExit(); spsmExit(); psmExit(); lblExit(); @@ -134,7 +141,10 @@ int main(int argc, char **argv) /* Load settings from set:sys. */ InitializeFatalConfig(); - /* TODO: Load shared font. */ + /* Load shared font. */ + if (R_FAILED(FontManager::InitializeSharedFont())) { + std::abort(); + } /* Check whether we should throw fatal due to repair process. */ CheckRepairStatus(); diff --git a/stratosphere/fatal/source/fatal_task.cpp b/stratosphere/fatal/source/fatal_task.cpp index 39a1c82d1..62b39cdbb 100644 --- a/stratosphere/fatal/source/fatal_task.cpp +++ b/stratosphere/fatal/source/fatal_task.cpp @@ -42,21 +42,21 @@ static void RunTaskThreadFunc(void *arg) { svcExitThread(); } -static void RunTask(IFatalTask *task) { +static void RunTask(IFatalTask *task, u32 stack_size = 0x4000) { if (g_num_threads >= MaxTasks) { std::abort(); } HosThread *cur_thread = &g_task_threads[g_num_threads++]; - cur_thread->Initialize(&RunTaskThreadFunc, task, 0x4000, 15); + cur_thread->Initialize(&RunTaskThreadFunc, task, stack_size, 15); cur_thread->Start(); } void RunFatalTasks(FatalContext *ctx, u64 title_id, bool error_report, Event *erpt_event, Event *battery_event) { RunTask(new ErrorReportTask(ctx, title_id, error_report, erpt_event)); RunTask(new PowerControlTask(ctx, title_id, erpt_event, battery_event)); - RunTask(new ShowFatalTask(ctx, title_id, battery_event)); + RunTask(new ShowFatalTask(ctx, title_id, battery_event), 0x10000); RunTask(new StopSoundTask(ctx, title_id)); RunTask(new BacklightControlTask(ctx, title_id)); RunTask(new AdjustClockTask(ctx, title_id)); diff --git a/stratosphere/fatal/source/fatal_task_screen.cpp b/stratosphere/fatal/source/fatal_task_screen.cpp index 7351e6022..b651c7ef9 100644 --- a/stratosphere/fatal/source/fatal_task_screen.cpp +++ b/stratosphere/fatal/source/fatal_task_screen.cpp @@ -17,6 +17,27 @@ #include #include "fatal_task_screen.hpp" #include "fatal_config.hpp" +#include "fatal_font.hpp" +#include "ams_logo.hpp" + +static constexpr u32 FatalScreenWidth = 1280; +static constexpr u32 FatalScreenHeight = 720; +static constexpr u32 FatalScreenBpp = 2; + +static constexpr u32 FatalScreenWidthAlignedBytes = (FatalScreenWidth * FatalScreenBpp + 63) & ~63; +static constexpr u32 FatalScreenWidthAligned = FatalScreenWidthAlignedBytes / FatalScreenBpp; + +u32 GetPixelOffset(uint32_t x, uint32_t y) +{ + u32 tmp_pos; + + tmp_pos = ((y & 127) / 16) + (x/32*8) + ((y/16/8)*(((FatalScreenWidthAligned/2)/16*8))); + tmp_pos *= 16*16 * 4; + + tmp_pos += ((y%16)/8)*512 + ((x%32)/16)*256 + ((y%8)/2)*64 + ((x%16)/8)*32 + (y%2)*16 + (x%8)*2;//This line is a modified version of code from the Tegra X1 datasheet. + + return tmp_pos / 2; +} Result ShowFatalTask::SetupDisplayInternal() { Result rc; @@ -107,8 +128,8 @@ Result ShowFatalTask::PrepareScreenForDrawing() { /* Display a layer of 1280 x 720 at 1.5x magnification */ /* NOTE: N uses 2 (770x400) RGBA4444 buffers (tiled buffer + linear). */ /* We use a single 1280x720 tiled RGB565 buffer. */ - constexpr u32 raw_width = 1280; - constexpr u32 raw_height = 720; + constexpr u32 raw_width = FatalScreenWidth; + constexpr u32 raw_height = FatalScreenHeight; constexpr u32 layer_width = ((raw_width) * 3) / 2; constexpr u32 layer_height = ((raw_height) * 3) / 2; @@ -160,13 +181,25 @@ Result ShowFatalTask::ShowFatal() { return FatalResult_NullGfxBuffer; } + /* Let the font manager know about our framebuffer. */ + FontManager::ConfigureFontFramebuffer(tiled_buf, GetPixelOffset); + FontManager::SetFontColor(0xFFFF); + /* Draw a background. */ for (size_t i = 0; i < this->fb.fb_size / sizeof(*tiled_buf); i++) { tiled_buf[i] = 0x39C9; } - /* TODO: Actually draw meaningful shit here. */ + /* Draw the atmosphere logo in the bottom right corner. */ + for (size_t y = 0; y < AMS_LOGO_HEIGHT; y++) { + for (size_t x = 0; x < AMS_LOGO_WIDTH; x++) { + tiled_buf[GetPixelOffset(FatalScreenWidth - AMS_LOGO_WIDTH - 32 + x, FatalScreenHeight - AMS_LOGO_HEIGHT - 32 + y)] = AMS_LOGO_BIN[y * AMS_LOGO_WIDTH + x]; + } + } + /* TODO: Actually draw meaningful shit here. */ + FontManager::DrawFormat(32, 64, u8"A fatal error occurred: 2%03d-%04d\n", R_MODULE(this->ctx->error_code), R_DESCRIPTION(this->ctx->error_code)); + /* Enqueue the buffer. */ framebufferEnd(&fb); From 2838e418196885490b0ef659b70f75ce3e53038f Mon Sep 17 00:00:00 2001 From: Michael Scire Date: Tue, 13 Nov 2018 12:42:35 -0800 Subject: [PATCH 22/33] Add defines for atmosphere git revision. --- exosphere/Makefile | 9 ++++++++- fusee/fusee-primary/Makefile | 9 ++++++++- fusee/fusee-secondary/Makefile | 9 ++++++++- stratosphere/boot/Makefile | 10 +++++++++- stratosphere/creport/Makefile | 9 ++++++++- stratosphere/fatal/Makefile | 9 ++++++++- stratosphere/fs_mitm/Makefile | 9 ++++++++- stratosphere/libstratosphere | 2 +- stratosphere/loader/Makefile | 9 ++++++++- stratosphere/pm/Makefile | 9 ++++++++- stratosphere/set_mitm/Makefile | 9 ++++++++- stratosphere/sm/Makefile | 9 ++++++++- thermosphere/Makefile | 8 ++++++++ 13 files changed, 98 insertions(+), 12 deletions(-) diff --git a/exosphere/Makefile b/exosphere/Makefile index efadefc58..11339bb05 100644 --- a/exosphere/Makefile +++ b/exosphere/Makefile @@ -9,6 +9,13 @@ endif TOPDIR ?= $(CURDIR) include $(DEVKITPRO)/devkitA64/base_rules +AMSBRANCH := $(shell git symbolic-ref --short HEAD) +AMSREV := $(AMSBRANCH)-$(shell git rev-parse --short HEAD) + +ifneq (, $(strip $(shell git status --porcelain 2>/dev/null))) + AMSREV := $(AMSREV)-dirty +endif + #--------------------------------------------------------------------------------- # TARGET is the name of the output # BUILD is the directory where object files & intermediate files will be placed @@ -26,7 +33,7 @@ INCLUDES := include ../common/include # options for code generation #--------------------------------------------------------------------------------- ARCH := -march=armv8-a -mtune=cortex-a57 -mgeneral-regs-only #<- important -DEFINES := -D__CCPLEX__ +DEFINES := -D__CCPLEX__ -DATMOSPHERE_GIT_BRANCH=\"$(AMSBRANCH)\" -DATMOSPHERE_GIT_REV=\"$(AMSREV)\" CFLAGS := \ -g \ -O2 \ diff --git a/fusee/fusee-primary/Makefile b/fusee/fusee-primary/Makefile index 8dce2efff..cf79835f8 100644 --- a/fusee/fusee-primary/Makefile +++ b/fusee/fusee-primary/Makefile @@ -9,6 +9,13 @@ endif TOPDIR ?= $(CURDIR) include $(DEVKITARM)/base_rules +AMSBRANCH := $(shell git symbolic-ref --short HEAD) +AMSREV := $(AMSBRANCH)-$(shell git rev-parse --short HEAD) + +ifneq (, $(strip $(shell git status --porcelain 2>/dev/null))) + AMSREV := $(AMSREV)-dirty +endif + #--------------------------------------------------------------------------------- # TARGET is the name of the output # BUILD is the directory where object files & intermediate files will be placed @@ -26,7 +33,7 @@ INCLUDES := include ../../common/include # options for code generation #--------------------------------------------------------------------------------- ARCH := -march=armv4t -mtune=arm7tdmi -mthumb -mthumb-interwork -DEFINES := -D__BPMP__ -DFUSEE_STAGE1_SRC +DEFINES := -D__BPMP__ -DFUSEE_STAGE1_SRC -DATMOSPHERE_GIT_BRANCH=\"$(AMSBRANCH)\" -DATMOSPHERE_GIT_REV=\"$(AMSREV)\" CFLAGS := \ -g \ diff --git a/fusee/fusee-secondary/Makefile b/fusee/fusee-secondary/Makefile index 9055bbf59..c2c849f4d 100644 --- a/fusee/fusee-secondary/Makefile +++ b/fusee/fusee-secondary/Makefile @@ -12,6 +12,13 @@ AMS := $(TOPDIR)/../../ include $(DEVKITARM)/base_rules +AMSBRANCH := $(shell git symbolic-ref --short HEAD) +AMSREV := $(AMSBRANCH)-$(shell git rev-parse --short HEAD) + +ifneq (, $(strip $(shell git status --porcelain 2>/dev/null))) + AMSREV := $(AMSREV)-dirty +endif + #--------------------------------------------------------------------------------- # TARGET is the name of the output # BUILD is the directory where object files & intermediate files will be placed @@ -29,7 +36,7 @@ INCLUDES := include ../../common/include # options for code generation #--------------------------------------------------------------------------------- ARCH := -march=armv4t -mtune=arm7tdmi -marm -DEFINES := -D__BPMP__ -DFUSEE_STAGE2_SRC +DEFINES := -D__BPMP__ -DFUSEE_STAGE2_SRC -DATMOSPHERE_GIT_BRANCH=\"$(AMSBRANCH)\" -DATMOSPHERE_GIT_REV=\"$(AMSREV)\" CFLAGS := \ -g \ diff --git a/stratosphere/boot/Makefile b/stratosphere/boot/Makefile index 57b69f6e0..7ea2668f3 100644 --- a/stratosphere/boot/Makefile +++ b/stratosphere/boot/Makefile @@ -9,6 +9,14 @@ endif TOPDIR ?= $(CURDIR) include $(DEVKITPRO)/libnx/switch_rules +AMSBRANCH := $(shell git symbolic-ref --short HEAD) +AMSREV := $(AMSBRANCH)-$(shell git rev-parse --short HEAD) + +ifneq (, $(strip $(shell git status --porcelain 2>/dev/null))) + AMSREV := $(AMSREV)-dirty +endif + + #--------------------------------------------------------------------------------- # TARGET is the name of the output # BUILD is the directory where object files & intermediate files will be placed @@ -24,7 +32,7 @@ DATA := data INCLUDES := include ../../common/include EXEFS_SRC := exefs_src -DEFINES := -DDISABLE_IPC +DEFINES := -DDISABLE_IPC -DATMOSPHERE_GIT_BRANCH=\"$(AMSBRANCH)\" -DATMOSPHERE_GIT_REV=\"$(AMSREV)\" #--------------------------------------------------------------------------------- # options for code generation diff --git a/stratosphere/creport/Makefile b/stratosphere/creport/Makefile index c042e968d..71c014dc5 100644 --- a/stratosphere/creport/Makefile +++ b/stratosphere/creport/Makefile @@ -9,6 +9,13 @@ endif TOPDIR ?= $(CURDIR) include $(DEVKITPRO)/libnx/switch_rules +AMSBRANCH := $(shell git symbolic-ref --short HEAD) +AMSREV := $(AMSBRANCH)-$(shell git rev-parse --short HEAD) + +ifneq (, $(strip $(shell git status --porcelain 2>/dev/null))) + AMSREV := $(AMSREV)-dirty +endif + #--------------------------------------------------------------------------------- # TARGET is the name of the output # BUILD is the directory where object files & intermediate files will be placed @@ -24,7 +31,7 @@ DATA := data INCLUDES := include ../../common/include EXEFS_SRC := exefs_src -DEFINES := -DDISABLE_IPC +DEFINES := -DDISABLE_IPC -DATMOSPHERE_GIT_BRANCH=\"$(AMSBRANCH)\" -DATMOSPHERE_GIT_REV=\"$(AMSREV)\" #--------------------------------------------------------------------------------- # options for code generation diff --git a/stratosphere/fatal/Makefile b/stratosphere/fatal/Makefile index 4fba60450..fbbe7ae9c 100644 --- a/stratosphere/fatal/Makefile +++ b/stratosphere/fatal/Makefile @@ -9,6 +9,13 @@ endif TOPDIR ?= $(CURDIR) include $(DEVKITPRO)/libnx/switch_rules +AMSBRANCH := $(shell git symbolic-ref --short HEAD) +AMSREV := $(AMSBRANCH)-$(shell git rev-parse --short HEAD) + +ifneq (, $(strip $(shell git status --porcelain 2>/dev/null))) + AMSREV := $(AMSREV)-dirty +endif + #--------------------------------------------------------------------------------- # TARGET is the name of the output # BUILD is the directory where object files & intermediate files will be placed @@ -24,7 +31,7 @@ DATA := data INCLUDES := include ../../common/include EXEFS_SRC := exefs_src -DEFINES := -DDISABLE_IPC +DEFINES := -DDISABLE_IPC -DATMOSPHERE_GIT_BRANCH=\"$(AMSBRANCH)\" -DATMOSPHERE_GIT_REV=\"$(AMSREV)\" #--------------------------------------------------------------------------------- # options for code generation diff --git a/stratosphere/fs_mitm/Makefile b/stratosphere/fs_mitm/Makefile index e8b1f047a..4ebc8f6d9 100644 --- a/stratosphere/fs_mitm/Makefile +++ b/stratosphere/fs_mitm/Makefile @@ -9,6 +9,13 @@ endif TOPDIR ?= $(CURDIR) include $(DEVKITPRO)/libnx/switch_rules +AMSBRANCH := $(shell git symbolic-ref --short HEAD) +AMSREV := $(AMSBRANCH)-$(shell git rev-parse --short HEAD) + +ifneq (, $(strip $(shell git status --porcelain 2>/dev/null))) + AMSREV := $(AMSREV)-dirty +endif + #--------------------------------------------------------------------------------- # TARGET is the name of the output # BUILD is the directory where object files & intermediate files will be placed @@ -24,7 +31,7 @@ DATA := data INCLUDES := include ../../common/include EXEFS_SRC := exefs_src -DEFINES := -DDISABLE_IPC +DEFINES := -DDISABLE_IPC -DATMOSPHERE_GIT_BRANCH=\"$(AMSBRANCH)\" -DATMOSPHERE_GIT_REV=\"$(AMSREV)\" #--------------------------------------------------------------------------------- # options for code generation diff --git a/stratosphere/libstratosphere b/stratosphere/libstratosphere index bcd80ab44..6a6eedeac 160000 --- a/stratosphere/libstratosphere +++ b/stratosphere/libstratosphere @@ -1 +1 @@ -Subproject commit bcd80ab445258c20d968aad1c083fd8cb0937bee +Subproject commit 6a6eedeacd69a4bddb1e43e31a642a1249a8eb88 diff --git a/stratosphere/loader/Makefile b/stratosphere/loader/Makefile index e8b1f047a..4ebc8f6d9 100644 --- a/stratosphere/loader/Makefile +++ b/stratosphere/loader/Makefile @@ -9,6 +9,13 @@ endif TOPDIR ?= $(CURDIR) include $(DEVKITPRO)/libnx/switch_rules +AMSBRANCH := $(shell git symbolic-ref --short HEAD) +AMSREV := $(AMSBRANCH)-$(shell git rev-parse --short HEAD) + +ifneq (, $(strip $(shell git status --porcelain 2>/dev/null))) + AMSREV := $(AMSREV)-dirty +endif + #--------------------------------------------------------------------------------- # TARGET is the name of the output # BUILD is the directory where object files & intermediate files will be placed @@ -24,7 +31,7 @@ DATA := data INCLUDES := include ../../common/include EXEFS_SRC := exefs_src -DEFINES := -DDISABLE_IPC +DEFINES := -DDISABLE_IPC -DATMOSPHERE_GIT_BRANCH=\"$(AMSBRANCH)\" -DATMOSPHERE_GIT_REV=\"$(AMSREV)\" #--------------------------------------------------------------------------------- # options for code generation diff --git a/stratosphere/pm/Makefile b/stratosphere/pm/Makefile index c3b31a855..766f33dd4 100644 --- a/stratosphere/pm/Makefile +++ b/stratosphere/pm/Makefile @@ -9,6 +9,13 @@ endif TOPDIR ?= $(CURDIR) include $(DEVKITPRO)/libnx/switch_rules +AMSBRANCH := $(shell git symbolic-ref --short HEAD) +AMSREV := $(AMSBRANCH)-$(shell git rev-parse --short HEAD) + +ifneq (, $(strip $(shell git status --porcelain 2>/dev/null))) + AMSREV := $(AMSREV)-dirty +endif + #--------------------------------------------------------------------------------- # TARGET is the name of the output # BUILD is the directory where object files & intermediate files will be placed @@ -24,7 +31,7 @@ DATA := data INCLUDES := include ../../common/include EXEFS_SRC := exefs_src -DEFINES := -DDISABLE_IPC +DEFINES := -DDISABLE_IPC -DATMOSPHERE_GIT_BRANCH=\"$(AMSBRANCH)\" -DATMOSPHERE_GIT_REV=\"$(AMSREV)\" #--------------------------------------------------------------------------------- # options for code generation diff --git a/stratosphere/set_mitm/Makefile b/stratosphere/set_mitm/Makefile index c042e968d..71c014dc5 100644 --- a/stratosphere/set_mitm/Makefile +++ b/stratosphere/set_mitm/Makefile @@ -9,6 +9,13 @@ endif TOPDIR ?= $(CURDIR) include $(DEVKITPRO)/libnx/switch_rules +AMSBRANCH := $(shell git symbolic-ref --short HEAD) +AMSREV := $(AMSBRANCH)-$(shell git rev-parse --short HEAD) + +ifneq (, $(strip $(shell git status --porcelain 2>/dev/null))) + AMSREV := $(AMSREV)-dirty +endif + #--------------------------------------------------------------------------------- # TARGET is the name of the output # BUILD is the directory where object files & intermediate files will be placed @@ -24,7 +31,7 @@ DATA := data INCLUDES := include ../../common/include EXEFS_SRC := exefs_src -DEFINES := -DDISABLE_IPC +DEFINES := -DDISABLE_IPC -DATMOSPHERE_GIT_BRANCH=\"$(AMSBRANCH)\" -DATMOSPHERE_GIT_REV=\"$(AMSREV)\" #--------------------------------------------------------------------------------- # options for code generation diff --git a/stratosphere/sm/Makefile b/stratosphere/sm/Makefile index dae1cae4a..a54a5a0d6 100644 --- a/stratosphere/sm/Makefile +++ b/stratosphere/sm/Makefile @@ -9,6 +9,13 @@ endif TOPDIR ?= $(CURDIR) include $(DEVKITPRO)/libnx/switch_rules +AMSBRANCH := $(shell git symbolic-ref --short HEAD) +AMSREV := $(AMSBRANCH)-$(shell git rev-parse --short HEAD) + +ifneq (, $(strip $(shell git status --porcelain 2>/dev/null))) + AMSREV := $(AMSREV)-dirty +endif + #--------------------------------------------------------------------------------- # TARGET is the name of the output # BUILD is the directory where object files & intermediate files will be placed @@ -24,7 +31,7 @@ DATA := data INCLUDES := include ../../common/include EXEFS_SRC := exefs_src -DEFINES := -DDISABLE_IPC +DEFINES := -DDISABLE_IPC -DATMOSPHERE_GIT_BRANCH=\"$(AMSBRANCH)\" -DATMOSPHERE_GIT_REV=\"$(AMSREV)\" #--------------------------------------------------------------------------------- # options for code generation diff --git a/thermosphere/Makefile b/thermosphere/Makefile index 76f6a100b..7f2634bbe 100644 --- a/thermosphere/Makefile +++ b/thermosphere/Makefile @@ -9,6 +9,13 @@ endif TOPDIR ?= $(CURDIR) include $(DEVKITPRO)/devkitA64/base_rules +AMSBRANCH := $(shell git symbolic-ref --short HEAD) +AMSREV := $(AMSBRANCH)-$(shell git rev-parse --short HEAD) + +ifneq (, $(strip $(shell git status --porcelain 2>/dev/null))) + AMSREV := $(AMSREV)-dirty +endif + #--------------------------------------------------------------------------------- # TARGET is the name of the output # BUILD is the directory where object files & intermediate files will be placed @@ -26,6 +33,7 @@ INCLUDES := include ../common/include # options for code generation #--------------------------------------------------------------------------------- ARCH := -march=armv8-a -mtune=cortex-a57 +DEFINES := -DATMOSPHERE_GIT_BRANCH=\"$(AMSBRANCH)\" -DATMOSPHERE_GIT_REV=\"$(AMSREV)\" CFLAGS := \ -g \ From 560d899a9b57641970c47a08ac7ad9ecdcf84204 Mon Sep 17 00:00:00 2001 From: Michael Scire Date: Tue, 13 Nov 2018 13:11:41 -0800 Subject: [PATCH 23/33] Improve text rendering API, add ams version. --- stratosphere/fatal/source/fatal_font.cpp | 21 ++++++++++++++----- stratosphere/fatal/source/fatal_font.hpp | 5 +++-- .../fatal/source/fatal_task_screen.cpp | 9 +++++++- stratosphere/libstratosphere | 2 +- 4 files changed, 28 insertions(+), 9 deletions(-) diff --git a/stratosphere/fatal/source/fatal_font.cpp b/stratosphere/fatal/source/fatal_font.cpp index b81c65126..e2fd4b3b2 100644 --- a/stratosphere/fatal/source/fatal_font.cpp +++ b/stratosphere/fatal/source/fatal_font.cpp @@ -31,6 +31,7 @@ static u16 *g_fb = nullptr; static u32 (*g_unswizzle_func)(u32, u32) = nullptr; static u16 g_font_color = 0xFFFF; +static u32 g_cur_x = 0, g_cur_y = 0; static PlFontData g_font; static PlFontData g_fonts[PlSharedFontType_Total]; @@ -68,13 +69,18 @@ static void DrawGlyph(FT_Bitmap *bitmap, u32 x, u32 y) { } } -void FontManager::DrawString(u32 x, u32 y, const char *str) { +void FontManager::PrintLine(const char *str) { FT_UInt glyph_index; FT_GlyphSlot slot = g_face->glyph; const size_t len = strlen(str); - u32 cur_x = x, cur_y = y; + u32 cur_x = g_cur_x, cur_y = g_cur_y; + ON_SCOPE_EXIT { + /* Advance to next line. */ + /* g_cur_x = g_cur_x; */ + g_cur_y = cur_y + (g_face->size->metrics.height >> 6); + }; for (u32 i = 0; i < len; ) { u32 cur_char; @@ -83,7 +89,7 @@ void FontManager::DrawString(u32 x, u32 y, const char *str) { i += unit_count; if (cur_char == '\n') { - cur_x = x; + cur_x = g_cur_x; cur_y += g_face->size->metrics.height >> 6; continue; } @@ -107,20 +113,25 @@ void FontManager::DrawString(u32 x, u32 y, const char *str) { } } -void FontManager::DrawFormat(u32 x, u32 y, const char *format, ...) { +void FontManager::PrintFormatLine(const char *format, ...) { va_list va_arg; va_start(va_arg, format); char char_buf[0x400]; vsnprintf(char_buf, sizeof(char_buf), format, va_arg); - DrawString(x, y, char_buf); + PrintLine(char_buf); } void FontManager::SetFontColor(u16 color) { g_font_color = color; } +void FontManager::SetPosition(u32 x, u32 y) { + g_cur_x = x; + g_cur_y = y; +} + void FontManager::ConfigureFontFramebuffer(u16 *fb, u32 (*unswizzle_func)(u32, u32)) { g_fb = fb; g_unswizzle_func = unswizzle_func; diff --git a/stratosphere/fatal/source/fatal_font.hpp b/stratosphere/fatal/source/fatal_font.hpp index ab553a28a..c72921065 100644 --- a/stratosphere/fatal/source/fatal_font.hpp +++ b/stratosphere/fatal/source/fatal_font.hpp @@ -30,6 +30,7 @@ class FontManager { static void ConfigureFontFramebuffer(u16 *fb, u32 (*unswizzle_func)(u32, u32)); static void SetFontColor(u16 color); - static void DrawString(u32 x, u32 y, const char *str); - static void DrawFormat(u32 x, u32 y, const char *format, ...); + static void SetPosition(u32 x, u32 y); + static void PrintLine(const char *str); + static void PrintFormatLine(const char *format, ...); }; \ No newline at end of file diff --git a/stratosphere/fatal/source/fatal_task_screen.cpp b/stratosphere/fatal/source/fatal_task_screen.cpp index b651c7ef9..81d4b143b 100644 --- a/stratosphere/fatal/source/fatal_task_screen.cpp +++ b/stratosphere/fatal/source/fatal_task_screen.cpp @@ -15,6 +15,9 @@ */ #include + +#include + #include "fatal_task_screen.hpp" #include "fatal_config.hpp" #include "fatal_font.hpp" @@ -198,7 +201,11 @@ Result ShowFatalTask::ShowFatal() { } /* TODO: Actually draw meaningful shit here. */ - FontManager::DrawFormat(32, 64, u8"A fatal error occurred: 2%03d-%04d\n", R_MODULE(this->ctx->error_code), R_DESCRIPTION(this->ctx->error_code)); + FontManager::SetPosition(32, 64); + FontManager::PrintFormatLine(u8"A fatal error occurred: 2%03d-%04d", R_MODULE(this->ctx->error_code), R_DESCRIPTION(this->ctx->error_code)); + FontManager::PrintFormatLine(u8"Firmware: %s (AMS %u.%u.%u-%s)", GetFatalConfig()->firmware_version.display_version, + CURRENT_ATMOSPHERE_VERSION, GetAtmosphereGitRevision()); + /* Enqueue the buffer. */ framebufferEnd(&fb); diff --git a/stratosphere/libstratosphere b/stratosphere/libstratosphere index 6a6eedeac..0fb33e9c0 160000 --- a/stratosphere/libstratosphere +++ b/stratosphere/libstratosphere @@ -1 +1 @@ -Subproject commit 6a6eedeacd69a4bddb1e43e31a642a1249a8eb88 +Subproject commit 0fb33e9c094bffde737c7a73cd5ccce4d7cbae33 From 1bface09d5412a368f0907503cd9f8126e7977ff Mon Sep 17 00:00:00 2001 From: Michael Scire Date: Tue, 13 Nov 2018 13:28:05 -0800 Subject: [PATCH 24/33] fatal: add line spacing func, improve 565->888 for blending --- stratosphere/fatal/source/fatal_font.cpp | 4 ++++ stratosphere/fatal/source/fatal_font.hpp | 7 ++++--- stratosphere/fatal/source/fatal_task_screen.cpp | 3 ++- 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/stratosphere/fatal/source/fatal_font.cpp b/stratosphere/fatal/source/fatal_font.cpp index e2fd4b3b2..a832f3238 100644 --- a/stratosphere/fatal/source/fatal_font.cpp +++ b/stratosphere/fatal/source/fatal_font.cpp @@ -132,6 +132,10 @@ void FontManager::SetPosition(u32 x, u32 y) { g_cur_y = y; } +void FontManager::AddSpacingLines(float num_lines) { + g_cur_y += static_cast((static_cast(g_face->size->metrics.height) * num_lines) / 64.0f); +} + void FontManager::ConfigureFontFramebuffer(u16 *fb, u32 (*unswizzle_func)(u32, u32)) { g_fb = fb; g_unswizzle_func = unswizzle_func; diff --git a/stratosphere/fatal/source/fatal_font.hpp b/stratosphere/fatal/source/fatal_font.hpp index c72921065..a7622dc56 100644 --- a/stratosphere/fatal/source/fatal_font.hpp +++ b/stratosphere/fatal/source/fatal_font.hpp @@ -20,9 +20,9 @@ #include #define RGB888_TO_RGB565(r, g, b) ((((r >> 3) << 11) & 0xF800) | (((g >> 2) << 5) & 0x7E0) | ((b >> 3) & 0x1F)) -#define RGB565_GET_R8(c) (((c >> 11) & 0x1F) << 3) -#define RGB565_GET_G8(c) (((c >> 5) & 0x3F) << 2) -#define RGB565_GET_B8(c) (((c >> 0) & 0x1F) << 3) +#define RGB565_GET_R8(c) ((((c >> 11) & 0x1F) << 3) | ((c >> 13) & 7)) +#define RGB565_GET_G8(c) ((((c >> 5) & 0x3F) << 2) | ((c >> 9) & 3)) +#define RGB565_GET_B8(c) ((((c >> 0) & 0x1F) << 3) | ((c >> 2) & 7)) class FontManager { public: @@ -31,6 +31,7 @@ class FontManager { static void SetFontColor(u16 color); static void SetPosition(u32 x, u32 y); + static void AddSpacingLines(float num_lines); static void PrintLine(const char *str); static void PrintFormatLine(const char *format, ...); }; \ No newline at end of file diff --git a/stratosphere/fatal/source/fatal_task_screen.cpp b/stratosphere/fatal/source/fatal_task_screen.cpp index 81d4b143b..1872a7222 100644 --- a/stratosphere/fatal/source/fatal_task_screen.cpp +++ b/stratosphere/fatal/source/fatal_task_screen.cpp @@ -203,7 +203,8 @@ Result ShowFatalTask::ShowFatal() { /* TODO: Actually draw meaningful shit here. */ FontManager::SetPosition(32, 64); FontManager::PrintFormatLine(u8"A fatal error occurred: 2%03d-%04d", R_MODULE(this->ctx->error_code), R_DESCRIPTION(this->ctx->error_code)); - FontManager::PrintFormatLine(u8"Firmware: %s (AMS %u.%u.%u-%s)", GetFatalConfig()->firmware_version.display_version, + FontManager::AddSpacingLines(0.5f); + FontManager::PrintFormatLine(u8"Firmware: %s (Atmosphère %u.%u.%u-%s)", GetFatalConfig()->firmware_version.display_version, CURRENT_ATMOSPHERE_VERSION, GetAtmosphereGitRevision()); From f16423c41355c7a6c7bb8c200b7866bb8fdff82f Mon Sep 17 00:00:00 2001 From: Michael Scire Date: Tue, 13 Nov 2018 14:32:50 -0800 Subject: [PATCH 25/33] fatal: Add font scaling support --- stratosphere/fatal/source/fatal_font.cpp | 8 +++++++- stratosphere/fatal/source/fatal_font.hpp | 1 + stratosphere/fatal/source/fatal_task_screen.cpp | 2 +- 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/stratosphere/fatal/source/fatal_font.cpp b/stratosphere/fatal/source/fatal_font.cpp index a832f3238..31b45833a 100644 --- a/stratosphere/fatal/source/fatal_font.cpp +++ b/stratosphere/fatal/source/fatal_font.cpp @@ -31,6 +31,7 @@ static u16 *g_fb = nullptr; static u32 (*g_unswizzle_func)(u32, u32) = nullptr; static u16 g_font_color = 0xFFFF; +static float g_font_sz = 16.0f; static u32 g_cur_x = 0, g_cur_y = 0; static PlFontData g_font; @@ -132,6 +133,11 @@ void FontManager::SetPosition(u32 x, u32 y) { g_cur_y = y; } +void FontManager::SetFontSize(float fsz) { + g_font_sz = fsz; + g_ft_err = FT_Set_Char_Size(g_face, 0, static_cast(g_font_sz * 64.0f), 96, 96); +} + void FontManager::AddSpacingLines(float num_lines) { g_cur_y += static_cast((static_cast(g_face->size->metrics.height) * num_lines) / 64.0f); } @@ -159,6 +165,6 @@ Result FontManager::InitializeSharedFont() { g_ft_err = FT_New_Memory_Face(g_library, reinterpret_cast(g_font.address), g_font.size, 0, &g_face); if (g_ft_err) return g_ft_err; - g_ft_err = FT_Set_Char_Size(g_face, 0, 8*64, 300, 300); + g_ft_err = FT_Set_Char_Size(g_face, 0, static_cast(g_font_sz * 64.0f), 96, 96); return g_ft_err; } \ No newline at end of file diff --git a/stratosphere/fatal/source/fatal_font.hpp b/stratosphere/fatal/source/fatal_font.hpp index a7622dc56..c0cb35456 100644 --- a/stratosphere/fatal/source/fatal_font.hpp +++ b/stratosphere/fatal/source/fatal_font.hpp @@ -31,6 +31,7 @@ class FontManager { static void SetFontColor(u16 color); static void SetPosition(u32 x, u32 y); + static void SetFontSize(float fsz); static void AddSpacingLines(float num_lines); static void PrintLine(const char *str); static void PrintFormatLine(const char *format, ...); diff --git a/stratosphere/fatal/source/fatal_task_screen.cpp b/stratosphere/fatal/source/fatal_task_screen.cpp index 1872a7222..1fffada4d 100644 --- a/stratosphere/fatal/source/fatal_task_screen.cpp +++ b/stratosphere/fatal/source/fatal_task_screen.cpp @@ -207,7 +207,7 @@ Result ShowFatalTask::ShowFatal() { FontManager::PrintFormatLine(u8"Firmware: %s (Atmosphère %u.%u.%u-%s)", GetFatalConfig()->firmware_version.display_version, CURRENT_ATMOSPHERE_VERSION, GetAtmosphereGitRevision()); - + /* Enqueue the buffer. */ framebufferEnd(&fb); From 20026587fd2835972b81e75a06c98bce45c5835c Mon Sep 17 00:00:00 2001 From: Michael Scire Date: Tue, 13 Nov 2018 17:53:26 -0800 Subject: [PATCH 26/33] fatal: Draw GPRs + Backtrace to screen. --- stratosphere/fatal/source/fatal_config.cpp | 24 ++++ stratosphere/fatal/source/fatal_config.hpp | 3 + stratosphere/fatal/source/fatal_font.cpp | 46 ++++++- stratosphere/fatal/source/fatal_font.hpp | 4 + .../fatal/source/fatal_task_screen.cpp | 124 +++++++++++++++++- stratosphere/fatal/source/fatal_types.hpp | 66 +++++++++- 6 files changed, 253 insertions(+), 14 deletions(-) diff --git a/stratosphere/fatal/source/fatal_config.cpp b/stratosphere/fatal/source/fatal_config.cpp index 5583e7a0b..f2adae661 100644 --- a/stratosphere/fatal/source/fatal_config.cpp +++ b/stratosphere/fatal/source/fatal_config.cpp @@ -48,6 +48,28 @@ IEvent *GetFatalSettingsEvent() { return g_fatal_settings_event; } +static void SetupConfigLanguages() { + FatalConfig *config = GetFatalConfig(); + + /* Defaults. */ + config->error_msg = u8"Error Code: 2%03d-%04d (0x%x)\n"; + + if (config->quest_flag) { + config->error_desc = u8"Please call 1-800-875-1852 for service.\n"; + } else { + config->error_desc = u8"An error has occured.\n\n" + u8"Please press the POWER Button to restart the console. If you are\n" + u8"unable to restart the console, hold the POWER Button for 12 seconds\n" + u8"to turn the console off.\n\n" + u8"If the problem persists, refer to the Nintendo Support Website.\n" + u8"nintendo.com/switch/error\n"; + } + + /* TODO: Try to load dynamically. */ + /* FsStorage message_storage; */ + /* TODO: if (R_SUCCEEDED(fsOpenDataStorageByDataId(0x010000000000081D, "fatal_msg"))) { ... } */ +} + void InitializeFatalConfig() { FatalConfig *config = GetFatalConfig(); @@ -61,4 +83,6 @@ void InitializeFatalConfig() { setsysGetSettingsItemValue("fatal", "quest_reboot_interval_second", &config->quest_reboot_interval_second, sizeof(config->quest_reboot_interval_second)); setsysGetFlag(SetSysFlag_Quest, &config->quest_flag); + + SetupConfigLanguages(); } diff --git a/stratosphere/fatal/source/fatal_config.hpp b/stratosphere/fatal/source/fatal_config.hpp index 105534bfc..5656feda0 100644 --- a/stratosphere/fatal/source/fatal_config.hpp +++ b/stratosphere/fatal/source/fatal_config.hpp @@ -26,6 +26,9 @@ struct FatalConfig { bool transition_to_fatal; bool show_extra_info; bool quest_flag; + const char *error_msg; + const char *error_desc; + const char *quest_desc; }; IEvent *GetFatalSettingsEvent(); diff --git a/stratosphere/fatal/source/fatal_font.cpp b/stratosphere/fatal/source/fatal_font.cpp index 31b45833a..92712f39d 100644 --- a/stratosphere/fatal/source/fatal_font.cpp +++ b/stratosphere/fatal/source/fatal_font.cpp @@ -32,7 +32,7 @@ static u16 *g_fb = nullptr; static u32 (*g_unswizzle_func)(u32, u32) = nullptr; static u16 g_font_color = 0xFFFF; static float g_font_sz = 16.0f; -static u32 g_cur_x = 0, g_cur_y = 0; +static u32 g_line_x = 0, g_cur_x = 0, g_cur_y = 0; static PlFontData g_font; static PlFontData g_fonts[PlSharedFontType_Total]; @@ -70,7 +70,7 @@ static void DrawGlyph(FT_Bitmap *bitmap, u32 x, u32 y) { } } -void FontManager::PrintLine(const char *str) { +static void DrawString(const char *str, bool add_line) { FT_UInt glyph_index; FT_GlyphSlot slot = g_face->glyph; @@ -78,9 +78,14 @@ void FontManager::PrintLine(const char *str) { u32 cur_x = g_cur_x, cur_y = g_cur_y; ON_SCOPE_EXIT { - /* Advance to next line. */ - /* g_cur_x = g_cur_x; */ - g_cur_y = cur_y + (g_face->size->metrics.height >> 6); + if (add_line) { + /* Advance to next line. */ + g_cur_x = g_line_x; + g_cur_y = cur_y + (g_face->size->metrics.height >> 6); + } else { + g_cur_x = cur_x; + g_cur_y = cur_y; + } }; for (u32 i = 0; i < len; ) { @@ -90,7 +95,7 @@ void FontManager::PrintLine(const char *str) { i += unit_count; if (cur_char == '\n') { - cur_x = g_cur_x; + cur_x = g_line_x; cur_y += g_face->size->metrics.height >> 6; continue; } @@ -114,6 +119,10 @@ void FontManager::PrintLine(const char *str) { } } +void FontManager::PrintLine(const char *str) { + return DrawString(str, true); +} + void FontManager::PrintFormatLine(const char *format, ...) { va_list va_arg; va_start(va_arg, format); @@ -124,21 +133,46 @@ void FontManager::PrintFormatLine(const char *format, ...) { PrintLine(char_buf); } +void FontManager::Print(const char *str) { + return DrawString(str, false); +} + +void FontManager::PrintFormat(const char *format, ...) { + va_list va_arg; + va_start(va_arg, format); + + char char_buf[0x400]; + vsnprintf(char_buf, sizeof(char_buf), format, va_arg); + + Print(char_buf); +} + + void FontManager::SetFontColor(u16 color) { g_font_color = color; } void FontManager::SetPosition(u32 x, u32 y) { + g_line_x = x; g_cur_x = x; g_cur_y = y; } +u32 FontManager::GetX() { + return g_cur_x; +} + +u32 FontManager::GetY() { + return g_cur_y; +} + void FontManager::SetFontSize(float fsz) { g_font_sz = fsz; g_ft_err = FT_Set_Char_Size(g_face, 0, static_cast(g_font_sz * 64.0f), 96, 96); } void FontManager::AddSpacingLines(float num_lines) { + g_cur_x = g_line_x; g_cur_y += static_cast((static_cast(g_face->size->metrics.height) * num_lines) / 64.0f); } diff --git a/stratosphere/fatal/source/fatal_font.hpp b/stratosphere/fatal/source/fatal_font.hpp index c0cb35456..e98d4e4cd 100644 --- a/stratosphere/fatal/source/fatal_font.hpp +++ b/stratosphere/fatal/source/fatal_font.hpp @@ -31,8 +31,12 @@ class FontManager { static void SetFontColor(u16 color); static void SetPosition(u32 x, u32 y); + static u32 GetX(); + static u32 GetY(); static void SetFontSize(float fsz); static void AddSpacingLines(float num_lines); static void PrintLine(const char *str); static void PrintFormatLine(const char *format, ...); + static void Print(const char *str); + static void PrintFormat(const char *format, ...); }; \ No newline at end of file diff --git a/stratosphere/fatal/source/fatal_task_screen.cpp b/stratosphere/fatal/source/fatal_task_screen.cpp index 1fffada4d..90132aa1a 100644 --- a/stratosphere/fatal/source/fatal_task_screen.cpp +++ b/stratosphere/fatal/source/fatal_task_screen.cpp @@ -172,6 +172,7 @@ Result ShowFatalTask::PrepareScreenForDrawing() { Result ShowFatalTask::ShowFatal() { Result rc = 0; + const FatalConfig *config = GetFatalConfig(); if (R_FAILED((rc = PrepareScreenForDrawing()))) { *(volatile u32 *)(0xCAFEBABE) = rc; @@ -196,17 +197,132 @@ Result ShowFatalTask::ShowFatal() { /* Draw the atmosphere logo in the bottom right corner. */ for (size_t y = 0; y < AMS_LOGO_HEIGHT; y++) { for (size_t x = 0; x < AMS_LOGO_WIDTH; x++) { - tiled_buf[GetPixelOffset(FatalScreenWidth - AMS_LOGO_WIDTH - 32 + x, FatalScreenHeight - AMS_LOGO_HEIGHT - 32 + y)] = AMS_LOGO_BIN[y * AMS_LOGO_WIDTH + x]; + tiled_buf[GetPixelOffset(FatalScreenWidth - AMS_LOGO_WIDTH - 32 + x, 32 + y)] = AMS_LOGO_BIN[y * AMS_LOGO_WIDTH + x]; } } /* TODO: Actually draw meaningful shit here. */ FontManager::SetPosition(32, 64); - FontManager::PrintFormatLine(u8"A fatal error occurred: 2%03d-%04d", R_MODULE(this->ctx->error_code), R_DESCRIPTION(this->ctx->error_code)); + FontManager::SetFontSize(16.0f); + FontManager::PrintFormatLine("Title: %016lx", this->title_id); FontManager::AddSpacingLines(0.5f); - FontManager::PrintFormatLine(u8"Firmware: %s (Atmosphère %u.%u.%u-%s)", GetFatalConfig()->firmware_version.display_version, - CURRENT_ATMOSPHERE_VERSION, GetAtmosphereGitRevision()); + FontManager::PrintFormatLine(config->error_msg, R_MODULE(this->ctx->error_code), R_DESCRIPTION(this->ctx->error_code), this->ctx->error_code); + FontManager::PrintLine(config->error_desc); + FontManager::AddSpacingLines(0.5f); + FontManager::PrintFormatLine(u8"Firmware: %s (Atmosphère %u.%u.%u-%s)", GetFatalConfig()->firmware_version.display_version, CURRENT_ATMOSPHERE_VERSION, GetAtmosphereGitRevision()); + /* Add a line. */ + for (size_t x = 32; x < FatalScreenWidth - 32; x++) { + tiled_buf[GetPixelOffset(x, FontManager::GetY())] = 0xFFFF; + } + + + FontManager::AddSpacingLines(1.5f); + + u32 backtrace_y = FontManager::GetY(); + u32 backtrace_x = 0; + + /* Print GPRs. */ + FontManager::SetFontSize(14.0f); + FontManager::PrintLine("General Purpose Registers"); + FontManager::AddSpacingLines(0.5f); + if (this->ctx->cpu_ctx.is_aarch32) { + for (size_t i = 0; i < (NumAarch32Gprs / 2); i++) { + u32 x = FontManager::GetX(); + FontManager::PrintFormat("%s:", Aarch32GprNames[i]); + FontManager::SetPosition(x + 47, FontManager::GetY()); + FontManager::PrintFormat("0x%08x ", this->ctx->cpu_ctx.aarch32_ctx.r[i]); + x = FontManager::GetX(); + FontManager::PrintFormat("%s:", Aarch32GprNames[i + (NumAarch32Gprs / 2)]); + FontManager::SetPosition(x + 47, FontManager::GetY()); + FontManager::PrintFormat("0x%08x ", this->ctx->cpu_ctx.aarch32_ctx.r[i]); + + + FontManager::PrintLine(""); + FontManager::SetPosition(32, FontManager::GetY()); + } + } else { + for (size_t i = 0; i < NumAarch64Gprs / 2; i++) { + u32 x = FontManager::GetX(); + FontManager::PrintFormat("%s:", Aarch64GprNames[i]); + FontManager::SetPosition(x + 47, FontManager::GetY()); + FontManager::PrintFormat("0x%016lx ", this->ctx->cpu_ctx.aarch64_ctx.x[i]); + x = FontManager::GetX(); + FontManager::PrintFormat("%s:", Aarch64GprNames[i + (NumAarch64Gprs / 2)]); + FontManager::SetPosition(x + 47, FontManager::GetY()); + FontManager::PrintFormat("0x%016lx ", this->ctx->cpu_ctx.aarch64_ctx.x[i]); + + if (i == (NumAarch64Gprs / 2) - 1) { + FontManager::Print(" "); + backtrace_x = FontManager::GetX(); + } + + FontManager::PrintLine(""); + FontManager::SetPosition(32, FontManager::GetY()); + } + } + + /* Print Backtrace. */ + FontManager::SetPosition(backtrace_x, backtrace_y); + if (this->ctx->cpu_ctx.is_aarch32) { + FontManager::PrintFormatLine("Backtrace (Start Address = 0x%08x)", this->ctx->cpu_ctx.aarch32_ctx.start_address); + FontManager::AddSpacingLines(0.5f); + for (u32 i = 0; i < Aarch32CpuContext::MaxStackTraceDepth / 2; i++) { + u32 bt_cur = 0, bt_next = 0; + if (i < this->ctx->cpu_ctx.aarch32_ctx.stack_trace_size) { + bt_cur = this->ctx->cpu_ctx.aarch32_ctx.stack_trace[i]; + } + if (i + Aarch32CpuContext::MaxStackTraceDepth / 2 < this->ctx->cpu_ctx.aarch32_ctx.stack_trace_size) { + bt_next = this->ctx->cpu_ctx.aarch32_ctx.stack_trace[i + Aarch32CpuContext::MaxStackTraceDepth / 2]; + } + + if (i < this->ctx->cpu_ctx.aarch32_ctx.stack_trace_size) { + u32 x = FontManager::GetX(); + FontManager::PrintFormat("BT[%02X]: ", i); + FontManager::SetPosition(x + 76, FontManager::GetY()); + FontManager::PrintFormat("0x%08x ", bt_cur); + } + + if (i + Aarch32CpuContext::MaxStackTraceDepth / 2 < this->ctx->cpu_ctx.aarch32_ctx.stack_trace_size) { + u32 x = FontManager::GetX(); + FontManager::PrintFormat("BT[%02X]: ", i + Aarch32CpuContext::MaxStackTraceDepth / 2); + FontManager::SetPosition(x + 76, FontManager::GetY()); + FontManager::PrintFormat("0x%08x ", bt_next); + } + + FontManager::PrintLine(""); + FontManager::SetPosition(backtrace_x, FontManager::GetY()); + } + } else { + FontManager::PrintFormatLine("Backtrace (Start Address = 0x%016lx)", this->ctx->cpu_ctx.aarch64_ctx.start_address); + FontManager::AddSpacingLines(0.5f); + for (u32 i = 0; i < Aarch64CpuContext::MaxStackTraceDepth / 2; i++) { + u64 bt_cur = 0, bt_next = 0; + if (i < this->ctx->cpu_ctx.aarch64_ctx.stack_trace_size) { + bt_cur = this->ctx->cpu_ctx.aarch64_ctx.stack_trace[i]; + } + if (i + Aarch64CpuContext::MaxStackTraceDepth / 2 < this->ctx->cpu_ctx.aarch64_ctx.stack_trace_size) { + bt_next = this->ctx->cpu_ctx.aarch64_ctx.stack_trace[i + Aarch64CpuContext::MaxStackTraceDepth / 2]; + } + + if (i < this->ctx->cpu_ctx.aarch64_ctx.stack_trace_size) { + u32 x = FontManager::GetX(); + FontManager::PrintFormat("BT[%02X]: ", i); + FontManager::SetPosition(x + 76, FontManager::GetY()); + FontManager::PrintFormat("0x%016lx ", bt_cur); + } + + if (i + Aarch64CpuContext::MaxStackTraceDepth / 2 < this->ctx->cpu_ctx.aarch64_ctx.stack_trace_size) { + u32 x = FontManager::GetX(); + FontManager::PrintFormat("BT[%02X]: ", i + Aarch64CpuContext::MaxStackTraceDepth / 2); + FontManager::SetPosition(x + 76, FontManager::GetY()); + FontManager::PrintFormat("0x%016lx ", bt_next); + } + + FontManager::PrintLine(""); + FontManager::SetPosition(backtrace_x, FontManager::GetY()); + } + } /* Enqueue the buffer. */ framebufferEnd(&fb); diff --git a/stratosphere/fatal/source/fatal_types.hpp b/stratosphere/fatal/source/fatal_types.hpp index 83abe9d0e..06c435364 100644 --- a/stratosphere/fatal/source/fatal_types.hpp +++ b/stratosphere/fatal/source/fatal_types.hpp @@ -26,13 +26,16 @@ enum FatalResult : Result { FatalResult_InRepairWithoutTimeReviserCartridge = 0xCA3, }; +static constexpr size_t NumAarch64Gprs = 32; +static constexpr size_t NumAarch32Gprs = 16; + struct Aarch64CpuContext { using RegisterType = u64; static constexpr size_t MaxStackTraceDepth = 0x20; /* Registers, exception context. N left names for these fields in fatal .rodata. */ union { - RegisterType x[31]; + RegisterType x[NumAarch64Gprs]; struct { RegisterType _x[29]; RegisterType fp; @@ -60,9 +63,9 @@ struct Aarch32CpuContext { /* Registers, exception context. N left names for these fields in fatal .rodata. */ union { - RegisterType r[16]; + RegisterType r[NumAarch32Gprs]; struct { - RegisterType _x[11]; + RegisterType _r[11]; RegisterType fp; RegisterType ip; RegisterType sp; @@ -86,7 +89,7 @@ struct Aarch32CpuContext { struct FatalCpuContext { union { Aarch64CpuContext aarch64_ctx; - Aarch64CpuContext aarch32_ctx; + Aarch32CpuContext aarch32_ctx; }; bool is_aarch32; @@ -102,3 +105,58 @@ static_assert(sizeof(Aarch64CpuContext) == 0x248, "Aarch64CpuContext definition! static_assert(sizeof(Aarch32CpuContext) == 0xE0, "Aarch32CpuContext definition!"); static_assert(sizeof(FatalCpuContext) == 0x250, "FatalCpuContext definition!"); static_assert(std::is_pod_v, "FatalCpuContext definition!"); + +static constexpr const char *Aarch64GprNames[NumAarch64Gprs] = { + u8"X0", + u8"X1", + u8"X2", + u8"X3", + u8"X4", + u8"X5", + u8"X6", + u8"X7", + u8"X8", + u8"X9", + u8"X10", + u8"X11", + u8"X12", + u8"X13", + u8"X14", + u8"X15", + u8"X16", + u8"X17", + u8"X18", + u8"X19", + u8"X20", + u8"X22", + u8"X23", + u8"X24", + u8"X25", + u8"X26", + u8"X27", + u8"X28", + u8"FP", + u8"LR", + u8"SP", + u8"PC", +}; + +static constexpr const char *Aarch32GprNames[NumAarch32Gprs] = { + u8"R0", + u8"R1", + u8"R2", + u8"R3", + u8"R4", + u8"R5", + u8"R6", + u8"R7", + u8"R8", + u8"R9", + u8"R10", + u8"FP", + u8"IP", + u8"LR", + u8"SP", + u8"PC", +}; + From fa9d7f40fc09dfae14f6c06fe3bff4152bee57e2 Mon Sep 17 00:00:00 2001 From: Michael Scire Date: Tue, 13 Nov 2018 18:07:27 -0800 Subject: [PATCH 27/33] fatal: Reorder error message lines. --- stratosphere/fatal/source/fatal_task_screen.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/stratosphere/fatal/source/fatal_task_screen.cpp b/stratosphere/fatal/source/fatal_task_screen.cpp index 90132aa1a..4b79cd4ef 100644 --- a/stratosphere/fatal/source/fatal_task_screen.cpp +++ b/stratosphere/fatal/source/fatal_task_screen.cpp @@ -204,12 +204,13 @@ Result ShowFatalTask::ShowFatal() { /* TODO: Actually draw meaningful shit here. */ FontManager::SetPosition(32, 64); FontManager::SetFontSize(16.0f); + FontManager::PrintFormat(config->error_msg, R_MODULE(this->ctx->error_code), R_DESCRIPTION(this->ctx->error_code), this->ctx->error_code); + FontManager::AddSpacingLines(0.5f); FontManager::PrintFormatLine("Title: %016lx", this->title_id); FontManager::AddSpacingLines(0.5f); - FontManager::PrintFormatLine(config->error_msg, R_MODULE(this->ctx->error_code), R_DESCRIPTION(this->ctx->error_code), this->ctx->error_code); - FontManager::PrintLine(config->error_desc); - FontManager::AddSpacingLines(0.5f); FontManager::PrintFormatLine(u8"Firmware: %s (Atmosphère %u.%u.%u-%s)", GetFatalConfig()->firmware_version.display_version, CURRENT_ATMOSPHERE_VERSION, GetAtmosphereGitRevision()); + FontManager::AddSpacingLines(1.5f); + FontManager::Print(config->error_desc); /* Add a line. */ for (size_t x = 32; x < FatalScreenWidth - 32; x++) { From d4ee772714dfe1374c31460a0443aabc36dce218 Mon Sep 17 00:00:00 2001 From: Michael Scire Date: Tue, 13 Nov 2018 18:11:08 -0800 Subject: [PATCH 28/33] fatal: Display start instead of bt if size = 0 --- .../fatal/source/fatal_task_screen.cpp | 126 ++++++++++-------- 1 file changed, 71 insertions(+), 55 deletions(-) diff --git a/stratosphere/fatal/source/fatal_task_screen.cpp b/stratosphere/fatal/source/fatal_task_screen.cpp index 4b79cd4ef..4acd3fdc6 100644 --- a/stratosphere/fatal/source/fatal_task_screen.cpp +++ b/stratosphere/fatal/source/fatal_task_screen.cpp @@ -264,66 +264,82 @@ Result ShowFatalTask::ShowFatal() { } /* Print Backtrace. */ - FontManager::SetPosition(backtrace_x, backtrace_y); + u32 bt_size; if (this->ctx->cpu_ctx.is_aarch32) { - FontManager::PrintFormatLine("Backtrace (Start Address = 0x%08x)", this->ctx->cpu_ctx.aarch32_ctx.start_address); - FontManager::AddSpacingLines(0.5f); - for (u32 i = 0; i < Aarch32CpuContext::MaxStackTraceDepth / 2; i++) { - u32 bt_cur = 0, bt_next = 0; - if (i < this->ctx->cpu_ctx.aarch32_ctx.stack_trace_size) { - bt_cur = this->ctx->cpu_ctx.aarch32_ctx.stack_trace[i]; - } - if (i + Aarch32CpuContext::MaxStackTraceDepth / 2 < this->ctx->cpu_ctx.aarch32_ctx.stack_trace_size) { - bt_next = this->ctx->cpu_ctx.aarch32_ctx.stack_trace[i + Aarch32CpuContext::MaxStackTraceDepth / 2]; - } - - if (i < this->ctx->cpu_ctx.aarch32_ctx.stack_trace_size) { - u32 x = FontManager::GetX(); - FontManager::PrintFormat("BT[%02X]: ", i); - FontManager::SetPosition(x + 76, FontManager::GetY()); - FontManager::PrintFormat("0x%08x ", bt_cur); - } - - if (i + Aarch32CpuContext::MaxStackTraceDepth / 2 < this->ctx->cpu_ctx.aarch32_ctx.stack_trace_size) { - u32 x = FontManager::GetX(); - FontManager::PrintFormat("BT[%02X]: ", i + Aarch32CpuContext::MaxStackTraceDepth / 2); - FontManager::SetPosition(x + 76, FontManager::GetY()); - FontManager::PrintFormat("0x%08x ", bt_next); - } - - FontManager::PrintLine(""); - FontManager::SetPosition(backtrace_x, FontManager::GetY()); + bt_size = this->ctx->cpu_ctx.aarch32_ctx.stack_trace_size; + } else { + bt_size = this->ctx->cpu_ctx.aarch64_ctx.stack_trace_size; + } + + if (bt_size == 0) { + if (this->ctx->cpu_ctx.is_aarch32) { + FontManager::PrintFormatLine("Start Address: 0x%08x", this->ctx->cpu_ctx.aarch32_ctx.start_address); + } else { + FontManager::PrintFormatLine("Start Address: 0x%016lx", this->ctx->cpu_ctx.aarch64_ctx.start_address); } - } else { - FontManager::PrintFormatLine("Backtrace (Start Address = 0x%016lx)", this->ctx->cpu_ctx.aarch64_ctx.start_address); - FontManager::AddSpacingLines(0.5f); - for (u32 i = 0; i < Aarch64CpuContext::MaxStackTraceDepth / 2; i++) { - u64 bt_cur = 0, bt_next = 0; - if (i < this->ctx->cpu_ctx.aarch64_ctx.stack_trace_size) { - bt_cur = this->ctx->cpu_ctx.aarch64_ctx.stack_trace[i]; + } else { + FontManager::SetPosition(backtrace_x, backtrace_y); + if (this->ctx->cpu_ctx.is_aarch32) { + FontManager::PrintFormatLine("Backtrace (Start Address = 0x%08x)", this->ctx->cpu_ctx.aarch32_ctx.start_address); + FontManager::AddSpacingLines(0.5f); + for (u32 i = 0; i < Aarch32CpuContext::MaxStackTraceDepth / 2; i++) { + u32 bt_cur = 0, bt_next = 0; + if (i < this->ctx->cpu_ctx.aarch32_ctx.stack_trace_size) { + bt_cur = this->ctx->cpu_ctx.aarch32_ctx.stack_trace[i]; + } + if (i + Aarch32CpuContext::MaxStackTraceDepth / 2 < this->ctx->cpu_ctx.aarch32_ctx.stack_trace_size) { + bt_next = this->ctx->cpu_ctx.aarch32_ctx.stack_trace[i + Aarch32CpuContext::MaxStackTraceDepth / 2]; + } + + if (i < this->ctx->cpu_ctx.aarch32_ctx.stack_trace_size) { + u32 x = FontManager::GetX(); + FontManager::PrintFormat("BT[%02X]: ", i); + FontManager::SetPosition(x + 76, FontManager::GetY()); + FontManager::PrintFormat("0x%08x ", bt_cur); + } + + if (i + Aarch32CpuContext::MaxStackTraceDepth / 2 < this->ctx->cpu_ctx.aarch32_ctx.stack_trace_size) { + u32 x = FontManager::GetX(); + FontManager::PrintFormat("BT[%02X]: ", i + Aarch32CpuContext::MaxStackTraceDepth / 2); + FontManager::SetPosition(x + 76, FontManager::GetY()); + FontManager::PrintFormat("0x%08x ", bt_next); + } + + FontManager::PrintLine(""); + FontManager::SetPosition(backtrace_x, FontManager::GetY()); } - if (i + Aarch64CpuContext::MaxStackTraceDepth / 2 < this->ctx->cpu_ctx.aarch64_ctx.stack_trace_size) { - bt_next = this->ctx->cpu_ctx.aarch64_ctx.stack_trace[i + Aarch64CpuContext::MaxStackTraceDepth / 2]; + } else { + FontManager::PrintFormatLine("Backtrace (Start Address = 0x%016lx)", this->ctx->cpu_ctx.aarch64_ctx.start_address); + FontManager::AddSpacingLines(0.5f); + for (u32 i = 0; i < Aarch64CpuContext::MaxStackTraceDepth / 2; i++) { + u64 bt_cur = 0, bt_next = 0; + if (i < this->ctx->cpu_ctx.aarch64_ctx.stack_trace_size) { + bt_cur = this->ctx->cpu_ctx.aarch64_ctx.stack_trace[i]; + } + if (i + Aarch64CpuContext::MaxStackTraceDepth / 2 < this->ctx->cpu_ctx.aarch64_ctx.stack_trace_size) { + bt_next = this->ctx->cpu_ctx.aarch64_ctx.stack_trace[i + Aarch64CpuContext::MaxStackTraceDepth / 2]; + } + + if (i < this->ctx->cpu_ctx.aarch64_ctx.stack_trace_size) { + u32 x = FontManager::GetX(); + FontManager::PrintFormat("BT[%02X]: ", i); + FontManager::SetPosition(x + 76, FontManager::GetY()); + FontManager::PrintFormat("0x%016lx ", bt_cur); + } + + if (i + Aarch64CpuContext::MaxStackTraceDepth / 2 < this->ctx->cpu_ctx.aarch64_ctx.stack_trace_size) { + u32 x = FontManager::GetX(); + FontManager::PrintFormat("BT[%02X]: ", i + Aarch64CpuContext::MaxStackTraceDepth / 2); + FontManager::SetPosition(x + 76, FontManager::GetY()); + FontManager::PrintFormat("0x%016lx ", bt_next); + } + + FontManager::PrintLine(""); + FontManager::SetPosition(backtrace_x, FontManager::GetY()); } - - if (i < this->ctx->cpu_ctx.aarch64_ctx.stack_trace_size) { - u32 x = FontManager::GetX(); - FontManager::PrintFormat("BT[%02X]: ", i); - FontManager::SetPosition(x + 76, FontManager::GetY()); - FontManager::PrintFormat("0x%016lx ", bt_cur); - } - - if (i + Aarch64CpuContext::MaxStackTraceDepth / 2 < this->ctx->cpu_ctx.aarch64_ctx.stack_trace_size) { - u32 x = FontManager::GetX(); - FontManager::PrintFormat("BT[%02X]: ", i + Aarch64CpuContext::MaxStackTraceDepth / 2); - FontManager::SetPosition(x + 76, FontManager::GetY()); - FontManager::PrintFormat("0x%016lx ", bt_next); - } - - FontManager::PrintLine(""); - FontManager::SetPosition(backtrace_x, FontManager::GetY()); } - } + } + /* Enqueue the buffer. */ framebufferEnd(&fb); From 98bdb2a7a394d2a88f29d62b5f9a70d42c2670a6 Mon Sep 17 00:00:00 2001 From: Michael Scire Date: Tue, 13 Nov 2018 19:30:40 -0800 Subject: [PATCH 29/33] fatal: Add fake monospace for hex output --- stratosphere/fatal/source/fatal_config.cpp | 2 +- stratosphere/fatal/source/fatal_font.cpp | 33 +++++++++-- stratosphere/fatal/source/fatal_font.hpp | 2 + .../fatal/source/fatal_task_screen.cpp | 58 +++++++++++-------- 4 files changed, 67 insertions(+), 28 deletions(-) diff --git a/stratosphere/fatal/source/fatal_config.cpp b/stratosphere/fatal/source/fatal_config.cpp index f2adae661..fd1703137 100644 --- a/stratosphere/fatal/source/fatal_config.cpp +++ b/stratosphere/fatal/source/fatal_config.cpp @@ -62,7 +62,7 @@ static void SetupConfigLanguages() { u8"unable to restart the console, hold the POWER Button for 12 seconds\n" u8"to turn the console off.\n\n" u8"If the problem persists, refer to the Nintendo Support Website.\n" - u8"nintendo.com/switch/error\n"; + u8"support.nintendo.com/switch/error\n"; } /* TODO: Try to load dynamically. */ diff --git a/stratosphere/fatal/source/fatal_font.cpp b/stratosphere/fatal/source/fatal_font.cpp index 92712f39d..b86cf4edf 100644 --- a/stratosphere/fatal/source/fatal_font.cpp +++ b/stratosphere/fatal/source/fatal_font.cpp @@ -34,6 +34,8 @@ static u16 g_font_color = 0xFFFF; static float g_font_sz = 16.0f; static u32 g_line_x = 0, g_cur_x = 0, g_cur_y = 0; +static u32 g_mono_adv = 0; + static PlFontData g_font; static PlFontData g_fonts[PlSharedFontType_Total]; static FT_Library g_library; @@ -70,7 +72,7 @@ static void DrawGlyph(FT_Bitmap *bitmap, u32 x, u32 y) { } } -static void DrawString(const char *str, bool add_line) { +static void DrawString(const char *str, bool add_line, bool mono = false) { FT_UInt glyph_index; FT_GlyphSlot slot = g_face->glyph; @@ -112,9 +114,9 @@ static void DrawString(const char *str, bool add_line) { return; } - DrawGlyph(&slot->bitmap, cur_x + slot->bitmap_left, cur_y - slot->bitmap_top); + DrawGlyph(&slot->bitmap, cur_x + slot->bitmap_left + ((mono && g_mono_adv > slot->advance.x) ? ((g_mono_adv - slot->advance.x) >> 7) : 0), cur_y - slot->bitmap_top); - cur_x += slot->advance.x >> 6; + cur_x += (mono ? g_mono_adv : slot->advance.x) >> 6; cur_y += slot->advance.y >> 6; } } @@ -147,6 +149,20 @@ void FontManager::PrintFormat(const char *format, ...) { Print(char_buf); } +void FontManager::PrintMonospaceU64(u64 x) { + char char_buf[0x400]; + snprintf(char_buf, sizeof(char_buf), "%016lX", x); + + DrawString(char_buf, false, true); +} + +void FontManager::PrintMonospaceU32(u32 x) { + char char_buf[0x400]; + snprintf(char_buf, sizeof(char_buf), "%08X", x); + + DrawString(char_buf, false, true); +} + void FontManager::SetFontColor(u16 color) { g_font_color = color; @@ -169,6 +185,15 @@ u32 FontManager::GetY() { void FontManager::SetFontSize(float fsz) { g_font_sz = fsz; g_ft_err = FT_Set_Char_Size(g_face, 0, static_cast(g_font_sz * 64.0f), 96, 96); + + g_ft_err = FT_Load_Glyph(g_face, FT_Get_Char_Index(g_face, 'A'), FT_LOAD_DEFAULT); + + if (g_ft_err == 0) { + g_ft_err = FT_Render_Glyph(g_face->glyph, FT_RENDER_MODE_NORMAL); + } + if (g_ft_err == 0) { + g_mono_adv = g_face->glyph->advance.x; + } } void FontManager::AddSpacingLines(float num_lines) { @@ -199,6 +224,6 @@ Result FontManager::InitializeSharedFont() { g_ft_err = FT_New_Memory_Face(g_library, reinterpret_cast(g_font.address), g_font.size, 0, &g_face); if (g_ft_err) return g_ft_err; - g_ft_err = FT_Set_Char_Size(g_face, 0, static_cast(g_font_sz * 64.0f), 96, 96); + SetFontSize(g_font_sz); return g_ft_err; } \ No newline at end of file diff --git a/stratosphere/fatal/source/fatal_font.hpp b/stratosphere/fatal/source/fatal_font.hpp index e98d4e4cd..5bd79dc14 100644 --- a/stratosphere/fatal/source/fatal_font.hpp +++ b/stratosphere/fatal/source/fatal_font.hpp @@ -39,4 +39,6 @@ class FontManager { static void PrintFormatLine(const char *format, ...); static void Print(const char *str); static void PrintFormat(const char *format, ...); + static void PrintMonospaceU64(u64 x); + static void PrintMonospaceU32(u32 x); }; \ No newline at end of file diff --git a/stratosphere/fatal/source/fatal_task_screen.cpp b/stratosphere/fatal/source/fatal_task_screen.cpp index 4acd3fdc6..e4b25d1ba 100644 --- a/stratosphere/fatal/source/fatal_task_screen.cpp +++ b/stratosphere/fatal/source/fatal_task_screen.cpp @@ -206,7 +206,7 @@ Result ShowFatalTask::ShowFatal() { FontManager::SetFontSize(16.0f); FontManager::PrintFormat(config->error_msg, R_MODULE(this->ctx->error_code), R_DESCRIPTION(this->ctx->error_code), this->ctx->error_code); FontManager::AddSpacingLines(0.5f); - FontManager::PrintFormatLine("Title: %016lx", this->title_id); + FontManager::PrintFormatLine("Title: %016lX", this->title_id); FontManager::AddSpacingLines(0.5f); FontManager::PrintFormatLine(u8"Firmware: %s (Atmosphère %u.%u.%u-%s)", GetFatalConfig()->firmware_version.display_version, CURRENT_ATMOSPHERE_VERSION, GetAtmosphereGitRevision()); FontManager::AddSpacingLines(1.5f); @@ -232,12 +232,19 @@ Result ShowFatalTask::ShowFatal() { u32 x = FontManager::GetX(); FontManager::PrintFormat("%s:", Aarch32GprNames[i]); FontManager::SetPosition(x + 47, FontManager::GetY()); - FontManager::PrintFormat("0x%08x ", this->ctx->cpu_ctx.aarch32_ctx.r[i]); + FontManager::Print("0x"); + FontManager::PrintMonospaceU32(this->ctx->cpu_ctx.aarch32_ctx.r[i]); + FontManager::Print(" "); x = FontManager::GetX(); FontManager::PrintFormat("%s:", Aarch32GprNames[i + (NumAarch32Gprs / 2)]); FontManager::SetPosition(x + 47, FontManager::GetY()); - FontManager::PrintFormat("0x%08x ", this->ctx->cpu_ctx.aarch32_ctx.r[i]); + FontManager::Print("0x"); + FontManager::PrintMonospaceU32(this->ctx->cpu_ctx.aarch32_ctx.r[i + (NumAarch32Gprs / 2)]); + if (i == (NumAarch32Gprs / 2) - 1) { + FontManager::Print(" "); + backtrace_x = FontManager::GetX(); + } FontManager::PrintLine(""); FontManager::SetPosition(32, FontManager::GetY()); @@ -247,11 +254,12 @@ Result ShowFatalTask::ShowFatal() { u32 x = FontManager::GetX(); FontManager::PrintFormat("%s:", Aarch64GprNames[i]); FontManager::SetPosition(x + 47, FontManager::GetY()); - FontManager::PrintFormat("0x%016lx ", this->ctx->cpu_ctx.aarch64_ctx.x[i]); + FontManager::PrintMonospaceU64(this->ctx->cpu_ctx.aarch64_ctx.x[i]); + FontManager::Print(" "); x = FontManager::GetX(); FontManager::PrintFormat("%s:", Aarch64GprNames[i + (NumAarch64Gprs / 2)]); FontManager::SetPosition(x + 47, FontManager::GetY()); - FontManager::PrintFormat("0x%016lx ", this->ctx->cpu_ctx.aarch64_ctx.x[i]); + FontManager::PrintMonospaceU64(this->ctx->cpu_ctx.aarch64_ctx.x[i + (NumAarch64Gprs / 2)]); if (i == (NumAarch64Gprs / 2) - 1) { FontManager::Print(" "); @@ -271,16 +279,17 @@ Result ShowFatalTask::ShowFatal() { bt_size = this->ctx->cpu_ctx.aarch64_ctx.stack_trace_size; } + + FontManager::SetPosition(backtrace_x, backtrace_y); if (bt_size == 0) { if (this->ctx->cpu_ctx.is_aarch32) { - FontManager::PrintFormatLine("Start Address: 0x%08x", this->ctx->cpu_ctx.aarch32_ctx.start_address); + FontManager::PrintFormatLine("Start Address: 0x%08X", this->ctx->cpu_ctx.aarch32_ctx.start_address); } else { - FontManager::PrintFormatLine("Start Address: 0x%016lx", this->ctx->cpu_ctx.aarch64_ctx.start_address); + FontManager::PrintFormatLine("Start Address: 0x%016lX", this->ctx->cpu_ctx.aarch64_ctx.start_address); } } else { - FontManager::SetPosition(backtrace_x, backtrace_y); if (this->ctx->cpu_ctx.is_aarch32) { - FontManager::PrintFormatLine("Backtrace (Start Address = 0x%08x)", this->ctx->cpu_ctx.aarch32_ctx.start_address); + FontManager::PrintFormatLine("Backtrace - Start Address: 0x%08X", this->ctx->cpu_ctx.aarch32_ctx.start_address); FontManager::AddSpacingLines(0.5f); for (u32 i = 0; i < Aarch32CpuContext::MaxStackTraceDepth / 2; i++) { u32 bt_cur = 0, bt_next = 0; @@ -293,23 +302,25 @@ Result ShowFatalTask::ShowFatal() { if (i < this->ctx->cpu_ctx.aarch32_ctx.stack_trace_size) { u32 x = FontManager::GetX(); - FontManager::PrintFormat("BT[%02X]: ", i); - FontManager::SetPosition(x + 76, FontManager::GetY()); - FontManager::PrintFormat("0x%08x ", bt_cur); + FontManager::PrintFormat("BT[%02d]: ", i); + FontManager::SetPosition(x + 72, FontManager::GetY()); + FontManager::PrintMonospaceU32(bt_cur); + FontManager::Print(" "); } if (i + Aarch32CpuContext::MaxStackTraceDepth / 2 < this->ctx->cpu_ctx.aarch32_ctx.stack_trace_size) { u32 x = FontManager::GetX(); - FontManager::PrintFormat("BT[%02X]: ", i + Aarch32CpuContext::MaxStackTraceDepth / 2); - FontManager::SetPosition(x + 76, FontManager::GetY()); - FontManager::PrintFormat("0x%08x ", bt_next); + FontManager::PrintFormat("BT[%02d]: ", i + Aarch32CpuContext::MaxStackTraceDepth / 2); + FontManager::SetPosition(x + 72, FontManager::GetY()); + FontManager::PrintMonospaceU32(bt_next); } FontManager::PrintLine(""); FontManager::SetPosition(backtrace_x, FontManager::GetY()); } - } else { - FontManager::PrintFormatLine("Backtrace (Start Address = 0x%016lx)", this->ctx->cpu_ctx.aarch64_ctx.start_address); + } else { + + FontManager::PrintFormatLine("Backtrace - Start Address: 0x%016lX", this->ctx->cpu_ctx.aarch64_ctx.start_address); FontManager::AddSpacingLines(0.5f); for (u32 i = 0; i < Aarch64CpuContext::MaxStackTraceDepth / 2; i++) { u64 bt_cur = 0, bt_next = 0; @@ -322,16 +333,17 @@ Result ShowFatalTask::ShowFatal() { if (i < this->ctx->cpu_ctx.aarch64_ctx.stack_trace_size) { u32 x = FontManager::GetX(); - FontManager::PrintFormat("BT[%02X]: ", i); - FontManager::SetPosition(x + 76, FontManager::GetY()); - FontManager::PrintFormat("0x%016lx ", bt_cur); + FontManager::PrintFormat("BT[%02d]: ", i); + FontManager::SetPosition(x + 72, FontManager::GetY()); + FontManager::PrintMonospaceU64(bt_cur); + FontManager::Print(" "); } if (i + Aarch64CpuContext::MaxStackTraceDepth / 2 < this->ctx->cpu_ctx.aarch64_ctx.stack_trace_size) { u32 x = FontManager::GetX(); - FontManager::PrintFormat("BT[%02X]: ", i + Aarch64CpuContext::MaxStackTraceDepth / 2); - FontManager::SetPosition(x + 76, FontManager::GetY()); - FontManager::PrintFormat("0x%016lx ", bt_next); + FontManager::PrintFormat("BT[%02d]: ", i + Aarch64CpuContext::MaxStackTraceDepth / 2); + FontManager::SetPosition(x + 72, FontManager::GetY()); + FontManager::PrintMonospaceU64(bt_next); } FontManager::PrintLine(""); From 50c65ea7e137a31321b772e1c4c6cc659a8f7125 Mon Sep 17 00:00:00 2001 From: Michael Scire Date: Tue, 13 Nov 2018 19:33:21 -0800 Subject: [PATCH 30/33] fatal: monospace start address --- .../fatal/source/fatal_task_screen.cpp | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/stratosphere/fatal/source/fatal_task_screen.cpp b/stratosphere/fatal/source/fatal_task_screen.cpp index e4b25d1ba..c20b14d7a 100644 --- a/stratosphere/fatal/source/fatal_task_screen.cpp +++ b/stratosphere/fatal/source/fatal_task_screen.cpp @@ -283,13 +283,19 @@ Result ShowFatalTask::ShowFatal() { FontManager::SetPosition(backtrace_x, backtrace_y); if (bt_size == 0) { if (this->ctx->cpu_ctx.is_aarch32) { - FontManager::PrintFormatLine("Start Address: 0x%08X", this->ctx->cpu_ctx.aarch32_ctx.start_address); + FontManager::Print("Start Address: "); + FontManager::PrintMonospaceU32(this->ctx->cpu_ctx.aarch32_ctx.start_address); + FontManager::PrintLine(""); } else { - FontManager::PrintFormatLine("Start Address: 0x%016lX", this->ctx->cpu_ctx.aarch64_ctx.start_address); + FontManager::Print("Start Address: "); + FontManager::PrintMonospaceU64(this->ctx->cpu_ctx.aarch64_ctx.start_address); + FontManager::PrintLine(""); } } else { if (this->ctx->cpu_ctx.is_aarch32) { - FontManager::PrintFormatLine("Backtrace - Start Address: 0x%08X", this->ctx->cpu_ctx.aarch32_ctx.start_address); + FontManager::PrintFormatLine("Backtrace - Start Address: "); + FontManager::PrintMonospaceU32(this->ctx->cpu_ctx.aarch32_ctx.start_address); + FontManager::PrintLine(""); FontManager::AddSpacingLines(0.5f); for (u32 i = 0; i < Aarch32CpuContext::MaxStackTraceDepth / 2; i++) { u32 bt_cur = 0, bt_next = 0; @@ -319,9 +325,9 @@ Result ShowFatalTask::ShowFatal() { FontManager::SetPosition(backtrace_x, FontManager::GetY()); } } else { - - FontManager::PrintFormatLine("Backtrace - Start Address: 0x%016lX", this->ctx->cpu_ctx.aarch64_ctx.start_address); - FontManager::AddSpacingLines(0.5f); + FontManager::PrintFormatLine("Backtrace - Start Address: "); + FontManager::PrintMonospaceU64(this->ctx->cpu_ctx.aarch64_ctx.start_address); + FontManager::PrintLine(""); for (u32 i = 0; i < Aarch64CpuContext::MaxStackTraceDepth / 2; i++) { u64 bt_cur = 0, bt_next = 0; if (i < this->ctx->cpu_ctx.aarch64_ctx.stack_trace_size) { From 9714db14d2a296b9e37dd258a0b87d25d19b2f0e Mon Sep 17 00:00:00 2001 From: Michael Scire Date: Tue, 13 Nov 2018 20:22:54 -0800 Subject: [PATCH 31/33] fatal/creport: Add cpu context. --- .../creport/source/creport_code_info.hpp | 2 +- .../creport/source/creport_crash_report.cpp | 29 +++++++++++++++++++ .../creport/source/creport_crash_report.hpp | 1 + stratosphere/creport/source/creport_main.cpp | 4 ++- .../creport/source/creport_thread_info.hpp | 2 +- stratosphere/fatal/source/fatal_task.cpp | 2 +- stratosphere/fatal/source/fatal_task.hpp | 6 ++-- .../fatal/source/fatal_task_clock.hpp | 2 +- .../fatal/source/fatal_task_error_report.hpp | 2 +- .../fatal/source/fatal_task_power.hpp | 6 ++-- .../fatal/source/fatal_task_screen.cpp | 5 ++-- .../fatal/source/fatal_task_screen.hpp | 4 +-- .../fatal/source/fatal_task_sound.hpp | 2 +- stratosphere/fatal/source/fatal_throw.cpp | 10 +++++-- stratosphere/fatal/source/fatal_types.hpp | 3 +- 15 files changed, 60 insertions(+), 20 deletions(-) diff --git a/stratosphere/creport/source/creport_code_info.hpp b/stratosphere/creport/source/creport_code_info.hpp index ff1c1fb1c..6f1baca95 100644 --- a/stratosphere/creport/source/creport_code_info.hpp +++ b/stratosphere/creport/source/creport_code_info.hpp @@ -28,7 +28,7 @@ struct CodeInfo { }; class CodeList { - private: + public: static const size_t max_code_count = 0x10; u32 code_count = 0; CodeInfo code_infos[max_code_count]; diff --git a/stratosphere/creport/source/creport_crash_report.cpp b/stratosphere/creport/source/creport_crash_report.cpp index cd9d1f9bb..6f2a2e62f 100644 --- a/stratosphere/creport/source/creport_crash_report.cpp +++ b/stratosphere/creport/source/creport_crash_report.cpp @@ -42,6 +42,35 @@ void CrashReport::BuildReport(u64 pid, bool has_extra_info) { } } +FatalContext *CrashReport::GetFatalContext() { + FatalContext *ctx = new FatalContext; + *ctx = (FatalContext){0}; + + ctx->is_aarch32 = false; + ctx->type = static_cast(this->exception_info.type); + + for (size_t i = 0; i < 29; i++) { + ctx->aarch64_ctx.x[i] = this->crashed_thread_info.context.cpu_gprs[i].x; + } + ctx->aarch64_ctx.fp = this->crashed_thread_info.context.fp; + ctx->aarch64_ctx.lr = this->crashed_thread_info.context.lr; + ctx->aarch64_ctx.pc = this->crashed_thread_info.context.pc.x; + + ctx->aarch64_ctx.stack_trace_size = this->crashed_thread_info.stack_trace_size; + for (size_t i = 0; i < ctx->aarch64_ctx.stack_trace_size; i++) { + ctx->aarch64_ctx.stack_trace[i] = this->crashed_thread_info.stack_trace[i]; + } + + if (this->code_list.code_count) { + ctx->aarch64_ctx.start_address = this->code_list.code_infos[0].start_address; + } + + /* For ams fatal... */ + ctx->aarch64_ctx.afsr0 = this->process_info.title_id; + + return ctx; +} + void CrashReport::ProcessExceptions() { if (!IsOpen()) { return; diff --git a/stratosphere/creport/source/creport_crash_report.hpp b/stratosphere/creport/source/creport_crash_report.hpp index 049610c87..38aa28568 100644 --- a/stratosphere/creport/source/creport_crash_report.hpp +++ b/stratosphere/creport/source/creport_crash_report.hpp @@ -61,6 +61,7 @@ class CrashReport { public: void BuildReport(u64 pid, bool has_extra_info); + FatalContext *GetFatalContext(); void SaveReport(); bool IsAddressReadable(u64 address, u64 size, MemoryInfo *mi = NULL); diff --git a/stratosphere/creport/source/creport_main.cpp b/stratosphere/creport/source/creport_main.cpp index 77fd7b400..d106268e8 100644 --- a/stratosphere/creport/source/creport_main.cpp +++ b/stratosphere/creport/source/creport_main.cpp @@ -132,7 +132,9 @@ int main(int argc, char **argv) { return 0; } - fatalWithType(g_Creport.GetResult(), FatalType_ErrorScreen); + FatalContext *ctx = g_Creport.GetFatalContext(); + + fatalWithContext(g_Creport.GetResult(), FatalType_ErrorScreen, ctx); } } \ No newline at end of file diff --git a/stratosphere/creport/source/creport_thread_info.hpp b/stratosphere/creport/source/creport_thread_info.hpp index 0b3d3f07f..2995342cf 100644 --- a/stratosphere/creport/source/creport_thread_info.hpp +++ b/stratosphere/creport/source/creport_thread_info.hpp @@ -22,7 +22,7 @@ #include "creport_code_info.hpp" class ThreadInfo { - private: + public: ThreadContext context{}; u64 thread_id = 0; u64 stack_top = 0; diff --git a/stratosphere/fatal/source/fatal_task.cpp b/stratosphere/fatal/source/fatal_task.cpp index 62b39cdbb..6cf13428f 100644 --- a/stratosphere/fatal/source/fatal_task.cpp +++ b/stratosphere/fatal/source/fatal_task.cpp @@ -53,7 +53,7 @@ static void RunTask(IFatalTask *task, u32 stack_size = 0x4000) { cur_thread->Start(); } -void RunFatalTasks(FatalContext *ctx, u64 title_id, bool error_report, Event *erpt_event, Event *battery_event) { +void RunFatalTasks(FatalThrowContext *ctx, u64 title_id, bool error_report, Event *erpt_event, Event *battery_event) { RunTask(new ErrorReportTask(ctx, title_id, error_report, erpt_event)); RunTask(new PowerControlTask(ctx, title_id, erpt_event, battery_event)); RunTask(new ShowFatalTask(ctx, title_id, battery_event), 0x10000); diff --git a/stratosphere/fatal/source/fatal_task.hpp b/stratosphere/fatal/source/fatal_task.hpp index ef19fbbc1..6926f96f2 100644 --- a/stratosphere/fatal/source/fatal_task.hpp +++ b/stratosphere/fatal/source/fatal_task.hpp @@ -21,12 +21,12 @@ class IFatalTask { protected: - FatalContext *ctx; + FatalThrowContext *ctx; u64 title_id; public: - IFatalTask(FatalContext *ctx, u64 tid) : ctx(ctx), title_id(tid) { } + IFatalTask(FatalThrowContext *ctx, u64 tid) : ctx(ctx), title_id(tid) { } virtual Result Run() = 0; virtual const char *GetName() const = 0; }; -void RunFatalTasks(FatalContext *ctx, u64 title_id, bool error_report, Event *erpt_event, Event *battery_event); +void RunFatalTasks(FatalThrowContext *ctx, u64 title_id, bool error_report, Event *erpt_event, Event *battery_event); diff --git a/stratosphere/fatal/source/fatal_task_clock.hpp b/stratosphere/fatal/source/fatal_task_clock.hpp index 8ceba6945..65aa609d3 100644 --- a/stratosphere/fatal/source/fatal_task_clock.hpp +++ b/stratosphere/fatal/source/fatal_task_clock.hpp @@ -23,7 +23,7 @@ class AdjustClockTask : public IFatalTask { private: Result AdjustClock(); public: - AdjustClockTask(FatalContext *ctx, u64 title_id) : IFatalTask(ctx, title_id) { } + AdjustClockTask(FatalThrowContext *ctx, u64 title_id) : IFatalTask(ctx, title_id) { } virtual Result Run() override; virtual const char *GetName() const override { return "AdjustClockTask"; diff --git a/stratosphere/fatal/source/fatal_task_error_report.hpp b/stratosphere/fatal/source/fatal_task_error_report.hpp index 7ade00bcf..71b220f4d 100644 --- a/stratosphere/fatal/source/fatal_task_error_report.hpp +++ b/stratosphere/fatal/source/fatal_task_error_report.hpp @@ -24,7 +24,7 @@ class ErrorReportTask : public IFatalTask { bool create_report; Event *erpt_event; public: - ErrorReportTask(FatalContext *ctx, u64 title_id, bool error_report, Event *evt) : IFatalTask(ctx, title_id), create_report(error_report), erpt_event(evt) { } + ErrorReportTask(FatalThrowContext *ctx, u64 title_id, bool error_report, Event *evt) : IFatalTask(ctx, title_id), create_report(error_report), erpt_event(evt) { } virtual Result Run() override; virtual const char *GetName() const override { return "WriteErrorReport"; diff --git a/stratosphere/fatal/source/fatal_task_power.hpp b/stratosphere/fatal/source/fatal_task_power.hpp index d31e78752..a4aedc155 100644 --- a/stratosphere/fatal/source/fatal_task_power.hpp +++ b/stratosphere/fatal/source/fatal_task_power.hpp @@ -27,7 +27,7 @@ class PowerControlTask : public IFatalTask { bool TryShutdown(); void MonitorBatteryState(); public: - PowerControlTask(FatalContext *ctx, u64 title_id, Event *er_evt, Event *bt_evt) : IFatalTask(ctx, title_id), erpt_event(er_evt), battery_event(bt_evt) { } + PowerControlTask(FatalThrowContext *ctx, u64 title_id, Event *er_evt, Event *bt_evt) : IFatalTask(ctx, title_id), erpt_event(er_evt), battery_event(bt_evt) { } virtual Result Run() override; virtual const char *GetName() const override { return "PowerControlTask"; @@ -40,7 +40,7 @@ class PowerButtonObserveTask : public IFatalTask { private: void WaitForPowerButton(); public: - PowerButtonObserveTask(FatalContext *ctx, u64 title_id, Event *er_evt) : IFatalTask(ctx, title_id), erpt_event(er_evt) { } + PowerButtonObserveTask(FatalThrowContext *ctx, u64 title_id, Event *er_evt) : IFatalTask(ctx, title_id), erpt_event(er_evt) { } virtual Result Run() override; virtual const char *GetName() const override { return "PowerButtonObserveTask"; @@ -49,7 +49,7 @@ class PowerButtonObserveTask : public IFatalTask { class StateTransitionStopTask : public IFatalTask { public: - StateTransitionStopTask(FatalContext *ctx, u64 title_id) : IFatalTask(ctx, title_id) { } + StateTransitionStopTask(FatalThrowContext *ctx, u64 title_id) : IFatalTask(ctx, title_id) { } virtual Result Run() override; virtual const char *GetName() const override { return "StateTransitionStopTask"; diff --git a/stratosphere/fatal/source/fatal_task_screen.cpp b/stratosphere/fatal/source/fatal_task_screen.cpp index c20b14d7a..94fa1bacb 100644 --- a/stratosphere/fatal/source/fatal_task_screen.cpp +++ b/stratosphere/fatal/source/fatal_task_screen.cpp @@ -293,7 +293,7 @@ Result ShowFatalTask::ShowFatal() { } } else { if (this->ctx->cpu_ctx.is_aarch32) { - FontManager::PrintFormatLine("Backtrace - Start Address: "); + FontManager::Print("Backtrace - Start Address: "); FontManager::PrintMonospaceU32(this->ctx->cpu_ctx.aarch32_ctx.start_address); FontManager::PrintLine(""); FontManager::AddSpacingLines(0.5f); @@ -325,9 +325,10 @@ Result ShowFatalTask::ShowFatal() { FontManager::SetPosition(backtrace_x, FontManager::GetY()); } } else { - FontManager::PrintFormatLine("Backtrace - Start Address: "); + FontManager::Print("Backtrace - Start Address: "); FontManager::PrintMonospaceU64(this->ctx->cpu_ctx.aarch64_ctx.start_address); FontManager::PrintLine(""); + FontManager::AddSpacingLines(0.5f); for (u32 i = 0; i < Aarch64CpuContext::MaxStackTraceDepth / 2; i++) { u64 bt_cur = 0, bt_next = 0; if (i < this->ctx->cpu_ctx.aarch64_ctx.stack_trace_size) { diff --git a/stratosphere/fatal/source/fatal_task_screen.hpp b/stratosphere/fatal/source/fatal_task_screen.hpp index bfaed2cea..9a2f7188c 100644 --- a/stratosphere/fatal/source/fatal_task_screen.hpp +++ b/stratosphere/fatal/source/fatal_task_screen.hpp @@ -32,7 +32,7 @@ class ShowFatalTask : public IFatalTask { Result PrepareScreenForDrawing(); Result ShowFatal(); public: - ShowFatalTask(FatalContext *ctx, u64 title_id, Event *evt) : IFatalTask(ctx, title_id), battery_event(evt) { } + ShowFatalTask(FatalThrowContext *ctx, u64 title_id, Event *evt) : IFatalTask(ctx, title_id), battery_event(evt) { } virtual Result Run() override; virtual const char *GetName() const override { return "ShowFatal"; @@ -43,7 +43,7 @@ class BacklightControlTask : public IFatalTask { private: void TurnOnBacklight(); public: - BacklightControlTask(FatalContext *ctx, u64 title_id) : IFatalTask(ctx, title_id) { } + BacklightControlTask(FatalThrowContext *ctx, u64 title_id) : IFatalTask(ctx, title_id) { } virtual Result Run() override; virtual const char *GetName() const override { return "BacklightControlTask"; diff --git a/stratosphere/fatal/source/fatal_task_sound.hpp b/stratosphere/fatal/source/fatal_task_sound.hpp index a6feea049..67954088b 100644 --- a/stratosphere/fatal/source/fatal_task_sound.hpp +++ b/stratosphere/fatal/source/fatal_task_sound.hpp @@ -23,7 +23,7 @@ class StopSoundTask : public IFatalTask { private: void StopSound(); public: - StopSoundTask(FatalContext *ctx, u64 title_id) : IFatalTask(ctx, title_id) { } + StopSoundTask(FatalThrowContext *ctx, u64 title_id) : IFatalTask(ctx, title_id) { } virtual Result Run() override; virtual const char *GetName() const override { return "SoundTask"; diff --git a/stratosphere/fatal/source/fatal_throw.cpp b/stratosphere/fatal/source/fatal_throw.cpp index 2eb617593..dbd6eba3b 100644 --- a/stratosphere/fatal/source/fatal_throw.cpp +++ b/stratosphere/fatal/source/fatal_throw.cpp @@ -42,7 +42,7 @@ Result ThrowFatalForSelf(u32 error) { Result ThrowFatalImpl(u32 error, u64 pid, FatalType policy, FatalCpuContext *cpu_ctx) { Result rc = 0; - FatalContext ctx; + FatalThrowContext ctx; ctx.error_code = error; ctx.cpu_ctx = *cpu_ctx; @@ -51,7 +51,13 @@ Result ThrowFatalImpl(u32 error, u64 pid, FatalType policy, FatalCpuContext *cpu /* Get title id. On failure, it'll be zero. */ u64 title_id = 0; - pminfoGetTitleId(&title_id, pid); + pminfoGetTitleId(&title_id, pid); + ctx.is_creport = title_id == 0x0100000000000036; + + /* Support for ams creport. TODO: Make this its own command? */ + if (ctx.is_creport && !cpu_ctx->is_aarch32 && cpu_ctx->aarch64_ctx.afsr0 != 0) { + title_id = cpu_ctx->aarch64_ctx.afsr0; + } switch (policy) { case FatalType_ErrorReport: diff --git a/stratosphere/fatal/source/fatal_types.hpp b/stratosphere/fatal/source/fatal_types.hpp index 06c435364..99be9c524 100644 --- a/stratosphere/fatal/source/fatal_types.hpp +++ b/stratosphere/fatal/source/fatal_types.hpp @@ -96,8 +96,9 @@ struct FatalCpuContext { u32 type; }; -struct FatalContext { +struct FatalThrowContext { u32 error_code; + bool is_creport; FatalCpuContext cpu_ctx; }; From 962fa0a69020004f8e827200249a4edb2d201a9a Mon Sep 17 00:00:00 2001 From: Michael Scire Date: Wed, 14 Nov 2018 03:23:28 -0800 Subject: [PATCH 32/33] fatal: automatically collect backtrace for callers. --- stratosphere/fatal/fatal.json | 11 +- stratosphere/fatal/source/fatal_debug.cpp | 256 ++++++++++++++++++ stratosphere/fatal/source/fatal_debug.hpp | 149 ++++++++++ stratosphere/fatal/source/fatal_font.cpp | 8 + stratosphere/fatal/source/fatal_font.hpp | 1 + .../fatal/source/fatal_task_screen.cpp | 41 ++- stratosphere/fatal/source/fatal_throw.cpp | 22 +- stratosphere/fatal/source/fatal_types.hpp | 3 +- stratosphere/fatal/source/fatal_user.cpp | 9 +- 9 files changed, 481 insertions(+), 19 deletions(-) create mode 100644 stratosphere/fatal/source/fatal_debug.cpp create mode 100644 stratosphere/fatal/source/fatal_debug.hpp diff --git a/stratosphere/fatal/fatal.json b/stratosphere/fatal/fatal.json index 380b2b85f..61f6ca88f 100644 --- a/stratosphere/fatal/fatal.json +++ b/stratosphere/fatal/fatal.json @@ -12,7 +12,7 @@ "is_64_bit": true, "address_space_type": 3, "filesystem_access": { - "permissions": "0x0000000000100000" + "permissions": "0xFFFFFFFFFFFFFFFF" }, "service_access": ["bpc", "bpc:c", "erpt:c", "fsp-srv", "gpio", "i2c", "lbl", "lm", "nvdrv:s", "pcv", "pl:u", "pm:info", "psm", "set", "set:sys", "spsm", "vi:m", "vi:s"], "service_host": ["fatal:p", "fatal:u"], @@ -76,7 +76,14 @@ "svcReplyAndReceive": "0x43", "svcReplyAndReceiveWithUserBuffer": "0x44", "svcCreateEvent": "0x45", - "svcReadWriteRegister": "0x4E" + "svcReadWriteRegister": "0x4E", + "svcDebugActiveProcess": "0x60", + "svcGetDebugEvent": "0x63", + "svcGetThreadList": "0x66", + "svcGetDebugThreadContext": "0x67", + "svcQueryDebugProcessMemory": "0x69", + "svcReadDebugProcessMemory": "0x6a", + "svcGetDebugThreadParam": "0x6d" } }, { "type": "min_kernel_version", diff --git a/stratosphere/fatal/source/fatal_debug.cpp b/stratosphere/fatal/source/fatal_debug.cpp new file mode 100644 index 000000000..46ed8df13 --- /dev/null +++ b/stratosphere/fatal/source/fatal_debug.cpp @@ -0,0 +1,256 @@ +/* + * Copyright (c) 2018 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#include +#include +#include "fatal_debug.hpp" +#include "fatal_config.hpp" + +static bool IsAddressReadable(Handle debug_handle, u64 address, u64 size, MemoryInfo *o_mi) { + MemoryInfo mi; + u32 pi; + + if (o_mi == NULL) { + o_mi = &mi; + } + + if (R_FAILED(svcQueryDebugProcessMemory(o_mi, &pi, debug_handle, address))) { + return false; + } + + /* Must be readable */ + if ((o_mi->perm & Perm_R) != Perm_R) { + return false; + } + + /* Must have space for both userdata address and userdata size. */ + if (address < o_mi->addr || o_mi->addr + o_mi->size < address + size) { + return false; + } + + return true; +} + +static bool CheckThreadIsFatalCaller(FatalThrowContext *ctx, u64 debug_handle, u64 thread_id, u64 thread_tls_addr, ThreadContext *thread_ctx) { + /* Verify that the thread is running or waiting. */ + { + u64 _; + u32 thread_state; + if (R_FAILED(svcGetDebugThreadParam(&_, &thread_state, debug_handle, thread_id, DebugThreadParam_State))) { + return false; + } + + if (thread_state > 1) { + return false; + } + } + + /* Get the thread context. */ + if (R_FAILED(svcGetDebugThreadContext(thread_ctx, debug_handle, thread_id, 0xF))) { + return false; + } + + /* Check if PC is readable. */ + if (!IsAddressReadable(debug_handle, thread_ctx->pc.x, sizeof(u32), NULL)) { + return false; + } + + /* Try to read the current instruction. */ + u32 insn; + if (R_FAILED(svcReadDebugProcessMemory(&insn, debug_handle, thread_ctx->pc.x, sizeof(insn)))) { + return false; + } + + /* If the instruction isn't svcSendSyncRequest, it's not the fatal caller. */ + if (insn != 0xD4000421) { + return false; + } + + /* The fatal caller will have readable tls. */ + if (!IsAddressReadable(debug_handle, thread_tls_addr, 0x100, NULL)) { + return false; + } + + /* Read in the fatal caller's tls. */ + u8 thread_tls[0x100]; + if (R_FAILED(svcReadDebugProcessMemory(thread_tls, debug_handle, thread_tls_addr, sizeof(thread_tls)))) { + return false; + } + + /* Replace our tls with the fatal caller's. */ + std::memcpy(armGetTls(), thread_tls, sizeof(thread_tls)); + + /* Parse the command that the thread sent. */ + { + IpcParsedCommand r; + if (R_FAILED(ipcParse(&r))) { + return false; + } + + /* Fatal command takes in a PID, only one buffer max. */ + if (!r.HasPid || r.NumStatics || r.NumStaticsOut || r.NumHandles) { + return false; + } + + struct { + u32 magic; + u32 version; + u64 cmd_id; + u32 err_code; + } *raw = (decltype(raw))(r.Raw); + + if (raw->magic != SFCI_MAGIC) { + return false; + } + + if (raw->cmd_id > 2) { + return false; + } + + if (raw->cmd_id != 2 && r.NumBuffers) { + return false; + } + + if (raw->err_code != ctx->error_code) { + return false; + } + } + + /* We found our caller. */ + return true; +} + +void TryCollectDebugInformation(FatalThrowContext *ctx, u64 pid) { + Handle debug_handle; + if (R_SUCCEEDED(svcDebugActiveProcess(&debug_handle, pid))) { + /* Ensure we close the debugged process. */ + ON_SCOPE_EXIT { svcCloseHandle(debug_handle); }; + + /* First things first, check if process is 64 bits, and get list of thread infos. */ + std::unordered_map thread_id_to_tls; + { + bool got_attach_process = false; + DebugEventInfo d; + while (R_SUCCEEDED(svcGetDebugEvent((u8 *)&d, debug_handle))) { + if (d.type == DebugEventType::AttachProcess) { + ctx->cpu_ctx.is_aarch32 = (d.info.attach_process.flags & 1) == 0; + got_attach_process = true; + } else if (d.type == DebugEventType::AttachThread) { + thread_id_to_tls[d.info.attach_thread.thread_id] = d.info.attach_thread.tls_address; + } + } + + if (!got_attach_process) { + return; + } + } + + /* TODO: Try to collect information on 32-bit fatals. This shouldn't really matter for any real use case. */ + if (ctx->cpu_ctx.is_aarch32) { + return; + } + + /* Welcome to hell. */ + bool found_fatal_caller = false; + u64 thread_id = 0; + ThreadContext thread_ctx; + { + /* We start by trying to get a list of threads. */ + u32 thread_count; + u64 thread_ids[0x60]; + if (R_FAILED(svcGetThreadList(&thread_count, thread_ids, 0x60, debug_handle))) { + return; + } + + /* We need to locate the thread that's called fatal. */ + for (u32 i = 0; i < thread_count; i++) { + const u64 cur_thread_id = thread_ids[i]; + if (thread_id_to_tls.find(cur_thread_id) == thread_id_to_tls.end()) { + continue; + } + + if (CheckThreadIsFatalCaller(ctx, debug_handle, cur_thread_id, thread_id_to_tls[cur_thread_id], &thread_ctx)) { + thread_id = cur_thread_id; + found_fatal_caller = true; + break; + } + } + if (!found_fatal_caller) { + return; + } + } + if (R_FAILED(svcGetDebugThreadContext(&thread_ctx, debug_handle, thread_id, 0xF))) { + return; + } + + /* So we found our caller. */ + for (u32 i = 0; i < 29; i++) { + /* GetDebugThreadContext won't give us any of these registers, because thread is in SVC :( */ + ctx->has_gprs[i] = false; + } + for (u32 i = 29; i < NumAarch64Gprs; i++) { + ctx->has_gprs[i] = true; + } + ctx->cpu_ctx.aarch64_ctx.fp = thread_ctx.fp; + ctx->cpu_ctx.aarch64_ctx.lr = thread_ctx.lr; + ctx->cpu_ctx.aarch64_ctx.sp = thread_ctx.sp; + ctx->cpu_ctx.aarch64_ctx.pc = thread_ctx.pc.x; + + + /* Parse a stack trace. */ + u64 cur_fp = thread_ctx.fp; + for (unsigned int i = 0; i < sizeof(ctx->cpu_ctx.aarch64_ctx.stack_trace)/sizeof(u64); i++) { + /* Validate the current frame. */ + if (cur_fp == 0 || (cur_fp & 0xF)) { + break; + } + + /* Read a new frame. */ + StackFrame cur_frame; + if (R_FAILED(svcReadDebugProcessMemory(&cur_frame, debug_handle, cur_fp, sizeof(StackFrame)))) { + break; + } + + /* Advance to the next frame. */ + ctx->cpu_ctx.aarch64_ctx.stack_trace[ctx->cpu_ctx.aarch64_ctx.stack_trace_size++] = cur_frame.lr; + cur_fp = cur_frame.fp; + } + + /* Parse the starting address. */ + { + u64 guess = thread_ctx.pc.x; + MemoryInfo mi; + u32 pi; + if (R_FAILED(svcQueryDebugProcessMemory(&mi, &pi, debug_handle, guess)) || mi.perm != Perm_Rx) { + return; + } + + /* Iterate backwards until we find the memory before the code region. */ + while (mi.addr > 0) { + if (R_FAILED(svcQueryDebugProcessMemory(&mi, &pi, debug_handle, guess))) { + return; + } + + if (mi.type == MemType_Unmapped) { + /* Code region will be at the end of the unmapped region preceding it. */ + ctx->cpu_ctx.aarch64_ctx.start_address = mi.addr + mi.size; + break; + } + + guess -= 4; + } + } + } +} \ No newline at end of file diff --git a/stratosphere/fatal/source/fatal_debug.hpp b/stratosphere/fatal/source/fatal_debug.hpp new file mode 100644 index 000000000..8a7c4ec3d --- /dev/null +++ b/stratosphere/fatal/source/fatal_debug.hpp @@ -0,0 +1,149 @@ +/* + * Copyright (c) 2018 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once +#include +#include + +#include "fatal_types.hpp" + +void TryCollectDebugInformation(FatalThrowContext *ctx, u64 pid); + +struct StackFrame { + u64 fp; + u64 lr; +}; + +struct AttachProcessInfo { + u64 title_id; + u64 process_id; + char name[0xC]; + u32 flags; + u64 user_exception_context_address; /* 5.0.0+ */ +}; + +struct AttachThreadInfo { + u64 thread_id; + u64 tls_address; + u64 entrypoint; +}; + +/* TODO: ExitProcessInfo */ +/* TODO: ExitThreadInfo */ + +enum class DebugExceptionType : u32 { + UndefinedInstruction = 0, + InstructionAbort = 1, + DataAbort = 2, + AlignmentFault = 3, + DebuggerAttached = 4, + BreakPoint = 5, + UserBreak = 6, + DebuggerBreak = 7, + BadSvc = 8, + UnknownNine = 9, +}; + +static inline const char *GetDebugExceptionTypeStr(DebugExceptionType type) { + switch (type) { + case DebugExceptionType::UndefinedInstruction: + return "Undefined Instruction"; + case DebugExceptionType::InstructionAbort: + return "Instruction Abort"; + case DebugExceptionType::DataAbort: + return "Data Abort"; + case DebugExceptionType::AlignmentFault: + return "Alignment Fault"; + case DebugExceptionType::DebuggerAttached: + return "Debugger Attached"; + case DebugExceptionType::BreakPoint: + return "Break Point"; + case DebugExceptionType::UserBreak: + return "User Break"; + case DebugExceptionType::DebuggerBreak: + return "Debugger Break"; + case DebugExceptionType::BadSvc: + return "Bad Svc"; + case DebugExceptionType::UnknownNine: + return "Unknown Nine"; + default: + return "Unknown"; + } +} + +struct UndefinedInstructionInfo { + u32 insn; +}; + +struct DataAbortInfo { + u64 address; +}; + +struct AlignmentFaultInfo { + u64 address; +}; + +struct UserBreakInfo { + u64 break_reason; + u64 address; + u64 size; +}; + +struct BadSvcInfo { + u32 id; +}; + +union SpecificExceptionInfo { + UndefinedInstructionInfo undefined_instruction; + DataAbortInfo data_abort; + AlignmentFaultInfo alignment_fault; + UserBreakInfo user_break; + BadSvcInfo bad_svc; + u64 raw; +}; + +struct ExceptionInfo { + DebugExceptionType type; + u64 address; + SpecificExceptionInfo specific; +}; + + +enum class DebugEventType : u32 { + AttachProcess = 0, + AttachThread = 1, + ExitProcess = 2, + ExitThread = 3, + Exception = 4 +}; + +union DebugInfo { + AttachProcessInfo attach_process; + AttachThreadInfo attach_thread; + ExceptionInfo exception; +}; + +struct DebugEventInfo { + DebugEventType type; + u32 flags; + u64 thread_id; + union { + DebugInfo info; + u64 _[0x40/sizeof(u64)]; + }; +}; + +static_assert(sizeof(DebugEventInfo) >= 0x50, "Incorrect DebugEventInfo definition!"); \ No newline at end of file diff --git a/stratosphere/fatal/source/fatal_font.cpp b/stratosphere/fatal/source/fatal_font.cpp index b86cf4edf..452bff06d 100644 --- a/stratosphere/fatal/source/fatal_font.cpp +++ b/stratosphere/fatal/source/fatal_font.cpp @@ -163,6 +163,14 @@ void FontManager::PrintMonospaceU32(u32 x) { DrawString(char_buf, false, true); } +void FontManager::PrintMonospaceBlank(u32 width) { + char char_buf[0x400] = {0}; + for (size_t i = 0; i < width && i < sizeof(char_buf); i++) { + char_buf[i] = ' '; + } + + DrawString(char_buf, false, true); +} void FontManager::SetFontColor(u16 color) { g_font_color = color; diff --git a/stratosphere/fatal/source/fatal_font.hpp b/stratosphere/fatal/source/fatal_font.hpp index 5bd79dc14..acd1bca63 100644 --- a/stratosphere/fatal/source/fatal_font.hpp +++ b/stratosphere/fatal/source/fatal_font.hpp @@ -41,4 +41,5 @@ class FontManager { static void PrintFormat(const char *format, ...); static void PrintMonospaceU64(u64 x); static void PrintMonospaceU32(u32 x); + static void PrintMonospaceBlank(u32 width); }; \ No newline at end of file diff --git a/stratosphere/fatal/source/fatal_task_screen.cpp b/stratosphere/fatal/source/fatal_task_screen.cpp index 94fa1bacb..66e39b69c 100644 --- a/stratosphere/fatal/source/fatal_task_screen.cpp +++ b/stratosphere/fatal/source/fatal_task_screen.cpp @@ -225,21 +225,40 @@ Result ShowFatalTask::ShowFatal() { /* Print GPRs. */ FontManager::SetFontSize(14.0f); - FontManager::PrintLine("General Purpose Registers"); + FontManager::Print("General Purpose Registers "); + { + FontManager::SetPosition(FontManager::GetX() + 2, FontManager::GetY()); + u32 x = FontManager::GetX(); + FontManager::Print("PC: "); + FontManager::SetPosition(x + 47, FontManager::GetY()); + } + if (this->ctx->cpu_ctx.is_aarch32) { + FontManager::PrintMonospaceU32(this->ctx->cpu_ctx.aarch32_ctx.pc); + } else { + FontManager::PrintMonospaceU64(this->ctx->cpu_ctx.aarch64_ctx.pc); + } + FontManager::PrintLine(""); + FontManager::SetPosition(32, FontManager::GetY()); FontManager::AddSpacingLines(0.5f); if (this->ctx->cpu_ctx.is_aarch32) { for (size_t i = 0; i < (NumAarch32Gprs / 2); i++) { u32 x = FontManager::GetX(); FontManager::PrintFormat("%s:", Aarch32GprNames[i]); FontManager::SetPosition(x + 47, FontManager::GetY()); - FontManager::Print("0x"); - FontManager::PrintMonospaceU32(this->ctx->cpu_ctx.aarch32_ctx.r[i]); + if (this->ctx->has_gprs[i]) { + FontManager::PrintMonospaceU32(this->ctx->cpu_ctx.aarch32_ctx.r[i]); + } else { + FontManager::PrintMonospaceBlank(8); + } FontManager::Print(" "); x = FontManager::GetX(); FontManager::PrintFormat("%s:", Aarch32GprNames[i + (NumAarch32Gprs / 2)]); FontManager::SetPosition(x + 47, FontManager::GetY()); - FontManager::Print("0x"); - FontManager::PrintMonospaceU32(this->ctx->cpu_ctx.aarch32_ctx.r[i + (NumAarch32Gprs / 2)]); + if (this->ctx->has_gprs[i + (NumAarch32Gprs / 2)]) { + FontManager::PrintMonospaceU32(this->ctx->cpu_ctx.aarch32_ctx.r[i + (NumAarch32Gprs / 2)]); + } else { + FontManager::PrintMonospaceBlank(8); + } if (i == (NumAarch32Gprs / 2) - 1) { FontManager::Print(" "); @@ -254,12 +273,20 @@ Result ShowFatalTask::ShowFatal() { u32 x = FontManager::GetX(); FontManager::PrintFormat("%s:", Aarch64GprNames[i]); FontManager::SetPosition(x + 47, FontManager::GetY()); - FontManager::PrintMonospaceU64(this->ctx->cpu_ctx.aarch64_ctx.x[i]); + if (this->ctx->has_gprs[i]) { + FontManager::PrintMonospaceU64(this->ctx->cpu_ctx.aarch64_ctx.x[i]); + } else { + FontManager::PrintMonospaceBlank(16); + } FontManager::Print(" "); x = FontManager::GetX(); FontManager::PrintFormat("%s:", Aarch64GprNames[i + (NumAarch64Gprs / 2)]); FontManager::SetPosition(x + 47, FontManager::GetY()); - FontManager::PrintMonospaceU64(this->ctx->cpu_ctx.aarch64_ctx.x[i + (NumAarch64Gprs / 2)]); + if (this->ctx->has_gprs[i + (NumAarch64Gprs / 2)]) { + FontManager::PrintMonospaceU64(this->ctx->cpu_ctx.aarch64_ctx.x[i + (NumAarch64Gprs / 2)]); + } else { + FontManager::PrintMonospaceBlank(16); + } if (i == (NumAarch64Gprs / 2) - 1) { FontManager::Print(" "); diff --git a/stratosphere/fatal/source/fatal_throw.cpp b/stratosphere/fatal/source/fatal_throw.cpp index dbd6eba3b..8dbd15e0e 100644 --- a/stratosphere/fatal/source/fatal_throw.cpp +++ b/stratosphere/fatal/source/fatal_throw.cpp @@ -19,6 +19,7 @@ #include "fatal_event_manager.hpp" #include "fatal_task.hpp" #include "fatal_config.hpp" +#include "fatal_debug.hpp" static bool g_thrown = false; @@ -34,17 +35,25 @@ static Result SetThrown() { Result ThrowFatalForSelf(u32 error) { u64 pid = 0; - FatalCpuContext ctx = {0}; svcGetProcessId(&pid, CUR_PROCESS_HANDLE); - return ThrowFatalImpl(error, pid, FatalType_ErrorScreen, &ctx); + return ThrowFatalImpl(error, pid, FatalType_ErrorScreen, nullptr); } Result ThrowFatalImpl(u32 error, u64 pid, FatalType policy, FatalCpuContext *cpu_ctx) { Result rc = 0; FatalThrowContext ctx; ctx.error_code = error; - ctx.cpu_ctx = *cpu_ctx; + if (cpu_ctx != nullptr) { + ctx.cpu_ctx = *cpu_ctx; + /* Assume if we're provided a context that it's complete. */ + for (u32 i = 0; i < NumAarch64Gprs; i++) { + ctx.has_gprs[i] = true; + } + } else { + std::memset(&ctx.cpu_ctx, 0, sizeof(ctx.cpu_ctx)); + cpu_ctx = &ctx.cpu_ctx; + } /* Get config. */ const FatalConfig *config = GetFatalConfig(); @@ -59,6 +68,13 @@ Result ThrowFatalImpl(u32 error, u64 pid, FatalType policy, FatalCpuContext *cpu title_id = cpu_ctx->aarch64_ctx.afsr0; } + /* Atmosphere extension: automatic debug info collection. */ + if (GetRuntimeFirmwareVersion() >= FirmwareVersion_200 && !ctx.is_creport) { + if ((cpu_ctx->is_aarch32 && cpu_ctx->aarch32_ctx.stack_trace_size == 0) || (!cpu_ctx->is_aarch32 && cpu_ctx->aarch32_ctx.stack_trace_size == 0)) { + TryCollectDebugInformation(&ctx, pid); + } + } + switch (policy) { case FatalType_ErrorReport: /* TODO: Don't write an error report. */ diff --git a/stratosphere/fatal/source/fatal_types.hpp b/stratosphere/fatal/source/fatal_types.hpp index 99be9c524..b0635ec9f 100644 --- a/stratosphere/fatal/source/fatal_types.hpp +++ b/stratosphere/fatal/source/fatal_types.hpp @@ -99,6 +99,7 @@ struct FatalCpuContext { struct FatalThrowContext { u32 error_code; bool is_creport; + bool has_gprs[NumAarch64Gprs]; FatalCpuContext cpu_ctx; }; @@ -129,6 +130,7 @@ static constexpr const char *Aarch64GprNames[NumAarch64Gprs] = { u8"X18", u8"X19", u8"X20", + u8"X21", u8"X22", u8"X23", u8"X24", @@ -139,7 +141,6 @@ static constexpr const char *Aarch64GprNames[NumAarch64Gprs] = { u8"FP", u8"LR", u8"SP", - u8"PC", }; static constexpr const char *Aarch32GprNames[NumAarch32Gprs] = { diff --git a/stratosphere/fatal/source/fatal_user.cpp b/stratosphere/fatal/source/fatal_user.cpp index 98b081494..520971bf5 100644 --- a/stratosphere/fatal/source/fatal_user.cpp +++ b/stratosphere/fatal/source/fatal_user.cpp @@ -21,19 +21,16 @@ #include "fatal_task.hpp" Result UserService::ThrowFatal(u32 error, PidDescriptor pid_desc) { - FatalCpuContext ctx = {0}; - return ThrowFatalImpl(error, pid_desc.pid, FatalType_ErrorReportAndErrorScreen, &ctx); + return ThrowFatalImpl(error, pid_desc.pid, FatalType_ErrorReportAndErrorScreen, nullptr); } Result UserService::ThrowFatalWithPolicy(u32 error, PidDescriptor pid_desc, FatalType policy) { - FatalCpuContext ctx = {0}; - return ThrowFatalImpl(error, pid_desc.pid, policy, &ctx); + return ThrowFatalImpl(error, pid_desc.pid, policy, nullptr); } Result UserService::ThrowFatalWithCpuContext(u32 error, PidDescriptor pid_desc, FatalType policy, InBuffer _ctx) { if (_ctx.num_elements < sizeof(FatalCpuContext)) { - FatalCpuContext ctx = {0}; - return ThrowFatalImpl(error, pid_desc.pid, policy, &ctx); + return ThrowFatalImpl(error, pid_desc.pid, policy, nullptr); } else { return ThrowFatalImpl(error, pid_desc.pid, policy, reinterpret_cast(_ctx.buffer)); } From 8054b2d219bbaedb1dc4aa941455e8e09c106313 Mon Sep 17 00:00:00 2001 From: Michael Scire Date: Wed, 14 Nov 2018 14:13:31 -0800 Subject: [PATCH 33/33] Fatal: save auto-debug info to SD card. --- .../creport/source/creport_crash_report.cpp | 2 +- stratosphere/fatal/fatal.json | 2 +- stratosphere/fatal/source/fatal_debug.cpp | 11 ++ stratosphere/fatal/source/fatal_main.cpp | 19 ++- .../fatal/source/fatal_task_error_report.cpp | 112 +++++++++++++++++- .../fatal/source/fatal_task_error_report.hpp | 4 + stratosphere/fatal/source/fatal_throw.cpp | 4 +- stratosphere/fatal/source/fatal_types.hpp | 3 + 8 files changed, 151 insertions(+), 6 deletions(-) diff --git a/stratosphere/creport/source/creport_crash_report.cpp b/stratosphere/creport/source/creport_crash_report.cpp index 6f2a2e62f..819655d11 100644 --- a/stratosphere/creport/source/creport_crash_report.cpp +++ b/stratosphere/creport/source/creport_crash_report.cpp @@ -257,7 +257,7 @@ void CrashReport::EnsureReportDirectories() { } void CrashReport::SaveReport() { - /* TODO: Save the report to the SD card. */ + /* Save the report to the SD card. */ char report_path[FS_MAX_PATH]; /* Ensure path exists. */ diff --git a/stratosphere/fatal/fatal.json b/stratosphere/fatal/fatal.json index 61f6ca88f..76bce7e4f 100644 --- a/stratosphere/fatal/fatal.json +++ b/stratosphere/fatal/fatal.json @@ -15,7 +15,7 @@ "permissions": "0xFFFFFFFFFFFFFFFF" }, "service_access": ["bpc", "bpc:c", "erpt:c", "fsp-srv", "gpio", "i2c", "lbl", "lm", "nvdrv:s", "pcv", "pl:u", "pm:info", "psm", "set", "set:sys", "spsm", "vi:m", "vi:s"], - "service_host": ["fatal:p", "fatal:u"], + "service_host": ["fatal:p", "fatal:u", "time:s"], "kernel_capabilities": [{ "type": "kernel_flags", "value": { diff --git a/stratosphere/fatal/source/fatal_debug.cpp b/stratosphere/fatal/source/fatal_debug.cpp index 46ed8df13..320f1a277 100644 --- a/stratosphere/fatal/source/fatal_debug.cpp +++ b/stratosphere/fatal/source/fatal_debug.cpp @@ -146,6 +146,7 @@ void TryCollectDebugInformation(FatalThrowContext *ctx, u64 pid) { while (R_SUCCEEDED(svcGetDebugEvent((u8 *)&d, debug_handle))) { if (d.type == DebugEventType::AttachProcess) { ctx->cpu_ctx.is_aarch32 = (d.info.attach_process.flags & 1) == 0; + memcpy(ctx->proc_name, d.info.attach_process.name, sizeof(d.info.attach_process.name)); got_attach_process = true; } else if (d.type == DebugEventType::AttachThread) { thread_id_to_tls[d.info.attach_thread.thread_id] = d.info.attach_thread.tls_address; @@ -228,6 +229,16 @@ void TryCollectDebugInformation(FatalThrowContext *ctx, u64 pid) { cur_fp = cur_frame.fp; } + /* Try to read up to 0x100 of stack. */ + for (size_t sz = 0x100; sz > 0; sz -= 0x10) { + if (IsAddressReadable(debug_handle, ctx->cpu_ctx.aarch64_ctx.sp, sz, nullptr)) { + if (R_SUCCEEDED(svcReadDebugProcessMemory(ctx->stack_dump, debug_handle, ctx->cpu_ctx.aarch64_ctx.sp, sz))) { + ctx->stack_dump_size = sz; + } + break; + } + } + /* Parse the starting address. */ { u64 guess = thread_ctx.pc.x; diff --git a/stratosphere/fatal/source/fatal_main.cpp b/stratosphere/fatal/source/fatal_main.cpp index 292258a73..7790e85b7 100644 --- a/stratosphere/fatal/source/fatal_main.cpp +++ b/stratosphere/fatal/source/fatal_main.cpp @@ -35,7 +35,7 @@ extern "C" { u32 __nx_applet_type = AppletType_None; - #define INNER_HEAP_SIZE 0x280000 + #define INNER_HEAP_SIZE 0x2A0000 size_t nx_inner_heap_size = INNER_HEAP_SIZE; char nx_inner_heap[INNER_HEAP_SIZE]; @@ -118,11 +118,28 @@ void __appInit(void) { std::abort(); } + rc = fsInitialize(); + if (R_FAILED(rc)) { + std::abort(); + } + + rc = fsInitialize(); + if (R_FAILED(rc)) { + std::abort(); + } + + rc = fsdevMountSdmc(); + if (R_FAILED(rc)) { + std::abort(); + } + /* fatal cannot throw fatal, so don't do: CheckAtmosphereVersion(CURRENT_ATMOSPHERE_VERSION); */ } void __appExit(void) { /* Cleanup services. */ + fsdevUnmountAll(); + fsExit(); plExit(); spsmExit(); psmExit(); diff --git a/stratosphere/fatal/source/fatal_task_error_report.cpp b/stratosphere/fatal/source/fatal_task_error_report.cpp index 111c4ce38..bd75e641c 100644 --- a/stratosphere/fatal/source/fatal_task_error_report.cpp +++ b/stratosphere/fatal/source/fatal_task_error_report.cpp @@ -14,17 +14,127 @@ * along with this program. If not, see . */ +#include +#include +#include #include +#include + #include "fatal_task_error_report.hpp" +#include "fatal_config.hpp" + +void ErrorReportTask::EnsureReportDirectories() { + char path[FS_MAX_PATH]; + strcpy(path, "sdmc:/atmosphere"); + mkdir(path, S_IRWXU); + strcat(path, "/fatal_reports"); + mkdir(path, S_IRWXU); + strcat(path, "/dumps"); + mkdir(path, S_IRWXU); +} + +bool ErrorReportTask::GetCurrentTime(u64 *out) { + *out = 0; + + /* Verify that pcv isn't dead. */ + { + Handle dummy; + if (R_SUCCEEDED(smRegisterService(&dummy, "time:s", false, 0x20))) { + svcCloseHandle(dummy); + return false; + } + } + + /* Try to get the current time. */ + bool success = false; + if (R_SUCCEEDED(timeInitialize())) { + if (R_SUCCEEDED(timeGetCurrentTime(TimeType_LocalSystemClock, out))) { + success = true; + } + timeExit(); + } + return success; +} + +void ErrorReportTask::SaveReportToSdCard() { + char file_path[FS_MAX_PATH]; + + /* Ensure path exists. */ + EnsureReportDirectories(); + + /* Get a timestamp. */ + u64 timestamp; + if (!GetCurrentTime(×tamp)) { + timestamp = svcGetSystemTick(); + } + + /* Open report file. */ + snprintf(file_path, sizeof(file_path) - 1, "sdmc:/atmosphere/fatal_reports/%011lu_%016lx.log", timestamp, this->title_id); + FILE *f_report = fopen(file_path, "w"); + if (f_report != NULL) { + ON_SCOPE_EXIT { fclose(f_report); }; + + fprintf(f_report, "Atmosphère Fatal Report (v1.0):\n"); + fprintf(f_report, "Result: 0x%X (2%03d-%04d)\n\n", this->ctx->error_code, R_MODULE(this->ctx->error_code), R_DESCRIPTION(this->ctx->error_code)); + fprintf(f_report, "Title ID: %016lx\n", this->title_id); + if (strlen(this->ctx->proc_name)) { + fprintf(f_report, "Process Name: %s\n", this->ctx->proc_name); + } + fprintf(f_report, u8"Firmware: %s (Atmosphère %u.%u.%u-%s)\n", GetFatalConfig()->firmware_version.display_version, CURRENT_ATMOSPHERE_VERSION, GetAtmosphereGitRevision()); + + if (this->ctx->cpu_ctx.is_aarch32) { + fprintf(f_report, "General Purpose Registers:\n"); + for (size_t i = 0; i < NumAarch32Gprs; i++) { + if (this->ctx->has_gprs[i]) { + fprintf(f_report, " %3s: %08x\n", Aarch32GprNames[i], this->ctx->cpu_ctx.aarch32_ctx.r[i]); + } + } + fprintf(f_report, " PC: %08x\n", this->ctx->cpu_ctx.aarch32_ctx.pc); + fprintf(f_report, "Start Address: %08x\n", this->ctx->cpu_ctx.aarch32_ctx.start_address); + fprintf(f_report, "Stack Trace:\n"); + for (unsigned int i = 0; i < this->ctx->cpu_ctx.aarch32_ctx.stack_trace_size; i++) { + fprintf(f_report, " ReturnAddress[%02u]: %08x\n", i, this->ctx->cpu_ctx.aarch32_ctx.stack_trace[i]); + } + } else { + fprintf(f_report, "General Purpose Registers:\n"); + for (size_t i = 0; i < NumAarch64Gprs; i++) { + if (this->ctx->has_gprs[i]) { + fprintf(f_report, " %3s: %016lx\n", Aarch64GprNames[i], this->ctx->cpu_ctx.aarch64_ctx.x[i]); + } + } + fprintf(f_report, " PC: %016lx\n", this->ctx->cpu_ctx.aarch64_ctx.pc); + fprintf(f_report, "Start Address: %016lx\n", this->ctx->cpu_ctx.aarch64_ctx.start_address); + fprintf(f_report, "Stack Trace:\n"); + for (unsigned int i = 0; i < this->ctx->cpu_ctx.aarch64_ctx.stack_trace_size; i++) { + fprintf(f_report, " ReturnAddress[%02u]: %016lx\n", i, this->ctx->cpu_ctx.aarch64_ctx.stack_trace[i]); + } + } + + } + + if (this->ctx->stack_dump_size) { + snprintf(file_path, sizeof(file_path) - 1, "sdmc:/atmosphere/fatal_reports/dumps/%011lu_%016lx.bin", timestamp, this->title_id); + FILE *f_stackdump = fopen(file_path, "wb"); + if (f_stackdump == NULL) { return; } + ON_SCOPE_EXIT { fclose(f_stackdump); }; + + fwrite(this->ctx->stack_dump, this->ctx->stack_dump_size, 1, f_stackdump); + } +} Result ErrorReportTask::Run() { if (this->create_report) { /* Here, Nintendo creates an error report with erpt. AMS will not do that. */ - /* TODO: Should atmosphere log reports to to the SD card? */ + } + + /* Save report to SD card. */ + if (!this->ctx->is_creport) { + SaveReportToSdCard(); } /* Signal we're done with our job. */ eventFire(this->erpt_event); + return 0; } \ No newline at end of file diff --git a/stratosphere/fatal/source/fatal_task_error_report.hpp b/stratosphere/fatal/source/fatal_task_error_report.hpp index 71b220f4d..464828dfb 100644 --- a/stratosphere/fatal/source/fatal_task_error_report.hpp +++ b/stratosphere/fatal/source/fatal_task_error_report.hpp @@ -23,6 +23,10 @@ class ErrorReportTask : public IFatalTask { private: bool create_report; Event *erpt_event; + private: + void EnsureReportDirectories(); + bool GetCurrentTime(u64 *out); + void SaveReportToSdCard(); public: ErrorReportTask(FatalThrowContext *ctx, u64 title_id, bool error_report, Event *evt) : IFatalTask(ctx, title_id), create_report(error_report), erpt_event(evt) { } virtual Result Run() override; diff --git a/stratosphere/fatal/source/fatal_throw.cpp b/stratosphere/fatal/source/fatal_throw.cpp index 8dbd15e0e..5cbcfa9dc 100644 --- a/stratosphere/fatal/source/fatal_throw.cpp +++ b/stratosphere/fatal/source/fatal_throw.cpp @@ -42,7 +42,7 @@ Result ThrowFatalForSelf(u32 error) { Result ThrowFatalImpl(u32 error, u64 pid, FatalType policy, FatalCpuContext *cpu_ctx) { Result rc = 0; - FatalThrowContext ctx; + FatalThrowContext ctx = {0}; ctx.error_code = error; if (cpu_ctx != nullptr) { ctx.cpu_ctx = *cpu_ctx; @@ -86,7 +86,7 @@ Result ThrowFatalImpl(u32 error, u64 pid, FatalType policy, FatalCpuContext *cpu if (R_FAILED((rc = SetThrown()))) { return rc; } - + /* Signal that fatal is about to happen. */ GetEventManager()->SignalEvents(); diff --git a/stratosphere/fatal/source/fatal_types.hpp b/stratosphere/fatal/source/fatal_types.hpp index b0635ec9f..f9ce5fb0e 100644 --- a/stratosphere/fatal/source/fatal_types.hpp +++ b/stratosphere/fatal/source/fatal_types.hpp @@ -100,6 +100,9 @@ struct FatalThrowContext { u32 error_code; bool is_creport; bool has_gprs[NumAarch64Gprs]; + size_t stack_dump_size; + u8 stack_dump[0x100]; + char proc_name[0xD]; FatalCpuContext cpu_ctx; };