From e919ee8352b1a7f7134c51dabf957c9f8866ca9a Mon Sep 17 00:00:00 2001 From: David Schmidt <1110325+david-schmidt@users.noreply.github.com> Date: Sat, 9 Feb 2019 15:34:41 -0500 Subject: [PATCH] Backport SDL from GSplus --- .gitignore | 2 + src/Makefile | 81 +- src/adb.c | 3812 ++++++++-------- src/adb.h | 3 +- src/atbridge/CMakeLists.txt | 5 + src/atbridge/aarp.c | 591 ++- src/atbridge/aarp.h | 77 +- src/atbridge/atalk.h | 277 +- src/atbridge/atbridge.c | 834 ++-- src/atbridge/atbridge.h | 96 +- src/atbridge/atbridge.vcxproj | 216 +- src/atbridge/atbridge.vcxproj.filters | 132 +- src/atbridge/elap.c | 783 ++-- src/atbridge/elap.h | 75 +- src/atbridge/elap_defs.h | 237 +- src/atbridge/llap.c | 656 ++- src/atbridge/llap.h | 77 +- src/atbridge/pcap_delay.c | 331 +- src/atbridge/pcap_delay.h | 98 +- src/atbridge/port.c | 271 +- src/atbridge/port.h | 119 +- src/config.c | 5736 ++++++++++++------------ src/config.h | 46 +- src/config.txt | 45 + src/debug.c | 1520 +++++++ src/debug.h | 30 + src/defc.h | 423 +- src/dis.c | 2070 +++++---- src/engine_c.c | 1651 ++++--- src/fix_mac_menu.m | 47 + src/fst.h | 203 + src/glog.c | 63 + src/glog.h | 30 + src/gsos.h | 186 + src/gsport | Bin 0 -> 985316 bytes src/host_common.c | 650 +++ src/host_common.h | 186 + src/host_fst.c | 1879 ++++++++ src/host_mli.c | 1567 +++++++ src/icongs.h | 2078 +++++++++ src/joystick_driver.c | 466 +- src/macdriver_console.c | 860 ---- src/moremem.c | 4459 ++++++++++--------- src/options.c | 453 ++ src/options.h | 29 + src/protos.h | 38 +- src/sdl2_driver.c | 887 ++++ src/sdl2snd_driver.c | 222 + src/sim65816.c | 4422 +++++++++---------- src/sound_driver.c | 865 ++-- src/tfe/CMakeLists.txt | 6 + src/tfe/protos_tfe.h | 5 +- src/tfe/tfe.c | 2139 +++++---- src/tfe/tfe.vcxproj | 216 +- src/tfe/tfe.vcxproj.filters | 108 +- src/tfe/tfearch.c | 453 +- src/tfe/tfesupp.c | 133 +- src/unix_host_common.c | 533 +++ src/vars_osx_sdl2 | 21 + src/vars_osx_x11 | 20 + src/vars_rpilinux_fb | 18 + src/vars_rpilinux_sdl2 | 16 + src/vars_win32 | 12 +- src/vars_win32_sdl | 19 +- src/vars_win32_sdl2 | 21 + src/vars_x86linux_sdl | 42 +- src/vars_x86linux_sdl2 | 21 + src/vars_x86linux_x11 | 21 + src/vars_x86solaris | 2 +- src/video.c | 5854 ++++++++++++------------- 70 files changed, 29538 insertions(+), 20006 deletions(-) create mode 100644 src/atbridge/CMakeLists.txt create mode 100644 src/config.txt create mode 100644 src/debug.c create mode 100644 src/debug.h create mode 100644 src/fix_mac_menu.m create mode 100644 src/fst.h create mode 100644 src/glog.c create mode 100644 src/glog.h create mode 100644 src/gsos.h create mode 100755 src/gsport create mode 100644 src/host_common.c create mode 100644 src/host_common.h create mode 100644 src/host_fst.c create mode 100644 src/host_mli.c create mode 100644 src/icongs.h delete mode 100755 src/macdriver_console.c create mode 100644 src/options.c create mode 100644 src/options.h create mode 100644 src/sdl2_driver.c create mode 100644 src/sdl2snd_driver.c create mode 100644 src/tfe/CMakeLists.txt create mode 100644 src/unix_host_common.c create mode 100644 src/vars_osx_sdl2 create mode 100644 src/vars_osx_x11 create mode 100644 src/vars_rpilinux_fb create mode 100644 src/vars_rpilinux_sdl2 create mode 100644 src/vars_win32_sdl2 create mode 100644 src/vars_x86linux_sdl2 create mode 100644 src/vars_x86linux_x11 diff --git a/.gitignore b/.gitignore index 9e02faf..94f251e 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,4 @@ /.project /GSport.app +/gsport +.DS_Store \ No newline at end of file diff --git a/src/Makefile b/src/Makefile index b9b60cc..60dcab7 100644 --- a/src/Makefile +++ b/src/Makefile @@ -1,12 +1,12 @@ # GSport central makefile - you need a 'vars' file linked/copied from a 'vars_xxx' template to build. - -OBJECTS1 = adb.o clock.o config.o dis.o engine_c.o scc.o iwm.o \ - joystick_driver.o moremem.o paddles.o parallel.o printer.o \ - sim65816.o smartport.o sound.o sound_driver.o video.o \ - scc_socket_driver.o imagewriter.o scc_imagewriter.o scc_llap.o -ATOBJ = atbridge/aarp.o atbridge/atbridge.o atbridge/elap.o atbridge/llap.o atbridge/port.o +OBJECTS1 = adb.o clock.o config.o debug.o dis.o engine_c.o scc.o iwm.o \ + joystick_driver.o moremem.o paddles.o parallel.o printer.o sim65816.o \ + smartport.o sound.o sound_driver.o video.o scc_socket_driver.o glog.o \ + imagewriter.o scc_imagewriter.o scc_llap.o options.o +ATOBJ = atbridge/aarp.o atbridge/atbridge.o atbridge/elap.o atbridge/llap.o atbridge/port.o PCAPOBJ = atbridge/pcap_delay.o TFEOBJ = tfe/tfe.o tfe/tfearch.o tfe/tfesupp.o +FSTOBJ = unix_host_common.o host_common.o host_fst.o host_mli.o include vars @@ -25,68 +25,51 @@ clean: - rm -f compile_time.o - rm -f 8inst_c.h - rm -f 16inst_c.h - - rm -rf ../GSport.app - - rm -rf ../GSportDmg specials: 8inst_s 16inst_s 8size 16size 8inst_c 16inst_c size_c size_s specials_clean: rm -f 8inst_s 16inst_s 8size 16size 8inst_c 16inst_c size_c size_s +# Linux/OSX/RPi SDL builds +gsport: $(OBJECTS) compile_time.o + $(LD) $(CCOPTS) $(LDOPTS) $(OBJECTS) compile_time.o $(LDFLAGS) -o $(NAME)$(SUFFIX) $(EXTRA_LIBS) + echo $(OBJECTS) + cp gsport .. -# Mac builds: -gsportmac: $(OBJECTS) compile_time.o - $(CC) $(CCOPTS) $(LDOPTS) $(OBJECTS) compile_time.o $(LDFLAGS) -o gsport $(EXTRA_LIBS) - mkdir -p ../GSport.app/Contents/Resources/English.lproj/main.nib - mkdir -p ../GSport.app/Contents/MacOS - mv gsport ../GSport.app/Contents/MacOS/GSport - echo "APPL????" > ../GSport.app/Contents/PkgInfo - cp -f arch/mac/Info.plist ../GSport.app/Contents/ - cp -f arch/mac/info.nib ../GSport.app/Contents/Resources/English.lproj/main.nib - cp -f arch/mac/classes.nib ../GSport.app/Contents/Resources/English.lproj/main.nib - cp -f arch/mac/objects.xib ../GSport.app/Contents/Resources/English.lproj/main.nib - cp -f arch/mac/gsporticon.icns ../GSport.app/Contents/Resources/ - cp -f arch/mac/525.icns ../GSport.app/Contents/Resources/ - cp -f arch/mac/2mg.icns ../GSport.app/Contents/Resources/ - touch '../GSport.app/Icon?' - rm -rf ../GSportDmg - mkdir ../GSportDmg - mkdir ../GSportDmg/GSport - cp ../LICENSE ../GSportDmg/GSport - cp -f parallel.rom ../GSportDmg/GSport - cp -f ../lib/NoBoot.po ../GSportDmg/GSport - mv ../GSport.app ../GSportDmg/GSport - cp -f ../config.template ../GSportDmg/GSport/config.txt - cp ../GSport.html ../GSportDmg/GSport/GSport.html - arch/mac/makedmg.sh .. GSportDmg GSport GSport 7 - -# Linux for X builds: +# Linux/OSX XWindows builds gsportx: $(OBJECTS) compile_time.o $(LD) $(CCOPTS) $(LDOPTS) $(OBJECTS) compile_time.o $(LDFLAGS) -o $(NAME)$(SUFFIX) $(XLIBS) $(EXTRA_LIBS) -lX11 echo $(OBJECTS) mv gsportx .. - cp -f ../config.template ../config.txt +# NOT CURRENTLY SUPPORTED # Linux framebuffer builds: gsportfb: $(OBJECTS) compile_time.o $(LD) $(CCOPTS) $(LDOPTS) $(OBJECTS) compile_time.o $(LDFLAGS) -o $(NAME)$(SUFFIX) $(EXTRA_LIBS) echo $(OBJECTS) mv gsportfb .. - cp -f ../config.template ../config.txt -# Mingw32 (native windows) builds: -gsport.exe: $(OBJECTS) compile_time.o +# Mingw32 / Cygwin builds: The Win32 API version +gsport32.exe: $(OBJECTS) compile_time.o g++ $(CCOPTS) $(LDOPTS) $(OBJECTS) compile_time.o $(LDFLAGS) -o $(NAME)$(SUFFIX) $(EXTRA_LIBS) -lwinmm -lgdi32 -ldsound -lcomctl32 -lws2_32 -lshell32 - mkdir -p ../GSport.app/lib - cp -f gsport.exe ../GSport.app/GSport.exe - cp -f ../config.template ../GSport.app/config.txt - cp -f ../lib/*.ttf ../GSport.app/lib - cp -f ../lib/arch/win32/*.dll ../GSport.app - cp -f ../lib/NoBoot.po ../GSport.app - cp -f GSport.bat ../GSport.app/GSport.bat - cp -f parallel.rom ../GSport.app - cp -f ../LICENSE ../GSport.app - cp -f ../GSport.html ../GSport.app + #mkdir -p ../GSport.app/lib + #cp -f gsport.exe ../GSport.app/GSport.exe + #cp -f ../config.template ../GSport.app/config.txt + #cp -f ../lib/*.ttf ../GSport.app/lib + #cp -f ../lib/arch/win32/*.dll ../GSport.app + #cp -f ../lib/NoBoot.po ../GSport.app + #cp -f GSport.bat ../GSport.app/GSport.bat + #cp -f parallel.rom ../GSport.app + #cp -f ../COPYING.txt ../GSport.app + cp gsport32.exe .. + +# Mingw32 / Cygwin builds: The SDL version (builds, but non-functioning) +gsport.exe: $(OBJECTS) compile_time.o + #g++ $(CCOPTS) $(LDOPTS) $(OBJECTS) compile_time.o $(LDFLAGS) -o $(NAME)$(SUFFIX) $(EXTRA_LIBS) -lwinmm -lgdi32 -ldsound -lcomctl32 -lws2_32 -lshell32 + #g++ $(CCOPTS) $(LDOPTS) $(OBJECTS) compile_time.o $(LDFLAGS) -o $(NAME)$(SUFFIX) $(EXTRA_LIBS) -mwindows + g++ $(CCOPTS) $(LDOPTS) $(OBJECTS) compile_time.o $(LDFLAGS) -o $(NAME)$(SUFFIX) $(EXTRA_LIBS) -lwinmm -lgdi32 -ldsound -lcomctl32 -lws2_32 -lshell32 + cp gsport.exe .. 8inst_c.h: instable.h $(PERL) make_inst c 8 instable.h > 8inst_c.h diff --git a/src/adb.c b/src/adb.c index 86c99a5..fef3a3f 100644 --- a/src/adb.c +++ b/src/adb.c @@ -1,1922 +1,1890 @@ -/* - GSport - an Apple //gs Emulator - Copyright (C) 2010 - 2013 by GSport contributors - - Based on the KEGS emulator written by and Copyright (C) 2003 Kent Dickey - - This program is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by the - Free Software Foundation; either version 2 of the License, or (at your - option) any later version. - - This program is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - for more details. - - You should have received a copy of the GNU General Public License along - with this program; if not, write to the Free Software Foundation, Inc., - 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ - -/* adb_mode bit 3 and bit 2 (faster repeats for arrows and space/del) not done*/ - -#include "adb.h" - -int g_fullscreen = 0; - -extern int Verbose; -extern word32 g_vbl_count; -extern int g_num_lines_prev_superhires640; -extern int g_num_lines_prev_superhires; -extern int g_rom_version; -extern int g_fast_disk_emul; -extern int g_limit_speed; -extern int g_irq_pending; -extern int g_swap_paddles; -extern int g_invert_paddles; -extern int g_joystick_type; -extern int g_a2vid_palette; -extern int g_config_control_panel; -extern word32 g_cfg_vbl_count; -extern double g_cur_dcycs; - -extern byte *g_slow_memory_ptr; -extern byte *g_memory_ptr; -extern word32 g_mem_size_total; - -enum { - ADB_IDLE = 0, - ADB_IN_CMD, - ADB_SENDING_DATA, -}; - -#define ADB_C027_MOUSE_DATA 0x80 -#define ADB_C027_MOUSE_INT 0x40 -#define ADB_C027_DATA_VALID 0x20 -#define ADB_C027_DATA_INT 0x10 -#define ADB_C027_KBD_VALID 0x08 -#define ADB_C027_KBD_INT 0x04 -#define ADB_C027_MOUSE_COORD 0x02 -#define ADB_C027_CMD_FULL 0x01 - -#define ADB_C027_NEG_MASK ( ~ ( \ - ADB_C027_MOUSE_DATA | ADB_C027_DATA_VALID | \ - ADB_C027_KBD_VALID | ADB_C027_MOUSE_COORD | \ - ADB_C027_CMD_FULL)) - - -int halt_on_all_c027 = 0; - -word32 g_adb_repeat_delay = 45; -word32 g_adb_repeat_rate = 3; -word32 g_adb_repeat_info = 0x23; -word32 g_adb_char_set = 0x0; -word32 g_adb_layout_lang = 0x0; - -word32 g_adb_interrupt_byte = 0; -int g_adb_state = ADB_IDLE; - -word32 g_adb_cmd = (word32)-1; -int g_adb_cmd_len = 0; -int g_adb_cmd_so_far = 0; -word32 g_adb_cmd_data[16]; - -#define MAX_ADB_DATA_PEND 16 - -word32 g_adb_data[MAX_ADB_DATA_PEND]; -int g_adb_data_pending = 0; - -word32 g_c027_val = 0; -word32 g_c025_val = 0; - -byte adb_memory[256]; - -word32 g_adb_mode = 0; /* mode set via set_modes, clear_modes */ - -int g_warp_pointer = 0; -int g_hide_pointer = 0; -int g_unhide_pointer = 0; - -int g_mouse_a2_x = 0; -int g_mouse_a2_y = 0; -int g_mouse_a2_button = 0; -int g_mouse_fifo_pos = 0; -int g_mouse_raw_x = 0; -int g_mouse_raw_y = 0; - -#define ADB_MOUSE_FIFO 8 - -STRUCT(Mouse_fifo) { - double dcycs; - int x; - int y; - int buttons; -}; - -Mouse_fifo g_mouse_fifo[ADB_MOUSE_FIFO] = { { 0, 0, 0, 0 } }; - -int g_mouse_warp_x = 0; -int g_mouse_warp_y = 0; - -int g_adb_mouse_valid_data = 0; -int g_adb_mouse_coord = 0; - -#define MAX_KBD_BUF 8 - -int g_key_down = 0; -int g_hard_key_down = 0; -int g_a2code_down = 0; -int g_kbd_read_no_update = 0; -int g_kbd_chars_buffered = 0; -int g_kbd_buf[MAX_KBD_BUF]; -word32 g_adb_repeat_vbl = 0; - -int g_kbd_dev_addr = 2; /* ADB physical kbd addr */ -int g_mouse_dev_addr = 3; /* ADB physical mouse addr */ - -int g_kbd_ctl_addr = 2; /* ADB microcontroller's kbd addr */ -int g_mouse_ctl_addr = 3; /* ADB ucontroller's mouse addr*/ - /* above are ucontroller's VIEW of where mouse/kbd */ - /* are...if they are moved, mouse/keyboard funcs */ - /* should stop (c025, c000, c024, etc). */ - -word32 g_virtual_key_up[4]; /* bitmask of all possible 128 a2codes */ - /* indicates which keys are up=1 by bit */ - -int g_keypad_key_is_down[10] = { 0 };/* List from 0-9 of which keypad */ - /* keys are currently pressed */ - - -#define SHIFT_DOWN ( (g_c025_val & 0x01) ) -#define CTRL_DOWN ( (g_c025_val & 0x02) ) -#define CAPS_LOCK_DOWN ( (g_c025_val & 0x04) ) -#define OPTION_DOWN ( (g_c025_val & 0x40) ) -#define CMD_DOWN ( (g_c025_val & 0x80) ) - - -#define MAX_ADB_KBD_REG3 16 - -int g_kbd_reg0_pos = 0; -int g_kbd_reg0_data[MAX_ADB_KBD_REG3]; -int g_kbd_reg3_16bit = 0x602; /* also set in adb_reset()! */ - - -int g_adb_init = 0; - -void -adb_init() -{ - int keycode; - int i; - - if(g_adb_init) { - halt_printf("g_adb_init = %d!\n", g_adb_init); - } - g_adb_init = 1; - - for(i = 0; i < 128; i++) { - keycode = a2_key_to_ascii[i][0]; - if(keycode != i) { - printf("ADB keycode lost/skipped: i=%x: keycode=%x\n", - i, keycode); - my_exit(1); - } - } - - g_c025_val = 0; - - for(i = 0; i < 4; i++) { - g_virtual_key_up[i] = -1; - } - - for(i = 0; i < 10; i++) { - g_keypad_key_is_down[i] = 0; - } - - adb_reset(); -} - -// OG Added adb_shut() -void adb_shut() -{ - g_adb_init = 0; -} - -void -adb_reset() -{ - - g_c027_val = 0; - - g_key_down = 0; - - g_kbd_dev_addr = 2; - g_mouse_dev_addr = 3; - - g_kbd_ctl_addr = 2; - g_mouse_ctl_addr = 3; - - adb_clear_data_int(); - adb_clear_mouse_int(); - adb_clear_kbd_srq(); - - g_adb_data_pending = 0; - g_adb_interrupt_byte = 0; - g_adb_state = ADB_IDLE; - g_adb_mouse_coord = 0; - g_adb_mouse_valid_data = 0; - - g_kbd_reg0_pos = 0; - g_kbd_reg3_16bit = 0x602; - -} - - -#define LEN_ADB_LOG 16 -STRUCT(Adb_log) { - word32 addr; - int val; - int state; -}; - -Adb_log g_adb_log[LEN_ADB_LOG]; -int g_adb_log_pos = 0; - -void -adb_log(word32 addr, int val) -{ - int pos; - - pos = g_adb_log_pos; - g_adb_log[pos].addr = addr; - g_adb_log[pos].val = val; - g_adb_log[pos].state = g_adb_state; - pos++; - if(pos >= LEN_ADB_LOG) { - pos = 0; - } - g_adb_log_pos = pos; -} - -void -show_adb_log(void) -{ - int pos; - int i; - - pos = g_adb_log_pos; - printf("ADB log pos: %d\n", pos); - for(i = 0; i < LEN_ADB_LOG; i++) { - pos--; - if(pos < 0) { - pos = LEN_ADB_LOG - 1; - } - printf("%d:%d: addr:%04x = %02x, st:%d\n", i, pos, - g_adb_log[pos].addr, g_adb_log[pos].val, - g_adb_log[pos].state); - } - printf("kbd: dev: %x, ctl: %x; mouse: dev: %x, ctl: %x\n", - g_kbd_dev_addr, g_kbd_ctl_addr, - g_mouse_dev_addr, g_mouse_ctl_addr); - printf("g_adb_state: %d, g_adb_interrupt_byte: %02x\n", - g_adb_state, g_adb_interrupt_byte); -} - -void -adb_error(void) -{ - halt_printf("Adb Error\n"); - - show_adb_log(); -} - - - -void -adb_add_kbd_srq() -{ - if(g_kbd_reg3_16bit & 0x200) { - /* generate SRQ */ - g_adb_interrupt_byte |= 0x08; - add_irq(IRQ_PENDING_ADB_KBD_SRQ); - } else { - printf("Got keycode but no kbd SRQ!\n"); - } -} - -void -adb_clear_kbd_srq() -{ - remove_irq(IRQ_PENDING_ADB_KBD_SRQ); - - /* kbd SRQ's are the only ones to handle now, so just clean it out */ - g_adb_interrupt_byte &= (~(0x08)); -} - -void -adb_add_data_int() -{ - if(g_c027_val & ADB_C027_DATA_INT) { - add_irq(IRQ_PENDING_ADB_DATA); - } -} - -void -adb_add_mouse_int() -{ - if(g_c027_val & ADB_C027_MOUSE_INT) { - add_irq(IRQ_PENDING_ADB_MOUSE); - } -} - -void -adb_clear_data_int() -{ - remove_irq(IRQ_PENDING_ADB_DATA); -} - -void -adb_clear_mouse_int() -{ - remove_irq(IRQ_PENDING_ADB_MOUSE); -} - - -void -adb_send_bytes(int num_bytes, word32 val0, word32 val1, word32 val2) -{ - word32 val; - int shift_amount; - int i; - - if((num_bytes >= 12) || (num_bytes >= MAX_ADB_DATA_PEND)) { - halt_printf("adb_send_bytes: %d is too many!\n", num_bytes); - } - - g_adb_state = ADB_SENDING_DATA; - g_adb_data_pending = num_bytes; - adb_add_data_int(); - - for(i = 0; i < num_bytes; i++) { - if(i < 4) { - val = val0; - } else if(i < 8) { - val = val1; - } else { - val = val2; - } - - shift_amount = 8*(3 - i); - g_adb_data[i] = (val >> shift_amount) & 0xff; - adb_printf("adb_send_bytes[%d] = %02x\n", i, g_adb_data[i]); - } -} - - -void -adb_send_1byte(word32 val) -{ - - if(g_adb_data_pending != 0) { - halt_printf("g_adb_data_pending: %d\n", g_adb_data_pending); - } - - adb_send_bytes(1, val << 24, 0, 0); -} - - - -void -adb_response_packet(int num_bytes, word32 val) -{ - - if(g_adb_data_pending != 0) { - halt_printf("adb_response_packet, but pending: %d\n", - g_adb_data_pending); - } - - g_adb_state = ADB_IDLE; - g_adb_data_pending = num_bytes; - g_adb_data[0] = val & 0xff; - g_adb_data[1] = (val >> 8) & 0xff; - g_adb_data[2] = (val >> 16) & 0xff; - g_adb_data[3] = (val >> 24) & 0xff; - if(num_bytes) { - g_adb_interrupt_byte |= 0x80 + num_bytes - 1; - } else { - g_adb_interrupt_byte |= 0x80; - } - - adb_printf("adb_response packet: %d: %08x\n", - num_bytes, val); - - adb_add_data_int(); -} - - -void -adb_kbd_reg0_data(int a2code, int is_up) -{ - if(g_kbd_reg0_pos >= MAX_ADB_KBD_REG3) { - /* too many keys, toss */ - halt_printf("Had to toss key: %02x, %d\n", a2code, is_up); - return; - } - - g_kbd_reg0_data[g_kbd_reg0_pos] = a2code + (is_up << 7); - - adb_printf("g_kbd_reg0_data[%d] = %02x\n", g_kbd_reg0_pos, - g_kbd_reg0_data[g_kbd_reg0_pos]); - - g_kbd_reg0_pos++; - - adb_add_kbd_srq(); -} - -void -adb_kbd_talk_reg0() -{ - word32 val0, val1; - word32 reg; - int num_bytes; - int num; - int i; - - num = 0; - val0 = g_kbd_reg0_data[0]; - val1 = g_kbd_reg0_data[1]; - - num_bytes = 0; - if(g_kbd_reg0_pos > 0) { - num_bytes = 2; - num = 1; - if((val0 & 0x7f) == 0x7f) { - /* reset */ - val1 = val0; - } else if(g_kbd_reg0_pos > 1) { - num = 2; - if((val1 & 0x7f) == 0x7f) { - /* If first byte some other key, don't */ - /* put RESET next! */ - num = 1; - val1 = 0xff; - } - } else { - val1 = 0xff; - } - } - - if(num) { - for(i = num; i < g_kbd_reg0_pos; i++) { - g_kbd_reg0_data[i-1] = g_kbd_reg0_data[i]; - } - g_kbd_reg0_pos -= num; - } - - reg = (val0 << 8) + val1; - - adb_printf("adb_kbd_talk0: %04x\n", reg); - - adb_response_packet(num_bytes, reg); - if(g_kbd_reg0_pos == 0) { - adb_clear_kbd_srq(); - } -} - -void -adb_set_config(word32 val0, word32 val1, word32 val2) -{ - int new_mouse; - int new_kbd; - int tmp1; - - new_mouse = val0 >> 4; - new_kbd = val0 & 0xf; - if(new_mouse != g_mouse_ctl_addr) { - printf("ADB config: mouse from %x to %x!\n", - g_mouse_ctl_addr, new_mouse); - adb_error(); - g_mouse_ctl_addr = new_mouse; - } - if(new_kbd != g_kbd_ctl_addr) { - printf("ADB config: kbd from %x to %x!\n", - g_kbd_ctl_addr, new_kbd); - adb_error(); - g_kbd_ctl_addr = new_kbd; - } - - - tmp1 = val2 >> 4; - if(tmp1 == 4) { - g_adb_repeat_delay = 0; - } else if(tmp1 < 4) { - g_adb_repeat_delay = (tmp1 + 1) * 15; - } else { - halt_printf("Bad ADB repeat delay: %02x\n", tmp1); - } - - tmp1 = val2 & 0xf; - if(g_rom_version >= 3) { - tmp1 = 9 - tmp1; - } - - switch(tmp1) { - case 0: - g_adb_repeat_rate = 1; - break; - case 1: - g_adb_repeat_rate = 2; - break; - case 2: - g_adb_repeat_rate = 3; - break; - case 3: - g_adb_repeat_rate = 3; - break; - case 4: - g_adb_repeat_rate = 4; - break; - case 5: - g_adb_repeat_rate = 5; - break; - case 6: - g_adb_repeat_rate = 7; - break; - case 7: - g_adb_repeat_rate = 15; - break; - case 8: - /* I don't know what this should be, ROM 03 uses it */ - g_adb_repeat_rate = 30; - break; - case 9: - /* I don't know what this should be, ROM 03 uses it */ - g_adb_repeat_rate = 60; - break; - default: - halt_printf("Bad repeat rate: %02x\n", tmp1); - } - -} - -void -adb_set_new_mode(word32 val) -{ - if(val & 0x03) { - printf("Disabling keyboard/mouse:%02x!\n", val); - } - - if(val & 0xa2) { - halt_printf("ADB set mode: %02x!\n", val); - adb_error(); - } - - g_adb_mode = val; -} - - -int -adb_read_c026() -{ - word32 ret; - int i; - - ret = 0; - switch(g_adb_state) { - case ADB_IDLE: - ret = g_adb_interrupt_byte; - g_adb_interrupt_byte = 0; - if(g_irq_pending & IRQ_PENDING_ADB_KBD_SRQ) { - g_adb_interrupt_byte |= 0x08; - } - if(g_adb_data_pending == 0) { - if(ret & 0x80) { - halt_printf("read_c026: ret:%02x, pend:%d\n", - ret, g_adb_data_pending); - } - adb_clear_data_int(); - } - if(g_adb_data_pending) { - if(g_adb_state != ADB_IN_CMD) { - g_adb_state = ADB_SENDING_DATA; - } - } - break; - case ADB_IN_CMD: - ret = 0; - break; - case ADB_SENDING_DATA: - ret = g_adb_data[0]; - for(i = 1; i < g_adb_data_pending; i++) { - g_adb_data[i-1] = g_adb_data[i]; - } - g_adb_data_pending--; - if(g_adb_data_pending <= 0) { - g_adb_data_pending = 0; - g_adb_state = ADB_IDLE; - adb_clear_data_int(); - } - break; - default: - halt_printf("Bad ADB state: %d!\n", g_adb_state); - adb_clear_data_int(); - break; - } - - adb_printf("Reading c026. Returning %02x, st: %02x, pend: %d\n", - ret, g_adb_state, g_adb_data_pending); - - adb_log(0xc026, ret); - return (ret & 0xff); -} - - -void -adb_write_c026(int val) -{ - word32 tmp; - int dev; - - adb_printf("Writing c026 with %02x\n", val); - adb_log(0x1c026, val); - - - switch(g_adb_state) { - case ADB_IDLE: - g_adb_cmd = val; - g_adb_cmd_so_far = 0; - g_adb_cmd_len = 0; - - dev = val & 0xf; - switch(val) { - case 0x01: /* Abort */ - adb_printf("Performing adb abort\n"); - /* adb_abort() */ - break; - case 0x03: /* Flush keyboard buffer */ - adb_printf("Flushing adb keyboard buffer\n"); - /* Do nothing */ - break; - case 0x04: /* Set modes */ - adb_printf("ADB set modes\n"); - g_adb_state = ADB_IN_CMD; - g_adb_cmd_len = 1; - break; - case 0x05: /* Clear modes */ - adb_printf("ADB clear modes\n"); - g_adb_state = ADB_IN_CMD; - g_adb_cmd_len = 1; - break; - case 0x06: /* Set config */ - adb_printf("ADB set config\n"); - g_adb_state = ADB_IN_CMD; - g_adb_cmd_len = 3; - break; - case 0x07: /* Sync */ - adb_printf("Performing sync cmd!\n"); - g_adb_state = ADB_IN_CMD; - if(g_rom_version == 1) { - g_adb_cmd_len = 4; - } else { - g_adb_cmd_len = 8; - } - break; - case 0x08: /* Write mem */ - adb_printf("Starting write_mem cmd\n"); - g_adb_state = ADB_IN_CMD; - g_adb_cmd_len = 2; - break; - case 0x09: /* Read mem */ - adb_printf("Performing read_mem cmd!\n"); - g_adb_state = ADB_IN_CMD; - g_adb_cmd_len = 2; - break; - case 0x0a: /* Read modes byte */ - printf("Performing read_modes cmd!\n"); - /* set_halt(1); */ - adb_send_1byte(g_adb_mode); - break; - case 0x0b: /* Read config bytes */ - printf("Performing read_configs cmd!\n"); - tmp = (g_mouse_ctl_addr << 20) + - (g_kbd_ctl_addr << 16) + - (g_adb_char_set << 12) + - (g_adb_layout_lang << 8) + - (g_adb_repeat_info << 0); - tmp = (0x82U << 24) + tmp; - adb_send_bytes(4, tmp, 0, 0); - break; - case 0x0d: /* Get Version */ - adb_printf("Performing get_version cmd!\n"); - val = 0; - if(g_rom_version == 1) { - /* ROM 01 = revision 5 */ - val = 5; - } else { - /* ROM 03 checks for rev >= 6 */ - val = 6; - } - adb_send_1byte(val); - break; - case 0x0e: /* Read avail char sets */ - adb_printf("Performing read avail char sets cmd!\n"); - adb_send_bytes(2, /* just 2 bytes */ - 0x08000000, /* number of ch sets=0x8 */ - 0, 0); - /* set_halt(1); */ - break; - case 0x0f: /* Read avail kbd layouts */ - adb_printf("Performing read avail kbd layouts cmd!\n"); - adb_send_bytes(0x2, /* number of kbd layouts=0xa */ - 0x0a000000, 0, 0); - /* set_halt(1); */ - break; - case 0x10: /* Reset */ - printf("ADB reset, cmd 0x10\n"); - do_reset(); - break; - case 0x11: /* Send ADB keycodes */ - adb_printf("Sending ADB keycodes\n"); - g_adb_state = ADB_IN_CMD; - g_adb_cmd_len = 1; - break; - case 0x12: /* ADB cmd 12: ROM 03 only! */ - if(g_rom_version >= 3) { - g_adb_state = ADB_IN_CMD; - g_adb_cmd_len = 2; - } else { - printf("ADB cmd 12, but not ROM 3!\n"); - adb_error(); - } - break; - case 0x13: /* ADB cmd 13: ROM 03 only! */ - if(g_rom_version >= 3) { - g_adb_state = ADB_IN_CMD; - g_adb_cmd_len = 2; - } else { - printf("ADB cmd 13, but not ROM 3!\n"); - adb_error(); - } - break; - case 0x73: /* Disable SRQ device 3: mouse */ - adb_printf("Disabling Mouse SRQ's (device 3)\n"); - /* HACK HACK...should deal with SRQs on mouse */ - break; - case 0xb0: case 0xb1: case 0xb2: case 0xb3: - case 0xb4: case 0xb5: case 0xb6: case 0xb7: - case 0xb8: case 0xb9: case 0xba: case 0xbb: - case 0xbc: case 0xbd: case 0xbe: case 0xbf: - /* Listen dev x reg 3 */ - adb_printf("Sending data to dev %x reg 3\n", dev); - g_adb_state = ADB_IN_CMD; - g_adb_cmd_len = 2; - break; - case 0xc0: case 0xc1: case 0xc2: case 0xc3: - case 0xc4: case 0xc5: case 0xc6: case 0xc7: - case 0xc8: case 0xc9: case 0xca: case 0xcb: - case 0xcc: case 0xcd: case 0xce: case 0xcf: - /* Talk dev x reg 0 */ - adb_printf("Performing talk dev %x reg 0\n", dev); - if(dev == g_kbd_dev_addr) { - adb_kbd_talk_reg0(); - } else { - printf("Unknown talk dev %x reg 0!\n", dev); - /* send no data, on SRQ, system polls devs */ - /* so we don't want to send anything */ - adb_error(); - } - break; - case 0xf0: case 0xf1: case 0xf2: case 0xf3: - case 0xf4: case 0xf5: case 0xf6: case 0xf7: - case 0xf8: case 0xf9: case 0xfa: case 0xfb: - case 0xfc: case 0xfd: case 0xfe: case 0xff: - /* Talk dev x reg 3 */ - adb_printf("Performing talk dev %x reg 3\n", dev); - if(dev == g_kbd_dev_addr) { - adb_response_packet(2, g_kbd_reg3_16bit); - } else { - printf("Performing talk dev %x reg 3!!\n", dev); - adb_error(); - } - break; - default: - /* The Gog's says ACS Demo 2 has a bug and writes to */ - /* c026 */ - // OG - if (val==0x84) - printf("ACS Demo2 (3: Colum& Music scroll) : discarding unknown controller command\n"); - else - halt_printf("ADB ucontroller cmd %02x unknown!\n", val); - - break; - } - break; - case ADB_IN_CMD: - adb_printf("Setting byte %d of cmd %02x to %02x\n", - g_adb_cmd_so_far, g_adb_cmd, val); - - g_adb_cmd_data[g_adb_cmd_so_far] = val; - g_adb_cmd_so_far++; - if(g_adb_cmd_so_far >= g_adb_cmd_len) { - adb_printf("Finished cmd %02x\n", g_adb_cmd); - do_adb_cmd(); - } - - break; - default: - printf("adb_state: %02x is unknown! Setting it to ADB_IDLE\n", - g_adb_state); - g_adb_state = ADB_IDLE; - adb_error(); - halt_on_all_c027 = 1; - break; - } - return; -} - -void -do_adb_cmd() -{ - int dev; - int new_kbd; - int addr; - int val; - - dev = g_adb_cmd & 0xf; - - g_adb_state = ADB_IDLE; - - switch(g_adb_cmd) { - case 0x04: /* Set modes */ - adb_printf("Performing ADB set mode: OR'ing in %02x\n", - g_adb_cmd_data[0]); - - val = g_adb_cmd_data[0] | g_adb_mode; - adb_set_new_mode(val); - - break; - case 0x05: /* clear modes */ - adb_printf("Performing ADB clear mode: AND'ing in ~%02x\n", - g_adb_cmd_data[0]); - - val = g_adb_cmd_data[0]; - val = g_adb_mode & (~val); - adb_set_new_mode(val); - break; - case 0x06: /* Set config */ - adb_printf("Set ADB config to %02x %02x %02x\n", - g_adb_cmd_data[0], g_adb_cmd_data[1],g_adb_cmd_data[2]); - - adb_set_config(g_adb_cmd_data[0], g_adb_cmd_data[1], - g_adb_cmd_data[2]); - - break; - case 0x07: /* SYNC */ - adb_printf("Performing ADB SYNC\n"); - adb_printf("data: %02x %02x %02x %02x\n", - g_adb_cmd_data[0], g_adb_cmd_data[1], g_adb_cmd_data[2], - g_adb_cmd_data[3]); - - adb_set_new_mode(g_adb_cmd_data[0]); - adb_set_config(g_adb_cmd_data[1], g_adb_cmd_data[2], - g_adb_cmd_data[3]); - - if(g_rom_version >= 3) { - adb_printf(" and cmd12:%02x %02x cmd13:%02x %02x\n", - g_adb_cmd_data[4], g_adb_cmd_data[5], - g_adb_cmd_data[6], g_adb_cmd_data[7]); - } - break; - case 0x08: /* Write mem */ - addr = g_adb_cmd_data[0]; - val = g_adb_cmd_data[1]; - write_adb_ram(addr, val); - break; - case 0x09: /* Read mem */ - addr = (g_adb_cmd_data[1] << 8) + g_adb_cmd_data[0]; - adb_printf("Performing mem read to addr %04x\n", addr); - adb_send_1byte(read_adb_ram(addr)); - break; - case 0x11: /* Send ADB keycodes */ - val = g_adb_cmd_data[0]; - adb_printf("Performing send ADB keycodes: %02x\n", val); - adb_virtual_key_update(val & 0x7f, val >> 7); - break; - case 0x12: /* ADB cmd12 */ - adb_printf("Performing ADB cmd 12\n"); - adb_printf("data: %02x %02x\n", g_adb_cmd_data[0], - g_adb_cmd_data[1]); - break; - case 0x13: /* ADB cmd13 */ - adb_printf("Performing ADB cmd 13\n"); - adb_printf("data: %02x %02x\n", g_adb_cmd_data[0], - g_adb_cmd_data[1]); - break; - case 0xb0: case 0xb1: case 0xb2: case 0xb3: - case 0xb4: case 0xb5: case 0xb6: case 0xb7: - case 0xb8: case 0xb9: case 0xba: case 0xbb: - case 0xbc: case 0xbd: case 0xbe: case 0xbf: - /* Listen dev x reg 3 */ - if(dev == g_kbd_dev_addr) { - if(g_adb_cmd_data[1] == 0xfe) { - /* change keyboard addr? */ - new_kbd = g_adb_cmd_data[0] & 0xf; - if(new_kbd != dev) { - printf("Moving kbd to dev %x!\n", - new_kbd); - adb_error(); - } - g_kbd_dev_addr = new_kbd; - } else if(g_adb_cmd_data[1] != 1) { - /* see what new device handler id is */ - printf("KBD listen to dev %x reg 3: 1:%02x\n", - dev, g_adb_cmd_data[1]); - adb_error(); - } - if(g_adb_cmd_data[0] != (word32)g_kbd_dev_addr) { - /* see if app is trying to change addr */ - printf("KBD listen to dev %x reg 3: 0:%02x!\n", - dev, g_adb_cmd_data[0]); - adb_error(); - } - g_kbd_reg3_16bit = ((g_adb_cmd_data[0] & 0xf) << 12) + - (g_kbd_reg3_16bit & 0x0fff); - } else if(dev == g_mouse_dev_addr) { - if(g_adb_cmd_data[0] != (word32)dev) { - /* see if app is trying to change mouse addr */ - printf("MOUS listen to dev %x reg3: 0:%02x!\n", - dev, g_adb_cmd_data[0]); - adb_error(); - } - if(g_adb_cmd_data[1] != 1 && g_adb_cmd_data[1] != 2) { - /* see what new device handler id is */ - printf("MOUS listen to dev %x reg 3: 1:%02x\n", - dev, g_adb_cmd_data[1]); - adb_error(); - } - } else { - printf("Listen cmd to dev %x reg3????\n", dev); - printf("data0: %02x, data1: %02x ????\n", - g_adb_cmd_data[0], g_adb_cmd_data[1]); - adb_error(); - } - break; - default: - printf("Doing adb_cmd %02x: UNKNOWN!\n", g_adb_cmd); - break; - } -} - - -int -adb_read_c027() -{ - word32 ret; - - if(halt_on_all_c027) { - halt_printf("halting on all c027 reads!\n"); - } - - if(g_c027_val & (~ADB_C027_NEG_MASK)) { - halt_printf("read_c027: g_c027_val: %02x\n", g_c027_val); - } - - ret = (g_c027_val & ADB_C027_NEG_MASK); - - if(g_adb_mouse_valid_data) { - ret |= ADB_C027_MOUSE_DATA; - } - - if(g_adb_interrupt_byte != 0) { - ret |= ADB_C027_DATA_VALID; - } else if(g_adb_data_pending > 0) { - if((g_adb_state != ADB_IN_CMD)) { - ret |= ADB_C027_DATA_VALID; - } - } - - if(g_adb_mouse_coord) { - ret |= ADB_C027_MOUSE_COORD; - } - -#if 0 - adb_printf("Read c027: %02x, int_byte: %02x, d_pend: %d\n", - ret, g_adb_interrupt_byte, g_adb_data_pending); -#endif - -#if 0 - adb_log(0xc027, ret); -#endif - return ret; -} - -void -adb_write_c027(int val) -{ - word32 old_val; - word32 new_int; - word32 old_int; - - adb_printf("Writing c027 with %02x\n", val); - adb_log(0x1c027, val); - - - old_val = g_c027_val; - - g_c027_val = (val & ADB_C027_NEG_MASK); - new_int = g_c027_val & ADB_C027_MOUSE_INT; - old_int = old_val & ADB_C027_MOUSE_INT; - if(!new_int && old_int) { - adb_clear_mouse_int(); - } - - new_int = g_c027_val & ADB_C027_DATA_INT; - old_int = old_val & ADB_C027_DATA_INT; - if(!new_int && old_int) { - /* ints were on, now off */ - adb_clear_data_int(); - } - - if(g_c027_val & ADB_C027_KBD_INT) { - halt_printf("Can't support kbd interrupts!\n"); - } - - return; -} - -int -read_adb_ram(word32 addr) -{ - int val; - - adb_printf("Reading adb ram addr: %02x\n", addr); - - if(addr >= 0x100) { - if(addr >= 0x1000 && addr < 0x2000) { - /* ROM self-test checksum */ - if(addr == 0x1400) { - val = 0x72; - } else if(addr == 0x1401) { - val = 0xf7; - } else { - val = 0; - } - } else { - printf("adb ram addr out of range: %04x!\n", addr); - val = 0; - } - } else { - val = adb_memory[addr]; - if((addr == 0xb) && (g_rom_version == 1)) { - // read special key state byte for Out of This World - val = (g_c025_val >> 1) & 0x43; - val |= (g_c025_val << 2) & 0x4; - val |= (g_c025_val >> 2) & 0x10; - } - if((addr == 0xc) && (g_rom_version >= 3)) { - // read special key state byte for Out of This World - val = g_c025_val & 0xc7; - printf("val is %02x\n", val); - } - } - - adb_printf("adb_ram returning %02x\n", val); - return val; -} - -void -write_adb_ram(word32 addr, int val) -{ - - adb_printf("Writing adb_ram addr: %02x: %02x\n", addr, val); - - if(addr >= 0x100) { - printf("write adb_ram addr: %02x: %02x!\n", addr, val); - adb_error(); - } else { - adb_memory[addr] = val; - } -} - -int -adb_get_keypad_xy(int get_y) -{ - int x, y; - int key; - int num_keys; - int i, j; - - key = 1; - num_keys = 0; - x = 0; - y = 0; - for(i = 0; i < 3; i++) { - for(j = 0; j < 3; j++) { - if(g_keypad_key_is_down[key]) { - num_keys++; - x = x + (j - 1)*32768; - y = y + (1 - i)*32768; - } - key++; - } - } - if(num_keys == 0) { - num_keys = 1; - } - - adb_printf("get_xy=%d, num_keys: %d, x:%d, y:%d\n", get_y, - num_keys, x, y); - - if(get_y) { - return y / num_keys; - } else { - return x / num_keys; - } -} - -int -update_mouse(int x, int y, int button_states, int buttons_valid) -{ - double dcycs; - int button1_changed; - int mouse_moved; - int unhide; - int pos; - int i; - - dcycs = g_cur_dcycs; - - g_mouse_raw_x = x; - g_mouse_raw_y = y; - - unhide = 0; - if(x < 0) { - x = 0; - unhide = 1; - } - if(x >= 640) { - x = 639; - unhide = 1; - } - if(y < 0) { - y = 0; - unhide = 1; - } - if(y >= 400) { - y = 399; - unhide = 1; - } - - - g_unhide_pointer = unhide && !g_warp_pointer; - - if(!g_warp_pointer) { - if(g_hide_pointer && g_unhide_pointer) { - /* cursor has left a2 window, show it */ - g_hide_pointer = 0; - x_hide_pointer(0); - } - if((g_num_lines_prev_superhires == 200) && - (g_num_lines_prev_superhires640 == 0) && - ((g_slow_memory_ptr[0x19d00] & 0x80) == 0)) { - // In 320-mode superhires, cut mouse range in half - x = x >> 1; - } - y = y >> 1; - } - - mouse_compress_fifo(dcycs); - -#if 0 - printf("Update Mouse called with buttons:%d x,y:%d,%d, fifo:%d,%d, " - " a2: %d,%d\n", buttons_valid, x, y, - g_mouse_fifo[0].x, g_mouse_fifo[0].y, - g_mouse_a2_x, g_mouse_a2_y); -#endif - - if((buttons_valid < 0) && g_warp_pointer) { - /* Warping the pointer causes it to jump here...this is not */ - /* real motion, just update info and get out */ - g_mouse_a2_x += (x - g_mouse_fifo[0].x); - g_mouse_a2_y += (y - g_mouse_fifo[0].y); - g_mouse_fifo[0].x = x; - g_mouse_fifo[0].y = y; - return 0; - } - -#if 0 - printf("...real move, warp: %d, %d, new x: %d, %d, a2:%d,%d\n", - g_mouse_warp_x, g_mouse_warp_y, g_mouse_fifo[0].x, - g_mouse_fifo[0].y, g_mouse_a2_x, g_mouse_a2_y); -#endif - - mouse_moved = (g_mouse_fifo[0].x != x) || (g_mouse_fifo[0].y != y); - - g_mouse_a2_x += g_mouse_warp_x; - g_mouse_a2_y += g_mouse_warp_y; - g_mouse_fifo[0].x = x; - g_mouse_fifo[0].y = y; - g_mouse_fifo[0].dcycs = dcycs; - g_mouse_warp_x = 0; - g_mouse_warp_y = 0; - - button1_changed = (buttons_valid & 1) && - ((button_states & 1) != (g_mouse_fifo[0].buttons & 1)); - - if((button_states & 4) && !(g_mouse_fifo[0].buttons & 4) && - (buttons_valid & 4)) { - /* right button pressed */ - adb_increment_speed(); - } - if((button_states & 2) && !(g_mouse_fifo[0].buttons & 2) && - (buttons_valid & 2)) { - /* middle button pressed */ - halt2_printf("Middle button pressed\n"); - } - - pos = g_mouse_fifo_pos; - if((pos < (ADB_MOUSE_FIFO - 2)) && button1_changed) { - /* copy delta to overflow, set overflow */ - /* overflow ensures the mouse button state is precise at */ - /* button up/down times. Using a mouse event list where */ - /* deltas accumulate until a button change would work, too */ - for(i = pos; i >= 0; i--) { - g_mouse_fifo[i + 1] = g_mouse_fifo[i]; /* copy struct*/ - } - g_mouse_fifo_pos = pos + 1; - } - - g_mouse_fifo[0].buttons = (button_states & buttons_valid) | - (g_mouse_fifo[0].buttons & ~buttons_valid); - - if(mouse_moved || button1_changed) { - if( (g_mouse_ctl_addr == g_mouse_dev_addr) && - ((g_adb_mode & 0x2) == 0)) { - g_adb_mouse_valid_data = 1; - adb_add_mouse_int(); - } - } - - return mouse_moved; -} - -int -mouse_read_c024(double dcycs) -{ - word32 ret; - word32 tool_start; - int em_active; - int target_x, target_y; - int delta_x, delta_y; - int a2_x, a2_y; - int mouse_button; - int clamped; - int pos; - - if(((g_adb_mode & 0x2) != 0) || (g_mouse_dev_addr != g_mouse_ctl_addr)){ - /* mouse is off, return 0, or mouse is not autopoll */ - g_adb_mouse_valid_data = 0; - adb_clear_mouse_int(); - return 0; - } - - mouse_compress_fifo(dcycs); - - pos = g_mouse_fifo_pos; - target_x = g_mouse_fifo[pos].x; - target_y = g_mouse_fifo[pos].y; - mouse_button = (g_mouse_fifo[pos].buttons & 1); - delta_x = target_x - g_mouse_a2_x; - delta_y = target_y - g_mouse_a2_y; - - clamped = 0; - if(delta_x > 0x3f) { - delta_x = 0x3f; - clamped = 1; - } else if(delta_x < -0x3f) { - delta_x = -0x3f; - clamped = 1; - } - if(delta_y > 0x3f) { - delta_y = 0x3f; - clamped = 1; - } else if(delta_y < -0x3f) { - delta_y = -0x3f; - clamped = 1; - } - - if(pos > 0) { - /* peek into next entry's button info if we are not clamped */ - /* and we're returning the y-coord */ - if(!clamped && g_adb_mouse_coord) { - mouse_button = g_mouse_fifo[pos - 1].buttons & 1; - } - } - - if(g_adb_mouse_coord) { - /* y coord */ - delta_x = 0; /* clear unneeded x delta */ - } else { - delta_y = 0; /* clear unneeded y delta */ - } - - - adb_printf(" pre a2_x:%02x,%02x,%02x,%02x\n", - g_slow_memory_ptr[0x100e9], g_slow_memory_ptr[0x100ea], - g_slow_memory_ptr[0x100eb], g_slow_memory_ptr[0x100ec]); - adb_printf(" pre a2_x:%02x,%02x,%02x,%02x\n", - g_slow_memory_ptr[0x10190], g_slow_memory_ptr[0x10192], - g_slow_memory_ptr[0x10191], g_slow_memory_ptr[0x10193]); - - /* Update event manager internal state */ - tool_start = (g_slow_memory_ptr[0x103ca] << 16) + - (g_slow_memory_ptr[0x103c9] << 8) + - g_slow_memory_ptr[0x103c8]; - - em_active = 0; - if((tool_start >= 0x20000) && (tool_start < (g_mem_size_total - 28)) ) { - /* seems to be valid ptr to addr of mem space for tools */ - /* see if event manager appears to be active */ - em_active = g_memory_ptr[tool_start + 6*4] + - (g_memory_ptr[tool_start + 6*4 + 1] << 8); - if(g_warp_pointer) { - em_active = 0; - } - } - - a2_x = g_mouse_a2_x; - a2_y = g_mouse_a2_y; - - if(em_active) { - if((!g_hide_pointer) && (g_num_lines_prev_superhires == 200) && - !g_unhide_pointer) { - /* if super-hires and forcing tracking, then hide */ - g_hide_pointer = 1; - x_hide_pointer(1); - } - if(g_adb_mouse_coord == 0) { - /* update x coord values */ - g_slow_memory_ptr[0x47c] = a2_x & 0xff; - g_slow_memory_ptr[0x57c] = a2_x >> 8; - g_memory_ptr[0x47c] = a2_x & 0xff; - g_memory_ptr[0x57c] = a2_x >> 8; - - g_slow_memory_ptr[0x10190] = a2_x & 0xff; - g_slow_memory_ptr[0x10192] = a2_x >> 8; - } else { - g_slow_memory_ptr[0x4fc] = a2_y & 0xff; - g_slow_memory_ptr[0x5fc] = a2_y >> 8; - g_memory_ptr[0x4fc] = a2_y & 0xff; - g_memory_ptr[0x5fc] = a2_y >> 8; - - g_slow_memory_ptr[0x10191] = a2_y & 0xff; - g_slow_memory_ptr[0x10193] = a2_y >> 8; - } - } else { - if(g_hide_pointer && !g_warp_pointer) { - g_hide_pointer = 0; - x_hide_pointer(0); - } - } - - ret = ((!mouse_button) << 7) + ((delta_x | delta_y) & 0x7f); - if(g_adb_mouse_coord) { - g_mouse_a2_button = mouse_button; /* y coord has button*/ - } else { - ret |= 0x80; /* mouse button not down on x coord rd */ - } - - a2_x += delta_x; - a2_y += delta_y; - g_mouse_a2_x = a2_x; - g_mouse_a2_y = a2_y; - if(g_mouse_fifo_pos) { - if((target_x == a2_x) && (target_y == a2_y) && - (g_mouse_a2_button == mouse_button)) { - g_mouse_fifo_pos--; - } - } - - - adb_printf("Read c024, mouse is_y:%d, %02x, vbl:%08x, dcyc:%f, em:%d\n", - g_adb_mouse_coord, ret, g_vbl_count, dcycs, em_active); - adb_printf("...mouse targ_x:%d,%d delta_x,y:%d,%d fifo:%d, a2:%d,%d\n", - target_x, target_y, delta_x, delta_y, g_mouse_fifo_pos, - a2_x, a2_y); - adb_printf(" post a2_x:%02x,%02x,%02x,%02x\n", - g_slow_memory_ptr[0x10190], g_slow_memory_ptr[0x10192], - g_slow_memory_ptr[0x10191], g_slow_memory_ptr[0x10193]); - - if((g_mouse_fifo_pos == 0) && (g_mouse_fifo[0].x == a2_x) && - (g_mouse_fifo[0].y == a2_y) && - ((g_mouse_fifo[0].buttons & 1) == g_mouse_a2_button)) { - g_adb_mouse_valid_data = 0; - adb_clear_mouse_int(); - } - - g_adb_mouse_coord = !g_adb_mouse_coord; - return ret; -} - -void -mouse_compress_fifo(double dcycs) -{ - int pos; - - /* The mouse fifo exists so that fast button changes don't get lost */ - /* if the emulator lags behind the mouse events */ - /* But the FIFO means really old mouse events are saved if */ - /* the emulated code isn't looking at the mouse registers */ - /* This routine compresses all mouse events > 0.5 seconds old */ - - for(pos = g_mouse_fifo_pos; pos >= 1; pos--) { - if(g_mouse_fifo[pos].dcycs < (dcycs - 500*1000.0)) { - /* Remove this entry */ - adb_printf("Old mouse FIFO pos %d removed\n", pos); - g_mouse_fifo_pos = pos - 1; - continue; - } - /* Else, stop searching the FIFO */ - break; - } -} - -void -adb_key_event(int a2code, int is_up) -{ - word32 special; - word32 vbl_count; - int key; - int hard_key; - int pos; - int tmp_ascii; - int ascii; - - if(is_up) { - adb_printf("adb_key_event, key:%02x, is up, g_key_down: %02x\n", - a2code, g_key_down); - } - - if(a2code < 0 || a2code > 0x7f) { - halt_printf("add_key_event: a2code: %04x!\n", a2code); - return; - } - - if(!is_up && a2code == 0x35) { - /* ESC pressed, see if ctrl & cmd key down */ - if(CTRL_DOWN && CMD_DOWN) { - /* Desk mgr int */ - printf("Desk mgr int!\n"); - - g_adb_interrupt_byte |= 0x20; - adb_add_data_int(); - } - } - - /* convert key to ascii, if possible */ - hard_key = 0; - if(a2_key_to_ascii[a2code][1] & 0xef00) { - /* special key */ - } else { - /* we have ascii */ - hard_key = 1; - } - - pos = 1; - ascii = a2_key_to_ascii[a2code][1]; - if(CAPS_LOCK_DOWN && (ascii >= 'a' && ascii <= 'z')) { - pos = 2; - if(SHIFT_DOWN && (g_adb_mode & 0x40)) { - /* xor shift mode--capslock and shift == lowercase */ - pos = 1; - } - } else if(SHIFT_DOWN) { - pos = 2; - } - - ascii = a2_key_to_ascii[a2code][pos]; - if(CTRL_DOWN) { - tmp_ascii = a2_key_to_ascii[a2code][3]; - if(tmp_ascii >= 0) { - ascii = tmp_ascii; - } - } - key = (ascii & 0x7f) + 0x80; - - special = (ascii >> 8) & 0xff; - if(ascii < 0) { - printf("ascii1: %d, a2code: %02x, pos: %d\n", ascii,a2code,pos); - ascii = 0; - special = 0; - } - - - if(!is_up) { - if(hard_key) { - g_kbd_buf[g_kbd_chars_buffered] = key; - g_kbd_chars_buffered++; - if(g_kbd_chars_buffered >= MAX_KBD_BUF) { - g_kbd_chars_buffered = MAX_KBD_BUF - 1; - } - g_key_down = 1; - g_a2code_down = a2code; - - /* first key down, set up autorepeat */ - vbl_count = g_vbl_count; - if(g_config_control_panel) { - vbl_count = g_cfg_vbl_count; - } - g_adb_repeat_vbl = vbl_count + g_adb_repeat_delay; - if(g_adb_repeat_delay == 0) { - g_key_down = 0; - } - g_hard_key_down = 1; - } - - g_c025_val = g_c025_val | special; - adb_printf("new c025_or: %02x\n", g_c025_val); - } else { - if(hard_key && (a2code == g_a2code_down)) { - g_hard_key_down = 0; - /* Turn off repeat */ - g_key_down = 0; - } - - g_c025_val = g_c025_val & (~ special); - adb_printf("new c025_and: %02x\n", g_c025_val); - } - - if(g_key_down) { - g_c025_val = g_c025_val & (~0x20); - } else { - /* If no hard key down, set update mod latch */ - g_c025_val = g_c025_val | 0x20; - } - -} - -word32 -adb_read_c000() -{ - word32 vbl_count; - - if( ((g_kbd_buf[0] & 0x80) == 0) && (g_key_down == 0)) { - /* nothing happening, check clipboard */ - int c = clipboard_get_char(); - if(c) { - /* inject clipboard char into keyboard buffer */ - g_kbd_buf[0] = c; - } - /* just get out */ - return g_kbd_buf[0]; - } - if(g_kbd_buf[0] & 0x80) { - /* got one */ - if((g_kbd_read_no_update++ > 5) && (g_kbd_chars_buffered > 1)) { - /* read 5 times, keys pending, let's move it along */ - printf("Read %02x %d times, tossing\n", g_kbd_buf[0], - g_kbd_read_no_update); - adb_access_c010(); - } - } else { - vbl_count = g_vbl_count; - if(g_config_control_panel) { - vbl_count = g_cfg_vbl_count; - } - if(g_key_down && vbl_count >= g_adb_repeat_vbl) { - /* repeat the g_key_down */ - g_c025_val |= 0x8; - adb_key_event(g_a2code_down, 0); - g_adb_repeat_vbl = vbl_count + g_adb_repeat_rate; - } - } - - return g_kbd_buf[0]; -} - -word32 -adb_access_c010() -{ - int tmp; - int i; - - g_kbd_read_no_update = 0; - - tmp = g_kbd_buf[0] & 0x7f; - g_kbd_buf[0] = tmp; - - tmp = tmp | (g_hard_key_down << 7); - if(g_kbd_chars_buffered) { - for(i = 1; i < g_kbd_chars_buffered; i++) { - g_kbd_buf[i - 1] = g_kbd_buf[i]; - } - g_kbd_chars_buffered--; - } - - g_c025_val = g_c025_val & (~ (0x08)); - - return tmp; -} - -word32 -adb_read_c025() -{ - return g_c025_val; -} - -int -adb_is_cmd_key_down() -{ - return CMD_DOWN; -} - -int -adb_is_option_key_down() -{ - return OPTION_DOWN; -} - -void -adb_increment_speed() -{ - const char *str; - - g_limit_speed++; - if(g_limit_speed > 3) { - g_limit_speed = 0; - } - - str = ""; - switch(g_limit_speed) { - case 0: - str = "...as fast as possible!"; - break; - case 1: - str = "...1.024MHz!"; - break; - case 2: - str = "...2.8MHz!"; - break; - case 3: - str = "...8.0MHz!"; - break; - } - printf("Toggling g_limit_speed to %d%s\n", g_limit_speed, str); -} - -void -adb_physical_key_update(int a2code, int is_up) -{ - int autopoll; - int special; - int ascii_and_type; - int ascii; - - /* this routine called by xdriver to pass raw codes--handle */ - /* ucontroller and ADB bus protocol issues here */ - /* if autopoll on, pass it on through to c025,c000 regs */ - /* else only put it in kbd reg 3, and pull SRQ if needed */ - - adb_printf("adb_phys_key_update: %02x, %d\n", a2code, is_up); - - adb_printf("Handle a2code: %02x, is_up: %d\n", a2code, is_up); - - if(a2code < 0 || a2code > 0x7f) { - halt_printf("a2code: %04x!\n", a2code); - return; - } - - /* Remap 0x7b-0x7e to 0x3b-0x3e (arrow keys on new mac keyboards) */ - if(a2code >= 0x7b && a2code <= 0x7e) { - a2code = a2code - 0x40; - } - - /* Now check for special keys (function keys, etc) */ - ascii_and_type = a2_key_to_ascii[a2code][1]; - special = 0; - if((ascii_and_type & 0xf000) == 0x8000) { - /* special function key */ - special = ascii_and_type & 0xff; - switch(special) { - case 0x01: /* F1 - remap to cmd */ - a2code = 0x37; - special = 0; - break; - case 0x02: /* F2 - remap to option */ - a2code = 0x3a; - special = 0; - break; - case 0x03: /* F3 - remap to escape for OS/2 */ - a2code = 0x35; - special = 0; - break; - case 0x0c: /* F12 - remap to reset */ - a2code = 0x7f; - special = 0; - break; - default: - break; - } - } - - /* CUA clipboard paste - for those that remember ctrl-insert/shift-insert */ - if(is_up == 0 && a2code == 0x72 && SHIFT_DOWN) { - clipboard_paste(); - } - - /* Only process reset requests here */ - if(is_up == 0 && a2code == 0x7f && CTRL_DOWN) { - /* Reset pressed! */ - printf("Reset pressed since CTRL_DOWN: %d\n", CTRL_DOWN); - do_reset(); - return; - } - - if(special && !is_up) { - switch(special) { -// OG Disabled special keys (but warp) -#ifndef ACTIVEGS - case 0x04: /* F4 - emulator config panel */ - if (CMD_DOWN) - { - printf("Quit!\n"); - iwm_shut(); - my_exit(1); - } - else - { - cfg_toggle_config_panel(); - } - break; - case 0x05: /* F5 - emulator clipboard paste */ - clipboard_paste(); - break; - case 0x06: /* F6 - emulator speed */ - if(SHIFT_DOWN) { - halt2_printf("Shift-F6 pressed\n"); - } else { - adb_increment_speed(); - } - break; - case 0x07: /* F7 - fast disk emul */ - g_fast_disk_emul = !g_fast_disk_emul; - printf("g_fast_disk_emul is now %d\n", - g_fast_disk_emul); - break; -#endif - case 0x08: /* F8 - warp pointer */ - g_warp_pointer = !g_warp_pointer; - if(g_hide_pointer != g_warp_pointer) { - g_hide_pointer = g_warp_pointer; - x_hide_pointer(g_hide_pointer); - } - break; -#ifndef ACTIVEGS - case 0x09: /* F9 - swap paddles */ - if(SHIFT_DOWN) { - g_swap_paddles = !g_swap_paddles; - printf("Swap paddles is now: %d\n", - g_swap_paddles); - } else { - g_invert_paddles = !g_invert_paddles; - printf("Invert paddles is now: %d\n", - g_invert_paddles); - } - break; - case 0x0a: /* F10 - change a2vid paletter */ - if (SHIFT_DOWN) { -#ifdef TOGGLE_STATUS - extern void x_toggle_status_lines(); - x_toggle_status_lines(); -#endif - } else if (CMD_DOWN) { - do_reset(); - return; - } else { - change_a2vid_palette((g_a2vid_palette + 1) & 0xf); - } - break; - case 0x0b: /* F11 - full screen */ - g_fullscreen = !g_fullscreen; - x_full_screen(g_fullscreen); - break; -#endif - } - - return; - } - /* Handle Keypad Joystick here partly...if keypad key pressed */ - /* while in Keypad Joystick mode, do not pass it on as a key press */ - if((ascii_and_type & 0xff00) == 0x1000) { - /* Keep track of keypad number keys being up or down even */ - /* if joystick mode isn't keypad. This avoid funny cases */ - /* if joystick mode is changed while a key is pressed */ - ascii = ascii_and_type & 0xff; - if(ascii > 0x30 && ascii <= 0x39) { - g_keypad_key_is_down[ascii - 0x30] = !is_up; - } - if(g_joystick_type == JOYSTICK_TYPE_KEYPAD) { - /* If Joystick type is keypad, then do not let these */ - /* keypress pass on further, except for cmd/opt */ - if(ascii == 0x30) { - /* remap '0' to cmd */ - a2code = 0x37; - } else if(ascii == 0x2e || ascii == 0x2c) { - /* remap '.' and ',' to option */ - a2code = 0x3a; - } else { - /* Just ignore it in this mode */ - return; - } - } - } - - autopoll = 1; - if(g_adb_mode & 1) { - /* autopoll is explicitly off */ - autopoll = 0; - } - if(g_kbd_dev_addr != g_kbd_ctl_addr) { - /* autopoll is off because ucontroller doesn't know kbd moved */ - autopoll = 0; - } - if(g_config_control_panel) { - /* always do autopoll */ - autopoll = 1; - } - - - if(is_up) { - if(!autopoll) { - /* no auto keys, generate SRQ! */ - adb_kbd_reg0_data(a2code, is_up); - } else { - adb_virtual_key_update(a2code, is_up); - } - } else { - if(!autopoll) { - /* no auto keys, generate SRQ! */ - adb_kbd_reg0_data(a2code, is_up); - } else { - /* was up, now down */ - adb_virtual_key_update(a2code, is_up); - } - } -} - -void -adb_virtual_key_update(int a2code, int is_up) -{ - int i; - int bitpos; - word32 mask; - - adb_printf("Virtual handle a2code: %02x, is_up: %d\n", a2code, is_up); - - if(a2code < 0 || a2code > 0x7f) { - halt_printf("a2code: %04x!\n", a2code); - return; - } - - i = (a2code >> 5) & 3; - bitpos = a2code & 0x1f; - mask = (1 << bitpos); - - if(is_up) { - if(g_virtual_key_up[i] & mask) { - /* already up, do nothing */ - } else { - g_virtual_key_up[i] |= mask; - adb_key_event(a2code, is_up); - } - } else { - if(g_virtual_key_up[i] & mask) { - g_virtual_key_up[i] &= (~mask); - adb_key_event(a2code, is_up); - } - } -} - -void -adb_all_keys_up() -{ - word32 mask; - int i, j; - - for(i = 0; i < 4; i++) { - for(j = 0; j < 32; j++) { - mask = 1 << j; - if((g_virtual_key_up[i] & mask) == 0) { - /* create key-up event */ - adb_physical_key_update(i*32 + j, 1); - } - } - } -} - -void -adb_kbd_repeat_off() -{ - g_key_down = 0; -} +/* + GSport - an Apple //gs Emulator + Copyright (C) 2010 - 2019 by GSport contributors + Copyright (C) 2016 - 2018 Dagen Brock + + Based on the KEGS emulator written by and Copyright (C) 2003 Kent Dickey + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 2 of the License, or (at your + option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +/* adb_mode bit 3 and bit 2 (faster repeats for arrows and space/del) not done*/ + +#include "adb.h" +#include "glog.h" + +int g_fullscreen = 0; +int g_grabmouse = 0; + +extern int Verbose; +extern word32 g_vbl_count; +extern int g_num_lines_prev_superhires640; +extern int g_num_lines_prev_superhires; +extern int g_rom_version; +extern int g_fast_disk_emul; +extern int g_limit_speed; +extern int g_irq_pending; +extern int g_swap_paddles; +extern int g_invert_paddles; +extern int g_joystick_type; +extern int g_a2vid_palette; +extern int g_config_control_panel; +extern int g_screenshot_requested; +extern word32 g_cfg_vbl_count; +extern double g_cur_dcycs; +extern byte *g_slow_memory_ptr; +extern byte *g_memory_ptr; +extern word32 g_mem_size_total; + +enum { + ADB_IDLE = 0, + ADB_IN_CMD, + ADB_SENDING_DATA, +}; + +#define ADB_C027_MOUSE_DATA 0x80 +#define ADB_C027_MOUSE_INT 0x40 +#define ADB_C027_DATA_VALID 0x20 +#define ADB_C027_DATA_INT 0x10 +#define ADB_C027_KBD_VALID 0x08 +#define ADB_C027_KBD_INT 0x04 +#define ADB_C027_MOUSE_COORD 0x02 +#define ADB_C027_CMD_FULL 0x01 + +#define ADB_C027_NEG_MASK ( ~( \ + ADB_C027_MOUSE_DATA | ADB_C027_DATA_VALID | \ + ADB_C027_KBD_VALID | ADB_C027_MOUSE_COORD | \ + ADB_C027_CMD_FULL)) + + +int halt_on_all_c027 = 0; + +word32 g_adb_repeat_delay = 45; +word32 g_adb_repeat_rate = 3; +word32 g_adb_repeat_info = 0x23; +word32 g_adb_char_set = 0x0; +word32 g_adb_layout_lang = 0x0; + +word32 g_adb_interrupt_byte = 0; +int g_adb_state = ADB_IDLE; + +word32 g_adb_cmd = (word32)-1; +int g_adb_cmd_len = 0; +int g_adb_cmd_so_far = 0; +word32 g_adb_cmd_data[16]; + +#define MAX_ADB_DATA_PEND 16 + +word32 g_adb_data[MAX_ADB_DATA_PEND]; +int g_adb_data_pending = 0; + +word32 g_c027_val = 0; +word32 g_c025_val = 0; + +byte adb_memory[256]; + +word32 g_adb_mode = 0; /* mode set via set_modes, clear_modes */ + +int g_warp_pointer = 0; +int g_hide_pointer = 0; +int g_unhide_pointer = 0; + +int g_mouse_a2_x = 0; +int g_mouse_a2_y = 0; +int g_mouse_a2_button = 0; +int g_mouse_fifo_pos = 0; +int g_mouse_raw_x = 0; +int g_mouse_raw_y = 0; + +#define ADB_MOUSE_FIFO 8 + +STRUCT(Mouse_fifo) { + double dcycs; + int x; + int y; + int buttons; + int delta_x; + int delta_y; + int dxrd; + int dyrd; +}; + +Mouse_fifo g_mouse_fifo[ADB_MOUSE_FIFO] = { { 0, 0, 0, 0, 0, 0 ,0 ,0} }; + +int g_mouse_warp_x = 0; +int g_mouse_warp_y = 0; + +int g_adb_mouse_valid_data = 0; +int g_adb_mouse_coord = 0; + +#define MAX_KBD_BUF 8 + +int g_key_down = 0; +int g_hard_key_down = 0; +int g_a2code_down = 0; +int g_kbd_read_no_update = 0; +int g_kbd_chars_buffered = 0; +int g_kbd_buf[MAX_KBD_BUF]; +word32 g_adb_repeat_vbl = 0; + +int g_kbd_dev_addr = 2; /* ADB physical kbd addr */ +int g_mouse_dev_addr = 3; /* ADB physical mouse addr */ + +int g_kbd_ctl_addr = 2; /* ADB microcontroller's kbd addr */ +int g_mouse_ctl_addr = 3; /* ADB ucontroller's mouse addr*/ +/* above are ucontroller's VIEW of where mouse/kbd */ +/* are...if they are moved, mouse/keyboard funcs */ +/* should stop (c025, c000, c024, etc). */ + +word32 g_virtual_key_up[4]; /* bitmask of all possible 128 a2codes */ + /* indicates which keys are up=1 by bit */ + +int g_keypad_key_is_down[10] = { 0 }; /* List from 0-9 of which keypad */ + /* keys are currently pressed */ + + +#define SHIFT_DOWN ( (g_c025_val & 0x01) ) +#define CTRL_DOWN ( (g_c025_val & 0x02) ) +#define CAPS_LOCK_DOWN ( (g_c025_val & 0x04) ) +#define OPTION_DOWN ( (g_c025_val & 0x40) ) +#define CMD_DOWN ( (g_c025_val & 0x80) ) + + +#define MAX_ADB_KBD_REG3 16 + +int g_kbd_reg0_pos = 0; +int g_kbd_reg0_data[MAX_ADB_KBD_REG3]; +int g_kbd_reg3_16bit = 0x602; /* also set in adb_reset()! */ + + +int g_adb_init = 0; + +void adb_init() { + int keycode; + int i; + + if(g_adb_init) { + halt_printf("g_adb_init = %d!\n", g_adb_init); + } + g_adb_init = 1; + + for(i = 0; i < 128; i++) { + keycode = a2_key_to_ascii[i][0]; + if(keycode != i) { + glogf("ADB keycode lost/skipped: i=%x: keycode=%x", i, keycode); + my_exit(1); + } + } + + g_c025_val = 0; + + for(i = 0; i < 4; i++) { + g_virtual_key_up[i] = -1; + } + + for(i = 0; i < 10; i++) { + g_keypad_key_is_down[i] = 0; + } + + adb_reset(); +} + +// OG Added adb_shut() +void adb_shut() { + g_adb_init = 0; +} + +void adb_reset() { + + g_c027_val = 0; + + g_key_down = 0; + + g_kbd_dev_addr = 2; + g_mouse_dev_addr = 3; + + g_kbd_ctl_addr = 2; + g_mouse_ctl_addr = 3; + + adb_clear_data_int(); + adb_clear_mouse_int(); + adb_clear_kbd_srq(); + + g_adb_data_pending = 0; + g_adb_interrupt_byte = 0; + g_adb_state = ADB_IDLE; + g_adb_mouse_coord = 0; + g_adb_mouse_valid_data = 0; + + g_kbd_reg0_pos = 0; + g_kbd_reg3_16bit = 0x602; + +} + + +#define LEN_ADB_LOG 16 +STRUCT(Adb_log) { + word32 addr; + int val; + int state; +}; + +Adb_log g_adb_log[LEN_ADB_LOG]; +int g_adb_log_pos = 0; + +void adb_log(word32 addr, int val) { + int pos; + + pos = g_adb_log_pos; + g_adb_log[pos].addr = addr; + g_adb_log[pos].val = val; + g_adb_log[pos].state = g_adb_state; + pos++; + if(pos >= LEN_ADB_LOG) { + pos = 0; + } + g_adb_log_pos = pos; +} + +void show_adb_log(void) { + int pos; + int i; + + pos = g_adb_log_pos; + printf("ADB log pos: %d\n", pos); + for(i = 0; i < LEN_ADB_LOG; i++) { + pos--; + if(pos < 0) { + pos = LEN_ADB_LOG - 1; + } + printf("%d:%d: addr:%04x = %02x, st:%d\n", i, pos, + g_adb_log[pos].addr, g_adb_log[pos].val, + g_adb_log[pos].state); + } + printf("kbd: dev: %x, ctl: %x; mouse: dev: %x, ctl: %x\n", + g_kbd_dev_addr, g_kbd_ctl_addr, + g_mouse_dev_addr, g_mouse_ctl_addr); + printf("g_adb_state: %d, g_adb_interrupt_byte: %02x\n", + g_adb_state, g_adb_interrupt_byte); +} + +void adb_error(void) { + halt_printf("Adb Error\n"); + + show_adb_log(); +} + + + +void adb_add_kbd_srq() { + if(g_kbd_reg3_16bit & 0x200) { + /* generate SRQ */ + g_adb_interrupt_byte |= 0x08; + add_irq(IRQ_PENDING_ADB_KBD_SRQ); + } else { + printf("Got keycode but no kbd SRQ!\n"); + } +} + +void adb_clear_kbd_srq() { + remove_irq(IRQ_PENDING_ADB_KBD_SRQ); + + /* kbd SRQ's are the only ones to handle now, so just clean it out */ + g_adb_interrupt_byte &= (~(0x08)); +} + +void adb_add_data_int() { + if(g_c027_val & ADB_C027_DATA_INT) { + add_irq(IRQ_PENDING_ADB_DATA); + } +} + +void adb_add_mouse_int() { + if(g_c027_val & ADB_C027_MOUSE_INT) { + add_irq(IRQ_PENDING_ADB_MOUSE); + } +} + +void adb_clear_data_int() { + remove_irq(IRQ_PENDING_ADB_DATA); +} + +void adb_clear_mouse_int() { + remove_irq(IRQ_PENDING_ADB_MOUSE); +} + + +void adb_send_bytes(int num_bytes, word32 val0, word32 val1, word32 val2) { + word32 val; + int shift_amount; + int i; + + if((num_bytes >= 12) || (num_bytes >= MAX_ADB_DATA_PEND)) { + halt_printf("adb_send_bytes: %d is too many!\n", num_bytes); + } + + g_adb_state = ADB_SENDING_DATA; + g_adb_data_pending = num_bytes; + adb_add_data_int(); + + for(i = 0; i < num_bytes; i++) { + if(i < 4) { + val = val0; + } else if(i < 8) { + val = val1; + } else { + val = val2; + } + + shift_amount = 8*(3 - i); + g_adb_data[i] = (val >> shift_amount) & 0xff; + adb_printf("adb_send_bytes[%d] = %02x\n", i, g_adb_data[i]); + } +} + + +void adb_send_1byte(word32 val) { + + if(g_adb_data_pending != 0) { + halt_printf("g_adb_data_pending: %d\n", g_adb_data_pending); + } + + adb_send_bytes(1, val << 24, 0, 0); +} + + + +void adb_response_packet(int num_bytes, word32 val) { + + if(g_adb_data_pending != 0) { + halt_printf("adb_response_packet, but pending: %d\n", + g_adb_data_pending); + } + + g_adb_state = ADB_IDLE; + g_adb_data_pending = num_bytes; + g_adb_data[0] = val & 0xff; + g_adb_data[1] = (val >> 8) & 0xff; + g_adb_data[2] = (val >> 16) & 0xff; + g_adb_data[3] = (val >> 24) & 0xff; + if(num_bytes) { + g_adb_interrupt_byte |= 0x80 + num_bytes - 1; + } else { + g_adb_interrupt_byte |= 0x80; + } + + adb_printf("adb_response packet: %d: %08x\n", + num_bytes, val); + + adb_add_data_int(); +} + + +void adb_kbd_reg0_data(int a2code, int is_up) { + if(g_kbd_reg0_pos >= MAX_ADB_KBD_REG3) { + /* too many keys, toss */ + halt_printf("Had to toss key: %02x, %d\n", a2code, is_up); + return; + } + + g_kbd_reg0_data[g_kbd_reg0_pos] = a2code + (is_up << 7); + + adb_printf("g_kbd_reg0_data[%d] = %02x\n", g_kbd_reg0_pos, + g_kbd_reg0_data[g_kbd_reg0_pos]); + + g_kbd_reg0_pos++; + + adb_add_kbd_srq(); +} + +void adb_kbd_talk_reg0() { + word32 val0, val1; + word32 reg; + int num_bytes; + int num; + int i; + + num = 0; + val0 = g_kbd_reg0_data[0]; + val1 = g_kbd_reg0_data[1]; + + num_bytes = 0; + if(g_kbd_reg0_pos > 0) { + num_bytes = 2; + num = 1; + if((val0 & 0x7f) == 0x7f) { + /* reset */ + val1 = val0; + } else if(g_kbd_reg0_pos > 1) { + num = 2; + if((val1 & 0x7f) == 0x7f) { + /* If first byte some other key, don't */ + /* put RESET next! */ + num = 1; + val1 = 0xff; + } + } else { + val1 = 0xff; + } + } + + if(num) { + for(i = num; i < g_kbd_reg0_pos; i++) { + g_kbd_reg0_data[i-1] = g_kbd_reg0_data[i]; + } + g_kbd_reg0_pos -= num; + } + + reg = (val0 << 8) + val1; + + adb_printf("adb_kbd_talk0: %04x\n", reg); + + adb_response_packet(num_bytes, reg); + if(g_kbd_reg0_pos == 0) { + adb_clear_kbd_srq(); + } +} + +void adb_set_config(word32 val0, word32 val1, word32 val2) { + int new_mouse; + int new_kbd; + int tmp1; + + new_mouse = val0 >> 4; + new_kbd = val0 & 0xf; + if(new_mouse != g_mouse_ctl_addr) { + glogf("ADB config: mouse from %x to %x!", g_mouse_ctl_addr, new_mouse); + adb_error(); + g_mouse_ctl_addr = new_mouse; + } + if(new_kbd != g_kbd_ctl_addr) { + glogf("ADB config: kbd from %x to %x!", g_kbd_ctl_addr, new_kbd); + adb_error(); + g_kbd_ctl_addr = new_kbd; + } + + + tmp1 = val2 >> 4; + if(tmp1 == 4) { + g_adb_repeat_delay = 0; + } else if(tmp1 < 4) { + g_adb_repeat_delay = (tmp1 + 1) * 15; + } else { + halt_printf("Bad ADB repeat delay: %02x\n", tmp1); + } + + tmp1 = val2 & 0xf; + if(g_rom_version >= 3) { + tmp1 = 9 - tmp1; + } + + switch(tmp1) { + case 0: + g_adb_repeat_rate = 1; + break; + case 1: + g_adb_repeat_rate = 2; + break; + case 2: + g_adb_repeat_rate = 3; + break; + case 3: + g_adb_repeat_rate = 3; + break; + case 4: + g_adb_repeat_rate = 4; + break; + case 5: + g_adb_repeat_rate = 5; + break; + case 6: + g_adb_repeat_rate = 7; + break; + case 7: + g_adb_repeat_rate = 15; + break; + case 8: + /* I don't know what this should be, ROM 03 uses it */ + g_adb_repeat_rate = 30; + break; + case 9: + /* I don't know what this should be, ROM 03 uses it */ + g_adb_repeat_rate = 60; + break; + default: + halt_printf("Bad repeat rate: %02x\n", tmp1); + } + +} + +void adb_set_new_mode(word32 val) { + if(val & 0x03) { + glogf("Disabling keyboard/mouse:%02x!", val); + } + + if(val & 0xa2) { + halt_printf("ADB set mode: %02x!\n", val); + adb_error(); + } + + g_adb_mode = val; +} + + +int adb_read_c026() { + word32 ret; + int i; + + ret = 0; + switch(g_adb_state) { + case ADB_IDLE: + ret = g_adb_interrupt_byte; + g_adb_interrupt_byte = 0; + if(g_irq_pending & IRQ_PENDING_ADB_KBD_SRQ) { + g_adb_interrupt_byte |= 0x08; + } + if(g_adb_data_pending == 0) { + if(ret & 0x80) { + halt_printf("read_c026: ret:%02x, pend:%d\n", + ret, g_adb_data_pending); + } + adb_clear_data_int(); + } + if(g_adb_data_pending) { + if(g_adb_state != ADB_IN_CMD) { + g_adb_state = ADB_SENDING_DATA; + } + } + break; + case ADB_IN_CMD: + ret = 0; + break; + case ADB_SENDING_DATA: + ret = g_adb_data[0]; + for(i = 1; i < g_adb_data_pending; i++) { + g_adb_data[i-1] = g_adb_data[i]; + } + g_adb_data_pending--; + if(g_adb_data_pending <= 0) { + g_adb_data_pending = 0; + g_adb_state = ADB_IDLE; + adb_clear_data_int(); + } + break; + default: + halt_printf("Bad ADB state: %d!\n", g_adb_state); + adb_clear_data_int(); + break; + } + + adb_printf("Reading c026. Returning %02x, st: %02x, pend: %d\n", + ret, g_adb_state, g_adb_data_pending); + + adb_log(0xc026, ret); + return (ret & 0xff); +} + + +void adb_write_c026(int val) { + word32 tmp; + int dev; + + adb_printf("Writing c026 with %02x\n", val); + adb_log(0x1c026, val); + + + switch(g_adb_state) { + case ADB_IDLE: + g_adb_cmd = val; + g_adb_cmd_so_far = 0; + g_adb_cmd_len = 0; + + dev = val & 0xf; + switch(val) { + case 0x01: /* Abort */ + adb_printf("Performing adb abort\n"); + /* adb_abort() */ + break; + case 0x03: /* Flush keyboard buffer */ + adb_printf("Flushing adb keyboard buffer\n"); + /* Do nothing */ + break; + case 0x04: /* Set modes */ + adb_printf("ADB set modes\n"); + g_adb_state = ADB_IN_CMD; + g_adb_cmd_len = 1; + break; + case 0x05: /* Clear modes */ + adb_printf("ADB clear modes\n"); + g_adb_state = ADB_IN_CMD; + g_adb_cmd_len = 1; + break; + case 0x06: /* Set config */ + adb_printf("ADB set config\n"); + g_adb_state = ADB_IN_CMD; + g_adb_cmd_len = 3; + break; + case 0x07: /* Sync */ + adb_printf("Performing sync cmd!\n"); + g_adb_state = ADB_IN_CMD; + if(g_rom_version == 1) { + g_adb_cmd_len = 4; + } else { + g_adb_cmd_len = 8; + } + break; + case 0x08: /* Write mem */ + adb_printf("Starting write_mem cmd\n"); + g_adb_state = ADB_IN_CMD; + g_adb_cmd_len = 2; + break; + case 0x09: /* Read mem */ + adb_printf("Performing read_mem cmd!\n"); + g_adb_state = ADB_IN_CMD; + g_adb_cmd_len = 2; + break; + case 0x0a: /* Read modes byte */ + printf("Performing read_modes cmd!\n"); + /* set_halt(1); */ + adb_send_1byte(g_adb_mode); + break; + case 0x0b: /* Read config bytes */ + printf("Performing read_configs cmd!\n"); + tmp = (g_mouse_ctl_addr << 20) + + (g_kbd_ctl_addr << 16) + + (g_adb_char_set << 12) + + (g_adb_layout_lang << 8) + + (g_adb_repeat_info << 0); + tmp = (0x82U << 24) + tmp; + adb_send_bytes(4, tmp, 0, 0); + break; + case 0x0d: /* Get Version */ + adb_printf("Performing get_version cmd!\n"); + val = 0; + if(g_rom_version == 1) { + /* ROM 01 = revision 5 */ + val = 5; + } else { + /* ROM 03 checks for rev >= 6 */ + val = 6; + } + adb_send_1byte(val); + break; + case 0x0e: /* Read avail char sets */ + adb_printf("Performing read avail char sets cmd!\n"); + adb_send_bytes(2, /* just 2 bytes */ + 0x08000000, /* number of ch sets=0x8 */ + 0, 0); + /* set_halt(1); */ + break; + case 0x0f: /* Read avail kbd layouts */ + adb_printf("Performing read avail kbd layouts cmd!\n"); + adb_send_bytes(0x2, /* number of kbd layouts=0xa */ + 0x0a000000, 0, 0); + /* set_halt(1); */ + break; + case 0x10: /* Reset */ + printf("ADB reset, cmd 0x10\n"); + do_reset(); + break; + case 0x11: /* Send ADB keycodes */ + adb_printf("Sending ADB keycodes\n"); + g_adb_state = ADB_IN_CMD; + g_adb_cmd_len = 1; + break; + case 0x12: /* ADB cmd 12: ROM 03 only! */ + if(g_rom_version >= 3) { + g_adb_state = ADB_IN_CMD; + g_adb_cmd_len = 2; + } else { + printf("ADB cmd 12, but not ROM 3!\n"); + adb_error(); + } + break; + case 0x13: /* ADB cmd 13: ROM 03 only! */ + if(g_rom_version >= 3) { + g_adb_state = ADB_IN_CMD; + g_adb_cmd_len = 2; + } else { + printf("ADB cmd 13, but not ROM 3!\n"); + adb_error(); + } + break; + case 0x73: /* Disable SRQ device 3: mouse */ + adb_printf("Disabling Mouse SRQ's (device 3)\n"); + /* HACK HACK...should deal with SRQs on mouse */ + break; + case 0xb0: case 0xb1: case 0xb2: case 0xb3: + case 0xb4: case 0xb5: case 0xb6: case 0xb7: + case 0xb8: case 0xb9: case 0xba: case 0xbb: + case 0xbc: case 0xbd: case 0xbe: case 0xbf: + /* Listen dev x reg 3 */ + adb_printf("Sending data to dev %x reg 3\n", dev); + g_adb_state = ADB_IN_CMD; + g_adb_cmd_len = 2; + break; + case 0xc0: case 0xc1: case 0xc2: case 0xc3: + case 0xc4: case 0xc5: case 0xc6: case 0xc7: + case 0xc8: case 0xc9: case 0xca: case 0xcb: + case 0xcc: case 0xcd: case 0xce: case 0xcf: + /* Talk dev x reg 0 */ + adb_printf("Performing talk dev %x reg 0\n", dev); + if(dev == g_kbd_dev_addr) { + adb_kbd_talk_reg0(); + } else { + printf("Unknown talk dev %x reg 0!\n", dev); + /* send no data, on SRQ, system polls devs */ + /* so we don't want to send anything */ + adb_error(); + } + break; + case 0xf0: case 0xf1: case 0xf2: case 0xf3: + case 0xf4: case 0xf5: case 0xf6: case 0xf7: + case 0xf8: case 0xf9: case 0xfa: case 0xfb: + case 0xfc: case 0xfd: case 0xfe: case 0xff: + /* Talk dev x reg 3 */ + adb_printf("Performing talk dev %x reg 3\n", dev); + if(dev == g_kbd_dev_addr) { + adb_response_packet(2, g_kbd_reg3_16bit); + } else { + printf("Performing talk dev %x reg 3!!\n", dev); + adb_error(); + } + break; + default: + /* The Gog's says ACS Demo 2 has a bug and writes to */ + /* c026 */ + // OG + if (val==0x84) + printf("ACS Demo2 (3: Colum& Music scroll) : discarding unknown controller command\n"); + else + halt_printf("ADB ucontroller cmd %02x unknown!\n", val); + + break; + } + break; + case ADB_IN_CMD: + adb_printf("Setting byte %d of cmd %02x to %02x\n", + g_adb_cmd_so_far, g_adb_cmd, val); + + g_adb_cmd_data[g_adb_cmd_so_far] = val; + g_adb_cmd_so_far++; + if(g_adb_cmd_so_far >= g_adb_cmd_len) { + adb_printf("Finished cmd %02x\n", g_adb_cmd); + do_adb_cmd(); + } + + break; + default: + printf("adb_state: %02x is unknown! Setting it to ADB_IDLE\n", + g_adb_state); + g_adb_state = ADB_IDLE; + adb_error(); + halt_on_all_c027 = 1; + break; + } + return; +} + +void do_adb_cmd() { + int dev; + int new_kbd; + int addr; + int val; + + dev = g_adb_cmd & 0xf; + + g_adb_state = ADB_IDLE; + + switch(g_adb_cmd) { + case 0x04: /* Set modes */ + adb_printf("Performing ADB set mode: OR'ing in %02x\n", + g_adb_cmd_data[0]); + + val = g_adb_cmd_data[0] | g_adb_mode; + adb_set_new_mode(val); + + break; + case 0x05: /* clear modes */ + adb_printf("Performing ADB clear mode: AND'ing in ~%02x\n", + g_adb_cmd_data[0]); + + val = g_adb_cmd_data[0]; + val = g_adb_mode & (~val); + adb_set_new_mode(val); + break; + case 0x06: /* Set config */ + adb_printf("Set ADB config to %02x %02x %02x\n", + g_adb_cmd_data[0], g_adb_cmd_data[1],g_adb_cmd_data[2]); + + adb_set_config(g_adb_cmd_data[0], g_adb_cmd_data[1], + g_adb_cmd_data[2]); + + break; + case 0x07: /* SYNC */ + adb_printf("Performing ADB SYNC\n"); + adb_printf("data: %02x %02x %02x %02x\n", + g_adb_cmd_data[0], g_adb_cmd_data[1], g_adb_cmd_data[2], + g_adb_cmd_data[3]); + + adb_set_new_mode(g_adb_cmd_data[0]); + adb_set_config(g_adb_cmd_data[1], g_adb_cmd_data[2], + g_adb_cmd_data[3]); + + if(g_rom_version >= 3) { + adb_printf(" and cmd12:%02x %02x cmd13:%02x %02x\n", + g_adb_cmd_data[4], g_adb_cmd_data[5], + g_adb_cmd_data[6], g_adb_cmd_data[7]); + } + break; + case 0x08: /* Write mem */ + addr = g_adb_cmd_data[0]; + val = g_adb_cmd_data[1]; + write_adb_ram(addr, val); + break; + case 0x09: /* Read mem */ + addr = (g_adb_cmd_data[1] << 8) + g_adb_cmd_data[0]; + adb_printf("Performing mem read to addr %04x\n", addr); + adb_send_1byte(read_adb_ram(addr)); + break; + case 0x11: /* Send ADB keycodes */ + val = g_adb_cmd_data[0]; + adb_printf("Performing send ADB keycodes: %02x\n", val); + adb_virtual_key_update(val & 0x7f, val >> 7); + break; + case 0x12: /* ADB cmd12 */ + adb_printf("Performing ADB cmd 12\n"); + adb_printf("data: %02x %02x\n", g_adb_cmd_data[0], + g_adb_cmd_data[1]); + break; + case 0x13: /* ADB cmd13 */ + adb_printf("Performing ADB cmd 13\n"); + adb_printf("data: %02x %02x\n", g_adb_cmd_data[0], + g_adb_cmd_data[1]); + break; + case 0xb0: case 0xb1: case 0xb2: case 0xb3: + case 0xb4: case 0xb5: case 0xb6: case 0xb7: + case 0xb8: case 0xb9: case 0xba: case 0xbb: + case 0xbc: case 0xbd: case 0xbe: case 0xbf: + /* Listen dev x reg 3 */ + if(dev == g_kbd_dev_addr) { + if(g_adb_cmd_data[1] == 0xfe) { + /* change keyboard addr? */ + new_kbd = g_adb_cmd_data[0] & 0xf; + if(new_kbd != dev) { + printf("Moving kbd to dev %x!\n", + new_kbd); + adb_error(); + } + g_kbd_dev_addr = new_kbd; + } else if(g_adb_cmd_data[1] != 1) { + /* see what new device handler id is */ + printf("KBD listen to dev %x reg 3: 1:%02x\n", + dev, g_adb_cmd_data[1]); + adb_error(); + } + if(g_adb_cmd_data[0] != (word32)g_kbd_dev_addr) { + /* see if app is trying to change addr */ + printf("KBD listen to dev %x reg 3: 0:%02x!\n", + dev, g_adb_cmd_data[0]); + adb_error(); + } + g_kbd_reg3_16bit = ((g_adb_cmd_data[0] & 0xf) << 12) + + (g_kbd_reg3_16bit & 0x0fff); + } else if(dev == g_mouse_dev_addr) { + if(g_adb_cmd_data[0] != (word32)dev) { + /* see if app is trying to change mouse addr */ + printf("MOUS listen to dev %x reg3: 0:%02x!\n", + dev, g_adb_cmd_data[0]); + adb_error(); + } + if(g_adb_cmd_data[1] != 1 && g_adb_cmd_data[1] != 2) { + /* see what new device handler id is */ + printf("MOUS listen to dev %x reg 3: 1:%02x\n", + dev, g_adb_cmd_data[1]); + adb_error(); + } + } else { + printf("Listen cmd to dev %x reg3????\n", dev); + printf("data0: %02x, data1: %02x ????\n", + g_adb_cmd_data[0], g_adb_cmd_data[1]); + adb_error(); + } + break; + default: + printf("Doing adb_cmd %02x: UNKNOWN!\n", g_adb_cmd); + break; + } +} + + +int adb_read_c027() { + word32 ret; + + if(halt_on_all_c027) { + halt_printf("halting on all c027 reads!\n"); + } + + if(g_c027_val & (~ADB_C027_NEG_MASK)) { + halt_printf("read_c027: g_c027_val: %02x\n", g_c027_val); + } + + ret = (g_c027_val & ADB_C027_NEG_MASK); + + if(g_adb_mouse_valid_data) { + ret |= ADB_C027_MOUSE_DATA; + } + + if(g_adb_interrupt_byte != 0) { + ret |= ADB_C027_DATA_VALID; + } else if(g_adb_data_pending > 0) { + if((g_adb_state != ADB_IN_CMD)) { + ret |= ADB_C027_DATA_VALID; + } + } + + if(g_adb_mouse_coord) { + ret |= ADB_C027_MOUSE_COORD; + } + +#if 0 + adb_printf("Read c027: %02x, int_byte: %02x, d_pend: %d\n", + ret, g_adb_interrupt_byte, g_adb_data_pending); +#endif + +#if 0 + adb_log(0xc027, ret); +#endif + return ret; +} + +void adb_write_c027(int val) { + word32 old_val; + word32 new_int; + word32 old_int; + + adb_printf("Writing c027 with %02x\n", val); + adb_log(0x1c027, val); + + + old_val = g_c027_val; + + g_c027_val = (val & ADB_C027_NEG_MASK); + new_int = g_c027_val & ADB_C027_MOUSE_INT; + old_int = old_val & ADB_C027_MOUSE_INT; + if(!new_int && old_int) { + adb_clear_mouse_int(); + } + + new_int = g_c027_val & ADB_C027_DATA_INT; + old_int = old_val & ADB_C027_DATA_INT; + if(!new_int && old_int) { + /* ints were on, now off */ + adb_clear_data_int(); + } + + if(g_c027_val & ADB_C027_KBD_INT) { + halt_printf("Can't support kbd interrupts!\n"); + } + + return; +} + +int read_adb_ram(word32 addr) { + int val; + + adb_printf("Reading adb ram addr: %02x\n", addr); + + if(addr >= 0x100) { + if(addr >= 0x1000 && addr < 0x2000) { + /* ROM self-test checksum */ + if(addr == 0x1400) { + val = 0x72; + } else if(addr == 0x1401) { + val = 0xf7; + } else { + val = 0; + } + } else { + printf("adb ram addr out of range: %04x!\n", addr); + val = 0; + } + } else { + val = adb_memory[addr]; + if((addr == 0xb) && (g_rom_version == 1)) { + // read special key state byte for Out of This World + val = (g_c025_val >> 1) & 0x43; + val |= (g_c025_val << 2) & 0x4; + val |= (g_c025_val >> 2) & 0x10; + } + if((addr == 0xc) && (g_rom_version >= 3)) { + // read special key state byte for Out of This World + val = g_c025_val & 0xc7; + printf("val is %02x\n", val); + } + } + + adb_printf("adb_ram returning %02x\n", val); + return val; +} + +void write_adb_ram(word32 addr, int val) { + + adb_printf("Writing adb_ram addr: %02x: %02x\n", addr, val); + + if(addr >= 0x100) { + printf("write adb_ram addr: %02x: %02x!\n", addr, val); + adb_error(); + } else { + adb_memory[addr] = val; + } +} + +int adb_get_keypad_xy(int get_y) { + int x, y; + int key; + int num_keys; + int i, j; + + key = 1; + num_keys = 0; + x = 0; + y = 0; + for(i = 0; i < 3; i++) { + for(j = 0; j < 3; j++) { + if(g_keypad_key_is_down[key]) { + num_keys++; + x = x + (j - 1)*32768; + y = y + (1 - i)*32768; + } + key++; + } + } + if(num_keys == 0) { + num_keys = 1; + } + + adb_printf("get_xy=%d, num_keys: %d, x:%d, y:%d\n", get_y, + num_keys, x, y); + + if(get_y) { + return y / num_keys; + } else { + return x / num_keys; + } +} + +// stub in a wrapper to experiment with full delta movement +int g_delta_x = 0; +int g_delta_y = 0; +int update_mouse_w_delta(int x, int y, int button_states, int buttons_valid, int delta_x, int delta_y) { + g_delta_x = delta_x; + g_delta_y = delta_y; + //glogf("dx: %d dy: %d but: %02x", delta_x, delta_y, button_states); + int ret = 0; + ret = update_mouse(x,y,button_states,buttons_valid); + g_delta_x = 0; + g_delta_y = 0; + return ret; +} + +int update_mouse(int x, int y, int button_states, int buttons_valid) { + double dcycs; + int button1_changed; + int mouse_moved; + int unhide; + int pos; + int i; + + dcycs = g_cur_dcycs; + + g_mouse_raw_x = x; + g_mouse_raw_y = y; + + unhide = 0; + if(x < 0) { + x = 0; + unhide = 1; + } + if(x >= 640) { + x = 639; + unhide = 1; + } + if(y < 0) { + y = 0; + unhide = 1; + } + if(y >= 400) { + y = 399; + unhide = 1; + } + + + g_unhide_pointer = unhide && !g_warp_pointer; + + if(!g_warp_pointer) { + if(g_hide_pointer && g_unhide_pointer) { + /* cursor has left a2 window, show it */ + g_hide_pointer = 0; + x_hide_pointer(0); + } + if((g_num_lines_prev_superhires == 200) && + (g_num_lines_prev_superhires640 == 0) && + ((g_slow_memory_ptr[0x19d00] & 0x80) == 0)) { + // In 320-mode superhires, cut mouse range in half + x = x >> 1; + } + y = y >> 1; + } + + mouse_compress_fifo(dcycs); + +#if 0 + printf("Update Mouse called with buttons:%d x,y:%d,%d, fifo:%d,%d, " + " a2: %d,%d\n", buttons_valid, x, y, + g_mouse_fifo[0].x, g_mouse_fifo[0].y, + g_mouse_a2_x, g_mouse_a2_y); +#endif + + if((buttons_valid < 0) && g_warp_pointer) { + /* Warping the pointer causes it to jump here...this is not */ + /* real motion, just update info and get out */ + g_mouse_a2_x += (x - g_mouse_fifo[0].x); + g_mouse_a2_y += (y - g_mouse_fifo[0].y); + g_mouse_fifo[0].x = x; + g_mouse_fifo[0].y = y; + return 0; + } + +#if 0 + printf("...real move, warp: %d, %d, new x: %d, %d, a2:%d,%d\n", + g_mouse_warp_x, g_mouse_warp_y, g_mouse_fifo[0].x, + g_mouse_fifo[0].y, g_mouse_a2_x, g_mouse_a2_y); +#endif + if (!g_grabmouse) { + mouse_moved = ((g_mouse_fifo[0].x != x) || (g_mouse_fifo[0].y != y)); + } + + g_mouse_a2_x += g_mouse_warp_x; + g_mouse_a2_y += g_mouse_warp_y; + g_mouse_fifo[0].x = x; + g_mouse_fifo[0].y = y; + g_mouse_fifo[0].dcycs = dcycs; + g_mouse_fifo[0].delta_x = g_delta_x; + g_mouse_fifo[0].delta_y = g_delta_y; + g_mouse_warp_x = 0; + g_mouse_warp_y = 0; + + button1_changed = (buttons_valid & 1) && + ((button_states & 1) != (g_mouse_fifo[0].buttons & 1)); //<- make sure fifo doesn't already have pending change to this state + + + if((button_states & 4) && !(g_mouse_fifo[0].buttons & 4) && // fifo check why? + (buttons_valid & 4)) { // right button pressed + adb_increment_speed(); + } + if((button_states & 2) && !(g_mouse_fifo[0].buttons & 2) && // fifo check why? + (buttons_valid & 2)) { + adb_increment_speed(); // middle button pressed + //halt2_printf("Middle button pressed\n"); + } + + pos = g_mouse_fifo_pos; + if((pos < (ADB_MOUSE_FIFO - 2)) && button1_changed) { + /* copy delta to overflow, set overflow */ + /* overflow ensures the mouse button state is precise at */ + /* button up/down times. Using a mouse event list where */ + /* deltas accumulate until a button change would work, too */ + for(i = pos; i >= 0; i--) { + g_mouse_fifo[i + 1] = g_mouse_fifo[i]; /* copy struct*/ + } + g_mouse_fifo_pos = pos + 1; + + } + g_mouse_fifo[0].buttons = (button_states & buttons_valid) | + (g_mouse_fifo[0].buttons & ~buttons_valid); + if (g_grabmouse) { + if (pos > 0) { + mouse_moved = (g_mouse_fifo[0].delta_x || g_mouse_fifo[0].delta_y ); + } + } + + if(mouse_moved || button1_changed) { + if( (g_mouse_ctl_addr == g_mouse_dev_addr) && + ((g_adb_mode & 0x2) == 0)) { + g_adb_mouse_valid_data = 1; + adb_add_mouse_int(); + } + } + + return mouse_moved; +} + +int mouse_read_c024(double dcycs) { + + word32 ret; + word32 tool_start; + int em_active; + int target_x, target_y; + int delta_x, delta_y; + int a2_x, a2_y; + int mouse_button; + int clamped; + int pos; + + if(((g_adb_mode & 0x2) != 0) || (g_mouse_dev_addr != g_mouse_ctl_addr)) { + /* mouse is off, return 0, or mouse is not autopoll */ + g_adb_mouse_valid_data = 0; + adb_clear_mouse_int(); + return 0; + } + + mouse_compress_fifo(dcycs); + + pos = g_mouse_fifo_pos; + target_x = g_mouse_fifo[pos].x; + target_y = g_mouse_fifo[pos].y; + mouse_button = (g_mouse_fifo[pos].buttons & 1); + delta_x = target_x - g_mouse_a2_x; + delta_y = target_y - g_mouse_a2_y; + if (g_grabmouse) { + delta_x = g_mouse_fifo[pos].delta_x; + delta_y = g_mouse_fifo[pos].delta_y; + } + + clamped = 0; + if(delta_x > 0x3f) { + delta_x = 0x3f; + clamped = 1; + } else if(delta_x < -0x3f) { + delta_x = -0x3f; + clamped = 1; + } + if(delta_y > 0x3f) { + delta_y = 0x3f; + clamped = 1; + } else if(delta_y < -0x3f) { + delta_y = -0x3f; + clamped = 1; + } + + if(pos > 0) { + /* peek into next entry's button info if we are not clamped */ + /* and we're returning the y-coord */ + if(!clamped && g_adb_mouse_coord) { + mouse_button = g_mouse_fifo[pos - 1].buttons & 1; + } + } + + if(g_adb_mouse_coord) { + /* y coord */ + delta_x = 0; // clear unneeded x delta + g_mouse_fifo[pos].dyrd = 1; // flag y delta as read + g_mouse_fifo[pos].delta_y = 0; // clear y delta + } else { + delta_y = 0; // clear unneeded y delta + g_mouse_fifo[pos].dxrd = 1; // flag x delta as read + g_mouse_fifo[pos].delta_x = 0; // clear x delta + } + + + adb_printf(" pre a2_x:%02x,%02x,%02x,%02x\n", + g_slow_memory_ptr[0x100e9], g_slow_memory_ptr[0x100ea], + g_slow_memory_ptr[0x100eb], g_slow_memory_ptr[0x100ec]); + adb_printf(" pre a2_x:%02x,%02x,%02x,%02x\n", + g_slow_memory_ptr[0x10190], g_slow_memory_ptr[0x10192], + g_slow_memory_ptr[0x10191], g_slow_memory_ptr[0x10193]); + + /* Update event manager internal state */ + tool_start = (g_slow_memory_ptr[0x103ca] << 16) + + (g_slow_memory_ptr[0x103c9] << 8) + + g_slow_memory_ptr[0x103c8]; + + em_active = 0; + if((tool_start >= 0x20000) && (tool_start < (g_mem_size_total - 28)) ) { + /* seems to be valid ptr to addr of mem space for tools */ + /* see if event manager appears to be active */ + em_active = g_memory_ptr[tool_start + 6*4] + + (g_memory_ptr[tool_start + 6*4 + 1] << 8); + if(g_warp_pointer) { + em_active = 0; + } + } + + a2_x = g_mouse_a2_x; + a2_y = g_mouse_a2_y; + + if(em_active) { + if((!g_hide_pointer) && (g_num_lines_prev_superhires == 200) && + !g_unhide_pointer) { + /* if super-hires and forcing tracking, then hide */ + g_hide_pointer = 1; + x_hide_pointer(1); + } + if(g_adb_mouse_coord == 0) { + /* update x coord values */ + g_slow_memory_ptr[0x47c] = a2_x & 0xff; + g_slow_memory_ptr[0x57c] = a2_x >> 8; + g_memory_ptr[0x47c] = a2_x & 0xff; + g_memory_ptr[0x57c] = a2_x >> 8; + + g_slow_memory_ptr[0x10190] = a2_x & 0xff; + g_slow_memory_ptr[0x10192] = a2_x >> 8; + } else { + g_slow_memory_ptr[0x4fc] = a2_y & 0xff; + g_slow_memory_ptr[0x5fc] = a2_y >> 8; + g_memory_ptr[0x4fc] = a2_y & 0xff; + g_memory_ptr[0x5fc] = a2_y >> 8; + + g_slow_memory_ptr[0x10191] = a2_y & 0xff; + g_slow_memory_ptr[0x10193] = a2_y >> 8; + } + } else { + if(g_hide_pointer && !g_warp_pointer) { + g_hide_pointer = 0; + x_hide_pointer(0); + } + } + + ret = ((!mouse_button) << 7) + ((delta_x | delta_y) & 0x7f); + if(g_adb_mouse_coord) { + g_mouse_a2_button = mouse_button; /* y coord has button*/ + } else { + ret |= 0x80; /* mouse button not down on x coord rd */ + } + + a2_x += delta_x; + a2_y += delta_y; + g_mouse_a2_x = a2_x; + g_mouse_a2_y = a2_y; + if(g_mouse_fifo_pos) { + if (!g_grabmouse) { + if((target_x == a2_x) && (target_y == a2_y) && + (g_mouse_a2_button == mouse_button)) { + g_mouse_fifo_pos--; + } + } else { + if(g_mouse_fifo[pos].dxrd && g_mouse_fifo[pos].dyrd + && (g_mouse_a2_button == mouse_button)) { + g_mouse_fifo_pos--; + } + } + } + + + adb_printf("Read c024, mouse is_y:%d, %02x, vbl:%08x, dcyc:%f, em:%d\n", + g_adb_mouse_coord, ret, g_vbl_count, dcycs, em_active); + adb_printf("...mouse targ_x:%d,%d delta_x,y:%d,%d fifo:%d, a2:%d,%d\n", + target_x, target_y, delta_x, delta_y, g_mouse_fifo_pos, + a2_x, a2_y); + adb_printf(" post a2_x:%02x,%02x,%02x,%02x\n", + g_slow_memory_ptr[0x10190], g_slow_memory_ptr[0x10192], + g_slow_memory_ptr[0x10191], g_slow_memory_ptr[0x10193]); + + if (g_grabmouse) { + if((g_mouse_fifo_pos == 0) && g_mouse_fifo[0].dxrd && g_mouse_fifo[0].dyrd + && ((g_mouse_fifo[0].buttons & 1) == g_mouse_a2_button)) { + g_adb_mouse_valid_data = 0; + adb_clear_mouse_int(); + } + + } else { + if((g_mouse_fifo_pos == 0) && (g_mouse_fifo[0].x == a2_x) && + (g_mouse_fifo[0].y == a2_y) && + ((g_mouse_fifo[0].buttons & 1) == g_mouse_a2_button)) { + g_adb_mouse_valid_data = 0; + adb_clear_mouse_int(); + } + } + + g_adb_mouse_coord = !g_adb_mouse_coord; + return ret; +} + +void mouse_compress_fifo(double dcycs) { + int pos; + + /* The mouse fifo exists so that fast button changes don't get lost */ + /* if the emulator lags behind the mouse events */ + /* But the FIFO means really old mouse events are saved if */ + /* the emulated code isn't looking at the mouse registers */ + /* This routine compresses all mouse events > 0.5 seconds old */ + + for(pos = g_mouse_fifo_pos; pos >= 1; pos--) { + if(g_mouse_fifo[pos].dcycs < (dcycs - 500*1000.0)) { + /* Remove this entry */ + adb_printf("Old mouse FIFO pos %d removed\n", pos); + g_mouse_fifo_pos = pos - 1; + continue; + } + /* Else, stop searching the FIFO */ + break; + } +} + +void adb_key_event(int a2code, int is_up) { + word32 special; + word32 vbl_count; + int key; + int hard_key; + int pos; + int tmp_ascii; + int ascii; + + if(is_up) { + adb_printf("adb_key_event, key:%02x, is up, g_key_down: %02x\n", + a2code, g_key_down); + } + + if(a2code < 0 || a2code > 0x7f) { + halt_printf("add_key_event: a2code: %04x!\n", a2code); + return; + } + + if(!is_up && a2code == 0x35) { + /* ESC pressed, see if ctrl & cmd key down */ + if(CTRL_DOWN && CMD_DOWN) { + /* Desk mgr int */ + glog("Desk mgr int!"); + + g_adb_interrupt_byte |= 0x20; + adb_add_data_int(); + } + } + + /* convert key to ascii, if possible */ + hard_key = 0; + if(a2_key_to_ascii[a2code][1] & 0xef00) { + /* special key */ + } else { + /* we have ascii */ + hard_key = 1; + } + + pos = 1; + ascii = a2_key_to_ascii[a2code][1]; + if(CAPS_LOCK_DOWN && (ascii >= 'a' && ascii <= 'z')) { + pos = 2; + if(SHIFT_DOWN && (g_adb_mode & 0x40)) { + /* xor shift mode--capslock and shift == lowercase */ + pos = 1; + } + } else if(SHIFT_DOWN) { + pos = 2; + } + + ascii = a2_key_to_ascii[a2code][pos]; + if(CTRL_DOWN) { + tmp_ascii = a2_key_to_ascii[a2code][3]; + if(tmp_ascii >= 0) { + ascii = tmp_ascii; + } + } + key = (ascii & 0x7f) + 0x80; + + special = (ascii >> 8) & 0xff; + if(ascii < 0) { + glogf("ascii1: %d, a2code: %02x, pos: %d", ascii,a2code,pos); + ascii = 0; + special = 0; + } + + + if(!is_up) { + if(hard_key) { + g_kbd_buf[g_kbd_chars_buffered] = key; + g_kbd_chars_buffered++; + if(g_kbd_chars_buffered >= MAX_KBD_BUF) { + g_kbd_chars_buffered = MAX_KBD_BUF - 1; + } + g_key_down = 1; + g_a2code_down = a2code; + + /* first key down, set up autorepeat */ + vbl_count = g_vbl_count; + if(g_config_control_panel) { + vbl_count = g_cfg_vbl_count; + } + g_adb_repeat_vbl = vbl_count + g_adb_repeat_delay; + if(g_adb_repeat_delay == 0) { + g_key_down = 0; + } + g_hard_key_down = 1; + } + + g_c025_val = g_c025_val | special; + adb_printf("new c025_or: %02x\n", g_c025_val); + } else { + if(hard_key && (a2code == g_a2code_down)) { + g_hard_key_down = 0; + /* Turn off repeat */ + g_key_down = 0; + } + + g_c025_val = g_c025_val & (~special); + adb_printf("new c025_and: %02x\n", g_c025_val); + } + + if(g_key_down) { + g_c025_val = g_c025_val & (~0x20); + } else { + /* If no hard key down, set update mod latch */ + g_c025_val = g_c025_val | 0x20; + } + +} + +word32 adb_read_c000() { + word32 vbl_count; + + if( ((g_kbd_buf[0] & 0x80) == 0) && (g_key_down == 0)) { + /* nothing happening, check clipboard */ + int c = clipboard_get_char(); + if(c) { + /* inject clipboard char into keyboard buffer */ + g_kbd_buf[0] = c; + } + /* just get out */ + return g_kbd_buf[0]; + } + if(g_kbd_buf[0] & 0x80) { + /* got one */ + if((g_kbd_read_no_update++ > 5) && (g_kbd_chars_buffered > 1)) { + /* read 5 times, keys pending, let's move it along */ + glogf("Read %02x %d times, tossing", g_kbd_buf[0], g_kbd_read_no_update); + adb_access_c010(); + } + } else { + vbl_count = g_vbl_count; + if(g_config_control_panel) { + vbl_count = g_cfg_vbl_count; + } + if(g_key_down && vbl_count >= g_adb_repeat_vbl) { + /* repeat the g_key_down */ + g_c025_val |= 0x8; + adb_key_event(g_a2code_down, 0); + g_adb_repeat_vbl = vbl_count + g_adb_repeat_rate; + } + } + + return g_kbd_buf[0]; +} + +word32 adb_access_c010() { + int tmp; + int i; + + g_kbd_read_no_update = 0; + + tmp = g_kbd_buf[0] & 0x7f; + g_kbd_buf[0] = tmp; + + tmp = tmp | (g_hard_key_down << 7); + if(g_kbd_chars_buffered) { + for(i = 1; i < g_kbd_chars_buffered; i++) { + g_kbd_buf[i - 1] = g_kbd_buf[i]; + } + g_kbd_chars_buffered--; + } + + g_c025_val = g_c025_val & (~(0x08)); + + return tmp; +} + +word32 adb_read_c025() { + return g_c025_val; +} + +int adb_is_cmd_key_down() { + return CMD_DOWN; +} + +int adb_is_option_key_down() { + return OPTION_DOWN; +} + +void adb_increment_speed() { + const char *str; + + g_limit_speed++; + if(g_limit_speed > 3) { + g_limit_speed = 0; + } + + str = ""; + switch(g_limit_speed) { + case 0: + str = "... as fast as possible!"; + break; + case 1: + str = "... 1.024MHz"; + break; + case 2: + str = "... 2.8MHz"; + break; + case 3: + str = "... 8.0MHz"; + break; + } + glogf("Setting g_limit_speed = %d %s", g_limit_speed, str); +} + +void adb_physical_key_update(int a2code, int is_up) { + int autopoll; + int special; + int ascii_and_type; + int ascii; + + /* this routine called by xdriver to pass raw codes--handle */ + /* ucontroller and ADB bus protocol issues here */ + /* if autopoll on, pass it on through to c025,c000 regs */ + /* else only put it in kbd reg 3, and pull SRQ if needed */ + + adb_printf("adb_phys_key_update: %02x, %d\n", a2code, is_up); + + adb_printf("Handle a2code: %02x, is_up: %d\n", a2code, is_up); + + if(a2code < 0 || a2code > 0x7f) { + halt_printf("a2code: %04x!\n", a2code); + return; + } + + /* Remap 0x7b-0x7e to 0x3b-0x3e (arrow keys on new mac keyboards) */ + if(a2code >= 0x7b && a2code <= 0x7e) { + a2code = a2code - 0x40; + } + + /* Now check for special keys (function keys, etc) */ + ascii_and_type = a2_key_to_ascii[a2code][1]; + special = 0; + if((ascii_and_type & 0xf000) == 0x8000) { + /* special function key */ + special = ascii_and_type & 0xff; + switch(special) { + case 0x01: /* F1 - remap to cmd */ + a2code = 0x37; + special = 0; + break; + case 0x02: /* F2 - remap to option */ + a2code = 0x3a; + special = 0; + break; + case 0x0c: /* F12 - remap to reset */ + a2code = 0x7f; + special = 0; + break; + default: + break; + } + } + + /* CUA clipboard paste - for those that remember ctrl-insert/shift-insert */ + if(is_up == 0 && a2code == 0x72 && SHIFT_DOWN) { + clipboard_paste(); + } + + /* Only process reset requests here */ + if(is_up == 0 && a2code == 0x7f && CTRL_DOWN) { + /* Reset pressed! */ + glogf("Reset pressed since CTRL_DOWN: %d", CTRL_DOWN); + do_reset(); + return; + } + + if(special && !is_up) { + switch(special) { + case 0x03: /* F3 - screenshot */ + g_screenshot_requested = 1; + break; + case 0x04: /* F4 - emulator config panel */ + if (CMD_DOWN) { + glog("Alt-F4 Quit!"); + iwm_shut(); + my_exit(1); + } + else + { + cfg_toggle_config_panel(); + } + break; + case 0x05: /* F5 - emulator clipboard paste */ + if (SHIFT_DOWN) { + g_grabmouse = !g_grabmouse; +#ifdef HAVE_SDL + extern void x_grabmouse(); + glogf("g_grabmouse = %d", g_grabmouse); + x_grabmouse(); +#endif + } else { + clipboard_paste(); + } + break; + case 0x06: /* F6 - emulator speed */ + if(SHIFT_DOWN) { + halt2_printf("Shift-F6 pressed\n"); + } else { + adb_increment_speed(); + } + break; + case 0x07: /* F7 - fast disk emul */ + g_fast_disk_emul = !g_fast_disk_emul; + glogf("g_fast_disk_emul is now %d", g_fast_disk_emul); + break; + case 0x08: /* F8 - warp pointer */ + g_warp_pointer = !g_warp_pointer; + if(g_hide_pointer != g_warp_pointer) { + g_hide_pointer = g_warp_pointer; + x_hide_pointer(g_hide_pointer); + } + glogf("g_warp_pointer is now %d", g_warp_pointer); + break; + case 0x09: /* F9 - swap paddles */ + if(SHIFT_DOWN) { + g_swap_paddles = !g_swap_paddles; + glogf("Swap paddles is now: %d", g_swap_paddles); + } else { + g_invert_paddles = !g_invert_paddles; + glogf("Invert paddles is now: %d", g_invert_paddles); + } + break; + case 0x0a: /* F10 - change a2vid paletter */ + if (SHIFT_DOWN) { +#ifdef TOGGLE_STATUS + extern void x_toggle_status_lines(); + x_toggle_status_lines(); +#endif + } else if (CMD_DOWN) { + do_reset(); + return; + } else { + change_a2vid_palette((g_a2vid_palette + 1) & 0xf); + } + break; + case 0x0b: /* F11 - full screen */ + g_fullscreen = !g_fullscreen; + x_full_screen(g_fullscreen); + break; + } + return; + } + /* Handle Keypad Joystick here partly...if keypad key pressed */ + /* while in Keypad Joystick mode, do not pass it on as a key press */ + if((ascii_and_type & 0xff00) == 0x1000) { + /* Keep track of keypad number keys being up or down even */ + /* if joystick mode isn't keypad. This avoid funny cases */ + /* if joystick mode is changed while a key is pressed */ + ascii = ascii_and_type & 0xff; + if(ascii > 0x30 && ascii <= 0x39) { + g_keypad_key_is_down[ascii - 0x30] = !is_up; + } + if(g_joystick_type == JOYSTICK_TYPE_KEYPAD) { + /* If Joystick type is keypad, then do not let these */ + /* keypress pass on further, except for cmd/opt */ + if(ascii == 0x30) { + /* remap '0' to cmd */ + a2code = 0x37; + } else if(ascii == 0x2e || ascii == 0x2c) { + /* remap '.' and ',' to option */ + a2code = 0x3a; + } else { + /* Just ignore it in this mode */ + return; + } + } + } + + autopoll = 1; + if(g_adb_mode & 1) { + /* autopoll is explicitly off */ + autopoll = 0; + } + if(g_kbd_dev_addr != g_kbd_ctl_addr) { + /* autopoll is off because ucontroller doesn't know kbd moved */ + autopoll = 0; + } + if(g_config_control_panel) { + /* always do autopoll */ + autopoll = 1; + } + + + if(is_up) { + if(!autopoll) { + /* no auto keys, generate SRQ! */ + adb_kbd_reg0_data(a2code, is_up); + } else { + adb_virtual_key_update(a2code, is_up); + } + } else { + if(!autopoll) { + /* no auto keys, generate SRQ! */ + adb_kbd_reg0_data(a2code, is_up); + } else { + /* was up, now down */ + adb_virtual_key_update(a2code, is_up); + } + } +} + +void adb_virtual_key_update(int a2code, int is_up) { + int i; + int bitpos; + word32 mask; + + adb_printf("Virtual handle a2code: %02x, is_up: %d\n", a2code, is_up); + + if(a2code < 0 || a2code > 0x7f) { + halt_printf("a2code: %04x!\n", a2code); + return; + } + + i = (a2code >> 5) & 3; + bitpos = a2code & 0x1f; + mask = (1 << bitpos); + + if(is_up) { + if(g_virtual_key_up[i] & mask) { + /* already up, do nothing */ + } else { + g_virtual_key_up[i] |= mask; + adb_key_event(a2code, is_up); + } + } else { + if(g_virtual_key_up[i] & mask) { + g_virtual_key_up[i] &= (~mask); + adb_key_event(a2code, is_up); + } + } +} + +void adb_all_keys_up() { + word32 mask; + int i, j; + + for(i = 0; i < 4; i++) { + for(j = 0; j < 32; j++) { + mask = 1 << j; + if((g_virtual_key_up[i] & mask) == 0) { + /* create key-up event */ + adb_physical_key_update(i*32 + j, 1); + } + } + } +} + +void adb_kbd_repeat_off() { + g_key_down = 0; +} diff --git a/src/adb.h b/src/adb.h index e829584..7eecebe 100644 --- a/src/adb.h +++ b/src/adb.h @@ -1,6 +1,7 @@ /* GSport - an Apple //gs Emulator - Copyright (C) 2010 by GSport contributors + Copyright (C) 2010 - 2019 by GSport contributors + Copyright (C) 2016 - 2018 Dagen Brock Based on the KEGS emulator written by and Copyright (C) 2003 Kent Dickey diff --git a/src/atbridge/CMakeLists.txt b/src/atbridge/CMakeLists.txt new file mode 100644 index 0000000..050752a --- /dev/null +++ b/src/atbridge/CMakeLists.txt @@ -0,0 +1,5 @@ +set(CMAKE_INCLUDE_CURRENT_DIR ON) + +add_library(atbridge aarp.c atbridge.c elap.c llap.c pcap_delay.c port.c) + +target_compile_definitions(atbridge PUBLIC HAVE_ATBRIDGE) diff --git a/src/atbridge/aarp.c b/src/atbridge/aarp.c index bdc3aef..a2f3d70 100644 --- a/src/atbridge/aarp.c +++ b/src/atbridge/aarp.c @@ -1,302 +1,289 @@ -/* -GSport - an Apple //gs Emulator -Copyright (C) 2013-2014 by Peter Neubauer - -This program is free software; you can redistribute it and/or modify it -under the terms of the GNU General Public License as published by the -Free Software Foundation; either version 2 of the License, or (at your -option) any later version. - -This program is distributed in the hope that it will be useful, but -WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY -or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -for more details. - -You should have received a copy of the GNU General Public License along -with this program; if not, write to the Free Software Foundation, Inc., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ - -/** This module implements AARP, a necessary protocol for ELAP communication. **/ - -#include -#include -#include "../defc.h" -#include "atbridge.h" -#include "elap.h" -#include "port.h" -#include "elap_defs.h" -#include "aarp.h" - -#ifdef WIN32 -#include -#elif __linux__ -#include -#endif - -struct amt_entry_t -{ - struct at_addr_t protocol; - struct ether_addr_t hardware; - - struct amt_entry_t* next; -}; - -typedef struct amt_entry_t* amt_t; - -static amt_t amt = 0; - -static unsigned int retry_count; -static clock_t retry_timer; - - -void aarp_init() -{ - aarp_retry_reset(); -} - -void aarp_shutdown() -{ - struct amt_entry_t* entry = amt; - while (entry) - { - struct amt_entry_t* next = entry->next; - free(entry); - entry = next; - } -} - -//// - -static void aarp_send_packet(enum AARP_FUNCTION function, const struct at_addr_t* source_at_addr, const struct at_addr_t* dest_at_addr, const struct ether_addr_t* dest_hw_addr) -{ - if (source_at_addr && dest_at_addr && dest_hw_addr) - { - struct aarp_header_t response; - response.hardware_type = htons(AARP_HARDWARE_ETHER); - response.protocol_type = htons(AARP_PROTOCOL_TYPE); - response.hw_addr_len = AARP_HW_ADDR_LEN; - response.protocol_addr_len = AARP_PROTOCOL_ADDR_LEN; - response.function = htons(function); - - memcpy(&response.source_proto_addr.addr, source_at_addr, sizeof(response.source_proto_addr.addr)); - response.source_proto_addr.addr.network = htons(response.source_proto_addr.addr.network); - response.source_proto_addr.zero = 0x00; - - memcpy(&response.dest_proto_addr.addr, dest_at_addr, sizeof(response.dest_proto_addr.addr)); - response.dest_proto_addr.addr.network = htons(response.dest_proto_addr.addr.network); - response.dest_proto_addr.zero = 0x00; - - memcpy(response.source_hw_addr.mac, elap_get_mac()->mac, sizeof(response.source_hw_addr.mac)); - - memcpy(response.dest_hw_addr.mac, &dest_hw_addr->mac, sizeof(response.dest_hw_addr.mac)); - - if (dest_hw_addr == &HW_ZERO) - elap_send(&HW_APPLETALK_BROADCAST, &SNAP_AARP, sizeof(struct aarp_header_t), (byte*)&response); - else - elap_send(&response.dest_hw_addr, &SNAP_AARP, sizeof(struct aarp_header_t), (byte*)&response); - } -} - -void aarp_probe(const struct at_addr_t* addr) -{ - if (addr) - { - aarp_send_packet(AARP_FUNCTION_PROBE, addr, addr, &HW_ZERO); - } -} - -static void aarp_request(const struct at_addr_t* addr) -{ - if (addr) - { - aarp_send_packet(AARP_FUNCTION_REQUEST, atbridge_get_addr(), addr, &HW_ZERO); - } -} - -//// - -static struct amt_entry_t* amt_lookup_entry_hardware(const struct ether_addr_t* hardware) -{ - if (hardware) - { - struct amt_entry_t* entry = amt; - while (entry) - { - if (memcmp(&entry->hardware, hardware, sizeof(entry->hardware)) == 0) - return entry; - entry = entry->next; - } - } - return 0; -} - -static struct amt_entry_t* amt_lookup_entry_protocol(const struct at_addr_t* protocol) -{ - if (protocol) - { - struct amt_entry_t* entry = amt; - while (entry) - { - if (memcmp(&entry->protocol, protocol, sizeof(entry->protocol)) == 0) - return entry; - entry = entry->next; - } - } - return 0; -} - -static void amt_delete_entry_protocol(const struct at_addr_t* protocol) -{ - if (protocol) - { - struct amt_entry_t* entry = amt; - struct amt_entry_t* previous = amt; - while (entry) - { - if (memcmp(&entry->protocol, protocol, sizeof(entry->protocol)) == 0) - { - previous->next = entry->next; - free(entry); - break; - } - previous = entry; - entry = entry->next; - } - } -} - -static void amt_add(const struct at_addr_t* protocol, const struct ether_addr_t* hardware) -{ - // Does an entry matching one of the protocol or hardware addresses exist? If so, update it. - struct amt_entry_t* entry = amt_lookup_entry_protocol(protocol); - if (entry) - { - memcpy(&entry->hardware, hardware, sizeof(entry->hardware)); - return; - } - - entry = amt_lookup_entry_hardware(hardware); - if (entry) - { - memcpy(&entry->protocol, protocol, sizeof(entry->protocol)); - return; - } - - // Otherwise, add a new entry. - entry = (struct amt_entry_t*)malloc(sizeof(struct amt_entry_t)); - memcpy(&entry->hardware, hardware, sizeof(entry->hardware)); - memcpy(&entry->protocol, protocol, sizeof(entry->protocol)); - entry->next = amt; - amt = entry; -} - -const struct ether_addr_t* aarp_request_hardware(const struct at_addr_t* protocol) -{ - struct amt_entry_t* entry = amt_lookup_entry_protocol(protocol); - if (entry) - { - aarp_retry_reset(); - return (const struct ether_addr_t*)&entry->hardware; - } - else - { - // The AMT doesn't have this protocol address so issue a request at no more than the AARP_PROBE_INTERVAL period. - if (((clock() - retry_timer) >= (AARP_REQUEST_INTERVAL * CLOCKS_PER_SEC / 1000)) && - (retry_count > 0)) - { - aarp_request(protocol); - - retry_count--; - retry_timer = clock(); - - //atbridge_printf("AARP request count %d timer %d.\n", retry_count, retry_timer); - } - - return 0; - } -} - -const struct at_addr_t* aarp_request_protocol(const struct ether_addr_t* hardware) -{ - struct amt_entry_t* entry = amt_lookup_entry_hardware(hardware); - if (entry) - return (const struct at_addr_t*)&entry->protocol; - else - return 0; -} - -bool aarp_retry() -{ - return retry_count > 0; -} - -void aarp_retry_reset() -{ - retry_count = AARP_REQUEST_COUNT; - retry_timer = clock(); -} - -void aarp_glean(const struct at_addr_t* protocol, const struct ether_addr_t* hardware) -{ - amt_add(protocol, hardware); -} - -bool aarp_address_used(const struct at_addr_t* protocol) -{ - // reference 2-8 - if (protocol) - { - // Check for reserved node numbers, per reference 3-9. - if (protocol->node == 0x00 || protocol->node == 0xfe || protocol->node == 0xff) - return true; - - // Look for the address in the AMT. If it's there, another node is using this address. - struct amt_entry_t* entry = amt_lookup_entry_protocol(protocol); - if (entry) - return true; - - // Try a probe. If this address is in use, another node will reply with an AARP RESPONSE packet. - // Return true to advise the caller that the address is not known to be in use. The caller should - // retry aarp_try_address() every 200 ms (AARP_PROBE_INTERVAL) and 10 times (AARP_PROBE_COUNT), - // per the AARP protocol definition, before choosing this address. - aarp_probe(protocol); - return false; - } - return false; -} - -//// - -void aarp_handle_packet(const struct aarp_header_t* aarp) -{ - if (aarp && - aarp->hardware_type == AARP_HARDWARE_ETHER && - aarp->protocol_type == AARP_PROTOCOL_TYPE && - aarp->hw_addr_len == AARP_HW_ADDR_LEN && - aarp->protocol_addr_len == AARP_PROTOCOL_ADDR_LEN) - { - switch (aarp->function) - { - case AARP_FUNCTION_REQUEST: - if (((aarp->dest_proto_addr.addr.network == atbridge_get_net()) || - (aarp->dest_proto_addr.addr.network == 0x00 /* reference 4-6 */)) && - (aarp->dest_proto_addr.addr.node == atbridge_get_node())) - { - // Generate a response for the AARP request. - aarp_send_packet(AARP_FUNCTION_RESPONSE, &aarp->dest_proto_addr.addr, &aarp->source_proto_addr.addr, &aarp->source_hw_addr); - } - break; - case AARP_FUNCTION_RESPONSE: - aarp_glean(&aarp->source_proto_addr.addr, &aarp->source_hw_addr); - aarp_glean(&aarp->dest_proto_addr.addr, &aarp->dest_hw_addr); - break; - case AARP_FUNCTION_PROBE: - // AMT entry aging, method 2, reference 2-11 - amt_delete_entry_protocol(&aarp->dest_proto_addr.addr); - break; - default: - break; - } - } -} +/* + GSport - an Apple //gs Emulator + Copyright (C) 2010 - 2019 by GSport contributors + Copyright (C) 2016 - 2018 Dagen Brock + + Based on the KEGS emulator written by and Copyright (C) 2003 Kent Dickey + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 2 of the License, or (at your + option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +/** This module implements AARP, a necessary protocol for ELAP communication. **/ + +#include +#include +#include "../defc.h" +#include "atbridge.h" +#include "elap.h" +#include "port.h" +#include "elap_defs.h" +#include "aarp.h" + +#ifdef WIN32 +#include +#elif __linux__ +#include +#endif + +struct amt_entry_t +{ + struct at_addr_t protocol; + struct ether_addr_t hardware; + + struct amt_entry_t* next; +}; + +typedef struct amt_entry_t* amt_t; + +static amt_t amt = 0; + +static unsigned int retry_count; +static clock_t retry_timer; + + +void aarp_init() { + aarp_retry_reset(); +} + +void aarp_shutdown() { + struct amt_entry_t* entry = amt; + while (entry) + { + struct amt_entry_t* next = entry->next; + free(entry); + entry = next; + } +} + +//// + +static void aarp_send_packet(enum AARP_FUNCTION function, const struct at_addr_t* source_at_addr, const struct at_addr_t* dest_at_addr, const struct ether_addr_t* dest_hw_addr) { + if (source_at_addr && dest_at_addr && dest_hw_addr) + { + struct aarp_header_t response; + response.hardware_type = htons(AARP_HARDWARE_ETHER); + response.protocol_type = htons(AARP_PROTOCOL_TYPE); + response.hw_addr_len = AARP_HW_ADDR_LEN; + response.protocol_addr_len = AARP_PROTOCOL_ADDR_LEN; + response.function = htons(function); + + memcpy(&response.source_proto_addr.addr, source_at_addr, sizeof(response.source_proto_addr.addr)); + response.source_proto_addr.addr.network = htons(response.source_proto_addr.addr.network); + response.source_proto_addr.zero = 0x00; + + memcpy(&response.dest_proto_addr.addr, dest_at_addr, sizeof(response.dest_proto_addr.addr)); + response.dest_proto_addr.addr.network = htons(response.dest_proto_addr.addr.network); + response.dest_proto_addr.zero = 0x00; + + memcpy(response.source_hw_addr.mac, elap_get_mac()->mac, sizeof(response.source_hw_addr.mac)); + + memcpy(response.dest_hw_addr.mac, &dest_hw_addr->mac, sizeof(response.dest_hw_addr.mac)); + + if (dest_hw_addr == &HW_ZERO) + elap_send(&HW_APPLETALK_BROADCAST, &SNAP_AARP, sizeof(struct aarp_header_t), (byte*)&response); + else + elap_send(&response.dest_hw_addr, &SNAP_AARP, sizeof(struct aarp_header_t), (byte*)&response); + } +} + +void aarp_probe(const struct at_addr_t* addr) { + if (addr) + { + aarp_send_packet(AARP_FUNCTION_PROBE, addr, addr, &HW_ZERO); + } +} + +static void aarp_request(const struct at_addr_t* addr) { + if (addr) + { + aarp_send_packet(AARP_FUNCTION_REQUEST, atbridge_get_addr(), addr, &HW_ZERO); + } +} + +//// + +static struct amt_entry_t* amt_lookup_entry_hardware(const struct ether_addr_t* hardware) { + if (hardware) + { + struct amt_entry_t* entry = amt; + while (entry) + { + if (memcmp(&entry->hardware, hardware, sizeof(entry->hardware)) == 0) + return entry; + entry = entry->next; + } + } + return 0; +} + +static struct amt_entry_t* amt_lookup_entry_protocol(const struct at_addr_t* protocol) { + if (protocol) + { + struct amt_entry_t* entry = amt; + while (entry) + { + if (memcmp(&entry->protocol, protocol, sizeof(entry->protocol)) == 0) + return entry; + entry = entry->next; + } + } + return 0; +} + +static void amt_delete_entry_protocol(const struct at_addr_t* protocol) { + if (protocol) + { + struct amt_entry_t* entry = amt; + struct amt_entry_t* previous = amt; + while (entry) + { + if (memcmp(&entry->protocol, protocol, sizeof(entry->protocol)) == 0) + { + previous->next = entry->next; + free(entry); + break; + } + previous = entry; + entry = entry->next; + } + } +} + +static void amt_add(const struct at_addr_t* protocol, const struct ether_addr_t* hardware) { + // Does an entry matching one of the protocol or hardware addresses exist? If so, update it. + struct amt_entry_t* entry = amt_lookup_entry_protocol(protocol); + if (entry) + { + memcpy(&entry->hardware, hardware, sizeof(entry->hardware)); + return; + } + + entry = amt_lookup_entry_hardware(hardware); + if (entry) + { + memcpy(&entry->protocol, protocol, sizeof(entry->protocol)); + return; + } + + // Otherwise, add a new entry. + entry = (struct amt_entry_t*)malloc(sizeof(struct amt_entry_t)); + memcpy(&entry->hardware, hardware, sizeof(entry->hardware)); + memcpy(&entry->protocol, protocol, sizeof(entry->protocol)); + entry->next = amt; + amt = entry; +} + +const struct ether_addr_t* aarp_request_hardware(const struct at_addr_t* protocol) { + struct amt_entry_t* entry = amt_lookup_entry_protocol(protocol); + if (entry) + { + aarp_retry_reset(); + return (const struct ether_addr_t*)&entry->hardware; + } + else + { + // The AMT doesn't have this protocol address so issue a request at no more than the AARP_PROBE_INTERVAL period. + if (((clock() - retry_timer) >= (AARP_REQUEST_INTERVAL * CLOCKS_PER_SEC / 1000)) && + (retry_count > 0)) + { + aarp_request(protocol); + + retry_count--; + retry_timer = clock(); + + //atbridge_printf("AARP request count %d timer %d.\n", retry_count, retry_timer); + } + + return 0; + } +} + +const struct at_addr_t* aarp_request_protocol(const struct ether_addr_t* hardware) { + struct amt_entry_t* entry = amt_lookup_entry_hardware(hardware); + if (entry) + return (const struct at_addr_t*)&entry->protocol; + else + return 0; +} + +bool aarp_retry() { + return retry_count > 0; +} + +void aarp_retry_reset() { + retry_count = AARP_REQUEST_COUNT; + retry_timer = clock(); +} + +void aarp_glean(const struct at_addr_t* protocol, const struct ether_addr_t* hardware) { + amt_add(protocol, hardware); +} + +bool aarp_address_used(const struct at_addr_t* protocol) { + // reference 2-8 + if (protocol) + { + // Check for reserved node numbers, per reference 3-9. + if (protocol->node == 0x00 || protocol->node == 0xfe || protocol->node == 0xff) + return true; + + // Look for the address in the AMT. If it's there, another node is using this address. + struct amt_entry_t* entry = amt_lookup_entry_protocol(protocol); + if (entry) + return true; + + // Try a probe. If this address is in use, another node will reply with an AARP RESPONSE packet. + // Return true to advise the caller that the address is not known to be in use. The caller should + // retry aarp_try_address() every 200 ms (AARP_PROBE_INTERVAL) and 10 times (AARP_PROBE_COUNT), + // per the AARP protocol definition, before choosing this address. + aarp_probe(protocol); + return false; + } + return false; +} + +//// + +void aarp_handle_packet(const struct aarp_header_t* aarp) { + if (aarp && + aarp->hardware_type == AARP_HARDWARE_ETHER && + aarp->protocol_type == AARP_PROTOCOL_TYPE && + aarp->hw_addr_len == AARP_HW_ADDR_LEN && + aarp->protocol_addr_len == AARP_PROTOCOL_ADDR_LEN) + { + switch (aarp->function) + { + case AARP_FUNCTION_REQUEST: + if (((aarp->dest_proto_addr.addr.network == atbridge_get_net()) || + (aarp->dest_proto_addr.addr.network == 0x00 /* reference 4-6 */)) && + (aarp->dest_proto_addr.addr.node == atbridge_get_node())) + { + // Generate a response for the AARP request. + aarp_send_packet(AARP_FUNCTION_RESPONSE, &aarp->dest_proto_addr.addr, &aarp->source_proto_addr.addr, &aarp->source_hw_addr); + } + break; + case AARP_FUNCTION_RESPONSE: + aarp_glean(&aarp->source_proto_addr.addr, &aarp->source_hw_addr); + aarp_glean(&aarp->dest_proto_addr.addr, &aarp->dest_hw_addr); + break; + case AARP_FUNCTION_PROBE: + // AMT entry aging, method 2, reference 2-11 + amt_delete_entry_protocol(&aarp->dest_proto_addr.addr); + break; + default: + break; + } + } +} diff --git a/src/atbridge/aarp.h b/src/atbridge/aarp.h index 461bcec..b83f6f1 100644 --- a/src/atbridge/aarp.h +++ b/src/atbridge/aarp.h @@ -1,37 +1,40 @@ -/* -GSport - an Apple //gs Emulator -Copyright (C) 2013-2014 by Peter Neubauer - -This program is free software; you can redistribute it and/or modify it -under the terms of the GNU General Public License as published by the -Free Software Foundation; either version 2 of the License, or (at your -option) any later version. - -This program is distributed in the hope that it will be useful, but -WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY -or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -for more details. - -You should have received a copy of the GNU General Public License along -with this program; if not, write to the Free Software Foundation, Inc., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ - -struct at_addr_t; -struct aarp_header_t; -struct ether_addr_t; - -void aarp_init(); -void aarp_shutdown(); - -const struct ether_addr_t* aarp_request_hardware(const struct at_addr_t* protocol); -const struct at_addr_t* aarp_request_protocol(const struct ether_addr_t* hardware); - -bool aarp_retry(); -void aarp_retry_reset(); - -void aarp_glean(const struct at_addr_t* protocol, const struct ether_addr_t* hardware); - -bool aarp_address_used(const struct at_addr_t* protocol); - -void aarp_handle_packet(const struct aarp_header_t* aarp); \ No newline at end of file +/* + GSport - an Apple //gs Emulator + Copyright (C) 2010 - 2019 by GSport contributors + Copyright (C) 2016 - 2018 Dagen Brock + + Based on the KEGS emulator written by and Copyright (C) 2003 Kent Dickey + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 2 of the License, or (at your + option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +struct at_addr_t; +struct aarp_header_t; +struct ether_addr_t; + +void aarp_init(); +void aarp_shutdown(); + +const struct ether_addr_t* aarp_request_hardware(const struct at_addr_t* protocol); +const struct at_addr_t* aarp_request_protocol(const struct ether_addr_t* hardware); + +bool aarp_retry(); +void aarp_retry_reset(); + +void aarp_glean(const struct at_addr_t* protocol, const struct ether_addr_t* hardware); + +bool aarp_address_used(const struct at_addr_t* protocol); + +void aarp_handle_packet(const struct aarp_header_t* aarp); diff --git a/src/atbridge/atalk.h b/src/atbridge/atalk.h index d4d1df4..ee57263 100644 --- a/src/atbridge/atalk.h +++ b/src/atbridge/atalk.h @@ -1,137 +1,140 @@ -/* -GSport - an Apple //gs Emulator -Copyright (C) 2013-2014 by Peter Neubauer - -This program is free software; you can redistribute it and/or modify it -under the terms of the GNU General Public License as published by the -Free Software Foundation; either version 2 of the License, or (at your -option) any later version. - -This program is distributed in the hope that it will be useful, but -WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY -or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -for more details. - -You should have received a copy of the GNU General Public License along -with this program; if not, write to the Free Software Foundation, Inc., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ - -typedef byte at_node_t; -static const at_node_t at_broadcast_node = 0xFF; - -typedef word16 at_network_t; - -#pragma pack(push, 1) -struct at_addr_t -{ - at_network_t network; - at_node_t node; -}; -#pragma pack(pop) - -enum LAP_TYPES { /* reference C-6 */ - LAP_DDP_SHORT = 0x01, - LAP_DDP_LONG = 0x02 -}; - -enum DDP_SOCKETS { /* reference C-7 */ - DDP_SOCKET_INVALID_00 = 0x00, - DDP_SOCKET_RTMP = 0x01, - DDP_SOCKET_NIS = 0x02, - DDP_SOCKET_ECHO = 0x04, - DDP_SOCKET_ZIS = 0x06, - DDP_SOCKET_INVALID_FF = 0xFF, -}; - -enum DDP_TYPES { /* reference C-6 */ - DDP_TYPE_INVALID = 0x00, - DDP_TYPE_RTMP = 0x01, - DDP_TYPE_NBP = 0x02, - DDP_TYPE_ATP = 0x03, - DDP_TYPE_AEP = 0x04, - DDP_TYPE_RTMP_REQUEST = 0x05, - DDP_TYPE_ZIP = 0x06, - DDP_TYPE_ADSP = 0x07, - DDP_TYPE_RESERVED_08 = 0x08, - DDP_TYPE_RESERVED_09 = 0x09, - DDP_TYPE_RESERVED_0A = 0x0A, - DDP_TYPE_RESERVED_0B = 0x0B, - DDP_TYPE_RESERVED_0C = 0x0C, - DDP_TYPE_RESERVED_0D = 0x0D, - DDP_TYPE_RESERVED_0E = 0x0E, - DDP_TYPE_RESERVED_0F = 0x0F -}; - -#pragma pack(push, 1) -struct DDP_LONG -{ - byte length[2]; - word16 checksum; - at_network_t dest_net; - at_network_t source_net; - at_node_t dest_node; - at_node_t source_node; - byte dest_socket; - byte source_socket; - byte type; -}; - -struct DDP_SHORT -{ - byte length[2]; - byte dest_socket; - byte source_socket; - byte type; -}; - -enum RTMP_FUNCTIONS { /* reference C-8*/ - RTMP_FUNCTION_REQUEST = 0x01, - RTMP_FUNCTION_RDR_SPLIT = 0x02, - RTMP_FUNCTION_RDR_NO_SPLIT = 0x03 -}; - -struct rtmp_request_t -{ - byte function; -}; - -struct rtmp_nonextended_data_t -{ - at_network_t net; - byte id_length; - at_node_t node; - word16 zero; - byte delimiter; -}; - -struct rtmp_nonextended_response_t -{ - at_network_t net; - byte id_length; - at_node_t node; -}; - -struct rtmp_extended_data_t -{ - at_network_t net; - byte id_length; - at_node_t node; -}; - -struct rtmp_nonextended_tuple_t -{ - at_network_t net; - byte distance; -}; - -struct rtmp_extended_tuple_t -{ - at_network_t range_start; - byte distance; - at_network_t range_end; - byte delimiter; -}; - -static const byte RTMP_TUPLE_DELIMITER = 0x82; -#pragma pack(pop) \ No newline at end of file +/* + GSport - an Apple //gs Emulator + Copyright (C) 2010 - 2019 by GSport contributors + Copyright (C) 2016 - 2018 Dagen Brock + + Based on the KEGS emulator written by and Copyright (C) 2003 Kent Dickey + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 2 of the License, or (at your + option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +typedef byte at_node_t; +static const at_node_t at_broadcast_node = 0xFF; + +typedef word16 at_network_t; + +#pragma pack(push, 1) +struct at_addr_t +{ + at_network_t network; + at_node_t node; +}; +#pragma pack(pop) + +enum LAP_TYPES { /* reference C-6 */ + LAP_DDP_SHORT = 0x01, + LAP_DDP_LONG = 0x02 +}; + +enum DDP_SOCKETS { /* reference C-7 */ + DDP_SOCKET_INVALID_00 = 0x00, + DDP_SOCKET_RTMP = 0x01, + DDP_SOCKET_NIS = 0x02, + DDP_SOCKET_ECHO = 0x04, + DDP_SOCKET_ZIS = 0x06, + DDP_SOCKET_INVALID_FF = 0xFF, +}; + +enum DDP_TYPES { /* reference C-6 */ + DDP_TYPE_INVALID = 0x00, + DDP_TYPE_RTMP = 0x01, + DDP_TYPE_NBP = 0x02, + DDP_TYPE_ATP = 0x03, + DDP_TYPE_AEP = 0x04, + DDP_TYPE_RTMP_REQUEST = 0x05, + DDP_TYPE_ZIP = 0x06, + DDP_TYPE_ADSP = 0x07, + DDP_TYPE_RESERVED_08 = 0x08, + DDP_TYPE_RESERVED_09 = 0x09, + DDP_TYPE_RESERVED_0A = 0x0A, + DDP_TYPE_RESERVED_0B = 0x0B, + DDP_TYPE_RESERVED_0C = 0x0C, + DDP_TYPE_RESERVED_0D = 0x0D, + DDP_TYPE_RESERVED_0E = 0x0E, + DDP_TYPE_RESERVED_0F = 0x0F +}; + +#pragma pack(push, 1) +struct DDP_LONG +{ + byte length[2]; + word16 checksum; + at_network_t dest_net; + at_network_t source_net; + at_node_t dest_node; + at_node_t source_node; + byte dest_socket; + byte source_socket; + byte type; +}; + +struct DDP_SHORT +{ + byte length[2]; + byte dest_socket; + byte source_socket; + byte type; +}; + +enum RTMP_FUNCTIONS { /* reference C-8*/ + RTMP_FUNCTION_REQUEST = 0x01, + RTMP_FUNCTION_RDR_SPLIT = 0x02, + RTMP_FUNCTION_RDR_NO_SPLIT = 0x03 +}; + +struct rtmp_request_t +{ + byte function; +}; + +struct rtmp_nonextended_data_t +{ + at_network_t net; + byte id_length; + at_node_t node; + word16 zero; + byte delimiter; +}; + +struct rtmp_nonextended_response_t +{ + at_network_t net; + byte id_length; + at_node_t node; +}; + +struct rtmp_extended_data_t +{ + at_network_t net; + byte id_length; + at_node_t node; +}; + +struct rtmp_nonextended_tuple_t +{ + at_network_t net; + byte distance; +}; + +struct rtmp_extended_tuple_t +{ + at_network_t range_start; + byte distance; + at_network_t range_end; + byte delimiter; +}; + +static const byte RTMP_TUPLE_DELIMITER = 0x82; +#pragma pack(pop) diff --git a/src/atbridge/atbridge.c b/src/atbridge/atbridge.c index 00f7343..bfb5260 100644 --- a/src/atbridge/atbridge.c +++ b/src/atbridge/atbridge.c @@ -1,426 +1,408 @@ -/* -GSport - an Apple //gs Emulator -Copyright (C) 2013-2014 by Peter Neubauer - -This program is free software; you can redistribute it and/or modify it -under the terms of the GNU General Public License as published by the -Free Software Foundation; either version 2 of the License, or (at your -option) any later version. - -This program is distributed in the hope that it will be useful, but -WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY -or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -for more details. - -You should have received a copy of the GNU General Public License along -with this program; if not, write to the Free Software Foundation, Inc., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ - -/** This module is the "heart" of the bridge and provides the connection between the ELAP and LLAP ports. **/ - -#include -#include "../defc.h" -#include -#include -#include "atbridge.h" -#include "port.h" -#include "elap.h" -#include "llap.h" -#include "aarp.h" - -#ifdef WIN32 -#include -#elif __linux__ -#include -#endif - -extern struct packet_port_t elap_port; - -static bool diagnostics = false; -static bool sent_rtmp_request = false; - -static struct at_addr_t local_address = { 0, 0 }; - -static const at_network_t NET_STARTUP_LOW = 0xFF00; -static const at_network_t NET_STARTUP_HIGH = 0xFFFE; -static const at_node_t NODE_STARTUP_LOW = 0x01; -static const at_node_t NODE_STARTUP_HIGH = 0xFE; - -static void send_rtmp_request(); - -bool atbridge_init() -{ - // If the GS reboots, we may try to reinitialize the bridge. If this is the case, keep the old address and AMT. - if (local_address.network == 0) - { - // Obtain a provisional node address and startup range network. - // - // This isn't correct for an extended network (like ELAP) but works adequately on small networks. - // The bridge should follow the complicated process on page 4-9 to obtain the network and node number. - srand((unsigned int)time(0)); - local_address.network = (at_network_t)((double)rand()/RAND_MAX * (NET_STARTUP_HIGH - NET_STARTUP_LOW) + NET_STARTUP_LOW); - local_address.node = (at_node_t)((double)rand()/RAND_MAX + (NODE_STARTUP_HIGH - NODE_STARTUP_LOW) + 0x01); - - aarp_init(); - llap_init(); - if (!elap_init()) - { - atbridge_shutdown(); - return false; - } - } - return true; -} - -void atbridge_shutdown() -{ - llap_shutdown(); - elap_shutdown(); - aarp_shutdown(); -} - -void atbridge_set_diagnostics(bool enabled) -{ - diagnostics = enabled; -} - -bool atbridge_get_diagnostics() -{ - return diagnostics; -} - -void atbridge_printf(const char *fmt, ...) -{ - if (atbridge_get_diagnostics()) - { - va_list args; - va_start(args, fmt); - vprintf(fmt, args); - va_end(args); - } -} - -const struct at_addr_t* atbridge_get_addr() -{ - return &local_address; -} - -const at_network_t atbridge_get_net() -{ - return local_address.network; -} - -const at_node_t atbridge_get_node() -{ - return local_address.node; -} - -void atbridge_set_net(at_network_t net) -{ - local_address.network = net; -} - -void atbridge_set_node(at_node_t node) -{ - local_address.node = node; -} - -bool atbridge_address_used(const struct at_addr_t* addr) -{ - if (!sent_rtmp_request) - send_rtmp_request(); - return aarp_address_used(addr); -} - -/* Calculate a DDP checksum, per Apple's documented algorithm in 4-17 of "Inside AppleTalk". */ -static word16 get_checksum(size_t size, byte data[]) -{ - word16 cksum = 0; - for (unsigned int i = 0; i < size; i++) - { - cksum += data[i]; - cksum = (cksum << 1) | ((cksum & 0x8000) >> 15); // roll left - } - if (cksum == 0) - cksum = 0xffff; - return cksum; -} - -static void calculate_checksum(struct packet_t* packet) -{ - if (packet && packet->data && (packet->size >= sizeof(struct DDP_LONG)) && (packet->type == LAP_DDP_LONG)) - { - struct DDP_LONG* header = (struct DDP_LONG*)(packet->data); - header->checksum = htons(get_checksum( - packet->size - offsetof(struct DDP_LONG, dest_net), - (byte*)&header->dest_net)); - } -} - -/* Convert a long-form DDP header to a short-form header. This function only converts the headers. */ -static word16 convert_ddp_header_to_short(const struct DDP_LONG* in, struct DDP_SHORT* out) -{ - word16 size; - - if (!in || !out) - return 0; - - size = ((in->length[0] & 0x3) << 8) + (in->length[1]) - (sizeof(struct DDP_LONG) - sizeof(struct DDP_SHORT)); - - out->length[0] = (size >> 8) & 0x03; - out->length[1] = size & 0xff; - - out->dest_socket = in->dest_socket; - out->source_socket = in->source_socket; - - out->type = in->type; - - return size; -} - -/* Convert a short-form DDP header to a long-form header. ELAP requires long-form, but LLAP often uses short-form. */ -/* This function only converts the headers. */ -static word16 convert_ddp_header_to_long(const struct at_addr_t dest, const struct at_addr_t source, const struct DDP_SHORT* in, struct DDP_LONG* out) -{ - word16 size; - - if (!in || !out) - return 0; - - size = ((in->length[0] & 0x3) << 8) + (in->length[1]) + (sizeof(struct DDP_LONG) - sizeof(struct DDP_SHORT)); - out->length[0] = (size >> 8) & 0x03; - out->length[1] = size & 0xff; - - out->checksum = 0x0000; /* 0x0000 == no checksum calculated, reference 4-17 */ - - if (dest.network) - out->dest_net = dest.network; - else - out->dest_net = atbridge_get_net(); - out->dest_net = (at_network_t)htons(out->dest_net); - - if (source.network) - out->source_net = source.network; - else - out->source_net = atbridge_get_net(); - out->source_net = (at_network_t)htons(out->source_net); - - out->dest_node = dest.node; - out->source_node = source.node; - - out->dest_socket = in->dest_socket; - out->source_socket = in->source_socket; - - out->type = in->type; - - return size; -} - -/* Convert a short-form DDP packet to a long-form packet. */ -/* This function converts an entire packet, not just the header. */ -static void convert_ddp_packet_to_long(struct packet_t* packet) -{ - if (packet && (packet->type == LAP_DDP_SHORT) && packet->data && (packet->size >= sizeof(struct DDP_SHORT))) - { - struct DDP_SHORT* header_short = (struct DDP_SHORT*)packet->data; - - const size_t payload_size = packet->size - sizeof(struct DDP_SHORT); - byte* data = (byte*)malloc(payload_size + sizeof(struct DDP_LONG)); - struct DDP_LONG* header_long = (struct DDP_LONG*)data; - - const word16 size = convert_ddp_header_to_long(packet->dest, packet->source, header_short, header_long); - packet->dest.network = ntohs(header_long->dest_net); - packet->source.network = ntohs(header_long->source_net); - - memcpy(data + sizeof(struct DDP_LONG), packet->data + sizeof(struct DDP_SHORT), payload_size); - - packet->type = LAP_DDP_LONG; - packet->size = size; - - // Replace the original short-form packet data. - free(packet->data); - packet->data = data; - - calculate_checksum(packet); - } -} - -/* Convert a long-form DDP packet to short-form. */ -static void convert_ddp_packet_to_short(struct packet_t* packet) -{ - if (packet && (packet->type == LAP_DDP_LONG) && packet->data) - { - struct DDP_LONG* header_long = (struct DDP_LONG*)packet->data; - - const size_t payload_size = packet->size - sizeof(struct DDP_LONG); - byte* data = (byte*)malloc(payload_size + sizeof(struct DDP_SHORT)); - struct DDP_SHORT* header_short = (struct DDP_SHORT*)data; - - const word16 size = convert_ddp_header_to_short(header_long, header_short); - - memcpy(data + sizeof(struct DDP_SHORT), packet->data + sizeof(struct DDP_LONG), payload_size); - - packet->type = LAP_DDP_SHORT; - packet->size = size; - - free(packet->data); - packet->data = data; - } -} - -/*static void convert_rtmp_to_extended(struct packet_t* packet) -{ - if (packet && (packet->type == LAP_DDP_SHORT) && packet->data) - { - struct DDP_SHORT* header_short = (struct DDP_SHORT*)packet->data; - if (header_short->type != DDP_TYPE_RTMP || header_short->dest_socket != DDP_SOCKET_RTMP) - return; - - struct rtmp_nonextended_data_t* in = (struct rtmp_nonextended_data_t*)(packet->data + sizeof(struct DDP_SHORT)); - - // Construct a new long-form DDP packet header. - size_t size = sizeof(struct DDP_LONG) + sizeof(struct rtmp_extended_data_t); - byte* data = (byte*)malloc(size); - struct DDP_LONG* header_long = (struct DDP_LONG*)data; - convert_ddp_header_to_long(packet->dest, packet->source, header_short, header_long); - - struct rtmp_extended_data_t* out = (struct rtmp_extended_data_t*)(data + sizeof(struct DDP_LONG)); - out->net = in->net; - out->id_length = in->id_length; - out->node = in->node; - - // Copy the routing tuples. - struct rtmp_nonextended_tuple_t* in_tuple = (struct rtmp_nonextended_tuple_t*)(packet->data + sizeof(struct DDP_SHORT) + sizeof(struct rtmp_nonextended_data_t)); - struct rtmp_extended_tuple_t* out_tuple = (struct rtmp_extended_tuple_t*)(data + size); - while ((byte*)in_tuple < (packet->data + packet->size)) - { - size += sizeof(struct rtmp_extended_tuple_t); - realloc(data, size); - out_tuple->range_start = in_tuple->net; - out_tuple->distance = in_tuple->distance | 0x80; - out_tuple->range_end = in_tuple->net; - out_tuple->delimiter = RTMP_TUPLE_DELIMITER; - in_tuple++; - } - - free(packet->data); - packet->data = data; - packet->size = size; - packet->type = LAP_DDP_LONG; - } -}*/ - -static void convert_rtmp_to_nonextended(struct packet_t* packet) -{ - if (packet && (packet->type == LAP_DDP_LONG) && packet->data) - { - struct DDP_LONG* header_long = (struct DDP_LONG*)packet->data; - if (header_long->type != DDP_TYPE_RTMP || header_long->dest_socket != DDP_SOCKET_RTMP) - return; - - struct rtmp_extended_data_t* in = (struct rtmp_extended_data_t*)(packet->data + sizeof(struct DDP_LONG)); - - size_t size = sizeof(struct DDP_SHORT) + sizeof(struct rtmp_nonextended_response_t); - byte* data = (byte*)malloc(size); - struct DDP_SHORT* header_short = (struct DDP_SHORT*)data; - convert_ddp_header_to_short(header_long, header_short); - header_short->length[0] = (size >> 8) & 0x03; - header_short->length[1] = size & 0xff; - - struct rtmp_nonextended_response_t* out = (struct rtmp_nonextended_response_t*)(data + sizeof(struct DDP_SHORT)); - out->net = in->net; - out->id_length = in->id_length; - out->node = in->node; - - /*rtmp_extended_tuple_t* in_tuple = (rtmp_extended_tuple_t*)(packet->data + sizeof(DDP_LONG) + sizeof(rtmp_extended_data_t)); - rtmp_nonextended_tuple_t* out_tuple = (rtmp_nonextended_tuple_t*)(data + size); - while ((byte*)in_tuple < (packet->data + packet->size)) - { - size += sizeof(rtmp_nonextended_tuple_t); - realloc(data, size); - out_tuple->net = in_tuple->range_start; - out_tuple->distance = in_tuple->distance & 0x7f; - in_tuple++; - }*/ - - free(packet->data); - packet->data = data; - packet->size = size; - packet->type = LAP_DDP_SHORT; - } -} - -/* Learn our network number from RTMP packets. */ -/* "Inside AppleTalk", section 4-8, describes this approach for non-extended networks. - Technically, we probably should be doing the more complicated extended network approach (also on 4-8), - but the easy approach using RTMP seems adequate for now. */ -static void glean_net_from_rtmp(struct packet_t* packet) -{ - if (packet && (packet->type == LAP_DDP_LONG) && packet->data) - { - struct DDP_LONG* header_long = (struct DDP_LONG*)packet->data; - if (header_long->type != DDP_TYPE_RTMP || header_long->dest_socket != DDP_SOCKET_RTMP) - return; - - struct rtmp_extended_data_t* in = (struct rtmp_extended_data_t*)(packet->data + sizeof(struct DDP_LONG)); - - atbridge_set_net(ntohs(in->net)); - } -} - -static void send_rtmp_request() -{ - struct packet_t* packet = (struct packet_t*)malloc(sizeof(struct packet_t)); - - packet->type = LAP_DDP_LONG; - packet->dest.network = atbridge_get_net(); - packet->dest.node = 255; - packet->source.network = atbridge_get_net(); - packet->source.node = atbridge_get_node(); - packet->next = 0; - packet->size = sizeof(struct DDP_LONG) + sizeof(struct rtmp_request_t); - packet->data = (byte*)malloc(packet->size); - - struct DDP_LONG* header = (struct DDP_LONG*)packet->data; - header->type = DDP_TYPE_RTMP_REQUEST; - header->source_net = htons(packet->source.network); - header->source_node = packet->source.node; - header->source_socket = DDP_SOCKET_RTMP; - header->dest_net = htons(packet->dest.network); - header->dest_node = packet->dest.node; - header->dest_socket = DDP_SOCKET_RTMP; - header->length[0] = (packet->size >> 8) & 0x03; - header->length[1] = packet->size & 0xff; - - struct rtmp_request_t* request = (struct rtmp_request_t*)(packet->data + sizeof(struct DDP_LONG)); - request->function = RTMP_FUNCTION_REQUEST; - - calculate_checksum(packet); - - elap_enqueue_out(packet); - sent_rtmp_request = true; -} - -void atbridge_process() -{ - elap_process(); - //llap_process(); - - struct packet_t* packet = elap_dequeue_in(); - if (packet) - { - glean_net_from_rtmp(packet); - convert_rtmp_to_nonextended(packet); - // The GS should understand long-form DDP, but converting to short-form ought to slightly improve performance (fewer bytes for the GS to process). - convert_ddp_packet_to_short(packet); - llap_enqueue_out(packet); - } - packet = llap_dequeue_in(); - if (packet) - { - // ELAP does not support short-form DDP, so convert such packets to long-form. - convert_ddp_packet_to_long(packet); - elap_enqueue_out(packet); - } -} \ No newline at end of file +/* + GSport - an Apple //gs Emulator + Copyright (C) 2010 - 2019 by GSport contributors + Copyright (C) 2016 - 2018 Dagen Brock + + Based on the KEGS emulator written by and Copyright (C) 2003 Kent Dickey + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 2 of the License, or (at your + option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +/** This module is the "heart" of the bridge and provides the connection between the ELAP and LLAP ports. **/ + +#include +#include "../defc.h" +#include +#include +#include "atbridge.h" +#include "port.h" +#include "elap.h" +#include "llap.h" +#include "aarp.h" + +#ifdef WIN32 +#include +#elif __linux__ +#include +#endif + +extern struct packet_port_t elap_port; + +static bool diagnostics = false; +static bool sent_rtmp_request = false; + +static struct at_addr_t local_address = { 0, 0 }; + +static const at_network_t NET_STARTUP_LOW = 0xFF00; +static const at_network_t NET_STARTUP_HIGH = 0xFFFE; +static const at_node_t NODE_STARTUP_LOW = 0x01; +static const at_node_t NODE_STARTUP_HIGH = 0xFE; + +static void send_rtmp_request(); + +bool atbridge_init() { + // If the GS reboots, we may try to reinitialize the bridge. If this is the case, keep the old address and AMT. + if (local_address.network == 0) + { + // Obtain a provisional node address and startup range network. + // + // This isn't correct for an extended network (like ELAP) but works adequately on small networks. + // The bridge should follow the complicated process on page 4-9 to obtain the network and node number. + srand((unsigned int)time(0)); + local_address.network = (at_network_t)((double)rand()/RAND_MAX * (NET_STARTUP_HIGH - NET_STARTUP_LOW) + NET_STARTUP_LOW); + local_address.node = (at_node_t)((double)rand()/RAND_MAX + (NODE_STARTUP_HIGH - NODE_STARTUP_LOW) + 0x01); + + aarp_init(); + llap_init(); + if (!elap_init()) + { + atbridge_shutdown(); + return false; + } + } + return true; +} + +void atbridge_shutdown() { + llap_shutdown(); + elap_shutdown(); + aarp_shutdown(); +} + +void atbridge_set_diagnostics(bool enabled) { + diagnostics = enabled; +} + +bool atbridge_get_diagnostics() { + return diagnostics; +} + +void atbridge_printf(const char *fmt, ...) { + if (atbridge_get_diagnostics()) + { + va_list args; + va_start(args, fmt); + vprintf(fmt, args); + va_end(args); + } +} + +const struct at_addr_t* atbridge_get_addr() { + return &local_address; +} + +const at_network_t atbridge_get_net() { + return local_address.network; +} + +const at_node_t atbridge_get_node() { + return local_address.node; +} + +void atbridge_set_net(at_network_t net) { + local_address.network = net; +} + +void atbridge_set_node(at_node_t node) { + local_address.node = node; +} + +bool atbridge_address_used(const struct at_addr_t* addr) { + if (!sent_rtmp_request) + send_rtmp_request(); + return aarp_address_used(addr); +} + +/* Calculate a DDP checksum, per Apple's documented algorithm in 4-17 of "Inside AppleTalk". */ +static word16 get_checksum(size_t size, byte data[]) { + word16 cksum = 0; + for (unsigned int i = 0; i < size; i++) + { + cksum += data[i]; + cksum = (cksum << 1) | ((cksum & 0x8000) >> 15); // roll left + } + if (cksum == 0) + cksum = 0xffff; + return cksum; +} + +static void calculate_checksum(struct packet_t* packet) { + if (packet && packet->data && (packet->size >= sizeof(struct DDP_LONG)) && (packet->type == LAP_DDP_LONG)) + { + struct DDP_LONG* header = (struct DDP_LONG*)(packet->data); + header->checksum = htons(get_checksum( + packet->size - offsetof(struct DDP_LONG, dest_net), + (byte*)&header->dest_net)); + } +} + +/* Convert a long-form DDP header to a short-form header. This function only converts the headers. */ +static word16 convert_ddp_header_to_short(const struct DDP_LONG* in, struct DDP_SHORT* out) { + word16 size; + + if (!in || !out) + return 0; + + size = ((in->length[0] & 0x3) << 8) + (in->length[1]) - (sizeof(struct DDP_LONG) - sizeof(struct DDP_SHORT)); + + out->length[0] = (size >> 8) & 0x03; + out->length[1] = size & 0xff; + + out->dest_socket = in->dest_socket; + out->source_socket = in->source_socket; + + out->type = in->type; + + return size; +} + +/* Convert a short-form DDP header to a long-form header. ELAP requires long-form, but LLAP often uses short-form. */ +/* This function only converts the headers. */ +static word16 convert_ddp_header_to_long(const struct at_addr_t dest, const struct at_addr_t source, const struct DDP_SHORT* in, struct DDP_LONG* out) { + word16 size; + + if (!in || !out) + return 0; + + size = ((in->length[0] & 0x3) << 8) + (in->length[1]) + (sizeof(struct DDP_LONG) - sizeof(struct DDP_SHORT)); + out->length[0] = (size >> 8) & 0x03; + out->length[1] = size & 0xff; + + out->checksum = 0x0000; /* 0x0000 == no checksum calculated, reference 4-17 */ + + if (dest.network) + out->dest_net = dest.network; + else + out->dest_net = atbridge_get_net(); + out->dest_net = (at_network_t)htons(out->dest_net); + + if (source.network) + out->source_net = source.network; + else + out->source_net = atbridge_get_net(); + out->source_net = (at_network_t)htons(out->source_net); + + out->dest_node = dest.node; + out->source_node = source.node; + + out->dest_socket = in->dest_socket; + out->source_socket = in->source_socket; + + out->type = in->type; + + return size; +} + +/* Convert a short-form DDP packet to a long-form packet. */ +/* This function converts an entire packet, not just the header. */ +static void convert_ddp_packet_to_long(struct packet_t* packet) { + if (packet && (packet->type == LAP_DDP_SHORT) && packet->data && (packet->size >= sizeof(struct DDP_SHORT))) + { + struct DDP_SHORT* header_short = (struct DDP_SHORT*)packet->data; + + const size_t payload_size = packet->size - sizeof(struct DDP_SHORT); + byte* data = (byte*)malloc(payload_size + sizeof(struct DDP_LONG)); + struct DDP_LONG* header_long = (struct DDP_LONG*)data; + + const word16 size = convert_ddp_header_to_long(packet->dest, packet->source, header_short, header_long); + packet->dest.network = ntohs(header_long->dest_net); + packet->source.network = ntohs(header_long->source_net); + + memcpy(data + sizeof(struct DDP_LONG), packet->data + sizeof(struct DDP_SHORT), payload_size); + + packet->type = LAP_DDP_LONG; + packet->size = size; + + // Replace the original short-form packet data. + free(packet->data); + packet->data = data; + + calculate_checksum(packet); + } +} + +/* Convert a long-form DDP packet to short-form. */ +static void convert_ddp_packet_to_short(struct packet_t* packet) { + if (packet && (packet->type == LAP_DDP_LONG) && packet->data) + { + struct DDP_LONG* header_long = (struct DDP_LONG*)packet->data; + + const size_t payload_size = packet->size - sizeof(struct DDP_LONG); + byte* data = (byte*)malloc(payload_size + sizeof(struct DDP_SHORT)); + struct DDP_SHORT* header_short = (struct DDP_SHORT*)data; + + const word16 size = convert_ddp_header_to_short(header_long, header_short); + + memcpy(data + sizeof(struct DDP_SHORT), packet->data + sizeof(struct DDP_LONG), payload_size); + + packet->type = LAP_DDP_SHORT; + packet->size = size; + + free(packet->data); + packet->data = data; + } +} + +/*static void convert_rtmp_to_extended(struct packet_t* packet) + { + if (packet && (packet->type == LAP_DDP_SHORT) && packet->data) + { + struct DDP_SHORT* header_short = (struct DDP_SHORT*)packet->data; + if (header_short->type != DDP_TYPE_RTMP || header_short->dest_socket != DDP_SOCKET_RTMP) + return; + + struct rtmp_nonextended_data_t* in = (struct rtmp_nonextended_data_t*)(packet->data + sizeof(struct DDP_SHORT)); + + // Construct a new long-form DDP packet header. + size_t size = sizeof(struct DDP_LONG) + sizeof(struct rtmp_extended_data_t); + byte* data = (byte*)malloc(size); + struct DDP_LONG* header_long = (struct DDP_LONG*)data; + convert_ddp_header_to_long(packet->dest, packet->source, header_short, header_long); + + struct rtmp_extended_data_t* out = (struct rtmp_extended_data_t*)(data + sizeof(struct DDP_LONG)); + out->net = in->net; + out->id_length = in->id_length; + out->node = in->node; + + // Copy the routing tuples. + struct rtmp_nonextended_tuple_t* in_tuple = (struct rtmp_nonextended_tuple_t*)(packet->data + sizeof(struct DDP_SHORT) + sizeof(struct rtmp_nonextended_data_t)); + struct rtmp_extended_tuple_t* out_tuple = (struct rtmp_extended_tuple_t*)(data + size); + while ((byte*)in_tuple < (packet->data + packet->size)) + { + size += sizeof(struct rtmp_extended_tuple_t); + realloc(data, size); + out_tuple->range_start = in_tuple->net; + out_tuple->distance = in_tuple->distance | 0x80; + out_tuple->range_end = in_tuple->net; + out_tuple->delimiter = RTMP_TUPLE_DELIMITER; + in_tuple++; + } + + free(packet->data); + packet->data = data; + packet->size = size; + packet->type = LAP_DDP_LONG; + } + }*/ + +static void convert_rtmp_to_nonextended(struct packet_t* packet) { + if (packet && (packet->type == LAP_DDP_LONG) && packet->data) + { + struct DDP_LONG* header_long = (struct DDP_LONG*)packet->data; + if (header_long->type != DDP_TYPE_RTMP || header_long->dest_socket != DDP_SOCKET_RTMP) + return; + + struct rtmp_extended_data_t* in = (struct rtmp_extended_data_t*)(packet->data + sizeof(struct DDP_LONG)); + + size_t size = sizeof(struct DDP_SHORT) + sizeof(struct rtmp_nonextended_response_t); + byte* data = (byte*)malloc(size); + struct DDP_SHORT* header_short = (struct DDP_SHORT*)data; + convert_ddp_header_to_short(header_long, header_short); + header_short->length[0] = (size >> 8) & 0x03; + header_short->length[1] = size & 0xff; + + struct rtmp_nonextended_response_t* out = (struct rtmp_nonextended_response_t*)(data + sizeof(struct DDP_SHORT)); + out->net = in->net; + out->id_length = in->id_length; + out->node = in->node; + + /*rtmp_extended_tuple_t* in_tuple = (rtmp_extended_tuple_t*)(packet->data + sizeof(DDP_LONG) + sizeof(rtmp_extended_data_t)); + rtmp_nonextended_tuple_t* out_tuple = (rtmp_nonextended_tuple_t*)(data + size); + while ((byte*)in_tuple < (packet->data + packet->size)) + { + size += sizeof(rtmp_nonextended_tuple_t); + realloc(data, size); + out_tuple->net = in_tuple->range_start; + out_tuple->distance = in_tuple->distance & 0x7f; + in_tuple++; + }*/ + + free(packet->data); + packet->data = data; + packet->size = size; + packet->type = LAP_DDP_SHORT; + } +} + +/* Learn our network number from RTMP packets. */ +/* "Inside AppleTalk", section 4-8, describes this approach for non-extended networks. + Technically, we probably should be doing the more complicated extended network approach (also on 4-8), + but the easy approach using RTMP seems adequate for now. */ +static void glean_net_from_rtmp(struct packet_t* packet) { + if (packet && (packet->type == LAP_DDP_LONG) && packet->data) + { + struct DDP_LONG* header_long = (struct DDP_LONG*)packet->data; + if (header_long->type != DDP_TYPE_RTMP || header_long->dest_socket != DDP_SOCKET_RTMP) + return; + + struct rtmp_extended_data_t* in = (struct rtmp_extended_data_t*)(packet->data + sizeof(struct DDP_LONG)); + + atbridge_set_net(ntohs(in->net)); + } +} + +static void send_rtmp_request() { + struct packet_t* packet = (struct packet_t*)malloc(sizeof(struct packet_t)); + + packet->type = LAP_DDP_LONG; + packet->dest.network = atbridge_get_net(); + packet->dest.node = 255; + packet->source.network = atbridge_get_net(); + packet->source.node = atbridge_get_node(); + packet->next = 0; + packet->size = sizeof(struct DDP_LONG) + sizeof(struct rtmp_request_t); + packet->data = (byte*)malloc(packet->size); + + struct DDP_LONG* header = (struct DDP_LONG*)packet->data; + header->type = DDP_TYPE_RTMP_REQUEST; + header->source_net = htons(packet->source.network); + header->source_node = packet->source.node; + header->source_socket = DDP_SOCKET_RTMP; + header->dest_net = htons(packet->dest.network); + header->dest_node = packet->dest.node; + header->dest_socket = DDP_SOCKET_RTMP; + header->length[0] = (packet->size >> 8) & 0x03; + header->length[1] = packet->size & 0xff; + + struct rtmp_request_t* request = (struct rtmp_request_t*)(packet->data + sizeof(struct DDP_LONG)); + request->function = RTMP_FUNCTION_REQUEST; + + calculate_checksum(packet); + + elap_enqueue_out(packet); + sent_rtmp_request = true; +} + +void atbridge_process() { + elap_process(); + //llap_process(); + + struct packet_t* packet = elap_dequeue_in(); + if (packet) + { + glean_net_from_rtmp(packet); + convert_rtmp_to_nonextended(packet); + // The GS should understand long-form DDP, but converting to short-form ought to slightly improve performance (fewer bytes for the GS to process). + convert_ddp_packet_to_short(packet); + llap_enqueue_out(packet); + } + packet = llap_dequeue_in(); + if (packet) + { + // ELAP does not support short-form DDP, so convert such packets to long-form. + convert_ddp_packet_to_long(packet); + elap_enqueue_out(packet); + } +} diff --git a/src/atbridge/atbridge.h b/src/atbridge/atbridge.h index f7bb27e..9592e91 100644 --- a/src/atbridge/atbridge.h +++ b/src/atbridge/atbridge.h @@ -1,47 +1,49 @@ -/* -GSport - an Apple //gs Emulator -Copyright (C) 2013-2014 by Peter Neubauer - -This program is free software; you can redistribute it and/or modify it -under the terms of the GNU General Public License as published by the -Free Software Foundation; either version 2 of the License, or (at your -option) any later version. - -This program is distributed in the hope that it will be useful, but -WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY -or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -for more details. - -You should have received a copy of the GNU General Public License along -with this program; if not, write to the Free Software Foundation, Inc., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ - -/** -ATBridge is a limited function AppleTalk bridge that allows GSPort to connect to an -EtherTalk network. The bridge has two ports, one the emulated LocalTalk port and the -other an EtherTalk Phase II port. - -Due to timing requirements of LocalTalk, it is not reasonable to transparently bridge -LLAP traffic to ELAP. For example, implementing the lapENQ/lapACK LLAP control packets -requires AARP queries on the ELAP port, which can't be reasonably done within the 200us -LLAP interframe gap. So, we must implement the local bridge functionality detailed -in "Inside AppleTalk", including AARP, RTMP, ZIP, and DDP routing. -**/ -#include "atalk.h" - -bool atbridge_init(); -void atbridge_shutdown(); -void atbridge_process(); - -void atbridge_set_diagnostics(bool enabled); -bool atbridge_get_diagnostics(); -void atbridge_printf(const char *fmt, ...); - -const struct at_addr_t* atbridge_get_addr(); -const at_network_t atbridge_get_net(); -const at_node_t atbridge_get_node(); -void atbridge_set_net(at_network_t net); -void atbridge_set_node(at_node_t node); -bool atbridge_address_used(const struct at_addr_t* addr); - +/* + GSport - an Apple //gs Emulator + Copyright (C) 2010 - 2019 by GSport contributors + Copyright (C) 2016 - 2018 Dagen Brock + + Based on the KEGS emulator written by and Copyright (C) 2003 Kent Dickey + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 2 of the License, or (at your + option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +/** +ATBridge is a limited function AppleTalk bridge that allows GSPort to connect to an +EtherTalk network. The bridge has two ports, one the emulated LocalTalk port and the +other an EtherTalk Phase II port. + +Due to timing requirements of LocalTalk, it is not reasonable to transparently bridge +LLAP traffic to ELAP. For example, implementing the lapENQ/lapACK LLAP control packets +requires AARP queries on the ELAP port, which can't be reasonably done within the 200us +LLAP interframe gap. So, we must implement the local bridge functionality detailed +in "Inside AppleTalk", including AARP, RTMP, ZIP, and DDP routing. +**/ +#include "atalk.h" + +bool atbridge_init(); +void atbridge_shutdown(); +void atbridge_process(); + +void atbridge_set_diagnostics(bool enabled); +bool atbridge_get_diagnostics(); +void atbridge_printf(const char *fmt, ...); + +const struct at_addr_t* atbridge_get_addr(); +const at_network_t atbridge_get_net(); +const at_node_t atbridge_get_node(); +void atbridge_set_net(at_network_t net); +void atbridge_set_node(at_node_t node); +bool atbridge_address_used(const struct at_addr_t* addr); diff --git a/src/atbridge/atbridge.vcxproj b/src/atbridge/atbridge.vcxproj index 30defba..8654124 100644 --- a/src/atbridge/atbridge.vcxproj +++ b/src/atbridge/atbridge.vcxproj @@ -1,108 +1,108 @@ - - - - - Debug - Win32 - - - Release - Win32 - - - - - - - - - - - - - - - - - - - - - - - {2C88133A-7CB8-4C03-AF4D-4ECFC6F8500B} - Win32Proj - atbridge - - - - StaticLibrary - true - v140 - MultiByte - - - StaticLibrary - false - v140 - true - MultiByte - - - - - - - - - - - - - - - - - Level3 - Disabled - WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) - true - Default - false - - - Windows - true - - - %(AdditionalDependencies) - - - - - Level3 - - - MaxSpeed - true - true - WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) - true - Speed - StreamingSIMDExtensions2 - Default - - - Windows - true - true - true - - - %(AdditionalDependencies) - - - - - - \ No newline at end of file + + + + + Debug + Win32 + + + Release + Win32 + + + + + + + + + + + + + + + + + + + + + + + {2C88133A-7CB8-4C03-AF4D-4ECFC6F8500B} + Win32Proj + atbridge + + + + StaticLibrary + true + v120 + MultiByte + + + StaticLibrary + false + v120 + true + MultiByte + + + + + + + + + + + + + + + + + Level3 + Disabled + WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) + true + Default + false + + + Windows + true + + + %(AdditionalDependencies) + + + + + Level3 + + + MaxSpeed + true + true + WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) + true + Speed + StreamingSIMDExtensions2 + Default + + + Windows + true + true + true + + + %(AdditionalDependencies) + + + + + + diff --git a/src/atbridge/atbridge.vcxproj.filters b/src/atbridge/atbridge.vcxproj.filters index 1c12228..3cbdd44 100644 --- a/src/atbridge/atbridge.vcxproj.filters +++ b/src/atbridge/atbridge.vcxproj.filters @@ -1,66 +1,66 @@ - - - - - {4FC737F1-C7A5-4376-A066-2A32D752A2FF} - cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx - - - {93995380-89BD-4b04-88EB-625FBE52EBFB} - h;hpp;hxx;hm;inl;inc;xsd - - - {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} - rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms - - - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - \ No newline at end of file + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + diff --git a/src/atbridge/elap.c b/src/atbridge/elap.c index c21c710..961a4cf 100644 --- a/src/atbridge/elap.c +++ b/src/atbridge/elap.c @@ -1,396 +1,389 @@ -/* -GSport - an Apple //gs Emulator -Copyright (C) 2013-2014 by Peter Neubauer - -This program is free software; you can redistribute it and/or modify it -under the terms of the GNU General Public License as published by the -Free Software Foundation; either version 2 of the License, or (at your -option) any later version. - -This program is distributed in the hope that it will be useful, but -WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY -or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -for more details. - -You should have received a copy of the GNU General Public License along -with this program; if not, write to the Free Software Foundation, Inc., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ - -/** This module implements the ELAP port of the bridge. **/ - -#include -#include "../defc.h" -#include "atbridge.h" -#include "elap.h" -#include "port.h" -#include "aarp.h" -#include "elap_defs.h" -#include "pcap_delay.h" - -#ifdef __CYGWIN__ -#include -#include -#endif -#ifdef WIN32 -#include -#include -#endif -#ifdef __linux__ -#include -#include -#endif - -extern int g_ethernet_interface; - -static pcap_t* pcap_session; - -static struct packet_port_t elap_port; -static struct ether_addr_t HW_LOCAL; - -/*static void dump_device_list(pcap_if_t* devices) -{ - int i = 0; - for(pcap_if_t* device = devices; device; device = device->next) - { - printf("%d. %s", ++i, device->name); - if (device->description) - printf(" (%s)\n", device->description); - else - printf(" (No description available)\n"); - } -}*/ - -static void elap_clone_host_mac(pcap_if_t* device) -{ - if (!device) - return; - -#ifdef WIN32 - //// - // Extract the device GUID, which Windows uses to identify the device. - char* name = device->name; - while (name && *name != '{') - name++; - size_t guidLen = strlen(name); - - //// - // Find and copy the device MAC address. - ULONG size = sizeof(IP_ADAPTER_ADDRESSES) * 15; - IP_ADAPTER_ADDRESSES* addresses = malloc(size); - - ULONG result = GetAdaptersAddresses(AF_UNSPEC, - GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_MULTICAST | GAA_FLAG_SKIP_DNS_SERVER, NULL, addresses, &size); - - if (result == ERROR_BUFFER_OVERFLOW) - { - // The addresses buffer is too small. Allocate a bigger buffer. - free(addresses); - addresses = malloc(size); - result = GetAdaptersAddresses(AF_UNSPEC, - GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_MULTICAST | GAA_FLAG_SKIP_DNS_SERVER, NULL, addresses, &size); - } - - if (result == NO_ERROR) - { - // Search for the desired adapter address. - IP_ADAPTER_ADDRESSES* current = addresses; - while (current) - { - if (current->PhysicalAddressLength == ETHER_ADDR_LEN && memcmp(current->AdapterName, name, guidLen) == 0) - { - memcpy(&HW_LOCAL.mac, ¤t->PhysicalAddress, sizeof(HW_LOCAL.mac)); - break; - } - current = current->Next; - } - } - else - { - halt_printf("ATBridge: Failed to find host MAC address (%d).", result); - } - - free(addresses); -#else - struct pcap_addr* address; - for (address = device->addresses; address != 0; address = address->next) - if (address->addr->sa_family == AF_PACKET) - { - struct sockaddr_ll* ll = (struct sockaddr_ll*)address->addr; - memcpy(&HW_LOCAL.mac, ll->sll_addr, sizeof(HW_LOCAL.mac)); - } -#endif -} - -const struct ether_addr_t* elap_get_mac() -{ - return &HW_LOCAL; -} - -bool elap_init() -{ - port_init(&elap_port); - - memcpy(&HW_LOCAL, &HW_LOCAL_DEFAULT, sizeof(HW_LOCAL)); - - pcap_if_t* device; - pcap_if_t* alldevs; - int i = 0; - - char errbuf[PCAP_ERRBUF_SIZE]; - - // Load the PCAP library. - if (!pcapdelay_load()) - { - halt_printf("ATBridge: PCAP not available.\n"); - return false; - } - - // Retrieve the device list. - if(pcapdelay_findalldevs(&alldevs, errbuf) == -1) - { - atbridge_printf("ATBridge: Error enumerating PCAP devices: %s\n", errbuf); - return false; - } - //dump_device_list(alldevs); - - // Jump to the selected adapter. - for (device = alldevs, i = 0; i < g_ethernet_interface; device = device->next, i++); - if (!device) - { - halt_printf("ATBridge: PCAP device not found. Check interface number in settings.\n"); - return false; - } - - // Clone the MAC address of the underlying interface. In certain configurations (e.g. Windows with an MS Loopback - // interface), the interface, even in promiscous mode, filters foreign MAC addresses. - elap_clone_host_mac(device); - - // Open the adapter, - if ((pcap_session = pcapdelay_open_live(device->name, // name of the device - 65536, // portion of the packet to capture. - // 65536 grants that the whole packet will be captured on all the MACs. - 1, // promiscuous mode (nonzero means promiscuous) - 1, // read timeout - errbuf // error buffer - )) == NULL) - { - halt_printf("ATBridge: Unable to open the adapter. Pcap does not support %s.\n", device->name); - pcapdelay_freealldevs(alldevs); - return false; - } +/* + GSport - an Apple //gs Emulator + Copyright (C) 2010 - 2019 by GSport contributors + Copyright (C) 2016 - 2018 Dagen Brock + + Based on the KEGS emulator written by and Copyright (C) 2003 Kent Dickey - // The device must support Ethernet because the bridge "speaks" EtherTalk. - if (pcapdelay_datalink(pcap_session) == DLT_EN10MB) - { - pcapdelay_setnonblock(pcap_session, 1, errbuf); - - atbridge_printf("ATBridge: AppleTalk bridging using network device '%s' with Ethernet address %.2X:%.2X:%.2X:%.2X:%.2X:%.2X.\n", - device->description, HW_LOCAL.mac[0], HW_LOCAL.mac[1], HW_LOCAL.mac[2], HW_LOCAL.mac[3], HW_LOCAL.mac[4], HW_LOCAL.mac[5]); - - pcapdelay_freealldevs(alldevs); - return true; - } - else - { - pcapdelay_close(pcap_session); - pcap_session = 0; - halt_printf("ATBridge: Selected network device %s must support Ethernet.\n", device->description); - pcapdelay_freealldevs(alldevs); - return false; - } -} - -void elap_shutdown() -{ - port_shutdown(&elap_port); - if (pcap_session) - { - pcapdelay_close(pcap_session); - pcap_session = 0; - } - pcapdelay_unload(); -} - -void elap_enqueue_out(struct packet_t* packet) -{ - enqueue_packet(&elap_port.out, packet); -} - -struct packet_t* elap_dequeue_in() -{ - return dequeue(&elap_port.in); -} - -void elap_send(const struct ether_addr_t* dest, const struct snap_discriminator_t* discriminator, size_t size, byte data[]) -{ - if (pcap_session && dest && discriminator) - { - // Allocate heap space for the frame. - const size_t frame_size = sizeof(struct ethernet_header_t) + sizeof(struct snap_header_t) + size; - u_char* frame_data; - size_t pad = 0; - if (frame_size < ETHER_MIN_SIZE) - pad = ETHER_MIN_SIZE - frame_size; - frame_data = (u_char*)malloc(frame_size + pad); - - // Build the 802.3 header. - struct ethernet_header_t* ether = (struct ethernet_header_t*)frame_data; - memcpy(ether->dest.mac, dest, sizeof(ether->dest.mac)); - memcpy(ether->source.mac, HW_LOCAL.mac, sizeof(ether->source.mac)); - ether->length = htons(frame_size - sizeof(struct ethernet_header_t)); - - // Build the 802.2 header. - struct snap_header_t* snap = (struct snap_header_t*)(frame_data + sizeof(struct ethernet_header_t)); - snap->dsap = SNAP_DSAP; - snap->ssap = SNAP_SSAP; - snap->control = SNAP_CONTROL; - memcpy(&snap->discriminator, discriminator, sizeof(snap->discriminator)); - - // Add the data payload. - struct snap_header_t* payload = (struct snap_header_t*)(frame_data + sizeof(struct ethernet_header_t) + sizeof(struct snap_header_t)); - memcpy(payload, data, size); - - // Add padding to meet minimum Ethernet frame size. - if (pad > 0) - memset(frame_data + frame_size, 0, pad); - - pcapdelay_sendpacket(pcap_session, frame_data, frame_size + pad); - } -} - -static bool elap_send_one_queued() -{ - // Attempt to send one packet out the host network interface. - struct packet_t* packet = queue_peek(&elap_port.out); - if (packet) - { - // Find the MAC address. - const struct ether_addr_t* dest; - if (packet->dest.node == at_broadcast_node) - dest = &HW_APPLETALK_BROADCAST; - else - dest = aarp_request_hardware(&packet->dest); - - // Send it. - if (dest) - { - elap_send(dest, &SNAP_APPLETALK, packet->size, packet->data); - - dequeue(&elap_port.out); - free(packet->data); - free(packet); - } - else - { - // AARP does not have the needed hardware address. Give AARP time to obtain the address and keep the current packet. - if (!aarp_retry()) - { - // However, if AARP has reached the retry limit, the packet is undeliverable. Discard the packet and move on. - atbridge_printf("ATBridge: AARP failed to find MAC address for network %d node %d. Dropping packet.\n", packet->dest.network, packet->dest.node); - aarp_retry_reset(); - dequeue(&elap_port.out); - free(packet->data); - free(packet); - } - } - return true; - } - else - return false; -} - -static void elap_send_all_queued() -{ - while (elap_send_one_queued()); -} - -static bool elap_receive_one() -{ - if (!pcap_session) - return false; - - struct pcap_pkthdr header; - const u_char* packet = pcapdelay_next(pcap_session, &header); - if (packet) - { - // Receive and process one packet from the host network interface. - //// - - // Check the Ethernet 802.3 header. - const struct ethernet_header_t* ether = (struct ethernet_header_t*)packet; - if (header.len > sizeof(struct ethernet_header_t) && - ntohs(ether->length) <= ETHER_MAX_SIZE && - ntohs(ether->length) > sizeof(struct snap_header_t) && - (memcmp(ðer->source, &HW_LOCAL, sizeof(ether->source)) != 0) && /* Ignore packets sent from our node. */ - (memcmp(ðer->dest, &HW_LOCAL, sizeof(ether->dest)) == 0 || /* Accept packets destined for our node ... */ - memcmp(ðer->dest, &HW_APPLETALK_BROADCAST, sizeof(ether->dest)) == 0 /* ... or for broadcast. */) - ) - { - // Check the 802.2 SNAP header. - const struct snap_header_t* snap = (struct snap_header_t*)(packet + sizeof(struct ethernet_header_t)); - if (snap->dsap == SNAP_DSAP && - snap->ssap == SNAP_SSAP && - snap->control == SNAP_CONTROL) - { - if (memcmp(&snap->discriminator, &SNAP_APPLETALK, sizeof(snap->discriminator)) == 0) - { - // Handle an AppleTalk packet. - const size_t payload_size = ntohs(ether->length) - sizeof(struct snap_header_t); - const u_char* payload = packet + sizeof(struct ethernet_header_t) + sizeof(struct snap_header_t); - - byte* copy = (byte*)malloc(payload_size); - memcpy(copy, payload, payload_size); - - // ELAP does not support short-form DDP, so this must be a long-form DDP packet. - struct at_addr_t source, dest; - if (payload_size >= sizeof(struct DDP_LONG)) - { - // Extract the protocol address from the header. - // - // ELAP really shouldn't be looking at the header for the next level of the protocol stack, - // but this is a convenient place to glean addresses for the AMT, a process that needs both - // hardware and protocol addresses. - struct DDP_LONG* header = (struct DDP_LONG*)copy; - dest.network = (at_network_t)ntohs(header->dest_net); - source.network = (at_network_t)ntohs(header->source_net); - dest.node = header->dest_node; - source.node = header->source_node; - - enqueue(&elap_port.in, dest, source, LAP_DDP_LONG, payload_size, copy); - - aarp_glean(&source, ðer->source); - } - else - atbridge_printf("ATBridge: Dropping invalid short ELAP frame.\n"); - } - else if (memcmp(&snap->discriminator, &SNAP_AARP, sizeof(snap->discriminator)) == 0) - { - // Handle an AARP packet. - struct aarp_header_t* aarp = (struct aarp_header_t*)(packet + sizeof(struct ethernet_header_t) + sizeof(struct snap_header_t)); - aarp->dest_proto_addr.addr.network = ntohs(aarp->dest_proto_addr.addr.network); - aarp->source_proto_addr.addr.network = ntohs(aarp->source_proto_addr.addr.network); - aarp->function = ntohs(aarp->function); - aarp->hardware_type = ntohs(aarp->hardware_type); - aarp->protocol_type = ntohs(aarp->protocol_type); - aarp_handle_packet(aarp); - } - } - } - - return true; - } - else - return false; -} - -static void elap_receive_all() -{ - while (elap_receive_one()); -} - -void elap_process() -{ - elap_receive_all(); - elap_send_all_queued(); -} \ No newline at end of file + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 2 of the License, or (at your + option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +/** This module implements the ELAP port of the bridge. **/ + +#include +#include "../defc.h" +#include "atbridge.h" +#include "elap.h" +#include "port.h" +#include "aarp.h" +#include "elap_defs.h" +#include "pcap_delay.h" + +#ifdef __CYGWIN__ +#include +#include +#endif +#ifdef WIN32 +#include +#include +#endif +#ifdef __linux__ +#include +#include +#endif + +extern int g_ethernet_interface; + +static pcap_t* pcap_session; + +static struct packet_port_t elap_port; +static struct ether_addr_t HW_LOCAL; + +/*static void dump_device_list(pcap_if_t* devices) + { + int i = 0; + for(pcap_if_t* device = devices; device; device = device->next) + { + printf("%d. %s", ++i, device->name); + if (device->description) + printf(" (%s)\n", device->description); + else + printf(" (No description available)\n"); + } + }*/ + +static void elap_clone_host_mac(pcap_if_t* device) { + if (!device) + return; + +#ifdef WIN32 + //// + // Extract the device GUID, which Windows uses to identify the device. + char* name = device->name; + while (name && *name != '{') + name++; + size_t guidLen = strlen(name); + + //// + // Find and copy the device MAC address. + ULONG size = sizeof(IP_ADAPTER_ADDRESSES) * 15; + IP_ADAPTER_ADDRESSES* addresses = malloc(size); + + ULONG result = GetAdaptersAddresses(AF_UNSPEC, + GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_MULTICAST | GAA_FLAG_SKIP_DNS_SERVER, NULL, addresses, &size); + + if (result == ERROR_BUFFER_OVERFLOW) + { + // The addresses buffer is too small. Allocate a bigger buffer. + free(addresses); + addresses = malloc(size); + result = GetAdaptersAddresses(AF_UNSPEC, + GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_MULTICAST | GAA_FLAG_SKIP_DNS_SERVER, NULL, addresses, &size); + } + + if (result == NO_ERROR) + { + // Search for the desired adapter address. + IP_ADAPTER_ADDRESSES* current = addresses; + while (current) + { + if (current->PhysicalAddressLength == ETHER_ADDR_LEN && memcmp(current->AdapterName, name, guidLen) == 0) + { + memcpy(&HW_LOCAL.mac, ¤t->PhysicalAddress, sizeof(HW_LOCAL.mac)); + break; + } + current = current->Next; + } + } + else + { + halt_printf("ATBridge: Failed to find host MAC address (%d).", result); + } + + free(addresses); +#else + #ifdef AF_PACKET + struct pcap_addr* address; + for (address = device->addresses; address != 0; address = address->next) + if (address->addr->sa_family == AF_PACKET) + { + struct sockaddr_ll* ll = (struct sockaddr_ll*)address->addr; + memcpy(&HW_LOCAL.mac, ll->sll_addr, sizeof(HW_LOCAL.mac)); + } + #endif +#endif +} + +const struct ether_addr_t* elap_get_mac() { + return &HW_LOCAL; +} + +bool elap_init() { + port_init(&elap_port); + + memcpy(&HW_LOCAL, &HW_LOCAL_DEFAULT, sizeof(HW_LOCAL)); + + pcap_if_t* device; + pcap_if_t* alldevs; + int i = 0; + + char errbuf[PCAP_ERRBUF_SIZE]; + + // Load the PCAP library. + if (!pcapdelay_load()) + { + halt_printf("ATBridge: PCAP not available.\n"); + return false; + } + + // Retrieve the device list. + if(pcapdelay_findalldevs(&alldevs, errbuf) == -1) + { + atbridge_printf("ATBridge: Error enumerating PCAP devices: %s\n", errbuf); + return false; + } + //dump_device_list(alldevs); + + // Jump to the selected adapter. + for (device = alldevs, i = 0; i < g_ethernet_interface; device = device->next, i++); + if (!device) + { + halt_printf("ATBridge: PCAP device not found. Check interface number in settings.\n"); + return false; + } + + // Clone the MAC address of the underlying interface. In certain configurations (e.g. Windows with an MS Loopback + // interface), the interface, even in promiscous mode, filters foreign MAC addresses. + elap_clone_host_mac(device); + + // Open the adapter, + if ((pcap_session = pcapdelay_open_live(device->name, // name of the device + 65536, // portion of the packet to capture. + // 65536 grants that the whole packet will be captured on all the MACs. + 1, // promiscuous mode (nonzero means promiscuous) + 1, // read timeout + errbuf // error buffer + )) == NULL) + { + halt_printf("ATBridge: Unable to open the adapter. Pcap does not support %s.\n", device->name); + pcapdelay_freealldevs(alldevs); + return false; + } + + // The device must support Ethernet because the bridge "speaks" EtherTalk. + if (pcapdelay_datalink(pcap_session) == DLT_EN10MB) + { + pcapdelay_setnonblock(pcap_session, 1, errbuf); + + atbridge_printf("ATBridge: AppleTalk bridging using network device '%s' with Ethernet address %.2X:%.2X:%.2X:%.2X:%.2X:%.2X.\n", + device->description, HW_LOCAL.mac[0], HW_LOCAL.mac[1], HW_LOCAL.mac[2], HW_LOCAL.mac[3], HW_LOCAL.mac[4], HW_LOCAL.mac[5]); + + pcapdelay_freealldevs(alldevs); + return true; + } + else + { + pcapdelay_close(pcap_session); + pcap_session = 0; + halt_printf("ATBridge: Selected network device %s must support Ethernet.\n", device->description); + pcapdelay_freealldevs(alldevs); + return false; + } +} + +void elap_shutdown() { + port_shutdown(&elap_port); + if (pcap_session) + { + pcapdelay_close(pcap_session); + pcap_session = 0; + } + pcapdelay_unload(); +} + +void elap_enqueue_out(struct packet_t* packet) { + enqueue_packet(&elap_port.out, packet); +} + +struct packet_t* elap_dequeue_in() { + return dequeue(&elap_port.in); +} + +void elap_send(const struct ether_addr_t* dest, const struct snap_discriminator_t* discriminator, size_t size, byte data[]) { + if (pcap_session && dest && discriminator) + { + // Allocate heap space for the frame. + const size_t frame_size = sizeof(struct ethernet_header_t) + sizeof(struct snap_header_t) + size; + u_char* frame_data; + size_t pad = 0; + if (frame_size < ETHER_MIN_SIZE) + pad = ETHER_MIN_SIZE - frame_size; + frame_data = (u_char*)malloc(frame_size + pad); + + // Build the 802.3 header. + struct ethernet_header_t* ether = (struct ethernet_header_t*)frame_data; + memcpy(ether->dest.mac, dest, sizeof(ether->dest.mac)); + memcpy(ether->source.mac, HW_LOCAL.mac, sizeof(ether->source.mac)); + ether->length = htons(frame_size - sizeof(struct ethernet_header_t)); + + // Build the 802.2 header. + struct snap_header_t* snap = (struct snap_header_t*)(frame_data + sizeof(struct ethernet_header_t)); + snap->dsap = SNAP_DSAP; + snap->ssap = SNAP_SSAP; + snap->control = SNAP_CONTROL; + memcpy(&snap->discriminator, discriminator, sizeof(snap->discriminator)); + + // Add the data payload. + struct snap_header_t* payload = (struct snap_header_t*)(frame_data + sizeof(struct ethernet_header_t) + sizeof(struct snap_header_t)); + memcpy(payload, data, size); + + // Add padding to meet minimum Ethernet frame size. + if (pad > 0) + memset(frame_data + frame_size, 0, pad); + + pcapdelay_sendpacket(pcap_session, frame_data, frame_size + pad); + } +} + +static bool elap_send_one_queued() { + // Attempt to send one packet out the host network interface. + struct packet_t* packet = queue_peek(&elap_port.out); + if (packet) + { + // Find the MAC address. + const struct ether_addr_t* dest; + if (packet->dest.node == at_broadcast_node) + dest = &HW_APPLETALK_BROADCAST; + else + dest = aarp_request_hardware(&packet->dest); + + // Send it. + if (dest) + { + elap_send(dest, &SNAP_APPLETALK, packet->size, packet->data); + + dequeue(&elap_port.out); + free(packet->data); + free(packet); + } + else + { + // AARP does not have the needed hardware address. Give AARP time to obtain the address and keep the current packet. + if (!aarp_retry()) + { + // However, if AARP has reached the retry limit, the packet is undeliverable. Discard the packet and move on. + atbridge_printf("ATBridge: AARP failed to find MAC address for network %d node %d. Dropping packet.\n", packet->dest.network, packet->dest.node); + aarp_retry_reset(); + dequeue(&elap_port.out); + free(packet->data); + free(packet); + } + } + return true; + } + else + return false; +} + +static void elap_send_all_queued() { + while (elap_send_one_queued()); +} + +static bool elap_receive_one() { + if (!pcap_session) + return false; + + struct pcap_pkthdr header; + const u_char* packet = pcapdelay_next(pcap_session, &header); + if (packet) + { + // Receive and process one packet from the host network interface. + //// + + // Check the Ethernet 802.3 header. + const struct ethernet_header_t* ether = (struct ethernet_header_t*)packet; + if (header.len > sizeof(struct ethernet_header_t) && + ntohs(ether->length) <= ETHER_MAX_SIZE && + ntohs(ether->length) > sizeof(struct snap_header_t) && + (memcmp(ðer->source, &HW_LOCAL, sizeof(ether->source)) != 0) && /* Ignore packets sent from our node. */ + (memcmp(ðer->dest, &HW_LOCAL, sizeof(ether->dest)) == 0 || /* Accept packets destined for our node ... */ + memcmp(ðer->dest, &HW_APPLETALK_BROADCAST, sizeof(ether->dest)) == 0 /* ... or for broadcast. */) + ) + { + // Check the 802.2 SNAP header. + const struct snap_header_t* snap = (struct snap_header_t*)(packet + sizeof(struct ethernet_header_t)); + if (snap->dsap == SNAP_DSAP && + snap->ssap == SNAP_SSAP && + snap->control == SNAP_CONTROL) + { + if (memcmp(&snap->discriminator, &SNAP_APPLETALK, sizeof(snap->discriminator)) == 0) + { + // Handle an AppleTalk packet. + const size_t payload_size = ntohs(ether->length) - sizeof(struct snap_header_t); + const u_char* payload = packet + sizeof(struct ethernet_header_t) + sizeof(struct snap_header_t); + + byte* copy = (byte*)malloc(payload_size); + memcpy(copy, payload, payload_size); + + // ELAP does not support short-form DDP, so this must be a long-form DDP packet. + struct at_addr_t source, dest; + if (payload_size >= sizeof(struct DDP_LONG)) + { + // Extract the protocol address from the header. + // + // ELAP really shouldn't be looking at the header for the next level of the protocol stack, + // but this is a convenient place to glean addresses for the AMT, a process that needs both + // hardware and protocol addresses. + struct DDP_LONG* header = (struct DDP_LONG*)copy; + dest.network = (at_network_t)ntohs(header->dest_net); + source.network = (at_network_t)ntohs(header->source_net); + dest.node = header->dest_node; + source.node = header->source_node; + + enqueue(&elap_port.in, dest, source, LAP_DDP_LONG, payload_size, copy); + + aarp_glean(&source, ðer->source); + } + else + atbridge_printf("ATBridge: Dropping invalid short ELAP frame.\n"); + } + else if (memcmp(&snap->discriminator, &SNAP_AARP, sizeof(snap->discriminator)) == 0) + { + // Handle an AARP packet. + struct aarp_header_t* aarp = (struct aarp_header_t*)(packet + sizeof(struct ethernet_header_t) + sizeof(struct snap_header_t)); + aarp->dest_proto_addr.addr.network = ntohs(aarp->dest_proto_addr.addr.network); + aarp->source_proto_addr.addr.network = ntohs(aarp->source_proto_addr.addr.network); + aarp->function = ntohs(aarp->function); + aarp->hardware_type = ntohs(aarp->hardware_type); + aarp->protocol_type = ntohs(aarp->protocol_type); + aarp_handle_packet(aarp); + } + } + } + + return true; + } + else + return false; +} + +static void elap_receive_all() { + while (elap_receive_one()); +} + +void elap_process() { + elap_receive_all(); + elap_send_all_queued(); +} diff --git a/src/atbridge/elap.h b/src/atbridge/elap.h index 1a89474..df8c86c 100644 --- a/src/atbridge/elap.h +++ b/src/atbridge/elap.h @@ -1,36 +1,39 @@ -/* -GSport - an Apple //gs Emulator -Copyright (C) 2013-2014 by Peter Neubauer - -This program is free software; you can redistribute it and/or modify it -under the terms of the GNU General Public License as published by the -Free Software Foundation; either version 2 of the License, or (at your -option) any later version. - -This program is distributed in the hope that it will be useful, but -WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY -or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -for more details. - -You should have received a copy of the GNU General Public License along -with this program; if not, write to the Free Software Foundation, Inc., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ - -/** ELAP port of the AppleTalk Bridge **/ - -bool elap_init(); -void elap_shutdown(); -void elap_process(); - -struct packet_t; - -void elap_enqueue_out(struct packet_t* packet); -struct packet_t* elap_dequeue_in(); - -struct ether_addr_t; -struct snap_discriminator_t; - -void elap_send(const struct ether_addr_t* dest, const struct snap_discriminator_t* discriminator, size_t size, byte data[]); - -const struct ether_addr_t* elap_get_mac(); \ No newline at end of file +/* + GSport - an Apple //gs Emulator + Copyright (C) 2010 - 2019 by GSport contributors + Copyright (C) 2016 - 2018 Dagen Brock + + Based on the KEGS emulator written by and Copyright (C) 2003 Kent Dickey + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 2 of the License, or (at your + option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +/** ELAP port of the AppleTalk Bridge **/ + +bool elap_init(); +void elap_shutdown(); +void elap_process(); + +struct packet_t; + +void elap_enqueue_out(struct packet_t* packet); +struct packet_t* elap_dequeue_in(); + +struct ether_addr_t; +struct snap_discriminator_t; + +void elap_send(const struct ether_addr_t* dest, const struct snap_discriminator_t* discriminator, size_t size, byte data[]); + +const struct ether_addr_t* elap_get_mac(); diff --git a/src/atbridge/elap_defs.h b/src/atbridge/elap_defs.h index 8ce656e..acc67ed 100644 --- a/src/atbridge/elap_defs.h +++ b/src/atbridge/elap_defs.h @@ -1,117 +1,120 @@ -/* -GSport - an Apple //gs Emulator -Copyright (C) 2013-2014 by Peter Neubauer - -This program is free software; you can redistribute it and/or modify it -under the terms of the GNU General Public License as published by the -Free Software Foundation; either version 2 of the License, or (at your -option) any later version. - -This program is distributed in the hope that it will be useful, but -WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY -or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -for more details. - -You should have received a copy of the GNU General Public License along -with this program; if not, write to the Free Software Foundation, Inc., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ - -/* Ethernet addresses are 6 bytes */ -#define ETHER_ADDR_LEN 6 - -static const word16 ETHER_MAX_SIZE = 0x5DC; -static const word16 ETHER_MIN_SIZE = 60; -static const byte SNAP_DSAP = 0xAA; -static const byte SNAP_SSAP = 0xAA; -static const byte SNAP_CONTROL = 0x03; - -#define OUI_APPLETALK_1 0x08 -#define OUI_APPLETALK_2 0x00 -#define OUI_APPLETALK_3 0x07 -#define TYPE_APPLETALK_1 0x80 -#define TYPE_APPLETALK_2 0x9B - -#define OUI_AARP_1 0x00 -#define OUI_AARP_2 0x00 -#define OUI_AARP_3 0x00 -#define TYPE_AARP_1 0x80 -#define TYPE_AARP_2 0xF3 - -static const byte AARP_HARDWARE_ETHER = 0x01; -static const word16 AARP_PROTOCOL_TYPE = 0x809B; -static const byte AARP_HW_ADDR_LEN = 6; -static const byte AARP_PROTOCOL_ADDR_LEN = 4; -enum AARP_FUNCTION -{ - AARP_FUNCTION_REQUEST = 0x01, - AARP_FUNCTION_RESPONSE = 0x02, - AARP_FUNCTION_PROBE = 0x03 -}; - -// reference C-4 -static const long AARP_PROBE_INTERVAL = 200; /* milliseconds */ -static const unsigned int AARP_PROBE_COUNT = 10; - -// reference 2-9 and 3-9, optional and at developer discretion -static const long AARP_REQUEST_INTERVAL = 200; /* milliseconds */ -static const unsigned int AARP_REQUEST_COUNT = 10; - -#pragma pack(push, 1) -struct ether_addr_t -{ - byte mac[ETHER_ADDR_LEN]; -}; - -/* Ethernet 802.2/802.3/SNAP header */ -struct ethernet_header_t -{ - // 802.3 header - struct ether_addr_t dest; - struct ether_addr_t source; - word16 length; -}; - -struct snap_discriminator_t -{ - byte oui[3]; - byte type[2]; -}; - -struct snap_header_t -{ - // 802.2 header - byte dsap; - byte ssap; - byte control; - - // SNAP header - struct snap_discriminator_t discriminator; -}; - -struct protocol_addr_t -{ - byte zero; // Reference C-4 and 3-11: The protocol address is four bytes with the high byte zero. - struct at_addr_t addr; -}; - -struct aarp_header_t -{ - word16 hardware_type; - word16 protocol_type; - byte hw_addr_len; - byte protocol_addr_len; - word16 function; - struct ether_addr_t source_hw_addr; - struct protocol_addr_t source_proto_addr; - struct ether_addr_t dest_hw_addr; - struct protocol_addr_t dest_proto_addr; -}; -#pragma pack(pop) - -static const struct ether_addr_t HW_APPLETALK_BROADCAST = {{ 0x09, 0x00, 0x07, 0xff, 0xff, 0xff }}; -static const struct ether_addr_t HW_LOCAL_DEFAULT = {{0x02 /* unicast, locally administered */, 'A', '2', 'G', 'S', 0x00}}; -//static const struct ether_addr_t HW_LOCAL = {{ 0x02 /* unicast, locally administered */, 0x00, 0x4c, 0x4f, 0x4f, 0x50 }}; -static const struct ether_addr_t HW_ZERO = { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }; -static const struct snap_discriminator_t SNAP_APPLETALK = {{ OUI_APPLETALK_1, OUI_APPLETALK_2, OUI_APPLETALK_3}, {TYPE_APPLETALK_1, TYPE_APPLETALK_2 }}; -static const struct snap_discriminator_t SNAP_AARP = {{ OUI_AARP_1, OUI_AARP_2, OUI_AARP_3}, {TYPE_AARP_1, TYPE_AARP_2 }}; \ No newline at end of file +/* + GSport - an Apple //gs Emulator + Copyright (C) 2010 - 2019 by GSport contributors + Copyright (C) 2016 - 2018 Dagen Brock + + Based on the KEGS emulator written by and Copyright (C) 2003 Kent Dickey + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 2 of the License, or (at your + option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +/* Ethernet addresses are 6 bytes */ +#define ETHER_ADDR_LEN 6 + +static const word16 ETHER_MAX_SIZE = 0x5DC; +static const word16 ETHER_MIN_SIZE = 60; +static const byte SNAP_DSAP = 0xAA; +static const byte SNAP_SSAP = 0xAA; +static const byte SNAP_CONTROL = 0x03; + +#define OUI_APPLETALK_1 0x08 +#define OUI_APPLETALK_2 0x00 +#define OUI_APPLETALK_3 0x07 +#define TYPE_APPLETALK_1 0x80 +#define TYPE_APPLETALK_2 0x9B + +#define OUI_AARP_1 0x00 +#define OUI_AARP_2 0x00 +#define OUI_AARP_3 0x00 +#define TYPE_AARP_1 0x80 +#define TYPE_AARP_2 0xF3 + +static const byte AARP_HARDWARE_ETHER = 0x01; +static const word16 AARP_PROTOCOL_TYPE = 0x809B; +static const byte AARP_HW_ADDR_LEN = 6; +static const byte AARP_PROTOCOL_ADDR_LEN = 4; +enum AARP_FUNCTION +{ + AARP_FUNCTION_REQUEST = 0x01, + AARP_FUNCTION_RESPONSE = 0x02, + AARP_FUNCTION_PROBE = 0x03 +}; + +// reference C-4 +static const long AARP_PROBE_INTERVAL = 200; /* milliseconds */ +static const unsigned int AARP_PROBE_COUNT = 10; + +// reference 2-9 and 3-9, optional and at developer discretion +static const long AARP_REQUEST_INTERVAL = 200; /* milliseconds */ +static const unsigned int AARP_REQUEST_COUNT = 10; + +#pragma pack(push, 1) +struct ether_addr_t +{ + byte mac[ETHER_ADDR_LEN]; +}; + +/* Ethernet 802.2/802.3/SNAP header */ +struct ethernet_header_t +{ + // 802.3 header + struct ether_addr_t dest; + struct ether_addr_t source; + word16 length; +}; + +struct snap_discriminator_t +{ + byte oui[3]; + byte type[2]; +}; + +struct snap_header_t +{ + // 802.2 header + byte dsap; + byte ssap; + byte control; + + // SNAP header + struct snap_discriminator_t discriminator; +}; + +struct protocol_addr_t +{ + byte zero; // Reference C-4 and 3-11: The protocol address is four bytes with the high byte zero. + struct at_addr_t addr; +}; + +struct aarp_header_t +{ + word16 hardware_type; + word16 protocol_type; + byte hw_addr_len; + byte protocol_addr_len; + word16 function; + struct ether_addr_t source_hw_addr; + struct protocol_addr_t source_proto_addr; + struct ether_addr_t dest_hw_addr; + struct protocol_addr_t dest_proto_addr; +}; +#pragma pack(pop) + +static const struct ether_addr_t HW_APPLETALK_BROADCAST = {{ 0x09, 0x00, 0x07, 0xff, 0xff, 0xff }}; +static const struct ether_addr_t HW_LOCAL_DEFAULT = {{0x02 /* unicast, locally administered */, 'A', '2', 'G', 'S', 0x00}}; +//static const struct ether_addr_t HW_LOCAL = {{ 0x02 /* unicast, locally administered */, 0x00, 0x4c, 0x4f, 0x4f, 0x50 }}; +static const struct ether_addr_t HW_ZERO = { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }; +static const struct snap_discriminator_t SNAP_APPLETALK = {{ OUI_APPLETALK_1, OUI_APPLETALK_2, OUI_APPLETALK_3}, {TYPE_APPLETALK_1, TYPE_APPLETALK_2 }}; +static const struct snap_discriminator_t SNAP_AARP = {{ OUI_AARP_1, OUI_AARP_2, OUI_AARP_3}, {TYPE_AARP_1, TYPE_AARP_2 }}; diff --git a/src/atbridge/llap.c b/src/atbridge/llap.c index d11233d..4221b51 100644 --- a/src/atbridge/llap.c +++ b/src/atbridge/llap.c @@ -1,332 +1,324 @@ -/* -GSport - an Apple //gs Emulator -Copyright (C) 2013-2014 by Peter Neubauer - -This program is free software; you can redistribute it and/or modify it -under the terms of the GNU General Public License as published by the -Free Software Foundation; either version 2 of the License, or (at your -option) any later version. - -This program is distributed in the hope that it will be useful, but -WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY -or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -for more details. - -You should have received a copy of the GNU General Public License along -with this program; if not, write to the Free Software Foundation, Inc., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ - -/** This module implements the LLAP port of the bridge. **/ - -#include -#include "../defc.h" -#include "atbridge.h" -#include "port.h" -#include "llap.h" - -typedef enum { - LLAP_DDP_SHORT = 0x01, - LLAP_DDP_LONG = 0x02, - LLAP_ENQ = 0x81, - LLAP_ACK = 0x82, - LLAP_RTS = 0x84, - LLAP_CTS = 0x85 -} LLAP_TYPES; - -const unsigned int LLAP_PACKET_MAX = 603 /* bytes */; -const unsigned int LLAP_PACKET_MIN = 3 /* bytes */; -const double LLAP_IDG = 400 /* microseconds */; -const double LLAP_IFG = 200 /* microseconds */; -const double GAP_TOLERANCE = 4.0; - -static struct packet_port_t llap_port; - -typedef enum { - DIALOG_READY, - DIALOG_GOT_CTS, - DIALOG_WAIT_IDG -} DIALOG_STATE; -static DIALOG_STATE dialog_state; -static double dialog_end_dcycs; -static double last_frame_dcycs; - -void llap_init() -{ - dialog_state = DIALOG_READY; - last_frame_dcycs = 0; - port_init(&llap_port); -} - -void llap_shutdown() -{ - port_shutdown(&llap_port); -} - - -/** Queue one data packet out from the bridge's LLAP port and into the guest. **/ -void llap_enqueue_out(struct packet_t* packet) -{ - // Generate the RTS. - struct packet_t* rts = (struct packet_t*)malloc(sizeof(struct packet_t)); - rts->source.network = packet->source.network; - rts->source.node = packet->source.node; - rts->dest.network = packet->dest.network; - rts->dest.node = packet->dest.node; - rts->size = 0; - rts->data = 0; - rts->type = LLAP_RTS; - enqueue_packet(&llap_port.out, rts); - - // Enqueue the data. - enqueue_packet(&llap_port.out, packet); -} - -struct packet_t* llap_dequeue_in() -{ - return dequeue(&llap_port.in); -} - -static void llap_dump_packet(size_t size, byte data[]) -{ - if (size < LLAP_PACKET_MIN) - atbridge_printf("LLAP short packet.\n"); - else if (size > LLAP_PACKET_MAX) - atbridge_printf("LLAP long packet.\n"); - else - { - at_node_t dest = data[0]; - at_node_t source = data[1]; - LLAP_TYPES type = (LLAP_TYPES)(data[2]); - - const char* typeName = 0; - switch (type) - { - case LLAP_DDP_SHORT: - typeName = "DDP (short)"; - break; - case LLAP_DDP_LONG: - typeName = "DDP (long)"; - break; - case LLAP_ENQ: - typeName = "lapENQ"; - break; - case LLAP_ACK: - typeName = "lapACK"; - break; - case LLAP_RTS: - typeName = "lapRTS"; - break; - case LLAP_CTS: - typeName = "lapCTS"; - break; - } - - if (typeName) - atbridge_printf("LLAP[%d->%d] %s: %d bytes.\n", source, dest, typeName, size); - else - atbridge_printf("LLAP[%d->%d] %x: %d bytes.\n", source, dest, type, size); - - /*for (size_t i = 0; i < size; i++) - atbridge_printf("%02x ", data[i]); - atbridge_printf("\n");*/ - } -} - -/** Reply to a control packet from the GS **/ -static void llap_reply_control(at_node_t dest, at_node_t source, LLAP_TYPES type) -{ - struct at_addr_t dest_addr = { 0, dest }; - struct at_addr_t source_addr = { 0, source }; - - // Insert control packets at the head of the queue contrary to normal FIFO queue operation - // to ensure that control frames arrive in the intended order. - insert(&llap_port.out, dest_addr, source_addr, type, 0, 0); -} - -/** Accept a data packet from the GS. **/ -static void llap_handle_data(size_t size, byte data[]) -{ - at_node_t dest = data[0]; - at_node_t source = data[1]; - LLAP_TYPES type = (LLAP_TYPES)(data[2]); - - const size_t data_size = size - 3; - byte* data_copy = (byte*)malloc(data_size); - memcpy(data_copy, data + 3, data_size); - - struct at_addr_t dest_addr = { 0, dest }; - struct at_addr_t source_addr = { 0, source }; - enqueue(&llap_port.in, dest_addr, source_addr, type, data_size, data_copy); -} - -/** Accept a control packet from the GS. **/ -static void llap_handle_control(size_t size, byte data[]) -{ - at_node_t dest = data[0]; - at_node_t source = data[1]; - LLAP_TYPES type = (LLAP_TYPES)(data[2]); - - struct at_addr_t addr = { atbridge_get_net(), dest }; - - switch (type) - { - case LLAP_ENQ: - // Require the GS to take a valid "client" address not known to be in use. - if (dest > 127 || dest == 0 || atbridge_address_used(&addr)) - llap_reply_control(source, dest, LLAP_ACK); - break; - case LLAP_ACK: - break; - case LLAP_RTS: - if (dest != at_broadcast_node) - // The GS is trying to make a directed transmission. Provide the required RTS/CTS handshake. - // Note that broadcast packets do not require a CTS. - llap_reply_control(source, dest, LLAP_CTS); - break; - case LLAP_CTS: - // The GS sent a CTS. If the bridge has pending data, prepare to deliver the packet. - dialog_state = DIALOG_GOT_CTS; - break; - default: - break; - } -} - -/** Occassionally, we receive an invalid packet from the GS. I'm unsure if this is due to a bug in GS/OS - or, more likely, a bug in the SCC emulation. Regardless, when such a thing does occur, discard the - current, corrupted dialog. Link errors are routine in real LocalTalk networks, and LocalTalk will recover. - **/ -static void llap_reset_dialog() -{ - dialog_state = DIALOG_READY; - last_frame_dcycs = 0; - - // Discard packets until the queue is either empty or the next dialog starts (and dialogs begin with an RTS). - while (true) - { - struct packet_t* packet = queue_peek(&llap_port.out); - - if (packet && (packet->type != LLAP_RTS)) - { - packet = dequeue(&llap_port.out); - if (packet->data) - free(packet->data); - free(packet); - } - else - break; - } -} - -/** Transfer (send) one LLAP packet from the GS. **/ -void llap_enqueue_in(double dcycs, size_t size, byte data[]) -{ - atbridge_printf("<%0.0f> TX: ", dcycs); - llap_dump_packet(size, data); - - if (size < LLAP_PACKET_MIN) - atbridge_printf("ATBridge: Dropping LLAP short packet.\n"); - else if (size > LLAP_PACKET_MAX) - atbridge_printf("ATBridge: Dropping LLAP long packet.\n"); - else - { - last_frame_dcycs = dcycs; - LLAP_TYPES type = (LLAP_TYPES)(data[2]); - - switch (type) - { - case LLAP_DDP_SHORT: - case LLAP_DDP_LONG: - llap_handle_data(size, data); - break; - case LLAP_ENQ: - case LLAP_ACK: - case LLAP_RTS: - case LLAP_CTS: - llap_handle_control(size, data); - break; - default: - // Intentionally check for valid types and ingore packets with invalid types. - // Sometimes, the bridge gets invalid packets from the GS, which tends to break the bridge. - atbridge_printf("ATBridge: Dropping LLAP packet with invalid type.\n"); - llap_reset_dialog(); - } - } -} - -/** Transfer (receive) one LLAP packet to the GS. **/ -void llap_dequeue_out(double dcycs, size_t* size, byte* data[]) -{ - *size = 0; - - // The LocalTalk protocol requires a minimum 400us gap between dialogs (called the IDG). - // If necessary, wait for the IDG. - if (dialog_state == DIALOG_WAIT_IDG) - { - if ((dcycs - dialog_end_dcycs) >= LLAP_IDG) - // The IDG is done. - dialog_state = DIALOG_READY; - else - // Continue waiting for the IDG. - return; - } - // The LocalTalk protocols requires a maximum 200us gap between frames within a dialog (called the IFG). - // If we exceed the IFG, the bridge must be stuck in an incomplete or corrupt dialog. In this case, - // discard the current dialog and try again. - if ((dialog_state != DIALOG_READY) && (last_frame_dcycs != 0) && ((dcycs - last_frame_dcycs) >= (GAP_TOLERANCE*LLAP_IFG))) - { - llap_reset_dialog(); - atbridge_printf("ATBridge: Dialog reset due to IFG violation.\n"); - } - - struct packet_t* packet = queue_peek(&llap_port.out); - - if ((dialog_state == DIALOG_READY) && (packet) && !(packet->type & 0x80) && (last_frame_dcycs != 0) && ((dcycs - last_frame_dcycs) >= (GAP_TOLERANCE*LLAP_IDG))) - { - llap_reset_dialog(); - packet = queue_peek(&llap_port.out); - atbridge_printf("ATBridge: Dialog reset due to IDG violation.\n"); - } - - if (packet && - ((packet->type & 0x80) || /* Pass along control frames without waiting for a CTS. */ - (!(packet->type & 0x80) && (packet->dest.node == at_broadcast_node) && (dialog_state == DIALOG_READY)) || /* Pass along broadcast frames, which don't wait for CTS frames. */ - (!(packet->type & 0x80) && (packet->dest.node != at_broadcast_node) && (dialog_state == DIALOG_GOT_CTS)))) /* Pass along directed frames only after receiving a CTS handshake. */ - { - dequeue(&llap_port.out); - - // Prepend the LLAP header. - *size = packet->size + 3 + 2; - *data = (byte*)malloc(*size); - (*data)[0] = packet->dest.node; - (*data)[1] = packet->source.node; - (*data)[2] = packet->type; - - // Insert the data into the new LLAP packet. - if (*size) - memcpy((*data) + 3, packet->data, packet->size); - - // Fake a frame check sequence (FCS). Since our SCC emulation doesn't actually - // check the FCS, the value of the FCS doesn't matter. - (*data)[packet->size + 3 + 0] = 0xff; - (*data)[packet->size + 3 + 1] = 0xff; - - atbridge_printf("<%0.0f> RX: ", dcycs); - llap_dump_packet(*size, *data); - - if (packet->type & 0x80) - dialog_state = DIALOG_READY; - else - { - // This was the last packet in the dialog. - dialog_state = DIALOG_WAIT_IDG; - dialog_end_dcycs = dcycs; - } - - last_frame_dcycs = dcycs; - - free(packet->data); - free(packet); - } -} +/* + GSport - an Apple //gs Emulator + Copyright (C) 2010 - 2019 by GSport contributors + Copyright (C) 2016 - 2018 Dagen Brock + + Based on the KEGS emulator written by and Copyright (C) 2003 Kent Dickey + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 2 of the License, or (at your + option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +/** This module implements the LLAP port of the bridge. **/ + +#include +#include "../defc.h" +#include "atbridge.h" +#include "port.h" +#include "llap.h" + +typedef enum { + LLAP_DDP_SHORT = 0x01, + LLAP_DDP_LONG = 0x02, + LLAP_ENQ = 0x81, + LLAP_ACK = 0x82, + LLAP_RTS = 0x84, + LLAP_CTS = 0x85 +} LLAP_TYPES; + +const unsigned int LLAP_PACKET_MAX = 603 /* bytes */; +const unsigned int LLAP_PACKET_MIN = 3 /* bytes */; +const double LLAP_IDG = 400 /* microseconds */; +const double LLAP_IFG = 200 /* microseconds */; +const double GAP_TOLERANCE = 4.0; + +static struct packet_port_t llap_port; + +typedef enum { + DIALOG_READY, + DIALOG_GOT_CTS, + DIALOG_WAIT_IDG +} DIALOG_STATE; +static DIALOG_STATE dialog_state; +static double dialog_end_dcycs; +static double last_frame_dcycs; + +void llap_init() { + dialog_state = DIALOG_READY; + last_frame_dcycs = 0; + port_init(&llap_port); +} + +void llap_shutdown() { + port_shutdown(&llap_port); +} + + +/** Queue one data packet out from the bridge's LLAP port and into the guest. **/ +void llap_enqueue_out(struct packet_t* packet) { + // Generate the RTS. + struct packet_t* rts = (struct packet_t*)malloc(sizeof(struct packet_t)); + rts->source.network = packet->source.network; + rts->source.node = packet->source.node; + rts->dest.network = packet->dest.network; + rts->dest.node = packet->dest.node; + rts->size = 0; + rts->data = 0; + rts->type = LLAP_RTS; + enqueue_packet(&llap_port.out, rts); + + // Enqueue the data. + enqueue_packet(&llap_port.out, packet); +} + +struct packet_t* llap_dequeue_in() { + return dequeue(&llap_port.in); +} + +static void llap_dump_packet(size_t size, byte data[]) { + if (size < LLAP_PACKET_MIN) + atbridge_printf("LLAP short packet.\n"); + else if (size > LLAP_PACKET_MAX) + atbridge_printf("LLAP long packet.\n"); + else + { + at_node_t dest = data[0]; + at_node_t source = data[1]; + LLAP_TYPES type = (LLAP_TYPES)(data[2]); + + const char* typeName = 0; + switch (type) + { + case LLAP_DDP_SHORT: + typeName = "DDP (short)"; + break; + case LLAP_DDP_LONG: + typeName = "DDP (long)"; + break; + case LLAP_ENQ: + typeName = "lapENQ"; + break; + case LLAP_ACK: + typeName = "lapACK"; + break; + case LLAP_RTS: + typeName = "lapRTS"; + break; + case LLAP_CTS: + typeName = "lapCTS"; + break; + } + + if (typeName) + atbridge_printf("LLAP[%d->%d] %s: %d bytes.\n", source, dest, typeName, size); + else + atbridge_printf("LLAP[%d->%d] %x: %d bytes.\n", source, dest, type, size); + + /*for (size_t i = 0; i < size; i++) + atbridge_printf("%02x ", data[i]); + atbridge_printf("\n");*/ + } +} + +/** Reply to a control packet from the GS **/ +static void llap_reply_control(at_node_t dest, at_node_t source, LLAP_TYPES type) { + struct at_addr_t dest_addr = { 0, dest }; + struct at_addr_t source_addr = { 0, source }; + + // Insert control packets at the head of the queue contrary to normal FIFO queue operation + // to ensure that control frames arrive in the intended order. + insert(&llap_port.out, dest_addr, source_addr, type, 0, 0); +} + +/** Accept a data packet from the GS. **/ +static void llap_handle_data(size_t size, byte data[]) { + at_node_t dest = data[0]; + at_node_t source = data[1]; + LLAP_TYPES type = (LLAP_TYPES)(data[2]); + + const size_t data_size = size - 3; + byte* data_copy = (byte*)malloc(data_size); + memcpy(data_copy, data + 3, data_size); + + struct at_addr_t dest_addr = { 0, dest }; + struct at_addr_t source_addr = { 0, source }; + enqueue(&llap_port.in, dest_addr, source_addr, type, data_size, data_copy); +} + +/** Accept a control packet from the GS. **/ +static void llap_handle_control(size_t size, byte data[]) { + at_node_t dest = data[0]; + at_node_t source = data[1]; + LLAP_TYPES type = (LLAP_TYPES)(data[2]); + + struct at_addr_t addr = { atbridge_get_net(), dest }; + + switch (type) + { + case LLAP_ENQ: + // Require the GS to take a valid "client" address not known to be in use. + if (dest > 127 || dest == 0 || atbridge_address_used(&addr)) + llap_reply_control(source, dest, LLAP_ACK); + break; + case LLAP_ACK: + break; + case LLAP_RTS: + if (dest != at_broadcast_node) + // The GS is trying to make a directed transmission. Provide the required RTS/CTS handshake. + // Note that broadcast packets do not require a CTS. + llap_reply_control(source, dest, LLAP_CTS); + break; + case LLAP_CTS: + // The GS sent a CTS. If the bridge has pending data, prepare to deliver the packet. + dialog_state = DIALOG_GOT_CTS; + break; + default: + break; + } +} + +/** Occassionally, we receive an invalid packet from the GS. I'm unsure if this is due to a bug in GS/OS + or, more likely, a bug in the SCC emulation. Regardless, when such a thing does occur, discard the + current, corrupted dialog. Link errors are routine in real LocalTalk networks, and LocalTalk will recover. + **/ +static void llap_reset_dialog() { + dialog_state = DIALOG_READY; + last_frame_dcycs = 0; + + // Discard packets until the queue is either empty or the next dialog starts (and dialogs begin with an RTS). + while (true) + { + struct packet_t* packet = queue_peek(&llap_port.out); + + if (packet && (packet->type != LLAP_RTS)) + { + packet = dequeue(&llap_port.out); + if (packet->data) + free(packet->data); + free(packet); + } + else + break; + } +} + +/** Transfer (send) one LLAP packet from the GS. **/ +void llap_enqueue_in(double dcycs, size_t size, byte data[]) { + atbridge_printf("<%0.0f> TX: ", dcycs); + llap_dump_packet(size, data); + + if (size < LLAP_PACKET_MIN) + atbridge_printf("ATBridge: Dropping LLAP short packet.\n"); + else if (size > LLAP_PACKET_MAX) + atbridge_printf("ATBridge: Dropping LLAP long packet.\n"); + else + { + last_frame_dcycs = dcycs; + LLAP_TYPES type = (LLAP_TYPES)(data[2]); + + switch (type) + { + case LLAP_DDP_SHORT: + case LLAP_DDP_LONG: + llap_handle_data(size, data); + break; + case LLAP_ENQ: + case LLAP_ACK: + case LLAP_RTS: + case LLAP_CTS: + llap_handle_control(size, data); + break; + default: + // Intentionally check for valid types and ingore packets with invalid types. + // Sometimes, the bridge gets invalid packets from the GS, which tends to break the bridge. + atbridge_printf("ATBridge: Dropping LLAP packet with invalid type.\n"); + llap_reset_dialog(); + } + } +} + +/** Transfer (receive) one LLAP packet to the GS. **/ +void llap_dequeue_out(double dcycs, size_t* size, byte* data[]) { + *size = 0; + + // The LocalTalk protocol requires a minimum 400us gap between dialogs (called the IDG). + // If necessary, wait for the IDG. + if (dialog_state == DIALOG_WAIT_IDG) + { + if ((dcycs - dialog_end_dcycs) >= LLAP_IDG) + // The IDG is done. + dialog_state = DIALOG_READY; + else + // Continue waiting for the IDG. + return; + } + // The LocalTalk protocols requires a maximum 200us gap between frames within a dialog (called the IFG). + // If we exceed the IFG, the bridge must be stuck in an incomplete or corrupt dialog. In this case, + // discard the current dialog and try again. + if ((dialog_state != DIALOG_READY) && (last_frame_dcycs != 0) && ((dcycs - last_frame_dcycs) >= (GAP_TOLERANCE*LLAP_IFG))) + { + llap_reset_dialog(); + atbridge_printf("ATBridge: Dialog reset due to IFG violation.\n"); + } + + struct packet_t* packet = queue_peek(&llap_port.out); + + if ((dialog_state == DIALOG_READY) && (packet) && !(packet->type & 0x80) && (last_frame_dcycs != 0) && ((dcycs - last_frame_dcycs) >= (GAP_TOLERANCE*LLAP_IDG))) + { + llap_reset_dialog(); + packet = queue_peek(&llap_port.out); + atbridge_printf("ATBridge: Dialog reset due to IDG violation.\n"); + } + + if (packet && + ((packet->type & 0x80) || /* Pass along control frames without waiting for a CTS. */ + (!(packet->type & 0x80) && (packet->dest.node == at_broadcast_node) && (dialog_state == DIALOG_READY)) || /* Pass along broadcast frames, which don't wait for CTS frames. */ + (!(packet->type & 0x80) && (packet->dest.node != at_broadcast_node) && (dialog_state == DIALOG_GOT_CTS)))) /* Pass along directed frames only after receiving a CTS handshake. */ + { + dequeue(&llap_port.out); + + // Prepend the LLAP header. + *size = packet->size + 3 + 2; + *data = (byte*)malloc(*size); + (*data)[0] = packet->dest.node; + (*data)[1] = packet->source.node; + (*data)[2] = packet->type; + + // Insert the data into the new LLAP packet. + if (*size) + memcpy((*data) + 3, packet->data, packet->size); + + // Fake a frame check sequence (FCS). Since our SCC emulation doesn't actually + // check the FCS, the value of the FCS doesn't matter. + (*data)[packet->size + 3 + 0] = 0xff; + (*data)[packet->size + 3 + 1] = 0xff; + + atbridge_printf("<%0.0f> RX: ", dcycs); + llap_dump_packet(*size, *data); + + if (packet->type & 0x80) + dialog_state = DIALOG_READY; + else + { + // This was the last packet in the dialog. + dialog_state = DIALOG_WAIT_IDG; + dialog_end_dcycs = dcycs; + } + + last_frame_dcycs = dcycs; + + free(packet->data); + free(packet); + } +} diff --git a/src/atbridge/llap.h b/src/atbridge/llap.h index 341f457..b0cd879 100644 --- a/src/atbridge/llap.h +++ b/src/atbridge/llap.h @@ -1,37 +1,40 @@ -/* -GSport - an Apple //gs Emulator -Copyright (C) 2013-2014 by Peter Neubauer - -This program is free software; you can redistribute it and/or modify it -under the terms of the GNU General Public License as published by the -Free Software Foundation; either version 2 of the License, or (at your -option) any later version. - -This program is distributed in the hope that it will be useful, but -WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY -or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -for more details. - -You should have received a copy of the GNU General Public License along -with this program; if not, write to the Free Software Foundation, Inc., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ - -struct packet_t; - -/** LLAP port of the AppleTalk Bridge **/ - -void llap_init(); -void llap_shutdown(); - -/** Send one LLAP packet from the GS - */ -void llap_enqueue_in(double dcycs, size_t size, byte data[]); - -/** Receive one LLAP packet from the world to the GS and return the size - */ -void llap_dequeue_out(double dcycs, size_t* size, byte* data[]); - - -void llap_enqueue_out(struct packet_t* packet); -struct packet_t* llap_dequeue_in(); +/* + GSport - an Apple //gs Emulator + Copyright (C) 2010 - 2019 by GSport contributors + Copyright (C) 2016 - 2018 Dagen Brock + + Based on the KEGS emulator written by and Copyright (C) 2003 Kent Dickey + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 2 of the License, or (at your + option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +struct packet_t; + +/** LLAP port of the AppleTalk Bridge **/ + +void llap_init(); +void llap_shutdown(); + +/** Send one LLAP packet from the GS + */ +void llap_enqueue_in(double dcycs, size_t size, byte data[]); + +/** Receive one LLAP packet from the world to the GS and return the size + */ +void llap_dequeue_out(double dcycs, size_t* size, byte* data[]); + + +void llap_enqueue_out(struct packet_t* packet); +struct packet_t* llap_dequeue_in(); diff --git a/src/atbridge/pcap_delay.c b/src/atbridge/pcap_delay.c index fff92d8..7ca89b6 100644 --- a/src/atbridge/pcap_delay.c +++ b/src/atbridge/pcap_delay.c @@ -1,170 +1,161 @@ -/* -GSport - an Apple //gs Emulator -Copyright (C) 2014 by Peter Neubauer - -This program is free software; you can redistribute it and/or modify it -under the terms of the GNU General Public License as published by the -Free Software Foundation; either version 2 of the License, or (at your -option) any later version. - -This program is distributed in the hope that it will be useful, but -WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY -or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -for more details. - -You should have received a copy of the GNU General Public License along -with this program; if not, write to the Free Software Foundation, Inc., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ - -#include -#include "pcap_delay.h" - -#ifdef WIN32 -#include -static HMODULE module = NULL; -#elif __linux__ -#include -static void* module = 0; -#endif - - -bool pcapdelay_load() -{ - if (!pcapdelay_is_loaded()) - { -#ifdef WIN32 - module = LoadLibrary("wpcap.dll"); -#elif __linux__ - module = dlopen("libpcap.so", RTLD_LAZY); -#endif - } - return pcapdelay_is_loaded(); -} - -bool pcapdelay_is_loaded() -{ -#ifdef WIN32 - return module != NULL; -#elif __linux__ - return module != 0; -#endif -} - -void pcapdelay_unload() -{ - if (pcapdelay_is_loaded()) - { -#ifdef WIN32 - FreeLibrary(module); - module = NULL; -#elif __linux__ - dlclose(module); - module = 0; -#endif - } -} - -typedef void (*PFNVOID)(); - -static PFNVOID delay_load(const char* proc, PFNVOID* ppfn) -{ - if (pcapdelay_load() && proc && ppfn && !*ppfn) - { -#ifdef WIN32 - *ppfn = (PFNVOID)GetProcAddress(module, proc); -#elif __linux__ - *ppfn = (PFNVOID)dlsym(module, proc); -#endif - } - if (ppfn) - return *ppfn; - else - return 0; -} - -void pcapdelay_freealldevs(pcap_if_t* a0) -{ - typedef void (*PFN)(pcap_if_t*); - static PFN pfn = 0; - if ((pfn = (PFN)delay_load("pcap_freealldevs", (PFNVOID*)&pfn))) - (*pfn)(a0); -} - -pcap_t* pcapdelay_open_live(const char* a0, int a1, int a2, int a3, char* a4) -{ - typedef pcap_t* (*PFN)(const char*, int, int, int, char*); - static PFN pfn = 0; - if ((pfn = (PFN)delay_load("pcap_open_live", (PFNVOID*)&pfn))) - return (*pfn)(a0, a1, a2, a3, a4); - else - return 0; -} - -void pcapdelay_close(pcap_t* a0) -{ - typedef void (*PFN)(pcap_t*); - static PFN pfn = 0; - if ((pfn = (PFN)delay_load("pcap_close", (PFNVOID*)&pfn))) - (*pfn)(a0); -} - -int pcapdelay_findalldevs(pcap_if_t** a0, char* a1) -{ - typedef int (*PFN)(pcap_if_t**, char*); - static PFN pfn = 0; - if ((pfn = (PFN)delay_load("pcap_findalldevs", (PFNVOID*)&pfn))) - return (*pfn)(a0, a1); - else - return 0; -} - -int pcapdelay_datalink(pcap_t* a0) -{ - typedef int(*PFN)(pcap_t*); - static PFN pfn = 0; - if ((pfn = (PFN)delay_load("pcap_datalink", (PFNVOID*)&pfn))) - return (*pfn)(a0); - else - return 0; -} - -int pcapdelay_setnonblock(pcap_t* a0, int a1, char* a2) -{ - typedef int(*PFN)(pcap_t*, int, char*); - static PFN pfn = 0; - if ((pfn = (PFN)delay_load("pcap_setnonblock", (PFNVOID*)&pfn))) - return (*pfn)(a0, a1, a2); - else - return 0; -} - -int pcapdelay_sendpacket(pcap_t* a0, u_char* a1, int a2) -{ - typedef int(*PFN)(pcap_t*, u_char*, int); - static PFN pfn = 0; - if ((pfn = (PFN)delay_load("pcap_sendpacket", (PFNVOID*)&pfn))) - return (*pfn)(a0, a1, a2); - else - return 0; -} - -const u_char* pcapdelay_next(pcap_t* a0, struct pcap_pkthdr* a1) -{ - typedef const u_char*(*PFN)(pcap_t*, struct pcap_pkthdr*); - static PFN pfn = 0; - if ((pfn = (PFN)delay_load("pcap_next", (PFNVOID*)&pfn))) - return (*pfn)(a0, a1); - else - return 0; -} - -int pcapdelay_dispatch(pcap_t* a0, int a1, pcap_handler a2, u_char* a3) -{ - typedef const int(*PFN)(pcap_t *, int, pcap_handler, u_char *); - static PFN pfn = 0; - if ((pfn = (PFN)delay_load("pcap_dispatch", (PFNVOID*)&pfn))) - return (*pfn)(a0, a1, a2, a3); - else - return 0; -} \ No newline at end of file +/* + GSport - an Apple //gs Emulator + Copyright (C) 2010 - 2019 by GSport contributors + Copyright (C) 2016 - 2018 Dagen Brock + + Based on the KEGS emulator written by and Copyright (C) 2003 Kent Dickey + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 2 of the License, or (at your + option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include +#include "pcap_delay.h" + +#ifdef WIN32 +#include +static HMODULE module = NULL; +#elif __linux__ +#include +static void* module = 0; +#endif + + +bool pcapdelay_load() { + if (!pcapdelay_is_loaded()) + { +#ifdef WIN32 + module = LoadLibrary("wpcap.dll"); +#elif __linux__ + module = dlopen("libpcap.so", RTLD_LAZY); +#endif + } + return pcapdelay_is_loaded(); +} + +bool pcapdelay_is_loaded() { +#ifdef WIN32 + return module != NULL; +#elif __linux__ + return module != 0; +#endif + return 0; +} + +void pcapdelay_unload() { + if (pcapdelay_is_loaded()) + { +#ifdef WIN32 + FreeLibrary(module); + module = NULL; +#elif __linux__ + dlclose(module); + module = 0; +#endif + } +} + +typedef void (*PFNVOID)(); + +static PFNVOID delay_load(const char* proc, PFNVOID* ppfn) { + if (pcapdelay_load() && proc && ppfn && !*ppfn) + { +#ifdef WIN32 + *ppfn = (PFNVOID)GetProcAddress(module, proc); +#elif __linux__ + *ppfn = (PFNVOID)dlsym(module, proc); +#endif + } + if (ppfn) + return *ppfn; + else + return 0; +} + +void pcapdelay_freealldevs(pcap_if_t* a0) { + typedef void (*PFN)(pcap_if_t*); + static PFN pfn = 0; + if ((pfn = (PFN)delay_load("pcap_freealldevs", (PFNVOID*)&pfn))) + (*pfn)(a0); +} + +pcap_t* pcapdelay_open_live(const char* a0, int a1, int a2, int a3, char* a4) { + typedef pcap_t* (*PFN)(const char*, int, int, int, char*); + static PFN pfn = 0; + if ((pfn = (PFN)delay_load("pcap_open_live", (PFNVOID*)&pfn))) + return (*pfn)(a0, a1, a2, a3, a4); + else + return 0; +} + +void pcapdelay_close(pcap_t* a0) { + typedef void (*PFN)(pcap_t*); + static PFN pfn = 0; + if ((pfn = (PFN)delay_load("pcap_close", (PFNVOID*)&pfn))) + (*pfn)(a0); +} + +int pcapdelay_findalldevs(pcap_if_t** a0, char* a1) { + typedef int (*PFN)(pcap_if_t**, char*); + static PFN pfn = 0; + if ((pfn = (PFN)delay_load("pcap_findalldevs", (PFNVOID*)&pfn))) + return (*pfn)(a0, a1); + else + return 0; +} + +int pcapdelay_datalink(pcap_t* a0) { + typedef int (*PFN)(pcap_t*); + static PFN pfn = 0; + if ((pfn = (PFN)delay_load("pcap_datalink", (PFNVOID*)&pfn))) + return (*pfn)(a0); + else + return 0; +} + +int pcapdelay_setnonblock(pcap_t* a0, int a1, char* a2) { + typedef int (*PFN)(pcap_t*, int, char*); + static PFN pfn = 0; + if ((pfn = (PFN)delay_load("pcap_setnonblock", (PFNVOID*)&pfn))) + return (*pfn)(a0, a1, a2); + else + return 0; +} + +int pcapdelay_sendpacket(pcap_t* a0, u_char* a1, int a2) { + typedef int (*PFN)(pcap_t*, u_char*, int); + static PFN pfn = 0; + if ((pfn = (PFN)delay_load("pcap_sendpacket", (PFNVOID*)&pfn))) + return (*pfn)(a0, a1, a2); + else + return 0; +} + +const u_char* pcapdelay_next(pcap_t* a0, struct pcap_pkthdr* a1) { + typedef const u_char*(*PFN)(pcap_t*, struct pcap_pkthdr*); + static PFN pfn = 0; + if ((pfn = (PFN)delay_load("pcap_next", (PFNVOID*)&pfn))) + return (*pfn)(a0, a1); + else + return 0; +} + +int pcapdelay_dispatch(pcap_t* a0, int a1, pcap_handler a2, u_char* a3) { + typedef const int (*PFN)(pcap_t *, int, pcap_handler, u_char *); + static PFN pfn = 0; + if ((pfn = (PFN)delay_load("pcap_dispatch", (PFNVOID*)&pfn))) + return (*pfn)(a0, a1, a2, a3); + else + return 0; +} diff --git a/src/atbridge/pcap_delay.h b/src/atbridge/pcap_delay.h index 139f4aa..7a79b64 100644 --- a/src/atbridge/pcap_delay.h +++ b/src/atbridge/pcap_delay.h @@ -1,46 +1,52 @@ -/* -GSport - an Apple //gs Emulator -Copyright (C) 2014 by Peter Neubauer - -This program is free software; you can redistribute it and/or modify it -under the terms of the GNU General Public License as published by the -Free Software Foundation; either version 2 of the License, or (at your -option) any later version. - -This program is distributed in the hope that it will be useful, but -WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY -or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -for more details. - -You should have received a copy of the GNU General Public License along -with this program; if not, write to the Free Software Foundation, Inc., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ -/* -This interface provides a thin, delay-loaded wrapper around the PCAP library so that -you may start GSport without intalling PCAP. Of course, some features that require -PCAP won't be available. - -This wrapper provides a subset of the available PCAP APIs necessary for ATBridge. -Feel free to extend the wrapper. -*/ - -#ifdef WIN32 -#include "../arch/win32/pcap.h" -#elif __linux__ -#include -#endif - -bool pcapdelay_load(); -bool pcapdelay_is_loaded(); -void pcapdelay_unload(); - -void pcapdelay_freealldevs(pcap_if_t *); -pcap_t* pcapdelay_open_live(const char *, int, int, int, char *); -void pcapdelay_close(pcap_t *); -int pcapdelay_findalldevs(pcap_if_t **, char *); -int pcapdelay_datalink(pcap_t *); -int pcapdelay_setnonblock(pcap_t *, int, char *); -int pcapdelay_sendpacket(pcap_t *p, u_char *buf, int size); -const u_char* pcapdelay_next(pcap_t *, struct pcap_pkthdr *); -int pcapdelay_dispatch(pcap_t *, int, pcap_handler, u_char *); \ No newline at end of file +/* + GSport - an Apple //gs Emulator + Copyright (C) 2010 - 2019 by GSport contributors + Copyright (C) 2016 - 2018 Dagen Brock + + Based on the KEGS emulator written by and Copyright (C) 2003 Kent Dickey + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 2 of the License, or (at your + option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +/* +This interface provides a thin, delay-loaded wrapper around the PCAP library so that +you may start GSport without intalling PCAP. Of course, some features that require +PCAP won't be available. + +This wrapper provides a subset of the available PCAP APIs necessary for ATBridge. +Feel free to extend the wrapper. +*/ + +#ifdef WIN32 +#include "../arch/win32/pcap.h" +#elif __linux__ +#include +#elif __APPLE__ +#include +#endif + +bool pcapdelay_load(); +bool pcapdelay_is_loaded(); +void pcapdelay_unload(); + +void pcapdelay_freealldevs(pcap_if_t *); +pcap_t* pcapdelay_open_live(const char *, int, int, int, char *); +void pcapdelay_close(pcap_t *); +int pcapdelay_findalldevs(pcap_if_t **, char *); +int pcapdelay_datalink(pcap_t *); +int pcapdelay_setnonblock(pcap_t *, int, char *); +int pcapdelay_sendpacket(pcap_t *p, u_char *buf, int size); +const u_char* pcapdelay_next(pcap_t *, struct pcap_pkthdr *); +int pcapdelay_dispatch(pcap_t *, int, pcap_handler, u_char *); diff --git a/src/atbridge/port.c b/src/atbridge/port.c index b47639c..bd58aca 100644 --- a/src/atbridge/port.c +++ b/src/atbridge/port.c @@ -1,139 +1,132 @@ -/* -GSport - an Apple //gs Emulator -Copyright (C) 2013-2014 by Peter Neubauer - -This program is free software; you can redistribute it and/or modify it -under the terms of the GNU General Public License as published by the -Free Software Foundation; either version 2 of the License, or (at your -option) any later version. - -This program is distributed in the hope that it will be useful, but -WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY -or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -for more details. - -You should have received a copy of the GNU General Public License along -with this program; if not, write to the Free Software Foundation, Inc., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ - -/** This module implements queues for storing and transferring packets within the bridge. **/ - -#include "../defc.h" -#include "atalk.h" -#include "port.h" - -void port_init(struct packet_port_t* port) -{ - if (port) - { - queue_init(&port->in); - queue_init(&port->out); - } -} - -void port_shutdown(struct packet_port_t* port) -{ - if (port) - { - queue_shutdown(&port->in); - queue_shutdown(&port->out); - } -} - -void queue_init(struct packet_queue_t* queue) -{ - if (queue) - { - queue->head = queue->tail = 0; - } -} - -void queue_shutdown(struct packet_queue_t* queue) -{ - if (queue) - { - struct packet_t* packet = dequeue(queue); - while (packet) - { - if (packet->data) - free(packet->data); - free(packet); - packet = dequeue(queue); - } - } -} - -void enqueue(struct packet_queue_t* queue, struct at_addr_t dest, struct at_addr_t source, byte type, size_t size, byte data[]) -{ - if (!queue) - return; - - struct packet_t* packet = (struct packet_t*)malloc(sizeof(struct packet_t)); - packet->dest.network = dest.network; - packet->dest.node = dest.node; - packet->source.network = source.network; - packet->source.node = source.node; - packet->type = type; - packet->size = size; - packet->data = data; - enqueue_packet(queue, packet); -} - -void enqueue_packet(struct packet_queue_t* queue, struct packet_t* packet) -{ - packet->next = 0; - - if (queue->tail) - queue->tail->next = packet; - else - queue->head = packet; - queue->tail = packet; -} - -void insert(struct packet_queue_t* queue, struct at_addr_t dest, struct at_addr_t source, byte type, size_t size, byte data[]) -{ - if (!queue) - return; - - struct packet_t* packet = (struct packet_t*)malloc(sizeof(struct packet_t)); - packet->dest.network = dest.network; - packet->dest.node = dest.node; - packet->source.network = source.network; - packet->source.node = source.node; - packet->type = type; - packet->size = size; - packet->data = data; - insert_packet(queue, packet); -} - -void insert_packet(struct packet_queue_t* queue, struct packet_t* packet) -{ - packet->next = queue->head; - queue->head = packet; - if (!queue->tail) - queue->tail = queue->head; -} - -struct packet_t* dequeue(struct packet_queue_t* queue) -{ - if (queue && queue->head) - { - struct packet_t* packet = queue->head; - if (queue->tail == queue->head) - queue->tail = queue->head = 0; - else - queue->head = packet->next; - return packet; - } - else - return 0; -} - -struct packet_t* queue_peek(struct packet_queue_t* queue) -{ - if (queue) - return queue->head; - else - return 0; -} +/* + GSport - an Apple //gs Emulator + Copyright (C) 2010 - 2019 by GSport contributors + Copyright (C) 2016 - 2018 Dagen Brock + + Based on the KEGS emulator written by and Copyright (C) 2003 Kent Dickey + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 2 of the License, or (at your + option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +/** This module implements queues for storing and transferring packets within the bridge. **/ + +#include "../defc.h" +#include "atalk.h" +#include "port.h" + +void port_init(struct packet_port_t* port) { + if (port) + { + queue_init(&port->in); + queue_init(&port->out); + } +} + +void port_shutdown(struct packet_port_t* port) { + if (port) + { + queue_shutdown(&port->in); + queue_shutdown(&port->out); + } +} + +void queue_init(struct packet_queue_t* queue) { + if (queue) + { + queue->head = queue->tail = 0; + } +} + +void queue_shutdown(struct packet_queue_t* queue) { + if (queue) + { + struct packet_t* packet = dequeue(queue); + while (packet) + { + if (packet->data) + free(packet->data); + free(packet); + packet = dequeue(queue); + } + } +} + +void enqueue(struct packet_queue_t* queue, struct at_addr_t dest, struct at_addr_t source, byte type, size_t size, byte data[]) { + if (!queue) + return; + + struct packet_t* packet = (struct packet_t*)malloc(sizeof(struct packet_t)); + packet->dest.network = dest.network; + packet->dest.node = dest.node; + packet->source.network = source.network; + packet->source.node = source.node; + packet->type = type; + packet->size = size; + packet->data = data; + enqueue_packet(queue, packet); +} + +void enqueue_packet(struct packet_queue_t* queue, struct packet_t* packet) { + packet->next = 0; + + if (queue->tail) + queue->tail->next = packet; + else + queue->head = packet; + queue->tail = packet; +} + +void insert(struct packet_queue_t* queue, struct at_addr_t dest, struct at_addr_t source, byte type, size_t size, byte data[]) { + if (!queue) + return; + + struct packet_t* packet = (struct packet_t*)malloc(sizeof(struct packet_t)); + packet->dest.network = dest.network; + packet->dest.node = dest.node; + packet->source.network = source.network; + packet->source.node = source.node; + packet->type = type; + packet->size = size; + packet->data = data; + insert_packet(queue, packet); +} + +void insert_packet(struct packet_queue_t* queue, struct packet_t* packet) { + packet->next = queue->head; + queue->head = packet; + if (!queue->tail) + queue->tail = queue->head; +} + +struct packet_t* dequeue(struct packet_queue_t* queue) { + if (queue && queue->head) + { + struct packet_t* packet = queue->head; + if (queue->tail == queue->head) + queue->tail = queue->head = 0; + else + queue->head = packet->next; + return packet; + } + else + return 0; +} + +struct packet_t* queue_peek(struct packet_queue_t* queue) { + if (queue) + return queue->head; + else + return 0; +} diff --git a/src/atbridge/port.h b/src/atbridge/port.h index 650b743..6b22dba 100644 --- a/src/atbridge/port.h +++ b/src/atbridge/port.h @@ -1,58 +1,61 @@ -/* -GSport - an Apple //gs Emulator -Copyright (C) 2013-2014 by Peter Neubauer - -This program is free software; you can redistribute it and/or modify it -under the terms of the GNU General Public License as published by the -Free Software Foundation; either version 2 of the License, or (at your -option) any later version. - -This program is distributed in the hope that it will be useful, but -WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY -or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -for more details. - -You should have received a copy of the GNU General Public License along -with this program; if not, write to the Free Software Foundation, Inc., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ - -struct packet_t -{ - struct at_addr_t dest; - struct at_addr_t source; - byte type; - size_t size; - byte* data; - struct packet_t* next; -}; - -struct packet_queue_t -{ - struct packet_t* head; - struct packet_t* tail; -}; - -void queue_init(struct packet_queue_t* queue); -void queue_shutdown(struct packet_queue_t* queue); - -void enqueue(struct packet_queue_t* queue, struct at_addr_t dest, struct at_addr_t source, byte type, size_t size, byte data[]); -void enqueue_packet(struct packet_queue_t* queue, struct packet_t* packet); - -struct packet_t* dequeue(struct packet_queue_t* queue); -struct packet_t* queue_peek(struct packet_queue_t* queue); - -// Insert the packet at the head of the queue, contrary to normal FIFO operation. -void insert(struct packet_queue_t* queue, struct at_addr_t dest, struct at_addr_t source, byte type, size_t size, byte data[]); -void insert_packet(struct packet_queue_t* queue, struct packet_t* packet); - - - -struct packet_port_t -{ - struct packet_queue_t in; - struct packet_queue_t out; -}; - -void port_init(struct packet_port_t* port); -void port_shutdown(struct packet_port_t* port); \ No newline at end of file +/* + GSport - an Apple //gs Emulator + Copyright (C) 2010 - 2019 by GSport contributors + Copyright (C) 2016 - 2018 Dagen Brock + + Based on the KEGS emulator written by and Copyright (C) 2003 Kent Dickey + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 2 of the License, or (at your + option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +struct packet_t +{ + struct at_addr_t dest; + struct at_addr_t source; + byte type; + size_t size; + byte* data; + struct packet_t* next; +}; + +struct packet_queue_t +{ + struct packet_t* head; + struct packet_t* tail; +}; + +void queue_init(struct packet_queue_t* queue); +void queue_shutdown(struct packet_queue_t* queue); + +void enqueue(struct packet_queue_t* queue, struct at_addr_t dest, struct at_addr_t source, byte type, size_t size, byte data[]); +void enqueue_packet(struct packet_queue_t* queue, struct packet_t* packet); + +struct packet_t* dequeue(struct packet_queue_t* queue); +struct packet_t* queue_peek(struct packet_queue_t* queue); + +// Insert the packet at the head of the queue, contrary to normal FIFO operation. +void insert(struct packet_queue_t* queue, struct at_addr_t dest, struct at_addr_t source, byte type, size_t size, byte data[]); +void insert_packet(struct packet_queue_t* queue, struct packet_t* packet); + + + +struct packet_port_t +{ + struct packet_queue_t in; + struct packet_queue_t out; +}; + +void port_init(struct packet_port_t* port); +void port_shutdown(struct packet_port_t* port); diff --git a/src/config.c b/src/config.c index d9a98f9..2241482 100644 --- a/src/config.c +++ b/src/config.c @@ -1,6 +1,7 @@ /* GSport - an Apple //gs Emulator - Copyright (C) 2010 - 2014 by GSport contributors + Copyright (C) 2010 - 2019 by GSport contributors + Copyright (C) 2016 - 2018 Dagen Brock Based on the KEGS emulator written by and Copyright (C) 2003 Kent Dickey @@ -22,10 +23,9 @@ #include "defc.h" #include #include "config.h" +#include "glog.h" #include "imagewriter.h" -#if defined(__OS2__) -#include "arch\os2\src\dirport.h" -#elif defined(_MSC_VER) +#if defined(_MSC_VER) #include "arch\win32\dirent-win32.h" #else #include @@ -33,7 +33,7 @@ #ifdef HAVE_TFE #include "tfe/tfesupp.h" -#include "tfe/protos_tfe.h" +#include "tfe/protos_tfe.h" #endif #if defined _MSC_VER @@ -42,6 +42,9 @@ typedef unsigned int mode_t; #endif +static const char parse_log_prefix_file[] = "Option set [file]:"; + + extern int Verbose; extern word32 g_vbl_count; extern Iwm iwm; @@ -60,6 +63,39 @@ extern int g_fatal_log; extern word32 g_adb_repeat_vbl; +extern int g_audio_enable; +extern int g_preferred_rate; +extern int g_fullscreen; +extern int g_highdpi; +extern int g_borderless; +extern int g_resizeable; +extern int g_noaspect; +extern int g_novsync; +extern int g_nohwaccel; +extern int g_fullscreen_desktop; +extern int g_screen_redraw_skip_amt; +extern int g_use_dhr140; +extern int g_use_bw_hires; +extern int g_scanline_simulator; +extern int g_startx; +extern int g_starty; +extern int g_startw; +extern int g_starth; +extern int g_joystick_number; +extern int g_joystick_x_axis; +extern int g_joystick_y_axis; +extern int g_joystick_x2_axis; +extern int g_joystick_y2_axis; +extern int g_joystick_button_0; +extern int g_joystick_button_1; +extern int g_joystick_button_2; +extern int g_joystick_button_3; +extern int g_ethernet; +extern int g_halt_on_bad_read; +extern int g_ignore_bad_acc; +extern int g_ignore_halts; +extern int g_dbg_enable_port; + extern int halt_sim; extern int g_limit_speed; extern int g_force_depth; @@ -97,22 +133,27 @@ extern char* g_printer_font_courier; extern char* g_printer_font_script; extern char* g_printer_font_ocra; extern int g_printer_timeout; - + extern int g_imagewriter; extern int g_imagewriter_dpi; extern char* g_imagewriter_output; extern int g_imagewriter_multipage; extern int g_imagewriter_timeout; extern char* g_imagewriter_fixed_font; -extern char* g_imagewriter_prop_font; +extern char* g_imagewriter_prop_font; extern int g_imagewriter_paper; -extern int g_imagewriter_banner; - -#if defined(_WIN32) || defined(__CYGWIN__) +extern int g_imagewriter_banner; + +#if defined(_WIN32) && !defined(WIN_SDL) || defined(__CYGWIN__) && !defined(WIN_SDL) extern int g_win_show_console_request; extern int g_win_status_debug_request; #endif +extern char *g_cfg_host_path; +extern int g_cfg_host_read_only; +extern int g_cfg_host_crlf; +extern int g_cfg_host_merlin; + extern int g_screen_index[]; extern word32 g_full_refresh_needed; extern word32 g_a2_screen_buffer_changed; @@ -127,34 +168,36 @@ extern int g_key_down; extern const char g_gsport_version_str[]; int g_config_control_panel = 0; char g_config_gsport_name[1024]; +char g_config_gsport_screenshot_dir[1024]; char g_cfg_cwd_str[CFG_PATH_MAX] = { 0 }; int g_config_gsport_auto_update = 1; int g_config_gsport_update_needed = 0; const char *g_config_gsport_name_list[] = { - "config.txt", "config.gsport", "gsport_conf", ".config.gsport", 0 + "config.txt", "config.gsp", ".config.gsp",0 }; -int g_highest_smartport_unit = -1; -int g_reparse_delay = 0; -int g_user_page2_shadow = 1; +int g_highest_smartport_unit = -1; +int g_reparse_delay = 0; +int g_user_page2_shadow = 1; -byte g_save_text_screen_bytes[0x800]; -int g_save_cur_a2_stat = 0; -char g_cfg_printf_buf[CFG_PRINTF_BUFSIZE]; -char g_config_gsport_buf[CONF_BUF_LEN]; +byte g_save_text_screen_bytes[0x800]; +int g_save_cur_a2_stat = 0; +char g_cfg_printf_buf[CFG_PRINTF_BUFSIZE]; +char g_config_gsport_buf[CONF_BUF_LEN]; -word32 g_cfg_vbl_count = 0; +word32 g_cfg_vbl_count = 0; -int g_cfg_curs_x = 0; -int g_cfg_curs_y = 0; -int g_cfg_curs_inv = 0; -int g_cfg_curs_mousetext = 0; +int g_cfg_curs_x = 0; +int g_cfg_curs_y = 0; +int g_cfg_curs_inv = 0; +int g_cfg_curs_mousetext = 0; int g_cfg_triggeriwreset = 0; -#define CFG_MAX_OPTS 16 -#define CFG_OPT_MAXSTR 100 +#define CFG_PG_SCROLL_AMT 15 +#define CFG_MAX_OPTS 16 +#define CFG_OPT_MAXSTR 100 int g_cfg_opts_vals[CFG_MAX_OPTS]; char g_cfg_opts_strs[CFG_MAX_OPTS][CFG_OPT_MAXSTR]; @@ -162,245 +205,299 @@ char g_cfg_opts_strvals[CFG_MAX_OPTS][CFG_OPT_MAXSTR]; char g_cfg_opt_buf[CFG_OPT_MAXSTR]; char *g_cfg_rom_path = "ROM"; -char *g_cfg_file_def_name = "Undefined"; +const char *g_cfg_file_def_name = "Undefined"; char **g_cfg_file_strptr = 0; int g_cfg_file_min_size = 1024; int g_cfg_file_max_size = 2047*1024*1024; -#define MAX_PARTITION_BLK_SIZE 65536 +int g_cfg_file_dir_only = 0; + +#define MAX_PARTITION_BLK_SIZE 65536 extern Cfg_menu g_cfg_main_menu[]; -#define KNMP(a) &a, #a, 0 +#define KNMP(a) &a, #a, 0 -Cfg_menu g_cfg_disk_menu[] = { -{ "Disk Configuration", g_cfg_disk_menu, 0, 0, CFGTYPE_MENU }, -{ "s5d1 = ", 0, 0, 0, CFGTYPE_DISK + 0x5000 }, -{ "s5d2 = ", 0, 0, 0, CFGTYPE_DISK + 0x5010 }, -{ "", 0, 0, 0, 0 }, -{ "s6d1 = ", 0, 0, 0, CFGTYPE_DISK + 0x6000 }, -{ "s6d2 = ", 0, 0, 0, CFGTYPE_DISK + 0x6010 }, -{ "", 0, 0, 0, 0 }, -{ "s7d1 = ", 0, 0, 0, CFGTYPE_DISK + 0x7000 }, -{ "s7d2 = ", 0, 0, 0, CFGTYPE_DISK + 0x7010 }, -{ "s7d3 = ", 0, 0, 0, CFGTYPE_DISK + 0x7020 }, -{ "s7d4 = ", 0, 0, 0, CFGTYPE_DISK + 0x7030 }, -{ "s7d5 = ", 0, 0, 0, CFGTYPE_DISK + 0x7040 }, -{ "s7d6 = ", 0, 0, 0, CFGTYPE_DISK + 0x7050 }, -{ "s7d7 = ", 0, 0, 0, CFGTYPE_DISK + 0x7060 }, -{ "s7d8 = ", 0, 0, 0, CFGTYPE_DISK + 0x7070 }, -{ "s7d9 = ", 0, 0, 0, CFGTYPE_DISK + 0x7080 }, -{ "s7d10 = ", 0, 0, 0, CFGTYPE_DISK + 0x7090 }, -{ "s7d11 = ", 0, 0, 0, CFGTYPE_DISK + 0x70a0 }, -{ "", 0, 0, 0, 0 }, -{ "Back to Main Config", g_cfg_main_menu, 0, 0, CFGTYPE_MENU }, -{ 0, 0, 0, 0, 0 }, +// This first menu is not a menu, but a list of config options that are +// represented here so they will be parsed correctly out of the config files. +Cfg_menu g_cfg_uiless_menu[] = { + { "", KNMP(g_audio_enable), CFGTYPE_INT }, + { "", KNMP(g_preferred_rate), CFGTYPE_INT }, + { "", KNMP(g_fullscreen), CFGTYPE_INT }, + { "", KNMP(g_highdpi), CFGTYPE_INT }, + { "", KNMP(g_borderless), CFGTYPE_INT }, + { "", KNMP(g_resizeable), CFGTYPE_INT }, + { "", KNMP(g_noaspect), CFGTYPE_INT }, + { "", KNMP(g_novsync), CFGTYPE_INT }, + { "", KNMP(g_nohwaccel), CFGTYPE_INT }, + { "", KNMP(g_fullscreen_desktop), CFGTYPE_INT}, + { "", KNMP(g_screen_redraw_skip_amt), CFGTYPE_INT }, + { "", KNMP(g_use_dhr140), CFGTYPE_INT }, + { "", KNMP(g_use_bw_hires), CFGTYPE_INT }, + { "", KNMP(g_scanline_simulator), CFGTYPE_INT }, + { "", KNMP(g_startx), CFGTYPE_INT }, + { "", KNMP(g_starty), CFGTYPE_INT }, + { "", KNMP(g_startw), CFGTYPE_INT }, + { "", KNMP(g_starth), CFGTYPE_INT }, + { "", KNMP(g_joystick_number), CFGTYPE_INT }, + { "", KNMP(g_joystick_x_axis), CFGTYPE_INT }, + { "", KNMP(g_joystick_y_axis), CFGTYPE_INT }, + { "", KNMP(g_joystick_x2_axis), CFGTYPE_INT }, + { "", KNMP(g_joystick_y2_axis), CFGTYPE_INT }, + { "", KNMP(g_joystick_button_0), CFGTYPE_INT }, + { "", KNMP(g_joystick_button_1), CFGTYPE_INT }, + { "", KNMP(g_joystick_button_2), CFGTYPE_INT }, + { "", KNMP(g_joystick_button_3), CFGTYPE_INT }, + { "", KNMP(g_ethernet), CFGTYPE_INT }, + { "", KNMP(g_halt_on_bad_read), CFGTYPE_INT }, + { "", KNMP(g_ignore_bad_acc), CFGTYPE_INT }, + { "", KNMP(g_ignore_halts), CFGTYPE_INT }, + { 0, 0, 0, 0, 0 }, }; -// OG Use define instead of const for joystick_types -#define STRINGIFY(x) #x -#define TOSTRING(x) STRINGIFY(x) - + +Cfg_menu g_cfg_disk_menu[] = { + { "Disk Configuration", g_cfg_disk_menu, 0, 0, CFGTYPE_MENU }, + { "s5d1 = ", 0, 0, 0, CFGTYPE_DISK + 0x5000 }, + { "s5d2 = ", 0, 0, 0, CFGTYPE_DISK + 0x5010 }, + { "", 0, 0, 0, 0 }, + { "s6d1 = ", 0, 0, 0, CFGTYPE_DISK + 0x6000 }, + { "s6d2 = ", 0, 0, 0, CFGTYPE_DISK + 0x6010 }, + { "", 0, 0, 0, 0 }, + { "s7d1 = ", 0, 0, 0, CFGTYPE_DISK + 0x7000 }, + { "s7d2 = ", 0, 0, 0, CFGTYPE_DISK + 0x7010 }, + { "s7d3 = ", 0, 0, 0, CFGTYPE_DISK + 0x7020 }, + { "s7d4 = ", 0, 0, 0, CFGTYPE_DISK + 0x7030 }, + { "s7d5 = ", 0, 0, 0, CFGTYPE_DISK + 0x7040 }, + { "s7d6 = ", 0, 0, 0, CFGTYPE_DISK + 0x7050 }, + { "s7d7 = ", 0, 0, 0, CFGTYPE_DISK + 0x7060 }, + { "s7d8 = ", 0, 0, 0, CFGTYPE_DISK + 0x7070 }, + { "s7d9 = ", 0, 0, 0, CFGTYPE_DISK + 0x7080 }, + { "s7d10 = ", 0, 0, 0, CFGTYPE_DISK + 0x7090 }, + { "s7d11 = ", 0, 0, 0, CFGTYPE_DISK + 0x70a0 }, + { "", 0, 0, 0, 0 }, + { "Back to Main Config", g_cfg_main_menu, 0, 0, CFGTYPE_MENU }, + { 0, 0, 0, 0, 0 }, +}; + +// OG Use define instead of const for joystick_types +#define STRINGIFY(x) #x +#define TOSTRING(x) STRINGIFY(x) + Cfg_menu g_cfg_joystick_menu[] = { -{ "Joystick Configuration", g_cfg_joystick_menu, 0, 0, CFGTYPE_MENU }, -{ "Joystick Emulation,"TOSTRING(JOYSTICK_TYPE_KEYPAD)",Keypad Joystick,"TOSTRING(JOYSTICK_TYPE_MOUSE)",Mouse Joystick,"TOSTRING(JOYSTICK_TYPE_NATIVE_1)",Native Joystick 1," - TOSTRING(JOYSTICK_TYPE_NATIVE_2)",Native Joystick 2,"TOSTRING(JOYSTICK_TYPE_NONE)",No Joystick", KNMP(g_joystick_type), CFGTYPE_INT }, -{ "Joystick Scale X,0x100,Standard,0x119,+10%,0x133,+20%," - "0x150,+30%,0xb0,-30%,0xcd,-20%,0xe7,-10%", - KNMP(g_joystick_scale_factor_x), CFGTYPE_INT }, -{ "Joystick Scale Y,0x100,Standard,0x119,+10%,0x133,+20%," - "0x150,+30%,0xb0,-30%,0xcd,-20%,0xe7,-10%", - KNMP(g_joystick_scale_factor_y), CFGTYPE_INT }, -{ "Joystick Trim X", KNMP(g_joystick_trim_amount_x), CFGTYPE_INT }, -{ "Joystick Trim Y", KNMP(g_joystick_trim_amount_y), CFGTYPE_INT }, -{ "Swap Joystick X and Y,0,Normal operation,1,Paddle 1 and Paddle 0 swapped", - KNMP(g_swap_paddles), CFGTYPE_INT }, -{ "Invert Joystick,0,Normal operation,1,Left becomes right and up becomes down", - KNMP(g_invert_paddles), CFGTYPE_INT }, -{ "", 0, 0, 0, 0 }, -{ "Back to Main Config", g_cfg_main_menu, 0, 0, CFGTYPE_MENU }, -{ 0, 0, 0, 0, 0 }, + { "Joystick Configuration", g_cfg_joystick_menu, 0, 0, CFGTYPE_MENU }, + { "Joystick Emulation,"TOSTRING (JOYSTICK_TYPE_KEYPAD)",Keypad Joystick,"TOSTRING (JOYSTICK_TYPE_MOUSE)",Mouse Joystick,"TOSTRING (JOYSTICK_TYPE_NATIVE_1)",Native Joystick 1," + TOSTRING(JOYSTICK_TYPE_NATIVE_2) ",Native Joystick 2,"TOSTRING (JOYSTICK_TYPE_NONE)",No Joystick", KNMP(g_joystick_type), CFGTYPE_INT }, + { "Joystick Scale X,0x100,Standard,0x119,+10%,0x133,+20%," + "0x150,+30%,0xb0,-30%,0xcd,-20%,0xe7,-10%", + KNMP(g_joystick_scale_factor_x), CFGTYPE_INT }, + { "Joystick Scale Y,0x100,Standard,0x119,+10%,0x133,+20%," + "0x150,+30%,0xb0,-30%,0xcd,-20%,0xe7,-10%", + KNMP(g_joystick_scale_factor_y), CFGTYPE_INT }, + { "Joystick Trim X", KNMP(g_joystick_trim_amount_x), CFGTYPE_INT }, + { "Joystick Trim Y", KNMP(g_joystick_trim_amount_y), CFGTYPE_INT }, + { "Swap Joystick X and Y,0,Normal operation,1,Paddle 1 and Paddle 0 swapped", + KNMP(g_swap_paddles), CFGTYPE_INT }, + { "Invert Joystick,0,Normal operation,1,Left becomes right and up becomes down", + KNMP(g_invert_paddles), CFGTYPE_INT }, + { "", 0, 0, 0, 0 }, + { "Back to Main Config", g_cfg_main_menu, 0, 0, CFGTYPE_MENU }, + { 0, 0, 0, 0, 0 }, }; Cfg_menu g_cfg_rom_menu[] = { -{ "ROM File Selection", g_cfg_rom_menu, 0, 0, CFGTYPE_MENU }, -{ "ROM File", KNMP(g_cfg_rom_path), CFGTYPE_FILE }, -{ "", 0, 0, 0, 0 }, -{ "Back to Main Config", g_cfg_main_menu, 0, 0, CFGTYPE_MENU }, -{ 0, 0, 0, 0, 0 }, + { "ROM File Selection", g_cfg_rom_menu, 0, 0, CFGTYPE_MENU }, + { "ROM File", KNMP(g_cfg_rom_path), CFGTYPE_FILE }, + { "", 0, 0, 0, 0 }, + { "Back to Main Config", g_cfg_main_menu, 0, 0, CFGTYPE_MENU }, + { 0, 0, 0, 0, 0 }, }; + +Cfg_menu g_cfg_host_menu[] = { + { "Host FST Configuration", g_cfg_host_menu, 0, 0, CFGTYPE_MENU }, + { "Shared Host Folder", KNMP(g_cfg_host_path), CFGTYPE_DIR }, + { "Read Only,0,No,1,Yes", KNMP(g_cfg_host_read_only), CFGTYPE_INT }, + { "CR/LF conversion,0,No,1,Yes", KNMP(g_cfg_host_crlf), CFGTYPE_INT }, + { "Merlin conversion,0,No,1,Yes", KNMP(g_cfg_host_merlin), CFGTYPE_INT }, + { "", 0, 0, 0, 0 }, + { "Back to Main Config", g_cfg_main_menu, 0, 0, CFGTYPE_MENU }, + { 0, 0, 0, 0, 0 }, +}; + + + + Cfg_menu g_cfg_serial_menu[] = { -{ "Serial Port Configuration", g_cfg_serial_menu, 0, 0, CFGTYPE_MENU }, + { "Serial Port Configuration", g_cfg_serial_menu, 0, 0, CFGTYPE_MENU }, #ifdef HAVE_SDL -{ "Port 0 (slot 1),0,Only use socket 6501,1,Use real port if avail,2,Virtual ImageWriter", - KNMP(g_serial_type[0]), CFGTYPE_INT }, -{ "Port 1 (slot 2),0,Only use socket 6502,1,Use real port if avail,2,Virtual ImageWriter", - KNMP(g_serial_type[1]), CFGTYPE_INT }, + { "Port 0 (slot 1),0,Only use socket 6501,1,Use real port if avail,2,Virtual ImageWriter", + KNMP(g_serial_type[0]), CFGTYPE_INT }, + { "Port 1 (slot 2),0,Only use socket 6502,1,Use real port if avail,2,Virtual ImageWriter", + KNMP(g_serial_type[1]), CFGTYPE_INT }, #else -{ "Port 0 (slot 1),0,Only use socket 6501,1,Use real port if avail", - KNMP(g_serial_type[0]), CFGTYPE_INT }, -{ "Port 1 (slot 2),0,Only use socket 6502,1,Use real port if avail", - KNMP(g_serial_type[1]), CFGTYPE_INT }, + { "Port 0 (slot 1),0,Only use socket 6501,1,Use real port if avail", + KNMP(g_serial_type[0]), CFGTYPE_INT }, + { "Port 1 (slot 2),0,Only use socket 6502,1,Use real port if avail", + KNMP(g_serial_type[1]), CFGTYPE_INT }, #endif -{ "Serial Output,0,Send full 8-bit data,1,Mask off high bit", - KNMP(g_serial_out_masking), CFGTYPE_INT }, -{ "Modem on port 0 (slot 1),0,Simple socket emulation mode,1,Modem with " - "incoming and outgoing emulation", KNMP(g_serial_modem[0]), - CFGTYPE_INT }, -{ "Modem on port 1 (slot 2),0,Simple socket emulation mode,1,Modem with " - "incoming and outgoing emulation", KNMP(g_serial_modem[1]), - CFGTYPE_INT }, -{ "", 0, 0, 0, 0 }, -{ "Back to Main Config", g_cfg_main_menu, 0, 0, CFGTYPE_MENU }, -{ 0, 0, 0, 0, 0 }, + { "Serial Output,0,Send full 8-bit data,1,Mask off high bit", + KNMP(g_serial_out_masking), CFGTYPE_INT }, + { "Modem on port 0 (slot 1),0,Simple socket emulation mode,1,Modem with " + "incoming and outgoing emulation", KNMP(g_serial_modem[0]), + CFGTYPE_INT }, + { "Modem on port 1 (slot 2),0,Simple socket emulation mode,1,Modem with " + "incoming and outgoing emulation", KNMP(g_serial_modem[1]), + CFGTYPE_INT }, + { "", 0, 0, 0, 0 }, + { "Back to Main Config", g_cfg_main_menu, 0, 0, CFGTYPE_MENU }, + { 0, 0, 0, 0, 0 }, }; Cfg_menu g_cfg_parallel_menu[] = { -{ "Parallel Card Configuration", g_cfg_parallel_menu, 0, 0, CFGTYPE_MENU }, -{ "Parallel Card in Slot 1,0,Off,1,On", - KNMP(g_parallel), CFGTYPE_INT }, -{ "Parallel Output,0,Send full 8-bit data,1,Mask off high bit", - KNMP(g_parallel_out_masking), CFGTYPE_INT }, -{ "", 0, 0, 0, 0 }, -{ "Back to Main Config", g_cfg_main_menu, 0, 0, CFGTYPE_MENU }, -{ 0, 0, 0, 0, 0 }, + { "Parallel Card Configuration", g_cfg_parallel_menu, 0, 0, CFGTYPE_MENU }, + { "Parallel Card in Slot 1,0,Off,1,On", + KNMP(g_parallel), CFGTYPE_INT }, + { "Parallel Output,0,Send full 8-bit data,1,Mask off high bit", + KNMP(g_parallel_out_masking), CFGTYPE_INT }, + { "", 0, 0, 0, 0 }, + { "Back to Main Config", g_cfg_main_menu, 0, 0, CFGTYPE_MENU }, + { 0, 0, 0, 0, 0 }, }; Cfg_menu g_cfg_ethernet_menu[] = { -{ "Ethernet Card Configuration", g_cfg_ethernet_menu, 0, 0, CFGTYPE_MENU }, -{ "Use Interface Number,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10", - KNMP(g_ethernet_interface), CFGTYPE_INT }, -{ "", 0, 0, 0, 0 }, -{ "Uthernet Card in Slot 3,0,Off,1,On", - KNMP(g_ethernet), CFGTYPE_INT }, + { "Ethernet Card Configuration", g_cfg_ethernet_menu, 0, 0, CFGTYPE_MENU }, + { "Use Interface Number,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10", + KNMP(g_ethernet_interface), CFGTYPE_INT }, + { "", 0, 0, 0, 0 }, + { "Uthernet Card in Slot 3,0,Off,1,On", + KNMP(g_ethernet), CFGTYPE_INT }, #ifdef HAVE_ATBRIDGE -{ "", 0, 0, 0, 0 }, -{ "AppleTalk Bridging,0,Off,1,On", - KNMP(g_appletalk_bridging), CFGTYPE_INT }, -{ "AppleTalk Speed,0,Normal (230.4 kbps),1,Turbo", - KNMP(g_appletalk_turbo), CFGTYPE_INT }, + { "", 0, 0, 0, 0 }, + { "AppleTalk Bridging,0,Off,1,On", + KNMP(g_appletalk_bridging), CFGTYPE_INT }, + { "AppleTalk Speed,0,Normal (230.4 kbps),1,Turbo", + KNMP(g_appletalk_turbo), CFGTYPE_INT }, #endif -{ "", 0, 0, 0, 0 }, -{ "Back to Main Config", g_cfg_main_menu, 0, 0, CFGTYPE_MENU }, -{ 0, 0, 0, 0, 0 }, + { "", 0, 0, 0, 0 }, + { "Back to Main Config", g_cfg_main_menu, 0, 0, CFGTYPE_MENU }, + { 0, 0, 0, 0, 0 }, }; #ifdef HAVE_SDL Cfg_menu g_cfg_printer_menu[] = { -{ "Virtual Epson Configuration", g_cfg_printer_menu, 0, 0, CFGTYPE_MENU }, -{ "Virtual Printer Type,0,Epson LQ", - KNMP(g_printer), CFGTYPE_INT }, -{ "Printer DPI,60,60x60 dpi,180,180x180 dpi,360,360x360 dpi", - KNMP(g_printer_dpi), CFGTYPE_INT }, -{ "Printer Output Type,bmp,Windows Bitmap,ps,Postscript (B&W),printer,Direct to host printer,text,Text file", - KNMP(g_printer_output), CFGTYPE_STR }, -{ "Multipage Files? (PS and Direct to Host Only),0,No,1,Yes", - KNMP(g_printer_multipage), CFGTYPE_INT }, -{ "Printer Timeout,0,Never,2,2 sec.,15,15 sec.,30,30 sec.,60, 1 min.", - KNMP(g_printer_timeout), CFGTYPE_INT }, -{ "", 0, 0, 0, 0 }, -{ "Epson LQ Fonts", 0, 0, 0, 0 }, -{ "--------------", 0, 0, 0, 0 }, -{ "", 0, 0, 0, 0 }, -{ "Roman", KNMP(g_printer_font_roman), CFGTYPE_FILE }, -{ "Sans Serif", KNMP(g_printer_font_sans), CFGTYPE_FILE }, -{ "Courier", KNMP(g_printer_font_courier), CFGTYPE_FILE }, -{ "Prestige", KNMP(g_printer_font_prestige), CFGTYPE_FILE }, -{ "Script", KNMP(g_printer_font_script), CFGTYPE_FILE }, -{ "OCR A/B", KNMP(g_printer_font_ocra), CFGTYPE_FILE }, -{ "", 0, 0, 0, 0 }, -{ "Back to Main Config", g_cfg_main_menu, 0, 0, CFGTYPE_MENU }, -{ 0, 0, 0, 0, 0 }, + { "Virtual Epson Configuration", g_cfg_printer_menu, 0, 0, CFGTYPE_MENU }, + { "Virtual Printer Type,0,Epson LQ", + KNMP(g_printer), CFGTYPE_INT }, + { "Printer DPI,60,60x60 dpi,180,180x180 dpi,360,360x360 dpi", + KNMP(g_printer_dpi), CFGTYPE_INT }, + { "Printer Output Type,bmp,Windows Bitmap,ps,Postscript (B&W),printer,Direct to host printer,text,Text file", + KNMP(g_printer_output), CFGTYPE_STR }, + { "Multipage Files? (PS and Direct to Host Only),0,No,1,Yes", + KNMP(g_printer_multipage), CFGTYPE_INT }, + { "Printer Timeout,0,Never,2,2 sec.,15,15 sec.,30,30 sec.,60, 1 min.", + KNMP(g_printer_timeout), CFGTYPE_INT }, + { "", 0, 0, 0, 0 }, + { "Epson LQ Fonts", 0, 0, 0, 0 }, + { "--------------", 0, 0, 0, 0 }, + { "", 0, 0, 0, 0 }, + { "Roman", KNMP(g_printer_font_roman), CFGTYPE_FILE }, + { "Sans Serif", KNMP(g_printer_font_sans), CFGTYPE_FILE }, + { "Courier", KNMP(g_printer_font_courier), CFGTYPE_FILE }, + { "Prestige", KNMP(g_printer_font_prestige), CFGTYPE_FILE }, + { "Script", KNMP(g_printer_font_script), CFGTYPE_FILE }, + { "OCR A/B", KNMP(g_printer_font_ocra), CFGTYPE_FILE }, + { "", 0, 0, 0, 0 }, + { "Back to Main Config", g_cfg_main_menu, 0, 0, CFGTYPE_MENU }, + { 0, 0, 0, 0, 0 }, }; -Cfg_menu g_cfg_imagewriter_menu[] = { -{ "Virtual ImageWriter Configuration", g_cfg_imagewriter_menu, 0, 0, CFGTYPE_MENU }, -{ "Virtual Printer Type,0,ImageWriter II,1,ImageWriter LQ", - KNMP(g_imagewriter), CFGTYPE_INT }, -{ "Paper Size,0,US Letter (8.5x11in),1,US Legal (8.5x14in),2,ISO A4 (210 x 297mm),3,ISO B5 (176 x 250mm),4,Wide Fanfold (14 x 11in),5,Ledger (11 x 17in),6,ISO A3 (297 x 420mm)", - KNMP(g_imagewriter_paper), CFGTYPE_INT }, -{ "Printer DPI,360,360x360 dpi (Best for 8-bit software),720,720x720 dpi (Best for GS/OS & IW LQ Modes),1440,1440x1440 dpi", - KNMP(g_imagewriter_dpi), CFGTYPE_INT }, -{ "Banner Printing (Limited To 144x144 dpi Output),0,Banner Printing Off,3,3 Pages Long,4,4 Pages Long,5,5 Pages Long,6,6 Pages Long,7,7 Pages Long,8,8 Pages Long,9,9 Pages Long,10,10 Pages Long", - KNMP(g_imagewriter_banner), CFGTYPE_INT }, -{ "Printer Output Type,bmp,Windows Bitmap,ps,Postscript (B&W),colorps,Postscript (Color),printer,Direct to host printer,text,Text file", - KNMP(g_imagewriter_output), CFGTYPE_STR }, -{ "Multipage Files? (PS and Direct to Host Only),0,No,1,Yes", - KNMP(g_imagewriter_multipage), CFGTYPE_INT }, -{ "Printer Timeout,0,Never,2,2 sec.,15,15 sec.,30,30 sec.,60, 1 min.", - KNMP(g_imagewriter_timeout), CFGTYPE_INT }, -{ "", 0, 0, 0, 0 }, -{ "ImageWriter Fonts", 0, 0, 0, 0 }, -{ "-----------------", 0, 0, 0, 0 }, -{ "", 0, 0, 0, 0 }, -{ "Fixed Width Font", KNMP(g_imagewriter_fixed_font), CFGTYPE_FILE }, -{ "", 0, 0, 0, 0 }, -{ "Proportional Font", KNMP(g_imagewriter_prop_font), CFGTYPE_FILE }, -{ "", 0, 0, 0, 0 }, -{ "", 0, 0, 0, 0 }, -{ "Back to Main Config", g_cfg_main_menu, 0, 0, CFGTYPE_MENU }, -{ 0, 0, 0, 0, 0 }, -}; -#endif - +Cfg_menu g_cfg_imagewriter_menu[] = { + { "Virtual ImageWriter Configuration", g_cfg_imagewriter_menu, 0, 0, CFGTYPE_MENU }, + { "Virtual Printer Type,0,ImageWriter II,1,ImageWriter LQ", + KNMP(g_imagewriter), CFGTYPE_INT }, + { "Paper Size,0,US Letter (8.5x11in),1,US Legal (8.5x14in),2,ISO A4 (210 x 297mm),3,ISO B5 (176 x 250mm),4,Wide Fanfold (14 x 11in),5,Ledger (11 x 17in),6,ISO A3 (297 x 420mm)", + KNMP(g_imagewriter_paper), CFGTYPE_INT }, + { "Printer DPI,360,360x360 dpi (Best for 8-bit software),720,720x720 dpi (Best for GS/OS & IW LQ Modes),1440,1440x1440 dpi", + KNMP(g_imagewriter_dpi), CFGTYPE_INT }, + { "Banner Printing (Limited To 144x144 dpi Output),0,Banner Printing Off,3,3 Pages Long,4,4 Pages Long,5,5 Pages Long,6,6 Pages Long,7,7 Pages Long,8,8 Pages Long,9,9 Pages Long,10,10 Pages Long", + KNMP(g_imagewriter_banner), CFGTYPE_INT }, + { "Printer Output Type,bmp,Windows Bitmap,ps,Postscript (B&W),colorps,Postscript (Color),printer,Direct to host printer,text,Text file", + KNMP(g_imagewriter_output), CFGTYPE_STR }, + { "Multipage Files? (PS and Direct to Host Only),0,No,1,Yes", + KNMP(g_imagewriter_multipage), CFGTYPE_INT }, + { "Printer Timeout,0,Never,2,2 sec.,15,15 sec.,30,30 sec.,60, 1 min.", + KNMP(g_imagewriter_timeout), CFGTYPE_INT }, + { "", 0, 0, 0, 0 }, + { "ImageWriter Fonts", 0, 0, 0, 0 }, + { "-----------------", 0, 0, 0, 0 }, + { "", 0, 0, 0, 0 }, + { "Fixed Width Font", KNMP(g_imagewriter_fixed_font), CFGTYPE_FILE }, + { "", 0, 0, 0, 0 }, + { "Proportional Font", KNMP(g_imagewriter_prop_font), CFGTYPE_FILE }, + { "", 0, 0, 0, 0 }, + { "", 0, 0, 0, 0 }, + { "Back to Main Config", g_cfg_main_menu, 0, 0, CFGTYPE_MENU }, + { 0, 0, 0, 0, 0 }, +}; +#endif + Cfg_menu g_cfg_devel_menu[] = { -{ "Developer Options", g_cfg_devel_menu, 0, 0, CFGTYPE_MENU }, -#if defined(_WIN32) || defined(__CYGWIN__) -{ "Status lines,0,Hide,1,Show", KNMP(g_win_status_debug_request), CFGTYPE_INT }, -{ "Console,0,Hide,1,Show", KNMP(g_win_show_console_request), CFGTYPE_INT }, + { "Developer Options", g_cfg_devel_menu, 0, 0, CFGTYPE_MENU }, +#if defined(_WIN32) && !defined(WIN_SDL) || defined(__CYGWIN__) && !defined(WIN_SDL) + { "Status lines,0,Hide,1,Show", KNMP(g_win_status_debug_request), CFGTYPE_INT }, + { "Console,0,Hide,1,Show", KNMP(g_win_show_console_request), CFGTYPE_INT }, #endif #ifdef HAVE_ATBRIDGE -{ "", 0, 0, 0, 0 }, -{ "Show AppleTalk Diagnostics,0,No,1,Yes", KNMP(g_appletalk_diagnostics), CFGTYPE_INT }, -{ "AppleTalk Network Hint", KNMP(g_appletalk_network_hint), CFGTYPE_INT }, + { "", 0, 0, 0, 0 }, + { "Show AppleTalk Diagnostics,0,No,1,Yes", KNMP(g_appletalk_diagnostics), CFGTYPE_INT }, + { "AppleTalk Network Hint", KNMP(g_appletalk_network_hint), CFGTYPE_INT }, #endif -{ "", 0, 0, 0, 0 }, + { "", 0, 0, 0, 0 }, #ifndef _WIN32 -{ "Force X-windows display depth", KNMP(g_force_depth), CFGTYPE_INT }, + { "Force X-windows display depth", KNMP(g_force_depth), CFGTYPE_INT }, #endif -{ "Code Red Halts,0,Do not stop on bad accesses,1,Enter debugger on bad accesses", KNMP(g_user_halt_bad), CFGTYPE_INT }, -{ "3200 Color Enable,0,Auto (Full if fast enough),1,Full (Update every line),8,Off (Update video every 8 lines)", KNMP(g_video_line_update_interval), CFGTYPE_INT }, -{ "Keyboard and mouse poll rate,0,60 times per second,1,240 times per second", KNMP(g_video_extra_check_inputs), CFGTYPE_INT }, -{ "Enable Text Page 2 Shadow,0,Disabled on ROM 01 (matches real hardware),1,Enabled on ROM 01 and 03", KNMP(g_user_page2_shadow), CFGTYPE_INT }, -{ "", 0, 0, 0, 0 }, -{ "Back to Main Config", g_cfg_main_menu, 0, 0, CFGTYPE_MENU }, -{ 0, 0, 0, 0, 0 }, + { "Code Red Halts,0,Do not stop on bad accesses,1,Enter debugger on bad accesses", KNMP(g_user_halt_bad), CFGTYPE_INT }, + { "3200 Color Enable,0,Auto (Full if fast enough),1,Full (Update every line),8,Off (Update video every 8 lines)", KNMP(g_video_line_update_interval), CFGTYPE_INT }, + { "Keyboard and mouse poll rate,0,60 times per second,1,240 times per second", KNMP(g_video_extra_check_inputs), CFGTYPE_INT }, + { "Enable Text Page 2 Shadow,0,Disabled on ROM 01 (matches real hardware),1,Enabled on ROM 01 and 03", KNMP(g_user_page2_shadow), CFGTYPE_INT }, + { "", 0, 0, 0, 0 }, + { "Back to Main Config", g_cfg_main_menu, 0, 0, CFGTYPE_MENU }, + { 0, 0, 0, 0, 0 }, }; Cfg_menu g_cfg_main_menu[] = { -{ "GSport Configuration", g_cfg_main_menu, 0, 0, CFGTYPE_MENU }, -{ "Disk Configuration", g_cfg_disk_menu, 0, 0, CFGTYPE_MENU }, -{ "Joystick Configuration", g_cfg_joystick_menu, 0, 0, CFGTYPE_MENU }, -{ "ROM File Selection", g_cfg_rom_menu, 0, 0, CFGTYPE_MENU }, -{ "Serial Port Configuration", g_cfg_serial_menu, 0, 0, CFGTYPE_MENU }, -{ "Ethernet Card Configuration", g_cfg_ethernet_menu, 0, 0, CFGTYPE_MENU }, -{ "Parallel Card Configuration", g_cfg_parallel_menu, 0, 0, CFGTYPE_MENU }, + { "GSport Configuration", g_cfg_main_menu, 0, 0, CFGTYPE_MENU }, + { "Disk Configuration", g_cfg_disk_menu, 0, 0, CFGTYPE_MENU }, + { "Joystick Configuration", g_cfg_joystick_menu, 0, 0, CFGTYPE_MENU }, + { "ROM File Selection", g_cfg_rom_menu, 0, 0, CFGTYPE_MENU }, + { "HOST FST Configuration", g_cfg_host_menu, 0, 0, CFGTYPE_MENU }, + { "Serial Port Configuration", g_cfg_serial_menu, 0, 0, CFGTYPE_MENU }, + { "Ethernet Card Configuration", g_cfg_ethernet_menu, 0, 0, CFGTYPE_MENU }, + { "Parallel Card Configuration", g_cfg_parallel_menu, 0, 0, CFGTYPE_MENU }, #ifdef HAVE_SDL -{ "Virtual Epson Configuration", g_cfg_printer_menu, 0, 0, CFGTYPE_MENU }, -{ "Virtual ImageWriter Configuration", g_cfg_imagewriter_menu, 0, 0, CFGTYPE_MENU }, + { "Virtual Epson Configuration", g_cfg_printer_menu, 0, 0, CFGTYPE_MENU }, + { "Virtual ImageWriter Configuration", g_cfg_imagewriter_menu, 0, 0, CFGTYPE_MENU }, #endif -{ "Developer Options", g_cfg_devel_menu, 0, 0, CFGTYPE_MENU }, -{ "Auto-update configuration file,0,Manual,1,Immediately", - KNMP(g_config_gsport_auto_update), CFGTYPE_INT }, -{ "Speed,0,Unlimited,1,1.0MHz,2,2.8MHz,3,8.0MHz (Zip)", - KNMP(g_limit_speed), CFGTYPE_INT }, -{ "Expansion Mem Size,0,0MB,0x100000,1MB,0x200000,2MB,0x300000,3MB," - "0x400000,4MB,0x600000,6MB,0x800000,8MB,0xa00000,10MB,0xc00000,12MB," - "0xe00000,14MB", KNMP(g_mem_size_exp), CFGTYPE_INT }, -{ "Dump text screen to file", (void *)cfg_text_screen_dump, 0, 0, CFGTYPE_FUNC}, + { "Developer Options", g_cfg_devel_menu, 0, 0, CFGTYPE_MENU }, + { "Auto-update configuration file,0,Manual,1,Immediately", KNMP(g_config_gsport_auto_update), CFGTYPE_INT }, + { "Speed,0,Unlimited,1,1.0MHz,2,2.8MHz,3,8.0MHz (Zip)", KNMP(g_limit_speed), CFGTYPE_INT }, + { "Expansion Mem Size,0,0MB,0x100000,1MB,0x200000,2MB,0x300000,3MB," + "0x400000,4MB,0x600000,6MB,0x800000,8MB,0xa00000,10MB,0xc00000,12MB," + "0xe00000,14MB", KNMP(g_mem_size_exp), CFGTYPE_INT }, + { "Dump text screen to file", (void *)cfg_text_screen_dump, 0, 0, CFGTYPE_FUNC}, #ifdef HAVE_SDL -{ "Reset Virtual ImageWriter", (void *)cfg_iwreset, 0, 0, CFGTYPE_FUNC }, + { "Reset Virtual ImageWriter", (void *)cfg_iwreset, 0, 0, CFGTYPE_FUNC }, #endif -{ "", 0, 0, 0, 0 }, -{ "Save changes to configuration file", (void *)config_write_config_gsport_file, 0, 0, - CFGTYPE_FUNC }, -{ "", 0, 0, 0, 0 }, -{ "Exit Config (or press F4)", (void *)cfg_exit, 0, 0, CFGTYPE_FUNC }, -{ 0, 0, 0, 0, 0 }, + { "", 0, 0, 0, 0 }, + { "Save changes to configuration file", (void *)config_write_config_gsport_file, 0, 0, + CFGTYPE_FUNC }, + { "", 0, 0, 0, 0 }, + { "Exit Config (or press F4)", (void *)cfg_exit, 0, 0, CFGTYPE_FUNC }, + { 0, 0, 0, 0, 0 }, }; -#define CFG_MAX_DEFVALS 128 +#define CFG_MAX_DEFVALS 128 Cfg_defval g_cfg_defvals[CFG_MAX_DEFVALS]; int g_cfg_defval_index = 0; @@ -419,3008 +516,2893 @@ Cfg_listhdr g_cfg_partitionlist = { 0 }; int g_cfg_file_pathfield = 0; -const char *g_gsport_rom_names[] = { "ROM", "ROM", "ROM.01", "ROM.03", 0 }; - /* First entry is special--it will be overwritten by g_cfg_rom_path */ +const char *g_gsport_rom_names[] = { "ROM", "ROM", "ROM1", "ROM3", "ROM01", "ROM03", "ROM.01", "ROM.03", 0 }; +/* First entry is special--it will be overwritten by g_cfg_rom_path */ const char *g_gsport_c1rom_names[] = { "parallel.rom", 0 }; const char *g_gsport_c2rom_names[] = { 0 }; const char *g_gsport_c3rom_names[] = { 0 }; const char *g_gsport_c4rom_names[] = { 0 }; const char *g_gsport_c5rom_names[] = { 0 }; -const char *g_gsport_c6rom_names[] = { "c600.rom", "controller.rom", "disk.rom", - "DISK.ROM", "diskII.prom", 0 }; +const char *g_gsport_c6rom_names[] = { "c600.rom", "controller.rom", "disk.rom", "DISK.ROM", "diskII.prom", 0 }; const char *g_gsport_c7rom_names[] = { 0 }; const char **g_gsport_rom_card_list[8] = { - 0, g_gsport_c1rom_names, - g_gsport_c2rom_names, g_gsport_c3rom_names, - g_gsport_c4rom_names, g_gsport_c5rom_names, - g_gsport_c6rom_names, g_gsport_c7rom_names }; + 0, g_gsport_c1rom_names, + g_gsport_c2rom_names, g_gsport_c3rom_names, + g_gsport_c4rom_names, g_gsport_c5rom_names, + g_gsport_c6rom_names, g_gsport_c7rom_names +}; byte g_rom_c600_rom01_diffs[256] = { - 0x00, 0x00, 0x00, 0x00, 0xc6, 0x00, 0xe2, 0x00, - 0xd0, 0x50, 0x0f, 0x77, 0x5b, 0xb9, 0xc3, 0xb1, - 0xb1, 0xf8, 0xcb, 0x4e, 0xb8, 0x60, 0xc7, 0x2e, - 0xfc, 0xe0, 0xbf, 0x1f, 0x66, 0x37, 0x4a, 0x70, - 0x55, 0x2c, 0x3c, 0xfc, 0xc2, 0xa5, 0x08, 0x29, - 0xac, 0x21, 0xcc, 0x09, 0x55, 0x03, 0x17, 0x35, - 0x4e, 0xe2, 0x0c, 0xe9, 0x3f, 0x9d, 0xc2, 0x06, - 0x18, 0x88, 0x0d, 0x58, 0x57, 0x6d, 0x83, 0x8c, - 0x22, 0xd3, 0x4f, 0x0a, 0xe5, 0xb7, 0x9f, 0x7d, - 0x2c, 0x3e, 0xae, 0x7f, 0x24, 0x78, 0xfd, 0xd0, - 0xb5, 0xd6, 0xe5, 0x26, 0x85, 0x3d, 0x8d, 0xc9, - 0x79, 0x0c, 0x75, 0xec, 0x98, 0xcc, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x77, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x7b, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x39, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x39, 0x00, 0x35, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x4a, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, - 0x6c, 0x44, 0xce, 0x4c, 0x01, 0x08, 0x00, 0x00 + 0x00, 0x00, 0x00, 0x00, 0xc6, 0x00, 0xe2, 0x00, + 0xd0, 0x50, 0x0f, 0x77, 0x5b, 0xb9, 0xc3, 0xb1, + 0xb1, 0xf8, 0xcb, 0x4e, 0xb8, 0x60, 0xc7, 0x2e, + 0xfc, 0xe0, 0xbf, 0x1f, 0x66, 0x37, 0x4a, 0x70, + 0x55, 0x2c, 0x3c, 0xfc, 0xc2, 0xa5, 0x08, 0x29, + 0xac, 0x21, 0xcc, 0x09, 0x55, 0x03, 0x17, 0x35, + 0x4e, 0xe2, 0x0c, 0xe9, 0x3f, 0x9d, 0xc2, 0x06, + 0x18, 0x88, 0x0d, 0x58, 0x57, 0x6d, 0x83, 0x8c, + 0x22, 0xd3, 0x4f, 0x0a, 0xe5, 0xb7, 0x9f, 0x7d, + 0x2c, 0x3e, 0xae, 0x7f, 0x24, 0x78, 0xfd, 0xd0, + 0xb5, 0xd6, 0xe5, 0x26, 0x85, 0x3d, 0x8d, 0xc9, + 0x79, 0x0c, 0x75, 0xec, 0x98, 0xcc, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x77, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x7b, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x39, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x39, 0x00, 0x35, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x4a, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, + 0x6c, 0x44, 0xce, 0x4c, 0x01, 0x08, 0x00, 0x00 }; -void -config_init_menus(Cfg_menu *menuptr) -{ - void *voidptr; - const char *name_str; - Cfg_defval *defptr; - char **str_ptr; - char *str; - int type; - int pos; - int val; +void config_init_menus(Cfg_menu *menuptr) { + void *voidptr; + const char *name_str; + Cfg_defval *defptr; + char **str_ptr; + char *str; + int type; + int pos; + int val; - if(menuptr[0].defptr != 0) { - return; - } - menuptr[0].defptr = (void *)1; - pos = 0; - while(pos < 100) { - type = menuptr->cfgtype; - voidptr = menuptr->ptr; - name_str = menuptr->name_str; - if(menuptr->str == 0) { - break; - } - if(name_str != 0) { - defptr = &(g_cfg_defvals[g_cfg_defval_index++]); - if(g_cfg_defval_index >= CFG_MAX_DEFVALS) { - fatal_printf("CFG_MAX_DEFVAL overflow\n"); - my_exit(5); - } - defptr->menuptr = menuptr; - defptr->intval = 0; - defptr->strval = 0; - switch(type) { - case CFGTYPE_INT: - val = *((int *)voidptr); - defptr->intval = val; - menuptr->defptr = &(defptr->intval); - break; - case CFGTYPE_STR: - str_ptr = (char **)menuptr->ptr; - str = *str_ptr; - // We need to malloc this string since all - // string values must be dynamically alloced - defptr->strval = str; // this can have a copy - *str_ptr = gsport_malloc_str(str); - menuptr->defptr = &(defptr->strval); - break; - case CFGTYPE_FILE: - str_ptr = (char **)menuptr->ptr; - str = *str_ptr; - // We need to malloc this string since all - // string values must be dynamically alloced - defptr->strval = str; // this can have a copy - *str_ptr = gsport_malloc_str(str); - menuptr->defptr = &(defptr->strval); - break; - default: - fatal_printf("name_str is %p = %s, but type: " - "%d\n", name_str, name_str, type); - my_exit(5); - } - } - if(type == CFGTYPE_MENU) { - config_init_menus((Cfg_menu *)voidptr); - } - pos++; - menuptr++; - } + if(menuptr[0].defptr != 0) { + return; + } + menuptr[0].defptr = (void *)1; + pos = 0; + while(pos < 100) { + type = menuptr->cfgtype; + voidptr = menuptr->ptr; + name_str = menuptr->name_str; + if(menuptr->str == 0) { + break; + } + if(name_str != 0) { + defptr = &(g_cfg_defvals[g_cfg_defval_index++]); + if(g_cfg_defval_index >= CFG_MAX_DEFVALS) { + fatal_printf("CFG_MAX_DEFVAL overflow\n"); + my_exit(5); + } + defptr->menuptr = menuptr; + defptr->intval = 0; + defptr->strval = 0; + switch(type) { + case CFGTYPE_INT: + val = *((int *)voidptr); + defptr->intval = val; + menuptr->defptr = &(defptr->intval); + break; + case CFGTYPE_STR: + case CFGTYPE_FILE: + case CFGTYPE_DIR: + str_ptr = (char **)menuptr->ptr; + str = *str_ptr; + // We need to malloc this string since all + // string values must be dynamically alloced + defptr->strval = str; // this can have a copy + *str_ptr = gsport_malloc_str(str); + menuptr->defptr = &(defptr->strval); + break; + default: + fatal_printf("name_str is %p = %s, but type: " + "%d\n", name_str, name_str, type); + my_exit(5); + } + } + if(type == CFGTYPE_MENU) { + config_init_menus((Cfg_menu *)voidptr); + } + pos++; + menuptr++; + } } -void -config_init() -{ - int can_create; +void config_init() { + int can_create; - config_init_menus(g_cfg_main_menu); + config_init_menus(g_cfg_main_menu); + config_init_menus(g_cfg_uiless_menu); - // Find the configuration file - g_config_gsport_name[0] = 0; - can_create = 1; - setup_gsport_file(&g_config_gsport_name[0], sizeof(g_config_gsport_name), 0, - can_create, &g_config_gsport_name_list[0]); + // Find the configuration file + g_config_gsport_name[0] = 0; + can_create = 1; + setup_gsport_file(&g_config_gsport_name[0], sizeof(g_config_gsport_name), 0, can_create, &g_config_gsport_name_list[0]); - config_parse_config_gsport_file(); + config_parse_config_gsport_file(); } -void -cfg_exit() -{ - /* printf("In cfg exit\n"); */ - if(g_rom_version >= 1) { - g_config_control_panel = 0; - } +void cfg_exit() { + if(g_rom_version >= 1) { + g_config_control_panel = 0; + } } -void -cfg_toggle_config_panel() -{ - g_config_control_panel = !g_config_control_panel; - if(g_rom_version < 0) { - g_config_control_panel = 1; /* Stay in config mode */ - } +void cfg_toggle_config_panel() { + g_config_control_panel = !g_config_control_panel; + if(g_rom_version < 0) { + g_config_control_panel = 1; /* Stay in config mode */ + } } -void -cfg_text_screen_dump() -{ - char buf[85]; - char *filename; - FILE *ofile; - int offset; - int c; - int pos; - int i, j; +void cfg_text_screen_dump() { + char buf[85]; + char *filename; + FILE *ofile; + int offset; + int c; + int pos; + int i, j; - filename = "gsport.screen.dump"; - printf("Writing text screen to the file %s\n", filename); - ofile = fopen(filename, "w"); - if(ofile == 0) { - fatal_printf("Could not write to file %s, (%d)\n", filename, - errno); - return; - } + filename = "gsport.screen.dump"; + glogf("Writing text screen to the file %s", filename); + ofile = fopen(filename, "w"); + if(ofile == 0) { + fatal_printf("Could not write to file %s, (%d)\n", filename, errno); + return; + } - for(i = 0; i < 24; i++) { - pos = 0; - for(j = 0; j < 40; j++) { - offset = g_screen_index[i] + j; - if(g_save_cur_a2_stat & ALL_STAT_VID80) { - c = g_save_text_screen_bytes[0x400+offset]; - c = c & 0x7f; - if(c < 0x20) { - c += 0x40; - } - buf[pos++] = c; - } - c = g_save_text_screen_bytes[offset] & 0x7f; - if(c < 0x20) { - c += 0x40; - } - buf[pos++] = c; - } - while((pos > 0) && (buf[pos-1] == ' ')) { - /* try to strip out trailing spaces */ - pos--; - } - buf[pos++] = '\n'; - buf[pos++] = 0; - fputs(buf, ofile); - } - fclose(ofile); + for(i = 0; i < 24; i++) { + pos = 0; + for(j = 0; j < 40; j++) { + offset = g_screen_index[i] + j; + if(g_save_cur_a2_stat & ALL_STAT_VID80) { + c = g_save_text_screen_bytes[0x400+offset]; + c = c & 0x7f; + if(c < 0x20) { + c += 0x40; + } + buf[pos++] = c; + } + c = g_save_text_screen_bytes[offset] & 0x7f; + if(c < 0x20) { + c += 0x40; + } + buf[pos++] = c; + } + while((pos > 0) && (buf[pos-1] == ' ')) { + /* try to strip out trailing spaces */ + pos--; + } + buf[pos++] = '\n'; + buf[pos++] = 0; + fputs(buf, ofile); + } + fclose(ofile); } -void -cfg_iwreset() -{ - imagewriter_feed(); - imagewriter_close(); - imagewriter_init(g_imagewriter_dpi,g_imagewriter_paper,g_imagewriter_banner, g_imagewriter_output,g_imagewriter_multipage); - return; +void cfg_iwreset() { + imagewriter_feed(); + imagewriter_close(); + imagewriter_init(g_imagewriter_dpi,g_imagewriter_paper,g_imagewriter_banner, g_imagewriter_output,g_imagewriter_multipage); + return; } #ifdef HAVE_TFE -void -cfg_get_tfe_name() -{ - int i = 0; - char *ppname = NULL; - char *ppdes = NULL; - cfg_htab_vtab(0,11); - if (tfe_enumadapter_open()) - { - cfg_printf("Interface List:\n---------------"); - while(tfe_enumadapter(&ppname,&ppdes)) - { - cfg_htab_vtab(0, 13+i); - cfg_printf("%2d: %s",i,ppdes); - i++; - lib_free(ppname); - lib_free(ppdes); - } - tfe_enumadapter_close(); - } - else - { - #if defined(_WIN32) || defined(__CYGWIN__) - cfg_printf("ERROR: Install/Enable WinPcap for Ethernet Support!!"); - #else - cfg_printf("ERROR: Install/Enable LibPcap for Ethernet Support!!"); - #endif - } - return; +void cfg_get_tfe_name() { + int i = 0; + char *ppname = NULL; + char *ppdes = NULL; + cfg_htab_vtab(0,11); + if (tfe_enumadapter_open()) + { + cfg_printf("Interface List:\n---------------"); + while(tfe_enumadapter(&ppname,&ppdes)) + { + cfg_htab_vtab(0, 13+i); + cfg_printf("%2d: %s",i,ppdes); + i++; + lib_free(ppname); + lib_free(ppdes); + } + tfe_enumadapter_close(); + } + else + { + #if defined(_WIN32) || defined(__CYGWIN__) + cfg_printf("ERROR: Install/Enable WinPcap for Ethernet Support!!"); + #else + cfg_printf("ERROR: Install/Enable LibPcap for Ethernet Support!!"); + #endif + } + return; } #endif -void -config_vbl_update(int doit_3_persec) -{ - if(doit_3_persec) { - if(g_config_gsport_auto_update && g_config_gsport_update_needed) { - config_write_config_gsport_file(); - } - } - return; +void config_vbl_update(int doit_3_persec) { + if(doit_3_persec) { + if(g_config_gsport_auto_update && g_config_gsport_update_needed) { + config_write_config_gsport_file(); + } + } + return; } -void -config_parse_option(char *buf, int pos, int len, int line) -{ - Cfg_menu *menuptr; - Cfg_defval *defptr; - char *nameptr; - char **strptr; - int *iptr; - int num_equals; - int type; - int val; - int c; - int i; +void config_parse_option(char *buf, int pos, int len, int line) { + Cfg_menu *menuptr; + Cfg_defval *defptr; + char *nameptr; + char **strptr; + int *iptr; + int num_equals; + int type; + int val; + int c; + int i; // warning: modifies buf (turns spaces to nulls) // parse buf from pos into option, "=" and then "rest" - if(pos >= len) { - /* blank line */ - return; - } + if(pos >= len) { + /* blank line */ + return; + } - if(strncmp(&buf[pos], "bram", 4) == 0) { - config_parse_bram(buf, pos+4, len); - return; - } + if(strncmp(&buf[pos], "bram", 4) == 0) { + config_parse_bram(buf, pos+4, len); + return; + } - // find "name" as first contiguous string - printf("...parse_option: line %d, %p,%p = %s (%s) len:%d\n", line, - &buf[pos], buf, &buf[pos], buf, len); + // find "name" as first contiguous string + glogf("%s line %d, len:%d \"%s\"", parse_log_prefix_file, line, len, &buf[pos]); - nameptr = &buf[pos]; - while(pos < len) { - c = buf[pos]; - if(c == 0 || c == ' ' || c == '\t' || c == '\n') { - break; - } - pos++; - } - buf[pos] = 0; - pos++; + nameptr = &buf[pos]; + while(pos < len) { + c = buf[pos]; + if(c == 0 || c == ' ' || c == '\t' || c == '\n') { + break; + } + pos++; + } + buf[pos] = 0; + pos++; - // Eat up all whitespace and '=' - num_equals = 0; - while(pos < len) { - c = buf[pos]; - if((c == '=') && num_equals == 0) { - pos++; - num_equals++; - } else if(c == ' ' || c == '\t') { - pos++; - } else { - break; - } - } + // Eat up all whitespace and '=' + num_equals = 0; + while(pos < len) { + c = buf[pos]; + if((c == '=') && num_equals == 0) { + pos++; + num_equals++; + } else if(c == ' ' || c == '\t') { + pos++; + } else { + break; + } + } - /* Look up nameptr to find type */ - type = -1; - defptr = 0; - menuptr = 0; - for(i = 0; i < g_cfg_defval_index; i++) { - defptr = &(g_cfg_defvals[i]); - menuptr = defptr->menuptr; - if(strcmp(menuptr->name_str, nameptr) == 0) { - type = menuptr->cfgtype; - break; - } - } + /* Look up nameptr to find type */ + type = -1; + defptr = 0; + menuptr = 0; + for(i = 0; i < g_cfg_defval_index; i++) { + defptr = &(g_cfg_defvals[i]); + menuptr = defptr->menuptr; + if(strcmp(menuptr->name_str, nameptr) == 0) { + type = menuptr->cfgtype; + break; + } + } - switch(type) { - case CFGTYPE_INT: - /* use strtol */ - val = (int)strtol(&buf[pos], 0, 0); - iptr = (int *)menuptr->ptr; - *iptr = val; - break; - case CFGTYPE_STR: - strptr = (char **)menuptr->ptr; - if(strptr && *strptr) { - free(*strptr); - } - *strptr = gsport_malloc_str(&buf[pos]); - break; - case CFGTYPE_FILE: - strptr = (char **)menuptr->ptr; - if(strptr && *strptr) { - free(*strptr); - } - *strptr = gsport_malloc_str(&buf[pos]); - break; - default: - printf("Config file variable %s is unknown type: %d\n", - nameptr, type); - } + switch(type) { + case CFGTYPE_INT: + /* use strtol */ + val = (int)strtol(&buf[pos], 0, 0); + iptr = (int *)menuptr->ptr; + *iptr = val; + break; + case CFGTYPE_STR: + case CFGTYPE_FILE: + case CFGTYPE_DIR: + strptr = (char **)menuptr->ptr; + if(strptr && *strptr) { + free(*strptr); + } + *strptr = gsport_malloc_str(&buf[pos]); + break; + default: + glogf("Config file variable %s is unknown type: %d", nameptr, type); + } } -void -config_parse_bram(char *buf, int pos, int len) -{ - int bram_num; - int offset; - int val; +void config_parse_bram(char *buf, int pos, int len) { + int bram_num; + int offset; + int val; - if((len < (pos+5)) || (buf[pos+1] != '[') || (buf[pos+4] != ']')) { - fatal_printf("While reading configuration file, found malformed bram " - "statement: %s\n", buf); - return; - } - bram_num = buf[pos] - '0'; - if(bram_num != 1 && bram_num != 3) { - fatal_printf("While reading configuration file, found bad bram " - "num: %s\n", buf); - return; - } + if((len < (pos+5)) || (buf[pos+1] != '[') || (buf[pos+4] != ']')) { + fatal_printf("While reading configuration file, found malformed bram " + "statement: %s\n", buf); + return; + } + bram_num = buf[pos] - '0'; + if(bram_num != 1 && bram_num != 3) { + fatal_printf("While reading configuration file, found bad bram " + "num: %s\n", buf); + return; + } - bram_num = bram_num >> 1; // turn 3->1 and 1->0 + bram_num = bram_num >> 1; // turn 3->1 and 1->0 - offset = strtoul(&(buf[pos+2]), 0, 16); - pos += 5; - while(pos < len) { - while(buf[pos] == ' ' || buf[pos] == '\t' || buf[pos] == 0x0a || - buf[pos] == 0x0d || buf[pos] == '=') { - pos++; - } - val = strtoul(&buf[pos], 0, 16); - clk_bram_set(bram_num, offset, val); - offset++; - pos += 2; - } + offset = strtoul(&(buf[pos+2]), 0, 16); + pos += 5; + while(pos < len) { + while(buf[pos] == ' ' || buf[pos] == '\t' || buf[pos] == 0x0a || + buf[pos] == 0x0d || buf[pos] == '=') { + pos++; + } + val = strtoul(&buf[pos], 0, 16); + clk_bram_set(bram_num, offset, val); + offset++; + pos += 2; + } } -void -config_load_roms() -{ - struct stat stat_buf; - const char **names_ptr; - int more_than_8mb; - int changed_rom; - int len; - FILE *file; - int ret; - int i; +void config_load_roms() { + struct stat stat_buf; + const char **names_ptr; + int more_than_8mb; + int changed_rom; + int len; + FILE *file; + int ret; + int i; - g_rom_version = -1; + g_rom_version = -1; - /* set first entry of g_gsport_rom_names[] to g_cfg_rom_path so that */ - /* it becomes the first place searched. */ - g_gsport_rom_names[0] = g_cfg_rom_path; - setup_gsport_file(&g_cfg_tmp_path[0], CFG_PATH_MAX, -1, 0, - &g_gsport_rom_names[0]); + /* set first entry of g_gsport_rom_names[] to g_cfg_rom_path so that */ + /* it becomes the first place searched. */ + g_gsport_rom_names[0] = g_cfg_rom_path; + setup_gsport_file(&g_cfg_tmp_path[0], CFG_PATH_MAX, -1, 0, + &g_gsport_rom_names[0]); - if(g_cfg_tmp_path[0] == 0) { - // Just get out, let config interface select ROM - g_config_control_panel = 1; - return; - } - file = fopen(&g_cfg_tmp_path[0], "rb"); - if(!file) { - fatal_printf("Open ROM file %s failed; errno:%d\n", - &g_cfg_tmp_path[0], errno); - g_config_control_panel = 1; - return; - } + if(g_cfg_tmp_path[0] == 0) { + // Just get out, let config interface select ROM + g_config_control_panel = 1; + return; + } + file = fopen(&g_cfg_tmp_path[0], "rb"); + if(!file) { + fatal_printf("Open ROM file %s failed; errno:%d\n", + &g_cfg_tmp_path[0], errno); + g_config_control_panel = 1; + return; + } - ret = stat(&g_cfg_tmp_path[0], &stat_buf); - if(ret != 0) { - fatal_printf("stat returned %d; errno: %d\n", - ret, errno); - g_config_control_panel = 1; - return; - } + ret = stat(&g_cfg_tmp_path[0], &stat_buf); + if(ret != 0) { + fatal_printf("stat returned %d; errno: %d\n", + ret, errno); + g_config_control_panel = 1; + return; + } - len = stat_buf.st_size; - if(len == 128*1024) { - g_rom_version = 1; - g_mem_size_base = 256*1024; - memset(&g_rom_fc_ff_ptr[0], 0, 2*65536); - /* Clear banks fc and fd to 0 */ - ret = fread(&g_rom_fc_ff_ptr[2*65536], 1, len, file); - } else if(len == 256*1024) { - g_rom_version = 3; - g_mem_size_base = 1024*1024; - ret = fread(&g_rom_fc_ff_ptr[0], 1, len, file); - } else { - fatal_printf("The ROM size should be 128K or 256K, this file " - "is %d bytes\n", len); - g_config_control_panel = 1; - return; - } + len = stat_buf.st_size; + if(len == 128*1024) { + g_rom_version = 1; + g_mem_size_base = 256*1024; + memset(&g_rom_fc_ff_ptr[0], 0, 2*65536); + /* Clear banks fc and fd to 0 */ + ret = fread(&g_rom_fc_ff_ptr[2*65536], 1, len, file); + } else if(len == 256*1024) { + g_rom_version = 3; + g_mem_size_base = 1024*1024; + ret = fread(&g_rom_fc_ff_ptr[0], 1, len, file); + } else { + fatal_printf("The ROM size should be 128K or 256K, this file " + "is %d bytes\n", len); + g_config_control_panel = 1; + return; + } - printf("Read: %d bytes of ROM\n", ret); - if(ret != len) { - fatal_printf("errno: %d\n", errno); - g_config_control_panel = 1; - return; - } - fclose(file); + glogf("Read %d bytes (%dK) of ROM", ret, ret/1024); + if(ret != len) { + fatal_printf("errno: %d\n", errno); + g_config_control_panel = 1; // THIS DOESN'T DO ANYTHING? + return; + } + fclose(file); - memset(&g_rom_cards_ptr[0], 0, 256*16); + memset(&g_rom_cards_ptr[0], 0, 256*16); - /* initialize c600 rom to be diffs from the real ROM, to build-in */ - /* Apple II compatibility without distributing ROMs */ - for(i = 0; i < 256; i++) { - g_rom_cards_ptr[0x600 + i] = g_rom_fc_ff_ptr[0x3c600 + i] ^ - g_rom_c600_rom01_diffs[i]; - } - if(g_rom_version >= 3) { - /* some patches */ - g_rom_cards_ptr[0x61b] ^= 0x40; - g_rom_cards_ptr[0x61c] ^= 0x33; - g_rom_cards_ptr[0x632] ^= 0xc0; - g_rom_cards_ptr[0x633] ^= 0x33; - } + /* initialize c600 rom to be diffs from the real ROM, to build-in */ + /* Apple II compatibility without distributing ROMs */ + for(i = 0; i < 256; i++) { + g_rom_cards_ptr[0x600 + i] = g_rom_fc_ff_ptr[0x3c600 + i] ^ + g_rom_c600_rom01_diffs[i]; + } + if(g_rom_version >= 3) { + /* some patches */ + g_rom_cards_ptr[0x61b] ^= 0x40; + g_rom_cards_ptr[0x61c] ^= 0x33; + g_rom_cards_ptr[0x632] ^= 0xc0; + g_rom_cards_ptr[0x633] ^= 0x33; + } - for(i = 1; i < 8; i++) { - names_ptr = g_gsport_rom_card_list[i]; - if(names_ptr == 0) { - continue; - } - if(*names_ptr == 0) { - continue; - } - setup_gsport_file(&g_cfg_tmp_path[0], CFG_PATH_MAX, 1, 0, - names_ptr); - if(g_cfg_tmp_path[0] != 0) { - file = fopen(&(g_cfg_tmp_path[0]), "rb"); - if(!file) { - fatal_printf("Open card ROM file %s failed; errno:%d\n", - &g_cfg_tmp_path[0], errno); - continue; - } + for(i = 1; i < 8; i++) { + names_ptr = g_gsport_rom_card_list[i]; + if(names_ptr == 0) { + continue; + } + if(*names_ptr == 0) { + continue; + } + setup_gsport_file(&g_cfg_tmp_path[0], CFG_PATH_MAX, 1, 0, names_ptr); + if(g_cfg_tmp_path[0] != 0) { + file = fopen(&(g_cfg_tmp_path[0]), "rb"); + if(!file) { + fatal_printf("Open card ROM file %s failed; errno:%d\n", + &g_cfg_tmp_path[0], errno); + continue; + } - len = 256; - ret = fread(&g_rom_cards_ptr[i*0x100], 1, len, file); + len = 256; + ret = fread(&g_rom_cards_ptr[i*0x100], 1, len, file); - if(ret != len) { - fatal_printf("While reading card ROM %s, file " - "is too short. (%d) Expected %d bytes, " - "read %d bytes\n", &g_cfg_tmp_path[0], errno, len, ret); - continue; - } - printf("Read: %d bytes of ROM in slot %d from file %s.\n", ret, i, &g_cfg_tmp_path[0]); - fclose(file); - } - } - more_than_8mb = (g_mem_size_exp > 0x800000); - /* Only do the patch if users wants more than 8MB of expansion mem */ + if(ret != len) { + fatal_printf("While reading card ROM %s, file " + "is too short. (%d) Expected %d bytes, " + "read %d bytes\n", &g_cfg_tmp_path[0], errno, len, ret); + continue; + } + glogf("Read: %d bytes of ROM in slot %d from file %s.", ret, i, &g_cfg_tmp_path[0]); + fclose(file); + } + } + more_than_8mb = (g_mem_size_exp > 0x800000); + /* Only do the patch if users wants more than 8MB of expansion mem */ - changed_rom = 0; - if(g_rom_version == 1) { - /* make some patches to ROM 01 */ + changed_rom = 0; + if(g_rom_version == 1) { + /* make some patches to ROM 01 */ #if 0 - /* 1: Patch ROM selftest to not do speed test */ - printf("Patching out speed test failures from ROM 01\n"); - g_rom_fc_ff_ptr[0x3785a] = 0x18; - changed_rom = 1; + /* 1: Patch ROM selftest to not do speed test */ + printf("Patching out speed test failures from ROM 01\n"); + g_rom_fc_ff_ptr[0x3785a] = 0x18; + changed_rom = 1; #endif #if 0 - /* 2: Patch ROM selftests not to do tests 2,4 */ - /* 0 = skip, 1 = do it, test 1 is bit 0 of LSByte */ - g_rom_fc_ff_ptr[0x371e9] = 0xf5; - g_rom_fc_ff_ptr[0x371ea] = 0xff; - changed_rom = 1; + /* 2: Patch ROM selftests not to do tests 2,4 */ + /* 0 = skip, 1 = do it, test 1 is bit 0 of LSByte */ + g_rom_fc_ff_ptr[0x371e9] = 0xf5; + g_rom_fc_ff_ptr[0x371ea] = 0xff; + changed_rom = 1; #endif - if(more_than_8mb) { - /* Geoff Weiss patch to use up to 14MB of RAM */ - g_rom_fc_ff_ptr[0x30302] = 0xdf; - g_rom_fc_ff_ptr[0x30314] = 0xdf; - g_rom_fc_ff_ptr[0x3031c] = 0x00; - changed_rom = 1; - } + if(more_than_8mb) { + /* Geoff Weiss patch to use up to 14MB of RAM */ + g_rom_fc_ff_ptr[0x30302] = 0xdf; + g_rom_fc_ff_ptr[0x30314] = 0xdf; + g_rom_fc_ff_ptr[0x3031c] = 0x00; + changed_rom = 1; + } - /* Patch ROM selftest to not do ROM cksum if any changes*/ - if(changed_rom) { - g_rom_fc_ff_ptr[0x37a06] = 0x18; - g_rom_fc_ff_ptr[0x37a07] = 0x18; - } - } else if(g_rom_version == 3) { - /* patch ROM 03 */ - printf("Patching ROM 03 smartport bug\n"); - /* 1: Patch Smartport code to fix a stupid bug */ - /* that causes it to write the IWM status reg into c036, */ - /* which is the system speed reg...it's "safe" since */ - /* IWM status reg bit 4 must be 0 (7MHz)..., otherwise */ - /* it might have turned on shadowing in all banks! */ - g_rom_fc_ff_ptr[0x357c9] = 0x00; - changed_rom = 1; + /* Patch ROM selftest to not do ROM cksum if any changes*/ + if(changed_rom) { + g_rom_fc_ff_ptr[0x37a06] = 0x18; + g_rom_fc_ff_ptr[0x37a07] = 0x18; + } + } else if(g_rom_version == 3) { + /* patch ROM 03 */ + glog("Patching ROM 03 smartport bug"); + /* 1: Patch Smartport code to fix a stupid bug */ + /* that causes it to write the IWM status reg into c036, */ + /* which is the system speed reg...it's "safe" since */ + /* IWM status reg bit 4 must be 0 (7MHz)..., otherwise */ + /* it might have turned on shadowing in all banks! */ + g_rom_fc_ff_ptr[0x357c9] = 0x00; + changed_rom = 1; #if 0 - /* patch ROM 03 to not to speed test */ - /* skip fast speed test */ - g_rom_fc_ff_ptr[0x36ad7] = 0x18; - g_rom_fc_ff_ptr[0x36ad8] = 0x18; - changed_rom = 1; + /* patch ROM 03 to not to speed test */ + /* skip fast speed test */ + g_rom_fc_ff_ptr[0x36ad7] = 0x18; + g_rom_fc_ff_ptr[0x36ad8] = 0x18; + changed_rom = 1; #endif #if 0 - /* skip slow speed test */ - g_rom_fc_ff_ptr[0x36ae7] = 0x18; - g_rom_fc_ff_ptr[0x36ae8] = 0x6b; - changed_rom = 1; + /* skip slow speed test */ + g_rom_fc_ff_ptr[0x36ae7] = 0x18; + g_rom_fc_ff_ptr[0x36ae8] = 0x6b; + changed_rom = 1; #endif #if 0 - /* 4: Patch ROM 03 selftests not to do tests 1-4 */ - g_rom_fc_ff_ptr[0x364a9] = 0xf0; - g_rom_fc_ff_ptr[0x364aa] = 0xff; - changed_rom = 1; + /* 4: Patch ROM 03 selftests not to do tests 1-4 */ + g_rom_fc_ff_ptr[0x364a9] = 0xf0; + g_rom_fc_ff_ptr[0x364aa] = 0xff; + changed_rom = 1; #endif - /* ROM tests are in ff/6403-642x, where 6403 = addr of */ - /* test 1, etc. */ + /* ROM tests are in ff/6403-642x, where 6403 = addr of */ + /* test 1, etc. */ - if(more_than_8mb) { - /* Geoff Weiss patch to use up to 14MB of RAM */ - g_rom_fc_ff_ptr[0x30b] = 0xdf; - g_rom_fc_ff_ptr[0x31d] = 0xdf; - g_rom_fc_ff_ptr[0x325] = 0x00; - changed_rom = 1; - } + if(more_than_8mb) { + /* Geoff Weiss patch to use up to 14MB of RAM */ + g_rom_fc_ff_ptr[0x30b] = 0xdf; + g_rom_fc_ff_ptr[0x31d] = 0xdf; + g_rom_fc_ff_ptr[0x325] = 0x00; + changed_rom = 1; + } - if(changed_rom) { - /* patch ROM 03 selftest to not do ROM cksum */ - g_rom_fc_ff_ptr[0x36cb0] = 0x18; - g_rom_fc_ff_ptr[0x36cb1] = 0x18; - } + if(changed_rom) { + /* patch ROM 03 selftest to not do ROM cksum */ + g_rom_fc_ff_ptr[0x36cb0] = 0x18; + g_rom_fc_ff_ptr[0x36cb1] = 0x18; + } - } + } } -void -config_parse_config_gsport_file() -{ - FILE *fconf; - char *buf; - char *ptr; - char *name_ptr; - char *partition_name; - int part_num; - int ejected; - int line; - int pos; - int slot; - int drive; - int size; - int len; - int ret; - int i; +void config_parse_config_gsport_file() { + FILE *fconf; + char *buf; + char *ptr; + char *name_ptr; + char *partition_name; + int part_num; + int ejected; + int line; + int pos; + int slot; + int drive; + int size; + int len; + int ret; + int i; - printf("Parsing configuration file\n"); + glogf("Parsing configuration file '%s'", g_config_gsport_name); - clk_bram_zero(); + clk_bram_zero(); - g_highest_smartport_unit = -1; + g_highest_smartport_unit = -1; - cfg_get_base_path(&g_cfg_cwd_str[0], g_config_gsport_name, 0); -#ifndef __OS2__ - if(g_cfg_cwd_str[0] != 0) { - ret = chdir(&g_cfg_cwd_str[0]); - if(ret != 0) { - printf("chdir to %s, errno:%d\n", g_cfg_cwd_str, errno); - } - } - /* In any case, copy the directory path to g_cfg_cwd_str */ - (void)getcwd(&g_cfg_cwd_str[0], CFG_PATH_MAX); -#endif + cfg_get_base_path(&g_cfg_cwd_str[0], g_config_gsport_name, 0); - fconf = fopen(g_config_gsport_name, "r"); - if(fconf == 0) { - fatal_printf("cannot open configuration file at %s! Stopping!\n", - g_config_gsport_name); - my_exit(3); - } + // I think this code is wrong. It breaks relative config paths on the "-config" + // option. ie "./gsport -config foo/bar.gsp" + // It's possible it was needed for some of the autodiscovery stuff, but I'm + // not really a fan of that either and think it should be take out. + // Especially now that you can pass a filename. - line = 0; - while(1) { - buf = &g_config_gsport_buf[0]; - ptr = fgets(buf, CONF_BUF_LEN, fconf); - if(ptr == 0) { - iwm_printf("Done reading disk_conf\n"); - break; - } + fconf = fopen(g_config_gsport_name, "r"); + if(fconf == 0) { + perror("ERROR"); + fatal_printf("Cannot open configuration file at %s! Stopping!\n",g_config_gsport_name); + my_exit(3); + } - line++; - /* strip off newline(s) */ - len = strlen(buf); - for(i = len - 1; i >= 0; i--) { - if((buf[i] != 0x0d) && (buf[i] != 0x0a)) { - break; - } - len = i; - buf[i] = 0; - } + line = 0; + while(1) { + buf = &g_config_gsport_buf[0]; + ptr = fgets(buf, CONF_BUF_LEN, fconf); + if(ptr == 0) { + iwm_printf("Done reading disk_conf\n"); + break; + } - iwm_printf("disk_conf[%d]: %s\n", line, buf); - if(len > 0 && buf[0] == '#') { - iwm_printf("Skipping comment\n"); - continue; - } + line++; + /* strip off newline(s) */ + len = strlen(buf); + for(i = len - 1; i >= 0; i--) { + if((buf[i] != 0x0d) && (buf[i] != 0x0a)) { + break; + } + len = i; + buf[i] = 0; + } - /* determine what this is */ - pos = 0; + iwm_printf("disk_conf[%d]: %s\n", line, buf); + if(len > 0 && buf[0] == '#') { + iwm_printf("Skipping comment\n"); + continue; + } - while(pos < len && (buf[pos] == ' ' || buf[pos] == '\t') ) { - pos++; - } - if((pos + 4) > len || buf[pos] != 's' || buf[pos+2] != 'd' || - buf[pos+1] > '9' || buf[pos+1] < '0') { - config_parse_option(buf, pos, len, line); - continue; - } + /* determine what this is */ + pos = 0; - slot = buf[pos+1] - '0'; - drive = buf[pos+3] - '0'; + while(pos < len && (buf[pos] == ' ' || buf[pos] == '\t') ) { + pos++; + } + if((pos + 4) > len || buf[pos] != 's' || buf[pos+2] != 'd' || + buf[pos+1] > '9' || buf[pos+1] < '0') { + config_parse_option(buf, pos, len, line); + continue; + } - /* skip over slot, drive */ - pos += 4; - if(buf[pos] >= '0' && buf[pos] <= '9') { - drive = drive * 10 + buf[pos] - '0'; - pos++; - } + slot = buf[pos+1] - '0'; + drive = buf[pos+3] - '0'; - /* make s6d1 mean index 0 */ - drive--; + /* skip over slot, drive */ + pos += 4; + if(buf[pos] >= '0' && buf[pos] <= '9') { + drive = drive * 10 + buf[pos] - '0'; + pos++; + } - while(pos < len && (buf[pos] == ' ' || buf[pos] == '\t' || - buf[pos] == '=') ) { - pos++; - } + /* make s6d1 mean index 0 */ + drive--; - ejected = 0; - if(buf[pos] == '#') { - /* disk is ejected, but read all the info anyway */ - ejected = 1; - pos++; - } + while(pos < len && (buf[pos] == ' ' || buf[pos] == '\t' || + buf[pos] == '=') ) { + pos++; + } - size = 0; - if(buf[pos] == ',') { - /* read optional size parameter */ - pos++; - while(pos < len && buf[pos] >= '0' && buf[pos] <= '9'){ - size = size * 10 + buf[pos] - '0'; - pos++; - } - size = size * 1024; - if(buf[pos] == ',') { - pos++; /* eat trailing ',' */ - } - } + ejected = 0; + if(buf[pos] == '#') { + /* disk is ejected, but read all the info anyway */ + ejected = 1; + pos++; + } - /* see if it has a partition name */ - partition_name = 0; - part_num = -1; - if(buf[pos] == ':') { - pos++; - /* yup, it's got a partition name! */ - partition_name = &buf[pos]; - while((pos < len) && (buf[pos] != ':')) { - pos++; - } - buf[pos] = 0; /* null terminate partition name */ - pos++; - } - if(buf[pos] == ';') { - pos++; - /* it's got a partition number */ - part_num = 0; - while((pos < len) && (buf[pos] != ':')) { - part_num = (10*part_num) + buf[pos] - '0'; - pos++; - } - pos++; - } + size = 0; + if(buf[pos] == ',') { + /* read optional size parameter */ + pos++; + while(pos < len && buf[pos] >= '0' && buf[pos] <= '9') { + size = size * 10 + buf[pos] - '0'; + pos++; + } + size = size * 1024; + if(buf[pos] == ',') { + pos++; /* eat trailing ',' */ + } + } - /* Get filename */ - name_ptr = &(buf[pos]); - if(name_ptr[0] == 0) { - continue; - } + /* see if it has a partition name */ + partition_name = 0; + part_num = -1; + if(buf[pos] == ':') { + pos++; + /* yup, it's got a partition name! */ + partition_name = &buf[pos]; + while((pos < len) && (buf[pos] != ':')) { + pos++; + } + buf[pos] = 0; /* null terminate partition name */ + pos++; + } + if(buf[pos] == ';') { + pos++; + /* it's got a partition number */ + part_num = 0; + while((pos < len) && (buf[pos] != ':')) { + part_num = (10*part_num) + buf[pos] - '0'; + pos++; + } + pos++; + } - insert_disk(slot, drive, name_ptr, ejected, size, - partition_name, part_num); + /* Get filename */ + name_ptr = &(buf[pos]); + if(name_ptr[0] == 0) { + continue; + } - } + insert_disk(slot, drive, name_ptr, ejected, size, + partition_name, part_num); - ret = fclose(fconf); - if(ret != 0) { - fatal_printf("Closing configuration file ret: %d, errno: %d\n", ret, - errno); - my_exit(4); - } + } - iwm_printf("Done parsing disk_conf file\n"); + ret = fclose(fconf); + if(ret != 0) { + fatal_printf("Closing configuration file ret: %d, errno: %d\n", ret, + errno); + my_exit(4); + } + + iwm_printf("Done parsing disk_conf file\n"); } -Disk * -cfg_get_dsk_from_slot_drive(int slot, int drive) -{ - Disk *dsk; - int max_drive; +Disk *cfg_get_dsk_from_slot_drive(int slot, int drive) { + Disk *dsk; + int max_drive; - /* Get dsk */ - max_drive = 2; - switch(slot) { - case 5: - dsk = &(iwm.drive35[drive]); - break; - case 6: - dsk = &(iwm.drive525[drive]); - break; - default: - max_drive = MAX_C7_DISKS; - dsk = &(iwm.smartport[drive]); - } + /* Get dsk */ + max_drive = 2; + switch(slot) { + case 5: + dsk = &(iwm.drive35[drive]); + break; + case 6: + dsk = &(iwm.drive525[drive]); + break; + default: + max_drive = MAX_C7_DISKS; + dsk = &(iwm.smartport[drive]); + } - if(drive >= max_drive) { - dsk -= drive; /* move back to drive 0 effectively */ - } + if(drive >= max_drive) { + dsk -= drive; /* move back to drive 0 effectively */ + } - return dsk; + return dsk; } -void -config_generate_config_gsport_name(char *outstr, int maxlen, Disk *dsk, - int with_extras) -{ - char *str; +void config_generate_config_gsport_name(char *outstr, int maxlen, Disk *dsk, + int with_extras) { + char *str; - str = outstr; + str = outstr; - if(with_extras && (!dsk->file)) { - snprintf(str, maxlen - (str - outstr), "#"); - str = &outstr[strlen(outstr)]; - } - if(with_extras && dsk->force_size > 0) { - snprintf(str, maxlen - (str - outstr), ",%d,", dsk->force_size); - str = &outstr[strlen(outstr)]; - } - if(with_extras && dsk->partition_name != 0) { - snprintf(str, maxlen - (str - outstr), ":%s:", - dsk->partition_name); - str = &outstr[strlen(outstr)]; - } else if(with_extras && dsk->partition_num >= 0) { - snprintf(str, maxlen - (str - outstr), ";%d:", - dsk->partition_num); - str = &outstr[strlen(outstr)]; - } - snprintf(str, maxlen - (str - outstr), "%s", dsk->name_ptr); + if(with_extras && (!dsk->file)) { + snprintf(str, maxlen - (str - outstr), "#"); + str = &outstr[strlen(outstr)]; + } + if(with_extras && dsk->force_size > 0) { + snprintf(str, maxlen - (str - outstr), ",%d,", dsk->force_size); + str = &outstr[strlen(outstr)]; + } + if(with_extras && dsk->partition_name != 0) { + snprintf(str, maxlen - (str - outstr), ":%s:", + dsk->partition_name); + str = &outstr[strlen(outstr)]; + } else if(with_extras && dsk->partition_num >= 0) { + snprintf(str, maxlen - (str - outstr), ";%d:", + dsk->partition_num); + str = &outstr[strlen(outstr)]; + } + snprintf(str, maxlen - (str - outstr), "%s", dsk->name_ptr); } -void -config_write_config_gsport_file() -{ - FILE *fconf; - Disk *dsk; - Cfg_defval *defptr; - Cfg_menu *menuptr; - char *curstr, *defstr; - int defval, curval; - int type; - int slot, drive; - int i; +void config_write_config_gsport_file() { + FILE *fconf; + Disk *dsk; + Cfg_defval *defptr; + Cfg_menu *menuptr; + char *curstr, *defstr; + int defval, curval; + int type; + int slot, drive; + int i; - printf("Writing configuration file to %s\n", g_config_gsport_name); + glogf("Writing configuration file to %s", g_config_gsport_name); - fconf = fopen(g_config_gsport_name, "w+"); - if(fconf == 0) { - halt_printf("cannot open %s! Stopping!\n",g_config_gsport_name); - return; - } + fconf = fopen(g_config_gsport_name, "w+"); + if(fconf == 0) { + halt_printf("cannot open %s! Stopping!\n",g_config_gsport_name); + return; + } - fprintf(fconf, "# GSport configuration file version %s\n", - g_gsport_version_str); + fprintf(fconf, "# GSport configuration file version %s\n", + g_gsport_version_str); - for(i = 0; i < MAX_C7_DISKS + 4; i++) { - slot = 7; - drive = i - 4; - if(i < 4) { - slot = (i >> 1) + 5; - drive = i & 1; - } - if(drive == 0) { - fprintf(fconf, "\n"); /* an extra blank line */ - } + for(i = 0; i < MAX_C7_DISKS + 4; i++) { + slot = 7; + drive = i - 4; + if(i < 4) { + slot = (i >> 1) + 5; + drive = i & 1; + } + if(drive == 0) { + fprintf(fconf, "\n"); /* an extra blank line */ + } - dsk = cfg_get_dsk_from_slot_drive(slot, drive); - if(dsk->name_ptr == 0 && (i > 4)) { - /* No disk, not even ejected--just skip */ - continue; - } - fprintf(fconf, "s%dd%d = ", slot, drive + 1); - if(dsk->name_ptr == 0) { - fprintf(fconf, "\n"); - continue; - } - config_generate_config_gsport_name(&g_cfg_tmp_path[0], - CFG_PATH_MAX, dsk, 1); - fprintf(fconf, "%s\n", &g_cfg_tmp_path[0]); - } + dsk = cfg_get_dsk_from_slot_drive(slot, drive); + if(dsk->name_ptr == 0 && (i > 4)) { + /* No disk, not even ejected--just skip */ + continue; + } + fprintf(fconf, "s%dd%d = ", slot, drive + 1); + if(dsk->name_ptr == 0) { + fprintf(fconf, "\n"); + continue; + } + config_generate_config_gsport_name(&g_cfg_tmp_path[0], + CFG_PATH_MAX, dsk, 1); + fprintf(fconf, "%s\n", &g_cfg_tmp_path[0]); + } - fprintf(fconf, "\n"); + fprintf(fconf, "\n"); - /* See if any variables are different than their default */ - for(i = 0; i < g_cfg_defval_index; i++) { - defptr = &(g_cfg_defvals[i]); - menuptr = defptr->menuptr; - defval = defptr->intval; - type = menuptr->cfgtype; - if(type == CFGTYPE_INT) { - curval = *((int *)menuptr->ptr); - if(curval != defval) { - fprintf(fconf, "%s = %d\n", menuptr->name_str, - curval); - } - } - if(type == CFGTYPE_STR) { - curstr = *((char **)menuptr->ptr); - defstr = *((char **)menuptr->defptr); - if(strcmp(curstr, defstr) != 0) { - fprintf(fconf, "%s = %s\n", menuptr->name_str, - curstr); - } - } - if(type == CFGTYPE_FILE) { - curstr = *((char **)menuptr->ptr); - defstr = *((char **)menuptr->defptr); - if(strcmp(curstr, defstr) != 0) { - fprintf(fconf, "%s = %s\n", menuptr->name_str, - curstr); - } - } - } + /* See if any variables are different than their default */ + for(i = 0; i < g_cfg_defval_index; i++) { + defptr = &(g_cfg_defvals[i]); + menuptr = defptr->menuptr; + defval = defptr->intval; + type = menuptr->cfgtype; - fprintf(fconf, "\n"); + switch (type) { + case CFGTYPE_INT: + curval = *((int *)menuptr->ptr); + if(curval != defval) { + fprintf(fconf, "%s = %d\n", menuptr->name_str, + curval); + } + break; + case CFGTYPE_STR: + case CFGTYPE_FILE: + case CFGTYPE_DIR: + curstr = *((char **)menuptr->ptr); + defstr = *((char **)menuptr->defptr); + if(strcmp(curstr, defstr) != 0) { + fprintf(fconf, "%s = %s\n", menuptr->name_str, + curstr); + } + break; + } + } - /* write bram state */ - clk_write_bram(fconf); + fprintf(fconf, "\n"); - fclose(fconf); + /* write bram state */ + clk_write_bram(fconf); - g_config_gsport_update_needed = 0; + fclose(fconf); + + g_config_gsport_update_needed = 0; } -void -insert_disk(int slot, int drive, const char *name, int ejected, int force_size, - const char *partition_name, int part_num) -{ - byte buf_2img[512]; - Disk *dsk; - char *name_ptr, *uncomp_ptr, *system_str; - char *part_ptr; - int size; - int system_len; - int part_len; - int cmp_o, cmp_p, cmp_dot; - int cmp_b, cmp_i, cmp_n; - int can_write; - int len; - int nibs; - int unix_pos; - int name_len; - int image_identified; - int exp_size; - int save_track; - int ret; - int tmp; - int i; +void insert_disk(int slot, int drive, const char *name, int ejected, int force_size, + const char *partition_name, int part_num) { + byte buf_2img[512]; + Disk *dsk; + char *name_ptr, *uncomp_ptr, *system_str; + char *part_ptr; + int size; + int system_len; + int part_len; + int cmp_o, cmp_p, cmp_dot; + int cmp_b, cmp_i, cmp_n; + int can_write; + int len = 0; + int nibs; + int unix_pos; + int name_len; + int image_identified; + int exp_size; + int save_track; + int ret; + int tmp; + int i; - g_config_gsport_update_needed = 1; + g_config_gsport_update_needed = 1; - if((slot < 5) || (slot > 7)) { - fatal_printf("Invalid slot for inserting disk: %d\n", slot); - return; - } - if(drive < 0 || ((slot == 7) && (drive >= MAX_C7_DISKS)) || - ((slot < 7) && (drive > 1))) { - fatal_printf("Invalid drive for inserting disk: %d\n", drive); - return; - } + if((slot < 5) || (slot > 7)) { + fatal_printf("Invalid slot for inserting disk: %d\n", slot); + return; + } + if(drive < 0 || ((slot == 7) && (drive >= MAX_C7_DISKS)) || + ((slot < 7) && (drive > 1))) { + fatal_printf("Invalid drive for inserting disk: %d\n", drive); + return; + } - dsk = cfg_get_dsk_from_slot_drive(slot, drive); + dsk = cfg_get_dsk_from_slot_drive(slot, drive); #if 0 - printf("Inserting disk %s (%s or %d) in slot %d, drive: %d\n", name, - partition_name, part_num, slot, drive); + printf("Inserting disk %s (%s or %d) in slot %d, drive: %d\n", name, + partition_name, part_num, slot, drive); #endif - dsk->just_ejected = 0; - dsk->force_size = force_size; + dsk->just_ejected = 0; + dsk->force_size = force_size; - if(!dsk->file) { - eject_disk(dsk); - } + if(!dsk->file) { + eject_disk(dsk); + } - /* Before opening, make sure no other mounted disk has this name */ - /* If so, unmount it */ - if(!ejected) { - for(i = 0; i < 2; i++) { - eject_named_disk(&iwm.drive525[i], name,partition_name); - eject_named_disk(&iwm.drive35[i], name, partition_name); - } - for(i = 0; i < MAX_C7_DISKS; i++) { - eject_named_disk(&iwm.smartport[i],name,partition_name); - } - } + /* Before opening, make sure no other mounted disk has this name */ + /* If so, unmount it */ + if(!ejected) { + for(i = 0; i < 2; i++) { + eject_named_disk(&iwm.drive525[i], name,partition_name); + eject_named_disk(&iwm.drive35[i], name, partition_name); + } + for(i = 0; i < MAX_C7_DISKS; i++) { + eject_named_disk(&iwm.smartport[i],name,partition_name); + } + } - if(dsk->name_ptr != 0) { - /* free old name_ptr */ - free(dsk->name_ptr); - } + if(dsk->name_ptr != 0) { + /* free old name_ptr */ + free(dsk->name_ptr); + } - name_len = strlen(name); - name_ptr = (char *)malloc(name_len + 1); + name_len = strlen(name); + name_ptr = (char *)malloc(name_len + 1); #if defined(_WIN32) || defined(__CYGWIN__) - // On Windows, we need to change backslashes to forward slashes. - for (i = 0; i < name_len; i++) { - if (name[i] == '\\') { - name_ptr[i] = '/'; - } else { - name_ptr[i] = name[i]; - } - } - name_ptr[name_len] = 0; + // On Windows, we need to change backslashes to forward slashes. + for (i = 0; i < name_len; i++) { + if (name[i] == '\\') { + name_ptr[i] = '/'; + } else { + name_ptr[i] = name[i]; + } + } + name_ptr[name_len] = 0; #else - strncpy(name_ptr, name, name_len + 1); + strncpy(name_ptr, name, name_len + 1); #endif - dsk->name_ptr = name_ptr; + dsk->name_ptr = name_ptr; - dsk->partition_name = 0; - if(partition_name != 0) { - part_len = strlen(partition_name) + 1; - part_ptr = (char *)malloc(part_len); - strncpy(part_ptr, partition_name, part_len); - dsk->partition_name = part_ptr; - } - dsk->partition_num = part_num; + dsk->partition_name = 0; + if(partition_name != 0) { + part_len = strlen(partition_name) + 1; + part_ptr = (char *)malloc(part_len); + strncpy(part_ptr, partition_name, part_len); + dsk->partition_name = part_ptr; + } + dsk->partition_num = part_num; - iwm_printf("Opening up disk image named: %s\n", name_ptr); + iwm_printf("Opening up disk image named: %s\n", name_ptr); - if(ejected) { - /* just get out of here */ - dsk->file = 0; - return; - } + if(ejected) { + /* just get out of here */ + dsk->file = 0; + return; + } - dsk->file = 0; - can_write = 1; + dsk->file = 0; + can_write = 1; - if((name_len > 3) && (strcmp(&name_ptr[name_len - 3], ".gz") == 0)) { + if((name_len > 3) && (strcmp(&name_ptr[name_len - 3], ".gz") == 0)) { - /* it's gzip'ed, try to gunzip it, then unlink the */ - /* uncompressed file */ + /* it's gzip'ed, try to gunzip it, then unlink the */ + /* uncompressed file */ - can_write = 0; + can_write = 0; - uncomp_ptr = (char *)malloc(name_len + 1); - strncpy(uncomp_ptr, name_ptr, name_len + 1); - uncomp_ptr[name_len - 3] = 0; + uncomp_ptr = (char *)malloc(name_len + 1); + strncpy(uncomp_ptr, name_ptr, name_len + 1); + uncomp_ptr[name_len - 3] = 0; - system_len = 2*name_len + 100; - system_str = (char *)malloc(system_len + 1); - snprintf(system_str, system_len, - "set -o noclobber;gunzip -c %c%s%c > %c%s%c", - 0x22, name_ptr, 0x22, - 0x22, uncomp_ptr, 0x22); - /* 0x22 are " to allow spaces in filenames */ - printf("I am uncompressing %s into %s for mounting\n", - name_ptr, uncomp_ptr); - ret = system(system_str); - if(ret == 0) { - /* successfully ran */ - dsk->file = fopen(uncomp_ptr, "rb"); - iwm_printf("Opening .gz file %s\n", uncomp_ptr); + system_len = 2*name_len + 100; + system_str = (char *)malloc(system_len + 1); + snprintf(system_str, system_len, + "set -o noclobber;gunzip -c %c%s%c > %c%s%c", + 0x22, name_ptr, 0x22, + 0x22, uncomp_ptr, 0x22); + /* 0x22 are " to allow spaces in filenames */ + printf("I am uncompressing %s into %s for mounting\n", + name_ptr, uncomp_ptr); + ret = system(system_str); + if(ret == 0) { + /* successfully ran */ + dsk->file = fopen(uncomp_ptr, "rb"); + iwm_printf("Opening .gz file %s\n", uncomp_ptr); - /* and, unlink the temporary file */ - (void)unlink(uncomp_ptr); - } - free(system_str); - free(uncomp_ptr); - /* Reduce name_len by 3 so that subsequent compares for .po */ - /* look at the correct chars */ - name_len -= 3; - } + /* and, unlink the temporary file */ + (void)unlink(uncomp_ptr); + } + free(system_str); + free(uncomp_ptr); + /* Reduce name_len by 3 so that subsequent compares for .po */ + /* look at the correct chars */ + name_len -= 3; + } - if((!dsk->file) && can_write) { - dsk->file = fopen(name_ptr, "rb+"); - } + if((!dsk->file) && can_write) { + dsk->file = fopen(name_ptr, "rb+"); + } - if((!dsk->file) && can_write) { - printf("Trying to open %s read-only, errno: %d\n", name_ptr, - errno); - dsk->file = fopen(name_ptr, "rb"); - can_write = 0; - } + if((!dsk->file) && can_write) { + printf("Trying to open %s read-only, errno: %d\n", name_ptr, + errno); + dsk->file = fopen(name_ptr, "rb"); + can_write = 0; + } - if(!dsk->file) { - fatal_printf("Disk image %s does not exist!\n", name_ptr); - return; - } + if(!dsk->file) { + fatal_printf("Disk image %s does not exist!\n", name_ptr); + return; + } - if(can_write != 0) { - dsk->write_prot = 0; - dsk->write_through_to_unix = 1; - } else { - dsk->write_prot = 1; - dsk->write_through_to_unix = 0; - } + if(can_write != 0) { + dsk->write_prot = 0; + dsk->write_through_to_unix = 1; + } else { + dsk->write_prot = 1; + dsk->write_through_to_unix = 0; + } - save_track = dsk->cur_qtr_track; /* save arm position */ - dsk->image_type = DSK_TYPE_PRODOS; - dsk->image_start = 0; + save_track = dsk->cur_qtr_track; /* save arm position */ + dsk->image_type = DSK_TYPE_PRODOS; + dsk->image_start = 0; - /* See if it is in 2IMG format */ - ret = fread((char *)&buf_2img[0], 1, 512, dsk->file); - size = force_size; - if(size <= 0) { - size = cfg_get_fd_size(name_ptr); - } + /* See if it is in 2IMG format */ + ret = fread((char *)&buf_2img[0], 1, 512, dsk->file); + size = force_size; + if(size <= 0) { + size = cfg_get_fd_size(name_ptr); + } - /* Try to guess that there is a Mac Binary header of 128 bytes */ - /* See if image size & 0xfff = 0x080 which indicates extra 128 bytes */ - if((size & 0xfff) == 0x080) { - printf("Assuming Mac Binary header on %s\n", dsk->name_ptr); - dsk->image_start += 0x80; - } - image_identified = 0; - if(buf_2img[0] == '2' && buf_2img[1] == 'I' && buf_2img[2] == 'M' && - buf_2img[3] == 'G') { - /* It's a 2IMG disk */ - printf("Image named %s is in 2IMG format\n", dsk->name_ptr); - image_identified = 1; + /* Try to guess that there is a Mac Binary header of 128 bytes */ + /* See if image size & 0xfff = 0x080 which indicates extra 128 bytes */ + if((size & 0xfff) == 0x080) { + printf("Assuming Mac Binary header on %s\n", dsk->name_ptr); + dsk->image_start += 0x80; + } + image_identified = 0; + if(buf_2img[0] == '2' && buf_2img[1] == 'I' && buf_2img[2] == 'M' && + buf_2img[3] == 'G') { + /* It's a 2IMG disk */ + glogf("Image named %s is in 2IMG format", dsk->name_ptr); + image_identified = 1; - if(buf_2img[12] == 0) { - printf("2IMG is in DOS 3.3 sector order\n"); - dsk->image_type = DSK_TYPE_DOS33; - } - if(buf_2img[19] & 0x80) { - /* disk is locked */ - printf("2IMG is write protected\n"); - dsk->write_prot = 1; - dsk->write_through_to_unix = 0; - } - if((buf_2img[17] & 1) && (dsk->image_type == DSK_TYPE_DOS33)) { - dsk->vol_num = buf_2img[16]; - printf("Setting DOS 3.3 vol num to %d\n", dsk->vol_num); - } - // Some 2IMG archives have the size byte reversed - size = (buf_2img[31] << 24) + (buf_2img[30] << 16) + - (buf_2img[29] << 8) + buf_2img[28]; - unix_pos = (buf_2img[27] << 24) + (buf_2img[26] << 16) + - (buf_2img[25] << 8) + buf_2img[24]; - if(size == 0x800c00) { - // Byte reversed 0x0c8000 - size = 0x0c8000; - } - dsk->image_start = unix_pos; - dsk->image_size = size; - } - exp_size = 800*1024; - if(dsk->disk_525) { - exp_size = 140*1024; - } - if(!image_identified) { - /* See if it might be the Mac diskcopy format */ - tmp = (buf_2img[0x40] << 24) + (buf_2img[0x41] << 16) + - (buf_2img[0x42] << 8) + buf_2img[0x43]; - if((size >= (exp_size + 0x54)) && (tmp == exp_size)) { - /* It's diskcopy since data size field matches */ - printf("Image named %s is in Mac diskcopy format\n", - dsk->name_ptr); - image_identified = 1; - dsk->image_start += 0x54; - dsk->image_size = exp_size; - dsk->image_type = DSK_TYPE_PRODOS; /* ProDOS */ - } - } - if(!image_identified) { - /* Assume raw image */ - dsk->image_size = size; - dsk->image_type = DSK_TYPE_PRODOS; - if(dsk->disk_525) { - dsk->image_type = DSK_TYPE_DOS33; - if(name_len >= 4) { - cmp_o = dsk->name_ptr[name_len-1]; - cmp_p = dsk->name_ptr[name_len-2]; - cmp_dot = dsk->name_ptr[name_len-3]; - if(cmp_dot == '.' && - (cmp_p == 'p' || cmp_p == 'P') && - (cmp_o == 'o' || cmp_o == 'O')) { - dsk->image_type = DSK_TYPE_PRODOS; - } + if(buf_2img[12] == 0) { + glog("2IMG is in DOS 3.3 sector order"); + dsk->image_type = DSK_TYPE_DOS33; + } + if(buf_2img[19] & 0x80) { + /* disk is locked */ + glog("2IMG is write protected"); + dsk->write_prot = 1; + dsk->write_through_to_unix = 0; + } + if((buf_2img[17] & 1) && (dsk->image_type == DSK_TYPE_DOS33)) { + dsk->vol_num = buf_2img[16]; + glogf("Setting DOS 3.3 vol num to %d", dsk->vol_num); + } + // Some 2IMG archives have the size byte reversed + size = (buf_2img[31] << 24) + (buf_2img[30] << 16) + + (buf_2img[29] << 8) + buf_2img[28]; + unix_pos = (buf_2img[27] << 24) + (buf_2img[26] << 16) + + (buf_2img[25] << 8) + buf_2img[24]; + if(size == 0x800c00) { + // Byte reversed 0x0c8000 + size = 0x0c8000; + } + dsk->image_start = unix_pos; + dsk->image_size = size; + } + exp_size = 800*1024; + if(dsk->disk_525) { + exp_size = 140*1024; + } + if(!image_identified) { + /* See if it might be the Mac diskcopy format */ + tmp = (buf_2img[0x40] << 24) + (buf_2img[0x41] << 16) + + (buf_2img[0x42] << 8) + buf_2img[0x43]; + if((size >= (exp_size + 0x54)) && (tmp == exp_size)) { + /* It's diskcopy since data size field matches */ + glogf("Image named %s is in Mac diskcopy format", dsk->name_ptr); + image_identified = 1; + dsk->image_start += 0x54; + dsk->image_size = exp_size; + dsk->image_type = DSK_TYPE_PRODOS; /* ProDOS */ + } + } + if(!image_identified) { + /* Assume raw image */ + dsk->image_size = size; + dsk->image_type = DSK_TYPE_PRODOS; + if(dsk->disk_525) { + dsk->image_type = DSK_TYPE_DOS33; + if(name_len >= 4) { + cmp_o = dsk->name_ptr[name_len-1]; + cmp_p = dsk->name_ptr[name_len-2]; + cmp_dot = dsk->name_ptr[name_len-3]; + if(cmp_dot == '.' && + (cmp_p == 'p' || cmp_p == 'P') && + (cmp_o == 'o' || cmp_o == 'O')) { + dsk->image_type = DSK_TYPE_PRODOS; + } - cmp_b = dsk->name_ptr[name_len-1]; - cmp_i = dsk->name_ptr[name_len-2]; - cmp_n = dsk->name_ptr[name_len-3]; - cmp_dot = dsk->name_ptr[name_len-4]; - if(cmp_dot == '.' && - (cmp_n == 'n' || cmp_n == 'N') && - (cmp_i == 'i' || cmp_i == 'I') && - (cmp_b == 'b' || cmp_b == 'B')) { - dsk->image_type = DSK_TYPE_NIB; - dsk->write_prot = 1; - dsk->write_through_to_unix = 0; - } - } - } - } + cmp_b = dsk->name_ptr[name_len-1]; + cmp_i = dsk->name_ptr[name_len-2]; + cmp_n = dsk->name_ptr[name_len-3]; + cmp_dot = dsk->name_ptr[name_len-4]; + if(cmp_dot == '.' && + (cmp_n == 'n' || cmp_n == 'N') && + (cmp_i == 'i' || cmp_i == 'I') && + (cmp_b == 'b' || cmp_b == 'B')) { + dsk->image_type = DSK_TYPE_NIB; + dsk->write_prot = 1; + dsk->write_through_to_unix = 0; + } + } + } + } - dsk->disk_dirty = 0; - dsk->nib_pos = 0; - dsk->trks = 0; + dsk->disk_dirty = 0; + dsk->nib_pos = 0; + dsk->trks = 0; - if(dsk->smartport) { - g_highest_smartport_unit = MAX(dsk->drive, - g_highest_smartport_unit); + if(dsk->smartport) { + g_highest_smartport_unit = MAX(dsk->drive, + g_highest_smartport_unit); - if(partition_name != 0 || part_num >= 0) { - ret = cfg_partition_find_by_name_or_num(dsk->file, - partition_name, part_num, dsk); - printf("partition %s (num %d) mounted, wr_prot: %d\n", - partition_name, part_num, dsk->write_prot); + if(partition_name != 0 || part_num >= 0) { + ret = cfg_partition_find_by_name_or_num(dsk->file, + partition_name, part_num, dsk); + printf("partition %s (num %d) mounted, wr_prot: %d\n", + partition_name, part_num, dsk->write_prot); - if(ret < 0) { - fclose(dsk->file); - dsk->file = 0; - return; - } - } - iwm_printf("adding smartport device[%d], size:%08x, " - "img_sz:%08x\n", dsk->drive, dsk->trks[0].unix_len, - dsk->image_size); - } else if(dsk->disk_525) { - unix_pos = dsk->image_start; - size = dsk->image_size; - disk_set_num_tracks(dsk, 4*35); - len = 0x1000; - nibs = NIB_LEN_525; - if(dsk->image_type == DSK_TYPE_NIB) { - len = dsk->image_size / 35;; - nibs = len; - } - if(size != 35*len) { - fatal_printf("Disk 5.25 error: size is %d, not 140K. " - "Will try to mount anyway\n", size, 35*len); - } - for(i = 0; i < 35; i++) { - iwm_move_to_track(dsk, 4*i); - disk_unix_to_nib(dsk, 4*i, unix_pos, len, nibs); - unix_pos += len; - } - } else { - /* disk_35 */ - unix_pos = dsk->image_start; - size = dsk->image_size; - if(size != 800*1024) { - fatal_printf("Disk 3.5 error: size is %d, not 800K. " - "Will try to mount anyway\n", size); - } - disk_set_num_tracks(dsk, 2*80); - for(i = 0; i < 2*80; i++) { - iwm_move_to_track(dsk, i); - len = g_track_bytes_35[i >> 5]; - nibs = g_track_nibs_35[i >> 5]; - iwm_printf("Trk: %d.%d = unix: %08x, %04x, %04x\n", - i>>1, i & 1, unix_pos, len, nibs); - disk_unix_to_nib(dsk, i, unix_pos, len, nibs); - unix_pos += len; + if(ret < 0) { + fclose(dsk->file); + dsk->file = 0; + return; + } + } + iwm_printf("adding smartport device[%d], size:%08x, " + "img_sz:%08x\n", dsk->drive, dsk->trks[0].unix_len, + dsk->image_size); + } else if(dsk->disk_525) { + unix_pos = dsk->image_start; + size = dsk->image_size; + disk_set_num_tracks(dsk, 4*35); + len = 0x1000; + nibs = NIB_LEN_525; + if(dsk->image_type == DSK_TYPE_NIB) { + len = dsk->image_size / 35;; + nibs = len; + } + if(size != 35*len) { + glogf("Warning - Disk 5.25 error: size is %d, not 140K. Will try to mount anyway", size, 35*len); + } + for(i = 0; i < 35; i++) { + iwm_move_to_track(dsk, 4*i); + disk_unix_to_nib(dsk, 4*i, unix_pos, len, nibs); + unix_pos += len; + } + } else { + /* disk_35 */ + unix_pos = dsk->image_start; + size = dsk->image_size; + if(size != 800*1024) { + glogf("Warning - Disk 3.5 error: size is %d, not 800K. Will try to mount anyway", size, 35*len); + } + disk_set_num_tracks(dsk, 2*80); + for(i = 0; i < 2*80; i++) { + iwm_move_to_track(dsk, i); + len = g_track_bytes_35[i >> 5]; + nibs = g_track_nibs_35[i >> 5]; + iwm_printf("Trk: %d.%d = unix: %08x, %04x, %04x\n", + i>>1, i & 1, unix_pos, len, nibs); + disk_unix_to_nib(dsk, i, unix_pos, len, nibs); + unix_pos += len; - iwm_printf(" trk_len:%05x\n", dsk->trks[i].track_len); - } - } + iwm_printf(" trk_len:%05x\n", dsk->trks[i].track_len); + } + } - iwm_move_to_track(dsk, save_track); + iwm_move_to_track(dsk, save_track); } -void -eject_named_disk(Disk *dsk, const char *name, const char *partition_name) -{ +void eject_named_disk(Disk *dsk, const char *name, const char *partition_name) { - if(!dsk->file) { - return; - } + if(!dsk->file) { + return; + } - /* If name matches, eject the disk! */ - if(!strcmp(dsk->name_ptr, name)) { - /* It matches, eject it */ - if((partition_name != 0) && (dsk->partition_name != 0)) { - /* If both have partitions, and they differ, then */ - /* don't eject. Otherwise, eject */ - if(strcmp(dsk->partition_name, partition_name) != 0) { - /* Don't eject */ - return; - } - } - eject_disk(dsk); - } + /* If name matches, eject the disk! */ + if(!strcmp(dsk->name_ptr, name)) { + /* It matches, eject it */ + if((partition_name != 0) && (dsk->partition_name != 0)) { + /* If both have partitions, and they differ, then */ + /* don't eject. Otherwise, eject */ + if(strcmp(dsk->partition_name, partition_name) != 0) { + /* Don't eject */ + return; + } + } + eject_disk(dsk); + } } -void -eject_disk_by_num(int slot, int drive) -{ - Disk *dsk; +void eject_disk_by_num(int slot, int drive) { + Disk *dsk; - dsk = cfg_get_dsk_from_slot_drive(slot, drive); + dsk = cfg_get_dsk_from_slot_drive(slot, drive); - eject_disk(dsk); + eject_disk(dsk); } -void -eject_disk(Disk *dsk) -{ - int motor_on; - int i; +void eject_disk(Disk *dsk) { + int motor_on; + int i; - if(!dsk->file) { - return; - } + if(!dsk->file) { + return; + } - g_config_gsport_update_needed = 1; + g_config_gsport_update_needed = 1; - motor_on = iwm.motor_on; - if(g_c031_disk35 & 0x40) { - motor_on = iwm.motor_on35; - } - if(motor_on) { - halt_printf("Try eject dsk:%s, but motor_on!\n", dsk->name_ptr); - } + motor_on = iwm.motor_on; + if(g_c031_disk35 & 0x40) { + motor_on = iwm.motor_on35; + } + if(motor_on) { + halt_printf("Try eject dsk:%s, but motor_on!\n", dsk->name_ptr); + } - iwm_flush_disk_to_unix(dsk); + iwm_flush_disk_to_unix(dsk); - printf("Ejecting disk: %s\n", dsk->name_ptr); + glogf("Ejecting disk: %s", dsk->name_ptr); - /* Free all memory, close file */ + /* Free all memory, close file */ - /* free the tracks first */ - if(dsk->trks != 0) { - for(i = 0; i < dsk->num_tracks; i++) { - if(dsk->trks[i].nib_area) { - free(dsk->trks[i].nib_area); - } - dsk->trks[i].nib_area = 0; - dsk->trks[i].track_len = 0; - } - free(dsk->trks); - } - dsk->num_tracks = 0; - dsk->trks = 0; + /* free the tracks first */ + if(dsk->trks != 0) { + for(i = 0; i < dsk->num_tracks; i++) { + if(dsk->trks[i].nib_area) { + free(dsk->trks[i].nib_area); + } + dsk->trks[i].nib_area = 0; + dsk->trks[i].track_len = 0; + } + free(dsk->trks); + } + dsk->num_tracks = 0; + dsk->trks = 0; - /* close file, clean up dsk struct */ - fclose(dsk->file); + /* close file, clean up dsk struct */ + fclose(dsk->file); - dsk->image_start = 0; - dsk->image_size = 0; - dsk->nib_pos = 0; - dsk->disk_dirty = 0; - dsk->write_through_to_unix = 0; - dsk->write_prot = 1; - dsk->file = 0; - dsk->just_ejected = 1; + dsk->image_start = 0; + dsk->image_size = 0; + dsk->nib_pos = 0; + dsk->disk_dirty = 0; + dsk->write_through_to_unix = 0; + dsk->write_prot = 1; + dsk->file = 0; + dsk->just_ejected = 1; - /* Leave name_ptr valid */ + /* Leave name_ptr valid */ } -int -cfg_get_fd_size(char *filename) -{ - struct stat stat_buf; - int ret; +int cfg_get_fd_size(char *filename) { + struct stat stat_buf; + int ret; - ret = stat(filename, &stat_buf); - if(ret != 0) { - fprintf(stderr,"stat %s returned errno: %d\n", - filename, errno); - stat_buf.st_size = 0; - } + ret = stat(filename, &stat_buf); + if(ret != 0) { + fprintf(stderr,"stat %s returned errno: %d\n", + filename, errno); + stat_buf.st_size = 0; + } - return stat_buf.st_size; + return stat_buf.st_size; } -int -cfg_partition_read_block(FILE *file, void *buf, int blk, int blk_size) -{ - int ret; +int cfg_partition_read_block(FILE *file, void *buf, int blk, int blk_size) { + int ret; - ret = fseek(file, blk * blk_size, SEEK_SET); - if(ret != 0) { - printf("fseek: wanted: %08x, errno: %d\n", - blk * blk_size, errno); - return 0; - } + ret = fseek(file, blk * blk_size, SEEK_SET); + if(ret != 0) { + printf("fseek: wanted: %08x, errno: %d\n", + blk * blk_size, errno); + return 0; + } - ret = fread((char *)buf, 1, blk_size, file); - if(ret != blk_size) { - printf("ret: %08x, wanted %08x, errno: %d\n", ret, blk_size, - errno); - return 0; - } - return ret; + ret = fread((char *)buf, 1, blk_size, file); + if(ret != blk_size) { + printf("ret: %08x, wanted %08x, errno: %d\n", ret, blk_size, + errno); + return 0; + } + return ret; } -int -cfg_partition_find_by_name_or_num(FILE *file, const char *partnamestr, int part_num, - Disk *dsk) -{ - Cfg_dirent *direntptr; - int match; - int num_parts; - int i; +int cfg_partition_find_by_name_or_num(FILE *file, const char *partnamestr, int part_num, + Disk *dsk) { + Cfg_dirent *direntptr; + int match; + int num_parts; + int i; - num_parts = cfg_partition_make_list(dsk->name_ptr, file); + num_parts = cfg_partition_make_list(dsk->name_ptr, file); - if(num_parts <= 0) { - return -1; - } + if(num_parts <= 0) { + return -1; + } - for(i = 0; i < g_cfg_partitionlist.last; i++) { - direntptr = &(g_cfg_partitionlist.direntptr[i]); - match = 0; - if((strncmp(partnamestr, direntptr->name, 32) == 0) && - (part_num < 0)) { - //printf("partition, match1, name:%s %s, part_num:%d\n", - // partnamestr, direntptr->name, part_num); + for(i = 0; i < g_cfg_partitionlist.last; i++) { + direntptr = &(g_cfg_partitionlist.direntptr[i]); + match = 0; + if((strncmp(partnamestr, direntptr->name, 32) == 0) && + (part_num < 0)) { + //printf("partition, match1, name:%s %s, part_num:%d\n", + // partnamestr, direntptr->name, part_num); - match = 1; - } - if((partnamestr == 0) && (direntptr->part_num == part_num)) { - //printf("partition, match2, n:%s, part_num:%d == %d\n", - // direntptr->name, direntptr->part_num, part_num); - match = 1; - } - if(match) { - dsk->image_start = direntptr->image_start; - dsk->image_size = direntptr->size; - //printf("match with image_start: %08x, image_size: " - // "%08x\n", dsk->image_start, dsk->image_size); + match = 1; + } + if((partnamestr == 0) && (direntptr->part_num == part_num)) { + //printf("partition, match2, n:%s, part_num:%d == %d\n", + // direntptr->name, direntptr->part_num, part_num); + match = 1; + } + if(match) { + dsk->image_start = direntptr->image_start; + dsk->image_size = direntptr->size; + //printf("match with image_start: %08x, image_size: " + // "%08x\n", dsk->image_start, dsk->image_size); - return i; - } - } + return i; + } + } - return -1; + return -1; } -int -cfg_partition_make_list(char *filename, FILE *file) -{ - Driver_desc *driver_desc_ptr; - Part_map *part_map_ptr; - word32 *blk_bufptr; - word32 start; - word32 len; - word32 data_off; - word32 data_len; - word32 sig; - int size; - int image_start, image_size; - int is_dir; - int block_size; - int map_blks; - int cur_blk; +int cfg_partition_make_list(char *filename, FILE *file) { + Driver_desc *driver_desc_ptr; + Part_map *part_map_ptr; + word32 *blk_bufptr; + word32 start; + word32 len; + word32 data_off; + word32 data_len; + word32 sig; + int size; + int image_start, image_size; + int is_dir; + int block_size; + int map_blks; + int cur_blk; - block_size = 512; + block_size = 512; - cfg_free_alldirents(&g_cfg_partitionlist); + cfg_free_alldirents(&g_cfg_partitionlist); - blk_bufptr = (word32 *)malloc(MAX_PARTITION_BLK_SIZE); + blk_bufptr = (word32 *)malloc(MAX_PARTITION_BLK_SIZE); - cfg_partition_read_block(file, blk_bufptr, 0, block_size); + cfg_partition_read_block(file, blk_bufptr, 0, block_size); - driver_desc_ptr = (Driver_desc *)blk_bufptr; - sig = GET_BE_WORD16(driver_desc_ptr->sig); - block_size = GET_BE_WORD16(driver_desc_ptr->blk_size); - if(block_size == 0) { - block_size = 512; - } - if(sig != 0x4552 || block_size < 0x200 || - (block_size > MAX_PARTITION_BLK_SIZE)) { - cfg_printf("Partition error: No driver descriptor map found\n"); - free(blk_bufptr); - return 0; - } + driver_desc_ptr = (Driver_desc *)blk_bufptr; + sig = GET_BE_WORD16(driver_desc_ptr->sig); + block_size = GET_BE_WORD16(driver_desc_ptr->blk_size); + if(block_size == 0) { + block_size = 512; + } + if(sig != 0x4552 || block_size < 0x200 || + (block_size > MAX_PARTITION_BLK_SIZE)) { + cfg_printf("Partition error: No driver descriptor map found\n"); + free(blk_bufptr); + return 0; + } - map_blks = 1; - cur_blk = 0; - size = cfg_get_fd_size(filename); - cfg_file_add_dirent(&g_cfg_partitionlist, "None - Whole image", - is_dir=0, size, 0, -1); + map_blks = 1; + cur_blk = 0; + size = cfg_get_fd_size(filename); + cfg_file_add_dirent(&g_cfg_partitionlist, "None - Whole image", + is_dir=0, size, 0, -1); - while(cur_blk < map_blks) { - cur_blk++; - cfg_partition_read_block(file, blk_bufptr, cur_blk, block_size); - part_map_ptr = (Part_map *)blk_bufptr; - sig = GET_BE_WORD16(part_map_ptr->sig); - if(cur_blk <= 1) { - map_blks = MIN(20, - GET_BE_WORD32(part_map_ptr->map_blk_cnt)); - } - if(sig != 0x504d) { - printf("Partition entry %d bad signature:%04x\n", - cur_blk, sig); - free(blk_bufptr); - return g_cfg_partitionlist.last; - } + while(cur_blk < map_blks) { + cur_blk++; + cfg_partition_read_block(file, blk_bufptr, cur_blk, block_size); + part_map_ptr = (Part_map *)blk_bufptr; + sig = GET_BE_WORD16(part_map_ptr->sig); + if(cur_blk <= 1) { + map_blks = MIN(20, + GET_BE_WORD32(part_map_ptr->map_blk_cnt)); + } + if(sig != 0x504d) { + printf("Partition entry %d bad signature:%04x\n", + cur_blk, sig); + free(blk_bufptr); + return g_cfg_partitionlist.last; + } - /* found it, check for consistency */ - start = GET_BE_WORD32(part_map_ptr->phys_part_start); - len = GET_BE_WORD32(part_map_ptr->part_blk_cnt); - data_off = GET_BE_WORD32(part_map_ptr->data_start); - data_len = GET_BE_WORD32(part_map_ptr->data_cnt); - if(data_off + data_len > len) { - printf("Poorly formed entry\n"); - continue; - } + /* found it, check for consistency */ + start = GET_BE_WORD32(part_map_ptr->phys_part_start); + len = GET_BE_WORD32(part_map_ptr->part_blk_cnt); + data_off = GET_BE_WORD32(part_map_ptr->data_start); + data_len = GET_BE_WORD32(part_map_ptr->data_cnt); + if(data_off + data_len > len) { + printf("Poorly formed entry\n"); + continue; + } - if(data_len < 10 || start < 1) { - printf("Poorly formed entry %d, datalen:%d, " - "start:%08x\n", cur_blk, data_len, start); - continue; - } + if(data_len < 10 || start < 1) { + printf("Poorly formed entry %d, datalen:%d, " + "start:%08x\n", cur_blk, data_len, start); + continue; + } - image_size = data_len * block_size; - image_start = (start + data_off) * block_size; - is_dir = 2*(image_size < 800*1024); + image_size = data_len * block_size; + image_start = (start + data_off) * block_size; + is_dir = 2*(image_size < 800*1024); #if 0 - printf(" partition add entry %d = %s %d %08x %08x\n", - cur_blk, part_map_ptr->part_name, is_dir, - image_size, image_start); + printf(" partition add entry %d = %s %d %08x %08x\n", + cur_blk, part_map_ptr->part_name, is_dir, + image_size, image_start); #endif - cfg_file_add_dirent(&g_cfg_partitionlist, - part_map_ptr->part_name, is_dir, image_size, - image_start, cur_blk); - } + cfg_file_add_dirent(&g_cfg_partitionlist, + part_map_ptr->part_name, is_dir, image_size, + image_start, cur_blk); + } - free(blk_bufptr); - return g_cfg_partitionlist.last; + free(blk_bufptr); + return g_cfg_partitionlist.last; } -int -cfg_maybe_insert_disk(int slot, int drive, const char *namestr) -{ - int num_parts; - FILE *file; +int cfg_maybe_insert_disk(int slot, int drive, const char *namestr) { + int num_parts; + FILE *file; - file = fopen(namestr, "rb"); - if(!file) { - fatal_printf("Cannot open disk image: %s\n", namestr); - return 0; - } + file = fopen(namestr, "rb"); + if(!file) { + fatal_printf("Cannot open disk image: %s\n", namestr); + return 0; + } - num_parts = cfg_partition_make_list((char*)namestr, file); - fclose(file); + num_parts = cfg_partition_make_list((char*)namestr, file); + fclose(file); - if(num_parts > 0) { - printf("Choose a partition\n"); - g_cfg_select_partition = 1; - } else { - insert_disk(slot, drive, namestr, 0, 0, 0, -1); - return 1; - } - return 0; + if(num_parts > 0) { + printf("Choose a partition\n"); + g_cfg_select_partition = 1; + } else { + insert_disk(slot, drive, namestr, 0, 0, 0, -1); + return 1; + } + return 0; } -int -cfg_stat(char *path, struct stat *sb) -{ - int removed_slash; - int len; - int ret; +int cfg_stat(char *path, struct stat *sb) { + int removed_slash; + int len; + int ret; - removed_slash = 0; - len = 0; + removed_slash = 0; + len = 0; #ifdef _WIN32 - /* Windows doesn't like to stat paths ending in a /, so remove it */ - len = strlen(path); - if((len > 1) && (path[len - 1] == '/') ) { - path[len - 1] = 0; /* remove the slash */ - removed_slash = 1; - } + /* Windows doesn't like to stat paths ending in a /, so remove it */ + len = strlen(path); + if((len > 1) && (path[len - 1] == '/') ) { + path[len - 1] = 0; /* remove the slash */ + removed_slash = 1; + } #endif - ret = stat(path, sb); + ret = stat(path, sb); #ifdef _WIN32 - /* put the slash back */ - if(removed_slash) { - path[len - 1] = '/'; - } + /* put the slash back */ + if(removed_slash) { + path[len - 1] = '/'; + } #endif - return ret; + return ret; } -void -cfg_htab_vtab(int x, int y) -{ - if(x > 79) { - x = 0; - } - if(y > 23) { - y = 0; - } - g_cfg_curs_x = x; - g_cfg_curs_y = y; - g_cfg_curs_inv = 0; - g_cfg_curs_mousetext = 0; +void cfg_htab_vtab(int x, int y) { + if(x > 79) { + x = 0; + } + if(y > 23) { + y = 0; + } + g_cfg_curs_x = x; + g_cfg_curs_y = y; + g_cfg_curs_inv = 0; + g_cfg_curs_mousetext = 0; } -void -cfg_home() -{ - int i; +void cfg_home() { + int i; - cfg_htab_vtab(0, 0); - for(i = 0; i < 24; i++) { - cfg_cleol(); - } + cfg_htab_vtab(0, 0); + for(i = 0; i < 24; i++) { + cfg_cleol(); + } } -void -cfg_cleol() -{ - g_cfg_curs_inv = 0; - g_cfg_curs_mousetext = 0; - cfg_putchar(' '); - while(g_cfg_curs_x != 0) { - cfg_putchar(' '); - } +void cfg_cleol() { + g_cfg_curs_inv = 0; + g_cfg_curs_mousetext = 0; + cfg_putchar(' '); + while(g_cfg_curs_x != 0) { + cfg_putchar(' '); + } } -void -cfg_putchar(int c) -{ - int offset; - int x, y; +void cfg_putchar(int c) { + int offset; + int x, y; - if(c == '\n') { - cfg_cleol(); - return; - } - if(c == '\b') { - g_cfg_curs_inv = !g_cfg_curs_inv; - return; - } - if(c == '\t') { - g_cfg_curs_mousetext = !g_cfg_curs_mousetext; - return; - } - y = g_cfg_curs_y; - x = g_cfg_curs_x; + if(c == '\n') { + cfg_cleol(); + return; + } + if(c == '\b') { + g_cfg_curs_inv = !g_cfg_curs_inv; + return; + } + if(c == '\t') { + g_cfg_curs_mousetext = !g_cfg_curs_mousetext; + return; + } + y = g_cfg_curs_y; + x = g_cfg_curs_x; - offset = g_screen_index[g_cfg_curs_y]; - if((x & 1) == 0) { - offset += 0x10000; - } - if(g_cfg_curs_inv) { - if(c >= 0x40 && c < 0x60) { - c = c & 0x1f; - } - } else { - c = c | 0x80; - } - if(g_cfg_curs_mousetext) { - c = (c & 0x1f) | 0x40; - } - set_memory_c(0xe00400 + offset + (x >> 1), c, 0); - x++; - if(x >= 80) { - x = 0; - y++; - if(y >= 24) { - y = 0; - } - } - g_cfg_curs_y = y; - g_cfg_curs_x = x; + offset = g_screen_index[g_cfg_curs_y]; + if((x & 1) == 0) { + offset += 0x10000; + } + if(g_cfg_curs_inv) { + if(c >= 0x40 && c < 0x60) { + c = c & 0x1f; + } + } else { + c = c | 0x80; + } + if(g_cfg_curs_mousetext) { + c = (c & 0x1f) | 0x40; + } + set_memory_c(0xe00400 + offset + (x >> 1), c, 0); + x++; + if(x >= 80) { + x = 0; + y++; + if(y >= 24) { + y = 0; + } + } + g_cfg_curs_y = y; + g_cfg_curs_x = x; } -void -cfg_printf(const char *fmt, ...) -{ - va_list ap; - int c; - int i; +void cfg_printf(const char *fmt, ...) { + va_list ap; + int c; + int i; - va_start(ap, fmt); - (void)vsnprintf(g_cfg_printf_buf, CFG_PRINTF_BUFSIZE, fmt, ap); - va_end(ap); + va_start(ap, fmt); + (void)vsnprintf(g_cfg_printf_buf, CFG_PRINTF_BUFSIZE, fmt, ap); + va_end(ap); - for(i = 0; i < CFG_PRINTF_BUFSIZE; i++) { - c = g_cfg_printf_buf[i]; - if(c == 0) { - return; - } - cfg_putchar(c); - } + for(i = 0; i < CFG_PRINTF_BUFSIZE; i++) { + c = g_cfg_printf_buf[i]; + if(c == 0) { + return; + } + cfg_putchar(c); + } } -void -cfg_print_num(int num, int max_len) -{ - char buf[64]; - char buf2[64]; - int len; - int cnt; - int c; - int i, j; +void cfg_print_num(int num, int max_len) { + char buf[64]; + char buf2[64]; + int len; + int cnt; + int c; + int i, j; - /* Prints right-adjusted "num" in field "max_len" wide */ - snprintf(&buf[0], 64, "%d", num); - len = strlen(buf); - for(i = 0; i < 64; i++) { - buf2[i] = ' '; - } - j = max_len + 1; - buf2[j] = 0; - j--; - cnt = 0; - for(i = len - 1; (i >= 0) && (j >= 1); i--) { - c = buf[i]; - if(c >= '0' && c <= '9') { - if(cnt >= 3) { - buf2[j--] = ','; - cnt = 0; - } - cnt++; - } - buf2[j--] = c; - } - cfg_printf(&buf2[1]); + /* Prints right-adjusted "num" in field "max_len" wide */ + snprintf(&buf[0], 64, "%d", num); + len = strlen(buf); + for(i = 0; i < 64; i++) { + buf2[i] = ' '; + } + j = max_len + 1; + buf2[j] = 0; + j--; + cnt = 0; + for(i = len - 1; (i >= 0) && (j >= 1); i--) { + c = buf[i]; + if(c >= '0' && c <= '9') { + if(cnt >= 3) { + buf2[j--] = ','; + cnt = 0; + } + cnt++; + } + buf2[j--] = c; + } + cfg_printf(&buf2[1]); } -void -cfg_get_disk_name(char *outstr, int maxlen, int type_ext, int with_extras) -{ - Disk *dsk; - int slot, drive; +void cfg_get_disk_name(char *outstr, int maxlen, int type_ext, int with_extras) { + Disk *dsk; + int slot, drive; - slot = type_ext >> 8; - drive = type_ext & 0xff; - dsk = cfg_get_dsk_from_slot_drive(slot, drive); + slot = type_ext >> 8; + drive = type_ext & 0xff; + dsk = cfg_get_dsk_from_slot_drive(slot, drive); - outstr[0] = 0; - if(dsk->name_ptr == 0) { - return; - } + outstr[0] = 0; + if(dsk->name_ptr == 0) { + return; + } - config_generate_config_gsport_name(outstr, maxlen, dsk, with_extras); + config_generate_config_gsport_name(outstr, maxlen, dsk, with_extras); } -void -cfg_parse_menu(Cfg_menu *menuptr, int menu_pos, int highlight_pos, int change) -{ - char valbuf[CFG_OPT_MAXSTR]; - char **str_ptr; - const char *menustr; - char *curstr, *defstr; - char *str; - char *outstr; - int *iptr; - int val; - int num_opts; - int opt_num; - int bufpos, outpos; - int curval, defval; - int type; - int type_ext; - int opt_get_str; - int separator; - int len; - int c; - int i; +void cfg_parse_menu(Cfg_menu *menuptr, int menu_pos, int highlight_pos, int change) { + char valbuf[CFG_OPT_MAXSTR]; + char **str_ptr; + const char *menustr; + char *curstr, *defstr; + char *str; + char *outstr; + int *iptr; + int val; + int num_opts; + int opt_num; + int bufpos, outpos; + int curval, defval; + int type; + int type_ext; + int opt_get_str; + int separator; + int len; + int c; + int i; - g_cfg_opt_buf[0] = 0; + g_cfg_opt_buf[0] = 0; - num_opts = 0; - opt_get_str = 0; - separator = ','; + num_opts = 0; + opt_get_str = 0; + separator = ','; - menuptr += menu_pos; /* move forward to entry menu_pos */ + menuptr += menu_pos; /* move forward to entry menu_pos */ - menustr = menuptr->str; - type = menuptr->cfgtype; - type_ext = (type >> 4); - type = type & 0xf; - len = strlen(menustr) + 1; + menustr = menuptr->str; + type = menuptr->cfgtype; + type_ext = (type >> 4); + type = type & 0xf; + len = strlen(menustr) + 1; - bufpos = 0; - outstr = &(g_cfg_opt_buf[0]); + bufpos = 0; + outstr = &(g_cfg_opt_buf[0]); - outstr[bufpos++] = ' '; - outstr[bufpos++] = ' '; - outstr[bufpos++] = '\t'; - outstr[bufpos++] = '\t'; - outstr[bufpos++] = ' '; - outstr[bufpos++] = ' '; + outstr[bufpos++] = ' '; + outstr[bufpos++] = ' '; + outstr[bufpos++] = '\t'; + outstr[bufpos++] = '\t'; + outstr[bufpos++] = ' '; + outstr[bufpos++] = ' '; - if(menu_pos == highlight_pos) { - outstr[bufpos++] = '\b'; - } + if(menu_pos == highlight_pos) { + outstr[bufpos++] = '\b'; + } - opt_get_str = 2; - i = -1; - outpos = bufpos; + opt_get_str = 2; + i = -1; + outpos = bufpos; #if 0 - printf("cfg menu_pos: %d str len: %d\n", menu_pos, len); + printf("cfg menu_pos: %d str len: %d\n", menu_pos, len); #endif - while(++i < len) { - c = menustr[i]; - if(c == separator) { - if(i == 0) { - continue; - } - c = 0; - } - outstr[outpos++] = c; - outstr[outpos] = 0; - if(outpos >= CFG_OPT_MAXSTR) { - fprintf(stderr, "CFG_OPT_MAXSTR exceeded\n"); - my_exit(1); - } - if(c == 0) { - if(opt_get_str == 2) { - outstr = &(valbuf[0]); - bufpos = outpos - 1; - opt_get_str = 0; - } else if(opt_get_str) { + while(++i < len) { + c = menustr[i]; + if(c == separator) { + if(i == 0) { + continue; + } + c = 0; + } + outstr[outpos++] = c; + outstr[outpos] = 0; + if(outpos >= CFG_OPT_MAXSTR) { + fprintf(stderr, "CFG_OPT_MAXSTR exceeded\n"); + my_exit(1); + } + if(c == 0) { + if(opt_get_str == 2) { + outstr = &(valbuf[0]); + bufpos = outpos - 1; + opt_get_str = 0; + } else if(opt_get_str) { #if 0 - if(menu_pos == highlight_pos) { - printf("menu_pos %d opt %d = %s=%d\n", - menu_pos, num_opts, - g_cfg_opts_strs[num_opts], - g_cfg_opts_vals[num_opts]); - } + if(menu_pos == highlight_pos) { + printf("menu_pos %d opt %d = %s=%d\n", + menu_pos, num_opts, + g_cfg_opts_strs[num_opts], + g_cfg_opts_vals[num_opts]); + } #endif - num_opts++; - outstr = &(valbuf[0]); - opt_get_str = 0; - if(num_opts >= CFG_MAX_OPTS) { - fprintf(stderr, "CFG_MAX_OPTS oflow\n"); - my_exit(1); - } - } else { - if (type == CFGTYPE_INT) - { - val = strtoul(valbuf, 0, 0); - g_cfg_opts_vals[num_opts] = val; - } + num_opts++; + outstr = &(valbuf[0]); + opt_get_str = 0; + if(num_opts >= CFG_MAX_OPTS) { + fprintf(stderr, "CFG_MAX_OPTS oflow\n"); + my_exit(1); + } + } else { + if (type == CFGTYPE_INT) + { + val = strtoul(valbuf, 0, 0); + g_cfg_opts_vals[num_opts] = val; + } - if (type == CFGTYPE_STR) - { - strncpy(&(g_cfg_opts_strvals[num_opts][0]),&(valbuf[0]),CFG_OPT_MAXSTR); - } - outstr = &(g_cfg_opts_strs[num_opts][0]); - opt_get_str = 1; - } - outpos = 0; - outstr[0] = 0; - } - } + if (type == CFGTYPE_STR) + { + strncpy(&(g_cfg_opts_strvals[num_opts][0]),&(valbuf[0]),CFG_OPT_MAXSTR); + } + outstr = &(g_cfg_opts_strs[num_opts][0]); + opt_get_str = 1; + } + outpos = 0; + outstr[0] = 0; + } + } - if(menu_pos == highlight_pos) { - g_cfg_opt_buf[bufpos++] = '\b'; - } + if(menu_pos == highlight_pos) { + g_cfg_opt_buf[bufpos++] = '\b'; + } - g_cfg_opt_buf[bufpos] = 0; + g_cfg_opt_buf[bufpos] = 0; - // Figure out if we should get a checkmark - curval = -1; - defval = -1; - curstr = 0; - if(type == CFGTYPE_INT) { - iptr = (int*)menuptr->ptr; // OG Added cast - curval = *iptr; - iptr = (int*)menuptr->defptr; // OG Added cast - defval = *iptr; - if(curval == defval) { - g_cfg_opt_buf[3] = 'D'; /* checkmark */ - g_cfg_opt_buf[4] = '\t'; - } - } - if(type == CFGTYPE_STR) { - str_ptr = (char **)menuptr->ptr; - curstr = *str_ptr; - str_ptr = (char **)menuptr->defptr; - defstr = *str_ptr; - if(strcmp(curstr,defstr) == 0) { - g_cfg_opt_buf[3] = 'D'; /* checkmark */ - g_cfg_opt_buf[4] = '\t'; - } - } - if(type == CFGTYPE_FILE) { - str_ptr = (char **)menuptr->ptr; - curstr = *str_ptr; - str_ptr = (char **)menuptr->defptr; - defstr = *str_ptr; - if(strcmp(curstr,defstr) == 0) { - g_cfg_opt_buf[3] = 'D'; /* checkmark */ - g_cfg_opt_buf[4] = '\t'; - } - } + // Figure out if we should get a checkmark + curval = -1; + defval = -1; + curstr = 0; - // If it's a menu, give it a special menu indicator - if(type == CFGTYPE_MENU) { - g_cfg_opt_buf[1] = '\t'; - g_cfg_opt_buf[2] = 'M'; /* return-like symbol */ - g_cfg_opt_buf[3] = '\t'; - g_cfg_opt_buf[4] = ' '; - } + switch(type) { - // Decide what to display on the "right" side - str = 0; - opt_num = -1; - if(type == CFGTYPE_INT || type == CFGTYPE_FILE) { - g_cfg_opt_buf[bufpos++] = ' '; - g_cfg_opt_buf[bufpos++] = '='; - g_cfg_opt_buf[bufpos++] = ' '; - g_cfg_opt_buf[bufpos] = 0; - for(i = 0; i < num_opts; i++) { - if(curval == g_cfg_opts_vals[i]) { - opt_num = i; - break; - } - } - } - if(type == CFGTYPE_STR) { - g_cfg_opt_buf[bufpos++] = ' '; - g_cfg_opt_buf[bufpos++] = '='; - g_cfg_opt_buf[bufpos++] = ' '; - g_cfg_opt_buf[bufpos] = 0; - for(i = 0; i < num_opts; i++) { - if(!strcmp(curstr,g_cfg_opts_strvals[i])) { - opt_num = i; - break; - } - } - } + case CFGTYPE_INT: + iptr = (int*)menuptr->ptr; // OG Added cast + curval = *iptr; + iptr = (int*)menuptr->defptr; // OG Added cast + defval = *iptr; + if(curval == defval) { + g_cfg_opt_buf[3] = 'D'; /* checkmark */ + g_cfg_opt_buf[4] = '\t'; + } + break; + case CFGTYPE_STR: + case CFGTYPE_FILE: + case CFGTYPE_DIR: + str_ptr = (char **)menuptr->ptr; + curstr = *str_ptr; + str_ptr = (char **)menuptr->defptr; + defstr = *str_ptr; + if(strcmp(curstr,defstr) == 0) { + g_cfg_opt_buf[3] = 'D'; /* checkmark */ + g_cfg_opt_buf[4] = '\t'; + } + break; - if(change != 0) { - if(type == CFGTYPE_INT) { - if(num_opts > 0) { - opt_num += change; - if(opt_num >= num_opts) { - opt_num = 0; - } - if(opt_num < 0) { - opt_num = num_opts - 1; - } - curval = g_cfg_opts_vals[opt_num]; - } else { - curval += change; - /* HACK: min_val, max_val testing here */ - } - iptr = (int *)menuptr->ptr; - *iptr = curval; - } - if(type == CFGTYPE_STR) { - if(num_opts > 0) { - opt_num += change; - if(opt_num >= num_opts) { - opt_num = 0; - } - if(opt_num < 0) { - opt_num = num_opts - 1; - } - curstr = g_cfg_opts_strvals[opt_num]; - } else { - //curstr += change; - /* HACK: min_val, max_val testing here */ - } - str_ptr = (char **)menuptr->ptr; - *str_ptr = curstr; - } - g_config_gsport_update_needed = 1; - } + + + // If it's a menu, give it a special menu indicator + case CFGTYPE_MENU: + g_cfg_opt_buf[1] = '\t'; + g_cfg_opt_buf[2] = 'M'; /* return-like symbol */ + g_cfg_opt_buf[3] = '\t'; + g_cfg_opt_buf[4] = ' '; + break; + } + + + + // Decide what to display on the "right" side + str = 0; + opt_num = -1; + + switch(type) { + + case CFGTYPE_INT: + case CFGTYPE_FILE: + case CFGTYPE_DIR: + g_cfg_opt_buf[bufpos++] = ' '; + g_cfg_opt_buf[bufpos++] = '='; + g_cfg_opt_buf[bufpos++] = ' '; + g_cfg_opt_buf[bufpos] = 0; + for(i = 0; i < num_opts; i++) { + if(curval == g_cfg_opts_vals[i]) { + opt_num = i; + break; + } + } + break; + + case CFGTYPE_STR: + g_cfg_opt_buf[bufpos++] = ' '; + g_cfg_opt_buf[bufpos++] = '='; + g_cfg_opt_buf[bufpos++] = ' '; + g_cfg_opt_buf[bufpos] = 0; + for(i = 0; i < num_opts; i++) { + if(!strcmp(curstr,g_cfg_opts_strvals[i])) { + opt_num = i; + break; + } + } + break; + } + + if(change != 0) { + if(type == CFGTYPE_INT) { + if(num_opts > 0) { + opt_num += change; + if(opt_num >= num_opts) { + opt_num = 0; + } + if(opt_num < 0) { + opt_num = num_opts - 1; + } + curval = g_cfg_opts_vals[opt_num]; + } else { + curval += change; + /* HACK: min_val, max_val testing here */ + } + iptr = (int *)menuptr->ptr; + *iptr = curval; + } + if(type == CFGTYPE_STR) { + if(num_opts > 0) { + opt_num += change; + if(opt_num >= num_opts) { + opt_num = 0; + } + if(opt_num < 0) { + opt_num = num_opts - 1; + } + curstr = g_cfg_opts_strvals[opt_num]; + } else { + //curstr += change; + /* HACK: min_val, max_val testing here */ + } + str_ptr = (char **)menuptr->ptr; + *str_ptr = curstr; + } + g_config_gsport_update_needed = 1; + } #if 0 - if(menu_pos == highlight_pos) { - printf("menu_pos %d opt_num %d\n", menu_pos, opt_num); - } + if(menu_pos == highlight_pos) { + printf("menu_pos %d opt_num %d\n", menu_pos, opt_num); + } #endif - if(opt_num >= 0) { - str = &(g_cfg_opts_strs[opt_num][0]); - } else { - if(type == CFGTYPE_INT) { - str = &(g_cfg_opts_strs[0][0]); - snprintf(str, CFG_OPT_MAXSTR, "%d", curval); - } else if (type == CFGTYPE_STR) { - str = &(g_cfg_opts_strs[0][0]); - printf("curstr is: %s str is: %s\n", curstr,str); - snprintf(str, CFG_OPT_MAXSTR, "%s", curstr); - } else if (type == CFGTYPE_DISK) { - str = &(g_cfg_opts_strs[0][0]), - cfg_get_disk_name(str, CFG_OPT_MAXSTR, type_ext, 1); - str = cfg_shorten_filename(str, 68); - } else if (type == CFGTYPE_FILE) { - str = &(g_cfg_opts_strs[0][0]); - snprintf(str, CFG_OPT_MAXSTR, "%s", curstr); - str = cfg_shorten_filename(str, 68); - } else { - str = ""; - } - } + if(opt_num >= 0) { + str = &(g_cfg_opts_strs[opt_num][0]); + } else { + switch(type) { + case CFGTYPE_INT: + str = &(g_cfg_opts_strs[0][0]); + snprintf(str, CFG_OPT_MAXSTR, "%d", curval); + break; + case CFGTYPE_STR: + str = &(g_cfg_opts_strs[0][0]); + //printf("curstr is: %s str is: %s\n", curstr,str); + snprintf(str, CFG_OPT_MAXSTR, "%s", curstr); + break; + case CFGTYPE_DISK: + str = &(g_cfg_opts_strs[0][0]), + cfg_get_disk_name(str, CFG_OPT_MAXSTR, type_ext, 1); + str = cfg_shorten_filename(str, 68); + break; + case CFGTYPE_FILE: + case CFGTYPE_DIR: + str = &(g_cfg_opts_strs[0][0]); + snprintf(str, CFG_OPT_MAXSTR, "%s", curstr); + str = cfg_shorten_filename(str, 68); + break; + default: + str = ""; + } + } #if 0 - if(menu_pos == highlight_pos) { - printf("menu_pos %d buf_pos %d, str is %s, %02x, %02x, " - "%02x %02x\n", - menu_pos, bufpos, str, g_cfg_opt_buf[bufpos-1], - g_cfg_opt_buf[bufpos-2], - g_cfg_opt_buf[bufpos-3], - g_cfg_opt_buf[bufpos-4]); - } + if(menu_pos == highlight_pos) { + printf("menu_pos %d buf_pos %d, str is %s, %02x, %02x, " + "%02x %02x\n", + menu_pos, bufpos, str, g_cfg_opt_buf[bufpos-1], + g_cfg_opt_buf[bufpos-2], + g_cfg_opt_buf[bufpos-3], + g_cfg_opt_buf[bufpos-4]); + } #endif - g_cfg_opt_buf[bufpos] = 0; - strncpy(&(g_cfg_opt_buf[bufpos]), str, CFG_OPT_MAXSTR - bufpos - 1); - g_cfg_opt_buf[CFG_OPT_MAXSTR-1] = 0; + g_cfg_opt_buf[bufpos] = 0; + strncpy(&(g_cfg_opt_buf[bufpos]), str, CFG_OPT_MAXSTR - bufpos - 1); + g_cfg_opt_buf[CFG_OPT_MAXSTR-1] = 0; } -void -cfg_get_base_path(char *pathptr, const char *inptr, int go_up) -{ - const char *tmpptr; - char *slashptr; - char *outptr; - int add_dotdot, is_dotdot; - int len; - int c; +void cfg_get_base_path(char *pathptr, const char *inptr, int go_up) { + const char *tmpptr; + char *slashptr; + char *outptr; + int add_dotdot, is_dotdot; + int len; + int c; - /* Take full filename, copy it to pathptr, and truncate at last slash */ - /* inptr and pathptr can be the same */ - /* if go_up is set, then replace a blank dir with ".." */ - /* but first, see if path is currently just ../ over and over */ - /* if so, just tack .. onto the end and return */ - //printf("cfg_get_base start with %s\n", inptr); + /* Take full filename, copy it to pathptr, and truncate at last slash */ + /* inptr and pathptr can be the same */ + /* if go_up is set, then replace a blank dir with ".." */ + /* but first, see if path is currently just ../ over and over */ + /* if so, just tack .. onto the end and return */ + //printf("cfg_get_base start with %s\n", inptr); - g_cfg_file_match[0] = 0; - tmpptr = inptr; - is_dotdot = 1; - while(1) { - if(tmpptr[0] == 0) { - break; - } - if(tmpptr[0] == '.' && tmpptr[1] == '.' && tmpptr[2] == '/') { - tmpptr += 3; - } else { - is_dotdot = 0; - break; - } - } - slashptr = 0; - outptr = pathptr; - c = -1; - while(c != 0) { - c = *inptr++; - if(c == '/') { - if(*inptr != 0) { /* if not a trailing slash... */ - slashptr = outptr; - } - } - *outptr++ = c; - } - if(!go_up) { - /* if not go_up, copy chopped part to g_cfg_file_match*/ - /* copy from slashptr+1 to end */ - tmpptr = slashptr+1; - if(slashptr == 0) { - tmpptr = pathptr; - } - strncpy(&g_cfg_file_match[0], tmpptr, CFG_PATH_MAX); - /* remove trailing / from g_cfg_file_match */ - len = strlen(&g_cfg_file_match[0]); - if((len > 1) && (len < (CFG_PATH_MAX - 1)) && - g_cfg_file_match[len - 1] == '/') { - g_cfg_file_match[len - 1] = 0; - } - //printf("set g_cfg_file_match to %s\n", &g_cfg_file_match[0]); - } - if(!is_dotdot && (slashptr != 0)) { - slashptr[0] = '/'; - slashptr[1] = 0; - outptr = slashptr + 2; - } - add_dotdot = 0; - if(pathptr[0] == 0 || is_dotdot) { - /* path was blank, or consisted of just ../ pattern */ - if(go_up) { - add_dotdot = 1; - } - } else if(slashptr == 0) { - /* no slashes found, but path was not blank--make it blank */ - if(pathptr[0] == '/') { - pathptr[1] = 0; - } else { - pathptr[0] = 0; - } - } + g_cfg_file_match[0] = 0; + tmpptr = inptr; + is_dotdot = 1; + while(1) { + if(tmpptr[0] == 0) { + break; + } + if(tmpptr[0] == '.' && tmpptr[1] == '.' && tmpptr[2] == '/') { + tmpptr += 3; + } else { + is_dotdot = 0; + break; + } + } + slashptr = 0; + outptr = pathptr; + c = -1; + while(c != 0) { + c = *inptr++; + if(c == '/') { + if(*inptr != 0) { /* if not a trailing slash... */ + slashptr = outptr; + } + } + *outptr++ = c; + } + if(!go_up) { + /* if not go_up, copy chopped part to g_cfg_file_match*/ + /* copy from slashptr+1 to end */ + tmpptr = slashptr+1; + if(slashptr == 0) { + tmpptr = pathptr; + } + strncpy(&g_cfg_file_match[0], tmpptr, CFG_PATH_MAX); + /* remove trailing / from g_cfg_file_match */ + len = strlen(&g_cfg_file_match[0]); + if((len > 1) && (len < (CFG_PATH_MAX - 1)) && + g_cfg_file_match[len - 1] == '/') { + g_cfg_file_match[len - 1] = 0; + } + //printf("set g_cfg_file_match to %s\n", &g_cfg_file_match[0]); + } + if(!is_dotdot && (slashptr != 0)) { + slashptr[0] = '/'; + slashptr[1] = 0; + outptr = slashptr + 2; + } + add_dotdot = 0; + if(pathptr[0] == 0 || is_dotdot) { + /* path was blank, or consisted of just ../ pattern */ + if(go_up) { + add_dotdot = 1; + } + } else if(slashptr == 0) { + /* no slashes found, but path was not blank--make it blank */ + if(pathptr[0] == '/') { + pathptr[1] = 0; + } else { + pathptr[0] = 0; + } + } - if(add_dotdot) { - --outptr; - outptr[0] = '.'; - outptr[1] = '.'; - outptr[2] = '/'; - outptr[3] = 0; - } + if(add_dotdot) { + --outptr; + outptr[0] = '.'; + outptr[1] = '.'; + outptr[2] = '/'; + outptr[3] = 0; + } - //printf("cfg_get_base end with %s, is_dotdot:%d, add_dotdot:%d\n", - // pathptr, is_dotdot, add_dotdot); + //printf("cfg_get_base end with %s, is_dotdot:%d, add_dotdot:%d\n", + // pathptr, is_dotdot, add_dotdot); } -void -cfg_file_init() -{ - int slot, drive; - int i; +void cfg_file_init() { + int slot, drive; + int i; - if(g_cfg_slotdrive < 0xfff) { - cfg_get_disk_name(&g_cfg_tmp_path[0], CFG_PATH_MAX, - g_cfg_slotdrive, 0); + if(g_cfg_slotdrive < 0xfff) { + cfg_get_disk_name(&g_cfg_tmp_path[0], CFG_PATH_MAX, + g_cfg_slotdrive, 0); - slot = g_cfg_slotdrive >> 8; - drive = g_cfg_slotdrive & 1; - for(i = 0; i < 6; i++) { - if(g_cfg_tmp_path[0] != 0) { - break; - } - /* try to get a starting path from some mounted drive */ - drive = !drive; - if(i & 1) { - slot++; - if(slot >= 8) { - slot = 5; - } - } - cfg_get_disk_name(&g_cfg_tmp_path[0], CFG_PATH_MAX, - (slot << 8) + drive, 0); - } - } else { - // Just use g_cfg_file_def_name - strncpy(&g_cfg_tmp_path[0], g_cfg_file_def_name, CFG_PATH_MAX); - } - - cfg_get_base_path(&g_cfg_file_curpath[0], &g_cfg_tmp_path[0], 0); - g_cfg_dirlist.invalid = 1; + slot = g_cfg_slotdrive >> 8; + drive = g_cfg_slotdrive & 1; + for(i = 0; i < 6; i++) { + if(g_cfg_tmp_path[0] != 0) { + break; + } + /* try to get a starting path from some mounted drive */ + drive = !drive; + if(i & 1) { + slot++; + if(slot >= 8) { + slot = 5; + } + } + cfg_get_disk_name(&g_cfg_tmp_path[0], CFG_PATH_MAX, + (slot << 8) + drive, 0); + } + } else { + // Just use g_cfg_file_def_name + strncpy(&g_cfg_tmp_path[0], g_cfg_file_def_name, CFG_PATH_MAX); + } + + cfg_get_base_path(&g_cfg_file_curpath[0], &g_cfg_tmp_path[0], 0); + g_cfg_dirlist.invalid = 1; } -void -cfg_free_alldirents(Cfg_listhdr *listhdrptr) -{ - int i; +void cfg_free_alldirents(Cfg_listhdr *listhdrptr) { + int i; - if(listhdrptr->max > 0) { - // Free the old directory listing - for(i = 0; i < listhdrptr->last; i++) { - free(listhdrptr->direntptr[i].name); - } - free(listhdrptr->direntptr); - } + if(listhdrptr->max > 0) { + // Free the old directory listing + for(i = 0; i < listhdrptr->last; i++) { + free(listhdrptr->direntptr[i].name); + } + free(listhdrptr->direntptr); + } - listhdrptr->direntptr = 0; - listhdrptr->last = 0; - listhdrptr->max = 0; - listhdrptr->invalid = 0; + listhdrptr->direntptr = 0; + listhdrptr->last = 0; + listhdrptr->max = 0; + listhdrptr->invalid = 0; - listhdrptr->topent = 0; - listhdrptr->curent = 0; + listhdrptr->topent = 0; + listhdrptr->curent = 0; } -void -cfg_file_add_dirent(Cfg_listhdr *listhdrptr, const char *nameptr, int is_dir, - int size, int image_start, int part_num) -{ - Cfg_dirent *direntptr; - char *ptr; - int inc_amt; - int namelen; +void cfg_file_add_dirent(Cfg_listhdr *listhdrptr, const char *nameptr, int is_dir, + int size, int image_start, int part_num) { + Cfg_dirent *direntptr; + char *ptr; + int inc_amt; + int namelen; - namelen = strlen(nameptr); - if(listhdrptr->last >= listhdrptr->max) { - // realloc - inc_amt = MAX(64, listhdrptr->max); - inc_amt = MIN(inc_amt, 1024); - listhdrptr->max += inc_amt; - listhdrptr->direntptr = (Cfg_dirent*)realloc(listhdrptr->direntptr, - listhdrptr->max * sizeof(Cfg_dirent)); - } - ptr = (char*)malloc(namelen+1+is_dir); // OG Added cast - strncpy(ptr, nameptr, namelen+1); - if(is_dir) { - strcat(ptr, "/"); - } + namelen = strlen(nameptr); + if(listhdrptr->last >= listhdrptr->max) { + // realloc + inc_amt = MAX(64, listhdrptr->max); + inc_amt = MIN(inc_amt, 1024); + listhdrptr->max += inc_amt; + listhdrptr->direntptr = (Cfg_dirent*)realloc(listhdrptr->direntptr, + listhdrptr->max * sizeof(Cfg_dirent)); + } + ptr = (char*)malloc(namelen+1+is_dir); // OG Added cast + strncpy(ptr, nameptr, namelen+1); + if(is_dir) { + strcat(ptr, "/"); + } #if 0 - printf("...file entry %d is %s\n", g_cfg_dirlist.last, ptr); + printf("...file entry %d is %s\n", g_cfg_dirlist.last, ptr); #endif - direntptr = &(listhdrptr->direntptr[listhdrptr->last]); - direntptr->name = ptr; - direntptr->is_dir = is_dir; - direntptr->size = size; - direntptr->image_start = image_start; - direntptr->part_num = part_num; - listhdrptr->last++; + direntptr = &(listhdrptr->direntptr[listhdrptr->last]); + direntptr->name = ptr; + direntptr->is_dir = is_dir; + direntptr->size = size; + direntptr->image_start = image_start; + direntptr->part_num = part_num; + listhdrptr->last++; } -int -cfg_dirent_sortfn(const void *obj1, const void *obj2) -{ - const Cfg_dirent *direntptr1, *direntptr2; - int ret; +/* Called by qsort to sort directory listings */ +int cfg_dirent_sortfn(const void *obj1, const void *obj2) { + const Cfg_dirent *direntptr1, *direntptr2; + int ret; - /* Called by qsort to sort directory listings */ - direntptr1 = (const Cfg_dirent *)obj1; - direntptr2 = (const Cfg_dirent *)obj2; -#if defined(MAC) || defined(_WIN32) - // OG - ret = 0; -// ret = strcasecmp(direntptr1->name, direntptr2->name); -#else - ret = strcmp(direntptr1->name, direntptr2->name); -#endif - return ret; + // all systems sort the file list case-insensitively + direntptr1 = (const Cfg_dirent *)obj1; + direntptr2 = (const Cfg_dirent *)obj2; + ret = strcasecmp(direntptr1->name, direntptr2->name); + return ret; } -int -cfg_str_match(const char *str1, const char *str2, int len) -{ - const byte *bptr1, *bptr2; - int c, c2; - int i; +void cfg_file_readdir(const char *pathptr) { - /* basically, work like strcmp, except if str1 ends first, return 0 */ + struct dirent *direntptr; + struct stat stat_buf; + DIR *dirptr; + mode_t fmt; + char *str; + const char *tmppathptr; + int size; + int ret; + int is_dir, is_gz; + int len; + int i; - bptr1 = (const byte *)str1; - bptr2 = (const byte *)str2; - for(i = 0; i < len; i++) { - c = *bptr1++; - c2 = *bptr2++; - if(c == 0) { - if(i > 0) { - return 0; - } else { - return c - c2; - } - } - if(c != c2) { - return c - c2; - } - } + if(!strncmp(pathptr, &g_cfg_file_cachedpath[0], CFG_PATH_MAX) && + (g_cfg_dirlist.last > 0) && (g_cfg_dirlist.invalid==0)) { + return; + } + // No match, must read new directory - return 0; + // Free all dirents that were cached previously + cfg_free_alldirents(&g_cfg_dirlist); + + strncpy(&g_cfg_file_cachedpath[0], pathptr, CFG_PATH_MAX); + strncpy(&g_cfg_file_cachedreal[0], pathptr, CFG_PATH_MAX); + + str = &g_cfg_file_cachedreal[0]; + + for(i = 0; i < 200; i++) { + len = strlen(str); + if(len <= 0) { + break; + } else if(len < CFG_PATH_MAX-2) { + if(str[len-1] != '/') { + // append / to make various routines work + str[len] = '/'; + str[len+1] = 0; + } + } + ret = cfg_stat(str, &stat_buf); + is_dir = 0; + if(ret == 0) { + fmt = stat_buf.st_mode & S_IFMT; + if(fmt == S_IFDIR) { + /* it's a directory */ + is_dir = 1; + } + } + if(is_dir) { + break; + } else { + // user is entering more path, use base for display + cfg_get_base_path(str, str, 0); + } + } + tmppathptr = str; + if(str[0] == 0) { + tmppathptr = "."; + } + cfg_file_add_dirent(&g_cfg_dirlist, "..", 1, 0, -1, -1); + dirptr = opendir(tmppathptr); + if(dirptr == 0) { + printf("Could not open %s as a directory\n", tmppathptr); + return; + } + while(1) { + direntptr = readdir(dirptr); + if(direntptr == 0) { + break; + } + if(!strcmp(".", direntptr->d_name)) { + continue; + } + if(!strcmp("..", direntptr->d_name)) { + continue; + } + // Else, see if it is a directory or a file + snprintf(&g_cfg_tmp_path[0], CFG_PATH_MAX, "%s%s", + &g_cfg_file_cachedreal[0], direntptr->d_name); + ret = cfg_stat(&g_cfg_tmp_path[0], &stat_buf); + len = strlen(g_cfg_tmp_path); + is_dir = 0; + is_gz = 0; + if((len > 3) && (strcmp(&g_cfg_tmp_path[len - 3], ".gz") == 0)) { + is_gz = 1; + } + if(ret != 0) { + printf("stat %s ret %d, errno:%d\n", &g_cfg_tmp_path[0], + ret, errno); + stat_buf.st_size = 0; + continue; /* skip it */ + } else { + fmt = stat_buf.st_mode & S_IFMT; + size = stat_buf.st_size; + if(fmt == S_IFDIR) { + // it's a directory + is_dir = 1; + } else if((fmt == S_IFREG) && (is_gz == 0)) { + if(g_cfg_slotdrive < 0xfff) { + if(size < 140*1024) { + continue; /* skip it */ + } + } else { + // see if there are size limits + if((size < g_cfg_file_min_size) || + (size > g_cfg_file_max_size)) { + continue; /* skip it */ + } + } + } + } + if (g_cfg_file_dir_only && !is_dir) continue; + + cfg_file_add_dirent(&g_cfg_dirlist, direntptr->d_name, is_dir, + stat_buf.st_size, -1, -1); + } + // always sort the results, all systems + qsort(&(g_cfg_dirlist.direntptr[0]), g_cfg_dirlist.last, sizeof(Cfg_dirent), cfg_dirent_sortfn); + g_cfg_dirlist.curent = g_cfg_dirlist.last - 1; + for(i = g_cfg_dirlist.last - 1; i >= 0; i--) { + ret = strcasecmp(&g_cfg_file_match[0], g_cfg_dirlist.direntptr[i].name); + if(ret <= 0) { + // set curent to closest filename to the match name + g_cfg_dirlist.curent = i; + } + } } -void -cfg_file_readdir(const char *pathptr) -{ -#ifndef __OS2__ - struct dirent *direntptr; - struct stat stat_buf; - DIR *dirptr; - mode_t fmt; - char *str; - const char *tmppathptr; - int size; - int ret; - int is_dir, is_gz; - int len; - int i; - - if(!strncmp(pathptr, &g_cfg_file_cachedpath[0], CFG_PATH_MAX) && - (g_cfg_dirlist.last > 0) && (g_cfg_dirlist.invalid==0)){ - return; - } - // No match, must read new directory - - // Free all dirents that were cached previously - cfg_free_alldirents(&g_cfg_dirlist); - - strncpy(&g_cfg_file_cachedpath[0], pathptr, CFG_PATH_MAX); - strncpy(&g_cfg_file_cachedreal[0], pathptr, CFG_PATH_MAX); - - str = &g_cfg_file_cachedreal[0]; - - for(i = 0; i < 200; i++) { - len = strlen(str); - if(len <= 0) { - break; - } else if(len < CFG_PATH_MAX-2) { - if(str[len-1] != '/') { - // append / to make various routines work - str[len] = '/'; - str[len+1] = 0; - } - } - ret = cfg_stat(str, &stat_buf); - is_dir = 0; - if(ret == 0) { - fmt = stat_buf.st_mode & S_IFMT; - if(fmt == S_IFDIR) { - /* it's a directory */ - is_dir = 1; - } - } - if(is_dir) { - break; - } else { - // user is entering more path, use base for display - cfg_get_base_path(str, str, 0); - } - } - tmppathptr = str; - if(str[0] == 0) { - tmppathptr = "."; - } - cfg_file_add_dirent(&g_cfg_dirlist, "..", 1, 0, -1, -1); - dirptr = opendir(tmppathptr); - if(dirptr == 0) { - printf("Could not open %s as a directory\n", tmppathptr); - return; - } - while(1) { - direntptr = readdir(dirptr); - if(direntptr == 0) { - break; - } - if(!strcmp(".", direntptr->d_name)) { - continue; - } - if(!strcmp("..", direntptr->d_name)) { - continue; - } - /* Else, see if it is a directory or a file */ - snprintf(&g_cfg_tmp_path[0], CFG_PATH_MAX, "%s%s", - &g_cfg_file_cachedreal[0], direntptr->d_name); - ret = cfg_stat(&g_cfg_tmp_path[0], &stat_buf); - len = strlen(g_cfg_tmp_path); - is_dir = 0; - is_gz = 0; - if((len > 3) && (strcmp(&g_cfg_tmp_path[len - 3], ".gz") == 0)){ - is_gz = 1; - } - if(ret != 0) { - printf("stat %s ret %d, errno:%d\n", &g_cfg_tmp_path[0], - ret, errno); - stat_buf.st_size = 0; - continue; /* skip it */ - } else { - fmt = stat_buf.st_mode & S_IFMT; - size = stat_buf.st_size; - if(fmt == S_IFDIR) { - /* it's a directory */ - is_dir = 1; - } else if((fmt == S_IFREG) && (is_gz == 0)) { - if(g_cfg_slotdrive < 0xfff) { - if(size < 140*1024) { - continue; /* skip it */ - } - } else { - /* see if there are size limits */ - if((size < g_cfg_file_min_size) || - (size > g_cfg_file_max_size)) { - continue; /* skip it */ - } - } - } - } - cfg_file_add_dirent(&g_cfg_dirlist, direntptr->d_name, is_dir, - stat_buf.st_size, -1, -1); - } - /* then sort the results (Mac's HFS+ is sorted, but other FS won't be)*/ - qsort(&(g_cfg_dirlist.direntptr[0]), g_cfg_dirlist.last, - sizeof(Cfg_dirent), cfg_dirent_sortfn); - g_cfg_dirlist.curent = g_cfg_dirlist.last - 1; - for(i = g_cfg_dirlist.last - 1; i >= 0; i--) { - ret = cfg_str_match(&g_cfg_file_match[0], - g_cfg_dirlist.direntptr[i].name, CFG_PATH_MAX); - if(ret <= 0) { - /* set cur ent to closest filename to the match name */ - g_cfg_dirlist.curent = i; - } - } -#endif -} - -void -cfg_inspect_maybe_insert_file(char *filename, int should_boot) -{ +void cfg_inspect_maybe_insert_file(char *filename, int should_boot) { /* -Take a look at a file. Based on its size, guess a slot/drive to insert it into. -Used for blind operations like dragging/dropping files. -Optionally boot from that slot. -*/ - int rc = 0; - int slot = 0; - rc = cfg_guess_image_size(filename); - switch (rc) - { - case 0: slot = 7; break; - case 1: slot = 6; break; - case 2: slot = 5; break; - case 3: slot = 7; break; - default: break; - } - if (slot > 0) - { - insert_disk(slot,0,filename,0,0,0,-1); - printf("Inserted disk in slot %d, drive 1. Filename: %s\n", slot, filename); - if (should_boot) { - g_temp_boot_slot = slot; - printf("That slot has been set to boot.\n"); - } - } - else - printf("Unable to determine appropriate place to insert file %s.\n",filename); + Take a look at a file. Based on its size, guess a slot/drive to insert it into. + Used for blind operations like dragging/dropping files. + Optionally boot from that slot. + */ + int rc = 0; + int slot = 0; + rc = cfg_guess_image_size(filename); + switch (rc) + { + case 0: slot = 7; break; + case 1: slot = 6; break; + case 2: slot = 5; break; + case 3: slot = 7; break; + default: break; + } + if (slot > 0) + { + insert_disk(slot,0,filename,0,0,0,-1); + glogf("Inserted disk in slot %d, drive 1. Filename: %s", slot, filename); + if (should_boot) { + g_temp_boot_slot = slot; + glog("That slot has been set to boot."); + } + } + else + glogf("Unable to determine appropriate place to insert file %s.",filename); } -int -cfg_guess_image_size(char *filename) -{ +int cfg_guess_image_size(char *filename) { /* -Guess the image size. Return values: - -1 : invalid/unknown. Can't guess. - 0 : Less than 140k; might be ram disk image. - 1 : 140k, 5.25" image. - 2 : 800k, 3.5" image. - 3 : Something bigger. -*/ - struct stat stat_buf; - int rc = -1; - int len; - rc = stat(filename, &stat_buf); - if(rc < 0) - { - printf("Can't get statistics on file %s; errno: %d\n", - filename, errno); - rc = -1; - } else { - len = stat_buf.st_size; - printf("Found file %s, size %d; guessing ", - filename, len); - if (len < 140 * 1024) { - /* Not enough for a 140k image */ - printf("small ProDOS image.\n"); - rc = 0; - } else if (len < 140 * 1024 + 256 + 1) { - /* Reasonable size for 140k image, maybe in 2mg format */ - printf("a 5-1/4\" image.\n"); - rc = 1; - } else if (len < 800 * 1024 + 256 + 1) { - /* Reasonable size for 800k image, maybe in 2mg format */ - printf("a 3-1/2\" image.\n"); - rc = 2; - } else { - /* Let's pretend it's an HDV image */ - printf("a hard drive image.\n"); - rc = 3; - } - } - return rc; + Guess the image size. Return values: + -1 : invalid/unknown. Can't guess. + 0 : Less than 140k; might be ram disk image. + 1 : 140k, 5.25" image. + 2 : 800k, 3.5" image. + 3 : Something bigger. + */ + struct stat stat_buf; + int rc = -1; + int len; + rc = stat(filename, &stat_buf); + if(rc < 0) + { + glogf("Can't get statistics on file %s; errno: %d", filename, errno); + rc = -1; + } else { + len = stat_buf.st_size; + if (len < 140 * 1024) { + /* Not enough for a 140k image */ + glogf("Found file %s, size %d; guessing small ProDOS image.", filename, len); + rc = 0; + } else if (len < 140 * 1024 + 256 + 1) { + /* Reasonable size for 140k image, maybe in 2mg format */ + glogf("Found file %s, size %d; guessing a 5-1/4\" image.", filename, len); + rc = 1; + } else if (len < 800 * 1024 + 256 + 1) { + /* Reasonable size for 800k image, maybe in 2mg format */ + glogf("Found file %s, size %d; guessing a 3-1/2\" image.", filename, len); + rc = 2; + } else { + /* Let's pretend it's an HDV image */ + glogf("Found file %s, size %d; guessing a hard drive image.", filename, len); + rc = 3; + } + } + return rc; } -char * -cfg_shorten_filename(const char *in_ptr, int maxlen) -{ - char *out_ptr; - int len; - int c; - int i; - /* Warning: uses a static string, not reentrant! */ - out_ptr = &(g_cfg_file_shortened[0]); - len = strlen(in_ptr); - maxlen = MIN(len, maxlen); - for(i = 0; i < maxlen; i++) { - c = in_ptr[i] & 0x7f; - if(c < 0x20) { - c = '*'; - } - out_ptr[i] = c; - } - out_ptr[maxlen] = 0; - if(len > maxlen) { - for(i = 0; i < (maxlen/2); i++) { - c = in_ptr[len-i-1] & 0x7f; - if(c < 0x20) { - c = '*'; - } - out_ptr[maxlen-i-1] = c; - } - out_ptr[(maxlen/2) - 1] = '.'; - out_ptr[maxlen/2] = '.'; - out_ptr[(maxlen/2) + 1] = '.'; - } - return out_ptr; +char *cfg_shorten_filename(const char *in_ptr, int maxlen) { + char *out_ptr; + int len; + int c; + int i; + /* Warning: uses a static string, not reentrant! */ + out_ptr = &(g_cfg_file_shortened[0]); + len = strlen(in_ptr); + maxlen = MIN(len, maxlen); + for(i = 0; i < maxlen; i++) { + c = in_ptr[i] & 0x7f; + if(c < 0x20) { + c = '*'; + } + out_ptr[i] = c; + } + out_ptr[maxlen] = 0; + if(len > maxlen) { + for(i = 0; i < (maxlen/2); i++) { + c = in_ptr[len-i-1] & 0x7f; + if(c < 0x20) { + c = '*'; + } + out_ptr[maxlen-i-1] = c; + } + out_ptr[(maxlen/2) - 1] = '.'; + out_ptr[maxlen/2] = '.'; + out_ptr[(maxlen/2) + 1] = '.'; + } + return out_ptr; } -void -cfg_fix_topent(Cfg_listhdr *listhdrptr) -{ - int num_to_show; - num_to_show = listhdrptr->num_to_show; - /* Force curent and topent to make sense */ - if(listhdrptr->curent >= listhdrptr->last) { - listhdrptr->curent = listhdrptr->last - 1; - } - if(listhdrptr->curent < 0) { - listhdrptr->curent = 0; - } - if(abs(listhdrptr->curent - listhdrptr->topent) >= num_to_show) { - listhdrptr->topent = listhdrptr->curent - (num_to_show/2); - } - if(listhdrptr->topent > listhdrptr->curent) { - listhdrptr->topent = listhdrptr->curent - (num_to_show/2); - } - if(listhdrptr->topent < 0) { - listhdrptr->topent = 0; - } +void cfg_fix_topent(Cfg_listhdr *listhdrptr) { + int num_to_show; + num_to_show = listhdrptr->num_to_show; + /* Force curent and topent to make sense */ + if(listhdrptr->curent >= listhdrptr->last) { + listhdrptr->curent = listhdrptr->last - 1; + } + if(listhdrptr->curent < 0) { + listhdrptr->curent = 0; + } + if(abs(listhdrptr->curent - listhdrptr->topent) >= num_to_show) { + listhdrptr->topent = listhdrptr->curent - (num_to_show/2); + } + if(listhdrptr->topent > listhdrptr->curent) { + listhdrptr->topent = listhdrptr->curent - (num_to_show/2); + } + if(listhdrptr->topent < 0) { + listhdrptr->topent = 0; + } } -void -cfg_file_draw() -{ - Cfg_listhdr *listhdrptr; - Cfg_dirent *direntptr; - char *str, *fmt; - int num_to_show; - int yoffset; - int x, y; - int i; - cfg_file_readdir(&g_cfg_file_curpath[0]); - for(y = 0; y < 21; y++) { - cfg_htab_vtab(0, y); - cfg_printf("\tZ\t"); - for(x = 1; x < 79; x++) { - cfg_htab_vtab(x, y); - cfg_putchar(' '); - } - cfg_htab_vtab(79, y); - cfg_printf("\t_\t"); - } - cfg_htab_vtab(1, 0); - cfg_putchar('\b'); - for(x = 1; x < 79; x++) { - cfg_putchar(' '); - } - if(g_cfg_slotdrive < 0xfff) { - cfg_htab_vtab(30, 0); - cfg_printf("\bSelect image for s%dd%d\b", - (g_cfg_slotdrive >> 8), (g_cfg_slotdrive & 0xff) + 1); - } else { - cfg_htab_vtab(5, 0); - cfg_printf("\bSelect file to use as %-40s\b", - cfg_shorten_filename(g_cfg_file_def_name, 40)); - } - cfg_htab_vtab(2, 1); - cfg_printf("Configuration file path: %-56s", - cfg_shorten_filename(&g_config_gsport_name[0], 56)); - cfg_htab_vtab(2, 2); - cfg_printf("Current directory: %-50s", - cfg_shorten_filename(&g_cfg_cwd_str[0], 50)); - cfg_htab_vtab(2, 3); - str = ""; - if(g_cfg_file_pathfield) { - str = "\b \b"; - } - cfg_printf("Path: %s%s", - cfg_shorten_filename(&g_cfg_file_curpath[0], 68), str); - cfg_htab_vtab(0, 4); - cfg_printf(" \t"); - for(x = 1; x < 79; x++) { - cfg_putchar('\\'); - } - cfg_printf("\t "); +void cfg_file_draw() { + Cfg_listhdr *listhdrptr; + Cfg_dirent *direntptr; + char *str, *fmt; + int num_to_show; + int yoffset; + int x, y; + int i; + cfg_file_readdir(&g_cfg_file_curpath[0]); + for(y = 0; y < 21; y++) { + cfg_htab_vtab(0, y); + cfg_printf("\tZ\t"); + for(x = 1; x < 79; x++) { + cfg_htab_vtab(x, y); + cfg_putchar(' '); + } + cfg_htab_vtab(79, y); + cfg_printf("\t_\t"); + } + cfg_htab_vtab(1, 0); + cfg_putchar('\b'); + for(x = 1; x < 79; x++) { + cfg_putchar(' '); + } + if(g_cfg_slotdrive < 0xfff) { + cfg_htab_vtab(30, 0); + cfg_printf("\bSelect image for s%dd%d\b", + (g_cfg_slotdrive >> 8), (g_cfg_slotdrive & 0xff) + 1); + } else { + cfg_htab_vtab(5, 0); + cfg_printf("\bSelect file to use as %-40s\b", + cfg_shorten_filename(g_cfg_file_def_name, 40)); + } + cfg_htab_vtab(2, 1); + cfg_printf("Configuration file path: %-40s", + cfg_shorten_filename(&g_config_gsport_name[0], 40)); + cfg_htab_vtab(2, 2); + cfg_printf("Current directory: %-50s", + cfg_shorten_filename(&g_cfg_cwd_str[0], 50)); + cfg_htab_vtab(2, 3); + str = ""; + if(g_cfg_file_pathfield) { + str = "\b \b"; + } + cfg_printf("Path: %s%s", + cfg_shorten_filename(&g_cfg_file_curpath[0], 68), str); + cfg_htab_vtab(0, 4); + cfg_printf(" \t"); + for(x = 1; x < 79; x++) { + cfg_putchar('\\'); + } + cfg_printf("\t "); - /* Force curent and topent to make sense */ - listhdrptr = &g_cfg_dirlist; - num_to_show = CFG_NUM_SHOWENTS; - yoffset = 5; - if(g_cfg_select_partition > 0) { - listhdrptr = &g_cfg_partitionlist; - num_to_show -= 2; - cfg_htab_vtab(2, yoffset); - cfg_printf("Select partition of %-50s\n", - cfg_shorten_filename(&g_cfg_file_path[0], 50), str); - yoffset += 2; - } - listhdrptr->num_to_show = num_to_show; - cfg_fix_topent(listhdrptr); - for(i = 0; i < num_to_show; i++) { - y = i + yoffset; - if(listhdrptr->last > (i + listhdrptr->topent)) { - direntptr = &(listhdrptr-> - direntptr[i + listhdrptr->topent]); - cfg_htab_vtab(2, y); - if(direntptr->is_dir) { - cfg_printf("\tXY\t "); - } else { - cfg_printf(" "); - } - if(direntptr->part_num >= 0) { - cfg_printf("%3d: ", direntptr->part_num); - } - str = cfg_shorten_filename(direntptr->name, 45); - fmt = "%-45s"; - if(i + listhdrptr->topent == listhdrptr->curent) { - if(g_cfg_file_pathfield == 0) { - fmt = "\b%-45s\b"; - } else { - fmt = "%-44s\b \b"; - } - } - cfg_printf(fmt, str); - if(!direntptr->is_dir) { - cfg_print_num(direntptr->size, 13); - } - } - } - cfg_htab_vtab(1, 5 + CFG_NUM_SHOWENTS); - cfg_putchar('\t'); - for(x = 1; x < 79; x++) { - cfg_putchar('L'); - } - cfg_putchar('\t'); -} -void -cfg_partition_selected() -{ - char *str; - const char *part_str; - char *part_str2; - int pos; - int part_num; - pos = g_cfg_partitionlist.curent; - str = g_cfg_partitionlist.direntptr[pos].name; - part_num = -2; - part_str = 0; - if(str[0] == 0 || (str[0] >= '0' && str[0] <= '9')) { - part_num = g_cfg_partitionlist.direntptr[pos].part_num; - } else { - part_str = str; - } - part_str2 = 0; - if(part_str != 0) { - part_str2 = (char *)malloc(strlen(part_str)+1); - strcpy(part_str2, part_str); - } - insert_disk(g_cfg_slotdrive >> 8, g_cfg_slotdrive & 0xff, - &(g_cfg_file_path[0]), 0, 0, part_str2, part_num); - if(part_str2 != 0) { - free(part_str2); - } - g_cfg_slotdrive = -1; - g_cfg_select_partition = -1; -} -void -cfg_file_update_ptr(char *str) -{ - char *newstr; - int len; - len = strlen(str) + 1; - newstr = (char*)malloc(len); - memcpy(newstr, str, len); - if(g_cfg_file_strptr) { - if(*g_cfg_file_strptr) { - free(*g_cfg_file_strptr); - } - } - *g_cfg_file_strptr = newstr; - if(g_cfg_file_strptr == &(g_cfg_rom_path)) { - printf("Updated ROM file\n"); - load_roms_init_memory(); - } - g_config_gsport_update_needed = 1; -} -void -cfg_file_selected() -{ -#ifndef __OS2__ - struct stat stat_buf; - char *str; - int fmt; - int ret; - if(g_cfg_select_partition > 0) { - cfg_partition_selected(); - return; - } - if(g_cfg_file_pathfield == 0) { - // in file section area of window - str = g_cfg_dirlist.direntptr[g_cfg_dirlist.curent].name; - if(!strcmp(str, "../")) { - /* go up one directory */ - cfg_get_base_path(&g_cfg_file_curpath[0], - &g_cfg_file_curpath[0], 1); - return; - } - snprintf(&g_cfg_file_path[0], CFG_PATH_MAX, "%s%s", - &g_cfg_file_cachedreal[0], str); - } else { - // just use cfg_file_curpath directly - strncpy(&g_cfg_file_path[0], &g_cfg_file_curpath[0], - CFG_PATH_MAX); - } - ret = cfg_stat(&g_cfg_file_path[0], &stat_buf); - fmt = stat_buf.st_mode & S_IFMT; - cfg_printf("Stat'ing %s, st_mode is: %08x\n", &g_cfg_file_path[0], - (int)stat_buf.st_mode); - if(ret != 0) { - printf("stat %s returned %d, errno: %d\n", &g_cfg_file_path[0], - ret, errno); - } else { - if(fmt == S_IFDIR) { - /* it's a directory */ - strncpy(&g_cfg_file_curpath[0], &g_cfg_file_path[0], - CFG_PATH_MAX); - } else { - /* select it */ - if(g_cfg_slotdrive < 0xfff) { - ret = cfg_maybe_insert_disk(g_cfg_slotdrive>>8, - g_cfg_slotdrive & 0xff, - &g_cfg_file_path[0]); - if(ret > 0) { - g_cfg_slotdrive = -1; - } - } else { - cfg_file_update_ptr(&g_cfg_file_path[0]); - g_cfg_slotdrive = -1; - } - } - } -#endif + /* Force curent and topent to make sense */ + listhdrptr = &g_cfg_dirlist; + num_to_show = CFG_NUM_SHOWENTS; + yoffset = 5; + if(g_cfg_select_partition > 0) { + listhdrptr = &g_cfg_partitionlist; + num_to_show -= 2; + cfg_htab_vtab(2, yoffset); + cfg_printf("Select partition of %-50s\n", + cfg_shorten_filename(&g_cfg_file_path[0], 50), str); + yoffset += 2; + } + listhdrptr->num_to_show = num_to_show; + cfg_fix_topent(listhdrptr); + for(i = 0; i < num_to_show; i++) { + y = i + yoffset; + if(listhdrptr->last > (i + listhdrptr->topent)) { + direntptr = &(listhdrptr-> + direntptr[i + listhdrptr->topent]); + cfg_htab_vtab(2, y); + if(direntptr->is_dir) { + cfg_printf("\tXY\t "); + } else { + cfg_printf(" "); + } + if(direntptr->part_num >= 0) { + cfg_printf("%3d: ", direntptr->part_num); + } + str = cfg_shorten_filename(direntptr->name, 45); + fmt = "%-45s"; + if(i + listhdrptr->topent == listhdrptr->curent) { + if(g_cfg_file_pathfield == 0) { + fmt = "\b%-45s\b"; + } else { + fmt = "%-44s\b \b"; + } + } + cfg_printf(fmt, str); + if(!direntptr->is_dir) { + cfg_print_num(direntptr->size, 13); + } + } + } + cfg_htab_vtab(1, 5 + CFG_NUM_SHOWENTS); + cfg_putchar('\t'); + for(x = 1; x < 79; x++) { + cfg_putchar('L'); + } + cfg_putchar('\t'); } -void -cfg_file_handle_key(int key) -{ - Cfg_listhdr *listhdrptr; - int len; - if(g_cfg_file_pathfield) { - if(key >= 0x20 && key < 0x7f) { - len = strlen(&g_cfg_file_curpath[0]); - if(len < CFG_PATH_MAX-4) { - g_cfg_file_curpath[len] = key; - g_cfg_file_curpath[len+1] = 0; - } - return; - } - } - listhdrptr = &g_cfg_dirlist; - if(g_cfg_select_partition > 0) { - listhdrptr = &g_cfg_partitionlist; - } - if( (g_cfg_file_pathfield == 0) && - ((key >= 'a' && key <= 'z') || (key >= 'A' && key <= 'Z')) ) { - /* jump to file starting with this letter */ - g_cfg_file_match[0] = key; - g_cfg_file_match[1] = 0; - g_cfg_dirlist.invalid = 1; /* re-read directory */ - } - switch(key) { - case 0x1b: - if(g_cfg_slotdrive < 0xfff) { - eject_disk_by_num(g_cfg_slotdrive >> 8, - g_cfg_slotdrive & 0xff); - } - g_cfg_slotdrive = -1; - g_cfg_select_partition = -1; - g_cfg_dirlist.invalid = 1; - break; - case 0x0a: /* down arrow */ - if(g_cfg_file_pathfield == 0) { - listhdrptr->curent++; - cfg_fix_topent(listhdrptr); - } - break; - case 0x0b: /* up arrow */ - if(g_cfg_file_pathfield == 0) { - listhdrptr->curent--; - cfg_fix_topent(listhdrptr); - } - break; - case 0x0d: /* return */ - printf("handling return press\n"); - cfg_file_selected(); - break; - case 0x09: /* tab */ - g_cfg_file_pathfield = !g_cfg_file_pathfield; - break; - case 0x08: /* left arrow */ - case 0x7f: /* delete key */ - if(g_cfg_file_pathfield) { - // printf("left arrow/delete\n"); - len = strlen(&g_cfg_file_curpath[0]) - 1; - if(len >= 0) { - g_cfg_file_curpath[len] = 0; - } - } - break; - default: - printf("key: %02x\n", key); - } +void cfg_partition_selected() { + char *str; + const char *part_str; + char *part_str2; + int pos; + int part_num; + pos = g_cfg_partitionlist.curent; + str = g_cfg_partitionlist.direntptr[pos].name; + part_num = -2; + part_str = 0; + if(str[0] == 0 || (str[0] >= '0' && str[0] <= '9')) { + part_num = g_cfg_partitionlist.direntptr[pos].part_num; + } else { + part_str = str; + } + part_str2 = 0; + if(part_str != 0) { + part_str2 = (char *)malloc(strlen(part_str)+1); + strcpy(part_str2, part_str); + } + insert_disk(g_cfg_slotdrive >> 8, g_cfg_slotdrive & 0xff, + &(g_cfg_file_path[0]), 0, 0, part_str2, part_num); + if(part_str2 != 0) { + free(part_str2); + } + g_cfg_slotdrive = -1; + g_cfg_select_partition = -1; +} +void cfg_file_update_ptr(char *str) { + char *newstr; + int len; + len = strlen(str) + 1; + newstr = (char*)malloc(len); + memcpy(newstr, str, len); + if(g_cfg_file_strptr) { + if(*g_cfg_file_strptr) { + free(*g_cfg_file_strptr); + } + } + *g_cfg_file_strptr = newstr; + if(g_cfg_file_strptr == &(g_cfg_rom_path)) { + glog("Updated ROM file"); + load_roms_init_memory(); + } + g_config_gsport_update_needed = 1; +} +void cfg_file_selected(int select_dir) { + struct stat stat_buf; + char *str; + int fmt; + int ret; + if(g_cfg_select_partition > 0) { + cfg_partition_selected(); + return; + } + if(g_cfg_file_pathfield == 0) { + // in file section area of window + str = g_cfg_dirlist.direntptr[g_cfg_dirlist.curent].name; + if(!strcmp(str, "../")) { + /* go up one directory */ + cfg_get_base_path(&g_cfg_file_curpath[0], + &g_cfg_file_curpath[0], 1); + return; + } + snprintf(&g_cfg_file_path[0], CFG_PATH_MAX, "%s%s", + &g_cfg_file_cachedreal[0], str); + } else { + // just use cfg_file_curpath directly + strncpy(&g_cfg_file_path[0], &g_cfg_file_curpath[0], + CFG_PATH_MAX); + } + ret = cfg_stat(&g_cfg_file_path[0], &stat_buf); + fmt = stat_buf.st_mode & S_IFMT; + #if 0 + cfg_printf("Stat'ing %s, st_mode is: %08x\n", &g_cfg_file_path[0], + (int)stat_buf.st_mode); + #endif + if(ret != 0) { + glogf("stat %s returned %d, errno: %d", &g_cfg_file_path[0], ret, errno); + } else { + if(fmt == S_IFDIR && !select_dir) { + /* it's a directory */ + strncpy(&g_cfg_file_curpath[0], &g_cfg_file_path[0], + CFG_PATH_MAX); + } else { + /* select it */ + if(g_cfg_slotdrive < 0xfff) { + ret = cfg_maybe_insert_disk(g_cfg_slotdrive>>8, + g_cfg_slotdrive & 0xff, + &g_cfg_file_path[0]); + if(ret > 0) { + g_cfg_slotdrive = -1; + } + } else { + cfg_file_update_ptr(&g_cfg_file_path[0]); + g_cfg_slotdrive = -1; + } + } + } +} + +void cfg_file_handle_key(int key) { + Cfg_listhdr *listhdrptr; + int len; + if(g_cfg_file_pathfield) { + if(key >= 0x20 && key < 0x7f) { + len = strlen(&g_cfg_file_curpath[0]); + if(len < CFG_PATH_MAX-4) { + g_cfg_file_curpath[len] = key; + g_cfg_file_curpath[len+1] = 0; + } + return; + } + } + listhdrptr = &g_cfg_dirlist; + if(g_cfg_select_partition > 0) { + listhdrptr = &g_cfg_partitionlist; + } + + // can't hotkey numbers because it falsely matches PGUP/PGDN + if( (g_cfg_file_pathfield == 0) && + ((key >= 'a' && key <= 'z') || (key >= 'A' && key <= 'Z')) ) { + /* jump to file starting with this letter */ + g_cfg_file_match[0] = key; + g_cfg_file_match[1] = 0; + g_cfg_dirlist.invalid = 1; /* re-read directory */ + } else { + switch(key) { + case 0x1b: + if(g_cfg_slotdrive < 0xfff) { + eject_disk_by_num(g_cfg_slotdrive >> 8, g_cfg_slotdrive & 0xff); + } + g_cfg_slotdrive = -1; + g_cfg_select_partition = -1; + g_cfg_dirlist.invalid = 1; + break; + case 0x0a: /* down arrow */ + if(g_cfg_file_pathfield == 0) { + listhdrptr->curent++; + cfg_fix_topent(listhdrptr); + } + break; + case 0x0b: /* up arrow */ + if(g_cfg_file_pathfield == 0) { + listhdrptr->curent--; + cfg_fix_topent(listhdrptr); + } + break; + case 0x33: /* pg dn */ + if(g_cfg_file_pathfield == 0) { + listhdrptr->curent += CFG_PG_SCROLL_AMT; + cfg_fix_topent(listhdrptr); + } + break; + case 0x39: /* pg up */ + if(g_cfg_file_pathfield == 0) { + listhdrptr->curent -= CFG_PG_SCROLL_AMT; + cfg_fix_topent(listhdrptr); + } + break; + case 0x0d: /* return */ + cfg_file_selected(0); + break; + case 0x09: /* tab */ + g_cfg_file_pathfield = !g_cfg_file_pathfield; + break; + case 0x15: + glogf("You can't go right!"); /* eggs - DB */ + break; + case 0x08: /* left arrow */ + case 0x7f: /* delete key */ + if(g_cfg_file_pathfield) { + len = strlen(&g_cfg_file_curpath[0]) - 1; + if(len >= 0) { + g_cfg_file_curpath[len] = 0; + } + } + break; + case 0x20: /* space -- selects file/directory */ + cfg_file_selected(g_cfg_file_dir_only); + break; + default: + glogf("Unhandled file config key: 0x%02x", key); + } + } +} + +void config_control_panel() { + void (*fn_ptr)(); + const char *str; + Cfg_menu *menuptr; + void *ptr; + int print_eject_help; + int line; + int type; + int match_found; + int menu_line; + int menu_inc; + int max_line; + int key; + int i, j; + // First, save important text screen state + g_save_cur_a2_stat = g_cur_a2_stat; + for(i = 0; i < 0x400; i++) { + g_save_text_screen_bytes[i] = g_slow_memory_ptr[0x400+i]; + g_save_text_screen_bytes[0x400+i] =g_slow_memory_ptr[0x10400+i]; + } + g_cur_a2_stat = ALL_STAT_TEXT | ALL_STAT_VID80 | ALL_STAT_ANNUNC3 | + (0xf << BIT_ALL_STAT_TEXT_COLOR) | ALL_STAT_ALTCHARSET; + g_a2_new_all_stat[0] = g_cur_a2_stat; + g_new_a2_stat_cur_line = 0; + for(i = 0; i < 20; i++) { + // Toss any queued-up keypresses + if(adb_read_c000() & 0x80) { + (void)adb_access_c010(); + } + } + g_adb_repeat_vbl = 0; + g_cfg_vbl_count = 0; + // HACK: Force adb keyboard (and probably mouse) to "normal"... + g_full_refresh_needed = -1; + g_a2_screen_buffer_changed = -1; + cfg_home(); + j = 0; + menuptr = g_cfg_main_menu; + if(g_rom_version < 0) { + /* Must select ROM file */ + menuptr = g_cfg_rom_menu; + } + menu_line = 1; + menu_inc = 1; + g_cfg_slotdrive = -1; + g_cfg_select_partition = -1; + while(g_config_control_panel & !(halt_sim&HALT_WANTTOQUIT)) { + if(g_fatal_log > 0) { + x_show_alert(0, 0); + } + cfg_home(); + line = 1; + max_line = 1; + match_found = 0; + print_eject_help = 0; + cfg_printf("%s\n\n", menuptr[0].str); + while(line < 24) { + str = menuptr[line].str; + type = menuptr[line].cfgtype; + ptr = menuptr[line].ptr; + if(str == 0) { + break; + } + if((type & 0xf) == CFGTYPE_DISK) { + print_eject_help = 1; + } + cfg_parse_menu(menuptr, line, menu_line, 0); + if(line == menu_line) { + if(type != 0) { + match_found = 1; + } else if(menu_inc) { + menu_line++; + } else { + menu_line--; + } + } + if(line > max_line) { + max_line = line; + } + cfg_printf("%s\n", g_cfg_opt_buf); + line++; + } + if((menu_line < 1) && !match_found) { + menu_line = 1; + } + if((menu_line >= max_line) && !match_found) { + menu_line = max_line; + } + if(g_rom_version < 0) { + cfg_htab_vtab(0, 21); + cfg_printf("\bYOU MUST SELECT A VALID ROM FILE\b\n"); + } + cfg_htab_vtab(0, 23); + cfg_printf("Move: \tJ\t \tK\t Change: \tH\t \tU\t \tM\t"); + if(print_eject_help) { + cfg_printf(" Eject: "); + if(g_cfg_slotdrive >= 0) { + cfg_printf("\bESC\b"); + } else { + cfg_printf("E"); + } + } #if 0 - printf("curent: %d, topent: %d, last: %d\n", - g_cfg_dirlist.curent, g_cfg_dirlist.topent, g_cfg_dirlist.last); + cfg_htab_vtab(0, 22); + cfg_printf("menu_line: %d line: %d, vbl:%d, adb:%d key_dn:%d\n", + menu_line, line, g_cfg_vbl_count, g_adb_repeat_vbl, + g_key_down); #endif -} -void -config_control_panel() -{ - void (*fn_ptr)(); - const char *str; - Cfg_menu *menuptr; - void *ptr; - int print_eject_help; - int line; - int type; - int match_found; - int menu_line; - int menu_inc; - int max_line; - int key; - int i, j; - // First, save important text screen state - g_save_cur_a2_stat = g_cur_a2_stat; - for(i = 0; i < 0x400; i++) { - g_save_text_screen_bytes[i] = g_slow_memory_ptr[0x400+i]; - g_save_text_screen_bytes[0x400+i] =g_slow_memory_ptr[0x10400+i]; - } - g_cur_a2_stat = ALL_STAT_TEXT | ALL_STAT_VID80 | ALL_STAT_ANNUNC3 | - (0xf << BIT_ALL_STAT_TEXT_COLOR) | ALL_STAT_ALTCHARSET; - g_a2_new_all_stat[0] = g_cur_a2_stat; - g_new_a2_stat_cur_line = 0; - cfg_printf("In config_control_panel\n"); - for(i = 0; i < 20; i++) { - // Toss any queued-up keypresses - if(adb_read_c000() & 0x80) { - (void)adb_access_c010(); - } - } - g_adb_repeat_vbl = 0; - g_cfg_vbl_count = 0; - // HACK: Force adb keyboard (and probably mouse) to "normal"... - g_full_refresh_needed = -1; - g_a2_screen_buffer_changed = -1; - cfg_home(); - j = 0; - menuptr = g_cfg_main_menu; - if(g_rom_version < 0) { - /* Must select ROM file */ - menuptr = g_cfg_rom_menu; - } - menu_line = 1; - menu_inc = 1; - g_cfg_slotdrive = -1; - g_cfg_select_partition = -1; - while(g_config_control_panel & !(halt_sim&HALT_WANTTOQUIT)) { - if(g_fatal_log > 0) { - x_show_alert(0, 0); - } - cfg_home(); - line = 1; - max_line = 1; - match_found = 0; - print_eject_help = 0; - cfg_printf("%s\n\n", menuptr[0].str); - while(line < 24) { - str = menuptr[line].str; - type = menuptr[line].cfgtype; - ptr = menuptr[line].ptr; - if(str == 0) { - break; - } - if((type & 0xf) == CFGTYPE_DISK) { - print_eject_help = 1; - } - cfg_parse_menu(menuptr, line, menu_line, 0); - if(line == menu_line) { - if(type != 0) { - match_found = 1; - } else if(menu_inc) { - menu_line++; - } else { - menu_line--; - } - } - if(line > max_line) { - max_line = line; - } - cfg_printf("%s\n", g_cfg_opt_buf); - line++; - } - if((menu_line < 1) && !match_found) { - menu_line = 1; - } - if((menu_line >= max_line) && !match_found) { - menu_line = max_line; - } - if(g_rom_version < 0) { - cfg_htab_vtab(0, 21); - cfg_printf("\bYOU MUST SELECT A VALID ROM FILE\b\n"); - } - cfg_htab_vtab(0, 23); - cfg_printf("Move: \tJ\t \tK\t Change: \tH\t \tU\t \tM\t"); - if(print_eject_help) { - cfg_printf(" Eject: "); - if(g_cfg_slotdrive >= 0) { - cfg_printf("\bESC\b"); - } else { - cfg_printf("E"); - } - } -#if 0 - cfg_htab_vtab(0, 22); - cfg_printf("menu_line: %d line: %d, vbl:%d, adb:%d key_dn:%d\n", - menu_line, line, g_cfg_vbl_count, g_adb_repeat_vbl, - g_key_down); -#endif - if(g_cfg_slotdrive >= 0) { - cfg_file_draw(); - } + if(g_cfg_slotdrive >= 0) { + cfg_file_draw(); + } #ifdef HAVE_TFE - /*HACK eh, at least I think it is. Display the available ethernet interfaces - when in the ethernet control panel. This is the only way one can customize a menu pane. - Kent did it with the directory browser, so why not.*/ - if(menuptr == g_cfg_ethernet_menu) - { - cfg_get_tfe_name(); - } + /*HACK eh, at least I think it is. Display the available ethernet interfaces + when in the ethernet control panel. This is the only way one can customize a menu pane. + Kent did it with the directory browser, so why not.*/ + if(menuptr == g_cfg_ethernet_menu) + { + cfg_get_tfe_name(); + } #endif #ifdef HAVE_SDL - /*If user enters the Virtual Imagewriter control panel, flag it so we can - automatically apply changes on exit.*/ - if(menuptr == g_cfg_imagewriter_menu) - { - g_cfg_triggeriwreset = 1; - } + /*If user enters the Virtual Imagewriter control panel, flag it so we can + automatically apply changes on exit.*/ + if(menuptr == g_cfg_imagewriter_menu) + { + g_cfg_triggeriwreset = 1; + } #endif - key = -1; - while(g_config_control_panel & !(halt_sim&HALT_WANTTOQUIT)) { - video_update(); - key = adb_read_c000(); - if(key & 0x80) { - key = key & 0x7f; - (void)adb_access_c010(); - break; - } else { - key = -1; - } - micro_sleep(1.0/60.0); - g_cfg_vbl_count++; - if(!match_found) { - break; - } - } - if((key >= 0) && (g_cfg_slotdrive < 0)) { - // Normal menu system - switch(key) { - case 0x0a: /* down arrow */ - menu_line++; - menu_inc = 1; - break; - case 0x0b: /* up arrow */ - menu_line--; - menu_inc = 0; - if(menu_line < 1) { - menu_line = 1; - } - break; - case 0x15: /* right arrow */ - cfg_parse_menu(menuptr, menu_line,menu_line,1); - break; - case 0x08: /* left arrow */ - cfg_parse_menu(menuptr,menu_line,menu_line,-1); - break; - case 0x0d: - type = menuptr[menu_line].cfgtype; - ptr = menuptr[menu_line].ptr; - switch(type & 0xf) { - case CFGTYPE_MENU: - menuptr = (Cfg_menu *)ptr; - menu_line = 1; - break; - case CFGTYPE_DISK: - g_cfg_slotdrive = type >> 4; - cfg_file_init(); - break; - case CFGTYPE_FUNC: - fn_ptr = (void (*)())ptr; - (*fn_ptr)(); - adb_all_keys_up(); //Needed otherwise menu function will continue to repeat until we move selection up or down - break; - case CFGTYPE_FILE: - g_cfg_slotdrive = 0xfff; - g_cfg_file_def_name = *((char **)ptr); - g_cfg_file_strptr = (char **)ptr; - cfg_file_init(); - } - break; - case 0x1b: - // Jump to last menu entry - menu_line = max_line; - break; - case 'e': - case 'E': - type = menuptr[menu_line].cfgtype; - if((type & 0xf) == CFGTYPE_DISK) { - eject_disk_by_num(type >> 12, - (type >> 4) & 0xff); - } - break; - default: - printf("key: %02x\n", key); - } - } else if(key >= 0) { - cfg_file_handle_key(key); - } - } - for(i = 0; i < 0x400; i++) { - set_memory_c(0xe00400+i, g_save_text_screen_bytes[i], 0); - set_memory_c(0xe10400+i, g_save_text_screen_bytes[0x400+i], 0); - } - // And quit - if (g_cfg_triggeriwreset) - { - g_cfg_triggeriwreset = 0; - cfg_iwreset(); //Reset the virtual Imagewriter if the user was in the control panel. - } - g_config_control_panel = 0; - g_adb_repeat_vbl = g_vbl_count + 60; - g_cur_a2_stat = g_save_cur_a2_stat; - change_display_mode(g_cur_dcycs); - g_full_refresh_needed = -1; - g_a2_screen_buffer_changed = -1; + key = -1; + while(g_config_control_panel & !(halt_sim&HALT_WANTTOQUIT)) { + video_update(); + key = adb_read_c000(); + if(key & 0x80) { + key = key & 0x7f; + (void)adb_access_c010(); + break; + } else { + key = -1; + } + micro_sleep(1.0/60.0); + g_cfg_vbl_count++; + if(!match_found) { + break; + } + } + if((key >= 0) && (g_cfg_slotdrive < 0)) { + // Normal menu system + switch(key) { + case 0x0a: /* down arrow */ + menu_line++; + menu_inc = 1; + break; + case 0x0b: /* up arrow */ + menu_line--; + menu_inc = 0; + if(menu_line < 1) { + menu_line = 1; + } + break; + case 0x33: /* pg dn */ + menu_line += CFG_PG_SCROLL_AMT; + menu_inc = 1; + break; + case 0x39: /* pg up */ + menu_line -= CFG_PG_SCROLL_AMT; + menu_inc = 0; + if(menu_line < 1) { + menu_line = 1; + } + break; + case 0x15: /* right arrow */ + cfg_parse_menu(menuptr, menu_line,menu_line,1); + break; + case 0x08: /* left arrow */ + cfg_parse_menu(menuptr,menu_line,menu_line,-1); + break; + case 0x0d: + type = menuptr[menu_line].cfgtype; + ptr = menuptr[menu_line].ptr; + str = menuptr[menu_line].str; + switch(type & 0xf) { + case CFGTYPE_MENU: + menuptr = (Cfg_menu *)ptr; + menu_line = 1; + break; + case CFGTYPE_DISK: + g_cfg_slotdrive = type >> 4; + g_cfg_file_dir_only = 0; + cfg_file_init(); + break; + case CFGTYPE_FUNC: + fn_ptr = (void (*)())ptr; + (*fn_ptr)(); + adb_all_keys_up(); //Needed otherwise menu function will continue to repeat until we move selection up or down + break; + case CFGTYPE_FILE: + g_cfg_slotdrive = 0xfff; + g_cfg_file_def_name = str /* *((char **)ptr) */; // was ptr + g_cfg_file_strptr = (char **)ptr; + g_cfg_file_dir_only = 0; + cfg_file_init(); + break; + case CFGTYPE_DIR: + g_cfg_slotdrive = 0xfff; + g_cfg_file_def_name = str /* *((char **)ptr) */; // was ptr + g_cfg_file_strptr = (char **)ptr; + g_cfg_file_dir_only = 1; + cfg_file_init(); + break; + } + break; + case 0x1b: + // Jump to last menu entry + menu_line = max_line; + break; + case 'e': + case 'E': + type = menuptr[menu_line].cfgtype; + if((type & 0xf) == CFGTYPE_DISK) { + eject_disk_by_num(type >> 12, + (type >> 4) & 0xff); + } + break; + default: + glogf("Unhandled config key: 0x%02x", key); + } + } else if(key >= 0) { + cfg_file_handle_key(key); + } + } + for(i = 0; i < 0x400; i++) { + set_memory_c(0xe00400+i, g_save_text_screen_bytes[i], 0); + set_memory_c(0xe10400+i, g_save_text_screen_bytes[0x400+i], 0); + } + // And quit + if (g_cfg_triggeriwreset) + { + g_cfg_triggeriwreset = 0; + cfg_iwreset(); //Reset the virtual Imagewriter if the user was in the control panel. + } + g_config_control_panel = 0; + g_adb_repeat_vbl = g_vbl_count + 60; + g_cur_a2_stat = g_save_cur_a2_stat; + change_display_mode(g_cur_dcycs); + g_full_refresh_needed = -1; + g_a2_screen_buffer_changed = -1; +} + +void x_clk_setup_bram_version() { + if(g_rom_version < 3) { + g_bram_ptr = (&g_bram[0][0]); // ROM 01 + } else { + g_bram_ptr = (&g_bram[1][0]); // ROM 03 + } } - -void x_clk_setup_bram_version() -{ - if(g_rom_version < 3) { - g_bram_ptr = (&g_bram[0][0]); // ROM 01 - } else { - g_bram_ptr = (&g_bram[1][0]); // ROM 03 - } -} diff --git a/src/config.h b/src/config.h index b1c3c71..64a6c61 100644 --- a/src/config.h +++ b/src/config.h @@ -1,6 +1,7 @@ /* GSport - an Apple //gs Emulator - Copyright (C) 2010 by GSport contributors + Copyright (C) 2010 - 2019 by GSport contributors + Copyright (C) 2016 - 2018 Dagen Brock Based on the KEGS emulator written by and Copyright (C) 2003 Kent Dickey @@ -19,20 +20,19 @@ 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#define CONF_BUF_LEN 1024 -#define COPY_BUF_SIZE 4096 +#define CONF_BUF_LEN 1024 +#define COPY_BUF_SIZE 4096 #define CFG_PRINTF_BUFSIZE 2048 - -#define CFG_PATH_MAX 1024 - -#define CFG_NUM_SHOWENTS 16 +#define CFG_PATH_MAX 1024 +#define CFG_NUM_SHOWENTS 16 #define CFGTYPE_MENU 1 -#define CFGTYPE_INT 2 +#define CFGTYPE_INT 2 #define CFGTYPE_DISK 3 #define CFGTYPE_FUNC 4 #define CFGTYPE_FILE 5 #define CFGTYPE_STR 6 +#define CFGTYPE_DIR 7 /* CFGTYPE limited to just 4 bits: 0-15 */ /* Cfg_menu, Cfg_dirent and Cfg_listhdr are defined in defc.h */ @@ -42,3 +42,33 @@ STRUCT(Cfg_defval) { int intval; char *strval; }; + + +int cfg_get_fd_size(char *filename); +int cfg_partition_read_block(FILE *file, void *buf, int blk, int blk_size); +int cfg_partition_find_by_name_or_num(FILE *file, const char *partnamestr, int part_num, Disk *dsk); +int cfg_maybe_insert_disk(int slot, int drive, const char *namestr); +int cfg_stat(char *path, struct stat *sb); +int cfg_partition_make_list(char *filename, FILE *file); +void cfg_htab_vtab(int x, int y); +void cfg_home(void); +void cfg_cleol(void); +void cfg_putchar(int c); +void cfg_printf(const char *fmt, ...); +void cfg_print_num(int num, int max_len); +void cfg_get_disk_name(char *outstr, int maxlen, int type_ext, int with_extras); +void cfg_parse_menu(Cfg_menu *menuptr, int menu_pos, int highlight_pos, int change); +void cfg_get_base_path(char *pathptr, const char *inptr, int go_up); +void cfg_file_init(void); +void cfg_free_alldirents(Cfg_listhdr *listhdrptr); +void cfg_file_add_dirent(Cfg_listhdr *listhdrptr, const char *nameptr, int is_dir, int size, int image_start, int part_num); +int cfg_dirent_sortfn(const void *obj1, const void *obj2); +int cfg_str_match(const char *str1, const char *str2, int len); +void cfg_file_readdir(const char *pathptr); +char *cfg_shorten_filename(const char *in_ptr, int maxlen); +void cfg_fix_topent(Cfg_listhdr *listhdrptr); +void cfg_file_draw(void); +void cfg_partition_selected(void); +void cfg_file_update_ptr(char *str); +void cfg_file_selected(int); +void cfg_file_handle_key(int key); diff --git a/src/config.txt b/src/config.txt new file mode 100644 index 0000000..60a8597 --- /dev/null +++ b/src/config.txt @@ -0,0 +1,45 @@ +# GSport configuration file version 0.4 + +s5d1 = +s5d2 = + +s6d1 = +s6d2 = + +s7d1 = + + + +bram1[00] = 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +bram1[10] = 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +bram1[20] = 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +bram1[30] = 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +bram1[40] = 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +bram1[50] = 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +bram1[60] = 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +bram1[70] = 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +bram1[80] = 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +bram1[90] = 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +bram1[a0] = 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +bram1[b0] = 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +bram1[c0] = 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +bram1[d0] = 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +bram1[e0] = 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +bram1[f0] = 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + +bram3[00] = 00 00 00 01 00 00 0d 06 02 01 01 00 01 00 00 00 +bram3[10] = 00 00 07 06 02 01 01 00 00 00 0f 06 06 00 05 06 +bram3[20] = 01 00 00 00 00 00 00 01 00 00 00 00 05 02 02 00 +bram3[30] = 00 00 2d 2d 00 00 00 00 00 00 02 02 02 06 08 00 +bram3[40] = 01 02 03 04 05 06 07 0a 00 01 02 03 04 05 06 07 +bram3[50] = 08 09 0a 0b 0c 0d 0e 0f 00 00 ff ff ff ff ff ff +bram3[60] = ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff +bram3[70] = ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff +bram3[80] = ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff +bram3[90] = ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff +bram3[a0] = ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff +bram3[b0] = ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff +bram3[c0] = ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff +bram3[d0] = ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff +bram3[e0] = ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff +bram3[f0] = ff ff ff ff ff ff ff ff ff ff ff ff 36 2d 9c 87 diff --git a/src/debug.c b/src/debug.c new file mode 100644 index 0000000..4be5793 --- /dev/null +++ b/src/debug.c @@ -0,0 +1,1520 @@ +/* + GSport - an Apple //gs Emulator + Copyright (C) 2010 - 2019 by GSport contributors + Copyright (C) 2016 - 2018 Dagen Brock + + Based on the KEGS emulator written by and Copyright (C) 2003 Kent Dickey + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 2 of the License, or (at your + option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "defc.h" +#include "debug.h" +#include "glog.h" + +// DISASSEMBLER STUFF +enum { + ABS = 1, ABSX, ABSY, ABSLONG, ABSIND, ABSXIND, IMPLY, ACCUM, IMMED, JUST8, + DLOC, DLOCX, DLOCY, LONG, LONGX, DLOCIND, DLOCINDY, DLOCXIND, DLOCBRAK, + DLOCBRAKY, DISP8, DISP8S, DISP8SINDY, DISP16, MVPMVN, REPVAL, SEPVAL +}; +extern const char * const disas_opcodes[256]; +extern const word32 disas_types[256]; + +// STEPPING/ENGINE STUFF +extern Engine_reg engine; +extern int g_config_control_panel; +extern int g_num_breakpoints; +extern word32 g_breakpts[MAX_BREAK_POINTS]; +int g_dbg_enable_port = 0; +int debug_pause = 0; +int g_dbg_step = 0; +int step_count = 0; + +// emulator command stuff +extern int g_limit_speed; +extern int g_screenshot_requested; + +// all the message types +typedef enum { + G_DBG_COMMAND_TEST = 0, + G_DBG_COMMAND_HELLO = 1, + G_DBG_COMMAND_STEP = 2, + G_DBG_COMMAND_CONTINUE = 3, + G_DBG_COMMAND_GET_CPU = 4, + G_DBG_COMMAND_SET_CPU = 5, + G_DBG_COMMAND_GET_MEM = 6, + G_DBG_COMMAND_SET_MEM = 7, + G_DBG_COMMAND_ADD_BRK = 8, + G_DBG_COMMAND_DEL_BRK = 9, + G_DBG_COMMAND_GET_BRK = 0xA, + G_DBG_COMMAND_PAUSE = 0xB, // deprecated + G_DBG_COMMAND_DEBUGGER = 0xC, // deprecated + G_DBG_COMMAND_QUIT = 0xD, // deprecated + G_DBG_COMMAND_EMU_CMD = 0xE +} G_DBG_COMMANDS; + + +// incoming commands - 1 char command + 256 char data +#define DBG_CMD_QUEUE_MAXLEN 50 +int dbg_cmd_queue_len = 0; +struct dbg_cmd +{ + unsigned int command; + char cdata[256]; +}; +struct dbg_cmd dbg_cmd_queue[DBG_CMD_QUEUE_MAXLEN]; + + + +// outgoing response messages - can be batched up +// this one can be bigger because it just has pointers to messages +// and we send multiple messages for debug (a "chain") +#define DBG_MSG_QUEUE_MAXLEN 30 +int dbg_msg_queue_len = 0; +struct dbg_msg +{ + unsigned int msg_size; + char *msg_str; +}; +struct dbg_msg dbg_msg_queue[DBG_MSG_QUEUE_MAXLEN]; + +extern int get_byte_at_address(int addr); +extern void set_byte_at_address(int addr, int value); + +//b64 funcs +int b64encode_len(int); +int b64encode(char *encoded, const char *string, int len); + + +void debug_wait_hello(); +void debug_setup_socket(); +void debug_pop_message(); +void debug_push_message(G_DBG_COMMANDS msg_type, char *msg_ptr, int msg_len); + + +void event_hello(); +void event_test_command(char *str); +void event_pause(); +void event_cpu_info(); +void event_set_cpu(); +void event_get_mem(char *str); +void event_did_step(int step_count); +void event_add_brk(char *str); +void event_del_brk(char *str); +void event_get_brk(); +void event_emu_cmd(char *str); +void event_set_mem(char *str); + + +void api_write_socket(); +void write_array_start(); +void write_array_end(); +void write_array_next(); +int writeStrToClient(int sckt, const char *str); + + + +int do_dis_json(char *buf, word32 kpc, int accsize, int xsize, int op_provided, word32 instr, int chain); + + +// derived from? +/// https://www.ibm.com/support/knowledgecenter/ssw_i5_54/rzab6/poll.htm +#define TRUE 1 +#define FALSE 0 + +int len, rc, on = 1; +int listen_sd = -1, new_sd = -1; +int desc_ready, end_server = FALSE, compress_array = FALSE; +int close_conn; +#define BUFFER_SIZE 128 +char buffer[BUFFER_SIZE]; +char tmp_buffer_4k[4097]; // adding +1 in case someone forgets \0 +char tmp_buffer2_4k[4097]; // adding +1 in case someone forgets \0 + +struct sockaddr_in addr; +int timeout; // poll timeout in ms +struct pollfd fds[200]; +int nfds = 0, current_size = 0, i, j; +int debugger_sd = -1; // this holds our socket file descriptor for the debugger, once attached + + + +/* socket debug version */ +void do_go_debug() { + while (1) { + if (g_dbg_step >= 0) { + if (g_dbg_step == 1) { + g_dbg_step = -1; // we are taking a step, so chill on the next round + } + g_config_control_panel = 0; + clear_halt(); + + + glog("calling run_prog()"); + run_prog(); // also calls debug_server_poll() + glog("left run_prog()"); + step_count++; + + // so this is a break... + // we need a pool waiter for a continue or go here + + event_did_step(step_count); + } + + timeout = 1000; + debug_server_poll(); + printf("."); + if (debug_events_waiting() > 0) { + timeout = 0; + debug_handle_event(); + } + g_config_control_panel = 1; + } +} + +// removes the message from the front of the queue and slides the rest over +void debug_pop_message() { + if (dbg_cmd_queue_len > 0) { + for (int i = 0; i< dbg_cmd_queue_len; i++) { + dbg_cmd_queue[i]=dbg_cmd_queue[i+1]; // does this copy bad stuff if we hit max? + } + dbg_cmd_queue_len--; + } +} + +// adds message to end of queue and ups the counter +void debug_push_message(G_DBG_COMMANDS msg_type, char *msg_ptr, int msg_len) { + glogf("debug_push_message() GOT: %d", (int) msg_type); + dbg_cmd_queue[dbg_cmd_queue_len].command = msg_type; + memcpy(dbg_cmd_queue[dbg_cmd_queue_len].cdata, msg_ptr, msg_len); // stripping that first char + dbg_cmd_queue[dbg_cmd_queue_len].cdata[msg_len+1] = '\0'; // terminator + dbg_cmd_queue_len++; // INC POINTER +} + +// this should be sufficient +int debug_events_waiting() { + return dbg_cmd_queue_len; +} + +// handle event onfront of queue and remove it +void debug_handle_event() { + while (debug_events_waiting() > 0) { + switch (dbg_cmd_queue[0].command) { + case G_DBG_COMMAND_TEST: //0 + event_test_command(dbg_cmd_queue[0].cdata); + break; + case G_DBG_COMMAND_HELLO: //1 + event_hello(); + break; + case G_DBG_COMMAND_PAUSE: //2 + event_pause(); + break; + case G_DBG_COMMAND_STEP: //3 + if (g_dbg_step == -1) { + g_dbg_step = 1; // take a step + } else { + g_dbg_step = -1; // first one just halts + } + break; + case G_DBG_COMMAND_CONTINUE: //4 + g_dbg_step = 0; + step_count = 0; + break; + case G_DBG_COMMAND_GET_MEM: //6 + event_get_mem(dbg_cmd_queue[0].cdata); + break; + case G_DBG_COMMAND_SET_MEM: //7 + event_set_mem(dbg_cmd_queue[0].cdata); + break; + case G_DBG_COMMAND_QUIT: + exit(0); // HALT! + break; + case G_DBG_COMMAND_DEBUGGER: + do_debug_intfc(); + break; + case G_DBG_COMMAND_SET_CPU: + event_set_cpu(&dbg_cmd_queue[0].cdata); + break; + case G_DBG_COMMAND_GET_CPU: + event_cpu_info(); + break; + case G_DBG_COMMAND_ADD_BRK: + event_add_brk(dbg_cmd_queue[0].cdata); + break; + case G_DBG_COMMAND_DEL_BRK: + event_del_brk(dbg_cmd_queue[0].cdata); + break; + case G_DBG_COMMAND_GET_BRK: + event_get_brk(dbg_cmd_queue[0].cdata); + break; + case G_DBG_COMMAND_EMU_CMD: + event_emu_cmd(dbg_cmd_queue[0].cdata); + break; + default: + break; + } + debug_pop_message(); + } +} + +void push_api_msg(int size, char *msg_str) { + if (dbg_msg_queue_len < DBG_MSG_QUEUE_MAXLEN) { + dbg_msg_queue[dbg_msg_queue_len].msg_size = size; + dbg_msg_queue[dbg_msg_queue_len].msg_str = msg_str; + //printf("Latest message : \n%s\n", dbg_msg_queue[dbg_msg_queue_len].msg_str); + dbg_msg_queue_len++; // INC POINTER + } else { + glog("ABORT! Message dropped because dbg_msg_queue is full."); + } +} + +void api_push_memack() { + int size = snprintf(tmp_buffer_4k, sizeof(tmp_buffer_4k),"{\"type\":\"memack\"}"); + char *msg = (char*)malloc(sizeof(char) * size); + strcpy(msg,tmp_buffer_4k); + push_api_msg(size, msg); +} + +void api_push_cpu() { + Engine_reg *eptr; + eptr = &engine; + int tmp_acc, tmp_x, tmp_y, tmp_psw; + int kpc, direct_page, dbank, stack; + + kpc = eptr->kpc; + tmp_acc = eptr->acc; + direct_page = eptr->direct; + dbank = eptr->dbank; + stack = eptr->stack; + tmp_x = eptr->xreg; + tmp_y = eptr->yreg; + tmp_psw = eptr->psr; + + int size = snprintf(tmp_buffer_4k, sizeof(tmp_buffer_4k),"{\"type\":\"cpu\",\"data\":{\"K\":\"%02X\",\"PC\":\"%04X\",\"A\":\"%04X\"," \ + "\"X\":\"%04X\",\"Y\":\"%04X\",\"S\":\"%04X\",\"D\":\"%04X\",\"B\":\"%02X\",\"PSR\":\"%04X\"}}", + kpc>>16, kpc & 0xffff,tmp_acc,tmp_x,tmp_y,stack,direct_page,dbank, tmp_psw & 0xFFF); + + char *msg = (char*)malloc(sizeof(char) * size); + strcpy(msg,tmp_buffer_4k); + push_api_msg(size, msg); +} + +void api_push_brk() { + int i; + // build our json array of breakpoints + tmp_buffer2_4k[0] = '\0'; // start with empty string + char *str_ptr = tmp_buffer2_4k; + for(i = 0; i < g_num_breakpoints; i++) { + //printf("{\"bp:%02x: %06x\n", i, g_breakpts[i]); + str_ptr += sprintf(str_ptr, "{\"trig\":\"addr\",\"match\":\"%06X\"}", g_breakpts[i]); + if (i < g_num_breakpoints-1) { + str_ptr += sprintf(str_ptr, ","); + } + } + str_ptr = tmp_buffer2_4k; // reset pointer to beginning of string + + int size = snprintf(tmp_buffer_4k, sizeof(tmp_buffer_4k),"{\"type\":\"brk\",\"data\":{\"breakpoints\":[%s]}}", str_ptr); + + char *msg = (char*)malloc(sizeof(char) * size); + strcpy(msg,tmp_buffer_4k); + push_api_msg(size, msg); +} + + +void api_push_stack() { + Engine_reg *eptr; + eptr = &engine; + int kpc, stack; + + kpc = eptr->kpc; + stack = eptr->stack; + word32 stack_loc = (kpc & 0xff0000) + (stack & 0xff00); // e.g. 0x00000100 (default) or 0x00FF0100 (GS Boot) + + // build our json array of 256 stack values ($nn00-nnFF) + char *str_ptr = tmp_buffer2_4k; // (1024B) + for (int i = 0; i<256; i++ ) { + unsigned int instruction = (int)get_memory_c(stack_loc+i, 0) & 0xff; + str_ptr += sprintf(str_ptr, "\"%02X\"", instruction); + if (i < 255) { + str_ptr += sprintf(str_ptr, ","); + } + } + str_ptr = tmp_buffer2_4k; // reset pointer to beginning of string + + int size = snprintf(tmp_buffer_4k, sizeof(tmp_buffer_4k),"{\"type\":\"stack\",\"data\":{\"loc\":\"%06X\",\"S\":\"%04X\",\"bytes\":[%s]}}", + stack_loc,stack,str_ptr); + + char *msg = (char*)malloc(sizeof(char) * size); + strcpy(msg,tmp_buffer_4k); + push_api_msg(size, msg); +} + + +void api_push_disassembly_start() { + int size = snprintf(tmp_buffer_4k, sizeof(tmp_buffer_4k),"{\"type\":\"dis0\"}"); + char *msg = (char*)malloc(sizeof(char) * size); + strcpy(msg,tmp_buffer_4k); + push_api_msg(size, msg); +} + + +void api_push_disassembly() { + int byte_size; + int size_mem_imm, size_x_imm; + + + // check accumulator size + size_mem_imm = 2; + if(engine.psr & 0x20) { + size_mem_imm = 1; + } + // check xy size + size_x_imm = 2; + if(engine.psr & 0x10) { + size_x_imm = 1; + } + + //disassemble chain from now -> to -> future + int disassemble_next = 10; // how many instructions + int kpc = engine.kpc; // get starting address + for (int i = 0; i= 0 && int_value <= 3) { + printf("Changing speed from %d to -> %d\n", g_limit_speed, int_value); + g_limit_speed = int_value; + } else { + printf("Specified speed out of range (%d)\n", int_value); + } + break; + case 'v': + g_screenshot_requested = 1; + break; + } +} + +void event_emu_cmd(char *str) { + // split our commands on spaces + char cmd_char = '\0'; + char *cmd_data = NULL; + + char * pch; + pch = strtok (str," "); + while (pch != NULL) + { + cmd_char = pch[0]; + cmd_data = pch+1; + if (cmd_data[0] == '\0') { + cmd_data = NULL; + } + // for each token go try to handle it + handle_emu_cmd(cmd_char, cmd_data); + + pch = strtok (NULL, " "); + } + return; +} + + +void event_add_brk(char *str) { + int addr = 0; + sscanf(str, "%06X", &addr); + addr = addr & 0xFFFFFF; // 24 bit KPC address for 65816 + set_bp(addr); + api_push_brk(); + api_write_socket(); + + return; +} + + +void event_del_brk(char *str) { + int addr = 0; + sscanf(str, "%06X", &addr); + addr = addr & 0xFFFFFF; // 24 bit KPC address for 65816 + delete_bp(addr); + api_push_brk(); + api_write_socket(); + + return; +} + + +void event_get_brk(char *str) { + api_push_brk(); + api_write_socket(); + + return; +} + + +void handle_cpu_cmd(char cmd_char, char *cmd_data) { + Engine_reg *eptr; + eptr = &engine; + int new_acc, new_x, new_y; + int new_kpc, new_d, new_b, new_s, new_psr; + + switch (cmd_char) { + case 'k': + sscanf(cmd_data, "%06x", &new_kpc); + new_kpc &= 0xFFFFFF; // 24-bit clamp + eptr->kpc = new_kpc; + break; + case 'a': + sscanf(cmd_data, "%04x", &new_acc); + new_acc &= 0xFFFF; // 24-bit clamp + eptr->acc = new_acc; + break; + case 'x': + sscanf(cmd_data, "%04x", &new_x); + new_x &= 0xFFFF; // 24-bit clamp + eptr->xreg = new_x; + break; + case 'y': + sscanf(cmd_data, "%04x", &new_y); + new_y &= 0xFFFF; // 24-bit clamp + eptr->yreg = new_y; + break; + case 's': + sscanf(cmd_data, "%04x", &new_s); + new_s &= 0xFFFF; // 24-bit clamp + eptr->stack = new_s; + break; + case 'd': + sscanf(cmd_data, "%04x", &new_d); + new_d &= 0xFFFF; // 24-bit clamp + eptr->direct = new_d; + break; + case 'b': + sscanf(cmd_data, "%02x", &new_b); + new_b &= 0xFF; // 24-bit clamp + eptr->dbank = new_b; + break; + case 'p': + sscanf(cmd_data, "%04x", &new_psr); + new_psr &= 0xFFFF; // 24-bit clamp + eptr->psr = new_psr; + break; + default: + printf("UNKNOWN CPU COMMAND\n"); + break; + } +} + + +void event_set_cpu(char *str) { + // split our commands on spaces + char cmd_char = '\0'; + char *cmd_data = NULL; + + char * pch; + pch = strtok (str," "); + while (pch != NULL) { + cmd_char = pch[0]; + cmd_data = pch+1; + if (cmd_data[0] == '\0') { + cmd_data = NULL; + } + // for each token go try to handle it + handle_cpu_cmd(cmd_char, cmd_data); + + pch = strtok (NULL, " "); + } + + api_push_stack(); + api_push_cpu(); + api_push_disassembly(); + + api_write_socket(); +} + + +void debug_init() { + if (g_dbg_enable_port > 0) { + // g_dbg_enable_port should be enabled by + glogf("Debug port enabled on: %d", g_dbg_enable_port); + debug_setup_socket(); + debug_server_poll(); + debug_wait_hello(); + // message is not popped off here because default behavior to send our cpu hello info to client + } else { + end_server = TRUE; + glog("Debug port not enabled"); + } +} + + +void debug_setup_socket() { + /*************************************************************/ + /* Create an AF_INET stream socket to receive incoming */ + /* connections on */ + /*************************************************************/ + listen_sd = socket(AF_INET, SOCK_STREAM, 0); + if (listen_sd < 0) { + perror("socket() failed"); + exit(-1); + } + + + /*************************************************************/ + /* Allow socket descriptor to be reuseable */ + /*************************************************************/ + rc = setsockopt(listen_sd, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof(on)); + if (rc < 0) { + perror("setsockopt() failed"); + close(listen_sd); + exit(-1); + } + + /*************************************************************/ + /* Set socket to be nonblocking. All of the sockets for */ + /* the incoming connections will also be nonblocking since */ + /* they will inherit that state from the listening socket. */ + /*************************************************************/ + //rc = ioctl(listen_sd, FIONBIO, (char *)&on); + int flags = fcntl(listen_sd, F_GETFL, 0); + rc = fcntl(listen_sd, F_SETFL, flags | O_NONBLOCK); + if (rc < 0) { + perror("ioctl()/fcntl() failed"); + close(listen_sd); + exit(-1); + } + + /*************************************************************/ + /* Bind the socket */ + /*************************************************************/ + memset(&addr, 0, sizeof(addr)); + addr.sin_family = AF_INET; + addr.sin_addr.s_addr = htonl(INADDR_ANY); + addr.sin_port = htons(g_dbg_enable_port); + rc = bind(listen_sd, (struct sockaddr *)&addr, sizeof(addr)); + if (rc < 0) { + perror("bind() failed"); + close(listen_sd); + exit(-1); + } + + /*************************************************************/ + /* Set the listen back log */ + /*************************************************************/ + rc = listen(listen_sd, 32); + if (rc < 0) { + perror("listen() failed"); + close(listen_sd); + exit(-1); + } + + /*************************************************************/ + /* Initialize the pollfd structure */ + /*************************************************************/ + memset(fds, 0, sizeof(fds)); + + /*************************************************************/ + /* Set up the initial listening socket */ + /*************************************************************/ + fds[0].fd = listen_sd; + fds[0].events = POLLIN; + nfds = 1; + /*************************************************************/ + /* Initialize the timeout to 3 minutes. If no */ + /* activity after 3 minutes this program will end. */ + /* timeout value is based on milliseconds. */ + /*************************************************************/ + timeout = (3 * 60 * 1000); +} + + +// builds our big json array of commands eg "[{},{},{},...]" +void api_write_socket() { + const char *comma = ","; + const char *lbrack = "["; + const char *rbrack = "]\r\n\r\n"; + unsigned int message_size = 0; + char *message_string = NULL; + for (int i = 0; i < dbg_msg_queue_len; i++) { + message_size = message_size + dbg_msg_queue[i].msg_size; // for sub-string sizes + } + message_size += dbg_msg_queue_len; // for "," + message_size += strlen(lbrack) + strlen(rbrack); // for "[]" + "\0" + message_string = malloc(sizeof(char)*message_size); + message_string[0] = '\0'; // necessary? + + char *str_ptr = message_string; // message_string is alloc'd above to message_size + str_ptr = strcat(str_ptr, lbrack); // "[" + for (int i = 0; i < dbg_msg_queue_len; i++) { + str_ptr = strcat(str_ptr, dbg_msg_queue[i].msg_str); + if (dbg_msg_queue_len > 1 && i < dbg_msg_queue_len-1) { // only split with comma if more than 1 item and not last item + str_ptr = strcat(str_ptr, comma); // "," + } + free(dbg_msg_queue[i].msg_str); // here we go! oh boy! + } + str_ptr = strcat(str_ptr, rbrack); // "]" + // message_string is now built! we can send it. + dbg_msg_queue_len = 0; // clear msg queue + + writeStrToClient(debugger_sd, message_string); // ignores result + free(message_string); // assuming it was all written :P +} + + +void write_array_start() { + const char *brack = "["; + write(debugger_sd, brack, strlen(brack)); +} + + +void write_array_end() { + const char *brack = "]\r\n\r\n"; + write(debugger_sd, brack, strlen(brack)); +} + + +void write_array_next() { + const char *com = ", "; // i'm so neat + write(debugger_sd, com, strlen(com)); +} + + +// // write(debugger_sd, buffer, strlen(buffer)); +//also for base 64 http://stackoverflow.com/questions/342409/how-do-i-base64-encode-decode-in-c +//http://stackoverflow.com/questions/32749925/sending-a-file-over-a-tcp-ip-socket-web-server +int writeDataToClient(int sckt, const void *data, int datalen) { + const char *pdata = (const char*) data; + + while (datalen > 0) { + int numSent = send(sckt, pdata, datalen, 0); + if (numSent <= 0) { + if (numSent == 0) { + printf("The client was not written to: disconnected\n"); + } else { + perror("The client was not written to"); + } + return FALSE; + } + pdata += numSent; + datalen -= numSent; + } + + return TRUE; +} + + +int writeStrToClient(int sckt, const char *str) { + return writeDataToClient(sckt, str, strlen(str)); +} + + +// @todo: probably clean up- this was a hack to allow preloading commands +void debug_wait_hello() { + int hello_received = FALSE; + timeout = 1000; // 1 sec + while (hello_received == FALSE) { + debug_server_poll(); + if (debug_events_waiting() > 0) { + if (dbg_cmd_queue[0].command == G_DBG_COMMAND_HELLO) { + hello_received = TRUE; + } else { + debug_handle_event(); + } + } + + } + timeout = 0; // instantaneous +} + + +void debug_server_poll() { + if (end_server == FALSE) { + /***********************************************************/ + /* Call poll() and wait for it to complete/timeout. */ + /***********************************************************/ + rc = poll(fds, nfds, timeout); + + /***********************************************************/ + /* Check to see if the poll call failed. */ + /***********************************************************/ + if (rc < 0) { + perror(" poll() failed"); + return; // @todo: break/exit? + } + + /***********************************************************/ + /* Check to see if the 3 minute time out expired. */ + /***********************************************************/ + if (rc == 0) { + return; // @todo: break/exit? + } + + + /***********************************************************/ + /* One or more descriptors are readable. Need to */ + /* determine which ones they are. */ + /***********************************************************/ + current_size = nfds; + for (i = 0; i < current_size; i++) { + /*********************************************************/ + /* Loop through to find the descriptors that returned */ + /* POLLIN and determine whether it's the listening */ + /* or the active connection. */ + /*********************************************************/ + if(fds[i].revents == 0) { + continue; + } + + /*********************************************************/ + /* If revents is not POLLIN, it's an unexpected result, */ + /* log and end the server. */ + /*********************************************************/ + if(fds[i].revents != POLLIN) { + glogf("Error! revents = %d", fds[i].revents); + end_server = TRUE; + break; + } + + if (fds[i].fd == listen_sd) { + /*******************************************************/ + /* Listening descriptor is readable. */ + /*******************************************************/ + glog("Listening socket is readable"); + + /*******************************************************/ + /* Accept all incoming connections that are */ + /* queued up on the listening socket before we */ + /* loop back and call poll again. */ + /*******************************************************/ + do { + /*****************************************************/ + /* Accept each incoming connection. If */ + /* accept fails with EWOULDBLOCK, then we */ + /* have accepted all of them. Any other */ + /* failure on accept will cause us to end the */ + /* server. */ + /*****************************************************/ + new_sd = accept(listen_sd, NULL, NULL); + if (new_sd < 0) { + if (errno != EWOULDBLOCK) { + perror(" accept() failed"); + end_server = TRUE; + } + break; + } + + /*****************************************************/ + /* Add the new incoming connection to the */ + /* pollfd structure */ + /*****************************************************/ + glogf("New incoming connection - %d", new_sd); + fds[nfds].fd = new_sd; + fds[nfds].events = POLLIN; + nfds++; + + // just set it and forget it :P + debugger_sd = new_sd; + timeout = 0; + + /*****************************************************/ + /* Loop back up and accept another incoming */ + /* connection */ + /*****************************************************/ + } while (new_sd != -1); + } + + /*********************************************************/ + /* This is not the listening socket, therefore an */ + /* existing connection must be readable */ + /*********************************************************/ + + else { + //printf(" Descriptor %d is readable\n", fds[i].fd); + close_conn = FALSE; + /*******************************************************/ + /* Receive all incoming data on this socket */ + /* before we loop back and call poll again. */ + /*******************************************************/ + + do { + /*****************************************************/ + /* Receive data on this connection until the */ + /* recv fails with EWOULDBLOCK. If any other */ + /* failure occurs, we will close the */ + /* connection. */ + /*****************************************************/ + rc = recv(fds[i].fd, buffer, sizeof(buffer), 0); + if (rc < 0) { + if (errno != EWOULDBLOCK) { + perror("recv() failed"); + close_conn = TRUE; + } + break; + } + + + /*****************************************************/ + /* Check to see if the connection has been */ + /* closed by the client */ + /*****************************************************/ + if (rc == 0) { + glog("Connection closed\n"); + close_conn = TRUE; + end_server = TRUE; + break; + } + + /*****************************************************/ + /* Data was received */ + /*****************************************************/ + len = rc; + char *mesg_ptr = buffer; + char *split_ptr = strchr(mesg_ptr, '\n'); + + int mesg_len = len-1; // stripping that first char + if(split_ptr) { + int index = split_ptr - buffer; + mesg_len = index - 1; // stripping that first char + } + int debug_echo = FALSE; + while (mesg_ptr < buffer + len - 1) { + // DO DEBUG QUEUE + if (dbg_cmd_queue_len < DBG_CMD_QUEUE_MAXLEN) { + switch (mesg_ptr[0]) { + case '0': + debug_push_message(G_DBG_COMMAND_TEST, mesg_ptr+1, mesg_len); + break; + case '1': + debug_push_message(G_DBG_COMMAND_HELLO, mesg_ptr+1, mesg_len); + break; + case '2': + debug_push_message(G_DBG_COMMAND_STEP, mesg_ptr+1, mesg_len); + break; + case '3': + debug_push_message(G_DBG_COMMAND_CONTINUE, mesg_ptr+1, mesg_len); + break; + case '4': + debug_push_message(G_DBG_COMMAND_GET_CPU, mesg_ptr+1, mesg_len); + break; + case '5': + debug_push_message(G_DBG_COMMAND_SET_CPU, mesg_ptr+1, mesg_len); + break; + case '6': + debug_push_message(G_DBG_COMMAND_GET_MEM, mesg_ptr+1, mesg_len); + break; + case '7': + debug_push_message(G_DBG_COMMAND_SET_MEM, mesg_ptr+1, mesg_len); + break; + case '8': + debug_push_message(G_DBG_COMMAND_ADD_BRK, mesg_ptr+1, mesg_len); + break; + case '9': + debug_push_message(G_DBG_COMMAND_DEL_BRK, mesg_ptr+1, mesg_len); + break; + case 'a': + debug_push_message(G_DBG_COMMAND_GET_BRK, mesg_ptr+1, mesg_len); + break; + + case 'b': // DEPRECATED + debug_push_message(G_DBG_COMMAND_PAUSE, mesg_ptr+1, mesg_len); + break; + case 'c': // DEPRECATED + debug_push_message(G_DBG_COMMAND_DEBUGGER, mesg_ptr+1, mesg_len); + break; + case 'd': // DEPRECATED ???? + debug_push_message(G_DBG_COMMAND_QUIT, mesg_ptr+1, mesg_len); + break; + + case 'e': + debug_push_message(G_DBG_COMMAND_EMU_CMD, mesg_ptr+1, mesg_len); + break; + + default: + glog("UNKNOWN COMMAND - DISCARDED"); + } + + + } else { + glog("COMMAND QUEUE FULL! ABORT!"); + // @TODO probably send error response + } + + mesg_ptr += mesg_len + 2; // +1 for command char and +1 for '\n' + split_ptr = strchr(mesg_ptr, '\n'); + if(split_ptr) { + int index = split_ptr - mesg_ptr; + mesg_len = index - 1; // stripping that first char + } + } + /*****************************************************/ + /* Echo the data back to the client */ + /*****************************************************/ + if (debug_echo) { + rc = send(fds[i].fd, buffer, len, 0); + if (rc < 0) { + perror(" send() failed"); + close_conn = TRUE; + break; + } + } + + // clear our buffer + memset(buffer, 0, sizeof(buffer)); + + } while(TRUE); + + /*******************************************************/ + /* If the close_conn flag was turned on, we need */ + /* to clean up this active connection. This */ + /* clean up process includes removing the */ + /* descriptor. */ + /*******************************************************/ + if (close_conn) { + close(fds[i].fd); + fds[i].fd = -1; + compress_array = TRUE; + } + + } /* End of existing connection is readable */ + } /* End of loop through pollable descriptors */ + + /***********************************************************/ + /* If the compress_array flag was turned on, we need */ + /* to squeeze together the array and decrement the number */ + /* of file descriptors. We do not need to move back the */ + /* events and revents fields because the events will always*/ + /* be POLLIN in this case, and revents is output. */ + /***********************************************************/ + if (compress_array) { + compress_array = FALSE; + for (i = 0; i < nfds; i++) { + if (fds[i].fd == -1) { + for(j = i; j < nfds; j++) { + fds[j].fd = fds[j+1].fd; + } + nfds--; + } + } + } + } else { + // end_server == TRUE // @TODO handle server exit (and multiple clients?) + /*************************************************************/ + /* Clean up all of the sockets that are open */ + /*************************************************************/ + for (i = 0; i < nfds; i++) { + if(fds[i].fd >= 0) + close(fds[i].fd); + } + nfds = 0; + } +} + + +int do_dis_json(char *buf, word32 kpc, int accsize, int xsize, int op_provided, word32 instr, int chain) { + char buf_instructions[5*5]; // '["12","DE","AB"]' + char buf_disasm[50]; + + + const char *out; + int args, type; + int opcode; + word32 val; + word32 oldkpc; + word32 dtype; + int signed_val; + + oldkpc = kpc; + if(op_provided) { + opcode = (instr >> 24) & 0xff; + } else { + opcode = (int)get_memory_c(kpc, 0) & 0xff; + } + + kpc++; + + dtype = disas_types[opcode]; + out = disas_opcodes[opcode]; + type = dtype & 0xff; + args = dtype >> 8; + + if(args > 3) { + if(args == 4) { + args = accsize; + } else if(args == 5) { + args = xsize; + } + } + + val = -1; + switch(args) { + case 0: + val = 0; + break; + case 1: + if(op_provided) { + val = instr & 0xff; + } else { + val = get_memory_c(kpc, 0); + } + break; + case 2: + if(op_provided) { + val = instr & 0xffff; + } else { + val = get_memory16_c(kpc, 0); + } + break; + case 3: + if(op_provided) { + val = instr & 0xffffff; + } else { + val = get_memory24_c(kpc, 0); + } + break; + default: + fprintf(stderr, "args out of range: %d, opcode: %08x\n", + args, opcode); + break; + } + kpc += args; + + if(!op_provided) { + instr = (opcode << 24) | (val & 0xffffff); + } + + switch(type) { + case ABS: + if(args != 2) { + printf("arg # mismatch for opcode %x\n", opcode); + } + sprintf(buf_disasm,"%s $%04x",out,val); + break; + case ABSX: + if(args != 2) { + printf("arg # mismatch for opcode %x\n", opcode); + } + sprintf(buf_disasm,"%s $%04x,X",out,val); + break; + case ABSY: + if(args != 2) { + printf("arg # mismatch for opcode %x\n", opcode); + } + sprintf(buf_disasm,"%s $%04x,Y",out,val); + break; + case ABSLONG: + if(args != 3) { + printf("arg # mismatch for opcode %x\n", opcode); + } + sprintf(buf_disasm,"%s $%06x",out,val); + break; + case ABSIND: + if(args != 2) { + printf("arg # mismatch for opcode %x\n", opcode); + } + sprintf(buf_disasm,"%s ($%04x)",out,val); + break; + case ABSXIND: + if(args != 2) { + printf("arg # mismatch for opcode %x\n", opcode); + } + sprintf(buf_disasm,"%s ($%04x,X)",out,val); + break; + case IMPLY: + if(args != 0) { + printf("arg # mismatch for opcode %x\n", opcode); + } + sprintf(buf_disasm,"%s",out); + break; + case ACCUM: + if(args != 0) { + printf("arg # mismatch for opcode %x\n", opcode); + } + sprintf(buf_disasm,"%s",out); + break; + case IMMED: + if(args == 1) { + sprintf(buf_disasm,"%s #$%02x",out,val); + } else if(args == 2) { + sprintf(buf_disasm,"%s #$%04x",out,val); + } else { + printf("arg # mismatch for opcode %x\n", opcode); + } + break; + case JUST8: + if(args != 1) { + printf("arg # mismatch for opcode %x\n", opcode); + } + sprintf(buf_disasm,"%s $%02x",out,val); + break; + case DLOC: + if(args != 1) { + printf("arg # mismatch for opcode %x\n", opcode); + } + sprintf(buf_disasm,"%s $%02x",out,val); + break; + case DLOCX: + if(args != 1) { + printf("arg # mismatch for opcode %x\n", opcode); + } + sprintf(buf_disasm,"%s $%02x,X",out,val); + break; + case DLOCY: + if(args != 1) { + printf("arg # mismatch for opcode %x\n", opcode); + } + sprintf(buf_disasm,"%s $%02x,Y",out,val); + break; + case LONG: + if(args != 3) { + printf("arg # mismatch for opcode %x\n", opcode); + } + sprintf(buf_disasm,"%s $%06x",out,val); + break; + case LONGX: + if(args != 3) { + printf("arg # mismatch for opcode %x\n", opcode); + } + sprintf(buf_disasm,"%s $%06x,X",out,val); + break; + case DLOCIND: + if(args != 1) { + printf("arg # mismatch for opcode %x\n", opcode); + } + sprintf(buf_disasm,"%s ($%02x)",out,val); + break; + case DLOCINDY: + if(args != 1) { + printf("arg # mismatch for opcode %x\n", opcode); + } + sprintf(buf_disasm,"%s ($%02x),Y",out,val); + break; + case DLOCXIND: + if(args != 1) { + printf("arg # mismatch for opcode %x\n", opcode); + } + sprintf(buf_disasm,"%s ($%02x,X)",out,val); + break; + case DLOCBRAK: + if(args != 1) { + printf("arg # mismatch for opcode %x\n", opcode); + } + sprintf(buf_disasm,"%s [$%02x]",out,val); + break; + case DLOCBRAKY: + if(args != 1) { + printf("arg # mismatch for opcode %x\n", opcode); + } + sprintf(buf_disasm,"%s [$%02x],y",out,val); + break; + case DISP8: + if(args != 1) { + printf("arg # mismatch for opcode %x\n", opcode); + } + signed_val = (signed char)val; + sprintf(buf_disasm,"%s $%04x",out, + (word32)(kpc+(signed_val)) & 0xffff); + break; + case DISP8S: + if(args != 1) { + printf("arg # mismatch for opcode %x\n", opcode); + } + sprintf(buf_disasm,"%s $%02x,S",out,(word32)(byte)(val)); + break; + case DISP8SINDY: + if(args != 1) { + printf("arg # mismatch for opcode %x\n", opcode); + } + sprintf(buf_disasm,"%s ($%02x,S),Y",out,(word32)(byte)(val)); + break; + case DISP16: + if(args != 2) { + printf("arg # mismatch for opcode %x\n", opcode); + } + sprintf(buf_disasm,"%s $%04x", out, + (word32)(kpc+(signed)(word16)(val)) & 0xffff); + break; + case MVPMVN: + if(args != 2) { + printf("arg # mismatch for opcode %x\n", opcode); + } + sprintf(buf_disasm,"%s $%02x,$%02x",out,val&0xff,val>>8); + break; + case SEPVAL: + case REPVAL: + if(args != 1) { + printf("arg # mismatch for opcode %x\n", opcode); + } + sprintf(buf_disasm,"%s #$%02x",out,val); + break; + default: + printf("argument type: %d unexpected\n", type); + break; + } + + + // gross + word32 operand = instr; + opcode = (operand >> 24) & 0xff; + switch (args+1) { + case 1: + snprintf(buf_instructions, sizeof(buf_instructions),"[\"%02X\"]", opcode); + break; + case 2: + snprintf(buf_instructions, sizeof(buf_instructions),"[\"%02X\",\"%02X\"]", opcode, instr & 0xff); + break; + case 3: + snprintf(buf_instructions, sizeof(buf_instructions),"[\"%02X\",\"%02X\",\"%02X\"]", opcode, instr & 0xff, (instr & 0xff00) >> 8); + break; + case 4: + snprintf(buf_instructions, sizeof(buf_instructions),"[\"%02X\",\"%02X\",\"%02X\",\"%02X\"]", opcode, instr & 0xff, (instr & 0xff00) >> 8, (instr & 0xff0000) >> 16); + break; + default: + break; + } + + + // @TODO: FIX!!! NEEDS REAL BUFFER SIZE, note magic 1024 + snprintf(buf, 1024,"{\"type\":\"dis\",\"data\":{\"K\":\"%02X\",\"PC\":\"%04X\",\"bytes\":%s," \ + "\"disasm\":\"%s\",\"chain\":\"%d\"}}", + oldkpc>>16, oldkpc & 0xffff,buf_instructions, buf_disasm, chain); + return(args+1); +} + +// BASE 64 ENCODER (FOR MEMORY DUMPS) +static const char b64chars[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + +int b64encode_len(int len) { + return ((len + 2) / 3 * 4) + 1; +} + +int b64encode(char *encoded, const char *string, int len) { + int i; + char *p; + + p = encoded; + // encode a chunk of 4 chars + for (i = 0; i < len - 2; i += 3) { + *p++ = b64chars[(string[i] >> 2) & 0x3F]; + *p++ = b64chars[((string[i] & 0x3) << 4) | ((int) (string[i + 1] & 0xF0) >> 4)]; + *p++ = b64chars[((string[i + 1] & 0xF) << 2) | ((int) (string[i + 2] & 0xC0) >> 6)]; + *p++ = b64chars[string[i + 2] & 0x3F]; + } + // end chunk + if (i < len) { + *p++ = b64chars[(string[i] >> 2) & 0x3F]; + + if (i == (len - 1)) { + *p++ = b64chars[((string[i] & 0x3) << 4)]; + *p++ = '='; + } else { + *p++ = b64chars[((string[i] & 0x3) << 4) | + ((int) (string[i + 1] & 0xF0) >> 4)]; + *p++ = b64chars[((string[i + 1] & 0xF) << 2)]; + } + *p++ = '='; + } + // terminator + *p++ = '\0'; + //printf("ENCODED : %d\n", p-encoded); + return p - encoded; +} diff --git a/src/debug.h b/src/debug.h new file mode 100644 index 0000000..c3652eb --- /dev/null +++ b/src/debug.h @@ -0,0 +1,30 @@ +/* + GSport - an Apple //gs Emulator + Copyright (C) 2010 - 2019 by GSport contributors + Copyright (C) 2016 - 2018 Dagen Brock + + Based on the KEGS emulator written by and Copyright (C) 2003 Kent Dickey + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 2 of the License, or (at your + option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +extern void debug_init(); +extern void debug_poll_only(); +extern void debug_cpu_test(); + +// used in sim65816.c +void debug_server_poll(); +int debug_events_waiting(); +void debug_handle_event(); diff --git a/src/defc.h b/src/defc.h index 9283d7e..8a0b7e8 100644 --- a/src/defc.h +++ b/src/defc.h @@ -1,6 +1,7 @@ /* GSport - an Apple //gs Emulator - Copyright (C) 2010 by GSport contributors + Copyright (C) 2010 - 2019 by GSport contributors + Copyright (C) 2016 - 2018 Dagen Brock Based on the KEGS emulator written by and Copyright (C) 2003 Kent Dickey @@ -21,15 +22,15 @@ #include "defcomm.h" -// OG redirect printf to console -#ifdef ACTIVEGS -#include -extern "C" int outputInfo(const char* format,...); -extern "C" int fOutputInfo(FILE*,const char* format,...); -#define printf outputInfo -#define fprintf fOutputInfo -#endif - +// OG redirect printf to console +#ifdef ACTIVEGS +#include +extern "C" int outputInfo(const char* format,...); +extern "C" int fOutputInfo(FILE*,const char* format,...); +#define printf outputInfo +#define fprintf fOutputInfo +#endif + #define STRUCT(a) typedef struct _ ## a a; struct _ ## a typedef unsigned char byte; @@ -44,30 +45,31 @@ typedef unsigned long long word64; void U_STACK_TRACE(); /* 28MHz crystal, plus every 65th 1MHz cycle is stretched 140ns */ -#define CYCS_28_MHZ (28636360) -#define DCYCS_28_MHZ (1.0*CYCS_28_MHZ) -#define CYCS_3_5_MHZ (CYCS_28_MHZ/8) -#define DCYCS_1_MHZ ((DCYCS_28_MHZ/28.0)*(65.0*7/(65.0*7+1.0))) -#define CYCS_1_MHZ ((int)DCYCS_1_MHZ) +#define CYCS_28_MHZ (28636360) +#define DCYCS_28_MHZ (1.0*CYCS_28_MHZ) +#define CYCS_3_5_MHZ (CYCS_28_MHZ/8) +#define DCYCS_1_MHZ ((DCYCS_28_MHZ/28.0)*(65.0*7/(65.0*7+1.0))) +#define CYCS_1_MHZ ((int)DCYCS_1_MHZ) /* #define DCYCS_IN_16MS_RAW (DCYCS_1_MHZ / 60.0) */ -#define DCYCS_IN_16MS_RAW (262.0 * 65.0) +#define DCYCS_IN_16MS_RAW (262.0 * 65.0) /* Use precisely 17030 instead of forcing 60 Hz since this is the number of */ /* 1MHz cycles per screen */ -#define DCYCS_IN_16MS ((double)((int)DCYCS_IN_16MS_RAW)) -#define DRECIP_DCYCS_IN_16MS (1.0 / (DCYCS_IN_16MS)) +#define DCYCS_IN_16MS ((double)((int)DCYCS_IN_16MS_RAW)) +#define DRECIP_DCYCS_IN_16MS (1.0 / (DCYCS_IN_16MS)) #ifdef GSPORT_LITTLE_ENDIAN -# define BIGEND(a) ((((a) >> 24) & 0xff) + \ - (((a) >> 8) & 0xff00) + \ - (((a) << 8) & 0xff0000) + \ - (((a) << 24) & 0xff000000)) -# define GET_BE_WORD16(a) ((((a) >> 8) & 0xff) + (((a) << 8) & 0xff00)) -# define GET_BE_WORD32(a) (BIGEND(a)) +// @todo: look at using for fastest platform implementations +# define BIGEND(a) ((((a) >> 24) & 0xff) + \ + (((a) >> 8) & 0xff00) + \ + (((a) << 8) & 0xff0000) + \ + (((a) << 24) & 0xff000000)) +# define GET_BE_WORD16(a) ((((a) >> 8) & 0xff) + (((a) << 8) & 0xff00)) +# define GET_BE_WORD32(a) (BIGEND(a)) #else -# define BIGEND(a) (a) -# define GET_BE_WORD16(a) (a) -# define GET_BE_WORD32(a) (a) +# define BIGEND(a) (a) +# define GET_BE_WORD16(a) (a) +# define GET_BE_WORD32(a) (a) #endif #define MAXNUM_HEX_PER_LINE 32 @@ -76,54 +78,54 @@ void U_STACK_TRACE(); # include #endif -#if !defined(_WIN32) && !defined (__OS2__) && !defined(UNDER_CE) // OG +#if !defined(_WIN32) && !defined(UNDER_CE) // OG # include # include # include #endif #include -#include -#include - -#include -#include -#include - -#ifndef UNDER_CE // OG CE SPecific +#include +#include + +#include +#include +#include + +#ifndef UNDER_CE // OG CE SPecific #include #include #include #include -// OG Adding support for open -#ifdef WIN32 -#include -#endif - -#else -extern int errno; -extern int open(const char* name,int,...); -extern int read(int,char*,int); -extern int close(int); -extern int write( int fd, const void *buffer, unsigned int count ); -extern int lseek(int,int,int); -struct stat { int st_size; }; -extern int stat(const char* name, struct stat*); -extern int fstat(int, struct stat*); -#define O_RDWR 1 -#define O_BINARY 2 -#define O_RDONLY 4 -#define O_WRONLY 8 -#define O_CREAT 16 -#define O_TRUNC 32 -#define EAGAIN 11 -#define EINTR 4 - -#endif - - +// OG Adding support for open +#ifdef WIN32 +#include +#endif + +#else +extern int errno; +extern int open(const char* name,int,...); +extern int read(int,char*,int); +extern int close(int); +extern int write( int fd, const void *buffer, unsigned int count ); +extern int lseek(int,int,int); +struct stat { int st_size; }; +extern int stat(const char* name, struct stat*); +extern int fstat(int, struct stat*); +#define O_RDWR 1 +#define O_BINARY 2 +#define O_RDONLY 4 +#define O_WRONLY 8 +#define O_CREAT 16 +#define O_TRUNC 32 +#define EAGAIN 11 +#define EINTR 4 + +#endif + + #ifdef HPUX -# include /* for GET_ITIMER */ +# include /* for GET_ITIMER */ #endif #ifdef SOLARIS @@ -132,239 +134,242 @@ extern int fstat(int, struct stat*); #ifndef O_BINARY /* work around some Windows junk */ -# define O_BINARY 0 +# define O_BINARY 0 #endif STRUCT(Pc_log) { - double dcycs; - word32 dbank_kpc; - word32 instr; - word32 psr_acc; - word32 xreg_yreg; - word32 stack_direct; - word32 pad; + double dcycs; + word32 dbank_kpc; + word32 instr; + word32 psr_acc; + word32 xreg_yreg; + word32 stack_direct; + word32 pad; }; STRUCT(Data_log) { - double dcycs; - word32 addr; - word32 val; - word32 size; + double dcycs; + word32 addr; + word32 val; + word32 size; }; STRUCT(Event) { - double dcycs; - int type; - Event *next; + double dcycs; + int type; + Event *next; }; STRUCT(Fplus) { - double plus_1; - double plus_2; - double plus_3; - double plus_x_minus_1; + double plus_1; + double plus_2; + double plus_3; + double plus_x_minus_1; }; STRUCT(Engine_reg) { - double fcycles; - word32 kpc; - word32 acc; + double fcycles; + word32 kpc; + word32 acc; - word32 xreg; - word32 yreg; + word32 xreg; + word32 yreg; - word32 stack; - word32 dbank; + word32 stack; + word32 dbank; - word32 direct; - word32 psr; - Fplus *fplus_ptr; + word32 direct; + word32 psr; + Fplus *fplus_ptr; }; STRUCT(Kimage) { - void *dev_handle; - void *dev_handle2; - byte *data_ptr; - int width_req; - int width_act; - int height; - int depth; - int mdepth; - int aux_info; + void *dev_handle; + void *dev_handle2; + byte *data_ptr; + int width_req; + int width_act; + int height; + int depth; + int mdepth; + int aux_info; }; typedef byte *Pg_info; STRUCT(Page_info) { - Pg_info rd_wr; + Pg_info rd_wr; }; STRUCT(Cfg_menu) { - const char *str; - void *ptr; - const char *name_str; - void *defptr; - int cfgtype; + const char *str; + void *ptr; + const char *name_str; + void *defptr; + int cfgtype; }; STRUCT(Cfg_dirent) { - char *name; - int is_dir; - int size; - int image_start; - int part_num; + char *name; + int is_dir; + int size; + int image_start; + int part_num; }; STRUCT(Cfg_listhdr) { - Cfg_dirent *direntptr; - int max; - int last; - int invalid; + Cfg_dirent *direntptr; + int max; + int last; + int invalid; - int curent; - int topent; + int curent; + int topent; - int num_to_show; + int num_to_show; }; STRUCT(Emustate_intlist) { - const char *str; - int *iptr; + const char *str; + int *iptr; }; STRUCT(Emustate_dbllist) { - const char *str; - double *dptr; + const char *str; + double *dptr; }; STRUCT(Emustate_word32list) { - const char *str; - word32 *wptr; + const char *str; + word32 *wptr; }; #ifdef __LP64__ -# define PTR2WORD(a) ((unsigned long)(a)) +# define PTR2WORD(a) ((unsigned long)(a)) #else -# define PTR2WORD(a) ((unsigned int)(a)) +# define PTR2WORD(a) ((unsigned int)(a)) #endif -#define ALTZP (g_c068_statereg & 0x80) +#define ALTZP (g_c068_statereg & 0x80) /* #define PAGE2 (g_c068_statereg & 0x40) */ -#define RAMRD (g_c068_statereg & 0x20) -#define RAMWRT (g_c068_statereg & 0x10) -#define RDROM (g_c068_statereg & 0x08) -#define LCBANK2 (g_c068_statereg & 0x04) -#define ROMB (g_c068_statereg & 0x02) -#define INTCX (g_c068_statereg & 0x01) +#define RAMRD (g_c068_statereg & 0x20) +#define RAMWRT (g_c068_statereg & 0x10) +#define RDROM (g_c068_statereg & 0x08) +#define LCBANK2 (g_c068_statereg & 0x04) +#define ROMB (g_c068_statereg & 0x02) +#define INTCX (g_c068_statereg & 0x01) -#define C041_EN_25SEC_INTS 0x10 -#define C041_EN_VBL_INTS 0x08 -#define C041_EN_SWITCH_INTS 0x04 -#define C041_EN_MOVE_INTS 0x02 -#define C041_EN_MOUSE 0x01 +#define C041_EN_25SEC_INTS 0x10 +#define C041_EN_VBL_INTS 0x08 +#define C041_EN_SWITCH_INTS 0x04 +#define C041_EN_MOVE_INTS 0x02 +#define C041_EN_MOUSE 0x01 /* WARNING: SCC1 and SCC0 interrupts must be in this order for scc.c */ /* This order matches the SCC hardware */ -#define IRQ_PENDING_SCC1_ZEROCNT 0x00001 -#define IRQ_PENDING_SCC1_TX 0x00002 -#define IRQ_PENDING_SCC1_RX 0x00004 -#define IRQ_PENDING_SCC0_ZEROCNT 0x00008 -#define IRQ_PENDING_SCC0_TX 0x00010 -#define IRQ_PENDING_SCC0_RX 0x00020 -#define IRQ_PENDING_C023_SCAN 0x00100 -#define IRQ_PENDING_C023_1SEC 0x00200 -#define IRQ_PENDING_C046_25SEC 0x00400 -#define IRQ_PENDING_C046_VBL 0x00800 -#define IRQ_PENDING_ADB_KBD_SRQ 0x01000 -#define IRQ_PENDING_ADB_DATA 0x02000 -#define IRQ_PENDING_ADB_MOUSE 0x04000 -#define IRQ_PENDING_DOC 0x08000 +#define IRQ_PENDING_SCC1_ZEROCNT 0x00001 +#define IRQ_PENDING_SCC1_TX 0x00002 +#define IRQ_PENDING_SCC1_RX 0x00004 +#define IRQ_PENDING_SCC0_ZEROCNT 0x00008 +#define IRQ_PENDING_SCC0_TX 0x00010 +#define IRQ_PENDING_SCC0_RX 0x00020 +#define IRQ_PENDING_C023_SCAN 0x00100 +#define IRQ_PENDING_C023_1SEC 0x00200 +#define IRQ_PENDING_C046_25SEC 0x00400 +#define IRQ_PENDING_C046_VBL 0x00800 +#define IRQ_PENDING_ADB_KBD_SRQ 0x01000 +#define IRQ_PENDING_ADB_DATA 0x02000 +#define IRQ_PENDING_ADB_MOUSE 0x04000 +#define IRQ_PENDING_DOC 0x08000 -#define EXTRU(val, pos, len) \ - ( ( (len) >= (pos) + 1) ? ((val) >> (31-(pos))) : \ - (((val) >> (31-(pos)) ) & ( (1<<(len) ) - 1) ) ) +#define EXTRU(val, pos, len) \ + ( ( (len) >= (pos) + 1) ? ((val) >> (31-(pos))) : \ + (((val) >> (31-(pos)) ) & ( (1<<(len) ) - 1) ) ) -#define DEP1(val, pos, old_val) \ - (((old_val) & ~(1 << (31 - (pos))) ) | \ - ( ((val) & 1) << (31 - (pos))) ) +#define DEP1(val, pos, old_val) \ + (((old_val) & ~(1 << (31 - (pos))) ) | \ + ( ((val) & 1) << (31 - (pos))) ) #define set_halt(val) \ - if(val) { set_halt_act(val); } + if(val) { set_halt_act(val); } #define clear_halt() \ - clr_halt_act() + clr_halt_act() #define GET_PAGE_INFO_RD(page) \ - (page_info_rd_wr[page].rd_wr) + (page_info_rd_wr[page].rd_wr) #define GET_PAGE_INFO_WR(page) \ - (page_info_rd_wr[0x10000 + PAGE_INFO_PAD_SIZE + (page)].rd_wr) + (page_info_rd_wr[0x10000 + PAGE_INFO_PAD_SIZE + (page)].rd_wr) #define SET_PAGE_INFO_RD(page,val) \ - ;page_info_rd_wr[page].rd_wr = (Pg_info)val; + ; page_info_rd_wr[page].rd_wr = (Pg_info)val; #define SET_PAGE_INFO_WR(page,val) \ - ;page_info_rd_wr[0x10000 + PAGE_INFO_PAD_SIZE + (page)].rd_wr = \ - (Pg_info)val; + ; page_info_rd_wr[0x10000 + PAGE_INFO_PAD_SIZE + (page)].rd_wr = \ + (Pg_info)val; -#define VERBOSE_DISK 0x001 -#define VERBOSE_IRQ 0x002 -#define VERBOSE_CLK 0x004 -#define VERBOSE_SHADOW 0x008 -#define VERBOSE_IWM 0x010 -#define VERBOSE_DOC 0x020 -#define VERBOSE_ADB 0x040 -#define VERBOSE_SCC 0x080 -#define VERBOSE_TEST 0x100 -#define VERBOSE_VIDEO 0x200 -#define VERBOSE_MAC 0x400 +#define VERBOSE_DISK 0x001 +#define VERBOSE_IRQ 0x002 +#define VERBOSE_CLK 0x004 +#define VERBOSE_SHADOW 0x008 +#define VERBOSE_IWM 0x010 +#define VERBOSE_DOC 0x020 +#define VERBOSE_ADB 0x040 +#define VERBOSE_SCC 0x080 +#define VERBOSE_TEST 0x100 +#define VERBOSE_VIDEO 0x200 +#define VERBOSE_MAC 0x400 #ifdef NO_VERB -# define DO_VERBOSE 0 +# define DO_VERBOSE 0 #else -# define DO_VERBOSE 1 +# define DO_VERBOSE 1 #endif -#define disk_printf if(DO_VERBOSE && (Verbose & VERBOSE_DISK)) printf -#define irq_printf if(DO_VERBOSE && (Verbose & VERBOSE_IRQ)) printf -#define clk_printf if(DO_VERBOSE && (Verbose & VERBOSE_CLK)) printf -#define shadow_printf if(DO_VERBOSE && (Verbose & VERBOSE_SHADOW)) printf -#define iwm_printf if(DO_VERBOSE && (Verbose & VERBOSE_IWM)) printf -#define doc_printf if(DO_VERBOSE && (Verbose & VERBOSE_DOC)) printf -#define adb_printf if(DO_VERBOSE && (Verbose & VERBOSE_ADB)) printf -#define scc_printf if(DO_VERBOSE && (Verbose & VERBOSE_SCC)) printf -#define test_printf if(DO_VERBOSE && (Verbose & VERBOSE_TEST)) printf -#define vid_printf if(DO_VERBOSE && (Verbose & VERBOSE_VIDEO)) printf -#define mac_printf if(DO_VERBOSE && (Verbose & VERBOSE_MAC)) printf +#define disk_printf if(DO_VERBOSE && (Verbose & VERBOSE_DISK)) printf +#define irq_printf if(DO_VERBOSE && (Verbose & VERBOSE_IRQ)) printf +#define clk_printf if(DO_VERBOSE && (Verbose & VERBOSE_CLK)) printf +#define shadow_printf if(DO_VERBOSE && (Verbose & VERBOSE_SHADOW)) printf +#define iwm_printf if(DO_VERBOSE && (Verbose & VERBOSE_IWM)) printf +#define doc_printf if(DO_VERBOSE && (Verbose & VERBOSE_DOC)) printf +#define adb_printf if(DO_VERBOSE && (Verbose & VERBOSE_ADB)) printf +#define scc_printf if(DO_VERBOSE && (Verbose & VERBOSE_SCC)) printf +#define test_printf if(DO_VERBOSE && (Verbose & VERBOSE_TEST)) printf +#define vid_printf if(DO_VERBOSE && (Verbose & VERBOSE_VIDEO)) printf +#define mac_printf if(DO_VERBOSE && (Verbose & VERBOSE_MAC)) printf -#define HALT_ON_SCAN_INT 0x001 -#define HALT_ON_IRQ 0x002 -#define HALT_ON_SHADOW_REG 0x004 -#define HALT_ON_C70D_WRITES 0x008 +#define HALT_ON_SCAN_INT 0x001 +#define HALT_ON_IRQ 0x002 +#define HALT_ON_SHADOW_REG 0x004 +#define HALT_ON_C70D_WRITES 0x008 -#define HALT_ON(a, msg) \ - if(Halt_on & a) { \ - halt_printf(msg); \ - } +#define HALT_ON(a, msg) \ + if(Halt_on & a) { \ + halt_printf(msg); \ + } #ifndef MIN -# define MIN(a,b) (((a) < (b)) ? (a) : (b)) +# define MIN(a,b) (((a) < (b)) ? (a) : (b)) #endif #ifndef MAX -# define MAX(a,b) (((a) < (b)) ? (b) : (a)) +# define MAX(a,b) (((a) < (b)) ? (b) : (a)) #endif -#define GET_ITIMER(dest) dest = get_itimer(); +#define GET_ITIMER(dest) dest = get_itimer(); #include "iwm.h" #include "protos.h" -// OG Added define for joystick -#define JOYSTICK_TYPE_KEYPAD 0 -#define JOYSTICK_TYPE_MOUSE 1 -#define JOYSTICK_TYPE_NATIVE_1 2 -#define JOYSTICK_TYPE_NATIVE_2 3 -#define JOYSTICK_TYPE_NONE 4 // OG Added Joystick None -#define NB_JOYSTICK_TYPE 5 +// OG Added define for joystick +#define JOYSTICK_TYPE_KEYPAD 0 +#define JOYSTICK_TYPE_MOUSE 1 +#define JOYSTICK_TYPE_NATIVE_1 2 +#define JOYSTICK_TYPE_NATIVE_2 3 +#define JOYSTICK_TYPE_NONE 4 // OG Added Joystick None +#define NB_JOYSTICK_TYPE 5 + +// starting window x/y position if Undefined +#define WINDOWPOS_UNDEFINED 0xFFFFFFFF diff --git a/src/dis.c b/src/dis.c index 77b18b3..9000e41 100644 --- a/src/dis.c +++ b/src/dis.c @@ -1,6 +1,7 @@ /* GSport - an Apple //gs Emulator - Copyright (C) 2010 by GSport contributors + Copyright (C) 2010 - 2019 by GSport contributors + Copyright (C) 2016 - 2018 Dagen Brock Based on the KEGS emulator written by and Copyright (C) 2003 Kent Dickey @@ -31,1176 +32,1109 @@ extern byte *g_memory_ptr; extern byte *g_slow_memory_ptr; extern int halt_sim; extern int enter_debug; +extern int g_dbg_step; //debug.c +extern int timeout; //debug.c extern int g_c068_statereg; extern word32 stop_run_at; extern int Verbose; extern int Halt_on; -extern int g_testing_enabled; extern int g_fullscreen; extern int g_config_control_panel; -int g_num_breakpoints = 0; -word32 g_breakpts[MAX_BREAK_POINTS]; +int g_num_breakpoints = 0; +word32 g_breakpts[MAX_BREAK_POINTS]; extern int g_irq_pending; extern Engine_reg engine; -#define W_BUF_LEN 128 +#define W_BUF_LEN 128 char w_buff[W_BUF_LEN]; int g_stepping = 0; -word32 list_kpc; -int hex_line_len; -word32 a1,a2,a3; -word32 g_a4, g_a4bank; +word32 list_kpc; +int hex_line_len; +word32 a1,a2,a3; +word32 g_a4, g_a4bank; int a1bank, a2bank, a3bank; char *line_ptr; int mode,old_mode; int got_num; -// OG replaced by HALT_WANTTOQUIT -//int g_quit_sim_now = 0; +// OG replaced by HALT_WANTTOQUIT +//int g_quit_sim_now = 0; -int -get_num() -{ - int tmp1; +int get_num() { + int tmp1; - a2 = 0; - got_num = 0; - while(1) { - if(mode == 0 && got_num != 0) { -/* - printf("In getnum, mode =0, setting a1,a3 = a2\n"); - printf("a2: %x\n", a2); -*/ - a3 = a2; - a3bank = a2bank; - a1 = a2; - a1bank = a2bank; - } - tmp1 = *line_ptr++ & 0x7f; - if(tmp1 >= '0' && tmp1 <= '9') { - a2 = (a2 << 4) + tmp1 - '0'; - got_num = 1; - continue; - } - if(tmp1 >= 'a' && tmp1 <= 'f') { - a2 = (a2 << 4) + tmp1 - 'a' + 10; - got_num = 1; - continue; - } - if(tmp1 == '/') { - a2bank = a2; - a2 = 0; - continue; - } - return tmp1; - } + a2 = 0; + got_num = 0; + while(1) { + if(mode == 0 && got_num != 0) { + a3 = a2; + a3bank = a2bank; + a1 = a2; + a1bank = a2bank; + } + tmp1 = *line_ptr++ & 0x7f; + if(tmp1 >= '0' && tmp1 <= '9') { + a2 = (a2 << 4) + tmp1 - '0'; + got_num = 1; + continue; + } + if(tmp1 >= 'a' && tmp1 <= 'f') { + a2 = (a2 << 4) + tmp1 - 'a' + 10; + got_num = 1; + continue; + } + if(tmp1 == '/') { + a2bank = a2; + a2 = 0; + continue; + } + return tmp1; + } } -void -debugger_help() -{ - printf("GSport Debugger help (courtesy Fredric Devernay\n"); - printf("General command syntax: [bank]/[address][command]\n"); - printf("e.g. 'e1/0010B' to set a breakpoint at the interrupt jump pt\n"); - printf("Enter all addresses using lower-case\n"); - printf("As with the IIgs monitor, you can omit the bank number after\n"); - printf("having set it: 'e1/0010B' followed by '14B' will set\n"); - printf("breakpoints at e1/0010 and e1/0014\n"); - printf("\n"); - printf("g Go\n"); - printf("[bank]/[addr]g Go from [bank]/[address]\n"); - printf("s Step one instruction\n"); - printf("[bank]/[addr]s Step one instr at [bank]/[address]\n"); - printf("[bank]/[addr]B Set breakpoint at [bank]/[address]\n"); - printf("B Show all breakpoints\n"); - printf("[bank]/[addr]D Delete breakpoint at [bank]/[address]\n"); - printf("[bank]/[addr1].[addr2] View memory\n"); - printf("[bank]/[addr]L Disassemble memory\n"); - - printf("P Dump the trace to 'pc_log_out'\n"); - printf("Z Dump SCC state\n"); - printf("I Dump IWM state\n"); - printf("[drive].[track]I Dump IWM state\n"); - printf("E Dump Ensoniq state\n"); - printf("[osc]E Dump oscillator [osc] state\n"); - printf("R Dump dtime array and events\n"); - printf("T Show toolbox log\n"); - printf("[bank]/[addr]T Dump tools using ptr [bank]/[addr]\n"); - printf(" as 'tool_set_info'\n"); - printf("[mode]V XOR verbose with 1=DISK, 2=IRQ,\n"); - printf(" 4=CLK,8=SHADOW,10=IWM,20=DOC,\n"); - printf(" 40=ABD,80=SCC, 100=TEST, 200=VIDEO\n"); - printf("[mode]H XOR halt_on with 1=SCAN_INT,\n"); - printf(" 2=IRQ, 4=SHADOW_REG, 8=C70D_WRITES\n"); - printf("r Reset\n"); - printf("[0/1]=m Changes m bit for l listings\n"); - printf("[0/1]=x Changes x bit for l listings\n"); - printf("[t]=z Stops at absolute time t (obsolete)\n"); - printf("S show_bankptr_bank0 & smartport errs\n"); - printf("P show_pmhz\n"); - printf("A show_a2_line_stuff show_adb_log\n"); - printf("Ctrl-e Dump registers\n"); - printf("[bank]/[addr1].[addr2]us[file] Save mem area to [file]\n"); - printf("[bank]/[addr1].[addr2]ul[file] Load mem area from [file]\n"); - printf("v Show video information\n"); - printf("q Exit Debugger (and GSport)\n"); +void debugger_help() { + printf("GSport Debugger Help (courtesy Fredric Devernay)\n\n"); + printf("General command syntax:\n"); + printf(" [bank]/[address][command]\n\n"); + printf("Example: > e1/0010B Set a Breakpoint at the interrupt jump pt\n\n"); + printf("Enter all addresses using lower-case.\n"); + printf("As with the IIgs monitor, you can omit the bank number after\n"); + printf("having set it: 'e1/0010B' followed by '14B' will set breakpoints\n"); + printf("at e1/0010 and e1/0014\n\n"); + printf(" g Go\n"); + printf(" [bank]/[addr]g Go from [bank]/[address]\n"); + printf(" s Step one instruction\n"); + printf(" [bank]/[addr]s Step one instr at [bank]/[address]\n"); + printf(" [bank]/[addr]B Set breakpoint at [bank]/[address]\n"); + printf(" B Show all breakpoints\n"); + printf(" [bank]/[addr]D Delete breakpoint at [bank]/[address]\n"); + printf(" [bank]/[addr].[addr2] View memory\n"); + printf(" [bank]/[addr]L Disassemble memory\n"); + printf(" P Dump the trace to 'pc_log_out'\n"); + printf(" Z Dump SCC state\n"); + printf(" I Dump IWM state\n"); + printf("[drive].[track]I Dump IWM state\n"); + printf(" E Dump Ensoniq state\n"); + printf(" [osc]E Dump oscillator [osc] state\n"); + printf(" R Dump dtime array and events\n"); + printf(" T Show toolbox log\n"); + printf(" [bank]/[addr]T Dump tools using ptr [bank]/[addr]\n"); + printf(" as 'tool_set_info'\n"); + printf(" [mode]V XOR verbose with 1=DISK, 2=IRQ,\n"); + printf(" 4=CLK,8=SHADOW,10=IWM,20=DOC,\n"); + printf(" 40=ABD,80=SCC, 100=TEST, 200=VIDEO\n"); + printf(" [mode]H XOR halt_on with 1=SCAN_INT,\n"); + printf(" 2=IRQ, 4=SHADOW_REG, 8=C70D_WRITES\n"); + printf(" r Reset\n"); + printf(" [0/1]=m Changes m bit for l listings\n"); + printf(" [0/1]=x Changes x bit for l listings\n"); + printf(" [t]=z Stops at absolute time t (obsolete)\n"); + printf(" S show_bankptr_bank0 & smartport errs\n"); + printf(" P show_pmhz\n"); + printf(" A show_a2_line_stuff show_adb_log\n"); + printf(" Ctrl-e Dump registers\n"); + printf("[bank]/[addr1].[addr2]us[file] Save mem area to [file]\n"); + printf("[bank]/[addr1].[addr2]ul[file] Load mem area from [file]\n"); + printf(" v Show video information\n"); + printf(" q Quit Debugger (and GSport)\n"); } -void -do_debug_intfc() -{ - char linebuf[LINE_SIZE]; - int slot_drive; - int track; - int osc; - int done; - int ret_val; +void do_debug_intfc() { + char linebuf[LINE_SIZE]; + int slot_drive; + int track; + int osc; + int done; + int ret_val; - g_config_control_panel = 1; + g_config_control_panel = 1; - hex_line_len = 0x10; - a1 = 0; a2 = 0; a3 = 0; g_a4 = 0; - a1bank = 0; a2bank = 0; a3bank = 0; g_a4bank = 0; - list_kpc = engine.kpc; - g_stepping = 0; - mode = 0; old_mode = 0; - done = 0; - stop_run_at = -1; + hex_line_len = 0x10; + a1 = 0; a2 = 0; a3 = 0; g_a4 = 0; + a1bank = 0; a2bank = 0; a3bank = 0; g_a4bank = 0; + list_kpc = engine.kpc; + g_stepping = 0; + mode = 0; old_mode = 0; + done = 0; + stop_run_at = -1; - x_auto_repeat_on(0); - g_fullscreen = 0; - x_full_screen(0); + x_auto_repeat_on(0); + g_fullscreen = 0; + x_full_screen(0); - // OG use HALT_WANTTOQUIT instead of g_quit_sim_now - if (halt_sim&HALT_WANTTOQUIT) - { - printf("Exiting immediately\n"); - return; - } + // OG use HALT_WANTTOQUIT instead of g_quit_sim_now + if (halt_sim&HALT_WANTTOQUIT) + { + printf("Exiting immediately\n"); + return; + } - printf("Type 'h' for help\n"); + printf("Type 'h' for help\n"); - while(!done) { - printf("> "); fflush(stdout); - if(read_line(linebuf,LINE_SIZE-1) <= 0) { - done = 1; - continue; - } - line_ptr = linebuf; + while(!done) { + printf("> "); fflush(stdout); + if(read_line(linebuf,LINE_SIZE-1) <= 0) { + done = 1; + continue; + } + line_ptr = linebuf; /* - printf("input line: :%s:\n", linebuf); - printf("mode: %d\n", mode); -*/ - mode = 0; + printf("input line: :%s:\n", linebuf); + printf("mode: %d\n", mode); + */ + mode = 0; - while(*line_ptr != 0) { - ret_val = get_num(); + while(*line_ptr != 0) { + ret_val = get_num(); /* - printf("ret_val: %x, got_num= %d\n", ret_val, - got_num); -*/ - old_mode = mode; - mode = 0; - switch(ret_val) { - case 'h': - debugger_help(); - break; - case 'R': - show_dtime_array(); - show_all_events(); - break; - case 'I': - slot_drive = -1; - track = -1; - if(got_num) { - if(old_mode == '.') { - slot_drive = a1; - } - track = a2; - } - iwm_show_track(slot_drive, track); - iwm_show_stats(); - break; - case 'E': - osc = -1; - if(got_num) { - osc = a2; - } - doc_show_ensoniq_state(osc); - break; - case 'T': - if(got_num) { - show_toolset_tables(a2bank, a2); - } else { - show_toolbox_log(); - } - break; - case 'v': - if(got_num) { - dis_do_compare(); - } else { - video_show_debug_info(); - } - break; - case 'V': - printf("g_irq_pending: %05x\n", g_irq_pending); - printf("Setting Verbose ^= %04x\n", a1); - Verbose ^= a1; - printf("Verbose is now: %04x\n", Verbose); - break; - case 'H': - printf("Setting Halt_on ^= %04x\n", a1); - Halt_on ^= a1; - printf("Halt_on is now: %04x\n", Halt_on); - break; - case 'r': - do_reset(); - list_kpc = engine.kpc; - break; - case 'm': - if(old_mode == '=') { - if(!a1) { - engine.psr &= ~0x20; - } else { - engine.psr |= 0x20; - } - if(engine.psr & 0x100) { - engine.psr |= 0x30; - } - } else { - dis_do_memmove(); - } - break; - case 'p': - dis_do_pattern_search(); - break; - case 'x': - if(old_mode == '=') { - if(!a1) { - engine.psr &= ~0x10; - } else { - engine.psr |= 0x10; - } - if(engine.psr & 0x100) { - engine.psr |= 0x30; - } - } - break; - case 'z': - if(old_mode == '=') { - stop_run_at = a1; - printf("Calling add_event for t:%08x\n", - a1); - add_event_stop((double)a1); - printf("set stop_run_at = %x\n", a1); - } - break; - case 'l': case 'L': - do_debug_list(); - break; - case 'Z': - show_scc_log(); - show_scc_state(); - break; - case 'S': - show_bankptrs_bank0rdwr(); - smartport_error(); - break; - case 'C': - show_xcolor_array(); - break; - case 'P': - show_pc_log(); - break; - case 'M': - show_pmhz(); - break; - case 'A': - show_a2_line_stuff(); - show_adb_log(); - break; - case 's': - g_stepping = 1; - if(got_num) { - engine.kpc = (a2bank<<16) + (a2&0xffff); - } - mode = 's'; - list_kpc = engine.kpc; - break; - case 'B': - if(got_num) { - printf("got_num: %d, a2bank: %x, a2: %x\n", got_num, a2bank, a2); - set_bp((a2bank << 16) + a2); - } else { - show_bp(); - } - break; - case 'D': - if(got_num) { - printf("got_num: %d, a2bank: %x, a2: %x\n", got_num, a2bank, a2); - delete_bp((a2bank << 16) + a2); - } - break; - case 'g': - case 'G': - printf("Going..\n"); - g_stepping = 0; - if(got_num) { - engine.kpc = (a2bank<<16) + (a2&0xffff); - } - if(ret_val == 'G' && g_testing_enabled) { - do_gen_test(got_num, a2); - } else { - do_go(); - } - list_kpc = engine.kpc; - break; - case 'q': - case 'Q': - printf("Exiting debugger\n"); - return; - break; - case 'u': - printf("Unix commands\n"); - do_debug_unix(); - break; - case ':': case '.': - case '+': case '-': - case '=': case ',': - mode = ret_val; - printf("Setting mode = %x\n", mode); - break; - case ' ': case '\t': - if(!got_num) { - mode = old_mode; - break; - } - do_blank(); - break; - case '<': - g_a4 = a2; - g_a4bank = a2bank; - break; - case 0x05: /* ctrl-e */ - show_regs(); - break; - case '\n': - case '\r': - *line_ptr = 0; - if(old_mode == 's') { - do_blank(); - break; - } - if(line_ptr == &linebuf[1]) { - a2 = a1 | (hex_line_len - 1); - show_hex_mem(a1bank,a1,a2bank,a2, -1); - a1 = a2 + 1; - } else { - if(got_num == 1 || mode == 's') { - do_blank(); - } - } - break; - case 'w': - read_line(w_buff, W_BUF_LEN); - break; - default: - printf("\nUnrecognized command: %s\n",linebuf); - *line_ptr = 0; - break; - } - } + printf("ret_val: %x, got_num= %d\n", ret_val, + got_num); + */ + old_mode = mode; + mode = 0; + switch(ret_val) { + case 'h': + debugger_help(); + break; + case 'R': + show_dtime_array(); + show_all_events(); + break; + case 'I': + slot_drive = -1; + track = -1; + if(got_num) { + if(old_mode == '.') { + slot_drive = a1; + } + track = a2; + } + iwm_show_track(slot_drive, track); + iwm_show_stats(); + break; + case 'E': + osc = -1; + if(got_num) { + osc = a2; + } + doc_show_ensoniq_state(osc); + break; + case 'T': + if(got_num) { + show_toolset_tables(a2bank, a2); + } else { + show_toolbox_log(); + } + break; + case 'v': + if(got_num) { + dis_do_compare(); + } else { + video_show_debug_info(); + } + break; + case 'V': + printf("g_irq_pending: %05x\n", g_irq_pending); + printf("Setting Verbose ^= %04x\n", a1); + Verbose ^= a1; + printf("Verbose is now: %04x\n", Verbose); + break; + case 'H': + printf("Setting Halt_on ^= %04x\n", a1); + Halt_on ^= a1; + printf("Halt_on is now: %04x\n", Halt_on); + break; + case 'r': + do_reset(); + list_kpc = engine.kpc; + break; + case 'm': + if(old_mode == '=') { + if(!a1) { + engine.psr &= ~0x20; + } else { + engine.psr |= 0x20; + } + if(engine.psr & 0x100) { + engine.psr |= 0x30; + } + } else { + dis_do_memmove(); + } + break; + case 'p': + dis_do_pattern_search(); + break; + case 'x': + if(old_mode == '=') { + if(!a1) { + engine.psr &= ~0x10; + } else { + engine.psr |= 0x10; + } + if(engine.psr & 0x100) { + engine.psr |= 0x30; + } + } + break; + case 'z': + if(old_mode == '=') { + stop_run_at = a1; + printf("Calling add_event for t:%08x\n", + a1); + add_event_stop((double)a1); + printf("set stop_run_at = %x\n", a1); + } + break; + case 'l': case 'L': + do_debug_list(); + break; + case 'Z': + show_scc_log(); + show_scc_state(); + break; + case 'S': + show_bankptrs_bank0rdwr(); + smartport_error(); + break; + case 'C': + show_xcolor_array(); + break; + case 'P': + show_pc_log(); + break; + case 'M': + show_pmhz(); + break; + case 'A': + show_a2_line_stuff(); + show_adb_log(); + break; + case 's': + g_stepping = 1; + if(got_num) { + engine.kpc = (a2bank<<16) + (a2&0xffff); + } + mode = 's'; + list_kpc = engine.kpc; + break; + case 'B': + if(got_num) { + printf("got_num: %d, a2bank: %x, a2: %x\n", got_num, a2bank, a2); + set_bp((a2bank << 16) + a2); + } else { + show_bp(); + } + break; + case 'D': + if(got_num) { + printf("got_num: %d, a2bank: %x, a2: %x\n", got_num, a2bank, a2); + delete_bp((a2bank << 16) + a2); + } + break; + case 'g': + case 'G': + printf("Going..\n"); + g_stepping = 0; + if(got_num) { + engine.kpc = (a2bank<<16) + (a2&0xffff); + } + do_go(); + list_kpc = engine.kpc; + break; + case 'q': + case 'Q': + printf("Exiting debugger\n"); + return; + break; + case 'u': + printf("Unix commands\n"); + do_debug_unix(); + break; + case ':': case '.': + case '+': case '-': + case '=': case ',': + mode = ret_val; + printf("Setting mode = %x\n", mode); + break; + case ' ': case '\t': + if(!got_num) { + mode = old_mode; + break; + } + do_blank(); + break; + case '<': + g_a4 = a2; + g_a4bank = a2bank; + break; + case 0x05: /* ctrl-e */ + show_regs(); + break; + case '\n': + case '\r': + *line_ptr = 0; + if(old_mode == 's') { + do_blank(); + break; + } + if(line_ptr == &linebuf[1]) { + a2 = a1 | (hex_line_len - 1); + show_hex_mem(a1bank,a1,a2bank,a2, -1); + a1 = a2 + 1; + } else { + if(got_num == 1 || mode == 's') { + do_blank(); + } + } + break; + case 'w': + read_line(w_buff, W_BUF_LEN); + break; + default: + printf("\nUnrecognized command: %s\n",linebuf); + *line_ptr = 0; + break; + } + } - } - printf("Console closed.\n"); + } + printf("Console closed.\n"); } -word32 -dis_get_memory_ptr(word32 addr) -{ - word32 tmp1, tmp2, tmp3; +word32 dis_get_memory_ptr(word32 addr) { + word32 tmp1, tmp2, tmp3; - tmp1 = get_memory_c(addr, 0); - tmp2 = get_memory_c(addr + 1, 0); - tmp3 = get_memory_c(addr + 2, 0); + tmp1 = get_memory_c(addr, 0); + tmp2 = get_memory_c(addr + 1, 0); + tmp3 = get_memory_c(addr + 2, 0); - return (tmp3 << 16) + (tmp2 << 8) + tmp1; + return (tmp3 << 16) + (tmp2 << 8) + tmp1; } -void -show_one_toolset(FILE *toolfile, int toolnum, word32 addr) -{ - word32 rout_addr; - int num_routs; - int i; +void show_one_toolset(FILE *toolfile, int toolnum, word32 addr) { + word32 rout_addr; + int num_routs; + int i; - num_routs = dis_get_memory_ptr(addr); - fprintf(toolfile, "Tool 0x%02x, table: 0x%06x, num_routs:%03x\n", - toolnum, addr, num_routs); + num_routs = dis_get_memory_ptr(addr); + fprintf(toolfile, "Tool 0x%02x, table: 0x%06x, num_routs:%03x\n", + toolnum, addr, num_routs); - for(i = 1; i < num_routs; i++) { - rout_addr = dis_get_memory_ptr(addr + 4*i); - fprintf(toolfile, "%06x = %02x%02x\n", rout_addr, i, toolnum); - } + for(i = 1; i < num_routs; i++) { + rout_addr = dis_get_memory_ptr(addr + 4*i); + fprintf(toolfile, "%06x = %02x%02x\n", rout_addr, i, toolnum); + } } -void -show_toolset_tables(word32 a2bank, word32 addr) -{ - FILE *toolfile; - word32 tool_addr; - int num_tools; - int i; +void show_toolset_tables(word32 a2bank, word32 addr) { + FILE *toolfile; + word32 tool_addr; + int num_tools; + int i; - addr = (a2bank << 16) + (addr & 0xffff); + addr = (a2bank << 16) + (addr & 0xffff); - toolfile = fopen("tool_set_info", "w"); - if(toolfile == 0) { - fprintf(stderr, "fopen of tool_set_info failed: %d\n", errno); - exit(2); - } + toolfile = fopen("tool_set_info", "w"); + if(toolfile == 0) { + fprintf(stderr, "fopen of tool_set_info failed: %d\n", errno); + exit(2); + } - num_tools = dis_get_memory_ptr(addr); - fprintf(toolfile, "There are 0x%02x tools using ptr at %06x\n", - num_tools, addr); + num_tools = dis_get_memory_ptr(addr); + fprintf(toolfile, "There are 0x%02x tools using ptr at %06x\n", + num_tools, addr); - for(i = 1; i < num_tools; i++) { - tool_addr = dis_get_memory_ptr(addr + 4*i); - show_one_toolset(toolfile, i, tool_addr); - } + for(i = 1; i < num_tools; i++) { + tool_addr = dis_get_memory_ptr(addr + 4*i); + show_one_toolset(toolfile, i, tool_addr); + } - fclose(toolfile); + fclose(toolfile); +} + +void set_bp(word32 addr) { + int count; + + printf("About to set BP at %06x\n", addr); + count = g_num_breakpoints; + if(count >= MAX_BREAK_POINTS) { + printf("Too many (0x%02x) breakpoints set!\n", count); + return; + } + + g_breakpts[count] = addr; + g_num_breakpoints = count + 1; + fixup_brks(); +} + +void show_bp() { + int i; + + printf("Showing breakpoints set\n"); + for(i = 0; i < g_num_breakpoints; i++) { + printf("bp:%02x: %06x\n", i, g_breakpts[i]); + } +} + +void delete_bp(word32 addr) { + int count; + int hit; + int i; + + printf("About to delete BP at %06x\n", addr); + count = g_num_breakpoints; + + hit = -1; + for(i = 0; i < count; i++) { + if(g_breakpts[i] == addr) { + hit = i; + break; + } + } + + if(hit < 0) { + printf("Breakpoint not found!\n"); + } else { + printf("Deleting brkpoint #0x%02x\n", hit); + for(i = hit+1; i < count; i++) { + g_breakpts[i-1] = g_breakpts[i]; + } + g_num_breakpoints = count - 1; + setup_pageinfo(); + } + + show_bp(); +} + +void do_blank() { + int tmp, i; + + switch(old_mode) { + case 's': + tmp = a2; + if(tmp == 0) tmp = 1; + enter_debug = 0; + for(i = 0; i < tmp; i++) { + g_stepping = 1; + do_step(); + if(enter_debug || halt_sim != 0) { + if(halt_sim != HALT_EVENT) { + break; + } + } + } + list_kpc = engine.kpc; + /* video_update_through_line(262); */ + break; + case ':': + set_memory_c(((a3bank << 16) + a3), a2, 0); + a3++; + mode = old_mode; + break; + case '.': + case 0: + xam_mem(-1); + break; + case ',': + xam_mem(16); + break; + case '+': + printf("%x\n", a1 + a2); + break; + case '-': + printf("%x\n", a1 - a2); + break; + default: + printf("Unknown mode at space: %d\n", old_mode); + break; + } } -#ifndef TEST65 -void -do_gen_test(int got_num, int base_seed) -{ - /* dummy */ +/* also called by do_step */ +void do_go() { + g_config_control_panel = 0; + clear_halt(); + run_prog(); + show_regs(); + g_config_control_panel = 1; } + +void do_step() { + int size; + int size_mem_imm, size_x_imm; + + // run an instruction + do_go(); + + // check accumulator size + size_mem_imm = 2; + if(engine.psr & 0x20) { + size_mem_imm = 1; + } + // check xy size + size_x_imm = 2; + if(engine.psr & 0x10) { + size_x_imm = 1; + } + // then disassemble + size = do_dis(stdout, engine.kpc, size_mem_imm, size_x_imm, 0, 0); +} + +void xam_mem(int count) { + show_hex_mem(a1bank, a1, a2bank, a2, count); + a1 = a2 + 1; +} + +void show_hex_mem(int startbank, word32 start, int endbank, word32 end, int count) { + char ascii[MAXNUM_HEX_PER_LINE]; + word32 i; + int val, offset; + + if(count < 0) { + count = 16 - (start & 0xf); + } + + offset = 0; + ascii[0] = 0; + printf("Showing hex mem: bank: %x, start: %x, end: %x\n", + startbank, start, end); + for(i = start; i <= end; i++) { + if( (i==start) || (count == 16) ) { + printf("%04x:",i); + } + printf(" %02x", get_memory_c((startbank <<16) + i, 0)); + val = get_memory_c((startbank << 16) + i, 0) & 0x7f; + if(val < 32 || val >= 0x7f) { + val = '.'; + } + ascii[offset++] = val; + ascii[offset] = 0; + count--; + if(count <= 0) { + printf(" %s\n", ascii); + offset = 0; + ascii[0] = 0; + count = 16; + } + } + if(offset > 0) { + printf(" %s\n", ascii); + } +} + + +int read_line(char *buf, int len) { + int space_left; + int ret; +#if !defined(_WIN32) + int flags, flags_save; + + /* Unix */ + flags = fcntl(0, F_GETFL, 0); + flags_save = flags; + if(flags == -1) { + return 0; + } + ret = fcntl(0, F_SETFL, flags | O_NONBLOCK); + if(ret == -1) { + return 0; + } #endif + space_left = len; -void -set_bp(word32 addr) -{ - int count; - - printf("About to set BP at %06x\n", addr); - count = g_num_breakpoints; - if(count >= MAX_BREAK_POINTS) { - printf("Too many (0x%02x) breakpoints set!\n", count); - return; - } - - g_breakpts[count] = addr; - g_num_breakpoints = count + 1; - fixup_brks(); -} - -void -show_bp() -{ - int i; - - printf("Showing breakpoints set\n"); - for(i = 0; i < g_num_breakpoints; i++) { - printf("bp:%02x: %06x\n", i, g_breakpts[i]); - } -} - -void -delete_bp(word32 addr) -{ - int count; - int hit; - int i; - - printf("About to delete BP at %06x\n", addr); - count = g_num_breakpoints; - - hit = -1; - for(i = 0; i < count; i++) { - if(g_breakpts[i] == addr) { - hit = i; - break; - } - } - - if(hit < 0) { - printf("Breakpoint not found!\n"); - } else { - printf("Deleting brkpoint #0x%02x\n", hit); - for(i = hit+1; i < count; i++) { - g_breakpts[i-1] = g_breakpts[i]; - } - g_num_breakpoints = count - 1; - setup_pageinfo(); - } - - show_bp(); -} - -void -do_blank() -{ - int tmp, i; - - switch(old_mode) { - case 's': - tmp = a2; - if(tmp == 0) tmp = 1; - enter_debug = 0; - for(i = 0; i < tmp; i++) { - g_stepping = 1; - do_step(); - if(enter_debug || halt_sim != 0) { - if(halt_sim != HALT_EVENT) { - break; - } - } - } - list_kpc = engine.kpc; - /* video_update_through_line(262); */ - break; - case ':': - set_memory_c(((a3bank << 16) + a3), a2, 0); - a3++; - mode = old_mode; - break; - case '.': - case 0: - xam_mem(-1); - break; - case ',': - xam_mem(16); - break; - case '+': - printf("%x\n", a1 + a2); - break; - case '-': - printf("%x\n", a1 - a2); - break; - default: - printf("Unknown mode at space: %d\n", old_mode); - break; - } -} - -void -do_go() -{ - /* also called by do_step */ - - g_config_control_panel = 0; - clear_halt(); - - run_prog(); - show_regs(); - g_config_control_panel = 1; -} - -void -do_step() -{ - int size; - int size_mem_imm, size_x_imm; - - do_go(); - - size_mem_imm = 2; - if(engine.psr & 0x20) { - size_mem_imm = 1; - } - size_x_imm = 2; - if(engine.psr & 0x10) { - size_x_imm = 1; - } - size = do_dis(stdout, engine.kpc, size_mem_imm, size_x_imm, 0, 0); -} - -void -xam_mem(int count) -{ - show_hex_mem(a1bank, a1, a2bank, a2, count); - a1 = a2 + 1; -} - -void -show_hex_mem(int startbank, word32 start, int endbank, word32 end, int count) -{ - char ascii[MAXNUM_HEX_PER_LINE]; - word32 i; - int val, offset; - - if(count < 0) { - count = 16 - (start & 0xf); - } - - offset = 0; - ascii[0] = 0; - printf("Showing hex mem: bank: %x, start: %x, end: %x\n", - startbank, start, end); - for(i = start; i <= end; i++) { - if( (i==start) || (count == 16) ) { - printf("%04x:",i); - } - printf(" %02x", get_memory_c((startbank <<16) + i, 0)); - val = get_memory_c((startbank << 16) + i, 0) & 0x7f; - if(val < 32 || val >= 0x7f) { - val = '.'; - } - ascii[offset++] = val; - ascii[offset] = 0; - count--; - if(count <= 0) { - printf(" %s\n", ascii); - offset = 0; - ascii[0] = 0; - count = 16; - } - } - if(offset > 0) { - printf(" %s\n", ascii); - } -} - - -int -read_line(char *buf, int len) -{ - int space_left; - int ret; -#if !defined(_WIN32) && !defined (__OS2__) - int flags, flags_save; - - /* Unix */ - flags = fcntl(0, F_GETFL, 0); - flags_save = flags; - if(flags == -1) { - return 0; - } - ret = fcntl(0, F_SETFL, flags | O_NONBLOCK); - if(ret == -1) { - return 0; - } -#endif - space_left = len; - - buf[0] = 0; - ret = 0; - while(space_left > 0) { -#ifdef _WIN32 - ret = win_nonblock_read_stdin(0, buf, 1); -#elif defined(__OS2__) + buf[0] = 0; + ret = 0; + while(space_left > 0) { +#if defined(_WIN32) && !defined(WIN_SDL) + ret = win_nonblock_read_stdin(0, buf, 1); #else - /* Unix */ - ret = read(0, buf, 1); + /* Unix */ + ret = read(0, buf, 1); #endif - if(ret <= 0) { - micro_sleep(15.0/60.0); - if(errno == EAGAIN) { - /* it would block, so no chars--do update */ - video_update(); - ret = 0; - continue; - } - printf("read ret %d, errno: %d\n", ret, errno); - if(errno == EAGAIN || errno == EINTR) { - ret = 0; - continue; - } - break; - } - space_left -= ret; - if(buf[ret-1] == '\r' || buf[ret-1] == '\n') { - break; - } - buf = &buf[ret]; - } -#if !defined(_WIN32) && !defined (__OS2__) - (void)fcntl(0, F_SETFL, flags_save); + if(ret <= 0) { + micro_sleep(15.0/60.0); + if(errno == EAGAIN) { + /* it would block, so no chars--do update */ + video_update(); + ret = 0; + continue; + } + printf("read ret %d, errno: %d\n", ret, errno); + if(errno == EAGAIN || errno == EINTR) { + ret = 0; + continue; + } + break; + } + space_left -= ret; + if(buf[ret-1] == '\r' || buf[ret-1] == '\n') { + break; + } + buf = &buf[ret]; + } +#if !defined(_WIN32) + (void)fcntl(0, F_SETFL, flags_save); #endif - return (len-space_left); + return (len-space_left); } -void -do_debug_list() -{ - int i; - int size; - int size_mem_imm, size_x_imm; +void do_debug_list() { + int i; + int size; + int size_mem_imm, size_x_imm; - if(got_num) { - list_kpc = (a2bank << 16) + (a2 & 0xffff); - } - printf("%d=m %d=x %d=LCBANK\n", (engine.psr >> 5)&1, - (engine.psr >> 4) & 1, (g_c068_statereg & 0x4) >> 2); - - size_mem_imm = 2; - if(engine.psr & 0x20) { - size_mem_imm = 1; - } - size_x_imm = 2; - if(engine.psr & 0x10) { - size_x_imm = 1; - } - for(i=0;i<20;i++) { - size = do_dis(stdout, list_kpc, size_mem_imm, - size_x_imm, 0, 0); - list_kpc += size; - } + if(got_num) { + list_kpc = (a2bank << 16) + (a2 & 0xffff); + } + printf("%d=m %d=x %d=LCBANK\n", (engine.psr >> 5)&1, + (engine.psr >> 4) & 1, (g_c068_statereg & 0x4) >> 2); + + size_mem_imm = 2; + if(engine.psr & 0x20) { + size_mem_imm = 1; + } + size_x_imm = 2; + if(engine.psr & 0x10) { + size_x_imm = 1; + } + for(i=0; i<20; i++) { + size = do_dis(stdout, list_kpc, size_mem_imm, + size_x_imm, 0, 0); + list_kpc += size; + } } -void -dis_do_memmove() -{ - word32 val; +void dis_do_memmove() { + word32 val; - printf("Memory move from %02x/%04x.%04x to %02x/%04x\n", a1bank, a1, a2, g_a4bank, g_a4); - while(a1 <= (a2 & 0xffff)) { - val = get_memory_c((a1bank << 16) + a1, 0); - set_memory_c((g_a4bank << 16) + g_a4, val, 0); - a1++; - g_a4++; - } - a1 = a1 & 0xffff; - g_a4 = g_a4 & 0xffff; + printf("Memory move from %02x/%04x.%04x to %02x/%04x\n", a1bank, a1, a2, g_a4bank, g_a4); + while(a1 <= (a2 & 0xffff)) { + val = get_memory_c((a1bank << 16) + a1, 0); + set_memory_c((g_a4bank << 16) + g_a4, val, 0); + a1++; + g_a4++; + } + a1 = a1 & 0xffff; + g_a4 = g_a4 & 0xffff; } -void -dis_do_pattern_search() -{ - printf("Memory pattern search for %04x in %02x/%04x.%04x\n", g_a4, a1bank, a1, a2); +void dis_do_pattern_search() { + printf("Memory pattern search for %04x in %02x/%04x.%04x\n", g_a4, a1bank, a1, a2); } -void -dis_do_compare() -{ - word32 val1, val2; +void dis_do_compare() { + word32 val1, val2; - printf("Memory Compare from %02x/%04x.%04x with %02x/%04x\n", a1bank, a1, a2, g_a4bank, g_a4); - while(a1 <= (a2 & 0xffff)) { - val1 = get_memory_c((a1bank << 16) + a1, 0); - val2 = get_memory_c((g_a4bank << 16) + g_a4, 0); - if(val1 != val2) { - printf("%02x/%04x: %02x vs %02x\n", a1bank, a1, val1, val2); - } - a1++; - g_a4++; - } - a1 = a1 & 0xffff; - g_a4 = g_a4 & 0xffff; + printf("Memory Compare from %02x/%04x.%04x with %02x/%04x\n", a1bank, a1, a2, g_a4bank, g_a4); + while(a1 <= (a2 & 0xffff)) { + val1 = get_memory_c((a1bank << 16) + a1, 0); + val2 = get_memory_c((g_a4bank << 16) + g_a4, 0); + if(val1 != val2) { + printf("%02x/%04x: %02x vs %02x\n", a1bank, a1, val1, val2); + } + a1++; + g_a4++; + } + a1 = a1 & 0xffff; + g_a4 = g_a4 & 0xffff; } -void -do_debug_unix() -{ -#ifndef __OS2__ - char localbuf[LINE_SIZE]; - word32 offset, len; - int fd, ret; - int load, save; - int i; +void do_debug_unix() { + char localbuf[LINE_SIZE]; + word32 offset, len; + int fd, ret; + int load, save; + int i; - load = 0; save = 0; - switch(*line_ptr++) { - case 'l': case 'L': - printf("Loading.."); - load = 1; - break; - case 's': case 'S': - printf("Saving..."); - save = 1; - break; - default: - printf("Unknown unix command: %c\n", *(line_ptr-1)); - *line_ptr = 0; - return; - } - while(*line_ptr == ' ' || *line_ptr == '\t') { - line_ptr++; - } - i = 0; - while(i < LINE_SIZE) { - localbuf[i++] = *line_ptr++; - if(*line_ptr==' ' || *line_ptr=='\t' || *line_ptr == '\n') { - break; - } - } - localbuf[i] = 0; - + load = 0; save = 0; + switch(*line_ptr++) { + case 'l': case 'L': + printf("Loading.."); + load = 1; + break; + case 's': case 'S': + printf("Saving..."); + save = 1; + break; + default: + printf("Unknown unix command: %c\n", *(line_ptr-1)); + *line_ptr = 0; + return; + } + while(*line_ptr == ' ' || *line_ptr == '\t') { + line_ptr++; + } + i = 0; + while(i < LINE_SIZE) { + localbuf[i++] = *line_ptr++; + if(*line_ptr==' ' || *line_ptr=='\t' || *line_ptr == '\n') { + break; + } + } + localbuf[i] = 0; - printf("About to open: %s,len: %d\n", localbuf, (int)strlen(localbuf)); - if(load) { - fd = open(localbuf,O_RDONLY | O_BINARY); - } else { - fd = open(localbuf,O_WRONLY | O_CREAT | O_BINARY, 0x1b6); - } - if(fd < 0) { - printf("Open %s failed: %d\n", localbuf, fd); - printf("errno: %d\n", errno); - return; - } - if(load) { - offset = a1 & 0xffff; - len = 0x20000 - offset; - } else { - if(old_mode == '.') { - len = a2 - a1 + 1; - } else { - len = 0x100; - } - } - if(load) { - if(a1bank >= 0xe0 && a1bank < 0xe2) { - ret = read(fd,(char*)&g_slow_memory_ptr[((a1bank & 1)<<16)+a1],len); - } else { - ret = read(fd,(char*)&g_memory_ptr[(a1bank << 16) + a1],len); - } - } else { - if(a1bank >= 0xe0 && a1bank < 0xe2) { - ret = write(fd,(char*)&g_slow_memory_ptr[((a1bank & 1)<<16)+a1],len); - } else { - ret = write(fd,(char*)&g_memory_ptr[(a1bank << 16) + a1],len); - } - } - printf("Read/write: addr %06x for %04x bytes, ret: %x bytes\n", - (a1bank << 16) + a1, len, ret); - if(ret < 0) { - printf("errno: %d\n", errno); - } - a1 = a1 + ret; -#endif + + printf("About to open: %s,len: %d\n", localbuf, (int)strlen(localbuf)); + if(load) { + fd = open(localbuf,O_RDONLY | O_BINARY); + } else { + fd = open(localbuf,O_WRONLY | O_CREAT | O_BINARY, 0x1b6); + } + if(fd < 0) { + printf("Open %s failed: %d\n", localbuf, fd); + printf("errno: %d\n", errno); + return; + } + if(load) { + offset = a1 & 0xffff; + len = 0x20000 - offset; + } else { + if(old_mode == '.') { + len = a2 - a1 + 1; + } else { + len = 0x100; + } + } + if(load) { + if(a1bank >= 0xe0 && a1bank < 0xe2) { + ret = read(fd,(char*)&g_slow_memory_ptr[((a1bank & 1)<<16)+a1],len); + } else { + ret = read(fd,(char*)&g_memory_ptr[(a1bank << 16) + a1],len); + } + } else { + if(a1bank >= 0xe0 && a1bank < 0xe2) { + ret = write(fd,(char*)&g_slow_memory_ptr[((a1bank & 1)<<16)+a1],len); + } else { + ret = write(fd,(char*)&g_memory_ptr[(a1bank << 16) + a1],len); + } + } + printf("Read/write: addr %06x for %04x bytes, ret: %x bytes\n", + (a1bank << 16) + a1, len, ret); + if(ret < 0) { + printf("errno: %d\n", errno); + } + a1 = a1 + ret; } -void -do_debug_load() -{ - printf("Sorry, can't load now\n"); +void do_debug_load() { + printf("Sorry, can't load now\n"); } -int -do_dis(FILE *outfile, word32 kpc, int accsize, int xsize, - int op_provided, word32 instr) -{ - char buffer[150]; - const char *out; - int args, type; - int opcode; - word32 val; - word32 oldkpc; - word32 dtype; - int signed_val; +int do_dis(FILE *outfile, word32 kpc, int accsize, int xsize, + int op_provided, word32 instr) { + char buffer[150]; + const char *out; + int args, type; + int opcode; + word32 val; + word32 oldkpc; + word32 dtype; + int signed_val; - oldkpc = kpc; - if(op_provided) { - opcode = (instr >> 24) & 0xff; - } else { - opcode = (int)get_memory_c(kpc, 0) & 0xff; - } + oldkpc = kpc; + if(op_provided) { + opcode = (instr >> 24) & 0xff; + } else { + opcode = (int)get_memory_c(kpc, 0) & 0xff; + } - kpc++; + kpc++; - dtype = disas_types[opcode]; - out = disas_opcodes[opcode]; - type = dtype & 0xff; - args = dtype >> 8; + dtype = disas_types[opcode]; + out = disas_opcodes[opcode]; + type = dtype & 0xff; + args = dtype >> 8; - if(args > 3) { - if(args == 4) { - args = accsize; - } else if(args == 5) { - args = xsize; - } - } + if(args > 3) { + if(args == 4) { + args = accsize; + } else if(args == 5) { + args = xsize; + } + } - val = -1; - switch(args) { - case 0: - val = 0; - break; - case 1: - if(op_provided) { - val = instr & 0xff; - } else { - val = get_memory_c(kpc, 0); - } - break; - case 2: - if(op_provided) { - val = instr & 0xffff; - } else { - val = get_memory16_c(kpc, 0); - } - break; - case 3: - if(op_provided) { - val = instr & 0xffffff; - } else { - val = get_memory24_c(kpc, 0); - } - break; - default: - fprintf(stderr, "args out of rang: %d, opcode: %08x\n", - args, opcode); - break; - } - kpc += args; + val = -1; + switch(args) { + case 0: + val = 0; + break; + case 1: + if(op_provided) { + val = instr & 0xff; + } else { + val = get_memory_c(kpc, 0); + } + break; + case 2: + if(op_provided) { + val = instr & 0xffff; + } else { + val = get_memory16_c(kpc, 0); + } + break; + case 3: + if(op_provided) { + val = instr & 0xffffff; + } else { + val = get_memory24_c(kpc, 0); + } + break; + default: + fprintf(stderr, "args out of rang: %d, opcode: %08x\n", + args, opcode); + break; + } + kpc += args; - if(!op_provided) { - instr = (opcode << 24) | (val & 0xffffff); - } + if(!op_provided) { + instr = (opcode << 24) | (val & 0xffffff); + } - switch(type) { - case ABS: - if(args != 2) { - printf("arg # mismatch for opcode %x\n", opcode); - } - sprintf(buffer,"%s\t$%04x",out,val); - show_line(outfile, oldkpc,instr,args+1,buffer); - break; - case ABSX: - if(args != 2) { - printf("arg # mismatch for opcode %x\n", opcode); - } - sprintf(buffer,"%s\t$%04x,X",out,val); - show_line(outfile, oldkpc,instr,args+1,buffer); - break; - case ABSY: - if(args != 2) { - printf("arg # mismatch for opcode %x\n", opcode); - } - sprintf(buffer,"%s\t$%04x,Y",out,val); - show_line(outfile, oldkpc,instr,args+1,buffer); - break; - case ABSLONG: - if(args != 3) { - printf("arg # mismatch for opcode %x\n", opcode); - } - sprintf(buffer,"%s\t$%06x",out,val); - show_line(outfile, oldkpc,instr,args+1,buffer); - break; - case ABSIND: - if(args != 2) { - printf("arg # mismatch for opcode %x\n", opcode); - } - sprintf(buffer,"%s\t($%04x)",out,val); - show_line(outfile, oldkpc,instr,args+1,buffer); - break; - case ABSXIND: - if(args != 2) { - printf("arg # mismatch for opcode %x\n", opcode); - } - sprintf(buffer,"%s\t($%04x,X)",out,val); - show_line(outfile, oldkpc,instr,args+1,buffer); - break; - case IMPLY: - if(args != 0) { - printf("arg # mismatch for opcode %x\n", opcode); - } - sprintf(buffer,"%s",out); - show_line(outfile, oldkpc,instr,args+1,buffer); - break; - case ACCUM: - if(args != 0) { - printf("arg # mismatch for opcode %x\n", opcode); - } - sprintf(buffer,"%s",out); - show_line(outfile, oldkpc,instr,args+1,buffer); - break; - case IMMED: - if(args == 1) { - sprintf(buffer,"%s\t#$%02x",out,val); - } else if(args == 2) { - sprintf(buffer,"%s\t#$%04x",out,val); - } else { - printf("arg # mismatch for opcode %x\n", opcode); - } - show_line(outfile, oldkpc,instr,args+1,buffer); - break; - case JUST8: - if(args != 1) { - printf("arg # mismatch for opcode %x\n", opcode); - } - sprintf(buffer,"%s\t$%02x",out,val); - show_line(outfile, oldkpc,instr,args+1,buffer); - break; - case DLOC: - if(args != 1) { - printf("arg # mismatch for opcode %x\n", opcode); - } - sprintf(buffer,"%s\t$%02x",out,val); - show_line(outfile, oldkpc,instr,args+1,buffer); - break; - case DLOCX: - if(args != 1) { - printf("arg # mismatch for opcode %x\n", opcode); - } - sprintf(buffer,"%s\t$%02x,X",out,val); - show_line(outfile, oldkpc,instr,args+1,buffer); - break; - case DLOCY: - if(args != 1) { - printf("arg # mismatch for opcode %x\n", opcode); - } - sprintf(buffer,"%s\t$%02x,Y",out,val); - show_line(outfile, oldkpc,instr,args+1,buffer); - break; - case LONG: - if(args != 3) { - printf("arg # mismatch for opcode %x\n", opcode); - } - sprintf(buffer,"%s\t$%06x",out,val); - show_line(outfile, oldkpc,instr,args+1,buffer); - break; - case LONGX: - if(args != 3) { - printf("arg # mismatch for opcode %x\n", opcode); - } - sprintf(buffer,"%s\t$%06x,X",out,val); - show_line(outfile, oldkpc,instr,args+1,buffer); - break; - case DLOCIND: - if(args != 1) { - printf("arg # mismatch for opcode %x\n", opcode); - } - sprintf(buffer,"%s\t($%02x)",out,val); - show_line(outfile, oldkpc,instr,args+1,buffer); - break; - case DLOCINDY: - if(args != 1) { - printf("arg # mismatch for opcode %x\n", opcode); - } - sprintf(buffer,"%s\t($%02x),Y",out,val); - show_line(outfile, oldkpc,instr,args+1,buffer); - break; - case DLOCXIND: - if(args != 1) { - printf("arg # mismatch for opcode %x\n", opcode); - } - sprintf(buffer,"%s\t($%02x,X)",out,val); - show_line(outfile, oldkpc,instr,args+1,buffer); - break; - case DLOCBRAK: - if(args != 1) { - printf("arg # mismatch for opcode %x\n", opcode); - } - sprintf(buffer,"%s\t[$%02x]",out,val); - show_line(outfile, oldkpc,instr,args+1,buffer); - break; - case DLOCBRAKY: - if(args != 1) { - printf("arg # mismatch for opcode %x\n", opcode); - } - sprintf(buffer,"%s\t[$%02x],y",out,val); - show_line(outfile, oldkpc,instr,args+1,buffer); - break; - case DISP8: - if(args != 1) { - printf("arg # mismatch for opcode %x\n", opcode); - } - signed_val = (signed char)val; - sprintf(buffer,"%s\t$%04x",out, - (word32)(kpc+(signed_val)) & 0xffff); - show_line(outfile, oldkpc,instr,args+1,buffer); - break; - case DISP8S: - if(args != 1) { - printf("arg # mismatch for opcode %x\n", opcode); - } - sprintf(buffer,"%s\t$%02x,S",out,(word32)(byte)(val)); - show_line(outfile, oldkpc,instr,args+1,buffer); - break; - case DISP8SINDY: - if(args != 1) { - printf("arg # mismatch for opcode %x\n", opcode); - } - sprintf(buffer,"%s\t($%02x,S),Y",out,(word32)(byte)(val)); - show_line(outfile, oldkpc,instr,args+1,buffer); - break; - case DISP16: - if(args != 2) { - printf("arg # mismatch for opcode %x\n", opcode); - } - sprintf(buffer,"%s\t$%04x", out, - (word32)(kpc+(signed)(word16)(val)) & 0xffff); - show_line(outfile, oldkpc,instr,args+1,buffer); - break; - case MVPMVN: - if(args != 2) { - printf("arg # mismatch for opcode %x\n", opcode); - } - sprintf(buffer,"%s\t$%02x,$%02x",out,val&0xff,val>>8); - show_line(outfile, oldkpc,instr,args+1,buffer); - break; - case SEPVAL: - case REPVAL: - if(args != 1) { - printf("arg # mismatch for opcode %x\n", opcode); - } - sprintf(buffer,"%s\t#$%02x",out,val); - show_line(outfile, oldkpc,instr,args+1,buffer); - break; - default: - printf("argument type: %d unexpected\n", type); - break; - } + switch(type) { + case ABS: + if(args != 2) { + printf("arg # mismatch for opcode %x\n", opcode); + } + sprintf(buffer,"%s\t$%04x",out,val); + show_line(outfile, oldkpc,instr,args+1,buffer); + break; + case ABSX: + if(args != 2) { + printf("arg # mismatch for opcode %x\n", opcode); + } + sprintf(buffer,"%s\t$%04x,X",out,val); + show_line(outfile, oldkpc,instr,args+1,buffer); + break; + case ABSY: + if(args != 2) { + printf("arg # mismatch for opcode %x\n", opcode); + } + sprintf(buffer,"%s\t$%04x,Y",out,val); + show_line(outfile, oldkpc,instr,args+1,buffer); + break; + case ABSLONG: + if(args != 3) { + printf("arg # mismatch for opcode %x\n", opcode); + } + sprintf(buffer,"%s\t$%06x",out,val); + show_line(outfile, oldkpc,instr,args+1,buffer); + break; + case ABSIND: + if(args != 2) { + printf("arg # mismatch for opcode %x\n", opcode); + } + sprintf(buffer,"%s\t($%04x)",out,val); + show_line(outfile, oldkpc,instr,args+1,buffer); + break; + case ABSXIND: + if(args != 2) { + printf("arg # mismatch for opcode %x\n", opcode); + } + sprintf(buffer,"%s\t($%04x,X)",out,val); + show_line(outfile, oldkpc,instr,args+1,buffer); + break; + case IMPLY: + if(args != 0) { + printf("arg # mismatch for opcode %x\n", opcode); + } + sprintf(buffer,"%s",out); + show_line(outfile, oldkpc,instr,args+1,buffer); + break; + case ACCUM: + if(args != 0) { + printf("arg # mismatch for opcode %x\n", opcode); + } + sprintf(buffer,"%s",out); + show_line(outfile, oldkpc,instr,args+1,buffer); + break; + case IMMED: + if(args == 1) { + sprintf(buffer,"%s\t#$%02x",out,val); + } else if(args == 2) { + sprintf(buffer,"%s\t#$%04x",out,val); + } else { + printf("arg # mismatch for opcode %x\n", opcode); + } + show_line(outfile, oldkpc,instr,args+1,buffer); + break; + case JUST8: + if(args != 1) { + printf("arg # mismatch for opcode %x\n", opcode); + } + sprintf(buffer,"%s\t$%02x",out,val); + show_line(outfile, oldkpc,instr,args+1,buffer); + break; + case DLOC: + if(args != 1) { + printf("arg # mismatch for opcode %x\n", opcode); + } + sprintf(buffer,"%s\t$%02x",out,val); + show_line(outfile, oldkpc,instr,args+1,buffer); + break; + case DLOCX: + if(args != 1) { + printf("arg # mismatch for opcode %x\n", opcode); + } + sprintf(buffer,"%s\t$%02x,X",out,val); + show_line(outfile, oldkpc,instr,args+1,buffer); + break; + case DLOCY: + if(args != 1) { + printf("arg # mismatch for opcode %x\n", opcode); + } + sprintf(buffer,"%s\t$%02x,Y",out,val); + show_line(outfile, oldkpc,instr,args+1,buffer); + break; + case LONG: + if(args != 3) { + printf("arg # mismatch for opcode %x\n", opcode); + } + sprintf(buffer,"%s\t$%06x",out,val); + show_line(outfile, oldkpc,instr,args+1,buffer); + break; + case LONGX: + if(args != 3) { + printf("arg # mismatch for opcode %x\n", opcode); + } + sprintf(buffer,"%s\t$%06x,X",out,val); + show_line(outfile, oldkpc,instr,args+1,buffer); + break; + case DLOCIND: + if(args != 1) { + printf("arg # mismatch for opcode %x\n", opcode); + } + sprintf(buffer,"%s\t($%02x)",out,val); + show_line(outfile, oldkpc,instr,args+1,buffer); + break; + case DLOCINDY: + if(args != 1) { + printf("arg # mismatch for opcode %x\n", opcode); + } + sprintf(buffer,"%s\t($%02x),Y",out,val); + show_line(outfile, oldkpc,instr,args+1,buffer); + break; + case DLOCXIND: + if(args != 1) { + printf("arg # mismatch for opcode %x\n", opcode); + } + sprintf(buffer,"%s\t($%02x,X)",out,val); + show_line(outfile, oldkpc,instr,args+1,buffer); + break; + case DLOCBRAK: + if(args != 1) { + printf("arg # mismatch for opcode %x\n", opcode); + } + sprintf(buffer,"%s\t[$%02x]",out,val); + show_line(outfile, oldkpc,instr,args+1,buffer); + break; + case DLOCBRAKY: + if(args != 1) { + printf("arg # mismatch for opcode %x\n", opcode); + } + sprintf(buffer,"%s\t[$%02x],y",out,val); + show_line(outfile, oldkpc,instr,args+1,buffer); + break; + case DISP8: + if(args != 1) { + printf("arg # mismatch for opcode %x\n", opcode); + } + signed_val = (signed char)val; + sprintf(buffer,"%s\t$%04x",out, + (word32)(kpc+(signed_val)) & 0xffff); + show_line(outfile, oldkpc,instr,args+1,buffer); + break; + case DISP8S: + if(args != 1) { + printf("arg # mismatch for opcode %x\n", opcode); + } + sprintf(buffer,"%s\t$%02x,S",out,(word32)(byte)(val)); + show_line(outfile, oldkpc,instr,args+1,buffer); + break; + case DISP8SINDY: + if(args != 1) { + printf("arg # mismatch for opcode %x\n", opcode); + } + sprintf(buffer,"%s\t($%02x,S),Y",out,(word32)(byte)(val)); + show_line(outfile, oldkpc,instr,args+1,buffer); + break; + case DISP16: + if(args != 2) { + printf("arg # mismatch for opcode %x\n", opcode); + } + sprintf(buffer,"%s\t$%04x", out, + (word32)(kpc+(signed)(word16)(val)) & 0xffff); + show_line(outfile, oldkpc,instr,args+1,buffer); + break; + case MVPMVN: + if(args != 2) { + printf("arg # mismatch for opcode %x\n", opcode); + } + sprintf(buffer,"%s\t$%02x,$%02x",out,val&0xff,val>>8); + show_line(outfile, oldkpc,instr,args+1,buffer); + break; + case SEPVAL: + case REPVAL: + if(args != 1) { + printf("arg # mismatch for opcode %x\n", opcode); + } + sprintf(buffer,"%s\t#$%02x",out,val); + show_line(outfile, oldkpc,instr,args+1,buffer); + break; + default: + printf("argument type: %d unexpected\n", type); + break; + } - return(args+1); + return(args+1); } -void -show_line(FILE *outfile, word32 kaddr, word32 operand, int size, - char *string) -{ - int i; - int opcode; +void show_line(FILE *outfile, word32 kaddr, word32 operand, int size, + char *string) { + int i; + int opcode; - fprintf(outfile, "%02x/%04x: ", kaddr >> 16, kaddr & 0xffff); - opcode = (operand >> 24) & 0xff; - fprintf(outfile,"%02x ", opcode); + fprintf(outfile, "%02x/%04x: ", kaddr >> 16, kaddr & 0xffff); + opcode = (operand >> 24) & 0xff; + fprintf(outfile,"%02x ", opcode); - for(i=1;i> 8; - } - for(;i<5;i++) { - fprintf(outfile, " "); - } - fprintf(outfile,"%s\n", string); + for(i=1; i> 8; + } + for(; i<5; i++) { + fprintf(outfile, " "); + } + fprintf(outfile,"%s\n", string); } -void -halt_printf(const char *fmt, ...) -{ - va_list args; +void halt_printf(const char *fmt, ...) { + va_list args; - va_start(args, fmt); - vprintf(fmt, args); - va_end(args); + va_start(args, fmt); + vprintf(fmt, args); + va_end(args); - set_halt(1); + set_halt(1); } -void -halt2_printf(const char *fmt, ...) -{ - va_list args; +void halt2_printf(const char *fmt, ...) { + va_list args; - va_start(args, fmt); - vprintf(fmt, args); - va_end(args); + va_start(args, fmt); + vprintf(fmt, args); + va_end(args); - set_halt(2); + set_halt(2); } diff --git a/src/engine_c.c b/src/engine_c.c index 0abf736..a080394 100644 --- a/src/engine_c.c +++ b/src/engine_c.c @@ -1,6 +1,7 @@ /* GSport - an Apple //gs Emulator - Copyright (C) 2010 by GSport contributors + Copyright (C) 2010 - 2019 by GSport contributors + Copyright (C) 2016 - 2018 Dagen Brock Based on the KEGS emulator written by and Copyright (C) 2003 Kent Dickey @@ -31,13 +32,14 @@ /* define FCYCS_PTR_FCYCLES_ROUND_SLOW to get accurate 1MHz write to slow mem*/ /* this might help joystick emulation in some Apple //gs games like */ /* Madness */ -# define FCYCS_PTR_FCYCLES_ROUND_SLOW FCYCLES_ROUND; *fcycs_ptr = fcycles; +# define FCYCS_PTR_FCYCLES_ROUND_SLOW FCYCLES_ROUND; *fcycs_ptr = fcycles; #endif #ifndef FCYCS_PTR_FCYCLES_ROUND_SLOW # define FCYCS_PTR_FCYCLES_ROUND_SLOW #endif +extern int g_dbg_step; extern int halt_sim; extern int g_code_red; extern int g_ignore_halts; @@ -55,7 +57,7 @@ extern byte *g_memory_ptr; extern byte *g_rom_fc_ff_ptr; extern byte *g_rom_cards_ptr; extern byte *g_dummy_memory1_ptr; -extern int g_c068_statereg; +extern int g_c068_statereg; unsigned char ioslotsel = 0; unsigned char iostrobe = 0; @@ -82,53 +84,53 @@ int size_tab[] = { }; int bogus[] = { - 0, + 0, #include "op_routs.h" }; -#define FINISH(arg1, arg2) g_ret1 = arg1; g_ret2 = arg2; goto finish; -#define INC_KPC_1 kpc = (kpc & 0xff0000) + ((kpc + 1) & 0xffff); -#define INC_KPC_2 kpc = (kpc & 0xff0000) + ((kpc + 2) & 0xffff); -#define INC_KPC_3 kpc = (kpc & 0xff0000) + ((kpc + 3) & 0xffff); -#define INC_KPC_4 kpc = (kpc & 0xff0000) + ((kpc + 4) & 0xffff); +#define FINISH(arg1, arg2) g_ret1 = arg1; g_ret2 = arg2; goto finish; +#define INC_KPC_1 kpc = (kpc & 0xff0000) + ((kpc + 1) & 0xffff); +#define INC_KPC_2 kpc = (kpc & 0xff0000) + ((kpc + 2) & 0xffff); +#define INC_KPC_3 kpc = (kpc & 0xff0000) + ((kpc + 3) & 0xffff); +#define INC_KPC_4 kpc = (kpc & 0xff0000) + ((kpc + 4) & 0xffff); -#define CYCLES_PLUS_1 fcycles += fplus_1; -#define CYCLES_PLUS_2 fcycles += fplus_2; -#define CYCLES_PLUS_3 fcycles += fplus_3; -#define CYCLES_PLUS_4 fcycles += (fplus_1 + fplus_3); -#define CYCLES_PLUS_5 fcycles += (fplus_2 + fplus_3); -#define CYCLES_MINUS_1 fcycles -= fplus_1; -#define CYCLES_MINUS_2 fcycles -= fplus_2; +#define CYCLES_PLUS_1 fcycles += fplus_1; +#define CYCLES_PLUS_2 fcycles += fplus_2; +#define CYCLES_PLUS_3 fcycles += fplus_3; +#define CYCLES_PLUS_4 fcycles += (fplus_1 + fplus_3); +#define CYCLES_PLUS_5 fcycles += (fplus_2 + fplus_3); +#define CYCLES_MINUS_1 fcycles -= fplus_1; +#define CYCLES_MINUS_2 fcycles -= fplus_2; -#define CYCLES_FINISH fcycles = g_fcycles_stop + fplus_1; +#define CYCLES_FINISH fcycles = g_fcycles_stop + fplus_1; -#define FCYCLES_ROUND fcycles = (int)(fcycles + fplus_x_m1); +#define FCYCLES_ROUND fcycles = (int)(fcycles + fplus_x_m1); #ifdef LOG_PC -# define LOG_PC_MACRO() \ - tmp_pc_ptr = g_log_pc_ptr++; \ - tmp_pc_ptr->dbank_kpc = (dbank << 24) + kpc; \ - tmp_pc_ptr->instr = (opcode << 24) + arg_ptr[1] + \ - (arg_ptr[2] << 8) + (arg_ptr[3] << 16); \ - tmp_pc_ptr->psr_acc = ((psr & ~(0x82)) << 16) + acc + \ - (neg << 23) + ((!zero) << 17); \ - tmp_pc_ptr->xreg_yreg = (xreg << 16) + yreg; \ - tmp_pc_ptr->stack_direct = (stack << 16) + direct; \ - tmp_pc_ptr->dcycs = fcycles + g_last_vbl_dcycs - fplus_2; \ - if(g_log_pc_ptr >= g_log_pc_end_ptr) { \ - /*halt2_printf("log_pc oflow %f\n", tmp_pc_ptr->dcycs);*/ \ - g_log_pc_ptr = g_log_pc_start_ptr; \ - } +# define LOG_PC_MACRO() \ + tmp_pc_ptr = g_log_pc_ptr++; \ + tmp_pc_ptr->dbank_kpc = (dbank << 24) + kpc; \ + tmp_pc_ptr->instr = (opcode << 24) + arg_ptr[1] + \ + (arg_ptr[2] << 8) + (arg_ptr[3] << 16); \ + tmp_pc_ptr->psr_acc = ((psr & ~(0x82)) << 16) + acc + \ + (neg << 23) + ((!zero) << 17); \ + tmp_pc_ptr->xreg_yreg = (xreg << 16) + yreg; \ + tmp_pc_ptr->stack_direct = (stack << 16) + direct; \ + tmp_pc_ptr->dcycs = fcycles + g_last_vbl_dcycs - fplus_2; \ + if(g_log_pc_ptr >= g_log_pc_end_ptr) { \ + /*halt2_printf("log_pc oflow %f\n", tmp_pc_ptr->dcycs);*/ \ + g_log_pc_ptr = g_log_pc_start_ptr; \ + } -# define LOG_DATA_MACRO(in_addr, in_val, in_size) \ - g_log_data_ptr->dcycs = fcycles + g_last_vbl_dcycs; \ - g_log_data_ptr->addr = in_addr; \ - g_log_data_ptr->val = in_val; \ - g_log_data_ptr->size = in_size; \ - g_log_data_ptr++; \ - if(g_log_data_ptr >= g_log_data_end_ptr) { \ - g_log_data_ptr = g_log_data_start_ptr; \ - } +# define LOG_DATA_MACRO(in_addr, in_val, in_size) \ + g_log_data_ptr->dcycs = fcycles + g_last_vbl_dcycs; \ + g_log_data_ptr->addr = in_addr; \ + g_log_data_ptr->val = in_val; \ + g_log_data_ptr->size = in_size; \ + g_log_data_ptr++; \ + if(g_log_data_ptr >= g_log_data_end_ptr) { \ + g_log_data_ptr = g_log_data_start_ptr; \ + } #else # define LOG_PC_MACRO() @@ -137,923 +139,906 @@ int bogus[] = { #endif -#define GET_1BYTE_ARG arg = arg_ptr[1]; -#define GET_2BYTE_ARG arg = arg_ptr[1] + (arg_ptr[2] << 8); -#define GET_3BYTE_ARG arg = arg_ptr[1] + (arg_ptr[2] << 8) + (arg_ptr[3]<<16); +#define GET_1BYTE_ARG arg = arg_ptr[1]; +#define GET_2BYTE_ARG arg = arg_ptr[1] + (arg_ptr[2] << 8); +#define GET_3BYTE_ARG arg = arg_ptr[1] + (arg_ptr[2] << 8) + (arg_ptr[3]<<16); /* HACK HACK HACK */ -#define UPDATE_PSR(dummy, old_psr) \ - if(psr & 0x100) { \ - psr |= 0x30; \ - stack = 0x100 + (stack & 0xff); \ - } \ - if((old_psr ^ psr) & 0x10) { \ - if(psr & 0x10) { \ - xreg = xreg & 0xff; \ - yreg = yreg & 0xff; \ - } \ - } \ - if(((psr & 0x4) == 0) && g_irq_pending) { \ - FINISH(RET_IRQ, 0); \ - } \ - if((old_psr ^ psr) & 0x20) { \ - goto recalc_accsize; \ - } +#define UPDATE_PSR(dummy, old_psr) \ + if(psr & 0x100) { \ + psr |= 0x30; \ + stack = 0x100 + (stack & 0xff); \ + } \ + if((old_psr ^ psr) & 0x10) { \ + if(psr & 0x10) { \ + xreg = xreg & 0xff; \ + yreg = yreg & 0xff; \ + } \ + } \ + if(((psr & 0x4) == 0) && g_irq_pending) { \ + FINISH(RET_IRQ, 0); \ + } \ + if((old_psr ^ psr) & 0x20) { \ + goto recalc_accsize; \ + } extern Page_info page_info_rd_wr[]; extern word32 slow_mem_changed[]; -#define GET_MEMORY8(addr,dest) \ - addr_latch = (addr);\ - CYCLES_PLUS_1; \ - stat = GET_PAGE_INFO_RD(((addr) >> 8) & 0xffff); \ - wstat = PTR2WORD(stat) & 0xff; \ - ptr = stat - wstat + ((addr) & 0xff); \ - if(wstat & (1 << (31 - BANK_IO_BIT)) || iostrobe == 1) { \ - fcycles_tmp1 = fcycles; \ - dest = get_memory8_io_stub((addr), stat, \ - &fcycles_tmp1, fplus_x_m1); \ - fcycles = fcycles_tmp1; \ - } else { \ - dest = *ptr; \ - } +#define GET_MEMORY8(addr,dest) \ + addr_latch = (addr); \ + CYCLES_PLUS_1; \ + stat = GET_PAGE_INFO_RD(((addr) >> 8) & 0xffff); \ + wstat = PTR2WORD(stat) & 0xff; \ + ptr = stat - wstat + ((addr) & 0xff); \ + if(wstat & (1 << (31 - BANK_IO_BIT)) || iostrobe == 1) { \ + fcycles_tmp1 = fcycles; \ + dest = get_memory8_io_stub((addr), stat, \ + &fcycles_tmp1, fplus_x_m1); \ + fcycles = fcycles_tmp1; \ + } else { \ + dest = *ptr; \ + } -#define GET_MEMORY(addr,dest) GET_MEMORY8(addr, dest) +#define GET_MEMORY(addr,dest) GET_MEMORY8(addr, dest) -#define GET_MEMORY16(addr, dest, in_bank) \ - save_addr = addr; \ - stat = GET_PAGE_INFO_RD(((addr) >> 8) & 0xffff); \ - wstat = PTR2WORD(stat) & 0xff; \ - ptr = stat - wstat + ((addr) & 0xff); \ - if((wstat & (1 << (31 - BANK_IO_BIT))) || (((addr) & 0xff) == 0xff)) { \ - fcycles_tmp1 = fcycles; \ - dest = get_memory16_pieces_stub((addr), stat, \ - &fcycles_tmp1, fplus_ptr, in_bank); \ - fcycles = fcycles_tmp1; \ - } else { \ - CYCLES_PLUS_2; \ - dest = ptr[0] + (ptr[1] << 8); \ - } \ - addr_latch = save_addr; +#define GET_MEMORY16(addr, dest, in_bank) \ + save_addr = addr; \ + stat = GET_PAGE_INFO_RD(((addr) >> 8) & 0xffff); \ + wstat = PTR2WORD(stat) & 0xff; \ + ptr = stat - wstat + ((addr) & 0xff); \ + if((wstat & (1 << (31 - BANK_IO_BIT))) || (((addr) & 0xff) == 0xff)) { \ + fcycles_tmp1 = fcycles; \ + dest = get_memory16_pieces_stub((addr), stat, \ + &fcycles_tmp1, fplus_ptr, in_bank); \ + fcycles = fcycles_tmp1; \ + } else { \ + CYCLES_PLUS_2; \ + dest = ptr[0] + (ptr[1] << 8); \ + } \ + addr_latch = save_addr; -#define GET_MEMORY24(addr, dest, in_bank) \ - save_addr = addr; \ - stat = GET_PAGE_INFO_RD(((addr) >> 8) & 0xffff); \ - wstat = PTR2WORD(stat) & 0xff; \ - ptr = stat - wstat + ((addr) & 0xff); \ - if((wstat & (1 << (31 - BANK_IO_BIT))) || (((addr) & 0xfe) == 0xfe)) { \ - fcycles_tmp1 = fcycles; \ - dest = get_memory24_pieces_stub((addr), stat, \ - &fcycles_tmp1, fplus_ptr, in_bank); \ - fcycles = fcycles_tmp1; \ - } else { \ - CYCLES_PLUS_3; \ - dest = ptr[0] + (ptr[1] << 8) + (ptr[2] << 16); \ - } \ - addr_latch = save_addr; +#define GET_MEMORY24(addr, dest, in_bank) \ + save_addr = addr; \ + stat = GET_PAGE_INFO_RD(((addr) >> 8) & 0xffff); \ + wstat = PTR2WORD(stat) & 0xff; \ + ptr = stat - wstat + ((addr) & 0xff); \ + if((wstat & (1 << (31 - BANK_IO_BIT))) || (((addr) & 0xfe) == 0xfe)) { \ + fcycles_tmp1 = fcycles; \ + dest = get_memory24_pieces_stub((addr), stat, \ + &fcycles_tmp1, fplus_ptr, in_bank); \ + fcycles = fcycles_tmp1; \ + } else { \ + CYCLES_PLUS_3; \ + dest = ptr[0] + (ptr[1] << 8) + (ptr[2] << 16); \ + } \ + addr_latch = save_addr; -#define GET_MEMORY_DIRECT_PAGE16(addr, dest) \ - save_addr = addr; \ - if(psr & 0x100) { \ - if((direct & 0xff) == 0) { \ - save_addr = (save_addr & 0xff) + direct; \ - } \ - } \ - if((psr & 0x100) && (((addr) & 0xff) == 0xff)) { \ - GET_MEMORY8(save_addr, getmem_tmp); \ - save_addr = (save_addr + 1) & 0xffff; \ - if((direct & 0xff) == 0) { \ - save_addr = (save_addr & 0xff) + direct; \ - } \ - GET_MEMORY8(save_addr, dest); \ - dest = (dest << 8) + getmem_tmp; \ - } else { \ - GET_MEMORY16(save_addr, dest, 1); \ - } +#define GET_MEMORY_DIRECT_PAGE16(addr, dest) \ + save_addr = addr; \ + if(psr & 0x100) { \ + if((direct & 0xff) == 0) { \ + save_addr = (save_addr & 0xff) + direct; \ + } \ + } \ + if((psr & 0x100) && (((addr) & 0xff) == 0xff)) { \ + GET_MEMORY8(save_addr, getmem_tmp); \ + save_addr = (save_addr + 1) & 0xffff; \ + if((direct & 0xff) == 0) { \ + save_addr = (save_addr & 0xff) + direct; \ + } \ + GET_MEMORY8(save_addr, dest); \ + dest = (dest << 8) + getmem_tmp; \ + } else { \ + GET_MEMORY16(save_addr, dest, 1); \ + } -#define PUSH8(arg) \ - SET_MEMORY8(stack, arg); \ - stack--; \ - if(psr & 0x100) { \ - stack = 0x100 | (stack & 0xff); \ - } \ - stack = stack & 0xffff; +#define PUSH8(arg) \ + SET_MEMORY8(stack, arg); \ + stack--; \ + if(psr & 0x100) { \ + stack = 0x100 | (stack & 0xff); \ + } \ + stack = stack & 0xffff; -#define PUSH16(arg) \ - if((stack & 0xfe) == 0) { \ - /* stack will cross page! */ \ - PUSH8((arg) >> 8); \ - PUSH8(arg); \ - } else { \ - stack -= 2; \ - stack = stack & 0xffff; \ - SET_MEMORY16(stack + 1, arg, 1); \ - } +#define PUSH16(arg) \ + if((stack & 0xfe) == 0) { \ + /* stack will cross page! */ \ + PUSH8((arg) >> 8); \ + PUSH8(arg); \ + } else { \ + stack -= 2; \ + stack = stack & 0xffff; \ + SET_MEMORY16(stack + 1, arg, 1); \ + } -#define PUSH16_UNSAFE(arg) \ - save_addr = (stack - 1) & 0xffff; \ - stack -= 2; \ - if(psr & 0x100) { \ - stack = 0x100 | (stack & 0xff); \ - } \ - stack = stack & 0xffff; \ - SET_MEMORY16(save_addr, arg, 1); +#define PUSH16_UNSAFE(arg) \ + save_addr = (stack - 1) & 0xffff; \ + stack -= 2; \ + if(psr & 0x100) { \ + stack = 0x100 | (stack & 0xff); \ + } \ + stack = stack & 0xffff; \ + SET_MEMORY16(save_addr, arg, 1); -#define PUSH24_UNSAFE(arg) \ - save_addr = (stack - 2) & 0xffff; \ - stack -= 3; \ - if(psr & 0x100) { \ - stack = 0x100 | (stack & 0xff); \ - } \ - stack = stack & 0xffff; \ - SET_MEMORY24(save_addr, arg, 1); +#define PUSH24_UNSAFE(arg) \ + save_addr = (stack - 2) & 0xffff; \ + stack -= 3; \ + if(psr & 0x100) { \ + stack = 0x100 | (stack & 0xff); \ + } \ + stack = stack & 0xffff; \ + SET_MEMORY24(save_addr, arg, 1); -#define PULL8(dest) \ - stack++; \ - if(psr & 0x100) { \ - stack = 0x100 | (stack & 0xff); \ - } \ - stack = stack & 0xffff; \ - GET_MEMORY8(stack, dest); +#define PULL8(dest) \ + stack++; \ + if(psr & 0x100) { \ + stack = 0x100 | (stack & 0xff); \ + } \ + stack = stack & 0xffff; \ + GET_MEMORY8(stack, dest); -#define PULL16(dest) \ - if((stack & 0xfe) == 0xfe) { /* page cross */ \ - PULL8(dest); \ - PULL8(pull_tmp); \ - dest = (pull_tmp << 8) + dest; \ - } else { \ - GET_MEMORY16(stack + 1, dest, 1); \ - stack = (stack + 2) & 0xffff; \ - if(psr & 0x100) { \ - stack = 0x100 | (stack & 0xff); \ - } \ - } +#define PULL16(dest) \ + if((stack & 0xfe) == 0xfe) { /* page cross */ \ + PULL8(dest); \ + PULL8(pull_tmp); \ + dest = (pull_tmp << 8) + dest; \ + } else { \ + GET_MEMORY16(stack + 1, dest, 1); \ + stack = (stack + 2) & 0xffff; \ + if(psr & 0x100) { \ + stack = 0x100 | (stack & 0xff); \ + } \ + } -#define PULL16_UNSAFE(dest) \ - stack = (stack + 1) & 0xffff; \ - if(psr & 0x100) { \ - stack = 0x100 | (stack & 0xff); \ - } \ - GET_MEMORY16(stack, dest, 1); \ - stack = (stack + 1) & 0xffff; \ - if(psr & 0x100) { \ - stack = 0x100 | (stack & 0xff); \ - } +#define PULL16_UNSAFE(dest) \ + stack = (stack + 1) & 0xffff; \ + if(psr & 0x100) { \ + stack = 0x100 | (stack & 0xff); \ + } \ + GET_MEMORY16(stack, dest, 1); \ + stack = (stack + 1) & 0xffff; \ + if(psr & 0x100) { \ + stack = 0x100 | (stack & 0xff); \ + } -#define PULL24(dest) \ - if((stack & 0xfc) == 0xfc) { /* page cross */ \ - PULL8(dest); \ - PULL8(pull_tmp); \ - pull_tmp = (pull_tmp << 8) + dest; \ - PULL8(dest); \ - dest = (dest << 16) + pull_tmp; \ - } else { \ - GET_MEMORY24(stack + 1, dest, 1); \ - stack = (stack + 3) & 0xffff; \ - if(psr & 0x100) { \ - stack = 0x100 | (stack & 0xff); \ - } \ - } +#define PULL24(dest) \ + if((stack & 0xfc) == 0xfc) { /* page cross */ \ + PULL8(dest); \ + PULL8(pull_tmp); \ + pull_tmp = (pull_tmp << 8) + dest; \ + PULL8(dest); \ + dest = (dest << 16) + pull_tmp; \ + } else { \ + GET_MEMORY24(stack + 1, dest, 1); \ + stack = (stack + 3) & 0xffff; \ + if(psr & 0x100) { \ + stack = 0x100 | (stack & 0xff); \ + } \ + } -#define SET_MEMORY8(addr, val) \ - LOG_DATA_MACRO(addr, val, 8); \ - CYCLES_PLUS_1; \ - stat = GET_PAGE_INFO_WR(((addr) >> 8) & 0xffff); \ - wstat = PTR2WORD(stat) & 0xff; \ - ptr = stat - wstat + ((addr) & 0xff); \ - if(wstat) { \ - fcycles_tmp1 = fcycles; \ - set_memory8_io_stub((addr), val, stat, &fcycles_tmp1, \ - fplus_x_m1); \ - fcycles = fcycles_tmp1; \ - } else { \ - *ptr = val; \ - } +#define SET_MEMORY8(addr, val) \ + LOG_DATA_MACRO(addr, val, 8); \ + CYCLES_PLUS_1; \ + stat = GET_PAGE_INFO_WR(((addr) >> 8) & 0xffff); \ + wstat = PTR2WORD(stat) & 0xff; \ + ptr = stat - wstat + ((addr) & 0xff); \ + if(wstat) { \ + fcycles_tmp1 = fcycles; \ + set_memory8_io_stub((addr), val, stat, &fcycles_tmp1, \ + fplus_x_m1); \ + fcycles = fcycles_tmp1; \ + } else { \ + *ptr = val; \ + } -#define SET_MEMORY16(addr, val, in_bank) \ - LOG_DATA_MACRO(addr, val, 16); \ - stat = GET_PAGE_INFO_WR(((addr) >> 8) & 0xffff); \ - wstat = PTR2WORD(stat) & 0xff; \ - ptr = stat - wstat + ((addr) & 0xff); \ - if((wstat) || (((addr) & 0xff) == 0xff)) { \ - fcycles_tmp1 = fcycles; \ - set_memory16_pieces_stub((addr), (val), \ - &fcycles_tmp1, fplus_1, fplus_x_m1, in_bank); \ - fcycles = fcycles_tmp1; \ - } else { \ - CYCLES_PLUS_2; \ - ptr[0] = (val); \ - ptr[1] = (val) >> 8; \ - } +#define SET_MEMORY16(addr, val, in_bank) \ + LOG_DATA_MACRO(addr, val, 16); \ + stat = GET_PAGE_INFO_WR(((addr) >> 8) & 0xffff); \ + wstat = PTR2WORD(stat) & 0xff; \ + ptr = stat - wstat + ((addr) & 0xff); \ + if((wstat) || (((addr) & 0xff) == 0xff)) { \ + fcycles_tmp1 = fcycles; \ + set_memory16_pieces_stub((addr), (val), \ + &fcycles_tmp1, fplus_1, fplus_x_m1, in_bank); \ + fcycles = fcycles_tmp1; \ + } else { \ + CYCLES_PLUS_2; \ + ptr[0] = (val); \ + ptr[1] = (val) >> 8; \ + } -#define SET_MEMORY24(addr, val, in_bank) \ - LOG_DATA_MACRO(addr, val, 24); \ - stat = GET_PAGE_INFO_WR(((addr) >> 8) & 0xffff); \ - wstat = PTR2WORD(stat) & 0xff; \ - ptr = stat - wstat + ((addr) & 0xff); \ - if((wstat) || (((addr) & 0xfe) == 0xfe)) { \ - fcycles_tmp1 = fcycles; \ - set_memory24_pieces_stub((addr), (val), \ - &fcycles_tmp1, fplus_ptr, in_bank); \ - fcycles = fcycles_tmp1; \ - } else { \ - CYCLES_PLUS_3; \ - ptr[0] = (val); \ - ptr[1] = (val) >> 8; \ - ptr[2] = (val) >> 16; \ - } +#define SET_MEMORY24(addr, val, in_bank) \ + LOG_DATA_MACRO(addr, val, 24); \ + stat = GET_PAGE_INFO_WR(((addr) >> 8) & 0xffff); \ + wstat = PTR2WORD(stat) & 0xff; \ + ptr = stat - wstat + ((addr) & 0xff); \ + if((wstat) || (((addr) & 0xfe) == 0xfe)) { \ + fcycles_tmp1 = fcycles; \ + set_memory24_pieces_stub((addr), (val), \ + &fcycles_tmp1, fplus_ptr, in_bank); \ + fcycles = fcycles_tmp1; \ + } else { \ + CYCLES_PLUS_3; \ + ptr[0] = (val); \ + ptr[1] = (val) >> 8; \ + ptr[2] = (val) >> 16; \ + } -void -check_breakpoints(word32 addr) -{ - int count; - int i; +void check_breakpoints(word32 addr) { + int count; + int i; - count = g_num_breakpoints; - for(i = 0; i < count; i++) { - if((g_breakpts[i] & 0xffffff) == addr) { - halt2_printf("Hit breakpoint at %06x\n", addr); - } - } + count = g_num_breakpoints; + for(i = 0; i < count; i++) { + if((g_breakpts[i] & 0xffffff) == addr) { + g_dbg_step = -2; + halt2_printf("Hit breakpoint at %06x\n", addr); + } + } } -word32 -get_memory8_io_stub(word32 addr, byte *stat, double *fcycs_ptr, - double fplus_x_m1) -{ - double fcycles; - word32 wstat; - byte *ptr; - wstat = PTR2WORD(stat) & 0xff; +word32 get_memory8_io_stub(word32 addr, byte *stat, double *fcycs_ptr, + double fplus_x_m1) { + double fcycles; + word32 wstat; + byte *ptr; + wstat = PTR2WORD(stat) & 0xff; - if(wstat & BANK_BREAK) { - check_breakpoints(addr); - } - fcycles = *fcycs_ptr; - if(wstat & BANK_IO2_TMP || iostrobe == 1) { - FCYCLES_ROUND; - *fcycs_ptr = fcycles; - return get_memory_io((addr), fcycs_ptr); - } else { - ptr = stat - wstat + (addr & 0xff); - return *ptr; - } + if(wstat & BANK_BREAK) { + check_breakpoints(addr); + } + fcycles = *fcycs_ptr; + if(wstat & BANK_IO2_TMP || iostrobe == 1) { + FCYCLES_ROUND; + *fcycs_ptr = fcycles; + return get_memory_io((addr), fcycs_ptr); + } else { + ptr = stat - wstat + (addr & 0xff); + return *ptr; + } } -word32 -get_memory16_pieces_stub(word32 addr, byte *stat, double *fcycs_ptr, - Fplus *fplus_ptr, int in_bank) -{ - byte *ptr; - double fcycles, fcycles_tmp1; - double fplus_1; - double fplus_x_m1; - word32 addrp1; - word32 wstat; - word32 addr_latch; - word32 ret; - word32 tmp1; - fcycles = *fcycs_ptr; - fplus_1 = fplus_ptr->plus_1; - fplus_x_m1 = fplus_ptr->plus_x_minus_1; - GET_MEMORY8(addr, tmp1); - addrp1 = addr + 1; - if(in_bank) { - addrp1 = (addr & 0xff0000) + (addrp1 & 0xffff); - } - GET_MEMORY8(addrp1, ret); - *fcycs_ptr = fcycles; - return (ret << 8) + (tmp1); +word32 get_memory16_pieces_stub(word32 addr, byte *stat, double *fcycs_ptr, + Fplus *fplus_ptr, int in_bank) { + byte *ptr; + double fcycles, fcycles_tmp1; + double fplus_1; + double fplus_x_m1; + word32 addrp1; + word32 wstat; + word32 addr_latch; + word32 ret; + word32 tmp1; + fcycles = *fcycs_ptr; + fplus_1 = fplus_ptr->plus_1; + fplus_x_m1 = fplus_ptr->plus_x_minus_1; + GET_MEMORY8(addr, tmp1); + addrp1 = addr + 1; + if(in_bank) { + addrp1 = (addr & 0xff0000) + (addrp1 & 0xffff); + } + GET_MEMORY8(addrp1, ret); + *fcycs_ptr = fcycles; + return (ret << 8) + (tmp1); } -word32 -get_memory24_pieces_stub(word32 addr, byte *stat, double *fcycs_ptr, - Fplus *fplus_ptr, int in_bank) -{ - byte *ptr; - double fcycles, fcycles_tmp1; - double fplus_1; - double fplus_x_m1; - word32 addrp1, addrp2; - word32 wstat; - word32 addr_latch; - word32 ret; - word32 tmp1; - word32 tmp2; - fcycles = *fcycs_ptr; - fplus_1 = fplus_ptr->plus_1; - fplus_x_m1 = fplus_ptr->plus_x_minus_1; - GET_MEMORY8(addr, tmp1); - addrp1 = addr + 1; - if(in_bank) { - addrp1 = (addr & 0xff0000) + (addrp1 & 0xffff); - } - GET_MEMORY8(addrp1, tmp2); - addrp2 = addr + 2; - if(in_bank) { - addrp2 = (addr & 0xff0000) + (addrp2 & 0xffff); - } - GET_MEMORY8(addrp2, ret); - *fcycs_ptr = fcycles; - return (ret << 16) + (tmp2 << 8) + tmp1; +word32 get_memory24_pieces_stub(word32 addr, byte *stat, double *fcycs_ptr, + Fplus *fplus_ptr, int in_bank) { + byte *ptr; + double fcycles, fcycles_tmp1; + double fplus_1; + double fplus_x_m1; + word32 addrp1, addrp2; + word32 wstat; + word32 addr_latch; + word32 ret; + word32 tmp1; + word32 tmp2; + fcycles = *fcycs_ptr; + fplus_1 = fplus_ptr->plus_1; + fplus_x_m1 = fplus_ptr->plus_x_minus_1; + GET_MEMORY8(addr, tmp1); + addrp1 = addr + 1; + if(in_bank) { + addrp1 = (addr & 0xff0000) + (addrp1 & 0xffff); + } + GET_MEMORY8(addrp1, tmp2); + addrp2 = addr + 2; + if(in_bank) { + addrp2 = (addr & 0xff0000) + (addrp2 & 0xffff); + } + GET_MEMORY8(addrp2, ret); + *fcycs_ptr = fcycles; + return (ret << 16) + (tmp2 << 8) + tmp1; } -void -set_memory8_io_stub(word32 addr, word32 val, byte *stat, double *fcycs_ptr, - double fplus_x_m1) -{ - double fcycles; - word32 setmem_tmp1; - word32 tmp1, tmp2; - byte *ptr; - word32 wstat; +void set_memory8_io_stub(word32 addr, word32 val, byte *stat, double *fcycs_ptr, + double fplus_x_m1) { + double fcycles; + word32 setmem_tmp1; + word32 tmp1, tmp2; + byte *ptr; + word32 wstat; - wstat = PTR2WORD(stat) & 0xff; - if(wstat & (1 << (31 - BANK_BREAK_BIT))) { - check_breakpoints(addr); - } - ptr = stat - wstat + ((addr) & 0xff); \ - fcycles = *fcycs_ptr; - if(wstat & (1 << (31 - BANK_IO2_BIT))) { - FCYCLES_ROUND; - *fcycs_ptr = fcycles; - set_memory_io((addr), val, fcycs_ptr); - } else if(wstat & (1 << (31 - BANK_SHADOW_BIT))) { - FCYCS_PTR_FCYCLES_ROUND_SLOW; - tmp1 = (addr & 0xffff); - setmem_tmp1 = g_slow_memory_ptr[tmp1]; - *ptr = val; - if(setmem_tmp1 != ((val) & 0xff)) { - g_slow_memory_ptr[tmp1] = val; - slow_mem_changed[tmp1 >> CHANGE_SHIFT] |= - (1 << (31-((tmp1 >> SHIFT_PER_CHANGE) & 0x1f))); - } - } else if(wstat & (1 << (31 - BANK_SHADOW2_BIT))) { - FCYCS_PTR_FCYCLES_ROUND_SLOW; - tmp2 = (addr & 0xffff); - tmp1 = 0x10000 + tmp2; - setmem_tmp1 = g_slow_memory_ptr[tmp1]; - *ptr = val; - if(setmem_tmp1 != ((val) & 0xff)) { - g_slow_memory_ptr[tmp1] = val; - slow_mem_changed[tmp2 >>CHANGE_SHIFT] |= - (1 <<(31-((tmp2 >> SHIFT_PER_CHANGE) & 0x1f))); - } - } else { - /* breakpoint only */ - *ptr = val; - } + wstat = PTR2WORD(stat) & 0xff; + if(wstat & (1 << (31 - BANK_BREAK_BIT))) { + check_breakpoints(addr); + } + ptr = stat - wstat + ((addr) & 0xff); \ + fcycles = *fcycs_ptr; + if(wstat & (1 << (31 - BANK_IO2_BIT))) { + FCYCLES_ROUND; + *fcycs_ptr = fcycles; + set_memory_io((addr), val, fcycs_ptr); + } else if(wstat & (1 << (31 - BANK_SHADOW_BIT))) { + FCYCS_PTR_FCYCLES_ROUND_SLOW; + tmp1 = (addr & 0xffff); + setmem_tmp1 = g_slow_memory_ptr[tmp1]; + *ptr = val; + if(setmem_tmp1 != ((val) & 0xff)) { + g_slow_memory_ptr[tmp1] = val; + slow_mem_changed[tmp1 >> CHANGE_SHIFT] |= + (1 << (31-((tmp1 >> SHIFT_PER_CHANGE) & 0x1f))); + } + } else if(wstat & (1 << (31 - BANK_SHADOW2_BIT))) { + FCYCS_PTR_FCYCLES_ROUND_SLOW; + tmp2 = (addr & 0xffff); + tmp1 = 0x10000 + tmp2; + setmem_tmp1 = g_slow_memory_ptr[tmp1]; + *ptr = val; + if(setmem_tmp1 != ((val) & 0xff)) { + g_slow_memory_ptr[tmp1] = val; + slow_mem_changed[tmp2 >>CHANGE_SHIFT] |= + (1 <<(31-((tmp2 >> SHIFT_PER_CHANGE) & 0x1f))); + } + } else { + /* breakpoint only */ + *ptr = val; + } } -void -set_memory16_pieces_stub(word32 addr, word32 val, double *fcycs_ptr, - double fplus_1, double fplus_x_m1, int in_bank) -{ - byte *ptr; - byte *stat; - double fcycles, fcycles_tmp1; - word32 addrp1; - word32 wstat; - fcycles = *fcycs_ptr; - SET_MEMORY8(addr, val); - addrp1 = addr + 1; - if(in_bank) { - addrp1 = (addr & 0xff0000) + (addrp1 & 0xffff); - } - SET_MEMORY8(addrp1, val >> 8); +void set_memory16_pieces_stub(word32 addr, word32 val, double *fcycs_ptr, + double fplus_1, double fplus_x_m1, int in_bank) { + byte *ptr; + byte *stat; + double fcycles, fcycles_tmp1; + word32 addrp1; + word32 wstat; + fcycles = *fcycs_ptr; + SET_MEMORY8(addr, val); + addrp1 = addr + 1; + if(in_bank) { + addrp1 = (addr & 0xff0000) + (addrp1 & 0xffff); + } + SET_MEMORY8(addrp1, val >> 8); - *fcycs_ptr = fcycles; + *fcycs_ptr = fcycles; } -void -set_memory24_pieces_stub(word32 addr, word32 val, double *fcycs_ptr, - Fplus *fplus_ptr, int in_bank) -{ - byte *ptr; - byte *stat; - double fcycles, fcycles_tmp1; - double fplus_1; - double fplus_x_m1; - word32 addrp1, addrp2; - word32 wstat; +void set_memory24_pieces_stub(word32 addr, word32 val, double *fcycs_ptr, + Fplus *fplus_ptr, int in_bank) { + byte *ptr; + byte *stat; + double fcycles, fcycles_tmp1; + double fplus_1; + double fplus_x_m1; + word32 addrp1, addrp2; + word32 wstat; - fcycles = *fcycs_ptr; - fplus_1 = fplus_ptr->plus_1; - fplus_x_m1 = fplus_ptr->plus_x_minus_1; - SET_MEMORY8(addr, val); - addrp1 = addr + 1; - if(in_bank) { - addrp1 = (addr & 0xff0000) + (addrp1 & 0xffff); - } - SET_MEMORY8(addrp1, val >> 8); - addrp2 = addr + 2; - if(in_bank) { - addrp2 = (addr & 0xff0000) + (addrp2 & 0xffff); - } - SET_MEMORY8(addrp2, val >> 16); + fcycles = *fcycs_ptr; + fplus_1 = fplus_ptr->plus_1; + fplus_x_m1 = fplus_ptr->plus_x_minus_1; + SET_MEMORY8(addr, val); + addrp1 = addr + 1; + if(in_bank) { + addrp1 = (addr & 0xff0000) + (addrp1 & 0xffff); + } + SET_MEMORY8(addrp1, val >> 8); + addrp2 = addr + 2; + if(in_bank) { + addrp2 = (addr & 0xff0000) + (addrp2 & 0xffff); + } + SET_MEMORY8(addrp2, val >> 16); - *fcycs_ptr = fcycles; + *fcycs_ptr = fcycles; } -word32 -get_memory_c(word32 addr, int cycs) -{ - byte *stat; - byte *ptr; - double fcycles, fcycles_tmp1; - double fplus_1; - double fplus_x_m1; - word32 addr_latch; - word32 wstat; - word32 ret; +word32 get_memory_c(word32 addr, int cycs) { + byte *stat; + byte *ptr; + double fcycles, fcycles_tmp1; + double fplus_1; + double fplus_x_m1; + word32 addr_latch; + word32 wstat; + word32 ret; - fcycles = 0; - fplus_1 = 0; - fplus_x_m1 = 0; - GET_MEMORY8(addr, ret); - return ret; + fcycles = 0; + fplus_1 = 0; + fplus_x_m1 = 0; + GET_MEMORY8(addr, ret); + return ret; } -word32 -get_memory16_c(word32 addr, int cycs) -{ - double fcycs; +word32 get_memory16_c(word32 addr, int cycs) { + double fcycs; - fcycs = 0; - return get_memory_c(addr, (int)fcycs) + - (get_memory_c(addr+1, (int)fcycs) << 8); + fcycs = 0; + return get_memory_c(addr, (int)fcycs) + + (get_memory_c(addr+1, (int)fcycs) << 8); } -word32 -get_memory24_c(word32 addr, int cycs) -{ - double fcycs; +word32 get_memory24_c(word32 addr, int cycs) { + double fcycs; - fcycs = 0; - return get_memory_c(addr, (int)fcycs) + - (get_memory_c(addr+1, (int)fcycs) << 8) + - (get_memory_c(addr+2, (int)fcycs) << 16); + fcycs = 0; + return get_memory_c(addr, (int)fcycs) + + (get_memory_c(addr+1, (int)fcycs) << 8) + + (get_memory_c(addr+2, (int)fcycs) << 16); } -void -set_memory_c(word32 addr, word32 val, int cycs) -{ - byte *stat; - byte *ptr; - double fcycles, fcycles_tmp1; - double fplus_1; - double fplus_x_m1; - word32 wstat; - fcycles = g_cur_dcycs - g_last_vbl_dcycs; - fplus_1 = 0; - fplus_x_m1 = 0; - SET_MEMORY8(addr, val); + + + +word32 get_memory32_c(word32 addr, int cycs) { + double fcycs; + + fcycs = 0; + return get_memory_c(addr, (int)fcycs) + + (get_memory_c(addr+1, (int)fcycs) << 8) + + (get_memory_c(addr+2, (int)fcycs) << 16) + + (get_memory_c(addr+3, (int)fcycs) << 24); } -void -set_memory16_c(word32 addr, word32 val, int cycs) -{ - byte *stat; - byte *ptr; - double fcycles, fcycles_tmp1; - double fplus_1, fplus_2; - double fplus_x_m1; - word32 wstat; - fcycles = g_cur_dcycs - g_last_vbl_dcycs; - fplus_1 = 0; - fplus_2 = 0; - fplus_x_m1 = 0; - SET_MEMORY16(addr, val, 0); + +void set_memory_c(word32 addr, word32 val, int cycs) { + byte *stat; + byte *ptr; + double fcycles, fcycles_tmp1; + double fplus_1; + double fplus_x_m1; + word32 wstat; + fcycles = g_cur_dcycs - g_last_vbl_dcycs; + fplus_1 = 0; + fplus_x_m1 = 0; + SET_MEMORY8(addr, val); } -void -set_memory24_c(word32 addr, word32 val, int cycs) -{ - set_memory_c(addr, val, 0); - set_memory_c(addr + 1, val >> 8, 0); - set_memory_c(addr + 2, val >> 16, 0); +void set_memory16_c(word32 addr, word32 val, int cycs) { + byte *stat; + byte *ptr; + double fcycles, fcycles_tmp1; + double fplus_1, fplus_2; + double fplus_x_m1; + word32 wstat; + + fcycles = g_cur_dcycs - g_last_vbl_dcycs; + fplus_1 = 0; + fplus_2 = 0; + fplus_x_m1 = 0; + SET_MEMORY16(addr, val, 0); } -word32 -do_adc_sbc8(word32 in1, word32 in2, word32 psr, int sub) -{ - word32 sum, carry, overflow; - word32 zero; - int decimal; - - overflow = 0; - decimal = psr & 8; - if(sub) { - in2 = (in2 ^ 0xff); - } - if(!decimal) { - sum = (in1 & 0xff) + in2 + (psr & 1); - overflow = ((sum ^ in2) >> 1) & 0x40; - } else { - /* decimal */ - sum = (in1 & 0xf) + (in2 & 0xf) + (psr & 1); - if(sub) { - if(sum < 0x10) { - sum = (sum - 0x6) & 0xf; - } - } else { - if(sum >= 0xa) { - sum = (sum - 0xa) | 0x10; - } - } - - sum = (in1 & 0xf0) + (in2 & 0xf0) + sum; - overflow = ((sum >> 2) ^ (sum >> 1)) & 0x40; - if(sub) { - if(sum < 0x100) { - sum = (sum + 0xa0) & 0xff; - } - } else { - if(sum >= 0xa0) { - sum += 0x60; - } - } - } - - zero = ((sum & 0xff) == 0); - carry = (sum >= 0x100); - if((in1 ^ in2) & 0x80) { - overflow = 0; - } - - psr = psr & (~0xc3); - psr = psr + (sum & 0x80) + overflow + (zero << 1) + carry; - - return (psr << 16) + (sum & 0xff); +void set_memory24_c(word32 addr, word32 val, int cycs) { + set_memory_c(addr, val, 0); + set_memory_c(addr + 1, val >> 8, 0); + set_memory_c(addr + 2, val >> 16, 0); } -word32 -do_adc_sbc16(word32 in1, word32 in2, word32 psr, int sub) -{ - word32 sum, carry, overflow; - word32 tmp1, tmp2; - word32 zero; - int decimal; - - overflow = 0; - decimal = psr & 8; - if(!decimal) { - if(sub) { - in2 = (in2 ^ 0xffff); - } - sum = in1 + in2 + (psr & 1); - overflow = ((sum ^ in2) >> 9) & 0x40; - } else { - /* decimal */ - if(sub) { - tmp1 = do_adc_sbc8(in1 & 0xff, in2 & 0xff, psr, sub); - psr = (tmp1 >> 16); - tmp2 = do_adc_sbc8((in1 >> 8) & 0xff, - (in2 >> 8) & 0xff, psr, sub); - in2 = (in2 ^ 0xfffff); - } else { - tmp1 = do_adc_sbc8(in1 & 0xff, in2 & 0xff, psr, sub); - psr = (tmp1 >> 16); - tmp2 = do_adc_sbc8((in1 >> 8) & 0xff, - (in2 >> 8) &0xff, psr, sub); - } - sum = ((tmp2 & 0xff) << 8) + (tmp1 & 0xff) + - (((tmp2 >> 16) & 1) << 16); - overflow = (tmp2 >> 16) & 0x40; - } - - zero = ((sum & 0xffff) == 0); - carry = (sum >= 0x10000); - if((in1 ^ in2) & 0x8000) { - overflow = 0; - } - - psr = psr & (~0xc3); - psr = psr + ((sum & 0x8000) >> 8) + overflow + (zero << 1) + carry; - - return (psr << 16) + (sum & 0xffff); +void set_memory32_c(word32 addr, word32 val, int cycs) { + set_memory_c(addr, val, 0); + set_memory_c(addr + 1, val >> 8, 0); + set_memory_c(addr + 2, val >> 16, 0); + set_memory_c(addr + 3, val >> 24, 0); } -int g_ret1; -int g_ret2; -void -fixed_memory_ptrs_init() -{ - /* set g_slow_memory_ptr, g_rom_fc_ff_ptr, g_dummy_memory1_ptr, */ - /* and rom_cards_ptr */ +word32 do_adc_sbc8(word32 in1, word32 in2, word32 psr, int sub) { + word32 sum, carry, overflow; + word32 zero; + int decimal; - // OG Filled allocated ptr parameter to free the memory - g_slow_memory_ptr = memalloc_align(128*1024, 0, (void**)&g_slow_memory_ptr_allocated); - g_dummy_memory1_ptr = memalloc_align(256, 1024, (void**)&g_dummy_memory1_ptr_allocated); - g_rom_fc_ff_ptr = memalloc_align(256*1024, 512, (void**)&g_rom_fc_ff_ptr_allocated); - g_rom_cards_ptr = memalloc_align(16*256, 256, (void**)&g_rom_cards_ptr_allocated); + overflow = 0; + decimal = psr & 8; + if(sub) { + in2 = (in2 ^ 0xff); + } + if(!decimal) { + sum = (in1 & 0xff) + in2 + (psr & 1); + overflow = ((sum ^ in2) >> 1) & 0x40; + } else { + /* decimal */ + sum = (in1 & 0xf) + (in2 & 0xf) + (psr & 1); + if(sub) { + if(sum < 0x10) { + sum = (sum - 0x6) & 0xf; + } + } else { + if(sum >= 0xa) { + sum = (sum - 0xa) | 0x10; + } + } + + sum = (in1 & 0xf0) + (in2 & 0xf0) + sum; + overflow = ((sum >> 2) ^ (sum >> 1)) & 0x40; + if(sub) { + if(sum < 0x100) { + sum = (sum + 0xa0) & 0xff; + } + } else { + if(sum >= 0xa0) { + sum += 0x60; + } + } + } + + zero = ((sum & 0xff) == 0); + carry = (sum >= 0x100); + if((in1 ^ in2) & 0x80) { + overflow = 0; + } + + psr = psr & (~0xc3); + psr = psr + (sum & 0x80) + overflow + (zero << 1) + carry; + + return (psr << 16) + (sum & 0xff); +} + +word32 do_adc_sbc16(word32 in1, word32 in2, word32 psr, int sub) { + word32 sum, carry, overflow; + word32 tmp1, tmp2; + word32 zero; + int decimal; + + overflow = 0; + decimal = psr & 8; + if(!decimal) { + if(sub) { + in2 = (in2 ^ 0xffff); + } + sum = in1 + in2 + (psr & 1); + overflow = ((sum ^ in2) >> 9) & 0x40; + } else { + /* decimal */ + if(sub) { + tmp1 = do_adc_sbc8(in1 & 0xff, in2 & 0xff, psr, sub); + psr = (tmp1 >> 16); + tmp2 = do_adc_sbc8((in1 >> 8) & 0xff, + (in2 >> 8) & 0xff, psr, sub); + in2 = (in2 ^ 0xfffff); + } else { + tmp1 = do_adc_sbc8(in1 & 0xff, in2 & 0xff, psr, sub); + psr = (tmp1 >> 16); + tmp2 = do_adc_sbc8((in1 >> 8) & 0xff, + (in2 >> 8) &0xff, psr, sub); + } + sum = ((tmp2 & 0xff) << 8) + (tmp1 & 0xff) + + (((tmp2 >> 16) & 1) << 16); + overflow = (tmp2 >> 16) & 0x40; + } + + zero = ((sum & 0xffff) == 0); + carry = (sum >= 0x10000); + if((in1 ^ in2) & 0x8000) { + overflow = 0; + } + + psr = psr & (~0xc3); + psr = psr + ((sum & 0x8000) >> 8) + overflow + (zero << 1) + carry; + + return (psr << 16) + (sum & 0xffff); +} + +int g_ret1; +int g_ret2; + + +void fixed_memory_ptrs_init() { + /* set g_slow_memory_ptr, g_rom_fc_ff_ptr, g_dummy_memory1_ptr, */ + /* and rom_cards_ptr */ + + // OG Filled allocated ptr parameter to free the memory + g_slow_memory_ptr = memalloc_align(128*1024, 0, (void**)&g_slow_memory_ptr_allocated); + g_dummy_memory1_ptr = memalloc_align(256, 1024, (void**)&g_dummy_memory1_ptr_allocated); + g_rom_fc_ff_ptr = memalloc_align(256*1024, 512, (void**)&g_rom_fc_ff_ptr_allocated); + g_rom_cards_ptr = memalloc_align(16*256, 256, (void**)&g_rom_cards_ptr_allocated); #if 0 - printf("g_memory_ptr: %08x, dummy_mem: %08x, slow_mem_ptr: %08x\n", - (word32)g_memory_ptr, (word32)g_dummy_memory1_ptr, - (word32)g_slow_memory_ptr); - printf("g_rom_fc_ff_ptr: %08x, g_rom_cards_ptr: %08x\n", - (word32)g_rom_fc_ff_ptr, (word32)g_rom_cards_ptr); - printf("page_info_rd = %08x, page_info_wr end = %08x\n", - (word32)&(page_info_rd_wr[0]), - (word32)&(page_info_rd_wr[PAGE_INFO_PAD_SIZE+0x1ffff].rd_wr)); + printf("g_memory_ptr: %08x, dummy_mem: %08x, slow_mem_ptr: %08x\n", + (word32)g_memory_ptr, (word32)g_dummy_memory1_ptr, + (word32)g_slow_memory_ptr); + printf("g_rom_fc_ff_ptr: %08x, g_rom_cards_ptr: %08x\n", + (word32)g_rom_fc_ff_ptr, (word32)g_rom_cards_ptr); + printf("page_info_rd = %08x, page_info_wr end = %08x\n", + (word32)&(page_info_rd_wr[0]), + (word32)&(page_info_rd_wr[PAGE_INFO_PAD_SIZE+0x1ffff].rd_wr)); #endif } -// OG added fixed_memory_ptrs_shut -void fixed_memory_ptrs_shut() -{ - - free(g_slow_memory_ptr_allocated); - free(g_dummy_memory1_ptr_allocated); - free(g_rom_fc_ff_ptr_allocated); - free(g_rom_cards_ptr_allocated); - g_slow_memory_ptr=g_slow_memory_ptr_allocated= NULL; - g_dummy_memory1_ptr = g_dummy_memory1_ptr_allocated = NULL; - g_rom_fc_ff_ptr = g_rom_fc_ff_ptr_allocated = NULL; - g_rom_cards_ptr = g_rom_cards_ptr = NULL; -} +// OG added fixed_memory_ptrs_shut +void fixed_memory_ptrs_shut() { - -word32 -get_itimer() -{ + free(g_slow_memory_ptr_allocated); + free(g_dummy_memory1_ptr_allocated); + free(g_rom_fc_ff_ptr_allocated); + free(g_rom_cards_ptr_allocated); + g_slow_memory_ptr=g_slow_memory_ptr_allocated= NULL; + g_dummy_memory1_ptr = g_dummy_memory1_ptr_allocated = NULL; + g_rom_fc_ff_ptr = g_rom_fc_ff_ptr_allocated = NULL; + // g_rom_cards_ptr = g_rom_cards_ptr = NULL; // a mistake? + g_rom_cards_ptr = NULL; +} + + +word32 get_itimer() { #if defined(_WIN32) - LARGE_INTEGER count; - if (QueryPerformanceCounter(&count)) - return count.LowPart; - else - return 0; + LARGE_INTEGER count; + if (QueryPerformanceCounter(&count)) + return count.LowPart; + else + return 0; #elif defined(__i386) && defined(__GNUC__) - /* Here's my bad ia32 asm code to do rdtsc */ - /* Linux source uses: */ - /* asm volatile("rdtsc" : "=a"(ret) : : "edx"); */ - /* asm volatile("rdtsc" : "=%eax"(ret) : : "%edx"); */ + /* Here's my bad ia32 asm code to do rdtsc */ + /* Linux source uses: */ + /* asm volatile("rdtsc" : "=a"(ret) : : "edx"); */ + /* asm volatile("rdtsc" : "=%eax"(ret) : : "%edx"); */ - /* GCC bug report 2001-03/msg00786.html used: */ - /*register word64 dtmp; */ - /*asm volatile ("rdtsc" : "=A" (dtmp)); */ - /*return (word32)dtmp; */ + /* GCC bug report 2001-03/msg00786.html used: */ + /*register word64 dtmp; */ + /*asm volatile ("rdtsc" : "=A" (dtmp)); */ + /*return (word32)dtmp; */ - register word32 ret; + register word32 ret; - asm volatile ("rdtsc;movl %%eax,%0" : "=r"(ret) : : "%eax","%edx"); + asm volatile ("rdtsc;movl %%eax,%0" : "=r" (ret) : : "%eax","%edx"); - return ret; + return ret; #elif defined(__POWERPC__) && defined(__GNUC__) - register word32 ret; + register word32 ret; - asm volatile ("mftb %0" : "=r"(ret)); - return ret; + asm volatile ("mftb %0" : "=r" (ret)); + return ret; #else - return 0; + return 0; #endif } -void -set_halt_act(int val) -{ - if(val == 1 && g_ignore_halts && !g_user_halt_bad) { - g_code_red++; - } else { - halt_sim |= val; - g_fcycles_stop = (double)0.0; - } +void set_halt_act(int val) { + if(val == 1 && g_ignore_halts && !g_user_halt_bad) { + g_code_red++; + } else { + halt_sim |= val; + g_fcycles_stop = (double)0.0; + } } -void -clr_halt_act() -{ - halt_sim = 0; +void clr_halt_act() { + halt_sim = 0; } -word32 -get_remaining_operands(word32 addr, word32 opcode, word32 psr, Fplus *fplus_ptr) -{ - byte *stat; - byte *ptr; - double fcycles, fcycles_tmp1; - double fplus_1, fplus_2, fplus_3; - double fplus_x_m1; - word32 addr_latch; - word32 wstat; - word32 save_addr; - word32 arg; - word32 addrp1; - int size; +word32 get_remaining_operands(word32 addr, word32 opcode, word32 psr, Fplus *fplus_ptr) { + byte *stat; + byte *ptr; + double fcycles, fcycles_tmp1; + double fplus_1, fplus_2, fplus_3; + double fplus_x_m1; + word32 addr_latch; + word32 wstat; + word32 save_addr; + word32 arg; + word32 addrp1; + int size; - fcycles = 0; - fplus_1 = 0; - fplus_2 = 0; - fplus_3 = 0; - fplus_x_m1 = 0; + fcycles = 0; + fplus_1 = 0; + fplus_2 = 0; + fplus_3 = 0; + fplus_x_m1 = 0; - size = size_tab[opcode]; + size = size_tab[opcode]; - addrp1 = (addr & 0xff0000) + ((addr + 1) & 0xffff); - switch(size) { - case 0: - arg = 0; /* no args */ - break; - case 1: - GET_MEMORY8(addrp1, arg); - break; /* 1 arg, already done */ - case 2: - GET_MEMORY16(addrp1, arg, 1); - break; - case 3: - GET_MEMORY24(addrp1, arg, 1); - break; - case 4: - if(psr & 0x20) { - GET_MEMORY8(addrp1, arg); - } else { - GET_MEMORY16(addrp1, arg, 1); - } - break; - case 5: - if(psr & 0x10) { - GET_MEMORY8(addrp1, arg); - } else { - GET_MEMORY16(addrp1, arg, 1); - } - break; - default: - printf("Unknown size: %d\n", size); - arg = 0; - exit(-2); - } + addrp1 = (addr & 0xff0000) + ((addr + 1) & 0xffff); + switch(size) { + case 0: + arg = 0; /* no args */ + break; + case 1: + GET_MEMORY8(addrp1, arg); + break; /* 1 arg, already done */ + case 2: + GET_MEMORY16(addrp1, arg, 1); + break; + case 3: + GET_MEMORY24(addrp1, arg, 1); + break; + case 4: + if(psr & 0x20) { + GET_MEMORY8(addrp1, arg); + } else { + GET_MEMORY16(addrp1, arg, 1); + } + break; + case 5: + if(psr & 0x10) { + GET_MEMORY8(addrp1, arg); + } else { + GET_MEMORY16(addrp1, arg, 1); + } + break; + default: + printf("Unknown size: %d\n", size); + arg = 0; + exit(-2); + } - return arg; + return arg; } -#define FETCH_OPCODE \ - addr = kpc; \ - CYCLES_PLUS_2; \ - stat = GET_PAGE_INFO_RD(((addr) >> 8) & 0xffff); \ - wstat = PTR2WORD(stat) & 0xff; \ - ptr = stat - wstat + ((addr) & 0xff); \ - arg_ptr = ptr; \ - opcode = *ptr; \ - if((wstat & (1 << (31-BANK_IO_BIT))) || ((addr & 0xff) > 0xfc)) {\ - if(wstat & BANK_BREAK) { \ - check_breakpoints(addr); \ - } \ - if((addr & 0xfffff0) == 0x00c700) { \ - if(addr == 0xc700) { \ - FINISH(RET_C700, 0); \ - } else if(addr == 0xc70a) { \ - FINISH(RET_C70A, 0); \ - } else if(addr == 0xc70d) { \ - FINISH(RET_C70D, 0); \ - } \ - } \ - if(wstat & (1 << (31 - BANK_IO2_BIT)) || iostrobe == 1) { \ - FCYCLES_ROUND; \ - fcycles_tmp1 = fcycles; \ - opcode = get_memory_io((addr), &fcycles_tmp1); \ - fcycles = fcycles_tmp1; \ - } else { \ - opcode = *ptr; \ - } \ - arg = get_remaining_operands(addr, opcode, psr, fplus_ptr);\ - arg_ptr = (byte *)&tmp_bytes; \ - arg_ptr[1] = arg; \ - arg_ptr[2] = arg >> 8; \ - arg_ptr[3] = arg >> 16; \ - } +#define FETCH_OPCODE \ + addr = kpc; \ + CYCLES_PLUS_2; \ + stat = GET_PAGE_INFO_RD(((addr) >> 8) & 0xffff); \ + wstat = PTR2WORD(stat) & 0xff; \ + ptr = stat - wstat + ((addr) & 0xff); \ + arg_ptr = ptr; \ + opcode = *ptr; \ + if((wstat & (1 << (31-BANK_IO_BIT))) || ((addr & 0xff) > 0xfc)) { \ + if(wstat & BANK_BREAK) { \ + check_breakpoints(addr); \ + } \ + if((addr & 0xfffff0) == 0x00c700) { \ + if(addr == 0xc700) { \ + FINISH(RET_C700, 0); \ + } else if(addr == 0xc70a) { \ + FINISH(RET_C70A, 0); \ + } else if(addr == 0xc70d) { \ + FINISH(RET_C70D, 0); \ + } \ + } \ + if(wstat & (1 << (31 - BANK_IO2_BIT)) || iostrobe == 1) { \ + FCYCLES_ROUND; \ + fcycles_tmp1 = fcycles; \ + opcode = get_memory_io((addr), &fcycles_tmp1); \ + fcycles = fcycles_tmp1; \ + } else { \ + opcode = *ptr; \ + } \ + arg = get_remaining_operands(addr, opcode, psr, fplus_ptr); \ + arg_ptr = (byte *)&tmp_bytes; \ + arg_ptr[1] = arg; \ + arg_ptr[2] = arg >> 8; \ + arg_ptr[3] = arg >> 16; \ + } -int -enter_engine(Engine_reg *engine_ptr) -{ - register byte *ptr; - byte *arg_ptr; - Pc_log *tmp_pc_ptr; - byte *stat; - word32 wstat; - word32 arg; - register word32 kpc; - register word32 acc; - register word32 xreg; - register word32 yreg; - word32 stack; - word32 dbank; - register word32 direct; - register word32 psr; - register word32 zero; - register word32 neg; - word32 getmem_tmp; - word32 save_addr; - word32 pull_tmp; - word32 tmp_bytes; - double fcycles; - Fplus *fplus_ptr; - double fplus_1; - double fplus_2; - double fplus_3; - double fplus_x_m1; - double fcycles_tmp1; +int enter_engine(Engine_reg *engine_ptr) { + register byte *ptr; + byte *arg_ptr; + Pc_log *tmp_pc_ptr; + byte *stat; + word32 wstat; + word32 arg; + register word32 kpc; + register word32 acc; + register word32 xreg; + register word32 yreg; + word32 stack; + word32 dbank; + register word32 direct; + register word32 psr; + register word32 zero; + register word32 neg; + word32 getmem_tmp; + word32 save_addr; + word32 pull_tmp; + word32 tmp_bytes; + double fcycles; + Fplus *fplus_ptr; + double fplus_1; + double fplus_2; + double fplus_3; + double fplus_x_m1; + double fcycles_tmp1; - word32 opcode; - register word32 addr; - word32 addr_latch; - word32 tmp1, tmp2; + word32 opcode; + register word32 addr; + word32 addr_latch; + word32 tmp1, tmp2; - tmp_pc_ptr = 0; + tmp_pc_ptr = 0; - kpc = engine_ptr->kpc; - acc = engine_ptr->acc; - xreg = engine_ptr->xreg; - yreg = engine_ptr->yreg; - stack = engine_ptr->stack; - dbank = engine_ptr->dbank; - direct = engine_ptr->direct; - psr = engine_ptr->psr; - fcycles = engine_ptr->fcycles; - fplus_ptr = engine_ptr->fplus_ptr; - zero = !(psr & 2); - neg = (psr >> 7) & 1; + kpc = engine_ptr->kpc; + acc = engine_ptr->acc; + xreg = engine_ptr->xreg; + yreg = engine_ptr->yreg; + stack = engine_ptr->stack; + dbank = engine_ptr->dbank; + direct = engine_ptr->direct; + psr = engine_ptr->psr; + fcycles = engine_ptr->fcycles; + fplus_ptr = engine_ptr->fplus_ptr; + zero = !(psr & 2); + neg = (psr >> 7) & 1; - fplus_1 = fplus_ptr->plus_1; - fplus_2 = fplus_ptr->plus_2; - fplus_3 = fplus_ptr->plus_3; - fplus_x_m1 = fplus_ptr->plus_x_minus_1; + fplus_1 = fplus_ptr->plus_1; + fplus_2 = fplus_ptr->plus_2; + fplus_3 = fplus_ptr->plus_3; + fplus_x_m1 = fplus_ptr->plus_x_minus_1; - g_ret1 = 0; - g_ret2 = 0; + g_ret1 = 0; + g_ret2 = 0; recalc_accsize: - if(psr & 0x20) { - while(fcycles <= g_fcycles_stop) { + if(psr & 0x20) { + while(fcycles <= g_fcycles_stop) { #if 0 - if((neg & ~1) || (psr & (~0x1ff))) { - halt_printf("psr = %04x\n", psr); - } + if((neg & ~1) || (psr & (~0x1ff))) { + halt_printf("psr = %04x\n", psr); + } #endif - FETCH_OPCODE; + FETCH_OPCODE; - LOG_PC_MACRO(); + LOG_PC_MACRO(); - switch(opcode) { - default: - halt_printf("acc8 unk op: %02x\n", opcode); - arg = 9 + switch(opcode) { + default: + halt_printf("acc8 unk op: %02x\n", opcode); + arg = 9 #define ACC8 #include "defs_instr.h" - * 2; - break; + * 2; + break; #include "8inst_c.h" - break; - } - } - } else { - while(fcycles <= g_fcycles_stop) { - FETCH_OPCODE; - LOG_PC_MACRO(); + break; + } + } + } else { + while(fcycles <= g_fcycles_stop) { + FETCH_OPCODE; + LOG_PC_MACRO(); - switch(opcode) { - default: - halt_printf("acc16 unk op: %02x\n", opcode); - arg = 9 + switch(opcode) { + default: + halt_printf("acc16 unk op: %02x\n", opcode); + arg = 9 #undef ACC8 #include "defs_instr.h" - * 2; - break; + * 2; + break; #include "16inst_c.h" - break; - } - } - } + break; + } + } + } finish: - engine_ptr->kpc = kpc; - engine_ptr->acc = acc; - engine_ptr->xreg = xreg; - engine_ptr->yreg = yreg; - engine_ptr->stack = stack; - engine_ptr->dbank = dbank; - engine_ptr->direct = direct; - engine_ptr->fcycles = fcycles; + engine_ptr->kpc = kpc; + engine_ptr->acc = acc; + engine_ptr->xreg = xreg; + engine_ptr->yreg = yreg; + engine_ptr->stack = stack; + engine_ptr->dbank = dbank; + engine_ptr->direct = direct; + engine_ptr->fcycles = fcycles; - psr = psr & (~0x82); - psr |= (neg << 7); - psr |= ((!zero) << 1); + psr = psr & (~0x82); + psr |= (neg << 7); + psr |= ((!zero) << 1); - engine_ptr->psr = psr; + engine_ptr->psr = psr; - return (g_ret1 << 28) + g_ret2; + return (g_ret1 << 28) + g_ret2; } -int g_engine_c_mode = 1; +int g_engine_c_mode = 1; int defs_instr_start_8 = 0; int defs_instr_end_8 = 0; diff --git a/src/fix_mac_menu.m b/src/fix_mac_menu.m new file mode 100644 index 0000000..bb7670a --- /dev/null +++ b/src/fix_mac_menu.m @@ -0,0 +1,47 @@ +/* + GSport - an Apple //gs Emulator + Copyright (C) 2010 - 2019 by GSport contributors + Copyright (C) 2016 - 2018 Dagen Brock + + Based on the KEGS emulator written by and Copyright (C) 2003 Kent Dickey + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 2 of the License, or (at your + option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#import + + +void fix_mac_menu(void) { + + /* + * add an option-key modifier to all menu shortcuts + * eg, command-Q -> option+command-Q + */ + + @autoreleasepool { + if (NSApp) { + NSMenu *menu = [NSApp mainMenu]; + + for (NSMenuItem *a in [menu itemArray]) { + for (NSMenuItem *b in [[a submenu] itemArray]) { + unsigned m = [b keyEquivalentModifierMask]; + if (m & NSEventModifierFlagCommand) + [b setKeyEquivalentModifierMask: m | NSEventModifierFlagOption]; + } + } + } + } + +} diff --git a/src/fst.h b/src/fst.h new file mode 100644 index 0000000..4d305b3 --- /dev/null +++ b/src/fst.h @@ -0,0 +1,203 @@ +/* + GSport - an Apple //gs Emulator + Copyright (C) 2010 - 2019 by GSport contributors + Copyright (C) 2016 - 2018 Dagen Brock + + Based on the KEGS emulator written by and Copyright (C) 2003 Kent Dickey + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 2 of the License, or (at your + option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +/* generated on Tue Oct 18 20:54:09 2016 */ + +#define GSString255_length 0 +#define GSString255_text 2 + +#define GSString32_length 0 +#define GSString32_text 2 + +#define ResultBuf255_bufSize 0 +#define ResultBuf255_bufString 2 + +#define ResultBuf32_bufSize 0 +#define ResultBuf32_bufString 2 + +#define TimeRec_second 0 +#define TimeRec_minute 1 +#define TimeRec_hour 2 +#define TimeRec_year 3 +#define TimeRec_day 4 +#define TimeRec_month 5 +#define TimeRec_extra 6 +#define TimeRec_weekDay 7 + +#define CreateRecGS_pCount 0 +#define CreateRecGS_pathname 2 +#define CreateRecGS_access 6 +#define CreateRecGS_fileType 8 +#define CreateRecGS_auxType 10 +#define CreateRecGS_storageType 14 +#define CreateRecGS_eof 16 +#define CreateRecGS_resourceEOF 20 + +#define CreateRec_pathname 0 +#define CreateRec_fAccess 4 +#define CreateRec_fileType 6 +#define CreateRec_auxType 8 +#define CreateRec_storageType 12 +#define CreateRec_createDate 14 +#define CreateRec_createTime 16 + +#define DirEntryRecGS_pCount 0 +#define DirEntryRecGS_refNum 2 +#define DirEntryRecGS_flags 4 +#define DirEntryRecGS_base 6 +#define DirEntryRecGS_displacement 8 +#define DirEntryRecGS_name 10 +#define DirEntryRecGS_entryNum 14 +#define DirEntryRecGS_fileType 16 +#define DirEntryRecGS_eof 18 +#define DirEntryRecGS_blockCount 22 +#define DirEntryRecGS_createDateTime 26 +#define DirEntryRecGS_modDateTime 34 +#define DirEntryRecGS_access 42 +#define DirEntryRecGS_auxType 44 +#define DirEntryRecGS_fileSysID 48 +#define DirEntryRecGS_optionList 50 +#define DirEntryRecGS_resourceEOF 54 +#define DirEntryRecGS_resourceBlocks 58 + +#define DirEntryRec_refNum 0 +#define DirEntryRec_flags 2 +#define DirEntryRec_base 4 +#define DirEntryRec_displacement 6 +#define DirEntryRec_nameBuffer 8 +#define DirEntryRec_entryNum 12 +#define DirEntryRec_fileType 14 +#define DirEntryRec_endOfFile 16 +#define DirEntryRec_blockCount 20 +#define DirEntryRec_createTime 24 +#define DirEntryRec_modTime 32 +#define DirEntryRec_access 40 +#define DirEntryRec_auxType 42 +#define DirEntryRec_fileSysID 46 + +#define FileInfoRecGS_pCount 0 +#define FileInfoRecGS_pathname 2 +#define FileInfoRecGS_access 6 +#define FileInfoRecGS_fileType 8 +#define FileInfoRecGS_auxType 10 +#define FileInfoRecGS_storageType 14 +#define FileInfoRecGS_createDateTime 16 +#define FileInfoRecGS_modDateTime 24 +#define FileInfoRecGS_optionList 32 +#define FileInfoRecGS_eof 36 +#define FileInfoRecGS_blocksUsed 40 +#define FileInfoRecGS_resourceEOF 44 +#define FileInfoRecGS_resourceBlocks 48 + +#define FileRec_pathname 0 +#define FileRec_fAccess 4 +#define FileRec_fileType 6 +#define FileRec_auxType 8 +#define FileRec_storageType 12 +#define FileRec_createDate 14 +#define FileRec_createTime 16 +#define FileRec_modDate 18 +#define FileRec_modTime 20 +#define FileRec_blocksUsed 22 + +#define OpenRecGS_pCount 0 +#define OpenRecGS_refNum 2 +#define OpenRecGS_pathname 4 +#define OpenRecGS_requestAccess 8 +#define OpenRecGS_resourceNumber 10 +#define OpenRecGS_access 12 +#define OpenRecGS_fileType 14 +#define OpenRecGS_auxType 16 +#define OpenRecGS_storageType 20 +#define OpenRecGS_createDateTime 22 +#define OpenRecGS_modDateTime 30 +#define OpenRecGS_optionList 38 +#define OpenRecGS_eof 42 +#define OpenRecGS_blocksUsed 46 +#define OpenRecGS_resourceEOF 50 +#define OpenRecGS_resourceBlocks 54 + +#define OpenRec_openRefNum 0 +#define OpenRec_openPathname 2 +#define OpenRec_ioBuffer 6 + +#define VolumeRecGS_pCount 0 +#define VolumeRecGS_devName 2 +#define VolumeRecGS_volName 6 +#define VolumeRecGS_totalBlocks 10 +#define VolumeRecGS_freeBlocks 14 +#define VolumeRecGS_fileSysID 18 +#define VolumeRecGS_blockSize 20 +#define VolumeRecGS_characteristics 22 +#define VolumeRecGS_deviceID 24 + +#define VolumeRec_deviceName 0 +#define VolumeRec_volName 4 +#define VolumeRec_totalBlocks 8 +#define VolumeRec_freeBlocks 12 +#define VolumeRec_fileSysID 16 + +#define JudgeNameRecGS_pCount 0 +#define JudgeNameRecGS_fileSysID 2 +#define JudgeNameRecGS_nameType 4 +#define JudgeNameRecGS_syntax 6 +#define JudgeNameRecGS_maxLen 10 +#define JudgeNameRecGS_name 12 +#define JudgeNameRecGS_nameFlags 16 + +#define PositionRecGS_pCount 0 +#define PositionRecGS_refNum 2 +#define PositionRecGS_position 4 + +#define MarkRec_markRefNum 0 +#define MarkRec_position 2 + +#define EOFRecGS_pCount 0 +#define EOFRecGS_refNum 2 +#define EOFRecGS_eof 4 + +#define EOFRec_eofRefNum 0 +#define EOFRec_eofPosition 2 + +#define IORecGS_pCount 0 +#define IORecGS_refNum 2 +#define IORecGS_dataBuffer 4 +#define IORecGS_requestCount 8 +#define IORecGS_transferCount 12 +#define IORecGS_cachePriority 16 + +#define FileIORec_fileRefNum 0 +#define FileIORec_dataBuffer 2 +#define FileIORec_requestCount 6 +#define FileIORec_transferCount 10 + +#define SetPositionRecGS_pCount 0 +#define SetPositionRecGS_refNum 2 +#define SetPositionRecGS_base 4 +#define SetPositionRecGS_displacement 6 + +#define DevNumRecGS_pCount 0 +#define DevNumRecGS_devName 2 +#define DevNumRecGS_devNum 6 + +#define DevNumRec_devName 0 +#define DevNumRec_devNum 4 diff --git a/src/glog.c b/src/glog.c new file mode 100644 index 0000000..2a4e13f --- /dev/null +++ b/src/glog.c @@ -0,0 +1,63 @@ +/* + GSport - an Apple //gs Emulator + Copyright (C) 2010 - 2019 by GSport contributors + Copyright (C) 2016 - 2018 Dagen Brock + + Based on the KEGS emulator written by and Copyright (C) 2003 Kent Dickey + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 2 of the License, or (at your + option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include +#include +#include + +#include "glog.h" + +int glog(const char *s) { + time_t timer; + char buffer[26]; + struct tm* tm_info; + + time(&timer); + tm_info = localtime(&timer); + + strftime(buffer, 26, "%Y-%m-%d %H:%M:%S", tm_info); + printf("%s - %s\n", buffer, s); + + return 0; +} + + +int glogf(const char *fmt, ...) { + + time_t timer; + char buffer[26]; + struct tm* tm_info; + + time(&timer); + tm_info = localtime(&timer); + + strftime(buffer, 26, "%Y-%m-%d %H:%M:%S", tm_info); + + printf("%s - ", buffer); + + va_list ap; + va_start(ap, fmt); + vprintf(fmt, ap); + va_end(ap); + fputc('\n', stdout); + return 0; +} diff --git a/src/glog.h b/src/glog.h new file mode 100644 index 0000000..2178f34 --- /dev/null +++ b/src/glog.h @@ -0,0 +1,30 @@ +/* + GSport - an Apple //gs Emulator + Copyright (C) 2010 - 2019 by GSport contributors + Copyright (C) 2016 - 2018 Dagen Brock + + Based on the KEGS emulator written by and Copyright (C) 2003 Kent Dickey + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 2 of the License, or (at your + option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#ifdef __cplusplus +extern "C" { +#endif + int glog(const char *s); + int glogf(const char *s, ...); +#ifdef __cplusplus +} +#endif diff --git a/src/gsos.h b/src/gsos.h new file mode 100644 index 0000000..07ee158 --- /dev/null +++ b/src/gsos.h @@ -0,0 +1,186 @@ +/* + GSport - an Apple //gs Emulator + Copyright (C) 2010 - 2019 by GSport contributors + Copyright (C) 2016 - 2018 Dagen Brock + + Based on the KEGS emulator written by and Copyright (C) 2003 Kent Dickey + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 2 of the License, or (at your + option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#define readEnableAllowWrite 0x0000 +#define readEnable 0x0001 +#define writeEnable 0x0002 +#define readWriteEnable 0x0003 +#define fileInvisible 0x0004 /* Invisible bit */ +#define backupNeeded 0x0020 /* backup needed bit: CreateRec/ OpenRec access field. (Must be 0 in requestAccess field ) */ +#define renameEnable 0x0040 /* rename enable bit: CreateRec/ OpenRec access and requestAccess fields */ +#define destroyEnable 0x0080 /* destroy enable bit: CreateRec/ OpenRec access and requestAccess fields */ +#define startPlus 0x0000 /* base -> setMark = displacement */ +#define eofMinus 0x0001 /* base -> setMark = eof - displacement */ +#define markPlus 0x0002 /* base -> setMark = mark + displacement */ +#define markMinus 0x0003 /* base -> setMark = mark - displacement */ + +/* cachePriority Codes */ +#define cacheOff 0x0000 /* do not cache blocks invloved in this read */ +#define cacheOn 0x0001 /* cache blocks invloved in this read if possible */ + +/* Error Codes */ +#define badSystemCall 0x0001 /* bad system call number */ +#define invalidPcount 0x0004 /* invalid parameter count */ +#define gsosActive 0x0007 /* GS/OS already active */ + +#ifndef devNotFound /* device not found */ + #define devNotFound 0x0010 +#endif + +#define invalidDevNum 0x0011 /* invalid device number */ +#define drvrBadReq 0x0020 /* bad request or command */ +#define drvrBadCode 0x0021 /* bad control or status code */ +#define drvrBadParm 0x0022 /* bad call parameter */ +#define drvrNotOpen 0x0023 /* character device not open */ +#define drvrPriorOpen 0x0024 /* character device already open */ +#define irqTableFull 0x0025 /* interrupt table full */ +#define drvrNoResrc 0x0026 /* resources not available */ +#define drvrIOError 0x0027 /* I/O error */ +#define drvrNoDevice 0x0028 /* device not connected */ +#define drvrBusy 0x0029 /* call aborted; driver is busy */ +#define drvrWrtProt 0x002B /* device is write protected */ +#define drvrBadCount 0x002C /* invalid byte count */ +#define drvrBadBlock 0x002D /* invalid block address */ +#define drvrDiskSwitch 0x002E /* disk has been switched */ +#define drvrOffLine 0x002F /* device off line/ no media present */ +#define badPathSyntax 0x0040 /* invalid pathname syntax */ +#define tooManyFilesOpen 0x0042 /* too many files open on server volume */ +#define invalidRefNum 0x0043 /* invalid reference number */ + +#ifndef pathNotFound /* subdirectory does not exist */ + #define pathNotFound 0x0044 +#endif + +#define volNotFound 0x0045 /* volume not found */ + +#ifndef fileNotFound /* file not found */ + #define fileNotFound 0x0046 +#endif + +#define dupPathname 0x0047 /* create or rename with existing name */ +#define volumeFull 0x0048 /* volume full error */ +#define volDirFull 0x0049 /* volume directory full */ +#define badFileFormat 0x004A /* version error (incompatible file format) */ + +#ifndef badStoreType /* unsupported (or incorrect) storage type */ + #define badStoreType 0x004B +#endif + +#ifndef eofEncountered /* end-of-file encountered */ + #define eofEncountered 0x004C +#endif + +#define outOfRange 0x004D /* position out of range */ +#define invalidAccess 0x004E /* access not allowed */ +#define buffTooSmall 0x004F /* buffer too small */ +#define fileBusy 0x0050 /* file is already open */ +#define dirError 0x0051 /* directory error */ +#define unknownVol 0x0052 /* unknown volume type */ + +#ifndef paramRangeErr /* parameter out of range */ + #define paramRangeErr 0x0053 +#endif + +#define outOfMem 0x0054 /* out of memory */ +#define dupVolume 0x0057 /* duplicate volume name */ +#define notBlockDev 0x0058 /* not a block device */ + +#ifndef invalidLevel /* specifield level outside legal range */ + #define invalidLevel 0x0059 +#endif + +#define damagedBitMap 0x005A /* block number too large */ +#define badPathNames 0x005B /* invalid pathnames for ChangePath */ +#define notSystemFile 0x005C /* not an executable file */ +#define osUnsupported 0x005D /* Operating System not supported */ + +#ifndef stackOverflow /* too many applications on stack */ + #define stackOverflow 0x005F +#endif + +#define dataUnavail 0x0060 /* Data unavailable */ +#define endOfDir 0x0061 /* end of directory has been reached */ +#define invalidClass 0x0062 /* invalid FST call class */ +#define resForkNotFound 0x0063 /* file does not contain required resource */ +#define invalidFSTID 0x0064 /* error - FST ID is invalid */ +#define invalidFSTop 0x0065 /* invalid FST operation */ +#define fstCaution 0x0066 /* FST handled call, but result is weird */ +#define devNameErr 0x0067 /* device exists with same name as replacement name */ +#define defListFull 0x0068 /* device list is full */ +#define supListFull 0x0069 /* supervisor list is full */ +#define fstError 0x006a /* generic FST error */ +#define resExistsErr 0x0070 /* cannot expand file, resource already exists */ +#define resAddErr 0x0071 /* cannot add resource fork to this type file */ +#define networkError 0x0088 /* generic network error */ + +/* fileSys IDs */ +#define proDOSFSID 0x0001 /* ProDOS/SOS */ +#define dos33FSID 0x0002 /* DOS 3.3 */ +#define dos32FSID 0x0003 /* DOS 3.2 */ +#define dos31FSID 0x0003 /* DOS 3.1 */ +#define appleIIPascalFSID 0x0004 /* Apple II Pascal */ +#define mfsFSID 0x0005 /* Macintosh (flat file system) */ +#define hfsFSID 0x0006 /* Macintosh (hierarchical file system) */ +#define lisaFSID 0x0007 /* Lisa file system */ +#define appleCPMFSID 0x0008 /* Apple CP/M */ +#define charFSTFSID 0x0009 /* Character FST */ +#define msDOSFSID 0x000A /* MS/DOS */ +#define highSierraFSID 0x000B /* High Sierra */ +#define iso9660FSID 0x000C /* ISO 9660 */ +#define appleShareFSID 0x000D /* ISO 9660 */ + +/* FSTInfo.attributes Codes */ +#define characterFST 0x4000 /* character FST */ +#define ucFST 0x8000 /* SCM should upper case pathnames before passing them to the FST */ + +/* QuitRec.flags Codes */ +#define onStack 0x8000 /* place state information about quitting program on the quit return stack */ +#define restartable 0x4000 /* the quitting program is capable of being restarted from its dormant memory */ + +/* storageType Codes */ +#define seedling 0x0001 /* standard file with seedling structure */ +#define standardFile 0x0001 /* standard file type (no resource fork) */ +#define sapling 0x0002 /* standard file with sapling structure */ +#define tree 0x0003 /* standard file with tree structure */ +#define pascalRegion 0x0004 /* UCSD Pascal region on a partitioned disk */ +#define extendedFile 0x0005 /* extended file type (with resource fork) */ +#define directoryFile 0x000D /* volume directory or subdirectory file */ + +/* version Codes */ +#define minorRelNumMask 0x00FF /* minor release number */ +#define majorRelNumMask 0x7F00 /* major release number */ +#define finalRelNumMask 0x8000 /* final release number */ + +/* Other Constants */ +#define isFileExtended 0x8000 /* GetDirEntryGS */ + +/* DControl Codes */ +#define resetDevice 0x0000 +#define formatDevice 0x0001 +#define eject 0x0002 +#define setConfigParameters 0x0003 +#define setWaitStatus 0x0004 +#define setFormatOptions 0x0005 +#define assignPartitionOwner 0x0006 +#define armSignal 0x0007 +#define disarmSignal 0x0008 +#define setPartitionMap 0x0009 diff --git a/src/gsport b/src/gsport new file mode 100755 index 0000000000000000000000000000000000000000..86ab47cd2692fb29fa3c57029a49a6bb1231b814 GIT binary patch literal 985316 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 z zt8)(E!Z7uLVNA>e2=$g`Jmz(7Fn1s&<;YBq*t?xyFc~-rAy#eUDydV^-2Dvw*pDO1BY2XyDlhm|Nk^emwfkNt8b2Of>O+HYGIu}Bm2scV|s$uYaMDl#uh zU63O(gHVixRsM>rg~3^%g~pJJb!aXj7?S8}g^_I3OA@llze_M0B4w^`nFM9n41bO+ zc`mZ!7~oAHdHx{RCP=SP7)6FdB*VxewJuCwBt%z z8^Wr%^Cq+WoUeLFqb;-sy8PvGH1Ft~$S-xi^qI!i1^!!X0XC~+8hXH631h8Li>~D9 zrP-^rg&XN|z7jo}>c2%_WHZ-uR9Ii6`j!887JDtkD{kdyvDeKvg<_qVzYj&l&Yoe)B&s+3I^c!C7#RK<HwaM*YjBBidLQs zwn}qt6#3Bz7a2z(k?`etu)j%Qqe+()&=l?&P%KvFo#;dMp^S_vnKXPT9YKs5gk$FlOU(bL1 zHkjPk%VP4GdxgpKKVT^mIxilnK5c?Tk`}ghUVettI|`@E)lerfdSTG@+c=ZoBup;j zVT{Qq%>JM8cb_(7iS%Ww__2=FBa7YQHa)F;wyRM#>Z(?`ZM(G0Eg-c)Z)c zTVl%aCZPa4PQL9`zNfJIrIKk9cQ)%e_5W%q*Pmzg(@x4P^e7o5SY2q?BCDra=@hG9 zO_C&57pdguSpD>g{~xn@e0`GO_fay~D?{Vb`wB_|cTOB3S{b>T0rQ20!vkfXXK_D5 zTkY|S@Z#|F=b1dQwjC{xD*`2-^HcVDdf=XM!vmhrJIew&s*N~&Ww7M)^petTLs?CB z4_?(aZ}+rzCC=@U9+p0(&swY$teD=?FNkwS(A_p~*(2Y3otyNgcJ9U4gK^VJ$#?GZ zb>*I_UwccJ7Y90es(dNVU;zn_vIf60IO%i7gzx&S^*EQwa91`^Z)#K4zc}DjtJu!z z%U$V?KA-c>@^-l=-6>)j`qz@W;=l-p;U0&2zH{UXz3HRrvitaslG`w%`6_hNXJUU- z>`nm93BhlvB;@vm!KF4ih=1k!}q-pL|M>~@sRV4^r@isGF;6C{j;yQf0 z*xCH#HbS8b39}AH4t@&;6MNKQBcXsiz4o)feh#vq{q1LO`6!rg)4gIG@#6a^-udSoJYYsGuqfh)(KyiGE5d`sIT5#LqrzysDc zNyW_!aQ}6qs9;!&+a$lmn{ASd-jt1^$pzSCaIwemakK%u(~pj|C7ZyoENG|osmLiO zKm;mI;9z1XKcgxkswc;*J^l=$oX6;w<3S_Iyh#BAgtaxWMeNHj{yYpX@$L&_E%aUV_B3AyNB(ykkyDc9jhp$J#w{r2lAL*4G zvXBs!(s$v>_yk8fjb%l7`?Ts?QGJJ(x|9Mst{=0|h;x!4yOK-N66_&9*U8F)%4W9^ z`){Yj?n7)MXSNXe?o%S42w7PVY9V&PDY4fPo2>h{5c#xIBEKM!8NXPOi5aFViD16g zp>JXNNLr|jNWqfxh4D+cKJi$lre8^qhGo>(bh3kE9qQ9IgFM0U4$gT@_pn`Y{uebO zWT$;356u&50i6oTKHeRLh@I@3W}k!Mr{^4zq}5`f8SO`$l57iCC3pg$kCiGYmE>f5 zf+cO7?sIB!_cvBx!J3)7{$keFo;<#w{yOZM_oY_(5l?R^zIs^&_MDY#iab&7=k& z%E*g7$3jQ#m(oa1UB(ZJ@JWxpC_0?%dBjRWJ3ME%}*i zy_{gf+%gAQ43jNJ6bv65=E;Wmb>o!ZGV$9NT7zHi-q`xEh4LT#x$+(H@?Cmm&D30X z?#HT%o+=LanajL0nq;kX?;BR0gOlsjQ}WDHX#CDXtw^EvfQ8x(_=PSOA7L^7vgD+X zaq)pw>j66Z*Hvp-B6#w4X_ag~INn#ptgn&77#}G&Ca;-EFd5%&i%2I};g0}>{y4Fm|6t)Mp;u4XUth}DIye2K-+=J~k-SV2U zM1(6V)+Eczw?t}gd0lULOF79=)c+JTv$3xwBX+`X2`BsRp?8aKY ztu5aw@#PeQ?R)Sgl|!}oqD``Wx8SSHp1pzgX-$}91=@HAS1aL%ahGUf-c73{L|9Q1 z1>H$}`3zZv`MQosu}|6oVs(-pnnnmrKF$hz#||@A(Q@gbTdlxCE3i%l(%R_=*2Aoz z-d50^LsenxLKos45#6a@`3PHd#mnv!7vmZJo)d)y@2U^Q_71aKZ-!p_hlt8Tp_9%J ztYB+fLP&r==ZOi&P$*|m5u-){20}UGh&@U6{n@B1-Y!1l^Hw+S zSP$LMtYd8vo1rh=d0Tx~V=|OuNrDfJZY~L)Y9n#Ukc1?dWLGc{Z@N0TTdt8TOi#d8dNCqP^JhtH&xgy#ZIUD7Zexsp8hQ8ysJjTlG zTicLEq}pSxog#URks%QkdO>SRK2>#Zwgco0i3{LJ*|OX%5OuV~%aSX+ljO_qL#Ka> zWO)2@kc!Kf@raiu2LJCvd%4fX5;2EG#*2O?IdIDMST4=w%kM+i67qBMwoX7)oiCH!(Q0 zoXI(-Wb!tds7CBX4$6$Ul5^n$$bnB)kJ5tYNnSEnw4C93Zlr0B)y=UCKfgML(ipAM z`LifJeo78qV>vt}Idq+&AMfGorXSDoasGmCxu2mPF3%7tjx#3Z&ogAlTDTd-2Aq=f z(yex7^T^o~z+#nzz1>Ew=VAyaKV#gvUvj)btGtsj7o$L7T13Hzc@vK841>*%mzK1i z_&&6}f%aDH)GKmPv-M3fzZ8IhiskFT)XW*^UiZ!q>mq2jScQAYv^jaruSFD@aZFZ3 zkQKaIPI>7mDVNzPMgG((Pb8J;VGQMeaT|Bs|m+>!n}nqq)Oue{}2<#v+S zHnj1UZf11I5h5*mn;+p6FFqdeLE})uB7)vMHfLPqiUfZ@Mo zjlE8f6cxysDHc^#BbjYH#_`%nYq$RW^dcwAa(k4p4myd707+s{Xdm1dIXij18q41b zzgv~yZnGVsm_oLXf>5rR(urh3<4e8zj{ZScl_&S85+#g^YB`&jIyNWAS!Zmm-J7m0 ztfQJaKUeNzzo%AJ(sajr!L zxQsGAUM~L7s%5SQk2nI|n^$lzEF1Pl6ZiQv55Al7!+i)=owF)m3H_0|+=?Ns#q}aN z<5bA1%j81v#?X3#B0ZJYYP?t>EQv){)rhn?wV9iB>zlx*d7p@UX>;jqS4s;Hm?2%& z>(+PmXLB?qUaw}koN-DnFOv(OZ7*F4SDq;urIJw|Ho#hCYmxUEb0p6U@^rPFXC1wz zIc8TS<+*HRB2SN2xtM7(mM5KISF4uuoP0{2O`E}UIZ8K7LuA=d=XEW(2$iF--iyu+|6q=T_ul=KT}EhSVhhxBuL@z zDOIjB<(0v{%EMtaxO^%f%39fcy~-lUH3^DVjc#{b+$fsGeL}e<>F9P%%5BAoiW|k3 z_?yZtaXPo-2HsX)z2@kQV^KPq|DRIz-t`p~<%h{+bJH!dr>Sm>&L|Cv(f`aAa;xY<5x0tWfvAvOy}z6wSh~S~1N*$uZr==5U1- zkdcRMXVfNg32plelIxvTXh%Ymg6bqloyZF27o3vtWeF8kH<*o5q031-nyHU38-!*_ zsGOrAbe782SQiT{5n6>P7+;!$bnaRi;4P6j0`JAH8F~fnna9OKi7m@T9!@)?K4OD@9N`HWgly=@h=tvPn}1S&QSKg;Mr>Rnc} zlPd8%(PEXj`Vv)%AYKu^$CCd|iz)6_8Qbj~OZpvA-=|g#Q=t(=u;tVeYgRY*jWE6| zGER6)C*_P{A9<5xyv5dk1m?^Yo>HfavF_1GEtm4-MaoF>{Rm@Ek@2JAjSnS%CCn?S zU1a#Z$naZF7T-Uh*CtuJ$HaGJ?PLM|J?}3G@c#ZS3h+L>spai|wgq^2VUnBSp0)6Y z!>qM1r^33sIi(E^-yJBi8JT4(^kUMeby_4%$O`sS=1yg)i9Tp z{t;d%Q!u8Ha4t%LC=Spt*?CKYl=8ha7<#- zFX_v*LJLRtb@4m4ZyLYj`?lhDQs376dipYbmi29;E%fzm%e${{JATXhW=N9ulDdOL z(#UKKONLRL9Y?+>%PEj%x6YTB$;ux+t*jeZgN#o)kO*0Xb`YsOz1`Rc|N3N<3uXL? zMJ}j&^<|lSPOJJdD$W+b)Fhg;Tz~ch*eWsB7RyGL*etUc{Bdu5F_=l*_8;$Lk$xcwo`Hn%W{cS~!mba`d9O+EO|E7iwwGVX$4QuRX z`^o9QuyW&reL?*)8+9(E64cefdZ}O%9YT*irN)4}RYo3Tm)rrqhPo_~UGx%6+qO1I z@285&C$x@NIlnH0FO?j!BGivsTF2I2v-0{v4Fl*AE64}?Sk{%Z329;d4ZpGD!qPpn zIM6yUY8+as&P9RYVma`G4B+yyg5Q!!QQ&s*J5!A(AQ?IjPxP?;{j!#|L)?qyb&33t zES(sUHX=(tzKW(2&2S?kE|PC?V0e0Q={7bJv*0<{x+Keq1GX;7O2IKn9H}@aio=Ct zyg1TujDvf}W(j|f&T3s`?7%TTi>tJc;wZ~%!|$Z5w&H9DuV)FDX9<^Q372Oz<8t`B z07f4qY~5d2zV`^DUf4Uk$XMf{AHeG<)#2}P!c9EK8+?W(&hc)@vfr)yl*{5!+XMfT1oAZ%|$_9t4w-=C+|D0+GH%Z2(X4dIHyvBd9^DKdd+p-4g0*D zX40c=?rXzV`#{hb$k)bKi5| zk!(@(W)zqHz@>j1Ly_6Us^fA}4A<{U54GhrAo)yI`EZN6=&UA^mAZehxO5X+%-L2K zgHs)$=SaY|wZ9#PN93FC?-RL1rbu=no*mV74{g ztv`Z(W&jUQiob~O&~44~mUe-FpQdvDbP6Baq{K~+QcupTw(0gOny60RS~jVjL@G5qo+z($&mh5jHKkFBtsRW zK*f;XQwy1*VvM6laQtnV3*ClHSA4~wzFgU*}A(b0fFKWIDZl4#Of{X`Dp=TJ9NTGEH|qy{hXdA$Q&;{~mS%zx=IbwJ56A z))!elU{~m0oCl)EH0-i^jLa9jsr9ql5a5Fb%4254p zC0zAitRKz1w+FbTa5qMsrptG@2zGk)1{!^{H*dZ6sEk9HAQT7hNh!(uqQuzb)kZ|U z<|ie6J}GFdPw}5Ubh)cty63SJurJnEI)_!cSbdl&_jL*1O^GE2A8q5~A~SF01$&9* zu8XPeWnTG0#R_LZ)sWQXo{LlPqSW9tE}{FxS>+nceRSMpwNy$hTO000(h){&vA*L# zaqvNy?x?pm#J7gVuz&h3Y-bAF)r_dzqE(8aPxzp!#>22(eQu4k;c(Qo@$qqT1}0gj zazdeMzCy10C`oCteG3)46=tg#!gMfGg53&7#n`Q|K*i|aVj+s%3SqYz*sUIRn*_Uo zxv!x32m|%xw7KZYll3X&^bbiX{1S#-84c19A&!rdN&3Q+LKk=4?XrX<3eG-Mw;=4JLiIKEK|T znQo>d;4O6xzBa4ufRT}d{id;EeJJBK=Io5}m9KI9N@h_Gf$?y;)ixmJ`iIbVW0(Gj zY=EbI&I?QSCGy}a&&=ihK!S;wVeSLjKv^`5AI-Dbx;9PrX&8G#+t9C=tNpu|h;GsP zv?{(U@LeK0K2FC4#&Nw;uU*AvP}=& z-rU0#x)zTTf{+^yoSflhgyG%1l%9B^m&)+u9=^CGEYb)+35!FhOO}XEB8Ez+L42Ck zbDj7^lH)8EAF&pSr+O{!6QklYr}#X2ijVIUpW9CH86`f=TH-h2(+tCY;v-ttI6l9^ zr?~dJbY(jeGnWyYnF9IgFF)BOsOB<7cX~G|9q(Pk&mysn;&dru9`*zho}X0oidx??Jm$Y%cSEE#BwGy>Gy~dAoSUr&+Bp5uax5k|RFN+ND$6C)O^G zQ+)PqilvIh`T7)}Rj2qYI>qM|d_?n^rDph_`0%gq|6%XlAv|-xYgKjk?k0NY9`F6*cRoM(bat&r)vl^twQAL>RaIwj zx}(rn9FOGM9p1dhX*N}#6JUL%K9|qwLQlPAB+D1?fPuVg`-y8=z-$kumP7xwO&yLo zbWvY<%I{%)JH5pc?1xhvF>qbe5*fHipzxH4WR7v*dUi4iz{q$TBcG}#Kqi2PZg zTMohsU;;rSG8^G$G!e$+xcs>ud2cFZE065{AK{ghUI8``eDO=_WEChgq;9l42Kno~ zX<+c7jVypehHj6RK@0n%KrwcL9l=b(7=-YS;N`$jHuKS;2FVV!BbW>m@frA*mM`WA6$u^y#t-hHj^yjA+;+6+!A2@mR`y72m;JXWQ^jgpE ziKcDIt=huEbEeg%vo%W z{t&8wD3=B<^6D<5+y1Dvk48n{)D5x*)1Z^VtS;n`8~}H&!zr_SZvmkwOC&MOr$*$=6S+I#wo%)0Swhm0i9xpHFdj7hm~(W z&PsE5`wpzXwSZgQBey~T{VH}0xs}HdkL|Hc8YKETP!8x!J?R?_LW1VtVR$P-zAIZJ z!vx899wtci8;6N}Hz|y^Ytu=#BNZzW89+xD`bxs*IQP5R?`c<*A$~* z!7wP@ltV9q5^YcQx6AU}j`G|UTb|pwJm>GHXsu z{6*I}AAx6jPu*M8K;s#t{D1~j#wA=CWZ^g(oJ{qDyE?bTl-E5Uy-pZYAq$bWHWa7-lPg-A|B{2is)4{7a1TEPvu3Ajsu z-u)5r`qWLSD$Wc9f`EV#sAd3NrW29hq<8qTnqiP#OsY$8*hG%*jl>9Eh6EuFM~BD< zD{ee=cx+8SNAnbWU+DBddE0$3_&n0_+CBr-n-##{;BsK#;*&NAuhbJkd!1=MY<~>S zA(}o4i=nm>#!e*cD*}tb?CqhigdGO6>r%g# zvr_K?&TE-7o#NjLPQh~4)0hxtF*D1B#BzCr<+P_UDax{UD3#{01uSR&8cyYer_n4~ zu(=D`5W0rt!I0@4Y)<9YZjiV6$Vw#=3C=@wN4;8sF#Q`{D;iO~`nJT>t1}~^S0bUQ zk?YwGBh&T@=rRTLtT_E?mipyM1%K>Vsee#!@_7 zM9psZCph)>tvF7ExxHB8<$poE{n4nN~!IUqVFjf&$N|#Ipk_lD~VnXBUBBesf z1PMk=y}D#_OQzm}2^Ud!ky3?Z>MNL1yJV`AO#KAYMO`vgNha)DqC8#PC6iw=T_Tt+ z?UJcUG7S(+X3dP3RP>%BT&6WJkvZ`;YI+|3x#A}Du0IY!|2CI3zVHZK zhrZd4eb5H^=e{o3Mv{h#g+f4MunH#MLapKuI5;aP(Ye(nx^ScC3I2lsc? z!5K;RGwjSNu8Nnhc>m79)Vr}<`J#fd0I>u|oq83$F1DNF-~|^dN_6wLdWdemj=Jmw zuPqN{aQR+|?dC_&&5OXu-F&2sEBg6Lx^D^ZGhuYN8!RA3JNim===HLruW!9X(qvCx zFMB%9%|7Dry-Zb0tujD=u)CLg`b7`N^z@gxx_$FvdOGnMd-}@?_w;!&Jw3{VoT6%8 zR=B6nqZ9EXeId$}A(^8N0}-l6ZiCaim|6hnJOg{_w;#+v8P9wsw5Nl^m#Eo zJ<8;lOx)AwDaM{2WonX4+|%bN#-1K!YLQIb(*xn29%(WEo1V_SpL+UY>gf*Lz#8Ab zdAM=vNuqx@M*4RR`geSPquTJN54sgMc~7m?>8U$YynvPouFo^AbK*c*S7OS_)k#=gsc{Wn zZ38l})YWPU(NaMvCV+{zieF3;!a%p1JUf#W}m zvT5``vHe!xTNf!LLr-jhuzB)<-bQH})<(tphM=9ZqJGD1W3jznMIP3?ZTs@GDqVktp>C)H3mS=XD zR=Rv?o-w^qotqrKzlFaSH$a?HK;LVg_+Ebtf3H>ay*APJa?B)kB&nAE-dk&NlmzIj z@l7oFXjOUGeo*!@EX$#L@cMBTsL@^nrM6ZjL|V$ho{;CsQ0R)U@!HkYz`qoT~|Oc{YSuVg^iFodj5Qv#SZzzh>~_}*4(C_Hvx zo5S~-f`c2$rrY5H&vL9>fv1J^RO*wyne;VWzA7q#%U4a+*slKZ3hcjdX}Rn0+lJrK zJS`W8tGuSHKy+UvjT^x3q8HT>W)6)Nz_hx2VNS7@d*ny2!2s}Tqr9EIpU>8(uJX%W|#h??e^6^u+%Aw$nPkly&Y0)t4 zSrNukceDCegk72w?%YoeZ1D~F4*e5Z$@=~`)P3xV?;{2F%50onqTSYt`|3(o`-$NZ zY!Q28IcMZjo{6Hwj=60|Nz+!N3p! zj9{Rr0PFzJZX}d1puU1uARxS|WM!cUC-w7{_^Id4L@w)mB>_XY#t^PGgqIt_D-7W} zL%7}$ZZL!!4dIoB@G3+2D?@m-A-pCME(xrqFg(?f>FiE_NiDTDR6Ukyi_wD}KJ~H7 zl9f92ZhU#AI2DLIv=f?ndHl%^eKOS&1K! z>Zo_fIjD=@ItG91Sp{{m71yqvgJkk9*(BA)!;Zm+J*z=F>(J*iGBO`Dn8dK8k%P&f zZ5-a-uD)r4UZ<7K6*+qQaw&2g$z`4B<_#`iiPD0?;;|D~d$OQ_M5Cz~XlZ}BS14#+ zS>rpG?riQ~(p9;_b z>rrs4BT?BjuqZqlvuS{sSXJ~|Boj{<7R5{$qD)rF#2sW&%!DDzlp&dT!muc2!VqP$ zOD3K$EQ*;hM49p>6Hgcx#Y`BYOa+pOCk%^XCJa%gLdnDvhD9+GhA5L;GVz3AQOtxP z%2Xklc*3wKX2K9y$pVwg?mtv=HibwCK&7sv3c8cDWmE~2O)x@T zcA23r*OR*3;MAvu)nznKjw~WgV|^K)kYi0Fg&9$_(whKNcC6&T+Nd|Ala1EKhT4nC zPq1SeL3+LEN#>d;%|O6Z(qNcfNwOEZD(<;L4NN0xe7;3?O_+&$%WD?N#9}vM zk&R$BQA{)n4A(>(=vT;n6k}1|A8^=^7nPM%naZG;66l;-1lrWVP> zVmD%ujWiX}3fjQrtXA+3W3;rxvPJd_!danVFS8;L_P=q!MJRAC4c6CRIxzc2kaSW? zLr?mp%T(jSnV9HBG~RpaVXwgra`qxMSX@r3h`Oe?)U@x1l*(>QRw}%ibaRK$uVIh9 zNZ;i2-qa5LdWU214%V+vJM{tW`g+Ktuznr0-V&={%SB?_NjxM2Az95N5Y*$xlSoS!wO>N|QLerc zH`n22F!gOt{N-dIF$cjyaBdTs-6L}ra)%&n06`9r zf{?mN5O#yGiv-5Ia|9uMwIH;DAV!{QK^VGR5RQQ$2S`E4`a%#+gCGY;L9l(wgytQT z{+mG{QG^bDL`FvJcPQLOBO_a5!Xx7(E^ge8(M)dZrls(N-o(&AFO1hP<=~#@#lfBNr$X| zEc5qLj^N7y*9KfU3dFdh0v80XB8CeG+{`fUdx6^wTqSTW-`rlxad?sFAJHdp z`QGcL;MCwe{oN`C=l4=h5cnB=2bXVpFQtRPSN#kkFDD7~Gyrr^Qm5eZsDIQ1Fb5Wx zW|wbjF9n_+P)as4%aUFS90#5H7cC4TdD@|*e@5Sj%Yk__vew2R-Ub^OsTBZS*o51W zr+-0O4ef14>E9$(hQcWIn-wyQ(!M!UhEd8lD-ovB@#EbpetbrskV?T14}C+*HACLb zc+h4YoG|xA3sXJ|^25`{52@tvS4L;{Sg7ZWU>j*0iJlf3PV1ExbRF*5@Vuy?kBWZR zBs$YtDYB?DvC)uMG^qu7gkh;f%vWL;IC!p2OkN9HpGt%^Fm{0>%4C&HT$8a298snW z$;1O^>;gxW$u60?Sm1~<WdfEyjAH4f8i(p`D{r1eaL z!HDfeXz_n)$C)AIPf)Ce(n?IY;uW|QtQUH*SA<)ozRI)P?!+`5dMaF#u$-^&2pm>j zzSO*1X^8tZYtJ>1zI3hf_>{+1$?6(fWSau=plf~f0%J9=rp^I)vz&atR&_|v6 zr(qSkPNo2hGy26Op+eV*Sf8>Ay#gxqNJ<5nvBJe+Cuz9Ef>57MO69{SouI1h>7Q{#Kbev7cGcOOsqmL4qGnb zn2;-GVo9)AL9^*1r3}f$l3;PzauJu3T{5vGSRA%o#4+VdCYA(?!tl3+1w z6X%z%P%^P3SRA%o#HHkxOe_f&hb@c zSGB^isBAXUcX`og+|(AmsVQbmx8Z+|d(W`k0x5viyps?F4S_?6?KQM2)q(i8+)N8k z*pbKIJ}eE!;QT$PPqgr4ALLC*1NR*W#Kuo~%X#=L*J6dmYO7AE2MzA@3RU{+kK(8nA_BrI@ zv>o!nR}uD>0D|NU5w_AwUe~@)DXL8v+)mD8yodaU>?bv;q~cFElv<9q@k|fD`(#kFo>)PhN#m(tDa*rmtP5^-e5& zvA$3Td4c`eNi=qrlgbOz6S_S0ZnCC|vHsd8xpz09``d3oBi1H5ETjWmCGmu?6XHq( zBA*af7!U=7uo@7Bgt$D4D0fp)fVPRzo@qBjBDMiIhvzBO z(R?#?R0NioEeJ>o&4RyYq*YMon=_c&jN@b>+UC`gvNrc16uAEFwUFEYK+a$a`Bx&T zZzlR|EWYndIA45Yr6ng25#LxTPjQbR@%>z!_ z*QNL_i4ouPSbXC|9M#OZB)e$w;}E5a70Z{K4F*wbd#%0r0oYmAVk0VKDhXpqbh3+X z3VBdcZ%VO=8fOIw@%8}pIx+#*A;v7kz#@I|ZK#4sH2r9+6SNZ0Lf@l>^E*u#`%?bQ zFK`Qm4{kGXQe~gj0NG5NNT8QTXj;xXWP%9m95`wUUIXYo)F&c+7`C6(VZ(($mwMl1 zq4!M->wS@FqEYXgECl+ru-+HPgfimWP8I@vT3GLkW6F?BEYPQg^}aYJyJTX4J}s>G z#WCeeCKl+^!g^mEQ-Ne+fj%v)_r)<4N+t{Ce_B}Yi(_(2CKl+^!g^mEQ-x$=fj%v) z_r)<)N+uTQ)53aR98;BKVu3y_toOw+`6Uwz^l4$eFOI26GO<9P7S{XXm|7$g3-r41 zidCe=81z0ild?ePxnLKjQxfP={S9gh330tI_W3nXP)8ke z)^ldXvkQt`6^Zn+^$_W8qWR{8W%~VpK$p*k^$$Yf$zd$ibqka(w0mpu6?#)3nCS5* zz|-hoIElb>OTt7t-|DqxkV3cMro{wo=a}j6E$OCEBh){)BPN6JtOn=^gVg%;&+{29 z?MAK8p_hyX2;rBK6wU&qpI#u5osY_V5wcJsPZ^PJi9BvZR!C%<5m_mbtwv;(MD8;p z{Svv;h-{L`Z;Z$miTv7#Yy+}veNkFwJF3rY*QVFep|1${t%htSyKY@;cj&F_f+ui^ zLjrvYjPbOTL|*`Pks74r$mFU`d|A1b>nC-O0cVl876Z;IahyLHH$&n!8~E%J*KEM$ zOI(uyS0Hg;8E}OX*I>Z8C2qL^S0QnJ1FllymKbnV5?5`&`6X_?0oNpPRR&xOSW@idIz_$JRBG0U%m)jn+^jH0>xSx(|Jod#k_FH010h7ndqG_Pj%3<2Q0 zpBj7dT*_2mDhociAM_HLnyML*GDWq!5h+p~uc}6*NPWDj7?F07A@wvBD*U2+iEK9_ z3ncQ05m_ja2aQO#MD8~tD%*BFs4gv@~pT?4Sk za!_w=z=#QML_Qk!kNecuPmv@_sl+22(iM((iOJrS%#&t?_E*tiQ{Us@;cU-dGq#(y ztM`9{nINW_Jne=vVjJd%u)iO~8P$lw*LDC5LM2AbJy2+VK?yHGr&e;coV|RAHB9|j zGr#&5aH7q@XC6ugKp$E?(oeYA&t{*dF<-dhHaz=y~rOf;Ay?2B1b=0vX40u;l~JC8)(5C z9TzoyNsAL@eh8#{d9(9=+4o_c&FH3ksU2f#wHHC6ho>fjeb1ZTTBa>s1 zTN&9s7P*a)Jz|mHFtTSX@>@ox#3Hvd@fM&ux{Iw4WO&)Ck=fl9E2qK%u7SwoA&;OAHihknVg*$+8$I)GXZv zl49#-pwttkP*T)0zm4Xa#s;^WD9H4&FhO(~cZI;GwMOxr<4S=~-yOwseyapNYg-i0 zdGZUqZ9^2#IcgGkb(O$}(3^tD&zu&cDB54gMyFg^@>1&~Wjh*ty_JWR#l(XX6m z36R^XNoJQ@XagLejRaL#CG;&pGczQ#m!L|!guWwaPQHYW6I4|op|b>47fNUaL2fre z^a7+`A;RAxJhM`S_aaP*|Ndtpz+dDgP)L_y;E>h`G+G*iaFT<$mHG6h0 z^X#@KuhRPm|Aq@(ApJ%5%N(Y9WAiwsi#p^JEZ^2nGS)PHtG5;2RkkOUgS@-gnq4Dyzs2e2sVEA)s z39K!ybwr&Y!**dFVJ8c_ANxRphwOfVmINHB3N>l2`L;{nG*Y?*0rmZO-YKi_z9RcQM<|~ zWUdU*J3Y66+je>*Ekzey$5uoPQ~}s8a0crp(p{tF{(~qt3?QjbT*ac|MLSRKo7D$E zLarv|14hI^YgTO3pGBgk{6a+4!%;66QA;RlSXUOsKYouWK8knhN`7CtUDm<@knlct zKGg#4A6tiF^Vi9XtZKKt3dXlkJ zkI=N7Ba(o{y?Pj{r{F_y*?D0UQ)${=m)ecWOiTVmB_>*bfSW&tJgTQSW12-W!F)nY za_fH_6Y|O_!CX#Eq@|pnQifz=Yw1frYAv0ju(kB1AGMZFQP^7g(vMn8rzmVKeMupG z;`}@n$~;*_#^u)kxYD^L6I)AP`cZ4?6osv&Fa4;sbc({((wBbJS~^8xYw1frYAv0j zu(kB1AGMZFQP^7g(vMn8rzmVKjrH%R7SpA*lo!3&TFMJywEXosx`$Z)it0n*MK4%K zX|;gurEgQKgTD;yrCV|JEgYn|{doegmuC9We$Co+dSKp|R7TR~a}p=$Nexa@V|Z_Y z=*Qp5&QFc`Ma4;SYP42j%gMA{{?*@(=S$hAgffkdt}A`2yQ zg%RnNNWT$TA(3Agk(Cm;(1@&($azMjUn1ukkxdf$ff3ol$Y%8&AXx^q0r6m1-nXkS z?>8&(@>jP8h1gFGtV~jhQyji*tUHl+YoPU#_L{y$YI}{j7`sbL=;P283?=lb!eX|A zrXkpT-JJ5qU917VnkK}oLWV=k0&TAV&penPu7$uYw@6BAxq(9FzH+Oiq`hFEtRhN= zq@))aC|?o9E-6EwFi^-ESe`E_Sp^2l8ln_PO3H5xlt!WyN{Z?-P-yThcM}DTZj>Nk zPdOWoD=Gv&^+ti;0sL0*&#V;qwCe?aKk&POudEXI^lJtFFz^R~pW_$!p;rm~3E+9w z)Fkj(mkNA6@T@VmFuvK=2YAGBU3b*}npE~L=9T8Gdss^@D z9*>PU)qG;L@+ewRb#?c)7;++Ypwk0Rvz84-TJ z0Ob2?4fb8n!O`vNyLFiTX=MkYKm-c{P`poLx{1np3w6sA%2B%!@TC&`Z%!!hrX<_z z?GQCxn47jyNquV0#Vk&u=B5qYYNK|}sJW@pK#84DE;CSKCzJ~el-LR7M+Qplg!1nO zO6-L4bps`KLg_P5{P^Axb5m)U5I3QGK8lZ-P!>h;F%!zCqWG8z<)cx2%!G2Rz@Imv zycc-n?*}H7w{esIpJ8r#0%bu-+1%u{mA9bzdX|rl8dXEdHQd7C3P&xRb_h6LRL6p^ zJZGTxg@yJ?CZ@fm<;JWk2m9eU|-Gb`3W!aPn$9H&$|oLpDn_TNW=d5e%4gzO(i!aPpML4+iK z7UqO`oRC&R4hkb-9w%gfLXyJ^bHY4MNMy5g_y{0f^dgwYU4ZQjPwk_?GVao+4tFp- zy^jK;xJ#ctJU^TW?BNuDG}GVeqrepI(%%|h!0`M&3asEReg5#r8D7$d4qtHTONJLR z{9YfjeY^DchEE`vss>vK99~>bikB3a9ActkFpTW;6WQh`vdd3o6HlxQX{bQd1;n#c zb8e*bHtaaz7wbD4$wAOB>XkpB8|5NgK;ZcMl}lWW!13p+khofbLorH+&y+YAIU^sh zQsPz!9Dlnxz`16K6YejaD=(1Wq5` z1d#mQS5fkB4d2Yv7nQGwI(2vpgOe1TkwKLhWabx@HN-r1cpHP0l(htw4(}jl93(n| zKEE6FM&F7*UbzJL!&OMYN}p$@1o*>MN`ODy8~|K6e$E|U%}*4EpC|`EQ2;zS=L{pu z{6t;}kA9fXIb|kfk)HTCJH@=wPvI637SkfEL=UH#E)jMcn0Cc8StQe51Jj;(CaYxH zZ(!ON&y*pVLI$Q_Jd<5A!PL$AIOXp^JX5}8!U-r5ri1ZJ1(NBof$2~@Q=w!!Vqk)8 zol=d~lUp(!GcX;EXR44)u*XO8^nE;2rDQr`U}}$Ns*+464NM*JOn%99+Q4)wo~cPP zoi#9>iDzn&Ojw4CWc*w_QyVeq+vy6z$a*;>ZFdEY3cJ6$ha1`oW6j;!#w=)3%p#jv z49kV&aZbh=56q7xCl#xr6n{WR2HWY#U@R1pxy5r5YZ@LJ3GD zxBy4uLTj76mAV-jwT5iLT1v_|B#eo^g{GJJ31agk-2dRKgXv{}r19QDdP!D8 zx#A6@<&D{-52g;&SRb6E(Da9vAFl@<%5P-ddy+*`QU@C-qz_KAN=n-01`26clQJYF zJ=H)V{c4h3Qik?0P)Hw~lrJe+CIf|ZuSo@xVmo1v=8d$kNrjT4erKSNJ~+uu6f8gP z2@`}qIH^M5)4z%0IbW3mKeRcD=Ui0@eAZV{Jm<+T@V4bqJm;uM;MFApzXh`untZ*{ z!uaNt`M?8yu??^TdlYCY;+sj|3X@HEbZR-LdBPdMgmV~AIKL2cs@&}kQ!O=cY{iwh-GOVA`YL0a<$y!(|35vJ+*JC!2bitsa67KEuK zBdxTVC=cjwv;l{T=%5MObl@EIb?gL%Ib-h4V$PT+o~ieVXWB#bG_EHiE>636=D3-v z43q!Dc2pT#0OnsOXOf42pb7BY>*P$55FthwXOh=NXOeaH;t$q^;G}2m2B$x6BH>{6rsl&@?Ei3Uon!Rh2p(f7m}oDLf(u?DBT21=~KX`6u(V{lq82QL=O^ z7TJTJie-5$P;La+t`1%=n*GxoWV0W$;3qZv>u%s?f2}#L+5ZgquA9BpK#6Vk{S1`Y zX5Z65iEZ`?21;zR@4ybya1LUd{UHM-w%PA7P-2?>HbFSA*>4c|^P2rCfj_U=*9!c3 z&Hf94Kd;$;Ch+Gq`;UPC?=}095&v_V{rf0OxY?u4W7qI0EWktKo8CmN8@fUG@Xhg9 z%n2X9nRfMBET)T7g<=-d&xuooFnDg_wRCb&6Km~!GAB;o{Mwr~_*1N<<2DCh)^N2q z6zll4^t-dTet&Q+9UH52|Bu$vcPEq_6XWG(8X)}`AjK-w?cDU)Y8_cj9|at0gcs9U z8!p9E1ofaEScq(oNSKJL2G#X1(MoceUn_-OgouAYg^<}awdWcHeC4E9Ve^1=$7@%I z&7-w;oUe+tc2_@kUJttfU_X~AFzq5pPhu$$SqV=C3Ay2wa2ym*+L|s`(!-m;$EUOm z;|fE3b#J1OBH@+vjUdtY4X>m}U;0rrQdKyTTuHACM*@s0pmSuF!a9umo+scHlfIJP zR8Jzm$0xBj)t`|9JKRR*NB?j9siO0*c6IM3Ns6U72^aCCc-4&n#KwRma*o%O zU4oe-yelXD3m*vwtYUR6WyxxMpF~sk=aw+Wxcw4t z)NokC0RxV}PP1b$PLAL1@D07mgszYKesPnxOW#80{g$9{bG1g6@ZnW0PXu{c!55+` zHyom*P0XcAy^q{h#4LJ+)#0fDM2^U>Q-qM4yadUs7Bhgm(Oj6wUb?C!s{Ti>t zc}Y0`xuN(waXvnII_L1UcsQ@dRGggI?!aE1(XCH82cHs0Opx0%u)eej3LS;qAkK%t z?Jj|nX)b+04~HJ2pwss%C$IPI5#1?@rSr2cQ-^cp(c;xe7nl14_E~Y9zBtfHy_!=T zkOAj-m@0AyFW06$im!l5?}^rc<5u9J0aFDkctx(h8`o&_dE4-0Y6y85y%mQd;ne0W zII0>sa|Bv&YBO5rC!MH22;92PUO0BU=n(F@T@~A39ljZKB#q0rAiUp$TQ?tGN;G^z zs(-d$;8sg+)OS+-_j8o25Y-PO230@K-(FvI-5tJRgHbkAewOoTI)M9I*WlI0{-k%q zDal;@@LKL%U3`d3b3x{Jp?{(zPTw<~+1ON%s?PRJ&!A`KcOz@GsXh=LfkQA-c(}k@ zL_?$09r^)rO!YeSF)A<|W;UMd1&Mix+Slt;K8J61c%Hhn>DrosPjlhi89cQI11zb)49i?VCS{vh6sr1I;}T z`G}bx(!t)k>o_-Fs)f!~xYfF|zIZ>PI`nUG-D2X?xHMkvi-@!yh*}uR$vuKI$$K^t zDBSPY)4@xWf61|HRLjVbDH7{uoi3%!aOLiD@_NJI<77WhF$;t?tx`%SXXNzJ4e?XH8EfQKwZ zAdGd;nLpy=fU&xW(K0DPo`I$y#Ag_~d_ylfONDn6gS?Nzspr@b=CkWzx1iiO^|3a^ zWjg6HokEMEjCimi8)prv4fULTr(UKgC>BO#X7`yHsvuscKEuKgpONj<7xV{25$qZs zJ}ka73qKb0$Ad~2RUo=uCq`asBt9#mLS0TV8Ic(hdDBn>r(Gh48sleK{Lz@RVfJsEwC_Dtt1k(v_Bw<;9xNX>nyYI zV`+apNHpyFxk0j65rL538j%?ix!H)cOXLP4GG8Ls7?D=_qDCV!Ln4LXAre zeuf}_2%6Er5abU*z9xnse+Vku42b0qf7up>Ab6r>mOnDg@<)bIK_9zinB|WQv;2`^mOmU8@&`dGJwFyy;X&nPXqKNJGaC5eYvM;4 zjsgP9(iVO!2=Ze_8$WzFH-qI*vO)f!x>^1h4o2rgy@cqI)T<2CAJrk;QvQ$^wUj?0 zgt*&U5n2WYeAM)YWzYluTm7{Xx8+z;Q2&Xkp2yCYKOnRG`Mbz5E64DigySvE_*e+x zavWxPw+oi;aq_2t%Y!u;MR|t`!jkCkks?(hB#ygE1jiTPHk>crW%)jbyutT*o*O(79FMJ6#Xr}4Eyu##dl$0@SaLi8LJY&j`bAbKmS*6+LT zU>^wf_F4#+XX#q07V6KQi`f(F+GQ-Ne6We!ZzcRsFkg_4PMIWS4z z`8X!GWMbd>*AY*!dhLeSyOZ1@}tk$NMhv+_oxT-u>jN6kE&tf~Pk zf;FxE!65H6A_ky9gGK{!QSTuTH-m=SU=3?D3sm}SG>5tsY}fA&`4Pvt`V`C=K4yT!%E-qd8UzCZ#@^D9ku4~r5+ zwyOkT=(SOT$h2P&Y*$7JB415{pk6EpICiVKjb6T>g$d0m77z&GYXbt_a3`sqVVo;G z!fpU27(Nka4YRPofgiw{W4VZ6A@Kuf6G1bq653ACtPBb5Bj|lhR+#e;K_BN!sGXn% z1rj<((9%K))e%(YCWu~u{LQEkz;*&=RSIAq0q<7{;1B^H`vt(qW-o0LfcSbX0?4`y zMIzP(Z9q8Tg+(3Jdo#S7lZw;zjh?;OMTpZ!v5OD~KpaCa+)P)v%M%{k^aHIId-mJI zEVxK0rwzxz@_N9r9Nq6}!Nuss+*_kY{09dZd#m0_vI0XB7|~mcZWLPxaY6Tja9<5a zHTKnToCU@`gf3H4tYF9|`!zZ1qlCWjCc-;_Bt#kQA}m8kZ9t!_L7%i1KgP=zS)o~2 z0J%9qn_UY_V$)v;P_!8VGj6}T*8&@M4J}X5(a$;jzUU@FyC|A?UwCEWMj-ipv^0^2 zjqt4*vAOKtRV>vQD|SoK)=Leg3U3PB2&8xmN)_B+FVq@u>K|~9oHu3m>rg^!*o&!9 zdNE;Np3#e`ipoTrWU5GhQ3k2nqh3tK;ruA%Uqh1V8P0ate~Bv8B1x%_8%RZWD*4RupsP2QZ1CL_gk3I zoU%`TUSAs!@*|N-h;Nnoop5J50e7Yq_@oZsO&`-YTuMX?Glv}}*4J0#d+ua8_TeSm zfcSzKpF%!DkX&Dpl<`?4)J)I}tAxHGXjX=V_7L>GT|x&5`Z!-g-xIW;Ktg8-T3RTf zpG+uLbzHN&tKz%>usw&QO&sZ4!WJAuRyVu#sSTElS08 z)&?9&B7DvCFM$kije%Fw_=~CJ<5Qj$&(w+HnKlJaX@3Pd>dyo-OxT|Zub!V8VwX{OH`) zi1BgyIJo&MUi$v~CvxF!EEeASj!S0yd)$2)7t?(i&mUJ}PJwXhPaRkI#*B>$gc@iu zH)b$0d_u%0P>%Y~fa0TRklh^P{Tn!E1Mga11wL;ELNy$+AT)lo6v2k!AhHD@y!iTk)80AgOiNQ$GlLGBkRF; zdf&@Z8cuZH>7ARUU@C;O?|im*kRXyvKyog9KbJSt@6tPiZRZGcICwRc7IPvcxCfZd zT3qmIE}oCdG8-yOuD{`APIWug2D}zVHavS7oJ;E=-@UyZrW(h{m48XmR}RLx!ZsUT z+WHqT2cpaulQ|B9ypiu};=2=kCGmWyBtv?=iSKIg{V~dS1)KLUcK~0ie6IpNlv-aC z>W#7>Bi$kh6A)}(jMi7+Fz#llNA>pEgX;Ar1>(-5M&qhyp0z0F;oZd3bEUR02|k)! zA2IZ`l5Q^_7N*~KkHd4YzkWK?U+OP@04r42{>!W!)hv1Rr`u6&bU@#XgT`VP;2(~Y)DB#2X1at4}_=OdnYtf>xR;P}q?2o`=dlOhZyET1BaQYR9vaqT3 zGl1Yo-+MhJo!I)Wtn-|QPj~7&B=GeuI2>akb<&MU$>B{-ky$Z?3Q_I|p9YJ9H}!7h zKQtV+3~%af2nKc~omgM8%Z-wTZUwhDHG>#-1NNq-Q}8wDr;CYxRcb211DNZ;KM|Y& zg&Enq0TRw@3GE{Di8iR|s5W*TzE4Vh|3rMWF)NR1L$+x5Hy(9pKU)PjWf9{?6Fz`1 z4-u1GTXNdn&7?e?i{?`BfoLw`d*koD11&+%ZFWsy*9D;`Ma@s2&bh2-gOECzAt>vCU5O#5;CNc%?56dh zUkcQ385KCtLsrq{0__lK?U3asNC^bHshv}C^6naD@1S5U2VbU`)d-662M2fJ%VaU>KZ!JpgU?d%6%P6-?i3DwPQm99 z%wu%MXXm+)6RCib5uucACrYC!^b0}hCn?yUu$(ED zP%6FI7Qh=kYwe=6q1$oL3(^U`LT?b~+0OubNh8!bydN<)1BM};fq%G7V5*B`Y?!| zT_$SZULeG`{1ZOaGWuMhM<|4ZmCzW3yr~aTTE7P)Dt8AqZJ;8kZ>oLp5zr6))N)4& zvfn`dzHgY^92zLdf0ty`k(z!%qEg&V^Cp8t@KUfZruTcc;!J520(J1Gcck=BIFX=) zz7tzqXxwPI9(2(=jz4f3MOyR^Dv~v@D^9J&l? zKxw-kQME-)Aq}86_4xa6lx#|;K|^0hYOXywpr`BrHgpIDUPdePLF-2>nbMa7y`R3! z2C566dWO6V(VK7t*gv6Fd3GMw&9d*$!U|JpB-p&RHxSFSf0^tiRuMHIqLM@BctkDP z*$MF!iM?Y&c>D|AO9{16>bB8HC{cUqH%P&qehYwep8b*W|krddahWY`K8Lsa8prr=eVD}BB;T`UjAoxt7V-!yR2H~@z{fuuyI3cu+ z@yiiD9a_uyYJ`(QwFsj=4o>6xpu?f&0fRz8>a;?4Q`a*EQXyHJ^cs;GNjB-`U@_L^ zLhs-zuX^=nBt`$gz80cQTWHo6<|jbC3G7Vr?9!4~hQ=ahz1mOmh4KJa{0HLp{ej;e z;O#&1vm$|CgZ@)~Hz19l^6QECKjqgSRs2(aKjq#3H{uqd{QoDvp(wABe+=UPl;0l_ z|EK&$AU_`>jrsVELU<*fv=5;LKkBxp@k>UJ`#XN0;8%;^z2Mt~CyCVKxYh0nz^4%= zk@Nz>I)2mfy9DqhXrJkLQeEFHpH4jA0!+Vq5q?zSXCuydg#Q!2GKu>qa1{tI#`ASN zSK_%5zqb)?!IRP@&$95hJOtbVz@!Xa2AM?f|DoS9@U`NnVh|Y#-plbUz;h&?MR?}n z`5~T9;_1QfP5chycL4@mIv4JG{O-Z;Vf<>qw->*5{7L|O@tc9)Z2UNncsAk}#Lt)? z2>#9zl;OYo3!jIL`+8}@g_YErO0x7o8P3+m_QPnK@_9r|3Pi|*KZlLVW_*% zh9U3zLL1K3Ed4OPI>8{dVGJA4hAqLFhoKDz-h)h@iUpZWe^?v#^N5!HaNPZ!GRrm% zSr+39t4GMVh6GhbWIO;hVY7C>pVWAqcsWLG>zRn9taCJp6dFW~CVvaE_S&0~yi>N8 z^%1$g2&7j*iqqkD9YU^qP_8%Wu)}-yX~;K}-)g#c5o>ZLMY}6#`nCj9&jjW9OR4;r z8`+8}r3C#DvWgjD@BzFe+jH*1;^e@0$#!kwiq-*oXkDmeryGNUe!x?63)HwwKb=3C zTa(-%Yb5)(5Apdk>>rIYOONZPbF_uWd2&2Z(*y26hx_COPxrh@(@Nh#LZ$v9tg_p> zzaa{kgBvo~TJbOv3Vq!h(_BorwXzR*p;uk_Hcz@yxuX-J)7|%o_=sV;dt#%U?S4AT ztQ4W{=~U4hCh{PjG!TJmtW6Z4(g7v;SD~;Sj;Glh1s# z?`RG&Ra8$AH%&UTKtgh;s^dIUgw2IZaRoW@MGN(7C|CN99Gr|A#jP2}QIT5drt1}Z z`H;lcH@s@wTS%E_<1`C5upj;q9Wrex$eFD<`Uz3K1JKm)>5>Mv*P?DmQ)c#RG12B+ zV^Z{>r{!{8)e#q474{WjcZRKLCRILi6dc!!4~sMxcV9+Er{KcBE5wGWh8gKCqh%dK zHfDl~ESF6dY6f(tT_i17cM5$Eo!Mg>hWB8GaRv)vIeON$fI?q_$7}10plAQN(A7xS zYwJePT2rV$Lmh9Lm6H7v5e{9zi2a0E>&C|jkvzgXd+|G=!1UH8{fS=MNam=}=lmWV zB2ES`uKa*LJ}3mRD3DQeB0}?%%bxCWZ_wH(!i3vm3R%_@JSh!irhB{ zF><3;s&e6eiyS3~LU-X!hS#ia;{sldjE262sK!?@P+!71rae zehOBPO+yfsv>T=bVLgq#yWT5Cv^2GAVMXW8hO><30hei(HhLUnoqPp zfQA$+Wr}$7S%`ek&a)vG=U1H^p_J_=N@GIkI#2?8Q%lH(MTXNyn1#;5H;+7^l`a8W zW+>DXT=*Ura~qtENvLRpyDmJ_=~bKlMs2@PZ$*zvh5^Xaa;2x^N@|zLPw?E^95o>f zUpSlksi!5!(~(0sD6_$>f+r~q9{}uCi;%9qrKHh~thFys)N)qoDUSjdx(1nw{c0nx zISowKKc2_t7`+WO;^{!mbwZTlEA>WxLuX;9K?#z%1pOl=u%ZMxH)i!hvWVXu53RI; zqp4$1rR{c80>>~#Vq}D1;fyxg&cC2js2gXZe+TE-i@GnfAh*FkUUjCkWUn7Vedy<) zg^G}-n66?Xj#n9*+(9%*Fx)|jN54O|~iB++#TUg_DtBlHkByfzy_YptQX z82Sa%4u`TCx`Jtz(Di_j`kkCQZgV~WYuEbhk(;#AccFBmfQcA*1N*vXC$GuTGeXFw z;!X3vM(!>&%JwEpeIzb2LulzamlFVazFntGN=;{Q(rQ4p9P4{2cGo2Wg!Yz3=K+oQSqQRcC z_TrvM_)Cap+AG-KoqjVS&PLi9NLvVmb=@g4CiSIwt5^NU471{MnDmrc2$cCLzU}9) z;)9;u8`FupH`2U1cAWjq@pGcbv_6fuel;=N=*tEpX|l0R5Yp~bNx@4sqU<~zdKeV1 z?IFAq#)A+U3B0zu2wH0o{SFY)d!A#R2=FGl(oN9R@i8GULRTVgd{!=n-6OWko;*kf zM)kmSd}%c2?BqH~k8c2lyhzGp3nGYNVjt?)lYS{I#z~>4nXpz6w$KOL+kwAc_3X2# z(3T65gSvVY!H|;~{~;KcFv~9B=U9p?Lb&vVS=g(t;b@0-bp=JDdA!H=A0pDL9O*;g zb28gJ9hT?&w5x9evOvDFcv^WG>5FSLWZFZqH(@4)0)}#siaY&sq;fh`0~{*q9(-;# zO2Yi`2~c74gQ0UBgx8omJ@hJBRi=W)o$@WhrjVP%>kv)|6>)e4!bzdW5w2Hj5T<{j zF#tWbg+$V(x&V09qwv6(V=0#99e~_=)$Qb!(O}WljR=GWf)9=9?-giFRl6Y_(w72# zn2Tq~+D^=sz_#Kg*+31X#}Nyp%}l~N&1k^OnxQuYAKjIp`~h2qf68wI;{TLif5iVO zzkN`Be#-Bsy!-z~-0t|kKjn8B;{TN2V-OP`V+`GZ-%k8!?tK=&?&u-?@w*zo;rP+q zc@}=3sM$7aIP#v9rT&_`H=1h_8Rs=D0le1KlD5b zUZULveoUr1Z$=zrKHdf{oX7CfNdKX5_>D$nON8wke*{CEeWQ9iECo9u+JkeSBMlm&tUo4BwG|a!_0uBA z#*T#IOt1P8g1Y)K{+9Wl`(=K;`U-;d53=s6sgRbFkd9Y%153gXdohbGUiCSS^(@Dl zV5+TG$3|l>T>0jWj^=j{EO79{i zF0wgz=3A;bGG2Jq@1LOr5{pN8)guV%>S6pv?q8@^HzFi6|I29PWroO$IC4_agIK>S z`VDjpM`m~t@jWbp=(VhM2WL_^ZITZ&3e}Cjj_S^d&}H#+=;||s@Tm$OZgWqOtyYwB zx#hvo;fHt_tS%##lm&P^sT8YbH%y<&^N}@dFnA7TNA(&?Iwd_m>HZ?=_os5wB1sz4 zjqNL3pQsEhvK)e%AI|kI3a5RA$hx``e`9jJln_{#6iJI*ix)h|FNpZ3fazo@XTKef zuCxC*y(48@{5!^ockJ_W_A&E8&MWT8T<@`61`1pxYjAUFe+0d1Km5({ruHGgb}{xv zds8l=-Oeu9I|m*HIO;;*d}4F9=cJJGGH~9M8{}6d!<~6*mUH%9ZG8=KH0t(S?BNBkx47F4chDeK+6S8 z&-bcgp2wMVHB}SKmR1{-M8LUylC%%2w*{6&!*4x{o7xIl_c)qeDZ- zk~;QeG}>2F5bZ%k8y)HeT19mylB<{^pAv4od1u?WqDN-0-f08pE3-| z+-Q2{%6t@SD&_BsEeQ~z!4|xwUfrY{605k+q3=cQ)=?W8jrG@~+QT(RwFmsbp|&5! z?*Xd)EeLPb?q3gZL$<#~b$YYS+1f(9EvGyo6G#78(mqA(aTVJAdyZ*8+o=u0iDqLC zYJ+g-+E|>MJ!Dh)z2)b$K{(bd9*ZlH#_ZAt;iR^)I52(4#`3=9bnKz$q_z0dhiWN* z+4pDvCi}kZd+*85)xXNq>-4)^~+PVAz3@p8-R3f^zD7P8J zCKP@hAzz=v$XfDM5iOFv0ou?s*O6Pm`pnMHsd95O{kS{x3FQeT_ylr9g2t)eZgF_+ z=E$!;&;qryVqAS`xf@YBJL^izCsBYfrD4ou3cyz|p?DKr#(6*0wCX@U!{ZCS3F;eH zosLJfiI@yY6;t3wmsSv^re1T0bQp1;mbr`YChJLFpe{ zK}qyQeLX`kP>TGqeE7{hPW@bV-EEZ2ZG{xWSwFd)p7;k;hI|g9C*E+|&FJ{`x81;K z@8n86o!)8Gxt;pt3h{9BW75N&!)dKupf(-&ZF2T(LY?okA zfF~r_A;1m^n(?Voz>^Z}FThh093;Tg5*#7GGZJ(N@T>$!19a&pfOz3|; zp$PZYf4U{Hk9Ju0e9vo zaHA18hR)S`7Xk;+DqC+uVCN|WYzS<|1h;h<0&C&l-Fhtow56-{N(7cd_Oj>F{3HZu zP3fa<2w`d!3FFbzNi zKOx~H2|p#_ZW8`8rAz&NG1j^*ie_0=t>9ZZ|%uW+^8z3tCXnIs~m!&`7?5h6t1Cg@V=~XqyGi zEoc>j78JA&L8}zBDnT<-{iA&JK=}l%Nzeuf8uwa@yG7921kE96)Mv>lLHPr0MO**> z-@jD{lVm-44fRDnP*i`j47h(F{E39g*P3i{@!~56%bex+S z%xJ{U72h-cy&f8eI~zP5>a&_-CPv{)hQXSIjU3#`S3F8U2I84BvDflQupi=K29t`Z zo6df*!Go(3F#2~x(^lMHOu#o+imr5cz2yiw^g9Y5oL?n%KwC8GUfP$4S;C+iECYG( z7)|5|dJc|{r~X00{8<<$FsFf6&KUI>gy&#+bPs5V+B7Gjh^#uP_mIHX#x#9sG2@NB z5KOT%su#U;^m@8Jkq#>yheP&~fbgeN!ykvdUySH!E`G(B4TuL{poihs&+&%TP!(y5 zFl8Fz$GLFb;3DgQ`>3|)juF{s;{2AhZ@$G zWRh4+e?F%_!N;h2e8rm``VPG&_+1^Emv}wS2+duQpm0mz`AoRK;<(8!bJh44OOi z#^p3ODcLW&2HJ|qA*(LW_x!*cN*jx{*3{C*qB|ofZIM5PJe^?i$QgJ8<^?&3hsi|F zz?+rqg(jcl9P2sHKRXC|P79o~BYF<;++qq%fpZrp4g(2NXuZi-z6MGa#~P$fc@ACE zu{hEFA|3EXPG&3r7klpl9%XSo{_iGvA%ui?k)%Wg3A)svh(tj_63xN}HW~yKBnaXq zh_v1ivVavau!-b#U8QQR)*G#tVr!MQ2nY&UA|!w!;tfH$sKC2K?ixTO`}>@E-`#8w z`~CL!)c@sqif-Pyo;h>o%$b=pGiN5P@-0b6ARq*kUsr-pL38NK>jOsz-hZpUh;MHB zy@8_x^r~u7@?t%QtH^;a=^?jF=y+#Gul#}#rjo9Q-j%tYR7$C6Jo>0g_k7}%j&Jr~ z#I<+;9JZ$7sIEUCD)h(&WKhL;%ZCPz-mF)3C4l<39^i<~2Umctv$ka+jb2!>>chf{ zreb~eM|MGwW98|fQI;~x=UgA%rYevU@k>_vUO$Cs0#;0WUD{=zz<0>OYh{M)b(ae6 zkH0IJA~(4B+;jbudjtnLY8jbB@Qdk_N3*RC7c=RX&!`0lOoH+qRV2hMWQZKv#l}&eX9(asY^VyDsf-xd2qP< zvc4ZoKGj&;RO_i8Lr8UbdLjJM_d|V_A6QU!=FurM)6{OvP~TC6O0V`g!_n=Y2YKkq z!xLJU34WJ4BKf4(-cvkN6F73VKKon(82^6VO_A5S#7DtolS89Q2RByh!OpV6O*M4n zFnt*r$}+MRSwu@Z2eFb zJhsHm&^so~0|-4U-7*B|v$k?|P;er5D#ha*4s8o252iBy_V`kv}!1yGvE_EK4;JpWV_1KW3P!ggiG>(_D%5_P*rFSVM}YX1u9l(LI4 z>nNt3BJEg`le3)Or7s%p_Cz?wVe{Sj`XgsRc<`>ul?Lc6=ewj&^REU)l_f1B{{T#) z{>l!1nqY-nV*h(RJpRA@r~>; z;SnDltnM&PK9%k#1&hB+HmOBQS}7RMrw#X?gfb7G-~BUR!|x5~1~>a9J) ze*HHY#X;nWK#_H?zyk_apvwq5Hd8-p7AZE?8{w9pY;r2C8itbD8DUB5^S}C@6`LyQ~IYh5kZF>?K zBFuSobF9nC$WdHp2~wJxTfzwfp(l!J>Ut8|*%acu^#4%OY^x-@8!%MK7<5p-LFxTU z+`S?`0l@6E(5O#YU#;D6O^PEweNuYG_NI!XS27nP8t(EyZZD*Zw2zh7EP+b3)2u@5 zc@$hLg;?D!SASq9on8ndB-#PDv* zk4jBwh2cUZucx}iJ)x5MZX1O{iF;th(PX`{E5%mu+FNC=a=?ZW_&8860})vxn}w_C zG=&^s{S-GPwit$bhV=)QOBz9NU~JqOAmfg(7{5{WK$;*UoAIrTWgQTctnk>g>>x|c ztl=(l<4KB582xS~b&JujB^EVc!K_$Dzfo%RLmI~Asb~=*hm-`BUPPS{dqVSX=zu4y z>PJ?`JZV)G35sGQ@Cpgo!ahd|7Jc=4nPTaIN8^xXv>+@zrL|PH1hly4ZFz>fg<4FI zY*c&cvxf+(BVxr55L@l~>>|rgV=`}Lkn4k=j_yT0tS?HxoccWEognOUi8Vpgt2(F@ z+CMg-g8r?gg5D7LezZROa=Hgn_%pRU%lxg+xhDE0({2Nq5%~jgCsHG!1$KOz*aFMF z?pR~CB)dI~P1GNF7+$m6V9K;*R16ylBGhi*$FO@hkyc^z6@g^3!~EodQIbg?seLN# z?a@2f6N>=^dk{mz>Ejce3y8u~ipP;W-g6s`%7<3Hju4T~H%m+;!zzQ0-7Df001w*q zL0;&KESgdIhbXEgl}3WB%%|02q?t-(41SR-0iB;${)>F(-5rhKPgw}ii7Dbv=Z*kIylxR^r_vf9as47W0NB;%Q}gie(& zNkNF`m9mfjSo}uX0zfTCE>-)7vZ!%JQUt0tDJNlq!?dy;3r$46lD9}-(pb$>At2No zlu<47H>bo(>4wa&bW1Efp~O9amp4?G@U*GdD>+;4hSs+S=-1 zbXHW>GGNlk5!y@SqMD?sInFQ=$3tX*jPMp+bBK(SksgG^+9F$Gg&zB)Ez*>aws1wT z02EKe7PLwxHVZEddNLN!H;jrl&LV# zkv*Af?LC?JJ`B^P66x>pjTi}Nu@fT!Ew*ALAifu~Fwy|&?d=#Pfu(pH54oq|h;7NJ znCe)}lU7WjY|E&ad9j$qR?LmEHKStcV=)_5OhpBaYj4k}crzA%#EPG5#fu%kPWDms;_nK(e=MRQ?IE_-R&rjuqdFkBYC3#Xo7q z7h3VdV)650@r$ka8?E?>vH1E}{6;Ij!it|0i#KEON38g{R{Z=}d@60L>X$8z++rI? z;g=hW?~7wR3AT}wZ}oopsw6&%Q7}qziPU|07YbsfFhXI#B`rDmpmeQ8d5sPG=)w;v zZHMTbwp*hTdc3QmMtxvgvM=y`vK~mKwPYds?gt$G+7S7@YQ>n2ZRSx?1nZRnP+TL_xuAcK z2x-8HG{Ptr>X>J1(eT2r((oU?uNs~kD-K_Gc6wYHVHF~|9{)%vB(7&Zs=VCh+O+F?_Z^`nXOmdWo^iO;A7h;4>79n@*M`S>r^s{KIKCxAHXAcLhITO z*`7wHle@+jt??5$vWAJsdi{aV*tnN+E8P{U+@34+2Uc2P92d`xylHLhC+ypMQK_kY z`~J+7)F^QQGYd6JbY}sgMu{95KxE&(qYNOjZ{JP^5E&&j89>D1$PZuRkbV0@J8{S; zu^Wl`|H3Ho9%mc=J4(2xSyDO&iH3~r#Yc(Q>X;ON(uyy%;)liJ=f&a|Tk$tq@e^b5 z^|APkR(ypOKPMJ1y-rE+BUb!eD}H_~{y#oSM84nxi`}tJc8K#fSpBYs62t!mE_;;*n-!;+p$+nJw=uzth}bSp-%MVUJZJp{Qojxc+o3A;#$iI z1Jzj0*hbzWe9lx}Z+(|x>!*IP_{49_{Zn~j;obiQY>A7-3%oEmECnI?N&eV(ErVe! zUE){r#C{SUbD#K)!AT64vcxa>KC$6%wZjtANxb|dePW(inpnJiWAFrb@eAIue0%Kt z5+~^r=_BP!Iti0+BCJIC;*RB$Z_J;VCKewHi}@4361V^BXf%a#|C7IC!1Vry;C2VM z{|T0qcOw41{{wZ3(MHO@30ghD{jh)c_b&O4{4ewN2j`!HUqak(?f7$O^S=B}miAAC z-wVDH_s@hh@7eCJ`5xofg?ZsQ{QB@4$nRvZt|I&fes}QuBfpMzJzm2t>38tm&+iz& zRy=wtVeR=2;y0Y%&HV1>_bk7~{Ob4}TQ6zuNu_T}VIK2+c2H9r5q{c9Z7^e#zw1f8r-`J3qxPG2bx1EBM{Z?V)KL0h0v)t3f zU7Fxdi>2A`7+)7CmHh$dcus6aL{V(T4U;@PHCgb<-Ev^lJoE>)%ohemkygD0Z>749 zR5k>s1>xa1gnY*W)U&ZtasMKg2e*yE0@B3tCyz(n*Kn1UNbOYHs96zxt%wC|VmEY& zC7R%j;oqvE!;b=;t;R2I#a>^H2NMnBjlgvvzbc@1xYdF1IUl3%-_CCjzoY!J(13U4 z*Wdn%`{(?P1b*2`$`DQbz5E_ON!-tgPa^EUQTChs*71woZ;zjUm;3*|nPNVREvg@U zK`re7_v3iu#VA@|9DGLJ5oOc2Psv?`a*Dq6DY?U-SIR~f!3PIf!5%w!IXpw~rEKl` zj6SVrUFcW}U~cTZA-7<8x8_%alkuJBk^6a_67DxdYkfwYS~`p2IX z`wDVs|1w8bK(x`FhPAR*ykGtUwnd9epqFhR-GXqbk z3U8^93P;U!yTVcPN^p;bw5V{tP&|}10B~O8z!1YU|7IoiVLz-yz)|BrHp~F0#q6~E zLeJWiPbUX>)X5de4zco+t@6iGzO?Q`fRZKHQI${WFW%8i>;;5#4Fi(umDgGfwGRMR+rA)~LVc!@-U@h>0CuXhxeL_E3C_dK zg_PFWq8@U@it7sV2;q*CvVXh?a~XYx#Is*x!7Ggi46p(oj+dBc1x$#i$gu+MhzIBd zoY3~_w2klr&yxyIQ|71`MB@YVi^nab8~*ukAl)ur;B#b`Gn201Fjvr*$)nl8Pm96# z80$U8YV#fvA;>igSTJJl2n1_*lWutgu{qj_QzQRv`hYy@Esr8ty+K}o-e9*~PEq%!JTX4k8DnE>kxtGHcq&xT^>!4l)cNE?Fe z_tuI-mpeU+oF&HZOu=~$uqNMB(r@*ot1Mv=oD9PEg0KbI=RD{u8*L#hFBSPh9t&fM zP#CAU{1^rISQz`9pV*Q%nCL9e1W^&KWLgk9EP_=`k9M1NU=ryV5PEkRO~aXYlj6 zyvKp-6c1*HIFH76T}AVKzgs47-K_`3vjN|2yeF_+CM=F}w%rysT2?oF%@{+>=x0MTUnB`8?%gyd-Pv|Xft7>23YPlBV| z8cmPZbHGG-8#3+U&8B)R>v8CII0Y96@0Yu^dgWj|o{AE8SP!TLLnnZ| zxgsRu;Qs8q4UCpyU)7EE2{`*AE)xHmXQqK8z`sjq)huY3YN@CN5% z2A9wLxqN)V3K>|K`_y~&MMLK4i|Cj|>x=UC6yg)0mUc>Yy7uEZML)Lpj zz1#8xbcw-X3}xSCp{sI3d3Qmh|4`TDoc>cYC!fwu+>+$MIS^5Qy{Tq*vL|h1&VcI7 z*4$6U&Q7$(7hUULRUEA?a(*|Y--rIExrGXq6z&%4lr%3??DQEU>U~ukj3Ep3%FPz` zQi_NHV>}u3HlK@HQ3*Z(POBq|J|<1!}{NoIr$2YaiAo* z7;;=CQ@wUJA*~kFD&&t!)ou5uKok4pSSO95bc2((fv7Q>MDm8x6>Z~;FW+o@) zelg~3)fL`OPY#ZtuKQyBQ|enxiLU;`T$2m?`!Xl@XPQ-#Tu6O=(w?iW_RQp<;Cgo# z$HshB+mSH$8pYh323KdM7SV;}D~(6}-uJ&u|D}HQL;8KCS55gB?bj@PV(ph$DXRx0 zvEq%jVoeKvLH@+}HD1S}P$!3~} zaFAU?`JT|8vHH@UHCBDif61>OD}GhN_NVF_s7e0+WqlcGj?K1a{UdW314s7d&(PsK z)8{`+M#AUi{*ZmBu69aqmNuPlVZBV$*c)zaa3^rRJn`~mg>>fi;cczrhseinByH*Q zKKcPCkFXUtrfYVMdU#l;(gdH01034{z6|k3LYB-u}>Srg_xVTe!ag-*+&>7HK4Gj7Xsp5*L;lIZk?zlS-80#2V4-(AL$x>~Q zUA8^k>x;Ie9K*<8ev(Ijl)fs~*p1K3^>PS|nyRuW2?Bydkr27BMI*H+9L$8HR6F#n zRaYBipjJB>Nc%~`>*bZ8(i?K+IMnk(_bEjQMj(iD&7M!FBw}tNBv&^(22Y#PIeuPB zOsFMJ<{o{UX?%+yu_Y6mUtTi|eIMF4QC)F~DqI~D7e@S&$4Ki&gECQkP(@#&RCM~R zH)v3-F0hE2+{^r-5vA!y*+FU+atcZ50BuLiopdPz4e?ASttfB zPG=gIa-r9#aWi*a&p?;yO&iQWSKp-}%WI8r7dCV%a;zU*O){e7+hROo^kbzOUE_bi zn$E3fI=5J#H3ITAFLV;@x5oNI%>HPd$5`hvJ`&@j$BTpaxy%l;k{n*f(Alq0NxFJb z-(S@m9Hb9NI{fND?+bYWYySSC%BVltGd~*MdrDF0%BUwa!x`f*qRP|g0~-$?=y!1H zO~sI0s8GthxBPTPiY#N3FL_u_urM2)a(GpWYriB44$JiRJ2)jfF>;l+I>lv2_WN{l zW;{-Ry-xCpy<7(UeqT*71a+&~W5!V<+h!t=RQnfJFS-hzQMRR|{twQMc?*?%$g7bk ztA9v*#qwd&LCf3PhSugg8u{b!xWqw&9>$4d!(%?*HdoxA`hq};k zD3ht<=Txnp(bpH8ivD0^Hs+G_*H?^3Ry6nD&~<1fHv621D)O@(<;nC}ebJ`S)y{sO z-T$=*1qSnGPrsV`7dIpW(@dvMd5xaNIww+pl@dC#9RK}dnXW!3+EX9>eRy$jnXNuv z(~EU%r+~75a{<7fu&vVEz)O*q!tq%^vf#b*x>&$N5@2jKZ{&+#))yA5M!Z547EP{x9QRNlk`~VG=HEt6am(i5;2^o+S^B=me$M1 z-p=8}E%i4k?Mc@X|F}KgVl)oM@tNO?V#R+u3-T&axgjsg&&^Ms+OZf7_yPj{o}3%j z7apMRnJqgPjyJeRX?sUAdM7S&b{-?QuL~Ca7$`I&KKTB&srFIL%FxRd~M*O zg;fi!s8nAYbPEeZi^NNe4aduR&VSi*r8)=khlQ>WR=r80rW#MRa^w%yXH`f!tCZJz zzg}v26Nw|^iSaED*I56Q@@|*U_{7*BHe20RGeX{quUOHwdc>!`@ZMIcS$2hYx4Lb` zi0-Q}TGO?#+W(1fN!v)>%T?nBo~g2b$&>QF?w|NR*ehDS@ZR*3=K9#TWcIT6-<+Nu z+7!zri94J$@khQTqsm_@UUuWdFUAso;0s4iwa~Tk30H)>RuB2mQ}MP`-{C){;%GO2 z#_}AyO()Nw3vQ0lty4qKmh*G;hIX7^v_7pxyU?$8`Y8=QYyGpBoenP6)!x@vUpBq- zheE%uK>RVWC%y3_LLa%0sois)RjuvL7!!3T+KY^jcf-6!ZL#q_^4(*6$IFGjK*3kH zV(-d-{_+~?W^SG?jJI$tf}zo8)bjb5-@EjF+0nV`C5B+5^FPSZl3{^~Qf#aF1ldLW zRP)u_TJ;loU>re3cCTc^id7qZ;r{C*SsdF`@|T#K>=yL5Q({b1D;;u*H zE+g&=#9jBrT~p((yW_6g;x0cmwJ35|+;vqv_6pkt*4}vFfVe9^?z$-M>H!#eOQ}x# zrE*o^%CW;#YbK5tapuItpbz2r$+=45I_-O2xX|vEp@;i=YKE4E$n*s}e~EE|l3=$( ze3%C(`-0jLoT$}&!Hk`_TJ}F#QKY!1oLY=Mx4aF-{oc_ZTT!A9-0pFH>#2@AR?RBJ)KqXq!*|Cdq*f6Swe@FLd60B(V1@q)3&hknB$Vk?Eu$4C4?Mzsp)B z#Z3rCGvw~pq;dQWPa5k9@~nr4J(%<&*M%;&eS_DyjE}>6T>7Fl zUM%JnVc^OWHeJ{#WPtfJyw7EP65g8?*y;2vmjTJs{cw19CaMJ6vw32H0S9!polwKLjmprM~c1gRRCFW^e#H{LcqzEs$K=J6lcC7+s?*J$iBvtE^l zHo|6V_^VWBZD3`R3XT4i&~P}CiiHIKvRX+UtiHKNN?**4X$xXJmWFK%=CagK2WwKx2Bhl!1n~TPmwnZp$dd zq6)E|DD!6s0&%p+kWS#QPKwn)V@$VnQnZ`doc%IMxl(GiBNY}3&2W+ZoF8T1;c~7V zXx!e7hbd;9a#B1R|8fEznE=`@fj^>-;E@TSUnJnMNKz)^kxlkL{V013k8HA^rtq*~ z&_?FumM{XVI^{L;Oqn_QC&6^`ga$jYNE3)&s$W@eWE{=q^@$c{)@6PeZ$IQu?$XQX z1VQb6QkI0eRg7rQr_YwNlSRB({kx>>ND1Rv80!eZ^c4DX3V%vc=-R_m(mlcQ6qhGB zJtfl)%(olUQCVT3Ey$aJf{Gh+)q!`wH8?gE;Eq(>jRGP;%rp8bCS z&D_N0T62FN0skJuSTx(;ljJ>AKgi|nk@thln|K$RjS#8f^)P8S$NnZqfum-dqr5dA zM)?jizlvhB%zotd`pC9voZ;&HppLkCqULaI6T6uD<6&dd%rDVm0hM{LW51*PuQ_4= zp9LN-p%yqC`y7762~U1x%zg7r4lwm_HW*Ru$zSsPN5S9QA^FSO@m?w3Dpu9E!_Z)P z_?K}kkNcB&un3-{Ljj}HnD+GHOl$=e?3YARkxe8C7F+^|wgr9pt5aQxtyNriuKlwX*$!hgQN zh}W+jOMcFF)GR*JQJtPt8z}fJL+aHwsJ+xpy z#mF3unDNSE$Bany+?e3$d~1H1V=??4J!_y_o$NCPy7h$vvomC_XAI27rfMevLYT`K z=;D)U49u+4PIt#i zOjkpw(r2mh=fwGxrHS}trm(tWsnky&x+PTEMO?nJBT8Fp-gbAAI#!ijY_#H$o6zvK zQTjYRtNR*^g4#s^-s^B&6Vz_OfJ?GAn!oh^tpMeZK47EKc^E;=#h;?4mJQu|fXh6w zk^uP^TIyg@VHJ5~B2k8R2T@YuZv{Qd1S=^M)ml~>QN~75aMz$^)K14D8*K8|vn(DQ z9l5$MdJ^7mDClmNmo>~xwF>ND7buuh{##H~{!s%5^3rDD^WtHDio0rvr2^z#5_eU{V`s%()8nowao3Y^*Q2%z#DmSw z7#u>YnnRmmR>brFChjVayY7s;Cd6Gg$6aIMu5072VR6^xahEslx-{k2z{TgWI>#Q**Vq|0-OsExb4l%lU=rmg#ME7TNIS`05IC z$$*9HS5%#cVT;li^7UGB8G-it#232T^ci<=^BKiQaA)I25gPVklH#}@>slGdyks&w zE?-^65z#&Hj{>zT2(1$fu6QkJBtq=DzaZ3w#m(WZ`7^YdKf8zV=cRE7zryDcgAJVY z4HPUuL?=&A1JcDbL`7<$X}^|S*f}Q9h|}YqI_+XeYIUAG+eLz%ovcU1TAN?zALIOi zSuhh)=1x4uay^Y?^3OcA6bV{mu9!>dL!M9+zxK}%Bv_zBT}u+}yIo15@9jMBB5;#nG9Sd4vb|K{0axSrrr^wVdq)jx>R}meR*JYVW8jxOm-#dSFSNq&5>O0U*43poq;TG!|2G7=bOiSd9OtQ)eiRl zS3Hbtt`O={kTD>EjsHjf?Juc+#J@$plk)GDKihPVJWiX-dJR%WU@{>k<466k6)is` zL?L61AJc8Gj2|+d1`0-rxw07-=51y$|9&tm6X%!WVEz_!CSZ!|Qe+E>qmCRD)Vh;F zxMf?Nb{bCMme{b`Qa_Qf{;&>ztD6Y2`@#aZb*(ILscxlP`if^&k!


JO*k%R@E2 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
  • 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

    xxNIeDm-5MY+*VRWqcL zzNE*Dn{6!IEYdy0a$HvEjN{?(l8d?2EWhFd(XY6B5Ln80F29apvGF76JANfi$DhPG zX_wd0E#+*o!^9o=2_BMuT-3P25AZ`)+X$(C*pd zzEHa>#eKGRFA;ZF?Oui(rO658?sS$g={MgUiL}ene0?MmZo9A=2X4EtUE;P2J0xzq zuw*B0yRbBI+lA%fjuaMOg02*&1DxtMl$c5zw88%inc0=<3^ruGLa;oCdFdj41NjZ( zHlF(4Ey5e+vThl8XYfvaE%P+;J&eCp1IEImBNMX-0{X{3>Zc z*XuN@qanJeRXVd$lrgWCkn8L@#^2CC1QhHC+xD zqO4T=d3-h&$ZL+aus#2Hjhvt_txKw7-_hl)m9lP>veZ6Bhq88Y6qmaT9DLVONaUo) zWlS8ICFShp@|#@_8vHe44Y`wd>V{iK%<1B-4W&)pP{W2^PLuI?trS_4)WoXQ<*cX1 zvQwKhqj$4gS5X%pf!{a4wP@s2PHitCzFjD2E)+Di_>V3Zf*eRNA&z84wN7XY1?4gx z7YL9w5^rG*Br@f2!7+A!U&)El{r-HTs$4agtD?>*UrIKZ*EY%nIK+S~z7I=h%GH60 zeJNwr$RX+?2$vWTHExCC6L&)m1gfFkKI|fQ8MZqQOA`+ppFCp_aVCxzY9Z_l?Y2#Y z*EySpjZB%*+uY`jAD>1ix;4#sX=LxNeUi&IT~OI4Ib7??+2ngX+~CgHY*aiz4~$gb zE*QxMDP{6*p~9_-3b$rqbKW)oge2eFDw?qFvBSh&Q=O@*gE9Q$0szwAaXKJCBWwhlq(aZa#hMYA8<^9dzDV zX(`|Z3CxU?m&pl2*_-L=q^vZ#1nXhxN^#rA+W+%;1%WryZPla&AF^&QU}PXcUJ{L0 ziX>Fk!oxEl5_3B+bTGFosab!YU>sKoWZ+^K^Cpn zV*(1~Zj==5^O{Hqg9Mvt<=Y?<2uBrgqS`mr=D6ph3Q1yNt$YEo zl|E86`bbUg;BZ?XsYU4{#d+Xm?e&r7bks-Mwkzo5ie;aK!jlmgQKs{RrB7`~dKoKu<}-&f(cR4;9(YZY5zQCngw0s%uQ zgx$c^l|q5Z|mcHPkn8zJ84Rp-L(FZsxnQ#jHZuiVX3gc1`VXx3ZJfh zzw*Wxoupjj^)NSnkuDGGK z@msjC;-S$=dg9phjIsx}XZbF2Epn${nC>k7iLuJJ+*mbkCF~r_9^;yL;h(qLNJ59+fV(iLNGSRxJZHZ(wGgx3(3`wh6jBN!IJH=SeC3 z4m)?kfWHC)!V^&MR|2D4#RS}%a1udkI8QqL2JHo2YQKs`Pr?>9c31wr#3)6cgUtikQ%DwzuEkX{Vn%|4T1T;SD5CLLyQ( zw>?|D=9)t+AiRO+YysuTZ6Z?avHna~L$EEEJL8BOM{V#UHdrgT4bJ$Rjy=l;9|L(} z%l#vSl5wA9>$B0q;2OCyhE~d}Bq$7C{Dk`SpMEDRsq6#(h7)Hlwv&#}cD3_eoA@fWP1kROo6>5L+cz zNo6!jR?p+SdH`9Z(uh*l#rQ)TIPxkC{8^F|1y-hu-gXg+_YW0tds``zn-w*(pKq*M zs{Em|l`8);x{Pa+y~V#yu4Z(wcjr9{=NyyfEiUNoMH!P9vw9-LZ2$wbTAl^J!oYv& z{4rIzT9MCh7hzF^vFf+t3q4{>nALcM!e?U96bc{t)TXdeem<3m()n7*0iBDs%BO$Q z9nkr#k|ikfL0>mjgubgtE7W`kBs6^uLC1!4q;F?(()697V+noFl$?aVq01<}?2QO^ zrPt~9k78HMVkwH{JcE2nJyI!JytnquEUL@^r5P|XG%_?ApZ)?g&TpqLrSVD8_$>TH)9V@X*Yw&$ zfZ!vLj`;L^A%ahS6rWFy+W3IV>UX1^a3gT^?CE1hc@c^(1SgVSN;zu1E{TGJA0fU5 zEC&FiN~~fPX!lZK9gEYK(Kob2-A}mj#PamzK)Amnw|ZDylglk_x%@(BdsiD^j0QaO zmq$Rg~ABAwb+;EN;| zQ71VtIyvA?F}q`aWAM3={88NJDJiRxNQ|-YW{hPpkTo81AL}_CkU;#kXU7IStONE* zir%pS_rwG+0;5@t)d5>21qyA^fMEpa$$H_}a1FJHDZVwiFxc;AIbgY-V0vaj@u(C< zsTvv2jO5^Q;ld)mJPP07(V|vwa5QfXKfVIE=yJX$Hcz}}#a{J!W|#WBCM<%)O?=dS zT=Vg2oT4R><~>)@&+G2CFKNzt$YfD6=6QsZAa)@RTUC~o<-%zRy-1}JiNT5 zVu`1-dL^wf-aAZTZ7i4x+xD-K8ZgXtg#x-J0bP^wd*CK${Ws5((HJ8i`Rn40s@;Xo zlir*oGy1!S_UrBYY492jS!ee$sy?vcodjO`UbwEgTbO;IjRnqk3(b?SJIOP1D{2kQ z_)Hnr7EwQJ*}+0~hYeW^BqY*f+kQwv&bu?tyLwT-Ay*HbHpJ;mmJb%zO0b3>nn5kD z3HBMHt$*qJB-aKL26}T2&A3QZ9?u$q`t@ZahPp4~lAwIzxU3ak?+Q1fU>m^~Xk&4#W+ z`AfJRNj0}yEqMk92igFC1t5I!LB1TtwxvwbDdqi&D2vbMK#_USvr#_%9g|KcZw!(W z0)t=pNb~nK;Hdd~Sd|pE1k#beXa6z6--`)l7LfTSPI6N6MsV=%4N?BS|0^hjmFWuR z_HDlrIv|Vqu{?dB^@b`abJP9dL~V zAQeP9=RT`U0=SuIy>n0_WQF+a)Jz_8#13%maC~D3Au+R(&OKx_1 z%}v#c#~h+j;JhLWs&4VQb*Csaw(Mju@3bK|011iM*`B`@=4>+jFMtyRL(=n(Ombns zl~!0hCRr}d?J78WxX@YWExuovbfbIGAjH{xXZAK5F0i44l6`jpjr$IC%vz+>cKgNN zVD~Eub3%syDtLet(9}L7qv8@_4&jEp@|OFzd7Vc>=i-mb>t6F2VNKrPwNBS6XUP)s znsHZQ&W8KOw^aavJ1_(BcaEw+llSORuk*0C_-3gV9`Y z;5shh$g`ayp-c81g!7c15q_%j`UiQrTHp0GG7MEk13Js#E%DC6fNJ={oMvNz8zLwU zX%AO;prCRO$rYot{gd#k4ioR0EDUBroOMr%7O*ow5#=kZtq&igY`+QJwFl1{HDKz61n zsOug6hzeb(jEa;f`&fCEt3*>q-oRA#U$ijd)%3`&k)U$wtM9v(t&`n#l1cmuN-9^-p^pP-x9 zmB19D<12U*{rf}4UD@#74))!-2)Sx^@Oo#?2lM{rVkoe`?8>Q`SIr&ORZi<4l!c{I zUT@4ZmNuwGt<00FYK0NW8zvDW#jn+gxaijP5qk&R4;H?+Bc%Ih1lgMe*(!~!ivOeW zZTVh&tDM%i6vy$1C^)LaOx+%GwGFlxn4N-@`jwVaH;3QNdEZ-n6oD1qF1D&?XPr~P4uZV@^KyJftx@$AT+Uhw zMyrL1BdUuO_7Aw-x`$|O@%$X}GHB1QXV6LyunGKChn_W*XzVe4QWRVx#qq`gGp1w4 zd6Dw)> z?ZTE`RZ!k^kPtf`Hwy{hRqGzG5r0VNyr`miP z5aL}|TciJpLH?s(c+H*Wp<1ic-8JLPjhR>h?OQqSeQ)i-PF{}akAA@uqj%Sh%WTLi zYv`L->D%dD-7VDkmx?>`FI34t@tT{xnLE8(4|<(DNre%Z)1=zrUA=JayRXmf9o!vB zC6UiMZRGd7t0$KJxnS*Wk31iVyp{8wb2Yj)KHMMaTUoRnbvUWD!*^!c@r!*u)}`5` zDYh6gA4cfbr+Gm8`B-FWO;ewokFk=e@uGHrX0unz`_)Y2*o&!uaEP&XZt8ZSUr%!U zF0t=>?K_0FzCiW%SyA9@-+_4Jt6hKgG6#5JBqgHK#i}0K&H#1hT7+Uo}eq?^R`20DjFCr!eV#QB05 z|I`a-9qON(Xs78kDf9=lMJBbqDtm*scn|l!a?7w#KLp2@zwhJ-Wa0Qi97q<4mlEU+ zu!K!~8xXs`{vnL5$7`&uBDYM9JS{YXHB6)1nIL^ctxax*=flr!V=zL!K;k7=+1sX^ zN&0ig{{i9AD1Vw1bzC?E3#f5|3(tf>}{2W={*TKGrQ8AepX)P-1L;Z%F^^+m1EP-wjY#|CxM3X z8i+T%$s3%Op3Hp3r3$XXi#<=mE>K|@kKW|_qA~HcCqa*Y;QgyB?b#o^u^k;TyJBtp zS4a6XYRjRx(SCsn?VB4bcq%pUbhc=UjtG=z%kvaDyEyeG`|E;lDtKZ1;4sCo)N(@! zmRher6z5oyx$AWYkuyJFC%K@B*<*BLVs8+Gy`ay7?dPgDvz{P=RnIEZb+^Yc+!c?x z{KT)H;38k*LH^1=B;5J+q6({?FEFm#FVJJBo#Bqw0BNp>Vw#Q{S~`6>Wg|Up_(AnZnGI{*zp&n#4|)eo-w!?>H0& zb5C8urN~Nn5H^loIsY_*qli>ce4rqZau5R~!Q8SMmc6`t`PScLBRk~86(L*!yQYy=`qPSN0Z0v5Jxjt(4MF z!G$8F&+CxK})+pg~36^W8>N9m-a_~*nq%94bYXGbFsjYJ-4NB-aiIEg(RstJrG?pYc?m;c*4 ztM8y2yN#l~JWgCKJ=$$}_bSA$i6R~(FN(YRF{s`En~vl=twX+V?2D4^m(k?c>Eu6` z+dXH>`xzoE}>|h5c*O7-PEpz|D zk2*OT^5W2?bPN~>{;GLz)CF>4_%6ZL-~Nnt>^ICak@{_r(qeeo9x@kYqG00DU?+#k z+xD=8~k9rirv=+pJ9W4r@=Wk_~^&F$UkZDC>y-j2LHDP|H1}uu)*@cE0~np z;8$!g?yd{D}>|(FV6@@V7SjDjOV^po%om zvK0zu*x)lX*kyxz+TdIbzRw1q_@}P?of`b24gS;yFVf&IZSdPR_$3WK50z9Y@--X$ zXVj*t{4F;4SsVO`22ZuY3vKX04Sv=JPq)EmqZ3Ug@7v&sHuy>nPG%J;MUJq+B^q34 zgDxS?v2)~Qx`eI25;2h**5qV8+=%Um)T&C4gLw2gg~`n{o zBQ&_h2A^Ytf2qM2BhyJO9X9wk8hnQh4t=O;vRZ>@+2Cz9I1#bZJ#1P!%Wg3|DKGc* zcL$VzPaMpr9$<8QtHHnMRVlF5y7!NQZK69MGZ%3kp%?kv?tDhYf5?u1m5#rQ!EGC< zc#!xi%0fFzA01^JoW_nKTBItC0^c6C>DyZI$vP4JuAR2|UP90^F9pxS!Wpy;l-y>0W*io+0QJ#uMsfq%xaZcAs# zYd0@H2jl;iR*U44&>@%4KZwqY-|A!{#NJOj@~oS|#P&)|av@GE5--Fg@4Qm=7)d@< zC!evXlcRZNr0AzQq`f;PZE7@a>$9rppHiLXp^>yxI;0&KlXhS&|MJ1p)`wcGs~?)SAj zAnr}ty-nQfwEN;J+^=f)Y;nJ!-J8Vyly?7yi6Qi;c8A36*Y5ss@8$<6v{)R!#_Ox5MhcQ`O;5FB6s5;&ML~ zhdg$7(JMF*C32^U152;Dui+pUzskj$CRsojhqZqPLw|{^F}G8W^}f#WBXMui?lhRR zwNAUoiu+aV7M^asV8<8tQ`#+>Q`V!}JxJVs?e>a$mUd4Q_ubmPOx(9>_j}^LLA#HM zd!%;vfrVPbv^!7S1GT$U+!twgwYbmG?k~mNO}o=%?Hs0>)Uj0DN3?snxWCZux5fRT zc8jGZ>s{?0B<_0co*?d3+PzrZf7k9BaX+Ws*U^kD(dTJji-c5Y_oa~Ax?j5|i~An! z{*AbA*X{;!kJIk1EP|{8?Y>gnxwr|Z$$tKxgC{cD{TuDiT~dkcWt7h)N=xEXYqK2~ zrM*}BzCZVId<3DbB)&(ruN0p(_8dTgL?0k;W1bRQy^WM1(A>L#u5~06ZSZy#?M48N zjx&lKT^jS!9PtSVsCnt}4)5#njzmXio*DI;>e+&l#H#&UB9W}HKfz>Cg?GQr%pX`u`1^@C>#?>eJ&0pVbeMx%I_X z6??M|-l~IlN$@-gZX#IkM~-etJoY9{*qB)Lu-zDI`)51r=AkqV<9oghX&bXi2Mmh*5OCt*)!?Ro$DeyMU}fLum^r zAgJpFFMtY9j0oO{ zJ!;C9h(A)?;{Fp3YVWClzL)g!ucqvAi4Sj`jDX28p{DG4mHa9Oz`c^*s9!}Yd^Oq! z=#G{2HSdtfm@wVf5-vv$LszOHuug|gv_sEed|Zv&I!nWI-sGgbi`3#ii9qM%rdIc% zdJPB&iIsJeq_d<5bWL%~zgG7L*-6^|P7*yH%RU!(P$z!}xBMgLX4~27ezqeg4}@uS zE?^F`3!5b9MCXs$_9nUFWip59jHx=>FVUMN`o~0P))VHyofIC7d1uInW*^5VK)q9+{4uTr#HFMlttT9Qa z)DV!nTR(tUh-)Rfw`zSK0UD*m8@Gd3)#uXCCoM|X@8J0FetZ&sK7 zquQwCh8{V4%^Ju#Csw6qoEAOMHGEPz2b_`F47DzRM|BOoJq>d`&MTT~+sY|(W{$Wn zl+sIT+eY&ZpIzG~bS`qXls?LQzjj;W**qn;Hb1&QpNl}R*KSMWH(yV^Slf0L31|E~ z_4nFO(^x7>Jz?%YRURoXlLEqZsb7JOEv(XD<8t-!ZsoJg$t1NVthWbfJ3g}ByF~e# zG(f%eH2V~x&Q~rW(Xz6o^c2P^b^I`V%p9KW#m_-vt3SHG$cV}qHV@W*dKh4$2fG;e zT~0u?|FvQ#BO}N-$JXV~l&#B}vMP#T*-8VlKf2XvEb&SeVm#$OWc1*y`bKo%jRPAE0qTYEr8C-zua z29{BmqyM^?_czlqr@zUl+f7uo>?agLh6pKwJWD-{7d3edIp8bj;VyYax#w31VtA^` zH$c6{DX!w6Desrg^+8YMx+>B+Z=_qU1t>O%{m?@7&>FJ=Jb;9K^! zOv%^RsbLXtCNIES(wKz5kRI>9xWthZu?=Hpv{Tum!Zpk(DyPNL$z@$g!Q%qQ;@K+? zk1>Sm^6<2}zy4c^TBeix2&Jt2J91=n@B+Y+ucL?aW)$cV^3CnMRO(!%dR339JE(i1 ztB7I6n0l2`u;)ttmvLbkrgWWg-wi<2;(m$%NAhyq`RkJRQ%Uu!E=V|ijQ%W^=jrt% zn%fz?4=&kT-zZOBCU$s8P*t)v%FC6HCKB87^S_R+b>ZVZw7vDabeg>Uua7LNeplGX z+EmP2oQ8K*px=43Krn|2jXZi=OMvjDTel4J2Xc zLit}|ycUV@tKlW-v--{R%1ZVgIsSt2$K;4Ih)#o=vzzE1WAUUR6B-^FtRk@1JQXOg zxij}In7XTOBY}&FIEupY58)&DK7%hxq3$>W}}`Cj>vbfg-+ADG&8B?vq*JkG@d^K@l3lnLAp9%=wcg>$XvpZ?38? z{o1JON&tg@Ji9~&|GR8D8T=RHTjmCn)&`dN+QXwrH0x%m>SGRh&2Op`tGcL_#541R z+8sj86JO;>-OD!uxbds+jRmjb@Yk*uO}_T}0;SuGx@U=?!jIUxQem~Oa2vj5CrgD_ zstVO&Gob@`S#*p#C+(D41aq~AW&Ma;k|{jemLCpMZoMwIi!S$BDYw6r>sIAnEe+`^ zWz-%PEY9kl`~wh{G(xlKD2b>xD&90VC6XRg-}g2;!#U_`#D;$PvP`v9L$`s^jUf8n zhQc23WYx^`U@Sj4;(oRAM9`U*Hv?r|%HH+A(xRFyf(M#B6VV4azU3!?Hj$LpEjs$J z3LiR2M_&r`l?xhwngWDPe+R!Y1tnndZUhhO-H|~qZ1M>(rxP{9lcIRKdGZdP_^tBiGGM^ zc>DxnTsK{p`8FY|6#rKHdmQ|^_}{kuCm}l#zkEB^`w5~_<-PtTS<9iYm$?Bv=ANSb zEF#tT>7eK#R`$Dbn;%5CAC9hLJ%-_d2qT?@BF`mxu2KIa9v0n4Z_aU)?`?L54es*t z=pQ6?0YN4@?cJ{>WqK78eKHP+Y;Bt+5LZxkdBYG7e1v-xQPqLcRYv{ijHPJV@%SC# zbBx6e`S{I^(Vb3n!=|sIJDfrcT+!{$MAFUD9dtY7oR5b)KjP$xRy_7+_OI>_`IUd< zS1bDBMY3ijwtMo|nVV|2%|Fa>_d28QZUP%riiYPUK~mOAn~nM087Y7zTLaVKOy!#& zn0pp>>uUZZKJf=*$$@CPz_@QN!@L}|Sw^bRnm4PL1>kpv{+i(6)R8NK&VA{fpr#5~ zgaOHLBc+e?W*1yT*|`d^AxnbJ z!|5G?{O{w1yJ{!~PM8Cy2S^R@56Z_l{~PrP%Uj#`ZRYAl@RS}wvxgM&)>ae&^SPIo zm+D0U3stcL$85VopNye`)&+Bkllr;n%ZsUP*M0kqwY?IzO@?LGRYfpiEi}O ze4}NJKmuQNF&?TEim3Qcl;^1QSt8|M``CF&jh!8y{0-(ewcBOv#1{%!#*((u!$w^p zr8F#(VP+4agJ44XScAc>sV@kKmW`Ei!v(GGQFaBb?xF2fy`+cfQdQMXPyRmhaP1DM z%KWBuU%1dNUqMo{ZRPn5^lF2vUvd#8`@ye2e+{$8{oEgzV0CjOP!FO-1emS0JCVIO z%(7pKucdZ}T2qJKFTPc^+Z`;!X7^u+FX1;E{ruK$tpNc6(|s$UFwL~hAKg|SFuijK zur7ugCc8^5ip`dGHYPivuGQvGe3=(0ExVFb5pSUM)G0V)sk6A4QQ1 zYY(KLHZ#Vwx)YLvf9mK~0TB_FkK`m9U^I3L}tR^d0((riMbRGSIj($m^=SlRlI{G3V zy--IF!nbU`MAz!*vvl+{9ev$QqFW^TIvwr&ld8K)M^BR6Q)M-&AbQbX;QAAc-RJG^ zpX~1=_V3tbrTL5v94?d(eeZc$tM`V{O#Q@qh2DcNAIa!xlyIJMeiqUmExU6DeINGK zl+_T-y{;DbEF2DNJJ!G0%FhrF55~Qc6gKUOqxHuoSi>2%C2QFUKAJGsTz+(X@(QA} z^gok-$Dbvk7V%hvz!M+(5FhKyQ=lselp5R8(gyFX5{JNzHh8DMP~uq1%ydvoroE^$ zA}d4NQ<#$rNx+F8$t!}fyFH?=Io!H{vCFGdkc+`Y2V=A4ovw%rhsPR7T*%BLuA7P@ zp}Qbci(YE3QY~tie<0v{|91jXI^2DN)dgq~KQ<8}|0IV3ume8Z+n)bu{2cA?;J0{u zswc*ItS6ZTvPx zh^WgOFD(bR%`zBd6C7lp>9KwQpDdz%D6}i6M*UR|f=8)k_<-vwf9Gd zdSdiT@bqmg7kS4xb3Lzihs-yW2o^M9UION*Y#)uHZE~m>G`FedSuu)~0n4DfAXey; zaeID{eZIVanLH=f z6n0~rCVZT_8^+}Pz&eYlDs#VjQqL~Wl=3E6zf_e`&*gUbozkSt_|@}a5@2y-=Wr-C zFvw^v6X0fwcnK=@0r>%QmW=BiQdWFAc7b+V7uey7_zA-zvRkik?eu|k zM%^MZLXP{qWTj>$p) z{gmoNz;}{|m|{5w?txZw%wtxe^1h@TX;#43tr`j1iEyO>-|+$`Q$GKIe1>||r^@G9 z)|+r^8n#!U4*g__VSF(g1u}a^a!IkzEiX#zw(u-fNVV?@*1IiYbuhQuKO!$uXe=Jf z?JocD@i}3)qBV5d`|K~srm*(*->ATJpCQFWn{tz%NUbX+@C7I^EczmmXoSK_8YYVGLmrS>1a*< zv)3yby~Tp`2}~4M&MVH5xyAw!V$$$uH9ryQmKxr^9%S0zPqp7@Z~tZ4?N2^H0VP|K z_enWfbJpdvXQiR1Y}d?`H5hnZGE=sfp0X#%lyliaT}CRV+!Z-xPt^#y zjp5~7HP5K8RW3IgeY13uyy*U1qwa00G?p~V>oj$;V^xJ*f`f;hdl^fn^#bStaJbc_ z&Ed{iW;~BV&mp>e;WQq(vQ8qZd|0zlFEZ(NG-08`<;zS#!@qF6(6)aQ^EK&8(WRm&`ttckU?1GD~vfv>xor(_;A2dQ7C!24(&eadnzt%HtJ-63O{>H za)G#F?%(`Ijd`Q)Uh$i)#uB4?#MoZa-IuB1enR_j51$j13tC($GdIHeN8V0d0yAO+ z<1;A}4sp|aB* z$w5tg#aSIK%LiPL`vkz2q^(70(ZThe!pHgxg(~ZiJP#G5NX#ABU+lgr{{WHOt%V`5 z?j^0!{yd+%mx`Y3?r(of6Ow&EV}tu?QqzG&$Y=T7%woc4vm1;1jgjNjSgqG#8|Vh2 zI+4(PPcDEtCg8nEN6JfEC5@LS#guaU{3>rKE2ngl*3lTwy4)q=ZI2Jue)%53*o-SN z`g8JV^oO}M`cLvrF#1pNU1RjW-Z$Oo{|8?UiH!b#^~us{^ncCwEZ-^yLq9p^ES5z8 zW@?gbP1wND;Xn7ZpCP|V(weeYS=$}q;X!k25QCnLgazYuzOC}bzf`_U=@k)us*soD z%K?det>eKYg^sZc9Z~0#LL(l|1_b&h>$yJxme6BH;W%n)Z!c2ivLpP9-Gj3I)n-|r zY(Mxivi*u*RhOj~y7&JQrmxYcm%3LL^JAU%X92dkr7{n>c%Qe4uQsoAv{dG#`Q{=E zD_cbvRyo}~c-@m6>@F)ktoV+V@?-4)?4Vg$RGnyI!JM2IXqcVP*VR()Nw=04IGt`M zR|6bfgh?JR%T$QR>g1`iAs5LDZQU-a-n6QARhpu3Fv&MMH&t&+q!XE+Xu_RwR!7^M zy*6{^omfRxVz_6wwUQy$;w}b6C#*jcB6I!v98L~weuVvjvMtLvbeJ_wpb_hc5 z=0R#|=Fs~3TZQOgB151&p=NfWGt#|gc7ZcuKwQ0=F1ufOj-6XU5Bhgeo zq?)o4!M(%!#~&5{t_)$KK+ZMQJYTMstaG__yfYr~>=!e~o|xJJ(2_r`DGLibzM?e&HI|5aV%sq4a=OhuVm z5XoC9?!ND0e?+Kr6LdfPGeedgZ(#ukcl&=D0QA<*5r0=izA=D z8|}r^?HD)hk#=?BTf~=_)c09;+Ie_Z+aq|A0%f~1p9w>U$fJXq4nf6SI)v5dMmnU5 z8Wl2sta?WtFHgIT1yvFizmdmJT0Pcv6rQo{^*p&*y%@L^IY^X?{P~T>lCku_Om|{O zQT~R+S4IAX$JJ~nWHaX|^vQf@AYL`x6EHU>c6-WecG4~9`4d)AWy5$U=A%aEFf`#N zmy|7ehRIrBiQ!Ylq33FLb8K!XKF=Eh{YX3n^$-4DVTzGqqy9$(RGE7CRWVk<#(wXN z^JV--Mh2seKPZMv?gw`4XJ}&h9GCMO=9jqv%a^5lW_?*5J>cvmDnL>_O<^wa7`ZLy zNZvw|J2vIeqqV=tqDK=UxT5L^HM={vokaGNka*eeNNN4ZD}CTLz5;Wmdl5k~_u*Zv zK<*mcba!cy&}*YkXA<+rh>41=1q4U;v%68tzdUYE-Pc}`$1P(H>c__~NSkj)w|0uQ zb((Ryndpx_Y(+0)$TLuLJL>=Oyb2Qel&Rc<*Ko4=yI|}D9tvqwlV9kdo=z+QE6~QU zWk@u}VZFs+6g=a1PumMWqYQtmm6GsS*@uKH{^mIeNBgB%i(fue(KCyT#oZqwiLuxl z%}ia4yNRYq~II8(O~ck$!I3EyXK zXiKNAAmnNlqOeEsH!Pdj$cdNTMR4jJY{Gc(yd<6ztnLCGW9+B|9sAvQ*+oPq1BFtj+!xOfbdg5} z&9_44cWSeV-KTe{M(y}E;Ghx16fBH1`j$SL*kkEw;^_Y#Q%@Fq=FfqVRmS<&xcJ;Y zJ%skb1{7Icp&~4bLek(DD_#Cro>?hFdi7JXK2{dQ+>3FUm3i?BkDkJnaNd<&UVO2o zvM5(7WXA}XN{v~GGE#sX1PRNOISA|BkQ&b;4d?KGl06+Wls#m451@V@vY$7HOM zm$+o#+5H*3?Yyv2_ZmrKokw`<>{JtVs=KpOh5OWw$ai!~%kFiotCqnJr*&6m_jpgu zoGvd$X4T9wUX0vXGp8swGOcz_SC6ApO~g~Owq{QEr`oFvR}({p64OY`w;d9NbE^{- zgXpb_Q{|_({PaL=`xBOs9=LmYtZ#T#Bvr)8!P;=VgMNa%uYabIr;NR+n-i>;dsrj) z!^Sgg_F13&MlJhl1R|=7o;Yn;m z?6N0+gRwZ^%VE_rmUQ#wuX+_aEJXEUsvl?W5luC@+8Y!p;8)i5r~oFfMx>>U5`E9} zCrOcqk)ebP)@t^6nLd4yg6Qx0mVC+2o(^wp19PIEcvV`-6EKj5&emk<{=poZ8HCt1Y;9n7{(Tf_(7I(gPUkBLi3&RFbjXzDRL%=8j*fWvbPE=@T|h zYjsb|INA5&Og;m{cQn0;mz7G?+e8UHk@Fh%zM36A4se8DKva>7{&7Rloh?P+-T_M# zfZO*ETFUe4z~F($)iH%www3k?BdT_G!iy$vBSav`rf08`AsOzZ>pzm7*(XQwvKxQu zMAI2t&RDXrdh*r{*b>_(yTC#aYX!6N>F5hd#NCbA@~MmEWu_mD|e^s@;qHx_>nuLYBz*e+|#md8pQuPz{C@(F&Z z_3)aJIYv}GOrJwcfPvU)oTvD~$A2mFXf;zSmoY_qg=RJonE1TNpV(PM;`J0cn<5pV z44LnZGq)Yp+#l1kt?qKt01ab+pPGY^zQ=GJ4cvJGTs;w(EkXWmeN5iebgJ+_tQO*5 z@aj;j`@2WmN7&aHXS^(jyw;U;qwE+)G7uzgQO)eUy6`}mF%Ls3Wd_2+%7k!R)1H%n zPpqkYCBaELZ-mFsvgy4#LFyPU=AMwbKZHzWRu|x^RB$EpfGbqHU-i2LpRa>=Lllg~ z;C{LjNhbES6Z31@T(f%f4kC$epq;$w{9w@8mfnW6`dl)l0wbN_(veu)B;W)IV9u{0 z@x{7Cd6J2kV`THdbWpj*9$IJmCm{oo-v2rA3d>2D+bqF+OYHuATEzxVjt#$SeC z=vb~e-%{qI(jk3^Am(25i11W7k<)megf}auc>hcQ&$)Tu{glbFpq5eI>b{XM`Ns)Y zqnaNcqwZ(;8R6Y8Q|T{*FX!d-JR??1xLp?SUJUd;PB}B~Xmy`rmjQcHoN+=oaa#9F zuhF3+Aea)D>Cc_ks@$Xc^C^aw^yg3cGF+{TbXNM4s~n5e__+#liSON?Qu0|uhspPv%i>K;Q{`A6FV8E3rg5}cMYRY%)Ki47S7g#LB3Z#(EcV!ZzS7rK3~@Rj!6 z>B5iPSK8;6@~$C(7U7-wpla?NC@HD-{R05T#c!~iGy7DY3eJhSUwRmPwsF=C3|NU` zPX38>ii`e@KpZdo6Dch9Kg+ztClN&4oS$yHF4}7hrg9 zAQZdA6N*JxhFYylB||JP6dQ;9&y$PQgN)lHz46@xnzlj_J=SY1S)tgdQ0yG*Ayz55 zo$Q$1uhs1U5)dN8iey4KPbMUFB6BtCAhgx}-a{JQ9qBd`qAdB%d0Ozc`-mLLY63fU zSBn-2Y3Lhl9b*eu#@H*&7}gCiqGtvap@SZf-XQ(|6mQGxo)SsY`H;I-j_lmP3_|Mj`nH&2?c&(%Fp=%Su1Mi`y z1YVFY>u{F55d6W9cak~YHCQ^v6YhcuP&N{V9Fp+=pK*J{`hDbj%`<9#S?@)59==&r z856sT0_GupR~FNOB4LCBVg#XNW-SGz>VP?{yx}HZ!ZD}k1{!X12O6$H--9Eepc#Z= zB0Y{Gcnm!vVq;MofqIK=`@rjBw8NBr|IrIZ$M|R+ZD$-q#>Qa0TrzUnJUD31!v4~~ zf&ZHS1pj_c(*9fcW1VRRXyrxWIUb&{{TE={`}a;kb2JIh4Mt&~!cL5e0%wPOm;ORG zrjvAy%o{#O^vBWu|D=EMpVA*4|NnqLd%A;v4oGXiTqLtQ-siM3*=CPeeuH>rfA%Pj zno$m;?tU3P@u9bk%M(&2qZNdv9rBsOg&mTJ{dU#}{kgJFzh+82)@oAX7 zg@AN=qb(hX&&lz}?s5^Z+uHkjTRJ{17r#fIwo6-|6F>^~`ge6xDc)8AQ{4mj6i&*QziYxx=WRmBR^Kx7&F! zUb~UHEu52`N0?0ij`dZQLkvE!+v2_7VzL=B_-n>b}FSad#|BF+d-|!xI|4rOq z!UlF?yE}hf=Lv)NJu+9weeMM9ukYdd#xYVw583aXfr_5 z1d9D_5CVsV)7CzAQmZSz?fdYd04zHmpk8|igOqk2X^ z?aSr6ZsscP2}QT}mD4D>ONrGbidBoU6b~&eSG4fmd{uy=`=k&k>! ze*{U!WsOFE4kMT#s`Kqrb*4-;_uSp0Tf(-F#>H}lE5R19o=q;yLWD65PP+uk}jJc1o zTQq{Zs*w|w-bzqd`jRcFZPwTa)o7^Z@WE_KZL%)Mf5iH51pT`SE<9xZBcxb%>xM-_ zGxdgCz2(AsIH8Ken91^t%%du{Rh>Ter)hFdqO|Pvr%0BAwN>V=zH0*J^>ST0?4uW^ zpi3~7cQLmrjXZd6Gz_q_57!R#Tsz`3>O<08vg8!nsPP0!_1`8b-Cc(yN^#VcvreNYzdg5cN53LEp!-9YK;Z&9ReN}9T zFXag#s-^N`LGqbYb%E(RC?G%nKn7%?W93GDZ#2+TXNsp^>NM+Z*mKMwD>?5?9qU7K zJaX)kwe|>+y}!BMDwe9_-iZLeOvq?P174)~CsK_74Hp9v0zxo*k~_LOtI#HaXA2by zLICt*>j_B2(n%DRdI$ZxQNh?b$;&B7;ahJno*>eeC9^TTSZU?UPI>^zAlf10C|iz@ znm1O&(HZ)66+1ZeUHg;|X4eyU-${XVR`_`98EGBFq%Y50&^_M1lEBR6 zsBs#_w_<7sv~t(uU)=YgJolbKQeL0uYNWjP?i!Fi{)6%0eo9;~Nn*42TRSL_EX&1T z`rfRq_63r5e$QS%C-6EqMRwUH=XL4uOw7hR!nX;Hq* z5tT_UARxWahC}T6(m~G{GxBHz#;CK~iz$>r!T1%v%D#+iwM zf-d(r^95ZfyTSW7D&nqlrB%U|(kjTEBj{`mCep=LE}$Tj7Y+2ggYilMzlH*;%o{Mq z_LUOTe-$*pu(r{V=%L)Xr;MA*mHKvkR@BTLk{%TChSD2C@zG9}MAtp3(9{-xi_0}A z6rbyIhNiwNgZer0SHuJ7IfG9~oFmo6y4}p+rn2O-Dip75bl7(-kK%9XG9DvHTQd~E z&4T+IHSDx`{h6xGhv%s_hcBhQ1A?Z@$IGn2sr#)Hsod_Q(RL%Bk{l>Qjho6@vF?{I ztRH|#e9qmWsc*}9OiBW#x_m9JTnD}RT0;inj1sTvzjlDj8Rl$W&xOVYqlb%TdRXd` z$Knei=8taOQ*GSg9==}WMv0(#K;&!R8g~>_8)3w}!@I3apG~cobS}W z9PP8?a6B)6qgK`_lV zjt!ALN6UBqGd>Tz{-5yaJp!NFm%*p@W$>we8GLGA2A|rO!Ke0R@Tq+nd}?0?pW2tf zr}ky=seKuIYF`GQ+Lytn_GR$t{Wth55PW+7Ek56q`5!%8JhKzS^EvUzzH;lKTz`jFB6uLYOyX&H2mPbz7iHSND%1Y=aSSU`Sa^?IP0GvZj-VjC zn(zC93R)fhP(|ZeZ^yRi*zm{IM(SNjg%zjN#!M=~k5t!zAEW*!vdaZWr5Z=V9cIyI zp4@o(*^&8zqnErjZ3SZ9Vq|eRr?94>lZ~}S zWf_uo<-du`l=c7BcV8B40%tUx6S=N~sSC2IZCM~=OmP%`xnb!!vOjZ24hp+Q4vgf% z3OHb?wBo>7b&B)rEv&$k?FB^MTq+%vDoFa^Z6~D z=}K_D&ixJQR!xg)=ewp~f5*)5)wQE0RZgB1o?ScY{Lpy6QMXabT6%rxwi~ann0|M# zw3AWSL{ROhaiKuSsDnV@_J>A~HtOEUxGR>@Vm1ja1XQ=?y{GRUDkG+h)9C)`kyDJt zW3Y6ThuTaIqC0%K`D>C0WhA}Jk-S$GHDTiA6T{cnj+!vBWw=s@BX&tz01`SKCfVTkI#GXt0n@aCMn{Xnl|?=ceL?^RFQaBMjO|bqU7x}o3_D}Y9w$l(y9jEgW8m`tD4 zs2#bjV>on}9lXX4{yp%L+Ghv9YzIH3gAF_QNjn&RRZ{;D)@4UkaCkmJyX>IpI%pL6Yu9J<<7Gd1^jU$TslOZm~duQwEOq z6xXhfV4*J^`xj1hX8Yyw6}Dpo-xaz7J_Ek#>YXg>%XtVy;guhdEta_jg|!tkG4UKL z`}Q9^-`24n8U5UAW$)XcO|<-!D|waNgSw`;SlmT&$FbNSJ=}GvNSQ=VgWh*l3){_G z{pM;^L6PKily`o76!li_@&sV+1pSxWUyG;GbF5`s@vd_wV~*t zPR1jN=+^oEeS!N%ikaBI3}gviH98(H$vwYe(tsjlFXKu-pYc1uxYi-C$c{K(=A<=< z4-j}ElM}7e@9&}OqfJF3V(`TMd!lV%uf=%q1n7`P$@`Kb=FR~Df-B@<)0KdFc836> z$(lTuX`Y3jBk^s%BYQ?veci9Ub2P?(Lh(ph9ykn^{M<8+pIS9TFn(q&N!!n3!T06t zfd3P|qlYxQML^@>F&?me8)jLMjcgWj)q!t+d`K5$^6Wm*8%*qWVQZ)N>G7X9&3786 z3>a*-M0XexbXvodk%KYIiS{=y@3m@#*DHj-A_#AaPdYBQVM<{U&sSEJCT2W;6uKY2 z(}`4TZx+7mK@^H++4we_jR$+Tqx%*TfT*9o{qNA7{E0$$R(te)^nFSvIUPQ!%KY|- z_R8Vyb#qi#bDw!*gh%l9X)%5kp}c3L1Q3__l?Xp5q$cJrvOz$fx111kIDZ@PIC!54 zP0{z*-0pu%K)eU?zGe16F@}@wi^`nkMO$9@v^RN+&KW)jl}@f8tcvbGbygX{Km7tZ z`QTI2^F^}gGVb$JGEyL7UQmmCVInzH1*sgJ2`^EC*g_ua7<$`uIT%JcZ$9mZ7ibxX z2%dMp!V_u_I?5?%!E-W-TE`S#C*PV2eb~ag(y>x})(h}B7>}o6=PJM%%DQ1j{gkt% zxS=Og{4z zf5_zb*Zfd~;I_!PuR4b?j*MQd_E4zttAr7iJCH9qp-Ucr?CRq9obyHQyVv^u4{hna ztC0)JvdW3iE6!v$ky*yQTQ;aBjHP;op)08;7>f{979z~L9DnV>oEnf+2jN0;OAUlL zC8R!js-!Oa$L+`|kUMonzSq}!VhDk>0hO6OR&1+WZQ9K?YQFm!lF9cz`+JA|z0CfO zvcIR>U&H?HyA3s~8J~#hqh@(*x1M)h9LYht?jMs#>h7-OD^h>Y?D{)Xf6_(LXwz_o z3)aBnz=qi@BHCkVj5^1A`}cBA*y@juaf*P&{Uy74sVqJ3i~vT2n{&pQUkQJy694YS zw)D$`Mh=%HF|@}NAW*#8KZW*}Z?cG`rg`m3nwWhVl5xdy{k z)VttdkLaU|073ew?r9JVv{dzpb*qA_MV6Mj1%&GZ%+rp9_A*S(*wFq6X#JdQSDCwX z(t|H_z}hg5x4@hIn1tj-xUE^hGDUNFTL)05yva1{t40XE@%WM{s?|d(xe7}oG6FM0 zivw@#Ns#e;d3cVjRK?Mz^W;2HApZ;DtO)Xu>yI@k(+Pp{RVWPq>I;FnHDrENzhxd! zr!>@ubkfRy19da_<%z`DnJ;Y=dQYt-TjYjYsn8T=;|sUSP!_S|Lw9L$Xn#BAL1I{G zJv2zAIAGmDij?;iCyhdG8hIDs<&E{4AAGaMCXm&8{mUnlSSA^B<( z7Vv=d<45Bnqr0F?}FDj0!{Wa$eGU}hF zG!St8ZIBWmqvU;7FOv9|SK{Mrq<+as_!f?Ki}v$fq#jAGUlGR2!ZohFHS^Ei_4bk?zA8b8F#sPUmcRk3HjCb1VB&j99}8j^83 z$cEtlhTz!j;%Mtxh(;MSk3O#khwkjjczA6xK9A#hYb+jKxQ!lk8TVd7Ed&>;A!S`F z$(r#OtPu8|2lPfUN}>nd;UWTyMEAlvlMo)hm8m@y$-kPdZNF88@ zh+)QBa{-50V`J|-(5rDYgmA8LY~`i09Am+rz6voYDOh6_{Ql(=sYdwzm{ce8FGrPx zt?0CC#@#3rt&kA`iV6V3zx+ZxMCH%83N50Lxhp=+y<)gdU`kc-Ie9CB%1@hT5fY!) zX~i8XK=dMRASBx4SuxX20=cm+B5Xxi2Yg~x-~*Gui$Q{N4KE$X`V9>CN;gSN-Dx_e z%ZkG~=2jiUrO84ab4&*Aiz$#iZlms-69x8`ZYxCapB!(`x%n=cTthprA?!^%ESEMD zwy#x<+~Sdp&3_QZnU3!!>{TzX09v(MdWIqyriVw+8|B?fD~gP|J>=!~ovdQJlk+7$ z*5|7mkH~ei&b1~h*D>^1d#;emZ9J&h@a)C2y>6EQK|yD^pnw1nF`OKbh>T za=U+$m77`neIJ3;J4tefx|IgWc&f^%2*K{;I}#u36UfTNs933Txlhc3v@jdeXLPPE zN9HnhUDj~w@@uSAWaqkB=X$UD2&_!hb^S$h*|-$T?p#7#tI7 z3H`q@3$|WIz_#Rs4%o!zhNAz332fPL6%zMf!SzKK8?J3Q+Tp61o`o~kjNcCPz$`v3 zGb%o`xjGBHpOCTxbv?7d`=P4_&n4i=Z3AA4i1(R7Np!gTlss7M4m?)LME`Hr(cu|* zOS0j8^9~zc)-qX2*}i{!u7F%~tOEI%Y>-@cMyBt?Tp4tq-;k^{rD{KuC~D&Zi7cRK1wm!{UUJe&1VC?{plkBulOGTAB%lr_-6pV~Oto zeC91exLS1xoC>c|sSwdkFd80%4wGno$9^8cp8CB;{Z3H7<)Xt=E*p@A z?{F#v_YC`e5*?~WNj2pl3zBE77a(MyM}(D~K&ag1oFL(Km#J_x4rG%#)Q*}Y`+@}{ zRTS?pSaAUeJ*4QtycuW5?+y0VKWZFXWDw@DKf<8vum)P$0^fpzRdim@W_=g zq^kS#j7N|@dC@nE9y-mq|4}k~HhI=)raV)wpNCsYw)o>C`;z<0Cq^+jOpBY3q2CW~(%#@vP5bGNj;6Ku&F%kC zGL3LKIx7SI0P9UyfTW0<3&)8j{(Bca6BL@<;3}{&?_BJN{3pX|4ij67F#KG zGiB$1;J0V6wOO8`h%e81N~K!)1ie!?K!ljcO(HuPi(-tx2*hUgj!i38^aBEJzcOFe@7J}R$C7evJNnc<~2K{X~uq4<4-NG*0M93+J;NVj4h#%GjlMs?G} zVE>p75+!=$6b>qC=DNzEY>gyLH;Wva7RjY1MD<0|I=1vZqpbzW z&Ug^;DMCY;!zq*DR1}+*S%L`s-St8pSFnDI@QHP~ z`&KGpjJGe_SX*WU42Q5+k=_~*`x?n}j3eq@_4vQ2chJ%Go_J)v#y{6PM%Vke>>jnO zihAp_>dm9xj1Or}t4zzGLNTbC+tOQrKmA%#1w_mqFN zv^0>vhr5{l!Xv98m(L9r6lMexLc%K(1W;yFmAQocN{9??|2=MdVcLUS(;g3nLbDEApD_xOCMgsK z7C%bgG*$bTJBt0UO%zC3hN7K-KnaGD4lIsC^B6;{=1>H)#rl;L5R~e&!o?W>LWvke zM5T$6;7;pF)<@P@We8>s!Hm1u6~!{FltHT{*C{SSl#$JwL7L^E$wFT~vJPLP8sF<9 z)p*+Y3=}E(Hc;7=aS&i5OtJ~%Nzw@67ByYW0S@Nh^?rnVfN`t>L+g)g==MU{<0A($ z9+v!+avEHNn3_Qn3ij{R6A74>SVXm~pNsPMG*JyZdx zf>uP3-;QE86rvP1DVI)e-=w6i&LrvBq`V-@%EB>98hRXV*+V_bSBzSXGk@>{j_lO0 z_c_DgCJ%L%tmSlm@=ldT_M`5(a+yOjOIago=4&!?sfU<@# z12Y^B!az~0_oVJ5gYZbR?2;$o7wB)q&vfDtYZ4&>b2A}upQh05$%GXW=Fh-`zl(Ls zTAR(WYyH;5!t>{_uhy%K|4h|FEH2g?0@g|ItZH^c>sb)mrS>bF5S(R;L6{s7q^*Lh zA?LEcZ1@zs+l*1#x@0}tG@n>qu7bg(?2GM{BRrkXkTdw`ek7E)2uX{!bV*$$>geto z;j1qtti6=JuWPa-D|#6b3OZPh@QMEA)2WVZQc&GV#Hm8zZM#dM%Msc*k_F<7wjlnN zXHPk(sFngI$;FELA@C^*GOuHWTqTmW6ay{V@_iIh3!j+{s+jvzpq^l@nIcq!El2W~ z1kzW@R+dPqNBH22sZ4Wi+aH2X-A5A5nzWP;4m5n zsKB|ta;s&ve(P=+A<~9`y7Wt0eXpv(+I=PM{hqbR`Wcy%DO|S9CwU9TT5J%E4iJ6~ zn`@t{d@6~RbjbZxQ9F!L60l;oZ(UAVBxBC*nw?f1!%2D~Uu+2`pQQ+Wu&I|Ixfc^2 zKF-_$5SlOGJnKO<6SysEp*KF`jQAXTZ}KxDWXsW$;K+##%GAWn@+x_^q^bxTXMTt4 z{P-MpT(Y6Lo=ntFO!!p2EULlaB%NHi=*bzUf{D57;6NkgX^)T*9$k~eD2SZxUp|$1 zIB%o=Beho?k2hX%Se3=zN^c-xL*=YJ;;Lp1ggm`z9=JkPg+UQWtH8$K-B`_=$I85EvXIj3e(eFoHkJK78kcB5#qP1U zq+=gYYh3%_`#qYF`j}YlE#zSqdyz-mM`oF(t)Im^cA#QuTPTx^{|RdRTc1;^+J)Y$ zqS<|gZ?KQYLJHK@B#NAbv9W=dHPt8DNvXX`jLIoKgvuP4|Z zAIvlA9+cT0pU0ye+|086s)D(dc;>plu&gdPtYl5|id6%wOM#x1fvYdKf@;Q|2X^^U zm{zsXc|3(d$0Fs}JBBFG_jaD=V(#=9ac3S0R zk=r@4hM_w0LG)n0vEX?~0L}E#$|)2(mw6!Jb&GU(Kfe6GR0d_A>qNE({_fWuOyx+<=V&PFe zhW}GghaYPj(n}G#10Pl!rE_i+U$mtM9$=N*XMZDi^2byf=>N6f+`tVqkaaD{8WDt1 z^b=vO<-XY(v?m8+V?^1}+lCIYJ#1U8@1T%kX|KC|RQ=gFeTe;q^~Plk+xpMsNBW7%U3ceLj9?5|P_owC zCl4GOb<61|Tu|NnwF^S?oOWSU>gTvnNQ)+1ye&6lJqiVIK*ckba~D}EQO{oo*f$SI z{(_XKWz1$U?z7GS6#w!`(!KSci8ckJ>>((npK0!L%rg9gS zTX1ueGE#yBCZ{U8`k88(%!ah}J5!UvdW#PCzjmQ?ksP2W-@|&5KiXW#h}8u19#SU7 zfU3}mP=6V(cb}B(nh9{OPIb~Tt67X?i`4Kvg>}eH_gY?oOT-o*5|OGnqMWsoRto+X z<@`~XBT~*sXg%OaA&(Pk{gz3^rZT}wlZ+BzZwFX8AMn`g&<>j)%`g=EtXkk;{Td_e zX}R^z-)X2?TG@|Owl7XoR3fce4*ujG+3rl`cb{mTsVXKkRbZW@+ydSUZ&DW1Q7dKr zHH1>uY9i6uxv-Cij@%XIF6NaYcsOJoBCY7E#fLsXIu^S|n5+QT-R>nvN=SA2-<;Mg z*2qfpjzU!Oe4-(GmvpkM#v-y0MYr*PI7&%vCS>5Bbkbk|$AF&Xbqp^(gc$56 zkX2cB)FH`AA~S?a=KAj#66y*oDhY}o=6&4#Zj>Zj5<3v=Skvy4gB`UC-)mi^JbJ1U zccJpi^N9T-OGqP43KL1_d=PX2VremS#D$xUiTf2P&Cc{b_#LqZyO+n=|t+3XtQgDA9N^P zk4j3>L;iF0oOqful^aducFaLUm=4EVJ9%+%ymm z@<#+ADkwIh??aIosdG9#)|Nnj_Bb*ej~7tLGU<* z!?l!tG%huqLapf*I2YJ6`i6k1i3e zu^`M|dH%_Im@iO4g)=G%!m<*qEY>owHe?3g@T7R7r?NXwEXcK@2W6d_O_`db ziF}s45qKoxR6HUtewA&?)2Bms>Y@GJbu%bwhr}uP?Z6D9HHr z71s@&Gk$%^bwgpsudlgo@Miq_qU(k(8Na^jy1~f!voE`*pbuD2U|bCOt%zv9W>i;U z(X_u{E9hKRGhA-J=5YIURWQ9avM2c_2^40xhB9|CfAkQ{9(OS}v*qV|s_j4Xn?=e$ z^Z;M3B>tbjh^ZSg?Kd1)4ajbUu{h_I{E^RwUB3Bd(@O<42jxcQdkr~uqqeFOA7$~r zZ5*K1H*)ARb1Wnlq3oy06{6{lV4<76>-=0MJ}ggiD-LE`atL!m&5@G5sRHFtoRe^y zjY3^#S1DCZ)B8OZ9L6HiCUl>59ii2jD@pZSfvNLsE;^`U8iy&p*qIOh z8mk$w%p4qH4%uw7-nc+bUxagmWe#7sM&>ZnH(Ue@EoUTGk|X&rO`ssnfRDAyFyBiq zpb)hN?g0YUKnORBy{v)L380Y$8NM!g&?2d97xr0iQYRPZeV)+NFsx(T+n;rF857%K zZ3JsnYW+%ssWuSF-qeyDN`553T;f%C%y&FsPswlo^^{b%iL<7p_IFH4?eCb9+TSrH zwZCIZYJbO+)c%essr?;OQu{lmr1p1AN$u~LlG@)fCAGg}N@{<{l+^x?DVcR&TBc-( zrLV3xT~Wo!n#{#-)LfLC(>WZc*>mwADAzb;GLF|5qyHFZSjk1gwQmJyrtOC^avRog3a*ZN@yV<| zCjbLjXSL?l(dTT6C{t%w4^jyL>c{$V!B#5$6-=7E**#bv_ z*z7ZK=>gMPY{vBp)+PJkrSN)=%Zz3`>aB80H55Y^QYg4Y{A{LzA<1_TG4|=h#dE-#t6~`o9EG? z5?*()ghyM4Yh*HNlDobXBi4=|vx%L--@W`j#9tX3#4Gr_o4=Q7O^7lA@ne^+k+?lZK?>gpy{N24Rot{GPit+8c`1_hG zIxfE5`8$z6krEU#>Q3ZO-0OKdc{8i#7XHM2fJru)c4#4q3f>CZs3NAB+^`*-@a zN2Bhi^thiFU$vpPxr2GiA&OPDezgfl4P$MMQt)_dd&1(RZ|ICtHa8>hHGZ{mW~Y6d zPkPrJd9ObXMe0L%@`=YP4%p*#jFO#ja+S6U z2@A#Md8}L%`oT{9NzcxqJ7L z#4?iy^Hq*w6rG)D@~I3eLV+HpqUd%5A0hZ3qI(ut#mpADy( zoJEw&G#^Y#OxL|?&_1JTjnLsDx%v+4X)KxRo57~hKr^dxyUVk#X5H3?OEKs@Z!{0F z1g9oTwp7c%j{DZeijgN;JNyg`^s?NdmsOfV*cGo}3{>QW;#Ixf(Sru(HZv!gt5Q6d zGTx0gm%3}bOzQNR5UnKl%+dw#|`xZF`hS1$?)enk^$Sb1G~c2|Ea@Y=}0NtPINBRSnK$^7O<>-2Kj zIkZ8bE1UBZ^uwlIXvi5eRtQB@gQo$dZ-F&l(TS@l4Y#@-sZlM?NId8?SG5GXgOv$6 z8XLh}+wZddZrh({V~51i#!eg$($;IN$uCMu?=87 zUO{mnh@oMB^A=)MQosTv2|7JqfmV~-;f+`1+er%SZ)f{kXn(!-w~PAf=`xv7D0W4Q z*=dc>1;i#UhxF!UY|MlwcmzufRw@&H6J))H{R7>&3I&fD`*^ba4#sxedoocvQ6TpO zC2aEfaaTXN>G;+t3DbHX@2fdI#m5GpwK%K|-C?)u1M3x1aqX_Jn851mR8mR$N0Q0x zw$Awj%a6HQ$l6d+$|+R+eH12l0_m)7zWDjPfrTMi3iXtJZGIgoO(%fg!()2DUAtWb zPx14ex?6&L1+VARZ8ErRe{|g$=9}ias@TwHcqD2>z!x;4zn~Hk$jm^780jnr;@knR z#wq|Jg+RV#Zjz1)#IJKACY@IqG`smK&D~$74r9ib*oN|(Z^JW$1LigX zKpl_iWE_++C~2LaTlBfHI$sT)rPEaTkYi2qxn;!BLvtlXo(w?=?IfYR^X7+N!@_NM zH7&2P{`foL2daGe4S_ytsEVhceXxqJvprk|h(golQ5I=K5~A(Yl-y$dHYH7>PgBrBQr@~jbZUn2zbBeF4G*eTY&A-)6J4Tu&IgXV$MRfcOx^6bvk?h@t=t%o|r~%`TuI43V zaGa*aRi+P67}JWBbFOdPXYp`Cswgv4_^P=BEQJk~r#9Sh8ZHiAF{6m}dI-W`K?hF` zaM9FS-zaRnd*Gw(@^M*ZBgmn|-ngvC9apxStT`iO`78Sx)lV1*#}N5=U3`|ICCdvN zL?5x9H;|vw-+V-u&Kh1LA@M%dZWM~<^h~!h_~2ttzeD)b_&s6@`GnhXyRR$}87v6b zDzSNzz+FXPY^=}pj=_N*TdVceZE%;}2jh(|EJt#uWd;5f)B@4w-{0jY+IFmQpLl~) zHv#tx^BJv5JFwLCm{H&JSdnAw1rpND8jIL@0O$NX)WS0t3D{~N+>+iFE88%*#DUe4 zz1H1SDyIzlqiy9zz32c(8yka9RKUA4W>Lhb81wq?4eBNk)S9zf$iEo1v>yMn96+M}_nBw_?uvCEPj+l?Jor;5EY_&_f*WaTbpP;K zr-1*fN>p#OLi5oIx;H3F2?T$17TdanG&=5WeUN>_-?aN2l51JbNaPrNGR793}jEOjl8%Oz?uj?*Lr6DQu2#epe5Z(nhUy@TH3 z7=ojhIL^p8PR=;wb(@|NCF1rXDNt^H7&z#%1Q8g*f2b7jI9%)o5(r&1NJ532&sGt; zG7pCdp)xB$LieAfO_c z#1h9?yJ+{S)vDdx>b|guf~a+E>#nF(XT-V}(dy*;|IfY8%p^klwr~6WzV~}O$-Vd7 zeLv^ibC+kG_IM{;3y)B;a|S+av;9Zi2il$Axbz6AVvlMr^?Ful+=m$$Lg#Y){b&t3 z=%MbNIEf7|u)h_Lpzqb5~jw}G({qw$5Bbq1ozd^=PRpxQ{gY!YP9%QwWPmpTz2-|I9KN5ELHZH_b z#h%TG7fSwoy83>50Jh!9AHcQ={&>K};UCw%6UW`qENhXj>jOCVB|n1z&YpP)jL!|+ z3JZTg64fVW8Cy3IEsUQ9t>>qtsJkQMn8)-B5ss{UmjnjTVFAq+u-XEaSwN))lvzNb z1)yb7<@51Gdicc_b?UDWTN|)G1}i8zUTSIp6L@|yobFbQRsvd%j|1Wj^ziivq|WaZ zbw9*&*cV-mMhD-Ig+;P|A5i|bX~+OOR(K-gaO6~sy%cO#;gI`I9`!*5ieyWCD?j8O zI}z}H_&iiyoyJ=P!q2VL)!W`;oIS{@O8^8a`5V9t&k;Uub-mK5VFFxZ#G;b z4!{v>rf?p>dOubj+*$XX3?k)4kWQKwzzk$XX54eTMwGwNyxH_0!>6 zWw(du9eGnyts2=3u zE{5)3W!(hU7zno#wsLke=G);-aN5d~5t2~&>##=pF@9w* zoQphT?KTr^7{-~ihaVH-4WJ&pcc2Fo`+X^5$yzisQUS26yWrlbnEC2Sk5Iuiun4JK zh+3jvQkTi73odeh2Yzxz{br=dg?3RM8Fm~(9dK{vs|JSin>=c7)t5)icOx0{;FrD% z4?On)Kj&7;^;AV}U@ik9UkXQfJxn3!$SnXv(~m)hc%)+I@j!Ka>D}3L14;syTf_zY z5S;cwM!*vys{v1ARlDz-bQ#J5>nJ&xb>F1z%K8&+{XkjY*H+oG#w7t-w-v#UDO7TD zJ9~MTv3&D`v|&CEM^;AU6^VBm(tiP%J~Xal3JH+9v=Khm%VwK*boWm6(T8EmJ|^-i zV&N`4!>$1)79npMYv0Y3E<;KR+y7A_Jcyk|LD#!sW&8D9gAne};rNudvu81@ylo*0 z!`nK&JuDF9Klp-*>E2cW=e`f8e&)QW74H2<51ajw^K@`SoZmeo-~`@mY-y|JC{hx>O%D&ZO$w|X+Z+N&$c>wl9F8y|vY_P+o=BAx4f8x5-J`&I)RY`0b4 zXJPHzDHq;uLEyfZxviQ6+^QZ@cJ^%NU`G{(gPAz7qVEmz_Bggp>GY54aYqWzm+Zvl z9Mar~J2cP1?0RlPgW-w*neXAw-aBB!_7>T-GOVv7*TF7#9+t9=r9UWALX#?9;5)$M z5RYkI;8ogoTc7%xHwDd2yQ$4F+8m`!%3<)D(>!4Y&wW8I5 zL3T5Og$hQW1ny@ynSl3EH#|%dN+Id$31b?#w-qC4Y0Yi~W@+`Epl}b02zixr%da?b z3lPla?0<*_>6>Rp=*Wb4a2KOzwB){atb5x6guwfUcz(qBjZDe^a+lxUP&8{~-or|%f^lTNgX*h+8hI5U#y=ujl{jl~C3w0su@c*6=t>+Luf!!} zqR^Tq3wamI3siO>(#^CB!jr7V`gWa~SHV-=+m;{@o|x&aW%7OVMz9a638SBbV?zbE zs#yG3k*a1VsuRg#2&qTpBuPAkV1gHCde9Np5~An+kJV}N_Yf#@H(OXTjC_c4vO8aN zpYNhf4Q`sH98>EFNhzruC6eOsBR6bXV&qH`fu`D%==dO^xpx!ev zIKbIl_Ihl^;krgv9CBB0E{D!0lqpp3!bDx*UX|cNl@-=>kHM!b^*LwHY@KNDY{XED z9xPfSc4Y%)xEdjGXb#mfhAzyUz2gxq!Y6r9PlWB1u&izO6Vb?rCTrX+lDj_WnE?E9O}vk%|~(__e{Y~bNC z8y4>!xGow^y5P;S@AJiXywp}Qp6mpdSC>pfFr@evGR7nM)8K(Ywe5!(GWsZI_yY7* z!!PX4k|9yq8^>0RDiCeKd2*T~hc!DPmy2^)2 zaQL+zQ=pveUMqWV~!go$Z=j4Z< z2ED_L3}-J+wjl5Vc)3qm1#!_2Y42NwtNH^Ge2UWuU!)>jZAD;B_c@5>u?!|Zz-p7H zl=fQzUvM)VpsY5!*NBXQ8|J>8u%7omYTcil^NL0;?}Z;mI|zrjKaxdH9Maq6I1FVf zMBMHJbDfvwfM7)US}yPSkn!xj;Uje)s3>+H=>71hlNCP1sQM#fh93vnPy z!x8{}&9ZHW!Lp%QjeYA#rAf0n^1i$h0d-ek)k4|9(MT1>r?IR*(tH!0u4qDCPJv9VvKIJ2Lp#+tcAa zaEp8cB?iOP)#l#(wlLv6SHcB_`5Fro!k4`690>a`Leyzo1EtbuaX$}#J{f{G6dzN3 zxgNbHK1|^=u-J=`N!IuVD#~8D1-@>4cZs7M z=YQt+kGKH138#KW2M$M>`%2QLfP0;U&+-8@Im)^pEo8=;QY~2i*#IIn=t!p_5(45A zrNOijyGzo>B3azkP9`IdLHFueDCS>zuoP!sUr3fCvJG1~ig{=XU&uj2<9Jp>`1dYr z=`_G$U1B*M>-G_Z#2jqi40u&VY@y`B8t9(9g)8k@9a@HyUN=l46%SbKRyY93P9U1D=E z8k!N+Ggb9)Jrq-4V#_0v_rPY=l#JyizkmZ0G1YNi^kDp$?|CDQYG>~j1|ZWk_^dD9 zvdM7vu7M|tf##QDY#X79!C@0w1V0`_S3REl6ATVK-f%~bMgsVrH2O}~0S}gA9q=Y+ z%y74Dt!lvIaX=xwW)eo+iN<&wiKc3Un+30i{W;jjprPsZC+zcEYBJoZEc;Ni2;mq0 zKdPK~n)57_tr5x(wGrxKsP91i80zOxH$vSBwH;~?)YDKeLj4Kq&rtiJ2B3x`t(`FK z*uVI{p?Z-Q)xR^Z9MtLGnf`w#?N3m)6L9|I9H^I}7U6T@??Ux}C_e?I z?e6S)frH^Y|w00Cs2p(s-E)`&RX51CuV;QVKp1 z&%r*(=V0H$bFlJoEg$*{j^0;b*?I7yl8&7xV-F#CTU!Tk{hoA9HRMfS ze`gp!fiP(jL>JGanxW)%NV4D|fWgTHyI?qbcR)v8?eGZSYXaV#yb3UXk)J~g6`T$$ zSM%IAdmq*A+bN%n19vta!cMdYpl7S_6au~tC?fh(k~0w{c;o;!HAZ!RIm-XizEz>* zv2f!Dal0ROkhSaE6|O^j^O%HwbBsLhB5?{>QbmeKPK6W1EHSC#r{R;~qNR$+dMs=> z1ThKZ{;#2tKOK$2zUD~9Jsc2Mt9c^3zk`yhUu55nU*eOpvGXc29;z#MC0~fBM&Flc z$@PG6n+L1CQDbmHufJgX(`0$0WzMpX?|~=^FuoIc0`HPNR0t-o9G4(s?vE>XbEx|r z${h!L28aKtawoGmD4mOxJHDSd*u7o3pNonnkI^a^k*L<`+Ea_ ziVkceaSoq9j+7Pk=ZB|F@ExPbl)@ZNwh{~(mWnLc`8#YlVuMugp>{XR?v~G9y2%m@ zggswF9l=WXC$AZX>8rL^%h19g`zVIFB2teK3FA+F&vO}g(Bs!C9uypU`51nRiMG)g21{B6PEV=Y2Uy0@oWp+mg?m~G^be4R8sNba9 z5#65;I7^;H(QbGs*$4sg+-)0$T9-Twr@SYVjlL%~Kf&JMwo}PxaGXTP&${=F5|=07 zatvJDeS6&9drY`tM-pGEPtIfN!vSOhC<#GGwFko!yGqAn=;0f=Dfl`b&Z_}I9F7*W zqZ;9qH=+akjtkc#gz)zTPaUoJ`^Up;;C1Ns|8m>kZvWSgV~RV=L#J`@KOyPA8h)Ry z{mHAJNXFM1S()$d=y&v^<={GcAzZuXK<3=fk>D(S5|Ou(@eBV@qK*5OgPb?+XYCGe zM5m(;%TZe3@-;BR3z$cLvcXjH@ikj4o3?I8O7}dDu;GdHg^R{n8R1F}y8e;R+f_PTM{JV1jeO-%^fW%X zx^eVJ&Xae17Z|*9?p+?#_M_Ieh+wtj$!;u^J-Aq)D>rnG< z3DNgJco|Bch4aa*TPXR2fL?!L>~{jk@FUEtaQ*|na=dT|zUJ2wy5C)mW2oVifJnep z_ZM7w6h{!&<|n@v#k)KkbIbeQ2Cn!uonMT{C-)rv_A>kFqxw(|?467#0dd5Vum<1F-uxLpy=mNY6*}y0?j<`b9>J8j zK8d(%4torQ>4EUC*j(KYj@gOt=kzD1{uT&aNzO3t6D>!H1!-|cq$OICW0oQGr@9Px z2#QS{vvJ;3Jf`oF9iN}L=%2puR!-jOO)x-G8pLpU#RyKy2P=_ZFo5Ov1&jN) z7?=r=ia9SNeJdcwclHc}Ucj9eXYXkMQPIzCvD(AEyHwf*2E4G4XJA>+(~KMr9f@M~ zA@9}w1a3Gb#RW6(jaPQ>-rK!vZ$XlS*^o;sunD-Eph2+rF@Pl~VoeDm;x1y=p2%%* zN}wm)+-g=w2>`8@{V_SONC?vq6O0fJ6=H{*5T4OMmF2h=Peh`>9h1VW@4mVMo+a&E zL19)Q_uF0#zw*cd2xMLjUxm{w`-)KaUV|egKfD=-0>azpelZXp1}`9KSZ&vQIk0bB z_iMwlo>rea-**@+3ha9%T-161OK;q7LR555?}eCz=)a?UF;sAn&)u{j^+D&2HUGx% zqGj^FX<5&UT_%}=!p`HclXf)u%{>Kw0<#9BkEOPI_Til=>g>w?o%YUS;$hxYVHm)H z?Eu@3eIvTxNGeJFYiRnw9uSU~!R|Snz3do3NzUFE6l8+{zAyUeA2DCI<+I+$oqJ%Q zZ``AZ;|@vsS^GDCZo`m52{;btWAGG|Ft=VJU^m|;=zRx}4%NetQ-e{OI*^IBJte#X zC%$e#5DGmp|FbZR!VkSjd~k{ogYfGJpqhLaAoR)wxDJhL;rYnoa$E}^(fv573uZ9B zPAW@?Um_d|4eX=JJ(K13Y&b9=HS0ME)UWTAr`}VZv*}r)JW&iMJR@TnVt4lwj?DvX zx6WhxUhe*#t^19ru0!d|edG3^6a|P}*g03Zc2;!1@nz(D2{kR0Dvg`<5Qyg~81*l~ z4^=#FB&zuO3sKzYi?Ee953mC}8+9^^yWjZhzUuBrllCn{;2Z|N9f46raEwpzbelkr zDhTcIog2v$0l1XFsPO&p;r>soJuZa<&OG#u8;vrT)sH@&M(@+kORq%kgo+I&>$z`fKjNS1idd&Mx{Qc+~8qAig)b2W0dUJVlvw{yY2532it4>1KUG9!cvl zclryKjzDo!P+T0c1?jS*RCoQxLLji*lxTTCEDQ*ryAv(9#VxUF06`)gcvc{X;lL_m zyLayeVljbLHh)I65*)wzGvbtBI&N&h?3`5+DjZu9Dl-L@+}wO%AXGLgVa7&&LZ`}6 z-LG5o_NmCla3ZnkL8%O*5(V4z1qW(=_&lJC@V%#eF|aIRI|9RDc_4jF_>Z(KqZOH~FNydvCP+5nJzmH<+)!(cgya<^dTu&d|sn*sy>e+x^;?`%c{a z*`GKL#)U?9#Ar z7{X7?-ta~6$k}tinkM$&&QQ?-wH^YW@!zMXOaICSiqq2-XedojBlEW$NL-Ir^IMza zG9(<|!8bd@AO1`Q^lgyq;eAtugt;14a+&4*~oN=EXPAg8wHeN=IZ6bZ_ugI4< zc;ohIbau(qy=C=b`Mf+%vCCG+JK<+gv|T;vOa&zT)$ncvlufo!@@)?$8=VtCYt%A^ z^ipKb;A1;eaTwFo=cNxCVl_gP_dU0u@3U|fvKUBiL~4|XydT~OJ8Rxs4Ge|p_R;|~ zJ&407S+Irk;EfvJ*sO_+sxi3s%@49M$V};vH;1D*c-MHDTAz&xKS=7-U+@XG@GzP# zLaJDqZTq9FRfeN_16U(sr3j83zj*iDZNiEbB36%BAtFGSht;@3M04;ZdrY4!77;7O z(0sEbR6GXfA-Gxy^YI%BRl)@l1B1ArAGvd}_jveD)}z1RQdOKCZz16yBA6^OkaQX3 zD>q8CSHod#zB58EX#au2UV=F46{H|WZ^4NwyAkV=-83W{TZ_DoaI);pYyA|JLEYww z%d6oaOpF-P7uG@a8{cy;7{iqf_Ef(X&PSU=1Z9Tdn-MW|%8E!6%pv$wvGeir|GVu%H51zFAI?w9 z0WE{;59yQe=Me2-BZ@ML5_D9!?rF*>U^|Ak8raavBk|Y=`Eg8i;FkfB6JS$!MdZPW zQ7vCyQr-742_9DmK&2BA<9=h4VN8A5ZO`Zn?>KPc4v50SE?$wG`Vh|YY=dm(C z!t>oJNrZZh|?2C!tnP!!Nw%3Hsor3Fn=o ze+zH8zpvsv1)tEkAHfZRh}j(GMeb*8aN- zQJy}Ct?s{pJX&Ax2Qb2AlA6GX5~XaNQ7&hO{g+F~{(hd_aLZ?c5$1Ij1__iQfq~KI zFlhGy7Nk%LVxSJu#nTBSTh3;plvcB8%#kf3EjQ%NN+;7qd^(sR- zhE$MHHlj+L*^pWHj#1G@!Ep9~#X*IoJRJMqN1JEuzf0=-Kv{qPYDx6|n_*OhdKu-6 z(5bu2`tA?Y19yOn5uq&9FV;|As#Nfafzg*qQ|9r6nKa5K+WRk;z&IWv~ z0PXUK3Wl-`htI(1D(N6;7XuE?o;F||-7b=ZYL^a{LE43(&@KnSZFex^@qiF z|6UrQUS%l9kP0I0B5|Z$o|EwXPr`_`3(LcH*(77Hw^?$OAY~!P!zl1o;-ZbbBdq#f zwi1`dALzUMYN-nw_yj{S1WBwfPZzi-e=^nV@d9GmuIIA=yJL z7IwuTW$BlK&PMM2QmMXP*3^07v1q!%Z7kys-$+K9O-wU%ziQu)a7CvyYfniZ&R(Fg0m;?Mn%%Cmma!vQn{@2!odUyoVGj#8Xv`;M{cb?AE47r5rqi3shS~fe=lRN=VMtdE=V1e`naE(k zl`r}n(N7iqG|>x1FA}{(^m(F}iGGIY6{0T`y;Afl(Q8CsBKk7X&l3G?(N~GSTJ$>6 z8$@puy;<~gL~j+nUGxso{h|j&Un_c-=o>^oPxOtVZxa1N(R)O{Nc1hDUo841qF*Zd zWukvu^zVv(h3MZG{fDCeSoEKYewFAy6a8AzuM_Kp|3LJQME^we{h}Wb{d3X35Irioff+gAN)p{6dWz`7MNbob zgy@HhK1%c>ML$~fV?-Y#`thQV75xO!P0=TaK1uYGM4ux1$)cx=o*{as=-Hy@iat~H ze9`BKeyZrFiC!prk?19&&l9~&bmE%_RsFV=*ikdxy_5+hPuP5{_ zp-Tw8PUz=^o+Gq_5ct%A=2r+&9@YE_As%6DP6i2#+)U_1Le~+RN$AIf783e4AupjV zgf1YokqGR7a%Ilynh(^h|qXKq?pawgkB+3PU!c9RuOuHP&=XRgfLA4LQAQdG6%jg{Pz|9f zLXCvV2yG;E8liqdxrBa9h_A9X|AvrB=pI7H5ZXg%1R-9hiX;(wlh6U|2sZC0^d6xU ztb8JWB6JL)7YI!x^dzBdLc0hR61tDjB0{$kT1n^zLTd>9lu#F;?-JruyOE0tT|sCQ zp=$}PC3GvHRzh6mM(POtj?gkfFA`cv=+A^o2z^0l4xz(9?<1Ln#uGY;&`d&O37t;p zNJ2{p4JYI!6ve}+&Fct#LWo>Lgf1f#B6Ja*NIIc0geDNmBs7K)MJJKN2`wPxAapjN&p!ur4xtYSZ6x#-p%9^$2wh3& zX+pOWdYBL|f=9LzdWz6(g!U5pC875TT}8+SDP!acLZb*>LdYa^A)yRHU4#kj?20Y~;s; z$fZZ{HJpKFY##&v5y~L6kx&_-AR!MS+}6jKB($1Ph|m&3*AS{8bRVH2LVqBX4+v)L zx2flZ9We_4ChLZ>X%&E34TViu$Oa6f0jdNFn3iiyqY-Kz6!4U|vHUFLa46tRqY3JC zC}0c;vjOH=P{(VxE|?TYQEJ3E^-#r7OdIWFtc6+vg>w-+^C3qTK#Jstabwg$6+y9V z=qKarP-j9N0fiPf*f^Ai9Sa44z2Su_g<{#bWc5Q;L19ysCkPB|7Z}T-j)P(vL8uxi zZ2U`@ESTe=SOB(3HdG-Le+-iYH4%#b?7&>8N!rdj%!FD6bpjO2ln3R4VtBSe0n{{Y zXBlQgP0@C?*(|7&v>ivOc!AESg*p)mNB4|;sFR_X-Z+>Pp-k0w=D8B;d?@-cjt^=P z6x+gt>V#Sh#j>-WE1=GWVqO!VTA<3I*f*?a2UH~#+m7{Qn^Q4=)~gk&0*ZaZa-Rcr z1{C{pvQ|u&;aSf$Q1hYKw=DN5P;;Q@&w8B=bsiM!%63YJIu(lkgl9m_g}MNWZPO05 z5Q=@D0o4Yz0E%T~Sh}4C#rSM1){BaE_O+=M?dvZm7Q(FIYUK%wgdZ(iuMASY-cLk zSx>er742*%n%1vyh}{i)20At!ieZX|_!q-|GW@9MUoym>^K2UYsOV2TLDTvXFN}d7 z72V2)_?Hi{pE1NfANCoDOU3vcXCnbq(awIRY5h13ro)elZXEZPAI-`k_A_BGKv*jJ z6HjCUrlP$X_AJ0uwAa9%4Va4d#jxi9rlNfb?74ucXkQ9@9$+fkm%%<0Fcs~~VV?z< ziuSW$_du~<>k$7o*wf(Orv2MtPnwZ9*BKVT|`3&0)# zOhtPT_8?#?+B;$I1WZNyTG$<%K-08+9qj7>Q_;T*_9XasY5RKE*8`@a{|4A?@aLHc z+Ruf3xK^~E2RL#56VG$*Q_-Jzi*uifb_;J2<`2%srk)HAFZ@23%Q0sC2%AHG7YzBG zIOKQoke~DLks}UEOC3HeCD~!ejn-jEGX*LcitrKg`xeoX{1$ZtTYT+iz#BAIG`6&Q zR|*2Oe4m_~hC&?)Me`V_!xGd{fSG10a3|Y{FdtL5)Zuot6~geKKhJy|3&r?2@gxez zr6rCXaT4S6vqn@-#AjN}-vRhvk-wEU&4cA{My5JdN^SsedxU{jK)5@*Y}$EB_S4Pt2eF$NK-h{H^#_-ZT%^|5pAZhqQlU z{KWhzWMKX@|5p7I<6C9;XY#l5=9pyrTlpW4GW;v@Kh*fQ%Fq6@%8;1<*ZxKMry_l; z4-Pi|hW0;(q|iZ{){k@bU_YP%AI2E%V%? zZ#@0A4L#a_c%e$yp-rRki{bBGvt`l@w{o}iLhWCvO)LFOZ6BjeQ=3O?bF4P8k!q-V zp;-sjk9OL&5bwR`rF%XzvIrk@45HB`?qd; z^mmUx@ys8eeg1_PUwZkKSKoZ=?Z`X(-u?4??|=01Cx6-h>1Ut+^@}f~1Ggc=L=~$X z`dxkxV^H(AN1Kmm^HFU+rp@1J^KorHp-pWF&&+g4SopJAfdiR8Ymku9=Z^%EKN3d% zMkqrT2?VVcw#sSc^UtQ^)aiqc%kKzn9;wZvw0X2PN!0l}Mj5hjBsfOfkJIMy+T?wVjMRe^ts50S3VuZ6{;S9~pA~$cXbt z2An@K-u#`V3}LhhlELPWj5U9&lpzanfUC9DqfO%~4P33wpK0?NZC^BHaaUYmc=<{!2BtTvz1=JVQoL7OjX^CfM*tj$-n z`KmVeYV$R1zOKzTwD~7(zNyW(wE4C+!`h5!^BryO)8@O{{IfRS)8_ly{6L!@YV#v) zeyq(;wD}ip?$_q0+B~4m&$RiuHvg*4FSPlkHlx}c(55wSleJyXTVdSjWNP>E+MJ-x ziQ1f`O_w%L(&l7sPSNI6ZJw;nY1&NJ=5%dlXmf@(Gqste&1`MvXfs!vdD@(*%~{&a z*XC?(&e7&6+B{X81=>7Kn{$=PYXGny|?UOW2yARi9sy5TKY0(KB29qBS`N@yF zfc(i-DwsHeEI%9pmme1@{E^YZ&!OWxbbN=7@6hobI=(~4cj)*I9shTa@#iR%#0tNu zOk;1cd0_L22R46G)v~a1yRb1wpHwKP{Z6_;nQxt@!%xzttMJJ!Cw*`2uU?;fZAU@c zvlFwl`;@|8{gS_TbgShSE|%Y$+Wx^dLw;+vi?L~Kp_t~cmAR==nZ`nGW@xjjP?i7P zxypPA>0MB4Uf8uPcr&D@=Rm^Q3MpheB(EKiR{My;DLE|A~kMWkV z%lO3DZ+v9@)%XlY_Wx+SWck1YsR0AkB!fb4~?gcU*Z<{He=MpU*mx9 zea6+sukif$w_M+LeaDsLn&k4h>Rd})i(U1uGhItvD_v*1R=7sFj&|j`(p_U+hU-+< zDp#%RELV-I#ntFq?W%OOx|&?gt_GLawcNGLRpqL7t#O^>8si$_+T!YQUE;dTwaImh z{Z->T_U-m->^tqZ8xPvAvwz?I3;S*M6DI7k-)^5e!873&!#km2f;n;g#7~W~2{#+Z zO}NuIe!>Ojt;SWZt1uMQJjt=}0bKCgB)VnB#@DLC|BRRajF_4{u#QszJmG-ObS7Rn#YyUas;q~?#FcWXF-)jFY=Hu=5JM4Gb z@3P-*zsG*B{XYBs_O149n72DHZy&HfXn)AQ%f8$Gu>IeSFZS4fZU2q^M*Ac7o9vI- ze`kNx{CoBKb-#`$lv{mGbUdlO7Zk?knk z5}a6?W?OHI(~AYR{l)~_&y2HdD{Q0}2S6{LGoCfB1^PVM_OWrU?L6BC+c@(&;}^z_ zhN2g4+hBU(u#K>du^nTx=tYKYwQVrH@Y~L@4W<|8+mdY~ZO7S;wau`3YysOE+eX`9 zdhv|$s!?Gpw*AHU1C}HuwwbnBwo`1U+UD7gw3XV9Gk;^;VvIGnVwrNi@u_iwsp!Ss z#&3-{z4+hU|Nk7nVDg7Q}!0e<;7`vkkMoZ4}w|8I`s(ZSNVJ|0%XT#%$Xh8~Mco+i5my{x{gX zHn;6rV`Pk9bYP~Q&)JFD`fFnY=6dar`Op48-nJ?>|A{jO_kWVjK4ku1i@lanw!>|Y z8cy5k(*IwJ&Hp-EyUptVVq1x=4EV%jtFgUcEVgyn*#Gr5_W#RCFDC6ydM=6cU-kd< zNnf`uvn{t-{Nn%S`CsKoa#TC)jx!xLM~%bbSnNo4EODebmO6$xmN|wymOD}%XF1Xw zD;$S8&UTD&ta2RgsC76U3mqAbGaM&7G99BFS&kzd^BgBRaveuI@*JZbC5}ms9LG_P z!T7(_;d10V#yG6`KihGfV{re^aUAa$I{!~`e9dvHW2~dVG0t(C;{?ZChc*9CbS!dg za?NlQI!uS#G2T(+nBXXOOmxh29OKA#9OUrFP>mK5!d4WwfO%YtU?w3H;liJ z{|)dY3je>0m92&U`PD#0|Nn#k4<#>n1M-3$A}@FZ@`B%iroIbm`~c(y+d+Fj0e$@l zE&Ca0?jN+g;CaXko-q>pU*8Ja4`v3o~yx>3cf2h3ZN$_2-43QT_AuoCvd{vzP zPm~w!z?gXkBjkUgyy!pu|2k&+Uf{??dEv3+P`Tr<5Z^{d=1!hq4!so$f zf7^B)cx=iGZvb!gTVUMBWAehS|6}BZ|C;_kC*^;ly!d9UhK`$X{Df~qVw(h+?Ie-j z=0cJ?0nPxmr|e7km5~gOleAKPH9PbD*CmQTcWo|?~b0B@-t&obaS*j+8cc& z8jAKuzZLyX^n1}CMX!ur6TLqAi|DVSzlq)y{cZHl=)KWx(H+r;qK`(Oh+YR8^C@Wk zo@impGtp#Y+UCt__i9_y-!Skbw#!kdgW)KskcreSS09V@^YSpQ{V zwUvXlUmjLov#`RO?U>^@1#7kftk>o`{@wE5LahCYuTdzo zsEe?wJrk?i8mwlQV&%HZVeJvcR zG7VFkH_x4V_BS8+%ajl1e({SBpI%T`sm%_(?>vg(!fVT#ieTcmTm@{P1W1D4CULT>!NaW!Wg8SgMXWn5CiHmlvN*1P!YAx2MiJw ztCXlDSm8~DI=C42kvKMm#8x9?KU@~$EX0$D#FzSb>|r|me~EJs--mq$(!VLiFh0Y% zi2)W=pFgzOlZT}qHj*xeQ|m0b*tKTaoU9=%mN#wuqZ2&{(%_F#`Lo-tbVtZf`6l|? z?M|l(HDZM28~0B^nU!tCh}6`02$edH2d2d1r>1^2emsB1j)$<~+wCbSPN&Kxp8CP^ zPnDmQgB3poKP!Gbb*Gbkr%vYMdlIqp`KP%VuW+3nN9RltJMQs`X>8w8NPpbk(&skJ zLa`ckF#p3J{p0-6|3Bv`8j{A?8-;T>swCbIDXu7wT@Oh$hN;=I$vSAa z9rjoC{Lu7Z@B5e!_+8~IOmb(RUJY!=Si_BBn|=i6SX5(uA%o%Brb01{9~7=gQukAp z-SThI{z8|O*ARW=kYC!6-&I3?3R}eWO+$XekiHEH#gQX@K+^)#jmoYSJD19GXZV9D zb>7`k2=76^?Fh{GTbpV<4Ry6G?JYsGz;rc?Pcz&lMdljs`g&i3*KG9#f-?eZS~@zs z4Rg$v0$0}@%MY*wZS^&o9lpREL{2kY4Ri2snx2LR{~T9lZWj~H%Ph-Fops9w>Q3omuMl z`}}DJD;4mzH;BI!&TI*oL7&fT^R%x=Ee8i!;c8f^i)!WB;0bzaJCH<6dy}dhqxijn z4qtn~TifBOU*ip?n{}N*^N^uT6^hZJGV@W!GEW1Ff&V~&ElFoK58I}x7OjIEnlfvd z`Jgf}Z~6v3t!pwFDVOy{Pu2U{8(UC7X+g8m?`uPYG6z@J_(1^>d#HC2%EC1K-VU!P zh;C{1=mMn~^waKs)%eoHB`pC@T`QV|g|G8@{0%cy-?17hLtgD_!{AX>LsR>`o`%}` z%K|SENMtmk;YpJ1Y$)o*R=$j zB}AH0t$NU8i?UfT_SisZWiuzusPy_9ef~B^WXmS{W~Ld7+t;-F*0q1t3q|}JG5>bD zIpYzVt=@^Q3;KPntzN%b-_{`IH9J+72vY40N`*MUQA5+$7!SqnmF}2_i5qD4HpIO2 zz}E8xVL0rqL`~C56tf*^pcJ*`B^9NEYQv(%yKqs}WHwGqyUsA7+6-9V>h<__Z@U+k zSYbD+(jhk)UuulXpk#^Ysgq-`sBsc^)m}g%?NYC-Y#A~t02(SQCvG29@-}Z9`c=&@ zA|S-zEJ-LbF@lsx<2ND(X~!YuNHZ4r*0SE5G_gU0PMKd+Vz#yff?f=Y!DDHTnI*;g z+hH;#3=&$fXmRyHQ_7iR{{28ELRr~WsN!%04JuO3T>R1u)=Urvu?#I)y1kWmiI3GJ zcCm)w9CPu)`3n~H3vAEKDBE-#OBhT3A1rl z;%qGTv`-G2fzFN&pFb$AE2~Lja;9m`dz8oYd)gEk(Mcw{nLc1$ObEZHy-Dy)ZWm%B ze~xxl0#=Dh0OKU!jx@t6ndL8(O5#{$7gj`?WN;CbKk{kv25Y<47mymYced4HED3>0 zH@kq)(#`dP*31sS*Ysr9!VN8wK3G#VWqanPYs}pesAWV@0tPqN*0myHKKrbGef=C) zW4h^WlY}!eG8C>4di+gHz9Ajh0k|9Fsw-X6fW5J$(I?4yFnbsx4Xb?8>EPce)S}h~ zU7C62^A<5Q5s%;7=3DDU0&Fr=w${7W+YZVHP}NOPOb1CbeH(x=t)@id#$(Ju&SWa+ zDg9OA4XiQSn*6{n!SRMCP~XzR!HG7A2V`4l?!svIu49ws)%yHa1~Dh#3d@ayNLrDF z54N;<1L>F)&@Gf-Ui{EOw$#RChBNjACOvic3{3~GN>qg8H(A;VPUlctB0QN>|njo z!Z8nNpeipBF$Pi~fJ{(?Q6Z5#0T+N(&7(xVlp=Wo$8VyJ>3U9pt()*QtduL3)NL;ju(D4&TuRsk7&YU za=@GdGTwsL$gysz#CThwO2CC#If^%HNBUKZ7MM9IIib8nby?X5_qX^3rlZRhh$Rky z?&uJ*eoQ8_E6cj@qCzE58=*y>wVsw%sS=ngpsfI->9R1!!Nb=#gRCNxp`izbCmuo< z1bCl5mgtc5Y8CB`r!&-_oLby>Q2K)5NmOHrqrBBXJ3^B z9LlONst;nELqP2Gma@c?5@=p)XP{Zrs2I-)uDh{O2_X~eLki)k17S%_!d+Z#mH>lg zn^QnEi+!z~Z6}!vIs+~BW}u$j*Hjbhj+Q_@SXpMHc_kJ##+>=uuxMydsV3wXA8H91 z9?U=c(EioS7ZxY@;$4dtl&Ut+>h*S*^&q;K_==ltB;T0mJ0;+4_0|WclEiUBfOi|(4J$}Yu&^-%9~z4VApuXHU;P?cfDofI zWSp5-%YypMoE!;2wy?NjzVML9RwzI1MOE$v*>ixabvWgR;wO4C8x-BcB_~lf8=n!e z=B$^rhNcMG5b(61IsBlzz*&qNPtx-BqaElg!!u6q2c?|Ikyu%?DHKLPrL4gyMYH$^ zX)Mi+TV*3Rffh`R%VNn$Mr3-kUNz+lN>#nA-jud-2ZP==yoZ4h=md!<$hRH1lM58K zXhJGMFK8CrW6fzLk4{2;YdieDAO?h0w(6h{M0p(+7jbXP&x(oc;wdIJ3*+d1Z?NVB zih_4xGIMfO4FheeG zZ}2v@w0kk>u;A}(Xz|s0+p+NU!U}qbx$pO4sSNT8hsMspX9KuQgM z&$?O)MQS~5Oao-8wxQXdm7A$8b?ZFuKS9fk zKwd)@#uUwLF=uM~Ol_Z~?XzO`90@n8Ay=Du+MKD)S=!9k=4@?dWmaJu6)?Eis4e^o6M7T5l|fnU$XN6}Rm4 z-1LRMSQs?fIo41i&PB?;Wd|~lMBgA2Wf6^02!k-Yj*mytV|cdoSgJ&*$T|d zOrMq`U|nYVbOqHnq)%7g-dX9>5hpP_ki}Lnc*c4R+}f_888838l=1p_#x?$yHgj2G z5rc5SMD%sGV^uaJ;POKSTyF?hYxRq{OoR=n58B<|2K4Le@T$>>KCBep*UXYI+LCDo zz!pO)iW~?*9w-d5p}Ar!<%6eK;cX0>b>4a(7AK}37z=9=NG3WvVvbxzA?X(3v15so zk)4M}lOV?->E~pzoDjIa5qQqmhS0%gql`DlSl@Z^EB>6G( zr`JJBM~MwGS>OSd^ffk`ByT1>IP6q`v8JePgEzPcNUa*cu46eMRUXtx)h%ru7&y9# zxb_odE5w-@NKD~0vCQ;|M3h4ksW*v;C>A50Gx>uyw$VOxz#KN z(i=KT2Kiy&Rm*VUXlZOjeHU?db?89xl>V81uu`c_?1@rM5)W234$N{cvVm8<=0c(G zC|D+nm4)G%4T_Kh3Xq$ghrgNln}xr8{LRK+7J`vpTQnCaLZ@Ub9+an5=bXekTSLFJ zBY;sdcw$+8`h8p9R-^P=9*I~s|5qc z(-RCy%)+U^(1)H;Xi#TSiwUHXh*hHos{o|W;E<5{*^^jE)Mun;<>6m}IcN`%4!WXg zKvFQ#G7_4FD+#1wSdDJZ!!k5rOds?!s(e_FCd6t)AYy(vR(sk5pbq{PyiH*BSFQL5 z;A0f~I{htz^R0S_U%hs&1k)O9X;NIaYBBK#%dOn2r4zoAv~pckTxGgv6b<$D)%!h$ zHMkOR?tg9gB}OPOM>ixo$f#^d*gvlHfNq=BVD-@rkg!)^69o=a@-yWoJ@#L2;fXggm`^#-eKTB(r>}S#hRGL>)jIgKn~2Ws@Ea zjW*-@AQLQEn1%s7-S z!ZPElOAR*ubk#Ow`{N6IA<8J`0#7@32~hX)wl;4=3t9(j3M^wJY%Rn>7?cqH1bw=N zjcRVTAmU<(R0J0xE_Q6NFGFH0n>9cz;*#PLV3RBAT5nrV=d3gqKN1IVR@ATRQ?q#(lrSq1!D@^Pr`Wst)>(Y#NPa7m-LD_9`bwCv3!d@MB zfw&5TtP=8FH4HLTdt@}AfnrkCAq@rYR~n1^aQNPUuM?!1BFc42Mypy^#90jkUz`(MaXx#ZzxjD~Kkgy{mCFCy4-znyhX0Re~WLR1A7#GUu4`wj8sV1g1 zRsm8eRiEVf&fkQhAS{0XL3OPI*=a3>zp)#|9JLG^=&bZ z;2k2fgYElFG_cp7Zp?87@aP#%one5-=F3+HCJ_b#tea-kCzN$)sV15l?H?ooE%}iF z9B?%>peZ4_5e$k`^}Z2gnbrEtnH6cRua!q!WSBG@JX;o$ zT~P1qSZ`$yk`ctlmz36=!UQ-=r3FF1t*t86-w>O!(c&{q?d)>`;Ls?rkv;~~(gumw z2C)EDdem{i>87-0UPg8v5gpHk2m%xI#CnjV4n-IZ zm;e^_Yx7au?rXqV$_96Huy!w7O2bT(*Onz7K=?lq^IOPhV93tX5GL0V~G6Menl zU66Xe$I#XL5Qv~;g0;!`$<%1zC8ARKZTiz;i# zX;jx#VLH`=TlAuY7W)CuYM_4MJZ9jr$c&5xF2S0zI1}VSV^gf;^RFlN8r2KNfA| zMzn{TWpF;lZ0ZDKsAnUlOQqjOL?C^d@%JNn%)IGYGjb>V0}*l%A^RVRz=ex$SzWBu zvr>)J+Ein>+7eNjb4;0v91V~8NPW?8Sk>_4muq@%W?;DH^YqrEY7_3Cps(m}6nA2$ z8Jpy>5kZeUcnmj(lTBbijt~>2Fo8e0ErTOb*7ye-B*D{+)Md*N0B7(FR}QA8f#ma$ ziWtLb%MCC|wH%G}NEoCuzB=XOW02js+}DYtB0N~xgi{3EO&X73qz+%{ZdR0Aj_l#c z63-Q2V5g-S!mmMQL%3={CWkmzN0RGq1d&6kjvLQCJM!)H71e)cL7q zu`D%UFN1wC)PhvjO7Ik_HN3RCc(_rTkpDrl7XCnM)x2E5F$da9UO3T@a0$^18dSz5 zCzrL^%*afo(bb-x34+mmH9hQKB zrrNJ}dOL-!=H5?+aqa}JfF{hDfaM|fq$ivocd75_oRB_&`$7}uoI7DY!k{~s!Kt!X z;9SD)IJhhhE{}uNaj+x~773_QtFE%#&zIaWu;2i4?MM0|O%VT?%TT!Vc=77|YZ8iA zhn`s@M+yTI=B#i9Rw6A`-gpe4c+@anC7l1UQcjj7s<7>e3R!l{s@6wCrWZd7L#uxuz@fC9`M} zb@Nop=gp$!HKk^u38$IMcvPl{%cBx>6i@{17;9Lj3x1VTqw2B-7Mwsz)4_^@R6)W~ z-_qEE0iq6;LORIBikx$nwGIeU=1fdp5KyCpqA|7A2l}FgI5OxGe1x-9zJ}WT!{Ahl zLo@^u8`ZY@4s%9%2CMq_}Om$)&n1Yh9c*IgNZR5cw^GLB;Fc|7UyEK#9&jmNf3C?S6j>LU94zQb zuyYzr$7qXNmd7mYbGlEF2vZX+>C5C0tawk9@u++WC!{SXUuA<+$MI}nNzBIbVMf_q z2^qm+1yp{_S2A58L01m4q_0<2@k*~&79FoTmXPuleK6KFRwyj7(gM;CZvWfPG2cXF zk$@Nufjl*$0XIGY$i)+ABZ3GZ9>i=d?X)xy+o+$rs2F0c)62@wm|wAA;iAejtEy`j zFIl>5`B|R2dK_YFYHm4aO>0}bujA|fK(KS|x~}ybGPAOCa`R@+%AY-L#*li)2V~`9 zYfugf@;B#~I?1X=xmO)nEvlMtEUI#2FjpEi)kXNwb%jw`RtZ&N6jfFjHC1>Gy`tDC z$2ruR;%eiJ>M8>h0cM3!R9<6LEkgJTgs(vO1?5I{X|YiPRa0GTRMnIlrHiVJr6miD z1xqT83dF4}b3@HH&R9@s6fG%+`$D8&4!7kosQ~eZ;A7!yWl8 zsYdz;TY<0$gF~ALgZJ92Dqt>$T86ygw~Tod8AZh?$8tC9)lkcgiV`X})H0*Sjd1Q| zNQ>dBQHCWbGu)RiGm0yh8^tJJRcR&ay&P#SGnTr`jiQC6C|5bcmLUCQ$gdLhs6cqY zMa3u^!!I+?&Bn4Kl&kbighv^HEGjFO8Ow@GjnhmBbzA&jPq;cLD?Mvzy~OLUBg3(Z z7bCd}vK)ZraBdZ7L|m=l+$zCJFdp1;7#zGUxGC8*Aaj1qL@+YRR-<`GKsF zag#5|!-WcQd9q0*0b`|#D5i<8qcd7>&@NZ#6y$3lwh& zNudYG8aJ81YR*K8$Oik<*tP)u%pvN7D^mo9p-M9#(QCzlmLPUF8hv;*zfqQBpnQWo zG%;d{ksr<+f^UOTnMzRHbrVLh12SdG*N_hcDs@EEAhK+SqRO}jiY(Vb%_%C0sgSG2 z_!Wl60=%vRWd`9NniekHV0|_yxe_{&Zh;39p2wW1(nW<)4C^+bG$$8lqS3*(4860>S)Yw$4v$(`UV^xIpC|9cw{U+6WhTVl7D_OTr+m zPv~lnA0!n>ryxOEViCo#pjV3bQEmyCwF(V5L*!w&r=%_qVvKSfDYX=uK(R7~^<9?a zdngycREIJF33&i?1yVuoge)sS=&c4xhY1R?PmPm$4aNw4YK+Va6iZD=JQL6aUW4&u zRc3M0E(u$NU0W1cPmL3G3lx&BlO#d6!fSG_eH1ZA!*p^r7u(2za1|R|V9m&MC3LpH zrnHe_lC`K=I9P7`mU&w{%qcve0%m%>IgiJ$ad(3|(f)SNdVXVj(C>6FPAy=IQ{yHR zr@Mom*laNj%$Gy_R&dg-oUwwvkJZ}B6*`HPgR&^?^6(%X?zo!}AA7TAWM*b%7SRTD ziDhI_41*BQ1i=l_HijwAE+~=Z@_SdRopK5HSkObxEw#u)bLz}S}0qUgBcGmP)*!Urb3vaI$swq zAK~&Ve?$5=A-w7@Fk%)0A`_K31!U&M)Bh@j_5S2R3>$hm7HS3go|Q{tc5~UHDicUt zxM5)jvI=;5Al=L^D6cxx`pj57{7@*j0N2UV^9!oW+_(>mQ?Ui;{PgV1f|5nWR_uiQ zhekJZGYi~BCF%K@1sG&Fifp z{*1Co*~Cn^j%`%?{C;fLtNoN#HZE4>Mj5IaPmzOKEiJ7zoorOgG6Uktd|sG@C=jaw zaN>OON4=uK7QhB5&oxL|SY0N1$$fl?X;kVI4M3(Mr=eI-9TB%X{3b7jLauU1Ka?SB z=8!_*W^bUrUI_dIp+T(|I$3{E{{H%y08MVIo&HFbnYmaGsG)YmsM7}h&D zOX#;?9>bsG!o5=hczU8E&1h+_^*3M+Gfi%U!@f>E4uz!>F0c6U4v=`zqJ6NS?NWOp z>g=e>NH$4S(X4keWUV7bOf$Hp%~P0ojl-{=;s`2Z10K*o{k&@}q0Co8)S*BKQRlDa za~pil0}pNlyZ#S*Zv!7^RppQ0Ow*E5LWD%F@BIKv6bfruF z-|s!=KJ(1enM}IwuAkq3pC`F+xSRtxOpP))7pRSd^^w9EdI`>!7xUT1-x1MuY(ew>(#x@$%}L@!m`@DOCZEKvKB`qG;dGHG8~2QvVF-4E7K#=uxMIRm}YL^JpkG9 z&G53QK!kCm#vch{cXZCVL}ZYi5e~(nBj)rQ1%lPaIpE^2;IOXVqE`{2+$f}VYe|lg z1!wE5KQWxysO#owEu4sq+1)wh4SKK^(QmQ`gvt$CR(Q1HU~g?hCr_Q+PH#OFl8Op5 zRTScc8dq3&ny^lg(87Y#j!xoKwlKuZ;>BfxR zZR$uO>R&=5<*Z8{CX)-yNlcx#bm7ds%@QB(CaWZ4up->bP7RBF&6~S$M@82L_YR+3 zT#ir_kJ``X2nhT4tsO1K+S@vsHyRrRC{3o+q!<%>S?B~Za&N< zFbiNV^^(lpVmMqTVJI6rWdjdbAvZ2w0auM%UEQ4dSUMNA8;Xo^y-uvs-m0+DDlxHD zX@f>M)x>690Ua`SQS4iHY(|fV45pd_8=oDx6$gSHGc!yVj?FJbUvBs4U_o!}EI43K z%WQn>l?xy|XrHlX-w?#E38IUZVu7t%o;E3UEx4YFm~jLracSdiEpojO)%H2ElO>X@uN3yQ5`lHNrw!Y0E+cIm1 zRXjtMu&v_eLNy`=RXRv50K#PmxYkH|$eA%wzT@_+)s~B0G8e5JKd6w{K|20sKw&aLYp8u>!^% zh3Gv#$aRQ5lGniH9|ns3hq-J&FUfMnVGuWDTUxh#Wi_`M^bSBNAxI-6fK8!ggLXAm zCK6^DUMxi?mE_S;3%f(~f%w(90ojEF0>)N*t}eWhQ<&pG6#Qf55~rfa7Xs z#-j|?JXv;}g{w<0hLm{4z`6y?fRGqkbmt0XDJx^Rr)z?}6AbyyqwwhBnZQO6pz6BP zWvL>3N`Q`Xy^C_twCvc7yS*%X9Y*|7+{HZHt^h8bm|8H$AHkgOLgG}5|&7{OU4UNFp9>k$E>S;)*tmt)@n=SG=f zh>mRuL4nlDkUP`N;#OKc(W1=~Ie~6D3P&47XvfRdy$k}E@7XRvs-jXr!JciC&3O`0 zSjIuCEAV= z%7z=DhA-1h%OvxY<(UIm@nprtMF(NYEBdw$hK?hV+>1~(eA`5!3$uPKXXGdxgK-&jXUZE2`jP@)?n^xU1)HJr6&Wv7 z&BdsT$HAG`K>}<~H)ETB(>A?VnNxsx_uToj=gvKWlP??$mMDE9LF`|Uf1?wlay!Az zFG;|oZSaK2D?CX29EyyU80M%=&Ir_VPl|fp=&7w7ug{jT#XR|n42fNWr8BgiHgXvq zfkN@lc*o}EiQY5l4Y|->9<`=6okSjix^N!Z;e0@xy-t&(6f4WNs`zA?3g0_;*&7GY zI%0y1OpW2T5vqaj=!~tm_gHc0i-sjL!;_4oK>g8gh#b!f+65-8V_d=Y0-S6`*MU*4 zo>fN5ygHA`x4pCxcM{I;=HWI*f-_<(-PxYl+uE@^AQ~|!v18Tq#zxm#a+Ke)=?2`J z%Aq|b8VHB8T&xdb%HP5vJ_immmB84Xf$+4A4ETYu11BJC-`gqevQE31vEUB~k>h)rH|OiuP=^&25zm)tfcu9|nFEOB)#%3O1Y zEfvLBFq}1ubF{?JBKUhs?a}R&4IHd zCcu^l1ruuwJh4S#BgQ|lu#wk9LRQh}NCC01a*QP06w2vDc}FWag+lC*vzm#bIL2sT ze+29KmhD12yAnFa6VYK`u=S=kn>4l8PD@=NO?wG!Zhe8lhZ&uox@Dmzdw-!-`3_M zpud`xRf}qC=GuY#P2NtpY=IDOCtx|T#t!y4RCH(1=J6^$-xaqU44#0`T>ohO3x8XI zWDer(zGV2LqVnt}=BHem%MdvJS$JRg)to~&cWy=maVa%M$Qas+*v*^I$*{e)ox3#{ z-jQn^t8@N|ihnu)?Z~M@FHJD!kesf1lLQ+}+dN>3fe8ku1=x?t%6{>m<$~EnzPc7G zR_?SrSA#HRVAJd_4V)SyNsXM3oZdwbb3G*Lhx5?FD(pOAH3M@*>T9_plDHV&JDX ziEUf)u?usRn-wC8s@1~YLPBCQjLk%xB14D6BXX%(v%nW&W6ZFi8wU*F;Bof3 zxfo`Em` zH7Bv?3^hc1UI|0BfHRH_wQ>^{@vUQgC2QcBS{4}VZ~>)}A3H$4*ez+S4RtkkG;)=} zt`vE@v7R{FO-Z|Sl!FI{0p7NzF1QGLtgY~=VH?Kc#pq=VZtm<%Ww+1hUq&R5OLoYB ztCOrZU05q@;LRADS)p)g230dxE?JB-e;aXXf3sC{v|;mSi)~_YTMti+N$;p*JKQ#p zYU~l}i_*^-ExkJl;O=+R3wXGVV;AQU*i@6m5@$nA-NKl6`f|H(C(NnN;wWdV3^ycT zy%h)GF2;fB*~-;k-`u?3q`C~R2g>l1`G@Tt^mwryx~n&CSn;x}>C>ks>t|K9Y+c_v zYhHOALoYnlTQ^vh;c6^_;G%Y155MJ7+yE#@-f#qo*o1#L5X35C*WovgzgZSe-vmY7 z*;Vz6moKllq#B15FeOJE(3asg2wW>@10f#{9l@o1HV*D${{#6v?Y+xZt*Ck5Y`i4b zR9h$xwVQC!O6Se9MXzPHnZ3QMb2db{xnp+6ruEK_H@T(8Iaq=mPV|%Ij4?oGYsLxp z%n09U?~NlCj5NJKRSJtL?H%RYwzU~vXo7${RFYdGNyt#sx_X(N3lFz>K{yib^ zv@elnIbk8n@DO0%oCX~L?p<<~=(6&;s5#YD4OMmk!iLz+rvU8TE7OI5ZTG@h6=n}; z_0|fwRzMP9UU#fsY}Eo50dSB_-)QNfaYADo0sMeDe#w!oLarZlGE||ky+h+BeCmXB z5HGfc_O#^Xms2+nZCe(dl}5JpJlkK`xF=rqJ) z$;Fp5opR=(3h&Gv0oMvh0?g|+v3jvq3s?kzz|hn!oL)W;1>n@4$}l6w-pIvf#*7&; zjFd2z-;6_Ph!C40bV#^B-_Fa?9%0UEXFez>~F#(_$}AP z;e^BB7@%~aXNIygE?aMDtiWMND+_Yl&k1;_7zGG;!U$#1Mejje9CKZ(#DI-a?_wo; zT~6kvCfxYWY4(lVxiuzd@plQj%%bRgy z`_`Mvp{X-FwSE0;>)5z_`E0oecWY%)2`Xzfb6##y0|WY<6?FKwh6@G;sQke z0!7*!RdS4c+A&qBTr&R(i(TJ|Yfs?~?#-OCW0ubgh-?_xj@l%<#J=xo{h>PPq@Q7ZieH7#L$1-vxC`e2i{eht_A* zEFL|kPag8pWeXdg7nbffCZS3SIz-Cb495V27tz5L0~{Q1;Ts3YnIQ@t%YF9MdUu%B zmyLI;zTo>?m}@MEGm~V*g(CMt%nZdcWjMj$8)Rns0&p>NRzOdeSNH+&0zUxn zmOmq0BsNHK3>W@!gTDqEy7Fq5v=>gFgQhZuJBy@mNpUqBa%1l;1-%;Kz1s?Yu#K)zwtz@q$|})?)~KGnxUb z2*r3d@={MEdp^q))rcwLJGL`{<$KIhVPS^DD_D`=ULP}SfjefC#2AHF585_vu{1L) zTDNRx0}LM+!nADSnge)nJ5#TtLd%3}9w&@|#>KoOfYf5z(t?WtA(Wgx;DjqTDbecK zgB1ASO-BcBS`_}`*0RYeUywXgZ|gN^OoSH1c)b+&Ot8SfcEl}E*qWCi#3T<9WzAzf zw5p~E1`R`o1iV;DxKP33fesRr29?+>dd%r?Ul-J6NN78TW-K0~yQ0zy=R636OW+y4 znV^HbmfLUoIA)mq*>>C7$%!H0Lp^9&GxwQFq^tB^E*A}UN)k3xq>57ZMpd*Qs4((b zRNQvt(t`E~oDfadpsQ6~USCVb1;z(8MmIc~4v3b|E{wiOy$SatwIQoF!?L&~m< zbKC}XW+n7FQhC~rUz`U}?P$?$w5hSw1~mHic%}8fqj?h=R(6~?=Pmx^keIfhJh;p; zbr%*1>T4RbZ^cUd_EzKo7uYy@Mn~(-uDR0g4OlVbm60Nwp3IXu`!Dwc7(3eK9YQic z?ZU8=O?%n0s@jIeHB~Dc8dkk?_40;`jr2_{Itrp%Yp!XmZ@_VM?^(7Sclk8bB$LZm zE=9{!Q+4%JvrT#jdhEP0d%A1ty{ip<>c8j@P^nQ1(c)mpiXLw>>?j0m%h^NR>ek4n zmhYlxjqMnCK(m0I9!0G0fD#r+AbFR@(aegPnkcigZ?XgNdEBG|V|P4!Tu0CO;4<@#;WFjUQs}OvferKSdZb>4Tu3o`6wbb226>o0G9AVBnmYs!$THa zax>AB(_Z$;nh$rjb7lfHTx~Wlv8OrgwxK^LJ135JZ+53;O}WLXm1Y3a4Q6bpPv z3<{UqnQHNYNK3->47@KJ5H0izI5?CeULu1dM?mG2>z9b4{Z150COg)@l5*0tDJWjL$J!MUfyOwgJHXV$}O~Wd3Fg^B#8$$72)} z78ef(S?+dd&h`NFwV9%gC6WMyqjPYH^eIT1_~WgBvKNieyYS^J7cupKR+}P%jnFP0 zBY}c2&ZpbKPwO^1Fw^p_`?##N^#PM4tj_ws<&HrHYAb$lhuxex*bu@1aLybKoLjgn zKPS#t8;TWs&|>I=FbUdj1Z2C#k)1r4)U$K2|2PHTIUf|LE?5E9H>^9R8W{-rs@@no z7jHzrgF6h;4ehXZfwDuIZ`%}Br}-#I%M(@DKUYK+FjJt7XYW_RU{L0Qyp;sGhPk7( z2wl`Z!ib1XN>}@4UZp4khOWUU^Z_z-8A64LUw$giI14dLZNfA<7ZDK{RueR~$=7Bv z(7?rEbeRh$#^37K`QrwGzCqZ{!VuFJwZ*t-+V-2NP1Yx;(za2=4a?R+i77m`Ggyda z7OV_)-srw3X$3}6E*CkHv_0FFmU1itL4V5Zz@@lc3&w^WbJjMhc5T=f8G5&+!!+Qjp_7F(BIztFa(AfYV_m zs*xpTWdx!|C32-s^MG4JGR zo}{nqI((W_aPuYKB@&{mi;C`%*;hhU`n#`uQn?aivl$OTT& zR^vOJmVs?L!NUei<#$}@wtb5%lDcVxR4uGmvYC}COiDXhko?i*9Jn}sbjLwL5j`QQ zt68z?ni`cSParQxb5Cxq$OZDI*itEyT zEVS*bpASqE=v@I^(EL+=sa*2zZ+P-*u(-bC6z4G%l^lsa1r_YNpy_=D6l^-4uWWtbyF ziI+WP5cs%Ypw3l1mu5E&W_YN{9M3?-sM{?!%4h=7J&~hoMKM1}#gcN7&TPVR#UFi= zjs2QzsyP`d8BAq3xYLW`5253hY$Qi2wO3%0Mp={eMJAANbf2z~6$K{>QbyKM4Jc8F zAb&CSDEwo`qc@(kCut`&AnxAab>tsptd^j}t`NQDhF0B4v_x^_Fx1ZuSD#KQB)jY6 z)qousIWbK;q`-OPO2#pnF$h<_Fp%GFKNW$jr_GK<++YU>qrpT5Hu9na6rN`g2dvqG zK*mNK^gu-e0phv=J4%s}53l;5TkB02YN54ok96Kvjxb!qhjUQ5>=zxBpt`lKnV%+u zEZgtqq6fv7Z#cHaA|bwWiKz+u49AXhX><>m+BpRx4tvBWql29kezrz#;=wl&I#`Rm zEpi(T|LsKFU#Ip6^2F;TZPV<{udY>y)=57)<<}zJ2 zRI?3tDe1{WPpj8I5zrKJ%?eV4)&dQvoh`5}5uwD0jhWrZFLrTgDwiiaD_8V)IL#%i z#pHNllA6(JLRs4RIbAwBY$ptf#D=H!-C>(%uGYy$JozDT3}EcR6-3NURM6@!=57}9 zu6Zt2Aa9hPtlX*LQF+D$^X; z6*Rccf^Id!mc=|fR)DUe@Rg>LJ?Ren*(gK~8&kN@n&F^O`Q2j)yQPsIUqK=~wI3_c zxR{k-3 zZMS!Qbh%Y2d)%C2z(_8VEU|Irw0O>Cb0xpkD;8+^g&tRqqSWdu%ldYFTUq*p9d<#$ z*1B%qUX3y8w#FOmuAba(AhnB!87u5vD{lJ?yU-F{d$%;B0=cn(xk1_VXQ)Fzirmo%v*-A8f-_yc7<8dtU0(rfFVox z%n9VB==OQ5=9xVn;L&7BOm&DYDn4Aosin#$ark-%POjLF92u_9yIMQ#_eL>=(920= zli%TW`#pwDCVrSpuHCjFm1&ludR@+S8@Yyr7aU{Gq=R&fx?s;YvGcA&#)>a)f3B*o zu5%vk1j^2DcoTA#t2;QV``g^{vxm1uT-@CUEF;u5%w(|G1Wj+;x&bGQ5xJCZZ+x~+ zOtw>D0D}%t)Nb8+1HN-&KX8d<5>eT}xY$44kSkwvMk^2j%z>#VAs=<62-%MWG%QYL zqGYdrjxDWeSW=slqu{Y5o(GRT2b@mFScf^?Xs>x;ol?V*uMY#geS3Wf#^Y#KE3XJ+}jM?Cp3k#i0*`wmzONdLo%EiBS`AW}Bb4-04d4syY4GK+~39GKgjlU~b;!1x5U9Y9MvNncW zt?QQK)?K^Z?6CO4Q#|fjF2m=&JPTSpzYSlCgsw4qb;egBZ&%7BNUTv}!p{e#Z?V{J zZ)DootIDnCkbO1__7lf)eF>6uBbKhb5<)A$dksWBK)?yuuj^QR>_t^aO-Q>PKa2}g<^o8Ll8eFfY-c}uH3a1=Y-jzE!F!cWObpsITU6>Rk zMy4-YIDN&!>GcK;4z6aWyzm8kx^}Svntpi05{kHY#V#%w zwzZ1&0y4?Fa=LNJlc(6|zuAM=mx=OEODn$qx9w(Q`#UHv+NT^Zm~mmX3fHsZQ60fD zRO2oDP8{79as2}MwP-6QS=2eSI*5W>jQKDQ+Anlp$#P%mOG?VTo=rj{w_4=&c4#8j zV)+E)LmUO9Yt5FH#qtddWR9@`a2L1(dp*7fBTo+4xt8X+&#v3PrM7j;#%=8Zy~noZ z4(Joj!-R_8#k6^Vb_yqIQV3l_)zr?>IILP?xiYVn+=hLH7nW-QaQRHVZM#ezQqhTE zmQZCLpP`ZOWmw-<3On`ljdmwHql2nxnsud_)sBDO3^og^0-Y@s44--mR|>e|fUh8P z3?ri(($u@v6{nGfWh?vXbS0U^Z>94~wxG3TM0uC*l#+58zod@O?Aq1}LEG_O2ex~& z=rhjh)yzU=!saifm6U5R96*<9b<&{w>qE}kvbEVNUj)f)p>l2s1vacMY}$s;?O{ZO zPLVOB;+Xj3%xlwD13ou#&4+C2Ad;9~VK(PJn_^K=?Zq7`AZ*{k#;7AV>9RGpsp?Q_ z<|aPrbOVW3+lduzSljbuqGryPt=ODFL4Y}_xlC$zYZzaaj||Z)cV1x2m;ldh>=Vds zpTP+tv7m%k($w&D3a?JK%4%<;^V|641RF1Rn{XzkXi%^qsll>1%q-?eE>3hW%!*Xh z1v0bjOf?rHizv)VX1a1{h)R6m$Qg7_jzkpZ2qgq)E-}x9w`Di$rd%9v%FWF!kzJ$L zZSoMZRXd&KmIHDWfueGA6oG*+d+muVDd6@_+~g0vRx1G5L17FjD>7|gi%k_QHaKZ9 zvvAZXR~q1)J4}}fcSMP+V!YcJ0}t|=Wj~P-6eNonCBL1C-8$%rG%Zg%NmN$=<<+TBp>*M)ixjsJ1ST4fU7rWs2pz+q&QYgdXSc8|T z>*wTUKj-Aw&&kO?Z-%TNZH8#<=jLQTFK_JUom}j#vY0<}TG~7DtwOSwx&=i?uD-Rj zW8V}@6!yc``0O5fsvRU+f)8uk<`>t-+%OBnAY6pR12#g=5guwGm4)n>4Ib>l7bpa( z6STyw!XU5wBsS3gIF3=X7#zHhNEUlf;`#5oEAtM4zp(O@BI%*Yo63**qI1 z&@mpI?P_dq=_5gt_#s zqGx>jmE+b7IT+JHgMm2Ni!5#~H?iehUFHng`;G{|rC^Up%(MXC9>2i7&AWgHQ~XaX zwu&tR!jwf3yO1bCg2hqUQ;~T@u-rJOpmJ7bLP5TylHsb1Z!^BCw{Cg9=Pn)T+IvUb zfRkfvJI>AW&jD@5cPtk09~k($G}-WRe`}Uk%chEI-MB2)-iznRjitw+#*$?Ha78RI zG;;A0h`%t>>%Iis1i3z`l5iJ)tKYCPH8JP5?V3A%I=yNN$Wo|QSfYF{iroyqx_;nl~_DwSlWb|mN2&Wn$47MJ1S^N(f?BXQkc;T+IS z_B1`2SzX3^Ov;B}-GHzQg?hs`kFl1|b&ZYu6bX7sNU8lWG#2YybzxeQNrs&5WHn$m z6qcuNhQm;7+m$1KID0vP0sXsaO~$hgPv#N+CKJx2&zijC3{d=Y3K9&E{&P)LGGTk= z!LC2(-G=Y=_FmXFJZ+t_Bh2s=VKs|9FIgF6{d+x;KT!J5AaeWG^0ytL-!Hk+zpq2I z2Q0jXE<4e_7}@yPafsJl(FxBgexS&!6DrNX_168rsk;o^5+e@UK5 z57(NU1S2~@WW|-00qccX{@X|6zuoy~ea!N&D;g56`$c<+yNfW)K&#|s1LHy6m{#0c zh$RzroQ{z{K5i+)v9gfum0QtxTN^Ihz#a770+K9jfJcloRIJxG*z1CCO( zSw-n)yI{hV8lL#Z8l}CenhH_ig41nw;ZiGQ?Wa7E=af?4pZe*)$i&cJ7RoO;sGBj{%Mcz>bj_w(%QfK^kYqxFmSR zcDsg$7N4ijP$O@`6~!^0{6&S@)*h?jaE|?f6Gt3Y#sTs? zKUsmv=e9944lu`D!QRE-;^>0N@?6a?F*94;g<7aQ7?jl1qEu`{lSN%sRR?F3lMKY| zN#zw)i@iv5cI09)om!{75U>RW-~}VK0!%BXU>A7S71#-eIC8gDw0jZZ zY#bHjGB`+yC(W%`RO3|>_MimCyBS(eI%nbT$!0wiUe^lcBXm$0JKx}QUcyGHb2-0V ziCILwJ%GuL5Tm)Bw5OoW#;&bhRctp~4XOe99lNpRh^pa))~KcPrp`spEp@Foy4S_r zu2bhEPFUJ^_~wAYzGJ6pYp1nAAq^X59j!~y(J2|C+_}NNFJEQb6m>^%sEF3GXnWVq z_GL}ywj>m%#jzRNQRv;AWf34vXy7hER4!^}%l9_7unwTeD^BHk)tAY!|BC^fN8Z zo6+sJ;DVDCSku$2Tgi0+`Vk3Y!l0<@+sdTk@rD~#VZW`7M}B$lD_U%J9|jvktJ;t& zE||r*FQ>~OIuuneLscG^)Hf`zc9gJeP2q^sw#CicS#wcH&zuFOp=NCZJ}tbm%Cs!sys>3*>SnWI zdG&HrwS37E{@}a6Kw3{E^?d8goCWrUUhE6KxtGQEg-a^-CFfboh2!z*N_L(b40f~H z5$RhDK2m@W4{SgIcj5m1ZKlgC!{=*a$QiU4R)?<3$kKw0Fs+iPe0bGvW*fV|*t)bH z8`RL~*m^VGM46A`3k&87EKRl$u;HQ#pY5vc7!I)Lff2ExZyfkXGq3@gKd`X^0n}jx z1+a!E!7L3vpai&tm+k{1kQG>c#Tx?9H@MZTS|U!~3&aF!nw^ZLR2;n2;7bjytl4;9 zjANq>HTW!YeM8+Ud@6Za)k+M`l2r}M477e4mn^TX!B@_ftTNCM^4YFgRl9mcjagh< zQ&rcv2o3e>WFtQzy((F=((s}!+yRBpnt@#Z}Fa*TZIyhLp zysoikWkcPyX346$6;%z;VX3OGY2@ePD7bP{0yG!wyBkH*qUQi^+R$ln5a(8Iq&3=Y zXfvCoY-X32vw>-8Lq(b0$;NWos`>^aYXZ1LPP+kne8o@;t8sJ3CJgID-!k@gT(^jr zHP+UwT-vY<15^B=PrarrggZQ5m~fqB^8NmW+v-umMmXuQ>(8lYu0$! zMXMzv2&)>FuS9Onp^hK!isHSe-CZ|trUDd|eh>~+^89D+anj!@_38qLOezs6y#x@; z6RGx18_?_F&=dN9Y^1jEdO&=OZe?{%T_e6{hoXMx>Z;o1`204P+L}9|zsnxxgpGu) zo&3H*K9qWD^Cn;(vCoO8pi$jg%2UwJncl?D!H~cwxnu#?bHdZ z)fozV>67M1749e8hC6e3=@u_TtgczKdMU5eqC?sAO&7=P-Szlv+YHojdo9fj5^6>; zD^@LOSW{JpeL^^lQk>aSh7I2XR5st(f6wr;h@-%hWn zPN4h!v#yX>L61vx0PKgdGXx|dfQu|I*@tIDq*WYt>;9#TA&Xg-a@FN zBRHL4wcnQ5{F>m@EA-+lNw)dI)dXgXEk{e+rMI1(0Di!teRe1)E6tIl=}jvCd1^{hfA%4<T02)XL-7Su;H&c?`F-^wm?7mX=8b>cX@ zpABeUFYaNx<~*IFkZoB1_Cqi^z*y8+{X z`v8-G2LXElj{r6yQ%j3XaSvbxU?1RGzyZK+z#+hWfc@toKx9!IqILxKL5du5DD_sX z+Yv&lnE&QNq3fM4_H+d_0fCQRCiW-_vm5q4z%*du9mez%Uun!y+Al|ZP#P&fmR)ZZ zAo4%H2=SvkAj>Dd4Dp1$=PG0N0Ge83`T+X@2LJ~EhX4lwqs2%EAZ23coyNpr@2!J> zz%(EeHUP-7Y^t}`NDp8y@qm4ReSib>w_5PAYnbojBK?3-6x9G=9B>FQ2^d?W>0bwW z%FTNaPq-%m50I`2=>?27qa4S{Y{Sa|2gsx z?#U0)Klpsim;u-mpF+Nkhx~mSd;n8`Oi%CKjNiCOd_T+M?8p#ciulh8zUK>y|DwdN zACPqY2M|8!dLNK@4ty1I4!ijp(h1lPNcl`b_^~xv-1Bu~ngGo=;14hg$n*{U9pVdn z{F|^tE_wk6NY{_}o{D$_#sPZ(lYj$&-GI@*7yfArCq{a{g?a<`{>O~voBX!m2LTz* z;CBemkEFjZa+LZ3?Gq!>AEJK2UjmTzE%lGa9D}_Fuyi8I4=@23`;qYL2V{9PJx%)J zNc6`@7x92SgwGh02J8Vm49H4v`Tj)8Dg86#59yvozMO_|0TX~tfK7lsfIWaifPKXO zAH)wZ_9FP8oa0B4ACpkNzlI%cUC*n?7ufs$4fzT<@O$JR?XL-a(=p`Z>5y|k%1O_^ z!yV}y0AxEB{{#2|-}Jh;_X3_e@!Uvs81aESnsS6QDUupfWXrP;Fb((KVz`5kK{G!H zdjimu#v%i!7MYT$DINqY1MHg!ceLTjNkygy_5nbaN8jm$lOl;T2&0jqvj|a+=M*8H z6C&w13tjr$BGXTQfRv}`TZ+t4*qZ=L--Pl8r2Hn{T4X9_jklfH;>N~G!M=;4sArsu~<{=5J?`myNIF=hz#3Bc$Xs2_l& zO9RGX9|UB${lB7nab)n11RgL2`w(C+VE@ZwOh4ej|AoIZ z;pMjs5A}i&{FA>MV`6Ym{+qZ*#}u0+>3p9zS5y8kS3?>z_Mg08QWcF572 zC7gjN#ikqXskhP}>eJL>bAWV!jK|=#Vlx1H({$n|L}D|=-OMgFLvW7+M$bb00pozZ zfGp4G9E1mZ956*ZAmt=}X|d^reV_t-Nq-sm0Gfrw&xn|6K*T%xPTJ3oMC-)fQ!n=Q?c0x`vBlUz#+gP z+OJ1?&Ov-{Kzab!#KInX5^@2UdW!DRh&c+mcr*M1mI20pRczV;&995i9>5sj0pbA<12zG&A0K!P zO$A`jG0I&@r1#&!7x=!CvDQ5~eyoX~i}V39|5B%pH5fw`_X9GWvD3zy6zmDWUcf%U z!^8s~1&mD^Yf9dN@Br}?nbXG_jxl3rj>P~wQWQT&+|zFn`_Oq~4ac2*=Zn1`<2(A} zIFDmP6B}#ZbZT)?Pp#n1D&d!E5`U@nYHtyL{ea{*&?@vzZQ|Yw$arwv$noYNAj3&s zKh|_3zNQ0qdm$C@(0AwbH1f7e*E4E8}l=1+9n zSkq3r?Z_X%Bp}9)#c4p|<2Q{pM__LPJO*gqEA9h;vGZWxIo2cqQ-Do?X}})3zYlb! zWs%gago%jxfP|mAZLDoKh5#x5@!ez10njG^4+Ay<9tG?HEIA+i0LuUe0G9y{0=5GV z0qy~eeGvWu`v95l!M(z_|D)hXd@tR<8tK1V+ zFmW&P6|f2LAYeb>5x^lp*8lY9ksq)R0G7rOFTe^wbKh9A7BKw<32z9H{nWr0$J%y3 z_LuaJcmno;t_g!k+K2v@aAhR*4Z>uk_fbH!H+_$dH3Q`P#8?xZif{lK|DMC7i$>Dl zgS^AN=_$xLVB!aeH((m@Al(PXnnA$m58?j;l#dO z+9yVuUPAb=_X4H>lfQx70rms-0S*8%eP#&hhP~(C#Ge^P`AkE+0ha;x0=5GV0$TdW zIFp7wIbj^aIVI9Rahw^1JvM2aiB1PSU>qk$0i-?MKsX`Nv=;G%d;D5)PjwNV5lMEBv+Z5#7Q`R;9zfE^ z-v@|zrvX!NkKT&-1NOgP++#iC%t6>ww~aH$0DE_hGZk+G|J~!vTEOJ(l*ejMS$-h+AYK0p&bVGe{j z5avLb17Qw?IS}SRm;+%B{Qoouu!3eLnkTWZv4bhRH*E|C>!zrGj2V~4jIw_$-Y1w- zv3~m5_?yiBzBA0^*qhBbtV`TIbgubK4D;&#DQ0|ZsyWACj*xttDM?+7G5N)2VtR%- zXK03*IPi9JPHd*RxM!vrKX8>PN!FT)O{>iK#72ziH=2owc2hFYj&b`YGk)*}zz#E` zw*%vF>?<^FHdB*Z%$e9*xGTBUoR{8e_6=+`r}w_kd^-7lb7$-W=2NK;m{0cJW`Lx4x25)B_J5c8KHQ>9IqI*CDg6=a3mU@Q67r{deX% z^G$O>|2NH>WBq1KU%z=*`dj8&>>r$){*GDO_Z@R#@(E*xo-k{A51VV!-!-d~-!l#A zCr$m(Q>Je4AIv+WKQPIj0qns2(5#C6(5&qHN3&w!N2WIUV>2m!1o1jzu8y5vG-lxR zqN@f^FPhSKPSHh!bBe|e&MR6zG_Ppc(EOsM=8~c%WC1|$`xh3S6?;d~ z;?z5^&i;;~MSbrmn$&lBQB{AUC=stJx-wZ+bVYPg(OIcQMVI$1!rJ(vqRPQVMem4K z7oCx+DKg0=MGJeD6kXQ4q{zgV7F8sc7G0WLTC|{PY0)LArA705mKM$HU0O6Zy|idf z-_oLZ|I(t_151m_2bUJj8d_Rp63dDr$*YRaPSzI9jIStqd((=d;)4rK@jjR)m;_7= z#=s0-hWY@LhUtN6f=R%{U<}M)1@JJY^r{HpnQXDOfbmM(3 z%$~WXxE*F0Oc{)U8Jq(iFneIyVG=Mg7(-J!Gjcd?iVwi-fq}0`J0MOA6dRbq+3*XK zhUtN6f=R%{V2+lX;=?cpU?L^h7dPV~d+?rwiNi!;j?6N}2VwTXbi=HLsembkIW`k` zn1e9AFe#V{m{OQyZ-+aKDIJLH0c?j^22%!80y8iJ;ldn5+Y~98hJ3|7BHJm<_s373 z5jhC>lOphkF?c5P2T##0b*890S`?jlN=YxaL#DuurtGZOhWUJ+M0~0yMG1(jggL1A zQ|ah?h+hYDK=IVF@IS=wgxNO&en0Sg6z}5c5C0J#z5?(5rxKQDVO;o+J0#-2Xj18- zNwGzf$`(zES52y@nv~de%HDAw8T--VJI4GON{i1F8stO8*^>UVtSf%}>G$C;a(IRG zzYh3i>fejM55IE+JmbILhv$~1eMTAoX&`=<{?C#4|CM?-izY>@CY4rAitQTnQKXge zgeHL*P`cY4-TS4SXTm-W_(ZAjIS!uo@#0Z6sjO;Je3#}P!)+k_9HF-#Bc=z?yKtGu zq}vI&XRgqFoHTp_bd2A9pfmG??$1cW2XqAF^EmJ+#ebWQd;)x!j+a1JI$!u)SRfq? zcM1j#rI!f(4D#fo;Syg7{L#w$rnF= zzA@Z~L6=x8baw09GL|3Wp9X$V@u&E3d?o%>;0F{xF$aEfu`&IM57t}e_k7^{mPz;+ zddQPQuGWFBY`M?{+Xq)4^0hmI>d&ip8jQ_%ygPg_eU-qigBei&&-n6jwDo>J{HJRr z-p)Im?8ERMf$3HJx#H~o6923ZA9tARL|zM}yS-k*z1sOxd8>q-W}o8IC&*Lb_G~Bo zA6qT_&vE<}lJ|Ze{t}mPPhJc2f0q8Q5&l)m*VPyDKMqs2M)26`mFFb*S0YZO*NOkB z>fM1Ucv%O0nc~lL2!#xPrw{*iyxV7#;nV*k@N;0DgwM3t=Op|ehyV6w@jvS%!)N*` zQRWq!#XnS}vL4pUb-*9qDtIa<+9yyinU39{OQwYGyGoX6mkO6N+uK3)f1UHMknwy0 z_@*7gA3Hx;5Anrlf0BxyorRV5X&Ug(|K}VY`OH`PuLj=i6#lo-(f2TYEx;#s37&14 zeNLjB?t}l>?c)DUNXyCix9Mm6{#^VA+dZ3p#3}Vr!QZ0n9bh?513vZ{!Jk52d;;Z2 zKDD4LIUsazvqYJneC-VTCHgh$?_uW!{ImO|y~Q6Lb4R2S_*$66moz>nDYp!7FHH2y z;(r_7?c_-A3_e=Ynj#k+k}J}O~34%4UjEhiaY@~?!S!3Tx^ zLdzUKKKWZmo_)FTEWe$=#}x0i<2lOjKF}>wy31TR3Ym__fj{yU4ToX!@$#*3JuQap zmi3GO3&gkg%XCfyzWwh7Kha?{olHkH@M{%+y~F27M+fNAO6SR;FTeH@|5)yD7>@^l z?^XQWzH~B3#^WjAQ{NW<@1Y}~Ks-qID(DU<-TN#Nerhx0PL6jej~v&fzbpKxf@vQw zUr&_BTF?(EeX!qT{5uNZIj+m+pYeIXhuK_CB~#DA%y599~sr??p9 zr*x-471};tI!BhDeC-F*OEdJegbz(^d9=J4E=}y81%I)xJV!JBqTih`(dWf~>3_oi zBk(_@{-49UeMXt?DIh)$lXyYGpC`V(Un@U|)6g#kKjVb>WtUeaeAa>{{cEA;7{ETG zj1T?qrJq;C|Dg4ZpHcd^^#}f=L*n0SX9DuVbiWF^gTEI#uRYN47>~)UUy6TH-A5ab zeDXxT47>lBgxh_Re3`y=FayQM>^j9%pMU?niRHE%rgW^(dE+B5AG6Diabn+Cq4d|{ z-9GCwJuigA)Yb;}8gsuf$JgexE9MROzgT`1!yeP<&MuR{S>r ze?;+<0{DFSO};eIAO0abztlf*l`ydp@auqYQaow>5B=|i>HV?rFY_buPW*nD#6RW6 zvz#7*NhnObX|^4A@S3QKTGfzI{b=Ey{ra4s(4#j9StD;xA^=o zb~vB^-N5&qE&Si=@CxbwJ|8~FzY_Szf$yCn{y)pG_;~qJSe`lV8#+(?W9uX9VLo!) z*L%L;Z*bT^Ig_pybjz+5x&?XYn4WE*Yf?HdKb5|aJeJi8|9^J;kxssnFY}^wrQlsQ z5XXo3bucB0_ts(5f1z-PRtR4lvB-K{xP8hum4(fOYgTEzU3;T+^uH5kpic13Iq>^| z?^!E&uYL3Re+2LS>jd8q)jj{?>Os>6!GF3~v4QeqJc^NN2RfBcU?NWZG~kcz7W@xU zhW63?V>s2oAG}@goNGFKu)cMGZt%lGHy-c)hvDpn+rVDI<7i3NL;M54r#~+EXI(s$ zig>nvO`j5cBEX;Ve2Mt9;QwW!dPF*c@#OfW?5~6_8Q{Zk<^zB9yMlj*vSGdBYb8tr z@Fm|9{J;9}qZ!wd|0m)9p!)xN=U*Z54+G!+r0_o@2mWav-jjEq|5r!AvmcoZS={$i z;XnCQ^@#Lk&--N;q)`2d{#y97yLkG>Ma-+{OM+kN@CupEbuj7Q2%dKTL;Fq`hxgBi zNLMIcN0e`%+Ia2BVa3;x8J{(o_J;8)d0FChrA6ZB-GUz}T#^>ulB~5mXs6u$ZM6AO zw~scGKc@BY^5eGu`-^})Qm!kBUm^HfyxS)r*Q9BI8B)4$IzC>xj@(}`ocmy6NePE- zhJ6CzFs@I*l)O{uz9>}QFYzzIwATr~)M3DfuMB4*c<)pEOczd$c8lZQbiMF#WR4yA zaNOIg_^TZv2Oo~ZmNf{US&mNoY4YJXY^~xyS*!#(()~E-($@-~iya?@O!o`G_bI+3 z2cG@0c~|~;us@C}-jmB5>0y7|-7I{9`!bA22kXD$-;yI9dkf$n@Zoc{FHiaK-a3zl zW6K|S7eCj$xM&bR5$%tQUoQMi;MZ#Wr#p{6{}9*z^N`^m@sk^H3)CQTZc& zFYw2@1y8&Gq5T0Lexe_V_ez+j$Y1>rIz0G~rv0A@`iYRSJvU4E3w-g*)&4R*m7w2u zi_pKx7am`U=l+_*ug!tq3H%ZDe_;;%e)_*v_%nX~hx{J_{($0x^Go8N_4#-0oa0f6 zm*YPCy(gr1$c~m!4#~F}x}8GxTK%@8tsFO#!|Z^nLdW{b`O~A@Lo+r@kim z3mjhCafY`S_#VZ7$Kms&kNh41{lGVcU$8x|1pZm#`vw0mc(;$oZ)CY8|0yif$Ho6e z;@kTrz7qJT;=kfyt_1EWn1tdV#k+k*8DH|Bh&cBDTEf5H z#aG!7Ka=?13ErE(My|0LO?)lzL$3+`I`wC6&6Gn2@n`>s9e1)F@jvvx7x-8#KmGyY zX9=EZ^*{9g6!6hig2!vtL;OqhUnh9BasG$#nF#q!DgLhB1SMf2QMM_+Pe0{NK&6`9!wcj3)o5fj_MHGyW6(5a(+L-X;9K z@ebk_oYzthDSDmIebz=I^TT*j52;u2A9AQj%EmKay<<7hZ|S>*uQv}1l*3HWRKuj3 zh3<2Bw~v>P+4YNjx4|^E3jIj>L;FE@MCn}dSl;*{pGRO07vRJAy#SNiCgJ@7@Ak

    HFzJCP#PT>1S!0!h>od=&UpIF{gV7k@cRJ_|KM}4RUBJt0XFJEy91Rd$~ z@h5MZ!_SMq?*;r3R|(Vog5X!+-9E~f_;oM`6z|`+BpvZPiT|beZ>A%k2r3i+<#a#H zF~#q8;RBsLKgj51uZqxTAoqLDdRH{VN@Iw|GDNDGkthBjL=YQdTN0$Q~yDH zp?o&#FQ~u4a;}7lDSm?sFwpKW{w*-=O6Sc-{p;|+cPrjyk7Gyw_xb$0?Dpdyhh?q$ z&xL=1_0J*ZRUv z;JXzcjevgy_~Z!q zXMsBCPH z-`;Pbc*RbWaJ_n>KBoXOUU9_-`A!3l@pAr0YOi*Ku00PQhI1cG_vsRkhw$!y3da9T z@i*P?3GZI~6(7{6cJUul{2J#!M|;comrV|okJ7vNA5}coz_T9WABX8aOZd|_?KXMrscX#TO2;n{^Tof#*e0Vqxc`KoD|}h{IKu~ zj(=t%tV)=K;(v>G`*`w_J>RwY2ZHF{K>SqB$!{+iDE@W6^T{KxihqkkX!?ln@Zk?Ryh7sl z62C8Ze2ISm__X3(xw(CL;-3OOx?lWz>#fUWoJ;&mz{eCHEKlOO-qfdfkY+u^&jda_ z0=^db-VyK}!1s)R-wS+d1pEWQH;sUQ3i#v*_?LiBC_dLbXd+}FK7#+5z{f_w*8(3M z0pCFx%Y%32nQxz`A}!_mtSgns-`Rp?xm3a&Q~V5vSGmi_*OC3PF!9^d3}q!ceUgP0 zpB8&uVbj~otb6+V6&Cj1HP6CG`EYrsaIh7iwb`w{9L*R?>SxgsY62J9sB;-);)Q<;9Fif#oD(h>{fW2 z!o3RbRG3!yWrYtb{HDU_uY}*Z3a2S7S6HENk-}Pq*C=dKc)h}H3U5`oN8!g6?pOFl zg?$RYq405q-&c4<;qwY#Quup?=GPMc2?{4GJYQj%!nq176)sVjRQN81Eef|N>{fW2 z!o3RbRG3!yWrYtb{HDUg3ja~zvkL!3;gG^VC@lV0NzWvOr3#&#ICz1&&s4ZTVM5_m z3L6x@M`63dPK7%a{+YsFg`ZJ)pTfUZcu?WD6h5W!pA-%%{I$YY6~3Xc{0k3g`ZS-kHP~A|3={>3csUpK;cgnzM$}Bg~t>| zek19asPJrsF@-Y}&R2Ma!X;Yok_z9YaGB!k6s}X)rZA=O7KOVNepKN;g`ZRSfWogT z>{s|bg-yhdS@!s``oQ+TVwJqkar zaKFMYD(qAE4TX;@{Jz2?3ZGZ_lEU9BG@8#76i!xnzQQtva}`!9boK3(`6ag99e;_y za}-{vaBzdTzo77F!2VLeJ`}LO8n8S3F?BEG|9HT^i-&`zB|CnOzrz;?@Fi-WsIZX# zsM1YVSQ@ZT3D{!+`?P@F;mg#$kpGzh|1KU57V;kt_@A%#icyANsdNd2)dBmmfW0jHS^?qE{@@Ax}>O90=l_6~)G!cQsPHig{*`_6#9Ct%+lusi%7 zb$8)A{toZ#djtNRyMu+o?+y6>q}un5GW`8YmsWURzp zl+J}8goXU~2mC*-_QMKY{yDxu`%_9cpz!H{y%7FLfc{yv4=OC=|Al~m7Y_#u`9B)) z|B~8=Mj8IAN_R}*@qj&upC7=RR%xG||6;Y5C@kcEV!*%S<6ty^4~9QEfG<`16os(> zKIng%;>#4y4A_JC5>3COj|b@ItGz;DA^(*D|BkPNi2yzresuu9OzpJ_qk;Ga{ZHB{ z<#)Eixe6C6tW)?Ng_{+=PvPwfdlmkL!iN<;s_=&jf1z+l;n?>{_!AYn@XuHKMG9vq zEO&GY7bsk;aH+z2g_{(p@+ShF-NEJGQ zbBUJpZhv@ez@2zL~He97Yhsfd-$6YF5Ud@XDL0?<#+da&H3ueVTt-* zrO>%wtM)d9+Z5iW@S_SHy@Q|5Ydejz~jfZ88Ycu3)63ZGQ?V};KtJgU&~b@2b@ zad-Gaa9I79{9N+g(N9+UTLSJEs(rS?%LDkU19r!+E|0szJGdc0*RJ->3cD2EtnmE` z_bB|B!n+hYz7GCH9(RW?1RqrYUk&j2d$s?A!k;Sql|l+<0%rdUlFwgI_@Kg{Dtuny zafS5vKl$)H9P9LjFjQ<}dqKMgb)$&&kdND+ctfmd=Pp*@DHf6q-6xc;_{!{hExDih{k+nRwtP=he*O6Hu#@o& zH=K*{TTbGAs`4Fd9+_{2(v{pQboT|)=f)imJ9ni!Gm)JSj&7E^7c1S~Jak`F_aSXp zznX{c2kQQ+(mj`l?wGnCRl2IG-0@4Q`%6l3K!zN-WH&9@>r?vG3B>54_&*u z?^S*u%tQC5%EwP@eEM2P&cClHUGzJm$8^f#?EG{2QmXEgm2OKOy7#MlhmIQ#=Arus zb>FMwfw|SW!>v~LUZwj|9=bnOKD#FNkj5*vape4dM(MgWfBujsJ!5MmKXxizLhUX* zS1y05bg$9)MB7JBZVLH3SC?P;;D1+t`m)9|zG>wAnXp94xkvM7 zhT2_xT{+KJ_fKj)*qn#%z3RSC>0SuXIepfDQ}^8(Zu!#O^>2~7rC75cZ@9mf39?UR1W(C>2dP^eRc0uy7w;6 zEw6W|`w=bYQ?ANQ_hxnfr1JYo9=ey+eNg#zUY*S^SfBPPzuNOtd^_cQIOYJTlC(CcN;r@5Y|16Dv zeCx>aKiYU+sr{L|`>wk0(e>j6E3)O<@vB$&1G*0R**tUy z)qR`JE6!b+o8M^D`(Iryb^|Zqo2z|_ZxMesC2ik$}OiKQTOz^+-oXsul0-0KR&eJ zpLe=;%h8Qi?)#Nr^1q1RFO=U<)5!62@ht?oFU800OF8%-8crlB`FV=M(-fYm@LYw# zaHa;_%hi6V!X*kc6{eJKNbThF9rL^yNS?mqy01U> zm9HFoa^=CMC(4fxKKj_VPTVE)-_<^ZUjbAR%sU99`uThzW^_YK~! z_I+yaReM_P_o)3owSP(N=DpINeO>LvYJXhq2bBJ4wLhTt=hfb)_LtTEu-gA!?Ip_Z z)Q?I0C#rpl+7BxIOtn9v_Dj{?ul7Z1e_ZYFRQqAIH>>?Awcn`r0k!w2J*we-}!)62p(IYZ`v! z1~}5J>w!HD(+@M4ad-GHCEm(c`*<(T0q{!^%f{!D{rceb{UZ|GQ2@W}!H$0O<@Q`b z+klpR=nfF%$J>gC%E&tCA1An2#@&m;zh%Y6lP(dt`e%BieS+BCcly#3#a_oohxkci zZ*cag*w;Aw8DhWI*(ZygcQ#u8XN&#a&R#0^MrS`)>`l%-MeOdo6Y2BCzTV+uVi)e2 z-}2d+_y3J=Za#DF_auLcKP~Vyg=Z<8rSNivD-|{?>{j?;g`ZOB@|3d1HkXhhrDA1a zJ1loAy^5E)SM7ZYzp3zh3ZGH6+)8q#z*s`ywF#HLH`(W7S30}k9sSUitL^jSD-od+>LlaYgNs8XzT%Vb zd}6RVb3Wet5uxuR5QY;p;$wK&qxsetGYNDgv^cynd>VG|EGPdn2A5M~m|$iBb^@-( zplUY4dk~AJNf0-o1O4&@+}RB{0G>mD|Bh@O2ISMjAGr50V(`}kV^A-9V9M}%0HzGM z12AR49e^nV?f^^@xB(b`w}iZtzzx78fg6Bf{NZfV3}Bu(bpPl7^3lhJUwP)xpMf9|QWKLyrvu32%pnpLm7O6T`3b zfxkmvd+^=|zjkOCWO#NBANs`o_ml3>p}X&Yi1e@=68_-(sI}k!wI^-(^oQ`DAfH{9 z?<)+)(p&J1wcmgLC&=#^M%_Y?4)1#XwO5{FJn!YRYk2t4=U#aYpX%84J3g>8rM3|5 zPmz1I!3@7L{LC}YSf^*6*@eGnhF^K?!6*Lp_E(1Qy&HTV`rYtz4?g%DPO z_19ix`d@qTnXm17?KR~4?KWS3@!X>*666d0KldE-jsJv?z5d!A;Ey=iPyi7wa|1a5 z7vu?knHz8e{cDKcE5jwxjyH}UzqJGKw%xnyI*ds)rMf#7y-{5jjg~dMVIswQlChY1 z%^A{VTG zqbUae_BmWyacf0s$?q?UR~)a1$9^6;Bl^b9iZddSGb(nz5w%~7v|fAUc_Ug<{6=v} z)HHlq{uDHrowtF4q{k5iqN`67Y<5;e8Am>El$E_~UM?#$Z$u(<=YmlA_DJ3^!=8Bk zF~~E-93pl*?3D1wAkUA%{uuFxcESGQ&z`%T`A$1>{0X5ygq&mnqP&J*eC@T@zV-uD zp0C{jIi@S!hlf!C?x*CDKOy|1+^iin0O64zB=z(6B4D^bh6-@|@N*3AXD`AI@`s)j z2>GWS6@ZWxK->`@lrxHV*YGcX@Pm7Q@Pl7aPVIBYi!c7}#TV}we)2Ct%IE%P@HaeM zQQfd^ZKBdd%c`q)R#%(u>T3R*it0onQC&eho^G=}G&GQ|y1J#Imh`Yx3xDuUSbM{=`8Is|L--Zsv(xg8 zG8{{9L7BBTG<1+(8KZ6?NXEbxVTR z7+)B;K0w%b;-1Rt+J+XSGa6?EDqt@zwec@5DP{UgO3Rk*#8`4?qTA-{lvn~qf_$NW z)JxyTnT$6@zpzFFP#?aX1>#o9Ip`iYUDNx5ane`OG-+X#Zh^dr69+2r8`y}8&CrP z$)6DZQEt|b8i4S~50bjB2?4{s5*45u_v<6LX}$#?HO^pJbw_S-{x_wKvh(^p;P7RBRk?ipveOU90Mm&9V#(#7M)yZQb4xvM2V zu5Q)JUA^6QH7Cg%es@jd#_J_NuG90}Ai9?4+CcJ{*s?J3bAR990R6s51nzI#eRp?5 zr%vwr4jtU}ZQHs>#*A@)e(W*#&VvuSx9+*eefr^t?mOq)H=?ga{}rwL_+xk3_1C-U z^XI!+mtXEKstH|vwVQp>MQ)ztMo8nvxq0hBbBl`H!b1*m*GLvzwe!x^(lxv6;udVP zjhicZ#`7WzHuT+k*|Fh$x1oLRe^)zw4#vTHloku~zdGOmckjS~?zNk4axdL~zkBK4 zd)+&aJmNlj>#em|2k&dX{@VTH^Uv4P*INJ6pZ?_LUv`bb9~DM=PyrQclBs8MJ?U_-1g84r8;Q9HbB{ps7P`xAb{mR}&cPCD@JK7HIBhaKkb z=+(>JdBhQJ#WmNs4_<%Wy)XJgc>dzw|91cQ?mPFd|NB4p)wkcefBfSg>(CcpeBmIr zfAh^Z?k&lP`O^I}!T+2&HK&@&ib{@~eaR&i@?yaPH>(<&D;abC+_|oN`gAvQ@?T!VjsNwL6{(J`L@uPVL1ydNi-rG7WOK~9^inqqU!|rb+lFIj>vwa{Ki|!f z{FpO!YDja>ImcZhJLF=u5X(QIbI)~iBzG>!%yd`my>}=JuIS#~CDT=V?&+@9e&`C> zD3?mk%#+ zliU>9CwW;}ZoFctIf{!+ly7!PLKYwoQqi2m_F3J!xrK_0ASbZ>JVv&>KEU3;ZU6n< zd%yp^drvXDxBmQR_oZz0FaP<^4Z?a9_qM#*^?wyuUoStTrss*s4znkwO`GP56pN%K z{*jlL=d!c2T|6fzq#U)micw6K&2X;d#5osS;Lg#p$uw2l&(e9alo!d-IiPI)E^JxX zGUv=uyfhV!)9-S192D1iN=A%u3zehwcEFa0edIm(zx}`i-O8t*cCW8o>Hhe~KZY^8 z5WAJw^M>o1wp$$jBXT0NBeXtO`hU7?`?9h!H$}cxzHF^b+4*td)Cd`XOsJBi>p3oz z8DK|Ul=T-&pB%*m&n=Ej_IiW_~>Np5sup__j2!R{9Efwuv+JQ-m6 z|J~pH&aHU+?F#(Y67EetY^nG+KO(dNF22}ZAl-eo>~(ZJ_|FoS#|f`dGFebv8~x2X z%LzGP^1xcohkbFTYA*&17~qale&dM44|m6%e6lMQEs_sNEYZt=ElUQ3`d>M{cV+*- zUXSn}#ZGN5ZxVYyN#EQ3Mz4kbzf6ApMXF^${})Q{ro#U^SWc1+8?(>wkIgZ7@L<#VcfnP;9^=h#Pf;5UqrzYq4I&<;5ANH%eZzkg z`|FF*DE3kbBWE^Ly$XN>w|6&2RobzWv7N@eTPcx_`W40WswW21(y% zWMqWc2mgKK2OKM#z~g_*!@kA;i2vjNZ*KeFun$J@k%tT!68fp|YgN=obxP>7QKLq= zF{(pOMWaWLb|tcNFH|0l7<_d!OLd3X9aY&AsrF&pgL%%6z6X02&ok_@Z9~ba~TTj$Q5T}Rc{9jrJvJ}FFV{e1Kx5`>DTdnR7>Jf7wzTW9`2C?(2?}k9~^r zZODbwlzZC{I`!03L+npbZ80%~nh>}L|HugB8F)9p-|PP^1N(+`!#ld4dU0aCjPaQ- zx<%M|Rpa(vQLS%%z(29FV~#l{#6S2(zcIff*SU)*GWB~GKplSm>{(ru>Pla`Ix;Kkx8P{{U=mOE%!qZ~m z;lZIp-I8I$+^fI&jeAu!{`C$2==EJRCO6PMr=qm9G}p9g)0EU$;~9_<+o&eKWy_Xs zYt1FHmF63PSVul!SEM5F+d*TS(c@qqSpeQmme3+kuqUDf#<^!~5+k!skORqtyf9f& zRm(k^ErTqmim-LK_n~^X*bCSl#~yoZi2bPV@9qDemn@)$6TJ?BbH?t@5{(y82mZ+L z;qDRH)t8AMCaV_Ze$g!&>vQuhx47Ra{`cC7748kmfX!|HNA z?#c++f((gL3(a4IErMJ@zenQ|$doo3|C@@~7bWBxz6!R3$%?94js@41k=Y*XM+Ok{ zB=0~A?y+CY?zh&*{~M+Zh>p)kuS1uL3PmM~ncXdU|2x@ycPQsONpa|VG*18D|N58v zQe*O0i$4DHOZVj`pSb5WM-O9DmOc7tSo;^&|88dgzb^5=vGOBXF0qbGsVQx%@i)i> zWIO-<`DfqOg0`qi{ai{kN^6Qf5zyc&%yX* zqIn|b(z`=){SLk7Un|bDT)y68^7H0v?8qX`&GDvc`Bw|a@2_6%{{GQN?tRgFfB$

    W5F}{;Ej_hvD&$UAO|4ohc-IDbG#^S#=exEEuDmy1W3o?S3htZBZ?ig-E z1{|ny9OO)?E4)N=9z6HlbD<2t_xJd(|2VgNJUC}OK6Hr)JN}oF-Ak2QdO~@mC)K`w z^UZFxQ2eKBuXQV>+gbkjtFPQ=qK}06x2WZnEl<1h-FMxeHLh=^WWuYjyy6~s-~o3P zbMa}e3u5i$hVRumUVH5|kAL-bW%#SF+nZ>vGVB0iep59z_;Ssw_RKTSg!3(tPx1J# zzt|^cXY=Zz+iz9w=t0dPvs60$LFIXVukm6le(?+UciHM|gmLE9TCMqZ-k1IUzQ*If zty-BCdf%^0kN@Ehe+b|C%P+qiV*DoA0Sh#q9DAA?H0sf4$p=l6&Ob-H(+P(A6JMJU-1W&2%=X}jY@$9qDhO)!^{|!(7 zBLj#Jkmuul62nCY;Lmyd*I)dD{X11lvU2%y_ZjxP=G*zRaQ?RP@b3zrf07J;;rZv? z6Tkhfdq{D*TNJ0K{`@@o_~4we|^tj ztGi5Nu5T4)-w+Pp5;k9v%)axEJKQyzXOs91b~|=@f#$7c?ies{%fxlBm)^hi)>}j0 z{Wr?rKdm`DUXpFV`$ztR{l_#XH+r9QVGCS&<&~igaK#l@gt7t~;S9--`|i8X`~P|; z>x;Ykay+p?{5p^S`ic2y%{}<19%r6>wsMVgxm0mDunZB0e^j|RVstFucH3>C-p8-I zL$cwnyY33{jt&393onHDCUys&8Fzy1kDNemU<+XPV;5rM+i&mJyxsR`j(*np9Wv!X z)&E)i-{$S8t+uA~e^~u*L(2cvC;St~_4sc%_`ggwISZwmACt|7--Zqc)97wuI8Q$L zqTNH{N(-C=>V{*v0N=etq(M`1Rl%S+ZQQ z1@MoqMYHjF{|y8GjKP_w8uPf` z+36zQ9ktrjYl3xjGI4uie)#5K9Gd`~6UPJR@4x?k7_-B6z-Qn%bU(4bUnpm2a)k5Y z8_+`d2E+=<|3l10g|C6`CwB0GVvt{{j-a;cfV}>%8(A`3_1)NvKK@s~WdQy^_`g{A zFO$E1pj_SpZ_Y=LoN@#N^R(}~}s%YUmp0C9mOOO}K&JZyb(0oVuNo7VgS@&Vu< zdjT23Z;>GuCp4VXa*l@|emKk-a~EA z|5wZ2e?hq#Fb}qg!+~#Xbn3U!&&2J)HvS#9I`Mk!1^fYGeZ=_89{|7j0n~q3zK<3n zz6Z9E1r}#SHeeI5jbo5M_yEKPzEq7-ZO8zR|GL3HW2VXXV8{9VU;VWK4F3x?PV{Qw z`(fGcS4a*ppA<0wYWA?v@y*fe=yGCw$OCHnz%Dlbhx%Rzas%I;ZO9DrhRmPExybu* zJUIm7faC)q;)3`GTn8CKy*N1m;(y>D`C-_v4If}j!hf@%ncJ@EcCKZ5OP98DTAk$+ z8AEWG#&Y8O@g6o@+%|6if8To=ejpQRe@TU5^vrir~l_~4&@`e_);dtNm__;vXB zH|sd$0J$=90oVl04a0m8C!BCXINt-9#t%Sla4cB2S|H>Fyn%hNhWcTR55P}AeqbAb zfBX)<*ZVJx7vz|Yl>u7{{=t67{u-kpen4~AX@=$-Ti(re{a07l z{>k>P*#XV!6#vXsLjK6(zy4yMIw0(SzPWgz=84Et&DQye8Xe|n0p}w}jtnu+9GHyV zCWePxr*@w_9`-)@e6We1j=ccZ!8n-3|D#2hBTw)L@C!H(b^$&GbHicxV>b{_AnsuJ z=l7fsd4Z4N@n5z7-fZ7yuG2G}T=&nqyUuTRcHLg+<~p1${l9J9>VJ>_`i*<50W|zu z{_hNp-DiGQbosA-^{dbpM>mtZ$0q=XmIuH$2d7bAo_b;Gf6VT;d>^qv=77ULn4#~> z5+AS{JMs-1PBx9$Gh)|u|7jsW|gc}KAwiQ{_vzy8Vs@Q?q0)js>Ud9w2tE9Pglf7ous-?78N zBJ*+)+sCfM20%toCqT{~{~jF<**uS69$A1)xZ#EyLVE$fg7Z-`VD>+91i6Bo!5*L< z82oc>#*T9z;Qe#W6$EXJ4EQ_$CI3Y#}CyZ$Pb~`Ty*Ls6U_v03U-oqmA(a8an>dw$~h^ z?V7qKyEh4`Y5S%wtyM*Af16{raa~q)aqS<~+~fuAU8@6Hxgf1>u@C;4pO85~umO4B z*l>RQU;UH=rvHim&zA2$LpA{RIeCBTH*IXrop;_D*6v`VlNSWrIi z0W2dk@Bxq^#1DxNV(;@Cc*5|HZ$Z5v$C>?)+yMK;6z~D4CEnN=KtsiU+O}z~MS2Uj z)6|_@yW85i-EYu0NJQ=KXymuf#{ZT2cEqK8lTxucbU(H}ae3l<_yg#2tN&r# zKej)*pK)H`9Q&U*9<@Q(3SgaDAaaEG_Q(@t3Fjh~0PeB*u@50)3S2AM|HpU47l4Oo zw>11W4m59g>lSWD;l9Je9bK1K^oE0q?ccSbzY&T+c%;QEpkhnZ{KlwSZ&3@+iVcZV>JvF=3^&mHxzX#kB_b2y< z{w6m-9*_Ot9DAR7KjZ_%GBO4K0^0zrn{9v{03Q)2u(%(3+?Lm;ZD{&`+a0!doi5ef z+<$82x~<&Fb$PXe>-=Iz*ZHM3BDF7ebzS7^cl+}muJdzUg!Oik2a*wg*~4{xOWz_& zP`8!cbzC>sQ89rwbK8WrLT&r~(ep6}0OLnI{_7|1ljHxh_3gSdmD3+}(n;Zb&FFLR z&Db0p&kMf6BK|rte=v&fCXR=1j*jMiQ}>AvZ!rOCe#jRR55m63E<~1KJ0M5!5s)eD zV_Ove#0a<^^5o->KMw1FHWd37H~i+CZ$epuFM^Gd>N~oYo7k-5|F;QTn>m5oW>-zS#Vas|lb$N~bqIdO8 zfXjAqP1-ftWc~nSfIa@}H})<5$NV2x$^M@sEG*ERJddfi4_t$9!#LQ+cBeKM-HpyB zK1ePAT$9fO!_)$y!xqo2*{{kPt#upK9K<-%lAN>#hi6LQ2 z5c{JJ(Z&OAh#Y7r`aezYWar^~xo)fSU6-exaGjTZ>$?2reb?pbi$&+TE>Aw=x;!(( zb$K>NbXG{6pE=7J*|uog`Pn?z`KeOZ<;9_H&o4B0w|t7I&aTa6kN^6QeZxQXKji<% zDL+3^7zLZ)n^=A{{>L`*csBP3aXoNtF+Os4=yT?IG=CqPf&3kHe_$QE0o-$LWQNrP zQUA|eBFr0wj4}H^nj^sWzy|=s|NQ4a!*K!YD+3w|{#)&;`n?5DyDrcFpRoTw*X2>? zx;zH`+jUv?UB&vN->dybB-v0y>io!mT(_4$)OoYr)&n=qcZ`rD9{&vs|8r#jpQ`V& z4jVDTjTC`n>~`Y)V4k@;(8uKMsqM3I0p#T%=ILP{xgIc&tRP;99gU5R-bepqBM?Kt zPGH?+2iGHh$o6FW-(&#Sr;ZTY1Y3Ywfc4DVmDpGvUNnZ=|8%mGsx5y3J-|1Yx zcdpwCri@6TTt2^%4Gw;Z*J5jfGxBcu_2^|{`Pc{e z&gg4mcHo#;0eJvyePV^w4^uD9m>}!|aF1<|Kh1BEC*YX)Ao7H3P!qs0HvY%#fAAkA za*f;%cEx9(eYRe8fei-#eR5s5+lAX}M8DVo;&%^=o)ZcGofkXT^*ZM|Ed0oAb;z(y zihYm&hJ}Cp|AqQy6XSnwS5BW;9b5fJ9<}+5>1JMs?YAZJKEkn$ElT1sV+g4;21q3b&F08$^@!yAn~c=<-51Sv%f_36|V2xY= zcqGpcVUJ_GQv*OvAT|KM$9^EEXFfg{XS@LG)CsYSFF^eOu?EH&BLm1UMB{&keOlxQ zgsj0gA@7I{fFDqm-nV@X1^?Uh$aCF=*UqK?k?!6=n)HL~QuLkMXXpoR|K9Jo9{tw1 zj{9Bb8aLVWJ?1OpqKCuJr0p%=?4wPkj$DJR|fzb9z(rV{>~G$H&&^ zcgPXs3b94-jT|xi9~+^%_`lfz;2*;02jAo!(Erp1+1S8TxVLQ$1^?T&9^!iJ`$u<3 zn-|={yFV*>ZUacaYx}(G+37{svx{Uv*A*_k^Q*4)cG<%Jrpx{L_+P`&{TBbn|6io| z|M}GWDPM<84uM~=3udwNvAc=8gJt9ZL`@JFhsgP(>zNA-TOV9w=SOV>YQoq@&VW21 zaRp=yGJ)6vHbiv%pW!~*f`1!RMm+#N05L>-2IPQYJyqLK@ZTs%bDg%I><-@J6SsG# zm)$;{UfpQgv*W9-clY<)L2Yl)xWHXEsSV)m|Arw0%>KVzqynN$PjFP@_AM_h;NVGPfP)O0K1O>|CjEZ`&FQ{?VZ=S{&+z?6Ja~wAX9ym~KzGVcnkIC>qrD zS(mrZ6Yl)|9(70WKH0Tuyy@})9{&vo|BU~^{y&2ppYnUu?}A};HFf&noVq;lO@5wS zAF)B^^rgNBpB|flaed$#T!KY(v(5cy`9J)2uxc?wYzX8Hu?5aaPO+-^U(^o39-&U* zlTSVgbv~`-0S)iTZ9~F;5HxYUcO2qwIp{uj*TKu&jp=u~n|j=}L9|%EyD|MP_p2UD z+}%Czb$9f9*iGp=(Y0ybW|P;%^tqCbw7}F#v3H@QSX*#s=5q z@2T4%&j+^I4*od~O!FIlORX?=y^RxK8Tr9nVAKj>OEAU|Sz~p9sp|itxVL5O1#%JC z4qzW_+g#zvxVQC&h5x`ck!&8)x}RIx^Dg(u;ZM3Hhdt`<+z487*kkTC{r%W zzmvKF>V&8lf|x59tP|Uhju{}|hg_gm82_CZ1NMJa^*@GvTJ%3M344NCB4UBntV~|6OgYbS4XT4 zT@7AsoG|u3b^$R4#tkNq|A}Hgx=b7p8DRMUu>Z5fzhnU80Z&xSeudhVqL)Rlh+d5l z>k#{Fzis0<+qX)~FX~)Js14=ICTKnW8y5cg{txV#Rk4^5~ zh`Kv`0_+Bp8_Wep-VpnMd;s-8;2T0lFwP&lpYg%i2+T9i*dO8zHMRevHUPc|v4!e# zfDKarNANjP%WsH261^retkb?EdPl^*4@G|$aV*R;ZoT!^e*C}s zp}zYSrvDeJ{_je~`tMb}ANn^+#N+YfvH8I+x}G?o5tt@sIC$`2H*DCj(DtY8*RNmr zeGtY0kq^M{M-D*P3TFEgKg1Tm=ipp5iT_9K0OA119ee@9KR7p^KiW2Q{9^}z-697}1%cWg=t&`)QYpdWtqB_WAzTuDk9U=5omw`}x1>uN(mX_Wj@K z`i9SR`Q*gbT`Y$0Ad6+_5Y*#-^KzZV?Dagazn?z;g+~yU(smM2?;t)?XDs_hPH$T zi4GJ+_iu{jt+v|AbyGZvS`Lr@`ip&R6Y$Uc9~bHSKji-xX-N5Bst7eHJdxzD%(^fTiF;05vnv~1&i*Z{;7$t7Y>q?-RL zs_T=NIS;V};tJURruQqe1AZ>}-xRp5t#dN}cW2EfNiB%SfBnb5<^L~IZ10!y_lf!A z_Y?cWrze*W#x34vdY9N6_`~j|Mi3lh%Of+W3&8KkSFrj&V*f_O5V0%p|H=DNZ$K`P zZR_j*bAQMgQsn|X{x?1Tn>1+>e*c&JF0vUy22kHcE*M`jBO}8N7%*TR>T}dl z?pW1@%s%KKcT>VPt?%)(hJJtG|3=Y_op*L;N&j9dAD;PsvBzo2;eltvHue7G^RVk6 zo68^EVGDr4sI8BmfRA9~1gQNr!r!;?0$dB*fE>X3=zo(1*djJhDEW!X<_Gln-}LzB z`+q%p^a$sW;k|hL*Khrg{Xe%|yYTye%Y;>QICw=rqnGj7!N27MsO^gq`Wl-b{Mz@z zi2YE@%N)QEetohZK&%hjADbWFpBlgo!9OwwLhlpfGan#TJ&?zL-Qb_^|02_g1L2!_ z{a-(20Qw*N&+E{^O%fh2(!5{z?acoLhELR-pycGiFw5YRTpu|-;{VkA;V&?c4=tF- zUtkQejT>U_Pv-h1ZfLsST9Y;C?wXAMH+>&%(J}BBc?IxIjRN(Aj0;MR0eJk^4gS&p z_=d!UJ^t$__AUM&+W$N4jwYC_=pW5*FFC0H~z{0&u!b*6-f7&tNxDf|KXdX=b5L6T3-7e2)dd29CC!{ zec}Vicv{Q<5y!_qU>tzu|Iq7I5yv3|*0=uGYy$9)EVA*%$N^*kwME1Om@Cv|!FS(% z7uG2dv)~@S$}uH0)cw^+F5`yaeFa&zcV zYU{`au+4IR#M!|%x)$tV3sCQCgj}E&7~7xtz`3d`M!!SU{a6i9w8b`H+%Pdl{EPLq z|4jzaA_KrW;|z&0po5SJJP&e-eb}Ykqu2knF9R6+L+yyif5X7P<^Sf&|G!qYyN%DW z_`QwU0mtZn!!S8JNwNw}=mF^8|7I4b}fUt4^veed&gHtzCB6#oPbFl-bzzxwZPg3-!+U{tx5-u!+&p zjLpG@M^7@B7q~PVpL$+me&7m<+TSc&EubyiI(USvW``Et3?4ZjKEe8o|4Y8EotNuD z?C1Q*8S;V10DJ&qg%+c%N&K&)=11$)sgr}ZTeN85TDENIw%vByTBGf@+s-v~vi>;q z&_lyq5B*O+lb68`^Yy>=PbPqWi~moM&o)tYJH+6q$-{<&sL{i2$2K>@zavga%pS}p z$M&fK!am@gW8)JCpw^ez069W*3f8vqk1Bq+YB>u;o z1&nzH`}^*@uNydUVCdUe-4p$=A!PkXAF@n;Ta4BEy`i<#g+bVG^euASWIg>&-j{y! z_5bxp4y@Jxty{a1^5aLyPd`QP2wt@JNi84wd$3Ht-g5aYlOH7hmps0QS^(mB)D44c z;)&DqFQd7FPi~4V8%RVmrbY^b;+8gSi)U6!c@qJ9^=qPH3I51t`g#^>gE2)`d003Sfq z5Ku=%{Q%?tXt@q}BHy^7`9IVD_!3|rn-gCj8DlX3_L0A+iT@8S@q?&?U_J!w7;2f} z@#!;}OlN+cG|Au{gM)W=WoG1Bo zR?Y;MpIzW`^K!%ITCi{HY-@;Q_m8j0{oA`l*Hb?N?#UB@{r>&?hvdiq z);->nW08jcc^dym{O@GplYAX_KD- zvIV;kz0dezYy<2FV*mII)EupE{eKkywu~GgE@|?>VvJy)TtiLpZ!(}lw#{*q%Sv3q zNm=g938USZDaW{RV=L;U=!f+s@M6>u@t*3Qc^>Nr_+`Y15$?bP4-94hkw+fs_EL?> z(MKO0jtxl0zSsYoM-~|VFBbmGgyRdP(=U>Zi>-^kV=h1Zc(dJY3@|M?WzJ6gZFFsv z*oN+f@Cn#w+ssE`9e*7=9p3@pVtwcTGrXs2!9K)3!#}xy;{P?pKlaU~(*3h9nC!-# zJ<*MvS?CUV-~`v_)@*mS#ze-)RmAU7;bBYPhCIObLl-b-B>Eql5UevkC|L%0`@imG zfcgK-|B<72b%C%C?xASip4IO~TN~%gSYdQ!GNCuY4`Y9c6EZ%4Wqb)6Kfo9x@LwD8 z|5P%-wrvRhx&L#|J;lMTcMs3$-MkPD>dA6*P>Z2r%%o~kwcTitS1`XAgQ(`fVa3nUj$ zbSK0vbnQ-9?RFmegKORY2iNY5kKM5)^WB7OY=DO8v!{BmwYd$f8`*hThp$rE0ABys zy-YCspYeap|FJ+dKlth9qvM~0(PSd8hu>~kBff?`&pfb~v2@~r*az4Q5OxIdLgN3#8;A#3 zEl+K=;GetzF$r>l#3Cyj{{!~1ama1ujLUI(;|kpk{qo%FJ00y-Zr#KEx_iu>edYyj zY_7+DWtdO3ojx6{d1lA~B*y?k{HuP*&;MC>a=`5W8Jhp+6z2a?+&0yFOWuYI2d|LD z`Z>nx*pTnUda0eW+#h*AY(Fr?@5l*(cZfI<`^YyCTSPxw?9OZqYuS!IhblY9j*Yfv zLr}{={Q*7+{s?xy5!+bCx1s(id~VsSW6v7z&N^eHn|oBcTXe`?Zt@9z-Rb%Aai#lB zxB2!*dp}iQ(3iY>@=ExamItJ@`2R85KdWa?KmTtXjUO=lU#R^58Nyz!_}*}B*aquH z7Q-P&dP)}@a>yYe9enV?4nkj0SAuPE_~D0#+c?Jd+wsws^YrfBJG3#tGcpDl zV6}TJgL}54yBNESEwT=&cJ=fqCGYp^>-JYte^C32%}1Y-12{_a{U6zHev^$D__+3LBGruL?^RD8P6ZM_I8JaKba=q)D^zNC9 z)?>f+uw9*;q_45Hu0sC{?-$B8o-W_MG%*ehosTb!&4v!g|7RO^0o$nUCQe5Dj+XWH zA!2_VkKKSh&p12$LWuQLgq>i=aJ>Bv8-lnJen8aruWXs)@G-DCI3K^~yA{YIYg8y*-Z|Z+le;a=PrxJZfT#WcX?--qmeT~hJu4l{;wtx|J zb<_{x2Vg7U6C@KgL&Okl4gkghS4E83qb@j^Z2TZ?Wxq$~gMGulVV~CH-{ar#u%)$z z|CyTqGfTBR6BYYn>D>wSR`T?j8lwa-{Ze-vCljA`oDhZf1Cfi zNLao`b966D;RD!sKicc3AYy_X7tJFik0T_mfPKLDL7NZM zVhq-@o$FXkk@!NCh&`~6`Ng@9WIMygB9N!VU-9^_d(21u0+0XthyPjf|4WpU`Gs(F zx8~uC#{O&>oP%jvwvi8nz!h;dbSpLd_KlBdYc>BI7bT8oAIB1#XCL(dMywNOfH)Rg z9SlcX!!x!$zCqLihgExH_C z%eZ-RYevM^E&iWugR_qP%`s-T(_+gr{)T-VgB_o2-!s;LaXB_NhhwAmJvj#U@mtPs zbBq#`AfHD(g1LN%MIft?4ag3Y8Q%V{dwJmXfBlgGhJWV&m?r=Fe%0|kAQ=#y=QFxY z?4Nu;u{#Lc9Q&Q`fpZ+SLCh6|O^{6Z1;`d7)+&+zvD=Ec6Z|Ld0=F#I$B&&m2m$2iqxMP+sJGI4yy`S49( z#>+4!h?-DxgB;8JKiKfZ;>jaWOT&13<^d&kh@C) z<)M?o6U4IVXnX){Z^j7_r?jG=e}f-lb;tu`12Tem zUo=+7vW*i!9uNaa9&bnd9sLUiD zb&H#1U#y|7d;MR3WPs^^>i=iSrv8oMW!Tbu?-tvgc|PGYYWWxwhaHdIk9@#~M;4eo zz&0!FN0mMjXzF3FZ2Eo|6>kL z_=4CUd3x+?>;mir@&ecb#PN)%%fny5ufRV*Pn!*ZzE8$?W%6KSx2L*JRrojTkI&9@ zg{S1WF&7MT$6ne`GGP2#8^G{gS!?)-?ze4QTI=y&IsU;tb~*E*Fc;c}62Gr0G4I+e z)&HEL8vZ=h0K$*N+=#u|_j{?OAr?>U51*SD9W}Vv3FHHq2b6i8Ee}BaAAj9!0{j7% zX^{uW2kZfC1PD13wa>w*`2fjyt?7DYaw7Tn99J3sD{Oq}{H)X6sT1e9jO*sQ?oa2r zUboG61*b7bKu#zFc58vgEgtc82p<5w&wE49Ge(~JKXf@dov}IO_8{a0$1?{o zaRcJ^{ElUQL(NdMKHqW+$Odc&YJ`vn(Yj#jiistzFM)HjFRZQ1&Zr9ix#ME)^!Ox~ zKJl-v^%Wnx)>r-2b-lp3;b$#$6LKoP|A*{@$bZ^0EwYh5;Cm>{b&p)-82S^;Z;3L% zrWNYvcF8qR;(-t{ffn0Eb-iTR&ZV zL5`Q(#N+*eanJeg zf|JW61Ek-_=Z0gVnLC*85%66LzA?a@!o*1|cFHny9kWgh1%JTf-{T+r6N4+zoXAHF z8RBk|{`-sSVBgX=FyGhQmCUOH9zLoeeW-8nf*XDtCAR-b^YpwVe8T^)NvFOnUHGtc zEP9q&I&^JS#QdM=RO;xd$wkjHZx*&a`2fBje80xw-YuK|&%*Iz)Cucb;y231xJh$$ z-y}Uqd$si9N<9ztyVVgnMCR$NDRFOnKa_jJR^fXh*x&dd+#|6Dn{&kEK&AMX+~WJ6 z@!Whjci8Ffu?{`lGdp#2H}^c=<>u%+VB;0@kp9QUH*90ulPh5x`4U=)T&gY8Zi(18 zpU2PtwXP4aSol9(-`_b>`f;)1=-8~_koj?_Und4n+#H*ELkWx%n@0x{hvPiN;jz2f zj$LgS13S@NyDhVwxIOry-WJ;(UJt+HCXCaL)-#M1Zm11DUHit$o=HVjeG{lQ_ThVD zYom+#)--j=j0wWGAP;zE{4-8;nR)Ae|I_Bi zMX!Tz<8^SJingSfU-Vh&i)8#)HUEEAxiG6?sp^>O_N6)p+v<{-gQG+>cq8%6<%47Y z<9FkWW4~f|6FZ~k#^%?ktTlfcoI~W|EeD64PJJ(NH{$sggQujz zHh~-D62AZOiXj{+9S_F%mWF+|4%hWteMm2V^tkv~AJh`F|i8-q7uZj}-HiQB>3_`Aprun*3yR>y338zYB34EC|- z(Tm_3JeVy&i%o4ZffyR`IL6>of6x8l^P>Ct{tokh!Ry>_O$d9LjmMz`s@>S1L{*2l?#>+rp9i3(Gpt2U56TXGt>1+C)*fTBXv2i-s6x7aRV?fmQ zA~Ud!iP;m=vsxW|1MCN4^2iJHKDPhopMM_4`iT+pK9N`GTI_A!JGOAt*R5_Dn;G8V zewkx%V+gEck6=fDb>skj!q_6te}KL(ja|a{MPwwgfdBmGKjCvSW|6+({^4uxtFr#C z&Fx$Zj2L$43uKfLvXOTSaoiaBST@fh@0xfb7^JoBv>eNCz?%{Lz&=`@f%nBej^q0L z#-1H{Xf>c5&pPw1U`xT1@DzPS-@-?X&w_{OLyp1DA}>s>2-~R%BL;(v<$g~i4l2IA zM90sR{GF`#beX;hI9uNZov9qy41FJDn*8GFilfXCua)b1XXsu>O4gj9@4cQP+{Bb~ znJWG*P+s~Nz58RNi^j;7K0~plY}sq4>KVt%9?a6WEC-4|N2y=&ONWcka`gSm$&wq{ z!hRpwpA+=_w}>xp(>LaB72n(~U36>v_U;N@$K=7LkO|1SvHGs<@shX9V~4Mf9dCqx zZgq9GExE-vK-YtBWCndto-WF#W}otI;Bk9*9EXhH9rAl@Vd{XX1GIVdunmZvBMaEa zyQJkkqW7`?!5-hx4fH&li&{#K@_k=)KlsP5*l)l6!gXTweA}6YMJpeS+TMcjt)bW-EVm zxt`$$`M0@}FMagR#t7pR^sGgUA=f$iF4ar&)9#baIbY|Pq3h)cgu&b zPm8|~Z@||OF+OBTlnlpgvlt*g0Cq6C9kOvd<^vG(BL>KEyh|G&gsgyn$$gXK20PdR z;kVtTgVDovN%;KW9=-*8_APO~8Hzu}_om6iL)a|%|2!``i99Ac4Sq-NArowFBY2kh zE3pxN!#jcBsd*-*LSGU?K_;7AgxA3W+c+0E;CQaZbr|o=It0GC4{R*X%lWw$z8L-% z{un+SSjJWZ+nk@65c_!V$QUpO_P`_8BhHIWgDe8i_>-)2E@TGV@Wqiu*Z}x+_;$zw z>qF!x`;aZ*o$DYs=u@_H4X(xWn2m`%L;s+MSjKMPy1WzQ2*1H5Kft(w>b5Ga^*y6oa`-NPkKRGYIgU5+)@cm-?8|)*e(8=)o5l0*m`aHybxM%Ed zu8(}<+`Kb>0|vn!`ks5mCImM;8_&h>A?^{|fn(qou0=fs&rOT`gMZBS_*5p?i=1EKTdoK*@9dLv&bA|A;%zV z=@;Yz+qoys$33wf*#M8A$2gXEMqhFs>@;l1Q}jNNFEJfIK=0#3Jzu`=`$lBG`tdf& zizPb$9XkJAI&QIi4e(A}58s~F2<)>jDg!FR|N7|unjXvhLay-6=s)6t$b9rWm?suk z8JSD~FZ`B1q@U3F_}M0F&A;TG)HU&*kxAGf$RzHG_yhM!UI6?zR(z~`=6 z?_rmtud&gvmDvuqkrD7dx*k6ntnhxo9E5$rKKdLvh7AE`z%#Ok_k|7yk5;=09(k|W z707(-Ht>TS!Y*e%G|mggxCge|J(3sZTpCxEESvEH*Ch zlfEP7!#l$60Q;PSet;i12k(euu!GEJW|{5CVBRY}G8n>gS<_J zf0F@V4?T3mkqKhC4$0&Z_k#_8GJA zKv%&h^clPb?$N2>4E(a6exV=1F+4`UB0Inx{05&x-~kyxKf{}xgWrQ?!#uhd8GxJy z3-CMGrCx#SfJ1(VZsUCH$9BWVV4bm77N_G}{03VY{R&_6%*ZXCneA-jI@~w7Lhhgw zcs6j44g`bTFFpw^*8!jODY6ecf&Ss1=qvCZl|$HN+!y;ep5OC)TnAl@i~-9$3-`kF za(!$CaEE;0KDiI@hnzqL(}H9BEzijPaWB|%_%mRe^YG4)UpzNBCk9Ns8X1Q@VKxnY zhYi4WxL>n@ERM#0WEk(2_s#FH)K50kaOK-)(sesHv6h`m(bJ6d^) zg=)!dL}fr-;UB#Z?vVlXjm^E!GCT{fR7db`Rrm*UA@v{N24<)xNbTBfwyzFb@Q-eR zU#Sh)M)BTVHQxcX`sikCZe$rY0P~OH+n}S70bmt76}dnSGJoU>z%srx_~5+oFSx=+ zL`Q&SbT9TYyvFtMKRFJJupPYeTX@OFRB<1?6LcEy3e3RU+#BzO+6!>OHZX-OfIpGn z*biU=Jiyajm-|O+7mCM*#_GTOTCnGi1e!lEa>;Urv>I(n7J9q(}$38+o zfqmW^dayd|v%fn0V{;EYO8&sneO%vRN4S22GTeZEn@2s{)w-EUx;N0elppQjN;n(mBf~;)|_|(#Btz( z{d*}U&`$X!WWlMbNub_`m;f@s@IPGra;@GG?*~lQ)TgiMac1-LtjH;N245As7JlDo z{P*wY2KE*1PZ;5P7x!~L=Bw|<^pQNsaQ*90=SS_0Wc)Xg{e}Hcj*z$j{0iQQd(jv0 z1DFQ8w9Fk0{=vTS3iFTSCw%+ux8ay1>LS1pSV7-1mpLtXK*qq=*agT3)6wvb;SHM- z9~E7KuI1Vgm}DQngNIoMljv}Go!{^b-~@fl^&#*AHo*aSMIV`t{y^hEu#MS=&BAZt zdzQIR2uy-4FoP|@HPC_RIPk}{xp%gMOZK6g;d$-}eF$cVhgcmZI-6(X{`fuT!ndG* zkT2X1*W>rd4)&ved4B8xbUoOFOyAO{Y)5A!8`zHAz*gtH*b3-sVmI&s_e4AoTyh<* z4{;9ek7s~)I2HoWsfhEiAI#ghFZ{{wswW_a+*KH7xtnr&#E#g?0^u|ML=>x+Nv9qcXoW59s^Zh)}g zXGE^s_mW3l=VjNqu6Nz%4$Yh;TR{51f8WjG2k@SFzo!4eKl(pCJw4`SmrKk)q6 z{$L*b(qCo+ARn+HIhL3jwj}ZZLa#x{k$?Q-AMS@AehBj<@H4s&4563K6%NgZWgnPB zMxc|??ckJSiBDluAg|3PK{oLl&V%1=JProHAMXJy@_YD)b8Z~}%{2BYk^W7rNJIo9xM%bc70NA@9Oz$ovAdtjMo z;-0`D`WJj5Ke!KgjAe2n=u^|t*zs(GIG*jck8|)F;!((Z>OPD*sJ4h0aND+R-R_$I zvb}tC_8E5fkiM>pz&XF?chtO8N1U5u+Uocnh5w<7LlYCk1_1wODmQ(wWEf-U9+zE) zUA|QB@m|?|cgbHz7Thj=#Fng#u%qCaR5HM9f6fc9Vi&^WHcq}KvA<;dAH4yu@O}mi z=;!+P>*Mwvd5>$8>)dVyU%1_KzjAw@afizoEV(f7uQ9%W7neZ!3VMez0G}bZF~#*oBiMg?Av+35qcAhVJjd*XgLlWm}?;e zkO{~_uFEyh_xvtezhrm@+YmaR-y7NaOm=V#cCa0vs%5{)0kiSJG}yFwu`TbT+CK1t z{tWe|ux5IdZAR>aY(3gW_nBS>e^&odRa+gF?L6Eg_f=Cu&a{^9*;a9Yfog5M0dk;B zap^IVQIqsuX37VcDLHVl?7XXl`8&jecPUPBpLD>Z(m}r!ZkLN6o{-K!Ry-zs{u}M* z+r8#HAS2LU$OQNbI~SiHJrCxI{a^>cr|2GZn_-|TJAh;0bAFGV2@f4{#E}*F?|-yA zvFEMsl)eA%hVSU_OE$6gzxZ z@8S`?FE9=+!LHe``1#o4__p*Z$AB|ha14Q8Y-el1F2{gF@Q++T-y;LSEYA(GkL_R( z-HiSQi-uE{(dD#JGR)FqUqp%D(!c0j@Cx?8S#=b}DEI+~w6+YE*k%~33a9J4uckQN zRL6zSC>hjR{dAms&>IsmfUp)o%U3mR>PlsgoUS_6xTsh*%}l+ko5Ux#iYM-pzFICG zxmB{^D#b2t7608Wee$5>!2_~S@0LusQTmKn(KFhHd_Xol$6Ppy_r4*0^`2rKf99Jw z*tw#W;@fu=>wZhNtLZZ^V6q@p3;wYoi0QzO*jd>B83Q!V_V9f7XonK_>W(q@WZMEa z=A7UfB@OOBb$^{`!mJ;87wjPEHINfvzKOf^CW}s=&YMf8@9I?|+m# zzgv5E>y9nm+>X1s6OQWbjvk2rUo}=YWPd+B`{BaHVS4sdbcpbht?N#c516ZQB*!T3 zI)c7bpI)rK9Io+U=c*4E$RC}lKDa~A^s=6BrQ{+y9odI%fW1UZydU46z5w6oc>F2s z0ptL-mibp4&pEKIh`SSSM%N<)_tm`^UbfeGG{!7ITj{;-ps^_Ulr<&rR}-@9rNY~W zZi~u`&4sI4yDl=PDq0Uaf1P_uI_DnJJKN}7hp868?0>5TuzX->4~R#tWqXv64UBKL znj(`MtY0b`C)?t5$(J)lG0_2skPkal%E!6G(HRe`!KySr>4moD1J8Z~cca-8sy^lS{9Xd>NaR{fi zMTbb{W$4^l!cu|y_$>8nGL4s=HLrQ|aBMj-7RHt`&YZZbjT>iMv1pY1u?wXuFH&sn z2Kif0$p(5``kr_>wLIv3pBM}F0R95@GqK#VR z@1dRa?wjdc$oezIbKuo5Zfz9jwru;Nt?f&0kqx(q;Om+Yb1!f_G*^@*{u?V^%#4!w zlAPsW+0)0$*BmaNaWB}u(@Po+>MPtmYv;Aj*Q*c-nrfgs0xSGnjPCC9S z>ZtQ}kU!E+yw<*k)Ky2Gb=I!-a2P?@qLSNb(3Fqn=3Zy5CBnzOkWjmD1zL=zE z{0S-6SuU(k({Y^F%*#^v${Tw{uWt)44q6YMtOo6iW$yVUhZDmJntwc zu;%Np-TR8^eIUP{ITf)Fh#O!N80Mq#17rcV0C`06`)2=R--Gk&_&zEN?AYkGT3I$M zR@TGD6yZo#q%GGxG{5(C^Ig%;oNM2M&Q+3R_I`&%O{Z8={7=rE)!T<0id{-TB z*5&>v4w9F_8T!#|g_^efrY0CozTWz**JdAaU3*sK3*)?}i#O&;H(acE!)5aIACeEm z7{9N+|K5Er-TtBE0Y1VfsuB7?J^*olFb@$!AZ9|ml)M`GYUUtG#y>c=oRzheV!JY& zMz(hbgVhknfY0{AQ)SeFeH;U}v|JNvufFQ2W4q}5)!6{VB^Z}|nBtaI(ZSNYgEWuB z1kK%3B7It80xEJjvmi!uE~w$8OiVMo*<8FdLmeth#0J zfi8iU7!RC^pKFtEH}$zv-T(S*+tl}0o9B-{7w5%(f#!%NF@{4pyI8T3iOQu@+;(L$;(lXvcLEk>~#}Hz&bWRap8{GtK!G@ z_?hBe);SKH3jTJ}GCD4m?n~Z=9_%QevnuK!f1|t3x3{jdr_Q~nu$WAHX?u6w(?P=M z(ZVS6O|7G9lQ;dj>fUBDd4OL)%obTNTXeR3gfhh+MhG7x6z|AaZBD6b?T`sGRFC^B z)fPOdoWYaw0gw-;C|r|HkUo`|2%o$ zzt?r&Ycgi&A7lddYLrY)q|&iq*)SXZjV*heuG{CH2Yr9kR~|@~2eq|cU!T|Cm&c;# z0nY=T2RsjW9`HQidBF34=K;?Ho(DV+cpmUP;CaCFfad|v1D*#w4|pE%Jm7i2^ML08 z&jX$ZJP&vt@I2so!1I9T0nY=T2RsjW9`HQidBF34=K;?Ho(DV+cpmUP;CaCFfad|v z1D*#w4|pE%Jm7i2^ML08&jX$ZJP&vt@I2so!1I9T0nY=T2RsjW9`HQidBF34=K;?H zo(DV+cpmUP;CaCFfad|v1D*#w4|pE%Jm7i2^ML08&jX$ZJP&vt@I2so!1I9T0nY=T z2RsjW9`HQidBF34=K;?Ho(DV+cpmUP;CaCFfad|v1D*#w4|pE%Jm7i2^ML08&jX$Z zJP&vt@I2so!1I9T0nY=T2RsjW9`HQidBF34=K;?Ho(DV+cpmUP;CaCFfad|v1D*#w z4|pE%Jm7i2^ML08&jX$ZJP&vt@I2so!1I9T0nY=T2RsjW9`HQidBF34=K;?Ho(DV+ zcpmUP;CaCFfad|v1D*#w4|pE%Jm7i2^ML08&jX$ZJP&vt@I2so!1I9T0nY=T2RsjW z9`HQidBF34=K;?Ho(DV+cpmUP;CaCFfad|v1D*#w4|pE%Jm7i2^ML08&jX$ZJP&vt z@I2so!1I9T0nY=T2RsjW9`HQidBF34=K;?Ho(DV+cpmUP;CaCFfad|v1D*#w4|pE% zJm7i2^ML08&jX$ZJP&vt*k~R|3)cNRM5}ERo2IHgJP0yaoh&*cv7D{tBNNLLwR}`! zd90TEB$hL^d~{+tOUoIFdO)ST?+%K_QpymFF03igp(rD%wNTPIQ=PAJJ~2-lDxk?M3OLy+!op{-T&@SCRTE*jL0gTZs585e-e; zbD5TpO)L-A@~Fh}2ra8$GSsj?7@b&Fp9Lo-mbvCuBL21!(J%b2m1vUaB+<4a`dxh* zY$xK{BSkxixVFw4Y%iK3Iz`k;R4&prf-WNUIrkcL6!C6O5YczVqTwR?_YBcFq7I_d zMCXa9jJdY)C4Ds#8VmS!wlYs_GPFEdFpRk z{!r9R>)`NIQF9SE}J{iRh)Zd|DXP=ID+ju1{!*Dzv31r_B$zkPRrt@jmD<;8{KbY`txbi zwrNqkAno*l#Vy9D8%OpZlfHDP;$4edC}g9!YDO$JAU-a$JilyYd0~85QFdm2JQz{3 z>jLeFm6l~@Pl#pbPKb>!&n(FarnN|H&WV?l6bH6aR9+UYEGw^2#|P7<{Vx&hX|$kCMyx37tn64p>G)CcLY;V8+Ja8o>yoFA9&>z;^jIu= z^5o2{yoo(}9IEB~%+k_W*_7gVEU$1}(ZFEZiuPl-e}b!@nv*|#VlZv_hj!+%!Q$^N zq@_=; zt+m%2QL?yMb(hjFN|vN`$cPOZ9UD+o7>^Cg%#H^Of|8}{Y%Gb#N9*C(u`ID;aJ($m zKR2@^HdI|VnLW!BdxjR~mBj`{e)4=`$FQQzoY>&}DaE-Qz9O;p`1qu?SA9FNZKQfU zUh?Cys}kEs*+oa?O%3m6b!5lrlFY)=aYZEsoPAAN$Bfv};|9k@WloF_KYlRVzE4xH zjT$g4)<3_fG~Ty7C$DHgd}3b315aygJ4@o3W$}@N`;96u8JFmdIhE}kR8kaPZb8xk z;r)xFbk%Ft-8DKsxvab-y!plJ?m0BEU_H};-zIJMN@vk;E6yqsLbyIZdOosqU`a_)c&{rW8;>t9sCW$nO7bR(6Zz5G zk^Sl+Hm!Zbc*a5bnd8GNeQ&$qCeAahN#gw+Q#7Tt zEH8UP_!8MOCwY$^x9{Y<@H7ij?CV!vR#sHVFRw}7dqQzM+_5-$$BD%`VhVn<#CE~W z{f-+R8+j6&m;SgpdqNUxEsO4pz8~9uTxM~iH=nmn>V13A@IhAC4sJ2&{BPU7;hE(> z;pfw(YMXJkAxXL#P^cz*cUi`U&L{0}P{pC=7q z0$_<90L~+?W9{a6*^s=7XI>WBHZq={SthnVu1Gz0Tv1N=NXsJ!Bw*SvUo36=pO5TM zuxojKerdK)7jn&tpX?u8l9|QRzx|UvL$fPbaMe%t*psbZyC=73QvY(Pg0O$rL^qGh zD=5y79~Unz%^V-^R}_lj@9lsS3-gP9!i&?IC0<*_-Uv6&S-U6X^@yBWV0*^tNqL-W znxT|WESw~X6&o2ZEiVW+FAX=xqzdCDWwDa7uv3;*Y|NS(FA3$r@``n-;fm*ZzGA%~ zvvfj<)H|nNk=PV3$S$6OZV$V#Vq_^WmB_bNJjV5^Lej zydAET#^d2hS5>S{DGX1tI$SFgW9c1+N3RLDOe)E%SpA+=-D|vXBDXMYtBTd!qSCUg zDb^Kp5?jmi3gSiMaxyCfT4Lkm%(AkuL$3)p6mSryTFh#Go}_39gC*fAwyPbmG~8nM zy^OVjwXbq{xEcb0lRckUEscjvvf{_pSh21jFDdNNi{su7cT7mU;#C!EcEQzKnN6En zURG2Rm&7iO4=*apA6_KeSlFm^f8x!4zxIH5p&(x(30hQmTzOg8a)xPJ>mlr2&#@KV zO}C-PpDyT(Pa<`b#QS)T3o3@D2woO>8R_u8S&! z#InSuwY;}H+>l$48UEt=#9DR*K361G#payv?Qk`3d}cPUk1eahEjoS00jtB+A91-R zT(>UzK3pr!&MXYy!?bO9B;9cI70;>IC>dKC&n^g=Yk_UbtpJOyR_tADs};t=lEi9G zdHCC&APbgVrb(Gz~h%f)5*I1~b!2gV&qn z1ix!BDR_6QlHj$i%Y$j#6a=4aGd_57+w9=$?ecXa2M?2;RN z*=1bt*nVdP@AWPVelhs$^5BUf`N7LWi-J#vPt41S7sY~=qlcCbl6f+!!aVtQ%CKR5 zhsT1yUD#-_+R-Nr8#uD>@%;w|OD<|u7(9DLqvJ9s$FilsN@At>RD7Q7s z4DM<+A-Jb`*ypkA^n-#2T1?C9p zEu%->vu#1Vpr~X@@P{{bCxyY&jZ0&}|5^oU(u*q_t7{8n#l}jDQkdyHuRH(Zy+*+{ znZZ|0%cKp0OS@+UZ|s>HpBxJo?L|z0t!SQm_7an;_xCEz&W;8D>QNlb99$9~UmDyt zBqw9Nw_^AVFP_$afaM5^-X^YvK4qGtK|u{hpGY4G*22T3vNyb8UH8y9>w zhF8oxyt!FUN$}sJ^o)n<$yOakhv>#%X(sDP;g#(49_hh9Tj@l4Yo&UR!GqfdjjeCi zG+Wzw-!%KN^ZrBE_NKS^Z-olD(&&s!nyY8NZmug&DT|i|H#YCVLU60z%o+|{egr>J zsZg4_K3Lvdd=uV%@R8oVIPj0n%QEvPNa~MI55ClC#;3=)eDG=WVnq*PMS8ABx79No zrPHiYTJny(Du|EN@alh{N*I;Idv>i-x2f1g6Ui7wOx8b&{9^^Q(I*Rm+UxRXKI%dyx%!1`0t*j!Gn7Nt|1e% z@B zaC^&wBHc;wpJVg$GPClvbk*n_x+}r=vEa*-<XjGD-YN|q?<2vHlP~7^^yszs_HoODV&fzigB2(0Rh8)FE+~VM z%Jtv!iL9!+E-e&5vEce`%JLAO@@K}&DkuwP<_Aqf&JAAMCcC_(Lc{!Shtk|k#f9Lt z;Fm}BO3$4dTzOo@4ab7dPST5=6w8U{i}~K$Ciq|*U1+KU;;*)Dzl_P$2Nva7B`5pivC6<1w#V_Da>PI{4$jF|wzvOXk0fG7{8g#Ks} z`Tzk!A0R;JLl6C_paBsE1w=&nf6uvR0R8{|pFg{vdEa-=J-57D&ONuJAUiuihb}`c zW{ZCNGnm?+dZvA_L`SAcFQ(JdP882w4$ZuTyR~+x0uY_}H&oTnx&CBg-x~@m=+DWA zXJ-?Hq>pRflDtb2$mwEXXJe?0X;f&);b*&_&`PG^ffl!fc3INHB2R@h;!>D2FhkD0 z8GC60MIe|!p3tbFqxg+81_~0}R>-Sm^iD7q;~e%#ofnqf!Ar;?zY} zQHdXxDxJhIazU01*bSHQi}g*lTOa9l`z^3&(>7GOwtiZhR7A@!FZSp0kP91)=HJJ|Tn<`B z0r!$YTKb&2^8B>zLrTa%qwrJT%Ta^c2mFHAUB|ZFl*`Q^$S-Ne?sAmB~eg{=h>?1I!9ko6rgWjc+f{XUPPpm!M&)2 ze!U`}#$PG5_P|xSwE5})9lJJ%j$hXobk7)|3$qJo*42oAHfOOTJ~K)r za%CZg_{`YTZ!p;d*I8)ED;$2{JBzb(TEUu?^V*q zqE`jdi@6+oUd>&vmgM}a3)o){ms^n5U7ed<$P=!!DOEKx&v36r^2HW2>7R)-MUW}}*oxK$p$x;=Lg(gKVbS#cx9v-^Ulsd?1vnk+hTO%9A1HZc!hi?A>iDY1|iUel3k zTNF{>$GG)Kt%YefG8+l>2aGrHXthQA(Y43(7pJY)aC=LK%{}umbW?+#;{ndQhI$vH zGv?ax<27n+^(#i6cXJYhZT&eYPV|Q87qZx^O@pq5tY1p;>l;vBKS@T9LOS7H{@}Fa zS~gnnX>Km0755dS!&qHXq)}|UmIG$NYl8UpBRA3GsOuS>q|e!V9ZKmJRu=`OcuZ3( zu4C5~eQ~``TeqM>mZ1MZ9%Gk>a<@HEo7g*$RIpkh1 zvFt=CIA#2b$IIE*m%{pk^QMG8zmXcF-(wdM!>%_-)jfIxCkpS#zLAGks=U!uU+y$% z^o?gzHvUG~niwv*qo)v(>2{0bq?L12m_E{k8}iUhvkRqV$Ok!uq=b7Ieulq830$eQ zHx$9UvJ#947|35wrlDR;!=EyZ^pWQ;8*aGT$hgVTCm-fuYNkCAm4Arre;A~bAHw_!f0Ty_oIg;6s)BLp`;XXJgTdd} zm2~7IEngb+KYXLMY&iU}+mGIajvlrWY8HL=Ka|N2T!=6dGTI|~H&gU3SU64gP zZ-)KLleu>7*ax!w7M>MR{Vh=Ir-Qff7tesZ&Q8v5*IsPCisZ~dd-S`o0k+;2-~|WT zbz5FGoFTOTHq487MHRNjk(;v%BxJW_6ysq;mdLSB{!;;*ZT^e^9k}bg_Sx;T>8JNP z(5X&2=rsyq3c)^IXa$jY)T&Oji<`TjR{bd#i-EMYDaQ(y8foL+r^EpDyv0l_{2kNL zlnQfc?k!r=jKRL>7OAM;+>V6qznz6JALZ08ZA$S)0eneup3{_D_^ZXxj9VmUljd8f zE>Zsc_D@2ON>vaV{WT7)9bFJt^>2`Ot`y(i!o{`zcGRp>T8-TuR&=H%m|@b^TVYG*7gE>TkdmGp*6U@$ z(vP=teM2RJ8Sj4=3)yt$R@!toBtDh+hBA!~gLFcxmf3}wJSSRs8(Ub&8W!Z!G3$OQqpY1WCSE&0Xw8y8DeS0>|&4o`F zbAcdF0J(4LeS1L(eS0@01ZmpsvD&@rcCOt#x7m8TI>>szAcLEkC@#G{s{j`A2l#wr zIUcWysWYCbYv^Qtwx@6@aLd$hQP#8=RvDT#e4DG9LLkIq(P z{8BoO#vj?lq3rz}iW@q*R-VXwc}GT3sm#RtK7;VzgPnjHcn9pf9uEY#?&(_BzSq*> z1{v@%#zEA=y?1b*fr)$=(5s_GxKP`o!m8X zNvcfn*T^TZvfzKGMlPWOLD~7l5Lj!_vRI6 zo0*}St*0^P4ba-V{xAXf>@gJMPn_%k?Y+x%1wq>VC^Ck($k1}D(3wV2)-y)?n;%@OEeEJYnmL(uSv>Ve z0(MWPVWE)${Oo~pY5aV5bIgjl2GFoSQ@lP_{u%ZL3;}kHJxF_ISi$^uRJ)XG%s|mM z7@^}aHSp7dKj-rf8RI{i|7tpI`8T?8PP+_GK^pj%?801j<)jDOVSItvf@*a98MqAm zRQpeM5*tqs(m?B9NN>(F=m56wV9A1Jzn)(hXkQZZ3XMXWiVQ*2javKhS$JCx)&8Yf zD?hFLOY@faw14r_u6tTE_h-_{dmuWL^BBm_hHJ*lh=&(Q*ens8EzfgVq%}>x7fU+TP#az#ufurVD4+J;D-%Ke zmeXIv9H9ihl^|_=yO<7#EzDZK;ZCxY4&RFz#%CYmQ)ZplIMHtV-N%h&+TSpn!S*IL zIlqP}A*1A&`-1F~oNynKy;#z;L?W+c8WHL)<>wG6CCCWXa387&ZFBFd7<S{=Ka_A%Xm^!svg3v&7ijSG89sD8PiZ5M*%iBg8sf@^DxB6Gww`GE%@~w#N?>EFUMDa z{=cR<_tOiSOSf3ds`jx!qilPSLgBgm4r1l4c(vk7ymCgcaAY*o z@K~V}m^xFqgt^KDX>qG`&ELR>Og^_En$T31v!}DlBKDGD4&CAbI?yVc6Jz9#wubK6 zEEioMS{Fk)fwi^|LUzQ1nZE2y8vCGBuSpMLhXstF=Ct`is9(YXycMh-`G1fa;C@D! zB@g18(h5j;D_J7Eo~c{U)ZU$B!D$D#VIF4YbcogL79pX|9#$5Mla9(^EC^F zzD8&o+M41xhViWtSqRLqFvAU!Pn6xt*02sWe;c_R4sqbf5$1Ew@j2*F>wKQHi-9y8 zGR{xTWwo6jg4*tQWgnFkmtT&+&Pbu7nc8ESMkid3;)gm8Gxs5;i#X(Rgp5uT=~+xe zVUb=f&uf@^p!gtWe;#~c57A+s!AX7Z@i*|sEkpPYxGeKW@q-ogoP?(_NlEkS7f!#@1_eXa4l0aBse z%rERD(>#AV9#}uEez>6I{Q#YYgu9RR*asxV-!t`o%fGZ${WLG|t#d}C+aT>E|%p)B!)J%Y|Gn~aDN;+oO%N1D?qC=6}j;NeXiZ!@ZRv^jkaJ2kw8 z--bM<&bLe>4f5s`Q@8(>s0y5Cnef*?dcLRd#B=ZGV}8SHpF#TVc_gzE(s2^GuQ;n? zF-0Gx~<+se2q*|NJVb4S#VJ+Tu8@>X_AGn)kR_m01iCr$38CLGg`^5`R`^r%cqn$76Lk z3c2tAmU9P*LQtND4oflKXkL!xDN`_=ckh`Q$mCRZ01wQ?450v?6PldTE|a1|V#TpA z#T3WV6l8m_Cb^^K?NGoao`F%}%XlPv`Ku^y;U1D3OIL`mL62upylK z7s+|zRoaC~Tk+F=fXY_$*k zJ-Z_~_&^8ru^YsX(wl0h4gC1)asi-v{PB6K`EfS-r;-{#$S z-_4-1r+MZ0X)f;$G?L3(w)M7YN0T|$rLN_wC zH!%%?V*X6KpN6?ZeO|;``2(#nt>gBPTTqmdj(xZ=X$FhR@#h9s(Zbq zJNj#}XdG8mz&;e2@W9#h4`bBH-h!=YX)Wcc{FzMp43od;PR>Dim*nOv$<5dDW-sSS z7XPL_Lp3b9kKaeW<@fm|ZQAiF9=6YJdIla;KP`I?TE1fm57Zc5(Pwyd_CY$#eu4(k zdVqPd!w}Q|{MbBjgX8EI8|q@r;xe>qM0LKF9iFXd$%O$2kJbWO8Zx zbMWu5^=cfuG#l*5&zuVT1k}5OO)w2q;#ccz5=Q7kPzeFS{;1;n{T}w~A?0 zXk-mbn~h%U;QGLNF!Z@=S;AW-UMi%qeJyzLWY1CMHVa;8 zSw-l>y%jtjrqauD^w^iAB;X?2xDa0kTCRj*uD90@rWFU;Tn%+aalBwnm6FJ-+O=8$6}Vfg0$;(6v;rSNq|8^dtS?E zFP`W2*oose6Tg_-xbjWon3tV5H0mwc#jdHuQ2!RH-w;leGnAm_+;|G9ZmEVS@-lVMrNSan{poiDWYb>l`bL6*PGBV&N}{Krqj-o%#} zCWYd1%u-Un{zqc^hVwXv-}1&A6ykZ_?@6y06{2OviW}t|z=+m`i+CJs3k&tei{?p8 zy*W(n`9c>m4KHCDS;{oDOy2K8Y>i5I(+drLBe$5QzmbKh0L^~G%pBLg5jzfqcn)bg5uleCOTQsL*P#&7bYVFxV7efssdc6gSK5s!{0P0F) zl|;XhX=EqU=(qA5mFJ@z##D$Pt$oYXxgKw8qX|-P{y@h#eX^&BzI!X1m-(p60`8?w zvJUsx>#ZRDjJTXrjKgQ-t&LqCFb!@%P%QTcX~f&uU zsGMo!Gp1f|rgk5u&gV>{pz2s$^WS!~@xPhW>mA;>!JfHX>?O#hDeshI7ZjpJ7iYhR zy$0_{vBf-}Hr{4-K)1%nDZ2g9&0K*cJ6KuVkg;i)7ivHE^UB{aKl0O;^N>zo{a3g& z1O8OrBqfn!UtCc;j=bwTFsloT3eE17aql2M{WzSQC>r$+##-KImkvKpkiG^tJV}QW0^WaLsjxTfoWti(@;pB zrwN_M)T?D0UcpJ?{fTThPKUoI$j7;6b1ql2Kxi9Nd*=;S4z0jjdlv#=#(UcTB!$u+ zq-7aT(RUdS(HEJmX-?L;3G#_7ogkmiV)5_Nn$z0!|7%KoI{p7WB`(YGQO}J3V@ljP z^Z%X_Z_jK&UgrPrlz2Qm)90qZ8FUca@6X{5^kWt>yoXEV?3B1J{p^(ZL^?{-WA6Dg zd(8BHOgH1sE8?r>Icx^>?B{}WjxcqFhC#94RNNOjZJv|yyJ>SZr>C@&P8x9(m6vOd z$p^qrzTZuzzsfi_neGX(C=1AB`qvDeOn1-Z$@Hh0NXRKs@EcR_G}F)-mJQ+ne;$vz znDW!w%>VD1@21T2=g5;$Mvi?W=dCAG7yI4*k2(3stUu1ltFrz-=j8o4pYvFow~%Rc zDbvta*8KY!_P1H*&9KX|QCzVZ_7K+b6Nif&6HP*+Lha-H#uXa*S-2>i}w(%w%$rf+Y&)I5M)a0CVD;?Wt$;zB*-oI`{@8_NorS?rw8WtJ_RcG** zIlt?DCg%KMU29qnO0+WvjSBU;@Uz<$3K~h;e$7GUMTdf}sB^9+sC(}3lzy7~2c=)+ zqEMg$N`>0p_}LNag7RoxLQ`@x3-Zx>@sdK2W*|&RBs`HQ2$&tzn{%;I0_KD4MX`CE z%pD00i7>pn=Sd0&<-wVqXDol%?0gWgm^S2LHhcgJnv?R)G`%m}!&IM#gpJ|EgvN0) z@@P^XAJC)SdAwpGlZs_|MeSk5>p{`g2;okY*1XG0F&)@~|MA_d?6cs+yZp7V+)St6#W+J{ZKdqko*t2Jhc zb3|KC+30s^?z@_@8Sk2uEqWJy?M6;nSZHXIq!N_79}HbkPv5@F8+^?3K?I13kiD5j z9ii@4ehz_BTn9hL-mh&o?*bj$7Mg__5$XxG>meAQft?I(u_t9xUkjg`w|aHM8eRg7 z&}{m?t)AFC0*PXAtP}k!WV9}m;MGa}kzK(D^)IIoS;qJl)cI;y=DkFi^c{hh?n0Ntjc_C_P>hru0@EXUDpYAF0&DrXfz^+8TaZ1y~s zO%$3`2)#e>du*c2EyS12hl_m?W}m|l!Z`#E<`?HUUyE8g1A(p(a9Mzxa}NDdC|+Zl zkJll*MjE5cM2-2pi2IL9R)|*!6=O^g##9a=jIhv%p+6#YB4>!}^BI^{n1*%5?6w!$ zlI($y#n4gMt!EHiX5#|tyQUcdMD~kB26`^nLlGEf;=m34CM77;IW3YxL-x(Ef+V(m zfwMK?`?HbKk+U&U861M4Za4F%0!3qjd*gHf2^j!JR9*q}d5_-@#VfBn%SMHIpCW`= zvJ1a=HlFX^GhKTZ-op|7;;hJ5=R|&Z4=X{~U095Q?92MXLhb&N4x#RVo3WX~9D?fs zxp1ZMghmJQvoi>)FW`;u^j$GJ9ezS({sEJCdHGW@zG$)7mId5$2M0|LF(Q~nldxNn zRs?0|+@T;+0bM8up<&jGzJi-3d@ZPxIJ1!z17jf_5jjt2RH!|e!|-++KH9k?i0N!P zmfz_pq#favoV94b4i;u<#u_+kuo1P;u+RtxxF|@QOSmg7Dk`BF?K9~IY>EB6LqQJD z$}=%M;FwW;N13nT1&*a4X6jrj4llDweQ;?GjVQ(0JUPA4xszzxfiAfbs&o5T8=BId z+tA$hy#MNKr$XO%=u}vO-2?1e#Yma$FEz8%Ql4{R6@kXJFDk~8h1_FAM>?Qhm~0H? z%tS%a8o8g6gEX7liw;q-uLF8+?%2O-Pv5mi=?vo#p35P0UVAQJMF-i(SCB)iJEDw6 zvJfYCcn6$L`x%k)Gy_HgjFOr$EZNhG#1wd_Y-!=vDzuDikDrm_2feyon$6|6yLy}Cg}mi2Zaj{i=^0MFytf1@TDu5 zVLY*1>92Ob@MFZtCl)p>DzK_m#!%;aak^oT&P)Mgf!s*XX z@YTwsJUy71kMr~&!&eTLRGYaoP~zSm7U%YZ1GOI)1(*}0$z8c_9+4auVUsEP zo>d=XAkR{;{$qsvRiYDWpMq%oEA+$1uTgbZ>si{~6>*+hT>sRze!sfDqYM#Du1m(> z{K%yxovkeD@rji|HC-&64=ls&02SS=wp8EUYDWXgtxWQISU5}G%W6+UKDCNz;}=#o z9q0>RM6dqV*$ocVV}SKO)eeHwY1B|Fp9T%L0yNdN3TWJD>}K0M9>@LHOtd;u#Vo4` z8yIl*6N#O+4N&uA~tW-S#Tj(^6U(@FGmB_Q7vyK| zD06U``hRI*orx;OTD-dgCk@9U-xXCBh5+n3p_x@EpQXz!^kTy2q|&K6i}zFn`FauA zl|d&~Tk3`8i$Uz|NO~+j_$q_czl((<3ZL;YkH{({2@a{^pdTK>X3%kUF;!NkuU)HQUFH)nkvdqeg zCBwWK##O;ZEGQa|D=weU(x%gx*>I$zCxh3`2yQO3a`Wit3KZ(uGeWy(A#hXz+nYIX z>Jv}?v(2mi7wBjis^Mo`4WD?OK0%#)k;=JNmv7;iDnKdjsejOruGZ84ppjDFg;Oci z6&n5&e~sk4YP_lIAF8q44I0D4e=l|Nk5b)O%7at_)woRSL2(fT=2siKS;e^>d}bB* z)DTPdAXYWJ`(mo*WL?_s4k$Jw)4mYmZ5yau^Lwf(Zj;ynzQ%GMyseI+lkAftP5hJrd! z!r0!2PIHNoA!%-T=)wCEHUc8H~LX}~Dx!c+vw zLkl+BHh3+VrmaK}-rsSyUtG`&wTO+s19b>rgYXG7PqdgbzXy6@KL{JtVi+%)A>U{x z&dkQ^b~zeYVW9z^cSLu`9E<1@=QN?_FfR|GRAiFPpzy#K22K> zp{NL93N_9CULq+EqB`hAlaVQ0-WJ^A;}La4>xR>R{xW(Z|Zh zq@|d>0wS}&k7-)sSt~a0dVOy3))WIK@u>6F9B#(C4m^D>#?2#hu^5aSP_{_&VRV1d z+Y*Iy93=S!C%I7;&B9CC+#9j?n`epTzhfTMm2;?U9Af7$vaYw4UySuAoQs<_4`J=; z2n&1IoNE5AH@fW~dgFb$ye~DcZO7udU&k+HPF-g&6$1=A+ ztz-4he3tf>Fm;zBssyBAAIgUJyfjo>nZ=k&9jZpdKogZzeZ@XL9P2nHdJ5^gO;8i9 z<5c2ANFNJhz1a*tontNL(^L}g6tLic;&m8vESYA1j*y{M91`n7OZ!;7Pmm7xK`_jn zu}@LLebWbHHv3DZ)@|lQyK5zj5s6d3QrFL|9C3FI<~kYLz!IT)mgo@EG!`Pf=wHJ+ zLc3Wa{1wyk2BsCD$QeFDkhbD8!&hZ$`kF5w?=ZJadu($E%|4UtzP!;wE@9|9 z+{(%H=j2E)^z8~1T`O!chDKjAOz?7Yu=dy2LQY_{!0I}=g7rfu==ZFdw`gR+mty(b z25@ByyPEeJ25fNnj$!{{`)zMtaBRT)1Ue`*$})}2;Vc^754C#iU`rbkbzg?m@u~LF z+b!8Zg}oNAv@x*kL@$IxLF^aX-p?`{>uE!sY2Z5Ffsw_I1+EFZ>nv=IlE=N=H%5Qr z6xc^O;c{TokA353`dQda9^}Wa{UHQICWdxNxZjm1kg+QR4K3Id!+MR}qPVNKc6%Q9#??hT2<;m!i;GQetI zh;-1*Fc+c3jv#*vLNgkH*Hl-D z%dXZ|Vwn7K5qKvgm`cy9v`nyr%sK@YO86MlGNI+5l-Qj541|t717Q+{msk&!VqRB> zYY&6yIjmN#Wx6Kk9=}~;wJwEms=MY7E`cfW5bw0X9v5^h8wXlAYmX+lZJ_m_JRF#5 zJs=O!nN|yV7_!9T**NBysKqpL36fY6e-YIFR0vwP29NwLaJu zm7!`0^odnAd5P6hG*>UN(93d_;%0e62 z#LmS-!yxzf=Ab_WJq*is>n(ZN94b9Q%|MC@7ZG1KCtJ1buHie>yx5 z+;F$?KJIen#y6wgLr{hGV$00|4p|`~9ie@Nx4|g+WGN zR3rEaW?hm=Q-`59`*}D9TkM`0gNna!G77CCgwX>AWv?&{$^b?Ra|Ke*T3A3OvZuDs zYRl~F>c7U~qXB3=FhvIMu;6BpZB1uWi;Vw(WtPlU;14Mbg0pu?LL4 z!_{P%0AU`re3*s#;LK_ZYaRVyTw$%q8)k{m2|F5i9Rs%OD4ZmOxy_qrK115!2rH#6 z(=av~pG8}qI_{iiwKF0E*d9EE45Pd|Bio5sX~23CZ5|GLB6bZ4Rgc7Md0yBmeh>4? z!Ynof`!7MK;nZ62KD8^M)pbY>tRG&Tqwj}HXBng;!=bzkYVo01xfy7whsz~FpPLwe!O9=f}yuimk^8i{`Vv$+qA85ga?VBGHl&GWF&~ffXYxzQ)Q= z>qc1UJk2hATCxl&>MJ>_6zX#78le-wCpkR=MpM~H*tzYC^O2SzBQ3rzsw6)bj<1oJ z%NM89`(YZmwj?4JeehMEUaf&gP4BU_JqV@QID!H z_{Z~YI5c21HjM{p=xD2?2tyT(8VwcYqM|~m1IjbP`J>^&SvAH&8^ReE>Dj}T#Qrb{NiP$atu#@v8#+h1u6q-9zT9Q2GLbYM6S>(iH=#b z&kwTjT#%(4BqYK$Lc<&+4o6e9XKxt8>!Ua}FHOSv65@3t7!g`;#L+eP{LQ}ngn$li-A<`B>a3k;*N5xiG2LA2p5i^gIPBg#zg^rQw6Jocc1bC@zmAm?{aC? z8XT+^&l2XHsK|TP;0xd?uC3fgPe|6-ADRuRRVTt}v^FhFBzCucsJ44hiQ2kT`B(93tPc%4(KLz!Z6$b^g)) z<5SSg;fRo(32SF#Dk4Yv{jE!inzh1(aI0ZPCYaf&x)owq?$LOdc<=*Y_8=oW{j|f9 zy#RC)BLue4pJgoFiTJ}DKQAqrJ)e3R!@BW0^`+(PfvFXteEMd*#hV*f^86k79&eq0 z=O-QK3q1K^)XE8#ehNoM ze-x)9duO+FVwpO^eS3N_PQqip3}0)07RIAR6Ro`L{9GK-S&r+|5(={6aUVAkqdLEu zG7&uiX1f!uj3StzxRY%na#n|&CD3Z25uuxe)(hPUien1&<3!k>7^J6J>I>y;p=r=3 zD_~mJ@_Zd5qdm#OxP6Kd%9Dpfs+wf+HAGsv*h|D-6+TOujVU~$_c#Ldyz}AN#LS&) z5I8c1rQ;^<2sCK4U=;nen zYomBkJYH~#vf6}Fnm7g4*R&}Z?Q7UewO|T(Mzu#hT3m(@XvJk18~BpJ0Bz*A6|4tSUm6yI@gx)D-F$H_jDrawI9j^T z1^E4@>2ljUd9G!ejhTs+@&!6GBDn73{cLIJ z3)aJ`8@#>m&NCcvz@Lo@ULK-#Q}OY0(96pbQ7vpKuCNNn@J_G3k`b6_@HMZVW zrS%uL$7V3pwe72Ava6oxC2KJRn6m*qs>;cL&1>cRpaO0|e-d|ImuWf(+`5LV0(9vq zNXyv#tmlNq>%bJMwpzlMI%JpC+9#LDF5LwYPeihCud8e$lu5|WY73X@6z9Miry~nx zkotKc%l6~kMuk@Pmy!}10_A}a)8pQ7jTdC`iYooe6DP9~-P}PSX5x$)JYhd~%zq3| zJVX6kL2+29jr)i33EWl|s#>ru_gu%>g*aN?R|%a6iqFxBOpZI&f&^quSlkMLV`CUa(CP!=-@=Y;V=@u$7%@J7rXq=BP1F}IhT zVW%2g=&_60>SrOrXX8D+92z%CZ1qBSiuO|eLsOloTa9`asDfkmL}IVd29|?|x+sWk z1r{w}{y}+HO4B%O4Zn$s>`|fi2o6z75$0}TZg>=bj#^OEx%2`Y1(R9zu^Kc3^hWe6 z3)P9xY7sI6_i!G#&0VaprDQDsmYw(!k%4QCmrvz&-E3I8@GY{77hM?qyj$4MyGc~m z3*9Ny6S`Mu6cqLiGWOeSv-lF_4^ugs6FUS{vpryrMSGd!%DYk;HwPJ;!Zl&E$X3aF zM7m^-mD`L~FlVB0LPD#B)(8!Q;@VELgZtPVEIFVt&Yp`95#dKBa_pNxF%@S!M7!}x za1ry8LdMQyD1A4IAWTF_?DDw{T;fg2VICKx9Acemt$`oRy2by!#FBw(`3Q(c}p2 zE40!`$(^883oJP|+QozD5MdP4vIS;|^{g?lpY4uww@__gfMs%r{g19F94+DC<;L-H z`gMVYbr)=w?9AO`l?aRzI#I;T1c^p06w95e7eX~|Us`Bk5qLQV35i&1S|qR5@T+PG zUn6whIW4qLl+gDq6Bcf*&^nQkM&1=uf_d!3T`li$xd!`|WVSFqj0K6am#Fn+%ReH) z>xFs}0EXV$Ff4lUY5vM?kR0A4B2Je5P=GC)yf#6@xzFA!LExJfzo_)HJr-HwKJV%A z*OK0X2Euh&$7yPihz<&k3Oy?H1Sq6w=^`rwM#Q)5>P#<13)zkrdU1!x5!zFvng}fy zS|QW{r36_n5)0qlPceNlyF&PkSdiwgh0iv2h%ZPh*224w!z)1;ne6)OD{3l5jk)k) z-(t*DcnyL^EaP6CzFP(}0~d>7qbcm~gjl+qCHVf>=3p*qD66&Dm_JghR@=|)M;ju_ zU7@3eRtcRbG$gcIXbmWC&k)DmCiqq5VLN;9<_SM6v{q=H(A7dCLN^Jm7wQRZ0Ht`0 zc(AW>M6zx%lB)_>Z^qhx4#xZW3BAbSEgf zIvzcjTAlcc&5m@8hY3&EdxbU#Jt#C9g8d*Cmi(E$!R%!@Dx4F{VZ(tfP&U10G4GV{ z?5R@4gq91f5b6l+E3{JR5Kt5@=7hKy7uLDBCAqfwWiC%W*H}2k={s)`b_Z@Xj^jxl zO<#@$?|0>KArI}YXsi+%61~bjwA^f05X0%Z6&uh0ge2Zct39u;~* zs69;zQE0hPXBwxH_pQU{okgGVB$@}L1uHChE8d8SD-nC;?4JNNhR2JyS9-@kMD zUFi4kzT|f`5`S1|ozRHTdZ8Yuu_9_$VwH^lqQnSxx-{_ncw^=tU1>bMx)^kFQ0&F$8)#vS^jeKk`1>`M ztg3U>qFHNUyrWstxQK=An=-|o62UCN%))5q2J1XG0j-e94C^%J-*D`!n#);pCAKP| z6NQFE%G8Rrt1aw0HqV>HMrrBbP7)oc)va^gfkzO+|o5%GSyNtpqlb+xEMUbDX$QYBeYWZQZQZ4@7rlAUmf0z z2Cl`T#qhOQvl@ePqY2#050Q|r(9uGxgiaJ15?U>^M(8}DVWG7`>x8Zb)>?b!xhI^ra@$)B4c)$ zg0p{}g+J+4NQYVCs7Ra;dWz+^H=+R%Da)alilfM-ct>#+wP#496k0CS5!zR1rBGLB z6(~9?b83?IM68(Otrn{#aqzCf`P7Miidei{wQ3J^Pn2*Wq17BZJ}a-d8BY6tx!%g? zXpUIZ#Pysa>_Ga7dzl&$o+mUcv{q;xDCSLaAwKP0Z*>UrA6q-H-pcF9r;`eBoF1W9 zi)=*bCZY8l4h{{OR{7cZ7SG%04Hm0nUy(My`JCXL62=p{S3-*P$_6?#Ib{UA~*?z3;U zSeWhYmoVl07ArAyatm90*w4dv(BRKTZ8fkr&qcf*4|4MQGxbKw^C+Ryh0YbaMCdA^ z8-;$uG-T*rehv$DR<_1-bPZE`Ez|IJrnN%rgsv7E0mZRef6KO1S#R;ruzF68Frz0q z(9uB;@nTh5n#P^Mrat6Z-@(RLkB%mES8}hs#a*k(9a&j8*hft`Ai#jJ$AnBvY3a1=q~0&zG7;B zEwcNVI^RCW^Z?W74@@IRn1+tY`(K_z{~~8J7H)?>4XejXx3d`xkM64NtoD?M{U)@> zKRKY#NKgE2qy(7>{e}Q+e|FiyEC1AEhlQ)^s5d9d>Gc+e5E>C073x&*`%0m%p+nxH zMz~D^3+s)@cIC&>A1u`4rMJc9pXip+<_GI;KnL{)lQTvb9Pu*|qaG#bd4O>{jYl*a zN1Q3NQ+=F*X6@vxme7KoRwHZ?L#Rd+StvizrSjvfmY>iD!>czxp5bAi1Ohl;p(P>d zXb}9<1y!H#Ch5M*YDS;!!e{Nb3);(c2(xNz48rZ}*g83DmsP~K|MT+# zmiJhKf8ZOY1fSs?hEDTz9E#1;Z@aLuL&BBqmT)^ITH9ls z*rO3u?KwZ9DSJ#rGxuXGZBD`SD!&aVMFdHRflt;ptEJZ#bM=EK|qDX=rALdZ@g|3z4bFAd# zBro2v0Fr(7MP6L0+bB64ml|r~OAg1|adwkXoOgAa8yAX8O^aA*j^#88IB`)6QTq^G zoRbjcC@z8igd~n6Y}uBR1Qt>fX&k=F7ly18XIn{LunLUBm}pNn)rv7L}+ThX{sf{o-Q2U5K&oj5lkbX6$Mjq@Oo;#sL_$dlbT+6W3g zE0E$`k`zHkBZ%BX5<`uhc#gu3^QEMwd6pYzBQqYj$Y^R(v~l?Gg<+&Tf|P|VuQ4tI zg&G&RK^lB`n+TX@CxjB5Yf(s1B;Sq?Bim66xp$j5RyZCn6C&|$9AZs$8@cgFdZKN4 ziTGb5Us9?apPXbTM!^VM0sAWF20Jbq7frAmy9w?E;fqrcOB69CB_sLK#?eGC0ns)N zU*cX6xx{V~zR118Y3wzMG;xrL=mlP*aGZB#^!iAg^I!_68wC@+A%x_+e{!urBrYx0 zi%Sk9rKO+@n>bC9lEY0R31MV6kmR%9up2p-dRN&A4zj>i#))%~%|<9+Uvelunvfcf zXI&vHEs)HgA{A^T#PS7v_+$=B*|t&<6tVh}xY~p+_2Rua_gYj5R3Maea+)vH*q4;- z#;1B#Y8WN$+-P6mUg$Q7B%)+3Hz6GFHA)NP^Km&Qxz~hDLEBas|8wJgX-<4J-i}9o z2_!}1Q|ycED^pTa-GoR|G{K7tB!y94QD{L9k)%spluH;HN{d_*igzxsFN`$yn)o6Y zM4I@*7et$c8}oOuFNj>=HFl8>?*ca=Dby$s2*syG65KeXDA7T>94jq?Z`vq?0thF% zNSNith2uT0G8Z~cJhYeS#SvsbgdkoMuQ9Ti;3fpZ7Uwe!GI3#_9q%NDFAv>h3Ku15 zr9>L}q;%7w$XyD`9K{yCF&rO>Pj%x0PCUNEWueOg$w^5m0TgMH6UQRSDDtG_)MVr} zE*VuZ5|^5kjBHyGBoDF?{(5M{d5w@&l&^et@bFPWsG&%-11@q6kP>PavXUZ~g<5iXAX@xC5K44W z+k9xHPGW!~OiD>cClQxsBkhuxvk|8{33h^qZI1Z2={6$#^$i+wFVU%Z_zNB&ipC{S z@=HXuc%Sw*QA_;pb%=cUt(!nphu@Yni27n6pE#fB5#Wp05>?=L-WH-P{66z7Q9XV~ z|A=46Wt}E+SiY(l3{9j6!oNK# zkzPkUuTDs$SMi&-J&~d)&%S#SO?s0XOF8-OYD|^j*FN1?^q$CQOxFRsBO0S@P_By` zQ)`4f(U#~^9#pPwO#G8rU~uGKgKtut1U=0Et76}q20x}aG}7RIC{7z?@P8BsmKuy1 zqr~U!F&MjU=u-TVfWQfZdntCCG?DlQ#_)v(kB#Ar4W1Fhmm0hzhLa3lAH!D|yeEdQ zGWdrWzQ*8RWB59QFKB1d=iXrOwK05?!FR;)pA2ph!^s9e5yQ6`{EFhFrUqvy4&P;P zAcp^JaA(Dy;x80Ce=+uUA~J_#4H$75}Puui}deP5$>QzJ@WH zKuV^GKUr~Ll)=pyC!&e$HTWsTO%?w~ajN2X6$cc5#P|}T@QWA7_wTMasw2D?@*kk_+iC)ic=K_6lW?p2LT&Z}zVps7R#Z`*;C?2o) zd&MEeCl%Kyz93-o7gl_&;#$S`DXvregyM+eRK=d+EX8{jcT(J-_*2CP6%SM#RXj@Z zQN>dfpHMto@kzx?6rWPOR`F@Y^@?eO`F`IhPE!1n;$+2f@0s#Q-e}~nP<*%In-%*M zw@{p-I3Y{>JBk-7 zu2j5Uv8#Be;;`aFit7}gP#jSlS8U45Q=F(cZKuiqWih_u>l8OAZmRg8;`#OFT?nle2?i*FJ}zWWZ)&z-{3kkx(oxeU1!G6yH!3(<(n(MPVpm( zn<#!k@x_YYVVs21+Mk&I5Z$4~m!R==WQ_RIP9;kGm5M{(8(gE?-=)}IVDR&b zUF8=mPF`mCgA~)R22WEQ)%4;|MvDH3^7ktaXnGT2Zc2WCG2!o2oUHOsDh`}6{4~W$ zOAW429R1p0{M9+pmlQU5g!DAJtD1U`wN;do-6uX)p3$_Wz=P15TaU|Qw`xHlSHuzb^cBaAEio+WI ze~QyIKLZp8GK@TmS>j82&ERc{eVX2=V!F)m8#gxc5zXKAio=TUQ5^b{k$;pi?4{S$ z9!gd0slDW9j54>?ek)e|*QTaF>8$dtHGE&iVGR#69_dGifPehGXE8?qQ}V*4g6AqO zRlG#;hl-aoM*QAk(?8WShPsqqrvEym^0vw!S6rs}q~dbLaZNZq$WIHS?`p+PbAxYH z9B66q1BxT}8=Rsz*=O+cio=Rw)|&67`rcQZrnsBpfZ|HUQPn?IF+Fd}t447M_kVHu ztyIjnBQoBhIHLHF;^<3;e@1Z3;%b6 z3l$TtwPpRKiX)o-PZfKL$HXvh3}X2j#m>tHuT~tu?I_IOquBS1!G{#5YI=WWjQSKF zZ0bY&g(iPdjqfJKHkJuk-#v=M%Kw|<)Y}dJS;e8h8T@*TkAafIXDaq-`b!muaT62s z%N67HH^G&P1GgGnrI<9nIWesHsa2e$@$XdZ++o5WRGjj#!KY%l%(Ul=E;9M2&IaG4 zI8FKYDE29SSh216ImNEx|0<3SG5T^8({~29XN>Z9kC^iRK>7A!lfE8`-9-iuQ0y%= zcv6hN*5DP2Q{uZhX4{yj1IFAe`k#XiN2FV*rHV))l8 zb~_tN6L)+6vfV9gV)C7VF+`1 z?@*ki@;@q0?P>UNmzn&eeq`_+ijzJz_%X%y{|tUThQ}BjP#h^Y_~TgkPYmv*INZ(P zO2x^23`RAO`WDvo)hKq~HvF}UBRK|tr`W#5*n_{t__rB+1;%Eszu}7wzKb#b^Zn1v z2Ykv;yV~&EC{BeFk<06K#VPGg|56;o!wv4KIPi(V_;Y{~U+Nx%XDIfqGxeSSDj%mO zMe$dPX_%2euGl$aa1*p8miH9jq}ct?@c*hfZJW{mcg3Xm6~*=|ro7T)@`?kBoqrqt zr;1(Wk5L>_JVSB#H6y=7aYXSB#ZkpSFvfpAG#oC^UzDG$<#W*$CV%d2ro69b44JF6 z|M;`=orxyC#}%i(Z*XP|XBZq%oRn^G7sXz_!Tn-5&)_P>u7>BoPsin*oNM^I6_es4 zic_^cU2&z6Py4GW|C<#DU}$oFTQWv|k|SpR{)FP2G=Kk6oTBCPj^ZZDe@}7J9mYPj z6<@6UFBo$~b4+^2DNa&6U$MQ_@KcpWz6OKaFh-p|*xt0amt*`jrhIZ3qkJCG{B%;>QgJWEtrfe9eTu6Y zBO$(%CO-UeF~Mp7H2UjQK6ponvrTcDhW8ZHEF=Fz zOn!y=p2rnOu|CG}$6agmC6yR_vEuMxgRfWY9f%kCyA(SKCVf7|F4o;xU+WlO?cb*q zN0k4(;;5F_tBM12O!)Me{I>=N6?^)9Ix|LlOuOf9iLa;fQ{i~v_y;NuE3Q%;Q9Mhr zbI{1IV~qA++1b>8{zF2nf1>)|4ye41bweqy>kPk2`Ij>W!?(}ylNE=t-pKMk#S}F- zMRC%4gI`gcdWEU)S&R{XRPD|8lppxOe9w;*C#!wqD0bBz8>u+yar3>WD~>*9F#djx zsXvbxyfGGD@ovSw6vIELI9c`mtT?3l5;2dJ{C}kO3}d7}N&CM)DUO7U{d}j&yW0QV zuQ=s-6W`-1|7xY_|DTV^V?CM6^G(GRHsz78IIzLsPKr~MU#>Vj%kV1|+sYrSIBB!t z&s6MNVDM7K$r}yc5DTyI?TPWX8vY^0j)wnDadf`nUw(rruc(H8QfNJ$^?V)=R!<<3>n-{acZ@}Rf?0Q8$2f_KhEGaic`iL>?uyR z4L+i>l|0pt5MReS0R#oi!O|8G;Ar|qM);!?%WDn6?9|24%? z#aW62{aZ-<9ThtR4ep^hGTh){vG5}eu2!7%rNOm|ed7$q-)4~hFs%LIPs*?FW7=cf z%_e`T6OH_}jM0BK(e;bFWBiceKd!h!{fTW9JBt6M_z}%tn&NvM6JLNa^j{1|8khG6 z$`21Q{9du}Dv!J6rTno)P2_P;xoJ;B4aVi-f}c`8?(G(Q)8~ed`?&?TRQ@5wKE>9b z3_nHnU931+!{4YlRpsweyjsieZ;I;_zswlv(sE;#$QmRK8m4%ae-feG~pA zl_%AorTm+;zPzXWi= zpHV!SG1rF=O!+NToS=A>%2%nror<5=_zozZsQh0PhZHB?YVu#L_zK2|uZilvL-ECm zA5{4om48O@JjJgn4l7PmT&tMJC0PotG@Ykad~@-;?&mC9GByr;Na@v)fvJR_fYyOyu&yGd~%Z1~L;mny#v zV|?#q-B0tH;y{+kU#`kmXnT8K`PZp@FXfjje}wXV1t$D##a_C>YZZqB2Jg}Efm)Nk zLyA4cXA~!|GW;u>n*61$H@GQdPJgb^_mJ|dG=DED-!tcmG2Sb?=$>yic_^b z>l9aNdOQuEpySP9-ct?Vt1;MZ>`wT@_trvsy;l>oHWCvztLYz z{-QGtzFBdk#$X>~q%WZQ{;qsS^}VV%G{?y2#rX3KwiPF_3>kIBzY{T_EQhW=ce`)p5kv5C&wB7F~&%LmfF9K?=|^L)AG52 zG585ues?K9r13qZ_!&*_voWmw%j=5MG`@lu{=~%paSX>jDCzwohBFKv8^enYo*Tor z8Gph$#z>#1{pBvjrMCGV2UWg7>%$r4*J^&QxzFS`S^NK{itDxg{7vz7irXk|s`4*0 zM*K}R{v5^EDK1g@CR!dnl%J;K@o?oww11kRxL)xp#h&7?6gMdTnK9xIsJ=`7YVs3R z{_TvxPtx*uSh1_}uf+I@a~Y#Q^l5+i5o7dEZ|nE%qj;0f=SC`iUCU#d;;@$2e8&Gz zduJYISyi6}gQy?@+4 z?(?LdXLs%2w}!pe+H3gMx7ON+>C*AA5#B|5`o&MDdN{ zGsuYlZuvh)ye7U({;!w+p4?aE{(89|k^7?D@0a_>#P^C<me69E|#k1m1iCf~k z#E;i{?vKQe6ypbry*`PbPDcG$P;-8BD zUjC1f|9iw&DgA5mf4%%abkv`>AonMVyW&&Hk3o7gpWY~5RsB9+{!dW-eTjHTd{F-H zk^fhThZWx&#V2U||5Jq@R`?IgeMRAy#cSd(iKkxe{oN15N5l``;OSo$A1@w$jr%`M zJSl#j_&n9u3&d;cA1@a#sXqRmcv1Y{$asI}ssCIQ&x&CNG4~1at>V1+PVu<-KJh8y zUx-f-A3Nsp4U3;D&Z~btos9Rlr2I|D{TTVbK>SE?K|CbxDEyT2e~tJA@tegH;tz;d z^}LUZbJuuz|6TBZgY#F#Q%9Wd6VIx@{AKL!^Mm6ydVWfBKaq^`ev0bLY2wF=&zAoM z`9EJ=6Tej464%6C@yo@_s&B6s-zxrNaZdUFAQ|adRr!5Fe5c;WJ@S8#>eo-ji#K`x zkKN??yF>2Bi|-UaL%bqBUHoBqAzqRH+r;Ba&zHq_%KeAp+r$ru?+^Lg?D79Xyh*$!-Xs30xGMg*()TLyHo3n= zJRyFs_(tXTQ{pkXe_ni+_&dQ}{n7p6w<`RxyJ_Rk@!b&dL33@#4Gv{Z0mc zpL0e0em#FdJg@NAi?0&DQ~Xx(2gH+~cK!AfWW4|PsQ%q9UKHOcUJ`#t;TII&kL7-& z#`D~n9^XgBCx}PVYR21iytq(M*fdh`}iaA z&3d2QN6Y*jkiPjT@ojSdoOpSUuMgfOzE%8nGW!$hpFfj(Uimxb`5ylz;%A6Y5s!%{ z#e2z!Z$ahxGP$=f5q=1U`OC$ZD7~)~FMiMa-Fu z6n^zOpMM;EmZyJ3`F*r_m)g@)#pj7nCnNn=Dg7@Hx0Iee^8Ze~k4Ww-az8BhU2=c3 z`2FG!h)a4u%i<~Vm&kbj^?Lqye-<{$ixnCw87atDpL(j7J_ge9y+}|v29rE?NcZn}ier^#@ife_!FhA|6)$*2J?a?}xt7!{?llD!xd3qw-r6U!wGM$w+Tk>3yBtmlXbO;+oR;K5U1Zt*l3`CruYULk&u_$}gVmA;RN zr!-%ZSI^%fo)=G&Q685l{g;V{WdCZ2 zA1_`IpCEoC8Tq|a_3NGD74e734?+FD&-WkPE?(T{`%CT=PiVjDs(9%b-(T`?!T*zd zf5^km@%WYy=|gh4+|$G>az8^n@mP1?DIR*V^NWLj?MH5i7f*EetHk*${Q0jJ4}aIw zd!sm~{JcxNr1XD6y!>U~-*S8K|3Tkx@j3B=_)BEA|1cf~|F7`p|EqZA-Odl+>iN&T z)A@Mu)FJ2J5ik6<=O<4_{HLh?oFn(8N4oo7xlgLTy;$zcZ}9kL#lv6p{LhQ0?sUFZ zJn>JS-?xh=?{vOJy!-|Cf17ytG4B2aGSYXl^8XFF=Pz*g2gIu{bv|aB=l@8_`9$$V z#d%!3B=?KN%Lm>4pg31^?umylbG}ZT*Yo})@JrnNL*i9^-{P;u3v&OQ_=wW~E%D?& z5C0$Hi384$-tPHX+V6a_cy-o!R6KdP^SR=+JPtCadthiNhegzrnn|QAFbCc1Z<+c8MgZxkA-2Y+-FaGc1#b0~- zyj46b_b-tVe@XfOVeo&H$9L4Z?miXzUor|}>QX^4+J;Ln>UBfY1n|9y@4+2R|-vr6wDlTlu4(pTRt_tm%idfH!* zk)Ia6d&Bp;EY59n{zBmAIe%BYg74+f|NY|S$2kw3=kcu`=lmq`)UnQ|iie)=e6~10 z<$OSV0PJyi#@khInz-`6uFKxgYl;kMBLIPtOn^5kFUao}M>KX2p1} zx1Y1bL*nzq3*rmKd2x}<`mOPzF3yYR$f(cX*7=B6EBxwKf8Lt{>w87-60gbq7I8~_ zn>a82f_O^&O>s``o1d$+_M-MZbiP>U^NtU!{jnRxlR6KzUA!p1NSxRBJ|kX{{?sL- zJjRs&E9JhX_j9fI$QJKU-X?BAui$I=pm{8a9XpY!-1 zyW7({^-!;W&lKmyd2wsEyKfO65nm`?5m&_v;sx=f_z%T-@%zQY;*X1$#dnCO#NQAv ziGLh3p*SHf7R{J<^ zugAYj{oA9-te?laK5>$G2zENQx6{PK&+-0rqj=$`?miLRRloKG_xs&{L44$FkAGe~ zalZ2##ra9+4~biH|D1UFOn3jLcx{XG{egElKW5VNGklKobH%NW^G@+n)ww60Y&idk zcm*HEVE*qAFI?vQb8)WVe98s>y!?xuFAR(iZ!mmaygcUoT5;=2=QoRUzxMb4Uh#zZ zlj0Sfe_sjiuW|q17O%?v-^D|3bN8dr@ACal={(Ny;_ z`@~b!tDq(lEj@#3m;L)`k7^DD(`-*{j)i=8PYsE+2?EH?vO7BO-%kOme74hO9INv9p ze2eo#F7otE{i*Xw;z@i6$I6?G_A+^m&o^Eu_XT`|lkU64t9oBW@uK*Z;^pso`Ccbp z(fj`+@xssC{k>#7Z$jG?lLymE?{&xPXF zD?R*d;5*#^ym(ms<#po4M|pjDyZFeHy?ov;&VSFte?+{d?+4r_p19ZD?-J+4YvL7^ z_XFbAw>^EwzS#4>r1$q^@xpEH{%rBE#)s#Nhc58vy-1up%FFW-@v6?#7R5_C-`orS zYaair#cLXmZV*pO|F}80>wWyWcu4)%Ux}B0==J~8;)RySf0uaa-@H7(FK($m|5`jL z{p$&rqCC)kh9C7TYoAXev%ToN?5X4-*b}7xkI6rO4uS1?hx`xY!(8NxLwIpTy!dzS z-VW|x_4@NV@zfpe{x){{% z63_q9n!h|&oEuVkkXatryZ>j)eL~-p9F_Z#Q~mkd#fzsoUn*XHwsT9Imw)^gfyKWd z_dgd;$^91bisHLH_?P?F#4Yhp#JT7A^NzmE<6la z68WD}daL4=ctJcNzDd0Fcux<%Q^NAhpXmHP@#EcBmMnX;wkZ?Uh3|xv)#UU5*hQI+^;%*Uk7r)~CSAoZ!Zxv6-{};tm;_r%w#XlDxkv;Tb1(jdW zf5bWQsp7nNT)c9NKYw5FFMC*1JS2W)aM$;Jt`{GXKK2&zn)tmTy!aOJ;upQXe_FgM z_j|;{O5YE~6XK(%J%6kE{?B8@i+6c^&lImHzO%%W3cpJ{C7u=M^u3HL#LLn*UrEOM zZXFu2_H!-xA^1dYPXBJo@Ov`+KQsIf8NMgO-^=jNGyKS6`uR_FesoCBY0gNo{~L8i zlKtO#8Gc!Y=QDhLhToClzs&Hh8UB2Rzm?$!GW>{={DTZ1RZc(uaT$JEhDS2IBg2`Zq+cW&Z4BwXFuV?rt8GhJII{lA!J}R`I zXJmMTGc^eNcd7A0%+ndJX2Q>9cp<~DbB^PCN5=gxGW@X&-=5*SGkjl$f0^N9X01Hp z{68+kPtWif8Gb>AcW3yL3>P!p&G1zjzBe_orm|ROh%oB6N%JA(O{#=Id%J6E2znkH^AC}AgGp;Y=`U4{`kn*BY)LDc;T>pXV7r1_j>sPq2oP{4_LS4dzsdet5xQ@p4FkBDE^$1+Y z;QB3GSc=RYhYO!<&HXkmOnq~hp5`#c%{>MeObxlm;ldO(htIa=F!jvwyZ2AR^<-R6 z!3Fa`4pY|LFfL4mbH9TNCW+k1xK6?KY+R?}It|xza6K0nObEF%aAD~#H-c*v*9Kf; zxHjV2gljXdaa>rA%smg+^KqSp>ug*v!1Y306S%hEItSNQT-$JM$Au-z+_|{U!?hFF zi*R9?Gq(%ZZd`kDP2#!$*FIePaluTGyAan!xGu(pX?zY#jk!y4VM#LgQd}>?72%q~ zRlqfktB9+Fi{JOJ;F`fTi>r$3a$E;-)o|5uHE=a?wQya5tBtFJtBb3L>kzIvT=TdN zp%W++W>lL_Oi3{e6+ybsw;d(W$*WkJu*K2Y8J}#IWa@XQ|9j@zey&l)~xNgAp z23&uD3;!m*iF)!x+&>N1GjaVcu4m!GzlHx-*B-_HlFW1dt1bOkTl)X8Ee+?QbGJ-J z2lnpTzHiH(t=n_ad4*axYBqAw&d!crt+v0|=C8a*yLQ3b&TZ$0yB*HJGhB1-7_+>vtF1f&$X-Fa(g5{Q|`_m zp5*VtZm-t|d1&^!tzLH$LAD|=e7&2+3mA~ydXin7Q9&DZ=W3$%~+>g zD;K+4o27D##XZQ+#!9tO?ac1()w)&lH0YgdO6LE(LVIvAj&2XyWx5Wp#HOg~VnWhK4x$#oFFt@APC~v>~^2-Og zSDNkmjt8k15aZ z@AVBc;kdq0_8kW`$iC};-qaHQ1~s#U^S~z7cOTrm`tA?XwE7+%tXcJaJb06e{Un-G zEK4_~Se$7_eR-w{#SR0SPv0%mbovgNW)nO7ADT?xU$(i#F6p+=7pK}mERNeiUlQtn zU!uByU}tI=V|zcaGxlY;f4z_WX&)D@_i<6uM}0Ob&zFn6ZaJDQ7fR)JF2c7)a809c z!{1R}(ZTZJsN0MRonp0`6m&{8I2F;EQ>q{vaKAzKg?1|{luGEUJ5jGwF2RYSnOeDk zf#2?D(J$A^Q43vg8GVh((Eo>9bl}sBox$4WD|+QlH$pF7nk%%kVtDN~p%TQtyY0it zdxS^xk)$)*>z0~xOhsurDik?NM8*6_UV>67!kAx(Fh2Gr2d7I>r+r0VP;Vkv2|u+O z%L;jIxt}63+RjAevQ$(q%0yOfx0`$&NFJ&$<82j6(LA#RQMCc>sa|e$qfQHhMG#uK z(HWVkm+Zy$a|vOy)vY!g89CF^F3;pGp&pZqTIB*1wo0Wh>lSJU&96kL80AAqg=4Kb z<2Utky=jGyq_k!acdEsLl?)1onv{ELqr#!c@huAI+L}pBQ|_H^)9OxeJ~Ykx90xyCEwKz;RQ0NeI@#&!;eZMNb-#a1strD~_p>6Gi!HP)%%Cn1fBvxO>K$RM{)x6oz*#csVi6CMyX z04+Kpfd9Z=P@Se)e0RECEzOjf%Vb9p#H{>uLR?8vsalw6G&|jDk*_rA(y&IJlK5K< zB6TkTt#4-??+Z+6Oh{Ng20zd%4htfLHc9${{my23(^$FT9cFwR)i?{9ZqD?Olj&Zi z!d{qlm3{7XwNYS&K_w~XH{_#Ar%-RfU$HV1q1#|@$JFGg3B5PE6F@vxa9o`eTi>DdRxp1heyt#0gZ9+_!bM`4~Y^NR|# znkPuv;ftOwSVP8ol0`-lD&)baQK+NWU{Di5QfW8qQK!~~hj#T)!m)z(U^7DVjRB(* zRXH0>NN1ZNw%KlBIy!{^Jo0J-y=k!<)eDEG*{^rX?XDG{oaZ!zFzS>aCer=13TvS=#DdD|ZULwp}8$C=$(_ZR@gXO4J?dZkz!&>J!T|<+}21%E`)#XIY zoZq2p+f#a&2Nv`~I1G>Bg-_IDAquNiD;!p5%S2(GLf3Nf;QDwdoJRf+wwlNc>x%g+ zH)b%2f=*J8N@Wx+dv)9nH(KKrW@tlA>w_#ab>|LpNVxz}qlp;ZW@{q*|OX#Ar}r-$U0nv^H3O3Pq;7S#McSUud@r z>}qTv=AUl6S&QqHOJ~ZBa+?{FuNjQ?Xq2k7?nhlzAFTbcP+e4OLeoHh(U*8DRhHe8 zi_%X~>XRN^gNmcZ_}nio_orfUP;wPfySQPLT|9!LMk7<~0E=DdN}-qOwb_v$s9Fc* zppL6FjUFF59dux9ABj@vLkLCn&P>urjPg;Q?qOu0#@31E3h0*_P=HD%Rp&2t&ShS( ze%~rU*A1Rq%@)eI(?P!)i>Pm8WavLp)1p?hhUVhYcqI&jzsr~s%s*;1)MAs&AP^Xh zC&muO7lUe}(uC62K)=F)5{(}ne52ECN2c>Z8Ow;qQxel#qLH*W7n(;{@z8ke$)Tjn zogyAsD50vB%7^T~2%TNIiRZF0LzrOi8_>r=^+N@$qh7I$oS_!gn;fmgtpaR@?FO1= zp^Z%yCgup|3bYTP@LHhePPG9w*pc0r!@+25ek^KKrz2QM%=w_YHOOERy0XC0M-KGH zV(PX{8$(0kfeZlzTYMu%_~lKgpnqzQb-wnp+*k}T;XdLEgu7vKHOslq{FQQkq>2qkc%_4^r^mSGhK-Q^a4q_G9 zR7ghBM=PE_T6qvTkf;ks1!m9bq0oEStAJzSP`MNxDzIfELTD6os9Gql>JgoNn%e0eKo4iVf@1bs4kbf=qV$OBjwAfyRlB^qW-<9 zTpR*j#DRmFuz9M%K3bwxp~ul1UMMIxTwrBr5^IqKB+}fvRO*z! z&Md~%l%zY~%|-@MKdSC{-i&S@Xb$>*#X6k|v@X;swo(f0?Qza#V~$&9Yz`MQ`;sd1 zKXWd8Z*^s`#vy(t8tIgaQ4#7PVRU1XV4f`Y+Ey6s6zBmW)5j0mye}!Kl`Bx|VQfeW z+tr!b_0mLSGz_t@6CzEGe726^mXil29na=4jh>IDMWSXz(RjBxvS}1UBZaA{QbvHD z&Za{UyYDg97z+n0Wvf3efd>w$m_GS*K+GXFzLiO@&t_}rV+R8p=Y%ftVYGiAVa8rE z713qhy23qrq;?PK@ptJ`OmEO_Mi|4~VVX0ez;QCoHK@lkXy83)Yr*ey4Fi=` z;?8WfV$U;Cy};oNzUl7ux$i+!aI2$M_UTDELb(sD`E?^|9$uZ3UfG;R$51mX=-OuE zXdzqn_j6IndsnDhm{@oL%&Ess z%4q2|O$kO0hJ=-NgX=1GzcF#YIdOj`@1e4A_GKPn9HN3__pq>H)Gb;^OaZKMarFU> zSkJZr=4*4@5Z76_jrF71uo0?~_1~t^nBPtQSU2RGq+BuO$%aM>#zy)vjG1?T%*J^P zT#a6XMo{|OH127N;~t+!F@!D|K48T`cgcYg6PX0t;sdQdDJh1ngdb~d7Q-BM3F|h9 zh@Qm;^HwMdD;YNJNVSVbG>6JRyY2&uLjoGOr1FQdq?l&Ww%;;kw6CP^p${ z*2Bf=mMPAMkG{0q4lf@$nT4SnHLnK4fj__m$>Nd#W$N`k1WG2t{Mh6qnNJ%eP48}} zUclwe!?doa-%1?|0x4fGhqyt*(*^9XYQ!%-2v9-NvZMer42-Xt3Id@UPLtKd6hvsk z$*jB5m`nxLjHC~8vLM`M3Xz@=N)_e`c2miqv@pxS>^bb#TdBCZ=x$-Is0P!p`|43$ z?WAI|o)xnnZ((M4bdzGGM$1VU0Nf&piF9J>jyP#m>|iRP;WOsWY@HJUZ;Qc`1~}RW zsT*;QWLX43?Ky9b3%FFx1 zG~-}Vfll=nS03WWyG0D$bkfX6e_V%)WGO3PTU0VZDMvG%Wka|raFA4{^sJLBZ)kU% zEPBbMo}$%@VC;;8bK;qPi&Q*Et;e+t1CwK`S9l0Z#lz~L0i7yz;J8dE(CFwvEh2bF zcZwN?Y1T-91YS9;+9dsPmSywoq!3C*{3aDVjK3VtlU{>-K315+11(ms0gA&Uqsh=F z*|1JBmXdI_aD5u*QFCkw3WG?Yba^PIa33c2bj4acEgPEZQ(~G@Xg0KcdId!jam9cl zpYg)?bkG~HW6<7{(`OSQq&C~{-inSJ~qe!BS ze|~ENNvy8$v1WC|Lqbww6$VovvzC>8P%bqv>ae&u?Xia;F(q60!>S%^aY1J5?T8T0 zEF1L=M64}EO_(iR`=JCa+4GHiH{F;`#zP%?3L@}^LU;w1K|1Yb)IW*-le!CXr}#V42r5d3mYrj zXFtAPy^duj+l(+06iO^-rG=c^HH(-B_}HAuqOuVwRSKx4vN!QAuku z=b%9$j&i$FD0YXp=%LL9f&?Dv2GzHv3gPAG{PqJ zY*-A{m-HHDEv85-U+yl5HHQi+6b4W*?YZ#I{fJ10M$Za{kg>cOwy;3%a|6kmSmsWO z#`E03k{=)&86d;rOd>iDyCEg(S1uTYi*>?xMivHSF{A!oZSG z-BZ=RB57l)&W+k=Y-xkCRpE9B_8vh{#|}Tv(#Y}rWV+Yw;yqgjl@(eal@(eyl@)GC z#cAt&iDzI$#wL@H6X2}lG;CxYX3Vcv_UA3cPgIV-lLeA-`NEW#K7 zO&fhY%g2#7>yI;IZgjpxvhfC0#OMY~Ms8v-6`!Iakb*vh||F1H2uMy>Y*x zlzZONsM(8;Tfq z(3lR!;6X!5snLC5P^@d!I#$}XV-%sdYXt*TXpU4OP1B}YEb~Jw%d)8nNnb6ho2hV+ zBtn5QVYp5L-9j2UZ3}al_4Lj5(A>>qgk+>br!NYJI4*z{?O*3&f$iQnbrr|W^?UyK$6%k zCRa<)GhjcMbvAShv+cfZ+ob3S;@x5%i7jpVt+lGKjZ&h7H3l82TdEjS(bZ4hQW-bR zJAQb2P1a+wJ-B|$0_jB9=yWJCGFtu-+d#)nV>X8IY3`n`aD(KDAe^9?9>YZ$tzR%m zSj%VA^p$*1pG_MOC?rW%X=I-&NxzKE>V(cF&bK#W>xE3#gtCb@0c#44WsJ_p`sCOp zNo)ua(|Fdmjz}nr`+$YBAo2wY8m0VccJfZk7AR~iH*?FZ?Y*RaVihg6F>-y1%Cd?` ztJ(1EljwNz*s8Y5qZ;vfA8yeeu<*sEqNO9*B<+EI9xsyi7Oa(2t2ldUSAEz{$(u!= z(5HmlAJ?t=I%UcMiZ72&Ah~*!#oZ}1>{Xxe;;(D<;yftxCj zTh6%oT-&WsiW=B*?>muWQOs^INC%D8xPgwSIA$^&=-6x63moWnW!1(3zK-;=7$sp! zWG~AWdE-T~Fe~G!eV2D&2+w zjEKE(ZEO^JnAd-B*$ESGcG{N-bi#oaBleI>^=Zf8=Q-Da~k-JDO`q?1DB*>_HQH{)x= zE`c4a6S<(*$XX$&IAX0k);`Il+4hL*2PBlUS3ZEYR>S(hT$sSN6=|KBLQW!ru0(x1 z$l^vp57yB7Mm8Na!XW3f3$}L)XFFdp)5H#4cB*L^hF%ym@i5HEt?u|nS$dZf`{{vU z%w{#vMMklHRCCpmTismb=K0Lxh&!3R+_gqz5XKODweDs;m==3XbCTwfKJdj9*#_mr zW*F0>6J{e$TU1ZAVGm(4G7K9SJKdHshaJ7F>ewwtebYN2HcAXe$yu*N9s5qgOoY)c z9*1#1!z~wB9LjGzlZi}8Y>gl#!7km5A5;C@55`zKTVmS)dGrWdw>Y)-jTu;l4=Yx< zg$<}~dJOJagfP?MG$MBD*fhdc?0NccWD^f9X(OR?t6GLp6D8GSVq%}zS(5Szeh{D7 zJ)iP99$}R$8(rE9eE74xFT+FGI5^ryw$%s%Zn%PJt1*L3);Md>;O0Z7E?y4vo)rIc z{T+I)N9ER2H-IBjtB@|M-lx^%5a{s68uNK4lo?;wXG2@1o59EtdpGjuq$iK!xZp7DVve`0vJn9Fw zjm&o?_)Z+!4Z>2d%dzge$2OT$vKv|2k0Yad2&~t zAB)dU=n)mREpwhJM%bWb#t3^Y86n<__2NP7iy?vh<@IBN?-I}Rx;u&`n^RVmScb}k z8XEhxTqd$bzb2bc2vMqj#>#?;P*yZKDlV9x+8BvMwF=9mh;H0M@GB1}-v%mrnpG=Z zSmxdkhI5;R3u{$7_ZJdXk zP%7C_6K@@c0xW4!BVS*JrspDa=$VksTm%z7_v51@!DnC4o|A@joEe}wDJkNISke;T z>zMT8r@4|6TNTi$yreuV94BQQVKv<1HGphWC!fMj9M6tz>#?5g=MU+GK^{eId)5VE zmw3F&j~m;>1Mf}fhF$D&v0Lo5-~sw76lCbz!OI*itY)CcrUts!sd2VudHm96*CxbF zh(|h1Wudad9S{i-!bk>-zV$}IlkaJ8j%zBCS$=VbXN9h_tC=!gN zJhVqwJ1bELhj3yE{j;hDAC~RFT*jeGx7jPsMjiXA57!GQW8I4D9N14$^fTD!IEM*Q zoJE(#dAvN=Ut{t27B3w5cKR5@voivyGF+KKA`kLBJvOYO1^DJ4W)-!P*2e?3JIMx= z8tR&N#=Hw1G4Jt0IHV#306lU{oU3w}<@#WBuw_1=`$HW=d#+{AcccWisAZCH^nx8n zO3?S>1z?W-ZYw@lX!Tkf4G={*Zir0N*rbmk_?T};d~N4dVj{|((YG79y99D=$|0##mRgJ@zfFm%=Ecr5jy0+?6`Y8At&pf zA0vosl6U_Jb0PNH#eQi%k>}-qIjsgp=G!Tvk%-B3oWxe@enQtsJ?(r z8N(X(cqe4oG~~Ne`!ecLs6JRmVAOGZY*PcoP%2neIr8=WQj%m=)g;@Ct(j)h4@BEZ z7?G0FF3f})ANyj?HS8JqFbI46QWH}GcFp`!2nDbl_GLWm8=~O7H$)qG`wcNzEF?$>obGwr*p4gn7Zd)s+Yw-=+sMeEE2dbtd@PH=`eu_y4J;5CY$8I*7U;xQHIpKz_0A&^y^}(8Lulr5?ZWvvc z;|Gm*{5SI2X#U?MLcV{)WXSjWgqYe(vrs1ACLcGsZ$Ao~OWPjnB$ZS@~#VafYN+w^N>akmI_n@%1d0vRRD%S{M z#tdg+OoZKC=pfh@Y`4IA8BR4MgqD}sC%;0_o=4+Fhel82ZiZO|-0U2CD#Iw$;)EPmQCl_L*FdYwuR_>ppFgXE$HL-ixi#$$I(%ouLDrZSo@4PHd+l9nCS5*c? zYYyw558I6&GeuuDv@j&Bpi&q?RH7wYvXtQK-y=jmn!4=z6XCL}m@ zjRm$jR?)PS-(xThW?hdBwu>X|YE0~%LrsrI2=+e#vRn%WSyvOvIPbiHQ080^xb zq5~5!51e4CibTbWP04$DW1=X7Nj9-Fo6PT2*x#(lmO?WaVp{HAeBR(jS-QrYGPU+y z+$fvk2l44f*}l(&QMNCnQ8qy|$`Z2+HG9PJV)cVP$#Tc3!%9s!WW&)J)mus$m4T_ zA)vhxKF+q8Xi40HxWMPVCg6^e{=VTJ ztqcKdiP3zbP(yxr>tEwB7q*CgTCAlfQkq!TQlxsGpG*yL&YLb5c1Xiiy=mh(DjaM5 zOszR>C&0MS$@K%oV|F~VHrlOyge$CSs(a=T5O2RV6LM1E3AQ<=T2_3|y@A+3?cZW? z{exa$*5}uRU>S26H_?TA*=O9LugIr48DZSJ*i*efK|@D;$-^#Oh;*Hu4xBVY$zlK2 z<>ppXfZ{1I>pH&!W5%>YW+911r7|sS86mzhRxgwaE$r_{gduc78m5v1-PnsKf_WLn zKCQ9X8If3oHBB~It7v^8c0Oli7zN5UMT~uMT!_-KAsX0t&@aTE`rW;WVDsjeyjWJq zn%kvNBOEdre~>&U#r^E|bIOs#V@zZLEusfghwGp2+OH3MI^H8K7QBsz5!j#XC4}A5 zJSXVm!Duvw31Xie?ej7?ZH}HBj#^Fj&(@3$60)2)8rsq$w+Pr`Wi0Z+$g550c@UgiX%@RW$tyW{6+$`3-;|feG>_W2et_GzfGaiAZ~A?qf+C2gvM8aojcUGhK{fw(BOOGYpQIaQJi_tn`@&sQP*e ztV<7{K;r&U7yFw`6Zehi^~}PYH#2M5%=k(5>&dv>HUJw2><8=Rw!V-O+mJfw33``i z%1wn}Wx?(buc;}QZYsTV*4T1bspq5>x)!%;;Pf^c7Z&32IS%~ghm*EJ0X)#$TC3VD z#zgzO?TiFV-!ja2^R`jh?VL%0o5qq7>-qI0TIO>R&gb($tG-WR-_p&9&;{d{4EVVv z7zwEtfp7{JEeKkTeF-7n^96kX>LNC2>+5mhSPxFGGMJyju#YwplWhUiKSnf<>XtnA zGVjW235o>6r8L)hB;B`H^IFb;Zs z)!Ibl|wV`yY3G$ z?uVLV{wX=Y9-Lni!*5{hJ~!Hr$~w8{++4J0|CSb1dH!g`R?a@RP|x3HDvYEUsJi8S z=bp2_r;~i`=HaAh2W)HmY%)m?ERs|r zPyMMr%fk1nDbuXlC{9G%|mvTU+`uCP#_p#HyWfeRrCn=#Pa!0K| zt(G47&iw90`gnnrW?F=_Y_any3=#Z6c#bVrrTy+T4JqmILVduRGFFIlc27q8F7{Bn zV3b(*<|s^+*X}|q&N2!mq(E8V6W7Ht$xkn?m*T66+ua(&)La0Iv!{c1`+L*-@%;wQ z7wEX}V%813Nz_GSE6=U`3TaBvY(XFHdzj>~LUT`Fv=17S{RD*)>@O9SdslOYpZWIs zPXDak$>M>Z^UNw_j^*w?e87iW9Cq_)!)~(*$VGMZ9L&W_DF?mr_{gLu3=z8newzdn zX+`3qov?&tM2QrlZ`z8lp>RW-g#z!da=~V|f7|k$COQMUTxk2F*1ZB3r(UmDkW?$< z@(aG#zs=7$?&~$ms1z9LA-j+#UP{rvGB$sbFFkP4o{@YM73b#*)73*GBlu00B34PU zF2b!cRN}VNTd6h)OJ{UxgJVpDui)Aafp!;pjiPDVym+G-Qxwh2qgzL#Yc{Zq1S{kr zScW6pAC1`vpUV!k*gA}97gSaJ3{1loLMkz5kl*sA8#Z%tw+I5nl9?WMKD!7#VjI00 zT}v<)>9&od)^WVucJis+b|dZBNVs+}5|{}tf+pF+_8z>nC_0o*YS7vFm){iP!69E* z#fP+!Ebg|WE!zx;_J<2?ApAIiebhSG%|IT`7eXuM1z$3QZ5SD@*!~9mohj2OT=A&| zI(C$v|ELZI?|FO@Fd0uP`=V%mglKl6_P;6OJfUDJm> zF?bv&&&^87K7EDXHNy8pQ4TY8pHt)49DE-Tm%}-^LuPRV)mPa4nPFAkU$`wWcc`p` z@fRwneUOx2=ByvIBB>wr@XhJVVUve4)Ao^n5_6VGo{t&mfKQspg;Owo!58bDyL(U~ zY|om7!GhX;v~XW6_W$w3lXvdfyKVcXF{}rw{_^w%$UY(qQ=6?Faup9{%p%6PZ8uh6 zUf3-a;}vMy$Q$?cabwRE*u9+}r>o(;D;?2QBbtY`ub2~3Y-m-AxiR^Hv70pw4M!zI5CKpkY zi~RNk@A;8F{te7t8*Ka3@VDY`40pDz0)J7x`oS9^9GjN~?BWM183Edu{_^C0M+1n* zhGkn@fsS`FdKs4v^K;kO(TQX7)Pa0j+_zO6sFWwM5Iu<=1O314T!bH6d*G%wR5-h^C=olQQBuR&hbsDaGOSw;WlkZ(O8O7ac(x%N2lX!z|8yH# zHF_&_mkfs;iTJ9xecPfR4L^6#_hOOJAC?1RLufzkUg}(bv`;Rg1IInPSLBLomqCjA zzEnFkAwv&3!>!#2Bq8pC@PK!2Tf&wb@%DDxmUxAG@Om+s%SGZHXiG)=6g>Je7G3;J z1()h`k9L*`XU(|2g%KRRrh}4ULwkRde(D32RNA99O^)%Q12k1@y!Z?+cg6V{H8hFU^RtJyqQW!u88D^Jijnx&IBgEX%wA literal 0 HcmV?d00001 diff --git a/src/host_common.c b/src/host_common.c new file mode 100644 index 0000000..a79ee9c --- /dev/null +++ b/src/host_common.c @@ -0,0 +1,650 @@ +/* + GSport - an Apple //gs Emulator + Copyright (C) 2010 - 2019 by GSport contributors + Copyright (C) 2016 - 2018 Dagen Brock + + Based on the KEGS emulator written by and Copyright (C) 2003 Kent Dickey + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 2 of the License, or (at your + option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#define _BSD_SOURCE + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "defc.h" +#include "gsos.h" +#include "fst.h" + +#ifdef _WIN32 +#include +#endif + +#include "host_common.h" + + +char *host_root = NULL; + +char *g_cfg_host_path = ""; // must not be null. +int g_cfg_host_read_only = 0; +int g_cfg_host_crlf = 1; +int g_cfg_host_merlin = 0; + + + + + + +/* + * simple malloc pool to simplify code. Should never need > 4 allocations. + * + */ +static void *gc[16]; +static void **gc_ptr = &gc[0]; + +void *host_gc_malloc(size_t size) { + if (gc_ptr == &gc[16]) { + errno = ENOMEM; + return NULL; + } + + void *ptr = malloc(size); + if (ptr) { + *gc_ptr++ = ptr; + } + return ptr; +} + + +void host_gc_free(void) { + + while (gc_ptr > gc) free(*--gc_ptr); + +} + +char *host_gc_strdup(const char *src) { + if (!src) return ""; + if (!*src) return ""; + int len = strlen(src) + 1; + char *cp = host_gc_malloc(len); + memcpy(cp, src, len); + return cp; +} + +char *host_gc_append_path(const char *a, const char *b) { + + /* strip all leading /s from b) */ + while (*b == '/') ++b; + + int aa = strlen(a); + int bb = strlen(b); + + char *cp = host_gc_malloc(aa + bb + 2); + if (!cp) return NULL; + memcpy(cp, a, aa); + int len = aa; + + /* strip all trailing /s from b */ + while (len > 2 && cp[len-1] == '/') --len; + cp[len++] = '/'; + memcpy(cp + len, b, bb); + len += bb; + cp[len] = 0; + return cp; +} + + +char *host_gc_append_string(const char *a, const char *b) { + int aa = strlen(a); + int bb = strlen(b); + + char *cp = host_gc_malloc(aa + bb + 2); + if (!cp) return NULL; + memcpy(cp, a, aa); + int len = aa; + memcpy(cp + len, b, bb); + len += bb; + cp[len] = 0; + return cp; +} + + + +/* + * text conversion. + */ + +void host_cr_to_lf(byte *buffer, size_t size) { + size_t i; + for (i = 0; i < size; ++i) { + if (buffer[i] == '\r') buffer[i] = '\n'; + } +} + +void host_lf_to_cr(byte *buffer, size_t size) { + size_t i; + for (i = 0; i < size; ++i) { + if (buffer[i] == '\n') buffer[i] = '\r'; + } +} + +void host_merlin_to_text(byte *buffer, size_t size) { + size_t i; + for (i = 0; i < size; ++i) { + byte b = buffer[i]; + if (b == 0xa0) b = '\t'; + b &= 0x7f; + if (b == '\r') b = '\n'; + buffer[i] = b; + } +} + +void host_text_to_merlin(byte *buffer, size_t size) { + size_t i; + for (i = 0; i < size; ++i) { + byte b = buffer[i]; + if (b == '\t') b = 0xa0; + if (b == '\n') b = '\r'; + if (b != ' ') b |= 0x80; + buffer[i] = b; + } +} + + +/* + * error remapping. + * NOTE - GS/OS errors are a superset of P8 errors + */ + +static word32 enoent(const char *path) { + /* + some op on path return ENOENT. check if it's + fileNotFound or pathNotFound + */ + char *p = (char *)path; + for(;;) { + struct stat st; + p = dirname(p); + if (p == NULL) break; + if (p[0] == '.' && p[1] == 0) break; + if (p[0] == '/' && p[1] == 0) break; + if (stat(p, &st) < 0) return pathNotFound; + } + return fileNotFound; +} + +word32 host_map_errno(int xerrno) { + switch(xerrno) { + case 0: return 0; + case EBADF: + return invalidAccess; +#ifdef EDQUOT + case EDQUOT: +#endif + case EFBIG: + return volumeFull; + case ENOENT: + return fileNotFound; + case ENOTDIR: + return pathNotFound; + case ENOMEM: + return outOfMem; + case EEXIST: + return dupPathname; + case ENOTEMPTY: + return invalidAccess; + + default: + return drvrIOError; + } +} + +word32 host_map_errno_path(int xerrno, const char *path) { + if (xerrno == ENOENT) return enoent(path); + return host_map_errno(xerrno); +} + +const char *host_error_name(word16 error) { + static char *errors[] = { + "", + "badSystemCall", + "", + "", + "invalidPcount", + "", + "", + "gsosActive", + "", + "", + "", + "", + "", + "", + "", + "", + // 0x10 + "devNotFound", + "invalidDevNum", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + // 0x20 + "drvrBadReq", + "drvrBadCode", + "drvrBadParm", + "drvrNotOpen", + "drvrPriorOpen", + "irqTableFull", + "drvrNoResrc", + "drvrIOError", + "drvrNoDevice", + "drvrBusy", + "", + "drvrWrtProt", + "drvrBadCount", + "drvrBadBlock", + "drvrDiskSwitch", + "drvrOffLine", + // 0x30 + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + // 0x40 + "badPathSyntax", + "", + "tooManyFilesOpen", + "invalidRefNum", + "pathNotFound", + "volNotFound", + "fileNotFound", + "dupPathname", + "volumeFull", + "volDirFull", + "badFileFormat", + "badStoreType", + "eofEncountered", + "outOfRange", + "invalidAccess", + "buffTooSmall", + // 0x50 + "fileBusy", + "dirError", + "unknownVol", + "paramRangeErr", + "outOfMem", + "", + "badBufferAddress", /* P8 MLI only */ + "dupVolume", + "notBlockDev", + "invalidLevel", + "damagedBitMap", + "badPathNames", + "notSystemFile", + "osUnsupported", + "", + "stackOverflow", + // 0x60 + "dataUnavail", + "endOfDir", + "invalidClass", + "resForkNotFound", + "invalidFSTID", + "invalidFSTop", + "fstCaution", + "devNameErr", + "defListFull", + "supListFull", + "fstError", + "", + "", + "", + "", + "", + //0x70 + "resExistsErr", + "resAddErr", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + //0x80 + "", + "", + "", + "", + "", + "", + "", + "", + "networkError" + }; + + if (error < sizeof(errors) / sizeof(errors[0])) + return errors[error]; + return ""; +} + + + +/* + * File info. + */ + + +static int hex(byte c) { + if (c >= '0' && c <= '9') return c - '0'; + if (c >= 'a' && c <= 'f') return c + 10 - 'a'; + if (c >= 'A' && c <= 'F') return c + 10 - 'A'; + return 0; +} + + +int host_finder_info_to_filetype(const byte *buffer, word16 *file_type, word32 *aux_type) { + + if (!memcmp("pdos", buffer + 4, 4)) + { + if (buffer[0] == 'p') { + *file_type = buffer[1]; + *aux_type = (buffer[2] << 8) | buffer[3]; + return 0; + } + if (!memcmp("PSYS", buffer, 4)) { + *file_type = 0xff; + *aux_type = 0x0000; + return 0; + } + if (!memcmp("PS16", buffer, 4)) { + *file_type = 0xb3; + *aux_type = 0x0000; + return 0; + } + + // old mpw method for encoding. + if (!isxdigit(buffer[0]) && isxdigit(buffer[1]) && buffer[2] == ' ' && buffer[3] == ' ') + { + *file_type = (hex(buffer[0]) << 8) | hex(buffer[1]); + *aux_type = 0; + return 0; + } + } + if (!memcmp("TEXT", buffer, 4)) { + *file_type = 0x04; + *aux_type = 0x0000; + return 0; + } + if (!memcmp("BINA", buffer, 4)) { + *file_type = 0x00; + *aux_type = 0x0000; + return 0; + } + if (!memcmp("dImgdCpy", buffer, 8)) { + *file_type = 0xe0; + *aux_type = 0x0005; + return 0; + } + + if (!memcmp("MIDI", buffer, 4)) { + *file_type = 0xd7; + *aux_type = 0x0000; + return 0; + } + + if (!memcmp("AIFF", buffer, 4)) { + *file_type = 0xd8; + *aux_type = 0x0000; + return 0; + } + + if (!memcmp("AIFC", buffer, 4)) { + *file_type = 0xd8; + *aux_type = 0x0001; + return 0; + } + + return -1; +} + +int host_file_type_to_finder_info(byte *buffer, word16 file_type, word32 aux_type) { + if (file_type > 0xff || aux_type > 0xffff) return -1; + + if (!file_type && aux_type == 0x0000) { + memcpy(buffer, "BINApdos", 8); + return 0; + } + + if (file_type == 0x04 && aux_type == 0x0000) { + memcpy(buffer, "TEXTpdos", 8); + return 0; + } + + if (file_type == 0xff && aux_type == 0x0000) { + memcpy(buffer, "PSYSpdos", 8); + return 0; + } + + if (file_type == 0xb3 && aux_type == 0x0000) { + memcpy(buffer, "PS16pdos", 8); + return 0; + } + + if (file_type == 0xd7 && aux_type == 0x0000) { + memcpy(buffer, "MIDIpdos", 8); + return 0; + } + if (file_type == 0xd8 && aux_type == 0x0000) { + memcpy(buffer, "AIFFpdos", 8); + return 0; + } + if (file_type == 0xd8 && aux_type == 0x0001) { + memcpy(buffer, "AIFCpdos", 8); + return 0; + } + if (file_type == 0xe0 && aux_type == 0x0005) { + memcpy(buffer, "dImgdCpy", 8); + return 0; + } + + + memcpy(buffer, "p pdos", 8); + buffer[1] = (file_type) & 0xff; + buffer[2] = (aux_type >> 8) & 0xff; + buffer[3] = (aux_type) & 0xff; + return 0; +} + + + +#undef _ +#define _(a, b, c) { a, sizeof(a) - 1, b, c } +struct ftype_entry { + char *ext; + unsigned length; + unsigned file_type; + unsigned aux_type; +}; + +static struct ftype_entry suffixes[] = { + _("c", 0xb0, 0x0008), + _("cc", 0xb0, 0x0008), + _("h", 0xb0, 0x0008), + _("rez", 0xb0, 0x0015), + _("asm", 0xb0, 0x0003), + _("mac", 0xb0, 0x0003), + _("pas", 0xb0, 0x0005), + _("txt", 0x04, 0x0000), + _("text", 0x04, 0x0000), + _("s", 0x04, 0x0000), + { 0, 0, 0, 0} +}; + +static struct ftype_entry prefixes[] = { + _("m16.", 0xb0, 0x0003), + _("e16.", 0xb0, 0x0003), + { 0, 0, 0, 0} +}; + +#undef _ + +void host_synthesize_file_xinfo(const char *path, struct file_info *fi) { + + /* guess the file type / auxtype based on extension */ + int n; + const char *dot = NULL; + const char *slash = NULL; + + for(n = 0;; ++n) { + char c = path[n]; + if (c == 0) break; + else if (c == '/') { slash = path + n + 1; dot = NULL; } + else if (c == '.') dot = path + n + 1; + } + + if (dot && *dot) { + for (n = 0; n < sizeof(suffixes) / sizeof(suffixes[0]); ++n) { + if (!suffixes[n].ext) break; + if (!strcasecmp(dot, suffixes[n].ext)) { + fi->file_type = suffixes[n].file_type; + fi->aux_type = suffixes[n].aux_type; + return; + } + } + } + return; +} + + +void host_hexdump(word32 address, int size) { + const char *HexMap = "0123456789abcdef"; + + char buffer1[16 * 3 + 1 + 1]; + char buffer2[16 + 1]; + unsigned i, j; + + printf("\n"); + while (size > 0) { + memset(buffer1, ' ', sizeof(buffer1)); + memset(buffer2, ' ', sizeof(buffer2)); + + int linelen = size; + if (linelen > 16) linelen = 16; + + for (i = 0, j = 0; i < linelen; i++) { + unsigned x = get_memory_c(address + i, 0); + buffer1[j++] = HexMap[x >> 4]; + buffer1[j++] = HexMap[x & 0x0f]; + j++; + if (i == 7) j++; + x &= 0x7f; + // isascii not part of std:: and may be a macro. + buffer2[i] = isascii(x) && isprint(x) ? x : '.'; + } + + buffer1[sizeof(buffer1) - 1] = 0; + buffer2[sizeof(buffer2) - 1] = 0; + + printf("%06x:\t%s\t%s\n", + address, buffer1, buffer2); + address += 16; + size -= 16; + } + printf("\n"); +} + + +void host_hexdump_native(void *data, unsigned address, int size) { + const char *HexMap = "0123456789abcdef"; + + char buffer1[16 * 3 + 1 + 1]; + char buffer2[16 + 1]; + unsigned i, j; + + printf("\n"); + while (size > 0) { + memset(buffer1, ' ', sizeof(buffer1)); + memset(buffer2, ' ', sizeof(buffer2)); + + int linelen = size; + if (linelen > 16) linelen = 16; + + for (i = 0, j = 0; i < linelen; i++) { + unsigned x = ((byte *)data)[address + i]; + buffer1[j++] = HexMap[x >> 4]; + buffer1[j++] = HexMap[x & 0x0f]; + j++; + if (i == 7) j++; + x &= 0x7f; + // isascii not part of std:: and may be a macro. + buffer2[i] = isascii(x) && isprint(x) ? x : '.'; + } + + buffer1[sizeof(buffer1) - 1] = 0; + buffer2[sizeof(buffer2) - 1] = 0; + + printf("%06x:\t%s\t%s\n", + address, buffer1, buffer2); + address += 16; + size -= 16; + } + printf("\n"); +} + + + +void host_free_directory(char **data, size_t count) { + for (int i = 0; i < count; ++i) free(data[i]); + free(data); +} diff --git a/src/host_common.h b/src/host_common.h new file mode 100644 index 0000000..7100ab8 --- /dev/null +++ b/src/host_common.h @@ -0,0 +1,186 @@ +/* + GSport - an Apple //gs Emulator + Copyright (C) 2010 - 2019 by GSport contributors + Copyright (C) 2016 - 2018 Dagen Brock + + Based on the KEGS emulator written by and Copyright (C) 2003 Kent Dickey + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 2 of the License, or (at your + option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#ifdef _WIN32 + +#include + +#pragma pack(push, 2) +struct AFP_Info { + uint32_t magic; + uint32_t version; + uint32_t file_id; + uint32_t backup_date; + uint8_t finder_info[32]; + uint16_t prodos_file_type; + uint32_t prodos_aux_type; + uint8_t reserved[6]; +}; +#pragma pack(pop) + +void afp_init(struct AFP_Info *info, word16 file_type, word32 aux_type); +BOOL afp_verify(struct AFP_Info *info); +int afp_to_filetype(struct AFP_Info *info, word16 *file_type, word32 *aux_type); +enum { prefer_prodos, prefer_hfs }; +void afp_synchronize(struct AFP_Info *info, int preference); + +#endif + +#ifdef _WIN32 +typedef FILETIME host_time_t; +typedef struct AFP_Info host_finder_info_t; +#else +typedef time_t host_time_t; +typedef unsigned char host_finder_info_t[32]; +#endif + + + +enum { + file_non, + file_regular, + file_resource, + file_directory, +}; + +enum { + translate_none, + translate_crlf, + translate_merlin, +}; + + + +struct file_info { + + host_time_t create_date; + host_time_t modified_date; + word16 access; + word16 storage_type; + word16 file_type; + word32 aux_type; + word32 eof; + word32 blocks; + word32 resource_eof; + word32 resource_blocks; + int has_fi; + #ifdef _WIN32 + struct AFP_Info afp; + #else + byte finder_info[32]; + #endif +}; + + +extern Engine_reg engine; + +#define SEC() engine.psr |= 0x01 +#define CLC() engine.psr &= ~0x01 +#define SEV() engine.psr |= 0x40 +#define CLV() engine.psr &= ~0x40 +#define SEZ() engine.psr |= 0x02 +#define CLZ() engine.psr &= ~0x02 +#define SEI() engine.psr |= 0x04 +#define CLI() engine.psr &= ~0x04 + +enum { + C = 0x01, + Z = 0x02, + I = 0x04, + D = 0x08, + X = 0x10, + M = 0x20, + V = 0x40, + N = 0x80 +}; + +extern char *g_cfg_host_path; +extern int g_cfg_host_read_only; +extern int g_cfg_host_crlf; +extern int g_cfg_host_merlin; +extern char *host_root; + +unsigned host_startup(void); +void host_shutdown(void); + +#ifdef _WIN32 +int host_is_root(const BY_HANDLE_FILE_INFORMATION *info); +#else +int host_is_root(struct stat *); +#endif + +/* garbage collected string routines */ + +void *host_gc_malloc(size_t size); +void host_gc_free(void); +char *host_gc_strdup(const char *src); +char *host_gc_append_path(const char *a, const char *b); +char *host_gc_append_string(const char *a, const char *b); + +/* text conversion */ +void host_cr_to_lf(byte *buffer, size_t size); +void host_lf_to_cr(byte *buffer, size_t size); +void host_merlin_to_text(byte *buffer, size_t size); +void host_text_to_merlin(byte *buffer, size_t size); + +/* errno -> IIgs/mli error */ +word32 host_map_errno(int xerrno); +word32 host_map_errno_path(int xerrno, const char *path); +const char *host_error_name(word16 error); + +#ifdef _WIN32 +word32 host_map_win32_error(DWORD); +word32 host_map_win32_error_path(DWORD, const char *path); +#endif + +/* file info */ +int host_finder_info_to_filetype(const byte *buffer, word16 *file_type, word32 *aux_type); +int host_file_type_to_finder_info(byte *buffer, word16 file_type, word32 aux_type); + +void host_get_file_xinfo(const char *path, struct file_info *fi); +word32 host_get_file_info(const char *path, struct file_info *fi); +word32 host_set_file_info(const char *path, struct file_info *fi); + +/* guesses filetype/auxtype from extension */ +void host_synthesize_file_xinfo(const char *path, struct file_info *fi); + +void host_set_date_time_rec(word32 ptr, host_time_t time); +void host_set_date_time(word32 ptr, host_time_t time); + +host_time_t host_get_date_time(word32 ptr); +host_time_t host_get_date_time_rec(word32 ptr); + +/* convert to prodos date/time */ +word32 host_convert_date_time(host_time_t time); + + +/* scan a directory, return array of char * */ +unsigned host_scan_directory(const char *path, char ***out, size_t *entries, unsigned p8); +void host_free_directory(char **data, size_t count); + + +/* 0x01, 0x0d, 0x0f, 0 on error */ +unsigned host_storage_type(const char *path, word16 *error_ptr); + +void host_hexdump(word32 address, int size); +void host_hexdump_native(void *data, unsigned address, int size); + diff --git a/src/host_fst.c b/src/host_fst.c new file mode 100644 index 0000000..35c7095 --- /dev/null +++ b/src/host_fst.c @@ -0,0 +1,1879 @@ +/* + GSport - an Apple //gs Emulator + Copyright (C) 2010 - 2019 by GSport contributors + Copyright (C) 2016 - 2018 Dagen Brock + + Based on the KEGS emulator written by and Copyright (C) 2003 Kent Dickey + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 2 of the License, or (at your + option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#define _BSD_SOURCE + +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#if defined(__APPLE__) +#include +#include +#include +#endif + +#ifndef XATTR_FINDERINFO_NAME +#define XATTR_FINDERINFO_NAME "com.apple.FinderInfo" +#endif + +#ifndef XATTR_RESOURCEFORK_NAME +#define XATTR_RESOURCEFORK_NAME "com.apple.ResourceFork" +#endif + + +#include "defc.h" +#include "gsos.h" +#include "fst.h" + +#include "host_common.h" + + + +extern Engine_reg engine; + + +/* direct page offsets */ + +#define dp_call_number 0x30 +#define dp_param_blk_ptr 0x32 +#define dp_dev1_num 0x36 +#define dp_dev2_num 0x38 +#define dp_path1_ptr 0x3a +#define dp_path2_ptr 0x3e +#define dp_path_flag 0x42 + +#define global_buffer 0x009a00 + + + +struct directory { + int displacement; + int num_entries; + char *entries[1]; +}; + +struct fd_entry { + struct fd_entry *next; + char *path; + int cookie; + int type; + int access; + int fd; + int translate; + struct directory *dir; +}; + +static void free_directory(struct directory *dd); +static struct directory *read_directory(const char *path, word16 *error); + +#define COOKIE_BASE 0x8000 + +static word32 cookies[32] = {}; + +static int alloc_cookie() { + for (int i = 0; i < 32; ++i) { + word32 x = cookies[i]; + + for (int j = 0; j < 32; ++j, x >>= 1) { + if (x & 0x01) continue; + + cookies[i] |= (1 << j); + return COOKIE_BASE + (i * 32 + j); + } + } + return -1; +} + +static int free_cookie(int cookie) { + if (cookie < COOKIE_BASE) return -1; + cookie -= COOKIE_BASE; + if (cookie >= 32 *32) return -1; + + int chunk = cookie / 32; + int offset = 1 << (cookie % 32); + + word32 x = cookies[chunk]; + + if ((x & offset) == 0) return -1; + x &= ~offset; + cookies[chunk] = x; + return 0; +} + +static struct fd_entry *fd_head = NULL; + + + + +static struct fd_entry *find_fd(int cookie) { + struct fd_entry *head = fd_head; + + while(head) { + if (head->cookie == cookie) return head; + head = head->next; + } + return NULL; +} + + +static void free_fd(struct fd_entry *e) { + if (!e) return; + if (e->cookie) free_cookie(e->cookie); + if (e->fd >= 0) close(e->fd); + if (e->dir) free_directory(e->dir); + free(e->path); + free(e); +} + +static struct fd_entry *alloc_fd() { + struct fd_entry *e = calloc(sizeof(struct fd_entry), 1); + e->fd = -1; + return e; +} + + +static word32 remove_fd(int cookie) { + word32 rv = invalidRefNum; + + struct fd_entry *prev = NULL; + struct fd_entry *head = fd_head; + while (head) { + if (head->cookie == cookie) { + if (prev) prev->next = head->next; + else fd_head = head->next; + + free_fd(head); + rv = 0; + break; + } + prev = head; + head = head->next; + } + return rv; +} + + +static ssize_t safe_read(struct fd_entry *e, byte *buffer, size_t count) { + int fd = e->fd; + int tr = e->translate; + + for (;;) { + ssize_t ok = read(fd, buffer, count); + if (ok >= 0) { + size_t i; + if (tr == translate_crlf) { + for (i = 0; i < ok; ++i) { + if (buffer[i] == '\n') buffer[i] = '\r'; + } + } + if (tr == translate_merlin) { + for (i = 0; i < ok; ++i) { + unsigned char c = buffer[i]; + if (c == '\t') c = 0xa0; + if (c == '\n') c = '\r'; + if (c != ' ') c |= 0x80; + buffer[i] = c; + } + } + return ok; + } + if (ok < 0 && errno == EINTR) continue; + return ok; + } +} + +static ssize_t safe_write(struct fd_entry *e, byte *buffer, size_t count) { + int fd = e->fd; + int tr = e->translate; + + if (tr == translate_crlf) { + size_t i; + for (i = 0; i < count; ++i) { + if (buffer[i] == '\r') buffer[i] = '\n'; + } + } + if (tr == translate_merlin) { + size_t i; + for (i = 0; i < count; ++i) { + unsigned char c = buffer[i]; + if (c == 0xa0) c = '\t'; + c &= 0x7f; + if (c == '\r') c = '\n'; + buffer[i] = c; + } + } + + for (;;) { + ssize_t ok = write(fd, buffer, count); + if (ok >= 0) return ok; + if (ok < 0 && errno == EINTR) continue; + return ok; + } +} + + +/* + * if this is an absolute path, verify and skip past :Host: + * + */ +static const char *check_path(const char *in, word32 *error) { + + word32 tmp; + if (!error) error = &tmp; + + *error = 0; + if (!in) return ""; + + /* check for .. */ + const char *cp = in; + do { + while (*cp == '/') ++cp; + if (cp[0] == '.' && cp[1] == '.' && (cp[2] == '/' || cp[2] == 0)) + { + *error = badPathSyntax; + return NULL; + } + cp = strchr(cp, '/'); + } while(cp); + + + if (in[0] != '/') return in; + + if (strncasecmp(in, "/Host", 5) == 0 && (in[5] == '/' || in[5] == 0)) { + in += 5; + while (*in == '/') ++in; + return in; + } + *error = volNotFound; + return NULL; +} + + +static char * get_gsstr(word32 ptr) { + if (!ptr) return NULL; + int length = get_memory16_c(ptr, 0); + ptr += 2; + char *str = host_gc_malloc(length + 1); + for (int i = 0; i < length; ++i) { + char c = get_memory_c(ptr+i, 0); + if (c == ':') c = '/'; + str[i] = c; + } + str[length] = 0; + return str; +} + +static char * get_pstr(word32 ptr) { + if (!ptr) return NULL; + int length = get_memory_c(ptr, 0); + ptr += 1; + char *str = host_gc_malloc(length + 1); + for (int i = 0; i < length; ++i) { + char c = get_memory_c(ptr+i, 0); + if (c == ':') c = '/'; + str[i] = c; + } + str[length] = 0; + return str; +} + +static word32 set_gsstr(word32 ptr, const char *str) { + + if (!ptr) return paramRangeErr; + + int l = str ? strlen(str) : 0; + + + word32 cap = get_memory16_c(ptr, 0); + ptr += 2; + + if (cap < 4) return paramRangeErr; + + set_memory16_c(ptr, l, 0); + ptr += 2; + + if (cap < l + 4) return buffTooSmall; + + + for (int i = 0; i < l; ++i) { + char c = *str++; + if (c == '/') c = ':'; + set_memory_c(ptr++, c, 0); + } + return 0; +} + +static word32 set_gsstr_truncate(word32 ptr, const char *str) { + + if (!ptr) return paramRangeErr; + + int l = str ? strlen(str) : 0; + + + word32 cap = get_memory16_c(ptr, 0); + ptr += 2; + + if (cap < 4) return paramRangeErr; + + set_memory16_c(ptr, l, 0); + ptr += 2; + + // get dir entry copies data even + // if buffTooSmall... + int rv = 0; + if (cap < l + 4) { + l = cap - 4; + rv = buffTooSmall; + } + + for (int i = 0; i < l; ++i) { + char c = *str++; + if (c == '/') c = ':'; + set_memory_c(ptr++, c, 0); + } + return rv; +} + +static word32 set_pstr(word32 ptr, const char *str) { + + if (!ptr) return paramRangeErr; + + int l = str ? strlen(str) : 0; + + if (l > 255) return buffTooSmall; + // / is the pascal separator. + set_memory_c(ptr++, l, 0); + for (int i = 0; i < l; ++i) { + set_memory_c(ptr++, *str++, 0); + } + return 0; +} + + +static word32 set_option_list(word32 ptr, word16 fstID, const byte *data, int size) { + if (!ptr) return 0; + + // totalSize + word32 cap = get_memory16_c(ptr, 0); + ptr += 2; + + if (cap < 4) return paramRangeErr; + + // reqSize + set_memory16_c(ptr, size + 2, 0); + ptr += 2; + + if (cap < size + 6) return buffTooSmall; + + + // fileSysID. + set_memory16_c(ptr, fstID, 0); + ptr += 2; + + for (int i = 0; i < size; ++i) + set_memory_c(ptr++, *data++, 0); + + return 0; +} + + + +static char *get_path1(void) { + word32 direct = engine.direct; + word16 flags = get_memory16_c(direct + dp_path_flag, 0); + if (flags & (1 << 14)) + return get_gsstr( get_memory24_c(direct + dp_path1_ptr, 0)); + return NULL; +} + +static char *get_path2(void) { + word32 direct = engine.direct; + word16 flags = get_memory16_c(direct + dp_path_flag, 0); + if (flags & (1 << 6)) + return get_gsstr( get_memory24_c(direct + dp_path2_ptr, 0)); + return NULL; +} + + + +static word32 fst_shutdown(void) { + + // close any remaining files. + struct fd_entry *head = fd_head; + while (head) { + struct fd_entry *next = head->next; + + free_fd(head); + head = next; + } + host_shutdown(); + return 0; +} + +static word32 fst_startup(void) { + // if restart, close any previous files. + + fst_shutdown(); + memset(&cookies, 0, sizeof(cookies)); + + return host_startup(); + +} + + +static word32 fst_create(int class, const char *path) { + + word32 pb = get_memory24_c(engine.direct + dp_param_blk_ptr, 0); + + struct file_info fi; + memset(&fi, 0, sizeof(fi)); + + word16 pcount = 0; + if (class) { + pcount = get_memory16_c(pb, 0); + if (pcount >= 2) fi.access = get_memory16_c(pb + CreateRecGS_access, 0); + if (pcount >= 3) fi.file_type = get_memory16_c(pb + CreateRecGS_fileType, 0); + if (pcount >= 4) fi.aux_type = get_memory32_c(pb + CreateRecGS_auxType, 0); + if (pcount >= 5) fi.storage_type = get_memory16_c(pb + CreateRecGS_storageType, 0); + if (pcount >= 6) fi.eof = get_memory32_c(pb + CreateRecGS_eof, 0); + if (pcount >= 7) fi.resource_eof = get_memory32_c(pb + CreateRecGS_resourceEOF, 0); + + + if (pcount >= 4) { + host_file_type_to_finder_info(fi.finder_info, fi.file_type, fi.aux_type); + fi.has_fi = 1; + } + + + } else { + + fi.access = get_memory16_c(pb + CreateRec_fAccess, 0); + fi.file_type = get_memory16_c(pb + CreateRec_fileType, 0); + fi.aux_type = get_memory32_c(pb + CreateRec_auxType, 0); + fi.storage_type = get_memory16_c(pb + CreateRec_storageType, 0); + fi.create_date = host_get_date_time(pb + CreateRec_createDate); + + host_file_type_to_finder_info(fi.finder_info, fi.file_type, fi.aux_type); + fi.has_fi = 1; + } + int ok; + + if (fi.storage_type == 0 && fi.file_type == 0x0f) + fi.storage_type = 0x0d; + + if (fi.storage_type == 0x0d) { + ok = mkdir(path, 0777); + if (ok < 0) { + return host_map_errno_path(errno, path); + } + + if (class) { + if (pcount >= 5) set_memory16_c(pb + CreateRecGS_storageType, fi.storage_type, 0); + } else { + set_memory16_c(pb + CreateRec_storageType, fi.storage_type, 0); + } + + return 0; + } + if (fi.storage_type <= 3 || fi.storage_type == 0x05) { + // normal file. + // 0x05 is an extended/resource file but we don't do anything special. + ok = open(path, O_WRONLY | O_CREAT | O_EXCL, 0666); + if (ok < 0) return host_map_errno_path(errno, path); + // set ftype, auxtype... + host_set_file_info(path, &fi); + close(ok); + + fi.storage_type = 1; + + if (class) { + if (pcount >= 5) set_memory16_c(pb + CreateRecGS_storageType, fi.storage_type, 0); + } else { + set_memory16_c(pb + CreateRec_storageType, fi.storage_type, 0); + } + + return 0; + } + + + if (fi.storage_type == 0x8005) { + // convert an existing file to an extended file. + // this checks that the file exists and has a 0-sized resource. + word32 rv = host_get_file_info(path, &fi); + if (rv) return rv; + if (fi.storage_type == extendedFile) return resExistsErr; + if (fi.storage_type < seedling || fi.storage_type > tree) return resAddErr; + return 0; + } + + // other storage types? + return badStoreType; +} + + +static word32 fst_destroy(int class, const char *path) { + + struct stat st; + + if (!path) return badStoreType; + + if (stat(path, &st) < 0) { + return host_map_errno_path(errno, path); + } + + // can't delete volume root. + if (host_is_root(&st)) + return badStoreType; + + int ok = S_ISDIR(st.st_mode) ? rmdir(path) : unlink(path); + + + if (ok < 0) return host_map_errno_path(errno, path); + return 0; +} + +static word32 fst_set_file_info(int class, const char *path) { + + + word32 pb = get_memory24_c(engine.direct + dp_param_blk_ptr, 0); + + struct file_info fi; + memset(&fi, 0, sizeof(fi)); + + + // load up existing file types / finder info. + host_get_file_xinfo(path, &fi); + + word32 option_list = 0; + if (class) { + word16 pcount = get_memory16_c(pb, 0); + + if (pcount >= 2) fi.access = get_memory16_c(pb + FileInfoRecGS_access, 0); + if (pcount >= 3) fi.file_type = get_memory16_c(pb + FileInfoRecGS_fileType, 0); + if (pcount >= 4) fi.aux_type = get_memory32_c(pb + FileInfoRecGS_auxType, 0); + // reserved. + //if (pcount >= 5) fi.storage_type = get_memory16_c(pb + FileInfoRecGS_storageType, 0); + if (pcount >= 6) fi.create_date = host_get_date_time_rec(pb + FileInfoRecGS_createDateTime); + if (pcount >= 7) fi.modified_date = host_get_date_time_rec(pb + FileInfoRecGS_modDateTime); + if (pcount >= 8) option_list = get_memory24_c(pb + FileInfoRecGS_optionList, 0); + // remainder reserved + + if (pcount >= 4) { + host_file_type_to_finder_info(fi.finder_info, fi.file_type, fi.aux_type); + fi.has_fi = 1; + } + + } else { + fi.access = get_memory16_c(pb + FileRec_fAccess, 0); + fi.file_type = get_memory16_c(pb + FileRec_fileType, 0); + fi.aux_type = get_memory32_c(pb + FileRec_auxType, 0); + // reserved. + //fi.storage_type = get_memory32_c(pb + FileRec_storageType, 0); + fi.create_date = host_get_date_time(pb + FileRec_createDate); + fi.modified_date = host_get_date_time(pb + FileRec_modDate); + + host_file_type_to_finder_info(fi.finder_info, fi.file_type, fi.aux_type); + fi.has_fi = 1; + } + + if (option_list) { + // total size, req size, fst id, data... + int total_size = get_memory16_c(option_list + 0, 0); + int req_size = get_memory16_c(option_list + 2, 0); + int fst_id = get_memory16_c(option_list + 4, 0); + + int size = req_size - 6; + if ((fst_id == proDOSFSID || fst_id == hfsFSID || fst_id == appleShareFSID) && size >= 32) { + fi.has_fi = 1; + for (int i = 0; i <32; ++i) + fi.finder_info[i] = get_memory_c(option_list + 6 + i, 0); + } + } + + + return host_set_file_info(path, &fi); +} + +static word32 fst_get_file_info(int class, const char *path) { + + word32 pb = get_memory24_c(engine.direct + dp_param_blk_ptr, 0); + + struct file_info fi; + int rv = 0; + + rv = host_get_file_info(path, &fi); + if (rv) return rv; + + if (class) { + + word16 pcount = get_memory16_c(pb, 0); + + if (pcount >= 2) set_memory16_c(pb + FileInfoRecGS_access, fi.access, 0); + if (pcount >= 3) set_memory16_c(pb + FileInfoRecGS_fileType, fi.file_type, 0); + if (pcount >= 4) set_memory32_c(pb + FileInfoRecGS_auxType, fi.aux_type, 0); + if (pcount >= 5) set_memory16_c(pb + FileInfoRecGS_storageType, fi.storage_type, 0); + + if (pcount >= 6) host_set_date_time_rec(pb + FileInfoRecGS_createDateTime, fi.create_date); + if (pcount >= 7) host_set_date_time_rec(pb + FileInfoRecGS_modDateTime, fi.modified_date); + + if (pcount >= 8) { + word16 fst_id = hfsFSID; + //if (fi.storage_type == 0x0f) fst_id = mfsFSID; + word32 option_list = get_memory24_c(pb + FileInfoRecGS_optionList, 0); + rv = set_option_list(option_list, fst_id, fi.finder_info, fi.has_fi ? 32 : 0); + } + if (pcount >= 9) set_memory32_c(pb + FileInfoRecGS_eof, fi.eof, 0); + if (pcount >= 10) set_memory32_c(pb + FileInfoRecGS_blocksUsed, fi.blocks, 0); + if (pcount >= 11) set_memory32_c(pb + FileInfoRecGS_resourceEOF, fi.resource_eof, 0); + if (pcount >= 12) set_memory32_c(pb + FileInfoRecGS_resourceBlocks, fi.resource_blocks, 0); + + } else { + + set_memory16_c(pb + FileRec_fAccess, fi.access, 0); + set_memory16_c(pb + FileRec_fileType, fi.file_type, 0); + set_memory32_c(pb + FileRec_auxType, fi.aux_type, 0); + set_memory16_c(pb + FileRec_storageType, fi.storage_type, 0); + + host_set_date_time(pb + FileRec_createDate, fi.create_date); + host_set_date_time(pb + FileRec_modDate, fi.modified_date); + + set_memory32_c(pb + FileRec_blocksUsed, fi.blocks, 0); + } + + return rv; +} + +static word32 fst_judge_name(int class, char *path) { + + if (class == 0) return invalidClass; + + + word32 pb = get_memory24_c(engine.direct + dp_param_blk_ptr, 0); + word16 pcount = get_memory16_c(pb, 0); + word16 name_type = get_memory16_c(pb + JudgeNameRecGS_nameType, 0); + word32 name = pcount >= 5 ? get_memory24_c(pb + JudgeNameRecGS_name, 0) : 0; + + // 255 max length. + if (pcount >= 4) set_memory16_c(pb + JudgeNameRecGS_maxLen, 255, 0); + if (pcount >= 6) set_memory16_c(pb + JudgeNameRecGS_nameFlags, 0, 0); + + word16 nameFlags = 0; + word16 rv = 0; + + if (name) { + word16 cap = get_memory16_c(name, 0); + if (cap < 4) return buffTooSmall; + word16 length = get_memory16_c(name + 2, 0); + if (length == 0) { + nameFlags |= 1 << 13; + rv = set_gsstr(name, "A"); + } else { + // if volume name, only allow "Host" ? + if (length > 255) nameFlags |= 1 << 14; + for (int i = 0; i < length; ++i) { + char c = get_memory_c(name + 4 + i, 0); + if (c == 0 || c == ':' || c == '/' || c == '\\') { + nameFlags |= 1 << 15; + set_memory_c(name + 4 + i, '.', 0); + } + } + } + } + if (pcount >= 6) set_memory16_c(pb + JudgeNameRecGS_nameFlags, nameFlags, 0); + return rv; +} + +static word32 fst_volume(int class) { + + word32 pb = get_memory24_c(engine.direct + dp_param_blk_ptr, 0); + + word32 rv = 0; + if (class) { + word16 pcount = get_memory16_c(pb, 0); + if (pcount >= 2) rv = set_gsstr(get_memory24_c(pb + VolumeRecGS_volName, 0), ":Host"); + // finder bug -- if used blocks is 0, doesn't display header. + if (pcount >= 3) set_memory32_c(pb + VolumeRecGS_totalBlocks, 0x007fffff, 0); + if (pcount >= 4) set_memory32_c(pb + VolumeRecGS_freeBlocks, 0x007fffff-1, 0); + if (pcount >= 5) set_memory16_c(pb + VolumeRecGS_fileSysID, mfsFSID, 0); + if (pcount >= 6) set_memory16_c(pb + VolumeRecGS_blockSize, 512, 0); + // handled via gs/os + //if (pcount >= 7) set_memory16_c(pb + VolumeRecGS_characteristics, 0, 0); + //if (pcount >= 8) set_memory16_c(pb + VolumeRecGS_deviceID, 0, 0); + } else { + + // prodos 16 uses / sep. + rv = set_pstr(get_memory24_c(pb + VolumeRec_volName, 0), "/Host"); + set_memory32_c(pb + VolumeRec_totalBlocks, 0x007fffff, 0); + set_memory32_c(pb + VolumeRec_freeBlocks, 0x007fffff-1, 0); + set_memory16_c(pb + VolumeRec_fileSysID, mfsFSID, 0); + } + + return rv; + +} + +static word32 fst_clear_backup(int class, const char *path) { + return invalidFSTop; +} + + +static int open_data_fork(const char *path, word16 *access, word16 *error) { + + int fd = -1; + for (;;) { + + switch(*access) { + case readEnableAllowWrite: + case readWriteEnable: + fd = open(path, O_RDWR); + break; + case readEnable: + fd = open(path, O_RDONLY); + break; + case writeEnable: + fd = open(path, O_WRONLY); + break; + } + + if (*access == readEnableAllowWrite) { + if (fd < 0) { + *access = readEnable; + continue; + } + *access = readWriteEnable; + } + break; + } + if (fd < 0) { + *error = host_map_errno_path(errno, path); + } + + return fd; +} +#if defined(__APPLE__) +static int open_resource_fork(const char *path, word16 *access, word16 *error) { + // os x / hfs/apfs don't need to specifically create a resource fork. + // or do they? + + char *rpath = host_gc_append_path(path, _PATH_RSRCFORKSPEC); + + int fd = -1; + for (;;) { + + switch(*access) { + case readEnableAllowWrite: + case readWriteEnable: + fd = open(rpath, O_RDWR | O_CREAT, 0666); + break; + case readEnable: + fd = open(rpath, O_RDONLY); + break; + case writeEnable: + fd = open(rpath, O_WRONLY | O_CREAT, 0666); + break; + } + + if (*access == readEnableAllowWrite) { + if (fd < 0) { + *access = readEnable; + continue; + } + *access = readWriteEnable; + } + break; + } + if (fd < 0) { + *error = host_map_errno_path(errno, path); + } + + return fd; + + + +} +#elif defined __sun +static int open_resource_fork(const char *path, word16 *access, word16 *error) { + int tmp = open(path, O_RDONLY); + if (tmp < 0) { + *error = host_map_errno_path(errno, path); + return -1; + } + + int fd = -1; + for(;;) { + + switch(*access) { + case readEnableAllowWrite: + case readWriteEnable: + fd = openat(tmp, XATTR_RESOURCEFORK_NAME, O_RDWR | O_CREAT | O_XATTR, 0666); + break; + case readEnable: + fd = openat(tmp, XATTR_RESOURCEFORK_NAME, O_RDONLY | O_XATTR); + break; + case writeEnable: + fd = openat(tmp, XATTR_RESOURCEFORK_NAME, O_WRONLY | O_CREAT | O_XATTR, 0666); + break; + } + + if (*access == readEnableAllowWrite) { + if (fd < 0) { + *access = readEnable; + continue; + } + *access = readWriteEnable; + } + break; + } + + if (fd < 0) { + *error = host_map_errno_path(errno, path); + close(tmp); + return -1; + } + close(tmp); + + return fd; +} +#elif defined __linux__ +static int open_resource_fork(const char *path, word16 *access, word16 *error) { + *error = resForkNotFound; + return -1; +} +#else +static int open_resource_fork(const char *path, word16 *access, word16 *error) { + *error = resForkNotFound; + return -1; +} +#endif + + +static word32 fst_open(int class, const char *path) { + + + word32 pb = get_memory24_c(engine.direct + dp_param_blk_ptr, 0); + + struct file_info fi; + word16 rv = 0; + + rv = host_get_file_info(path, &fi); + if (rv) return rv; + + + int fd = -1; + int type = file_regular; + struct directory *dd = NULL; + + word16 pcount = 0; + word16 request_access = readEnableAllowWrite; + word16 access = 0; + word16 resource_number = 0; + if (class) { + pcount = get_memory16_c(pb, 0); + if (pcount >= 3) request_access = get_memory16_c(pb + OpenRecGS_requestAccess, 0); + if (pcount >= 4) resource_number = get_memory16_c(pb + OpenRecGS_resourceNumber, 0); + } + + if (resource_number) { + if (resource_number > 1) return paramRangeErr; + type = file_resource; + } + + if (access > 3) return paramRangeErr; + + // special access checks for directories. + if (fi.storage_type == 0x0d || fi.storage_type == 0x0f) { + if (resource_number) return resForkNotFound; + switch (request_access) { + case readEnableAllowWrite: + request_access = readEnable; + break; + case writeEnable: + case readWriteEnable: + return invalidAccess; + } + type = file_directory; + } + + + if (g_cfg_host_read_only) { + switch (request_access) { + case readEnableAllowWrite: + request_access = readEnable; + break; + case readWriteEnable: + case writeEnable: + return invalidAccess; + break; + } + } + + access = request_access; + switch(type) { + case file_regular: + fd = open_data_fork(path, &access, &rv); + break; + case file_resource: + fd = open_resource_fork(path, &access, &rv); + break; + case file_directory: + dd = read_directory(path, &rv); + break; + } + + if (rv) return rv; + + + if (class) { + if (pcount >= 5) set_memory16_c(pb + OpenRecGS_access, access, 0); + if (pcount >= 6) set_memory16_c(pb + OpenRecGS_fileType, fi.file_type, 0); + if (pcount >= 7) set_memory32_c(pb + OpenRecGS_auxType, fi.aux_type, 0); + if (pcount >= 8) set_memory16_c(pb + OpenRecGS_storageType, fi.storage_type, 0); + + if (pcount >= 9) host_set_date_time_rec(pb + OpenRecGS_createDateTime, fi.create_date); + if (pcount >= 10) host_set_date_time_rec(pb + OpenRecGS_modDateTime, fi.modified_date); + + if (pcount >= 11) { + word16 fst_id = hfsFSID; + //if (fi.storage_type == 0x0f) fst_id = mfsFSID; + + word32 option_list = get_memory24_c(pb + OpenRecGS_optionList, 0); + word32 tmp = set_option_list(option_list, fst_id, fi.finder_info, fi.has_fi ? 32 : 0); + if (!rv) rv = tmp; + } + + if (pcount >= 12) set_memory32_c(pb + OpenRecGS_eof, fi.eof, 0); + if (pcount >= 13) set_memory32_c(pb + OpenRecGS_blocksUsed, fi.blocks, 0); + if (pcount >= 14) set_memory32_c(pb + OpenRecGS_resourceEOF, fi.resource_eof, 0); + if (pcount >= 15) set_memory32_c(pb + OpenRecGS_resourceBlocks, fi.resource_blocks, 0); + + + } + // prodos 16 doesn't return anything in the parameter block. + + struct fd_entry *e = alloc_fd(); + if (!e) { + if (fd >=0) close(fd); + if (dd) free_directory(dd); + return outOfMem; + } + e->fd = fd; + e->dir = dd; + + e->cookie = alloc_cookie(); + if (!e->cookie) { + free_fd(e); + return tooManyFilesOpen; + } + + if (type == file_regular) { + + if (g_cfg_host_crlf) { + if (fi.file_type == 0x04 || fi.file_type == 0xb0) + e->translate = translate_crlf; + } + + if (g_cfg_host_merlin && fi.file_type == 0x04) { + int n = strlen(path); + if (n >= 3 && path[n-1] == 'S' && path[n-2] == '.') + e->translate = translate_merlin; + } + } + + e->access = access; + e->path = strdup(path); + e->type = type; + + + // insert it in the linked list. + e->next = fd_head; + fd_head = e; + + engine.xreg = e->cookie; + engine.yreg = access; // actual access, needed in fcr. + + return rv; +} + +static word32 fst_read(int class) { + + int cookie = engine.yreg; + struct fd_entry *e = find_fd(cookie); + + if (!e) return invalidRefNum; + + switch (e->type) { + case file_directory: + return badStoreType; + } + + word32 pb = get_memory24_c(engine.direct + dp_param_blk_ptr, 0); + + word32 data_buffer = 0; + word32 request_count = 0; + word32 transfer_count = 0; + + if (class) { + data_buffer = get_memory24_c(pb + IORecGS_dataBuffer, 0); + request_count = get_memory24_c(pb + IORecGS_requestCount, 0); + // pre-zero transfer count + set_memory32_c(pb + IORecGS_transferCount, 0, 0); + } else { + data_buffer = get_memory24_c(pb + FileIORec_dataBuffer, 0); + request_count = get_memory24_c(pb + FileIORec_requestCount, 0); + set_memory32_c(pb + FileIORec_transferCount, 0, 0); + } + + if (request_count == 0) return 0; + + + word16 newline_mask; + word32 rv = 0; + ssize_t ok; + + newline_mask = get_memory16_c(global_buffer, 0); + if (newline_mask) { + byte newline_table[256]; + for (int i = 0; i < 256; ++i) + newline_table[i] = get_memory_c(global_buffer + 2 + i, 0); + + for (word32 i = 0; i < request_count; ++i) { + byte b; + ok = safe_read(e, &b, 1); + if (ok < 0) return host_map_errno(errno); + if (ok == 0) break; + transfer_count++; + set_memory_c(data_buffer++, b, 0); + if (newline_table[b & newline_mask]) break; + } + if (transfer_count == 0) rv = eofEncountered; + } + else { + byte *data = host_gc_malloc(request_count); + if (!data) return outOfMem; + + + ok = safe_read(e, data, request_count); + if (ok < 0) rv = host_map_errno(errno); + if (ok == 0) rv = eofEncountered; + if (ok > 0) { + transfer_count = ok; + for (size_t i = 0; i < ok; ++i) { + set_memory_c(data_buffer + i, data[i], 0); + } + } + } + + if (transfer_count) { + if (class) + set_memory32_c(pb + IORecGS_transferCount, transfer_count, 0); + else + set_memory32_c(pb + FileIORec_transferCount, transfer_count, 0); + } + + return rv; +} + +static word32 fst_write(int class) { + + int cookie = engine.yreg; + struct fd_entry *e = find_fd(cookie); + + if (!e) return invalidRefNum; + + if (!(e->access & writeEnable)) + return invalidAccess; + + switch (e->type) { + case file_directory: + return badStoreType; + } + + + word32 pb = get_memory24_c(engine.direct + dp_param_blk_ptr, 0); + + word32 data_buffer = 0; + word32 request_count = 0; + + if (class) { + data_buffer = get_memory24_c(pb + IORecGS_dataBuffer, 0); + request_count = get_memory24_c(pb + IORecGS_requestCount, 0); + // pre-zero transfer count + set_memory32_c(pb + IORecGS_transferCount, 0, 0); + } else { + data_buffer = get_memory24_c(pb + FileIORec_dataBuffer, 0); + request_count = get_memory24_c(pb + FileIORec_requestCount, 0); + set_memory32_c(pb + FileIORec_transferCount, 0, 0); + } + + if (request_count == 0) return 0; + byte *data = host_gc_malloc(request_count); + if (!data) return outOfMem; + + for (word32 i = 0; i < request_count; ++i) { + data[i] = get_memory_c(data_buffer + i,0); + } + + word32 rv = 0; + ssize_t ok = safe_write(e, data, request_count); + if (ok < 0) rv = host_map_errno(errno); + if (ok > 0) { + if (class) + set_memory32_c(pb + IORecGS_transferCount, ok, 0); + else + set_memory32_c(pb + FileIORec_transferCount, ok, 0); + } + return rv; +} + +static word32 fst_close(int class) { + + int cookie = engine.yreg; + + return remove_fd(cookie); + +} + +static word32 fst_flush(int class) { + + int cookie = engine.yreg; + struct fd_entry *e = find_fd(cookie); + + if (!e) return invalidRefNum; + + switch (e->type) { + case file_directory: + return badStoreType; + } + + int ok = fsync(e->fd); + if (ok < 0) return host_map_errno(errno); + return 0; +} + +static off_t get_offset(int fd, word16 base, word32 displacement) { + + off_t pos = lseek(fd, 0, SEEK_CUR); + off_t eof = lseek(fd, 0, SEEK_END); + lseek(fd, pos, SEEK_SET); + + switch (base) { + case startPlus: + return displacement; + break; + case eofMinus: + return eof - displacement; + break; + case markPlus: + return pos + displacement; + break; + case markMinus: + return pos - displacement; + break; + default: + return -1; + } + + +} + +static word32 fst_set_mark(int class) { + + int cookie = engine.yreg; + + struct fd_entry *e = find_fd(cookie); + if (!e) return invalidRefNum; + + switch (e->type) { + case file_directory: + return badStoreType; + } + + word32 pb = get_memory24_c(engine.direct + dp_param_blk_ptr, 0); + + word16 base = 0; + word32 displacement = 0; + if (class) { + base = get_memory16_c(pb + SetPositionRecGS_base, 0); + displacement = get_memory32_c(pb + SetPositionRecGS_displacement, 0); + } else { + displacement = get_memory32_c(pb + MarkRec_position, 0); + } + if (base > markMinus) return paramRangeErr; + + off_t offset = get_offset(e->fd, base, displacement); + if (offset < 0) return outOfRange; + + off_t ok = lseek(e->fd, offset, SEEK_SET); + if (ok < 0) return host_map_errno(errno); + return 0; +} + +static word32 fst_set_eof(int class) { + + int cookie = engine.yreg; + + struct fd_entry *e = find_fd(cookie); + if (!e) return invalidRefNum; + + switch (e->type) { + case file_directory: + return badStoreType; + } + + + word32 pb = get_memory24_c(engine.direct + dp_param_blk_ptr, 0); + + word16 base = 0; + word32 displacement = 0; + if (class) { + base = get_memory16_c(pb + SetPositionRecGS_base, 0); + displacement = get_memory32_c(pb + SetPositionRecGS_displacement, 0); + } else { + displacement = get_memory32_c(pb + EOFRec_eofPosition, 0); + } + + if (base > markMinus) return paramRangeErr; + + off_t offset = get_offset(e->fd, base, displacement); + if (offset < 0) return outOfRange; + + int ok = ftruncate(e->fd, offset); + if (ok < 0) return host_map_errno(errno); + return 0; + +} + +static word32 fst_get_mark(int class) { + + int cookie = engine.yreg; + + struct fd_entry *e = find_fd(cookie); + if (!e) return invalidRefNum; + + word32 pb = get_memory24_c(engine.direct + dp_param_blk_ptr, 0); + + off_t pos = 0; + + switch (e->type) { + case file_directory: + return badStoreType; + } + + pos = lseek(e->fd, 0, SEEK_CUR); + if (pos < 0) return host_map_errno(errno); + + if (class) { + set_memory32_c(pb + PositionRecGS_position, pos, 0); + } else { + set_memory32_c(pb + MarkRec_position, pos, 0); + } + + return 0; +} + +static word32 fst_get_eof(int class) { + + int cookie = engine.yreg; + + struct fd_entry *e = find_fd(cookie); + if (!e) return invalidRefNum; + + word32 pb = get_memory24_c(engine.direct + dp_param_blk_ptr, 0); + + + switch (e->type) { + case file_directory: + return badStoreType; + } + + + off_t eof = 0; + off_t pos = 0; + + pos = lseek(e->fd, 0, SEEK_CUR); + eof = lseek(e->fd, 0, SEEK_END); + if (eof < 0) return host_map_errno(errno); + lseek(e->fd, pos, SEEK_SET); + + + if (class) { + set_memory32_c(pb + PositionRecGS_position, eof, 0); + } else { + set_memory32_c(pb + MarkRec_position, eof, 0); + } + + return 0; +} + +static void free_directory(struct directory *dd) { + if (!dd) return; + for (int i = 0; i < dd->num_entries; ++i) { + free(dd->entries[i]); + } + free(dd); +} + +static int qsort_callback(const void *a, const void *b) { + return strcmp(*(const char **)a, *(const char **)b); +} + +/* + * exclude files from get_dir_entries. + * + */ +static int filter_directory_entry(const char *name) { + if (!name[0]) return 1; + if (name[0] == '.') { + return 1; + /* + if (!strcmp(name, ".")) return 1; + if (!strcmp(name, "..")) return 1; + if (!strncmp(name, "._", 2)) return 1; // ._ resource fork + if (!strcmp(name, ".fseventsd")) return 1; + */ + } + return 0; +} + + +static struct directory *read_directory(const char *path, word16 *error) { + DIR *dirp; + struct directory *dd; + int capacity = 100; + int size = sizeof(struct directory) + capacity * sizeof(char *); + + dirp = opendir(path); + if (!dirp) { + *error = host_map_errno_path(errno, path); + return NULL; + } + + dd = (struct directory *)malloc(size); + if (!dd) { + *error = outOfMem; + closedir(dirp); + return NULL; + } + memset(dd, 0, size); + + for(;;) { + struct dirent *d = readdir(dirp); + if (!d) break; + if (filter_directory_entry(d->d_name)) continue; + + if (dd->num_entries >= capacity) { + capacity += capacity; + size = sizeof(struct directory) + capacity * sizeof(char *); + struct directory * tmp = realloc(dd, size); + if (!tmp) { + *error = host_map_errno(errno); + free_directory(dd); + closedir(dirp); + return NULL; + } + dd = tmp; + } + dd->entries[dd->num_entries++] = strdup(d->d_name); + }; + + closedir(dirp); + + // sort them.... + qsort(dd->entries, dd->num_entries, sizeof(char *), qsort_callback); + + return dd; +} + + +static word32 fst_get_dir_entry(int class) { + + + int cookie = engine.yreg; + + struct fd_entry *e = find_fd(cookie); + if (!e) return invalidRefNum; + + + if (e->type != file_directory) return badFileFormat; + + word32 pb = get_memory24_c(engine.direct + dp_param_blk_ptr, 0); + + word16 base = 0; + word16 pcount = 0; + word32 displacement = 0; + word32 name = 0; + + if (class) { + pcount = get_memory16_c(pb, 0); + base = get_memory16_c(pb + DirEntryRecGS_base, 0); + displacement = get_memory16_c(pb + DirEntryRecGS_displacement, 0); + name = get_memory24_c(pb + DirEntryRecGS_name, 0); + } else { + base = get_memory16_c(pb + DirEntryRec_base, 0); + displacement = get_memory16_c(pb + DirEntryRec_displacement, 0); + name = get_memory24_c(pb + DirEntryRec_nameBuffer, 0); + } + + if (base == 0 && displacement == 0) { + // count them up. + int count = e->dir->num_entries; + e->dir->displacement = 0; + + if (class) { + if (pcount >= 6) set_memory16_c(pb + DirEntryRecGS_entryNum, count, 0); + } + else { + set_memory16_c(pb + DirEntryRec_entryNum, count, 0); + } + + return 0; + } + + int dir_displacement = e->dir->displacement; + switch (base) { + case 0: // displacement is absolute entry number. + break; + case 1: // displacement is added to the current displacement. + displacement = dir_displacement + displacement; + break; + case 2: // displacement is substracted from current displacement. + displacement = dir_displacement - displacement; + break; + default: + return paramRangeErr; + } + //if (displacement) --displacement; + --displacement; + if (displacement < 0) return endOfDir; + if (displacement >= e->dir->num_entries) return endOfDir; + + + word32 rv = 0; + const char *dname = e->dir->entries[displacement++]; + e->dir->displacement = displacement; + char *fullpath = host_gc_append_path(e->path, dname); + struct file_info fi; + rv = host_get_file_info(fullpath, &fi); + + if (dname) fprintf(stderr, " - %s", dname); + + // p16 and gs/os both use truncating c1 output string. + rv = set_gsstr_truncate(name, dname); + + if (class) { + + if (pcount > 2) set_memory16_c(pb + DirEntryRecGS_flags, fi.storage_type == 0x05 ? 0x8000 : 0, 0); + + if (pcount >= 6) set_memory16_c(pb + DirEntryRecGS_entryNum, displacement, 0); + if (pcount >= 7) set_memory16_c(pb + DirEntryRecGS_fileType, fi.file_type, 0); + if (pcount >= 8) set_memory32_c(pb + DirEntryRecGS_eof, fi.eof, 0); + if (pcount >= 9) set_memory32_c(pb + DirEntryRecGS_blockCount, fi.blocks, 0); + + if (pcount >= 10) host_set_date_time_rec(pb + DirEntryRecGS_createDateTime, fi.create_date); + if (pcount >= 11) host_set_date_time_rec(pb + DirEntryRecGS_modDateTime, fi.modified_date); + + if (pcount >= 12) set_memory16_c(pb + DirEntryRecGS_access, fi.access, 0); + if (pcount >= 13) set_memory32_c(pb + DirEntryRecGS_auxType, fi.aux_type, 0); + if (pcount >= 14) set_memory16_c(pb + DirEntryRecGS_fileSysID, mfsFSID, 0); + + if (pcount >= 15) { + word16 fst_id = hfsFSID; + //if (fi.storage_type == 0x0f) fst_id = mfsFSID; + word32 option_list = get_memory24_c(pb + DirEntryRecGS_optionList, 0); + word32 tmp = set_option_list(option_list, fst_id, fi.finder_info, fi.has_fi ? 32 : 0); + if (!rv) rv = tmp; + } + + if (pcount >= 16) set_memory32_c(pb + DirEntryRecGS_resourceEOF, fi.resource_eof, 0); + if (pcount >= 17) set_memory32_c(pb + DirEntryRecGS_resourceBlocks, fi.resource_blocks, 0); + } + else { + set_memory16_c(pb + DirEntryRec_flags, fi.storage_type == 0x05 ? 0x8000 : 0, 0); + + set_memory16_c(pb + DirEntryRec_entryNum, displacement, 0); + set_memory16_c(pb + DirEntryRec_fileType, fi.file_type, 0); + set_memory32_c(pb + DirEntryRec_endOfFile, fi.eof, 0); + set_memory32_c(pb + DirEntryRec_blockCount, fi.blocks, 0); + + host_set_date_time_rec(pb + DirEntryRec_createTime, fi.create_date); + host_set_date_time_rec(pb + DirEntryRec_modTime, fi.modified_date); + + set_memory16_c(pb + DirEntryRec_access, fi.access, 0); + set_memory32_c(pb + DirEntryRec_auxType, fi.aux_type, 0); + set_memory16_c(pb + DirEntryRec_fileSysID, mfsFSID, 0); + + } + + return rv; +} + +static word32 fst_change_path(int class, const char *path1, const char *path2) { + + /* make sure they're not trying to rename the volume... */ + struct stat st; + if (stat(path1, &st) < 0) return host_map_errno_path(errno, path1); + if (host_is_root(&st)) + return invalidAccess; + + // rename will delete any previous file. ChangePath should return an error. + if (stat(path2, &st) == 0) return dupPathname; + + if (rename(path1, path2) < 0) return host_map_errno_path(errno, path2); + return 0; +} + +static word32 fst_format(int class) { + return notBlockDev; +} + +static word32 fst_erase(int class) { + return notBlockDev; +} + +static const char *call_name(word16 call) { + static char* class1[] = { + // 0x00 + "", + "CreateGS", + "DestroyGS", + "", + "ChangePathGS", + "SetFileInfoGS", + "GetFileInfoGS", + "JudgeNameGS", + "VolumeGS", + "", + "", + "ClearBackupGS", + "", + "", + "", + "", + + // 0x10 + "OpenGS", + "", + "ReadGS", + "WriteGS", + "CloseGS", + "FlushGS", + "SetMarkGS", + "GetMarkGS", + "SetEOFGS", + "GetEOFGS", + "", + "", + "GetDirEntryGS", + "", + "", + "", + + // 0x20 + "", + "", + "", + "", + "FormatGS", + "EraseDiskGS", + }; + + + static char* class0[] = { + // 0x00 + "", + "CREATE", + "DESTROY", + "", + "CHANGE_PATH", + "SET_FILE_INFO", + "GET_FILE_INFO", + "", + "VOLUME", + "", + "", + "CLEAR_BACKUP_BIT", + "", + "", + "", + "", + + // 0X10 + "OPEN", + "", + "READ", + "WRITE", + "CLOSE", + "FLUSH", + "SET_MARK", + "GET_MARK", + "SET_EOF", + "GET_EOF", + "", + "", + "GET_DIR_ENTRY", + "", + "", + "", + + // 0X20 + "", + "", + "", + "", + "FORMAT", + "ERASE_DISK", + }; + + + + if (call & 0x8000) { + static char *sys[] = { + "", + "fst_startup", + "fst_shutdown", + "fst_remove_vcr", + "fst_deferred_flush" + }; + call &= ~0x8000; + + if (call < sizeof(sys) / sizeof(sys[0])) + return sys[call]; + + return ""; + } + + int class = call >> 13; + call &= 0x1fff; + switch(class) { + case 0: + if (call < sizeof(class0) / sizeof(class0[0])) + return class0[call]; + break; + case 1: + if (call < sizeof(class1) / sizeof(class1[0])) + return class1[call]; + break; + + } + return ""; +} + + +void host_fst(void) { + + /* + * input: + * c = set + * a = default error code + * x = gs/os callnum + * y = [varies] + * + * output: + * c = set/clear + * a = error code/0 + * x = varies + * y = varies + */ + + + word32 acc = 0; + word16 call = engine.xreg; + + fprintf(stderr, "Host FST: %04x %s", call, call_name(call)); + + + if (call & 0x8000) { + fputs("\n", stderr); + // system level. + switch(call) { + case 0x8001: + acc = fst_startup(); + break; + case 0x8002: + acc = fst_shutdown(); + break; + default: + acc = badSystemCall; + break; + } + } else { + + if (!host_root) { + acc = networkError; + engine.acc = acc; + SEC(); + fprintf(stderr, " %02x %s\n", acc, host_error_name(acc)); + + return; + } + + int class = call >> 13; + call &= 0x1fff; + + if (class > 1) { + acc = invalidClass; + engine.acc = acc; + SEC(); + fprintf(stderr, " %02x %s\n", acc, host_error_name(acc)); + + return; + } + + char *path1 = NULL; + char *path2 = NULL; + char *path3 = NULL; + char *path4 = NULL; + const char *cp; + + switch(call & 0xff) { + case 0x01: + case 0x02: + case 0x05: + case 0x06: + case 0x0b: + case 0x10: + path1 = get_path1(); + break; + case 0x04: + path1 = get_path1(); + path2 = get_path2(); + break; + } + + if (path1) fprintf(stderr, " - %s", path1); + if (path2) fprintf(stderr, " - %s", path2); + + switch(call & 0xff) { + case 0x01: + cp = check_path(path1, &acc); + if (acc) break; + path3 = host_gc_append_path(host_root, cp); + + acc = fst_create(class, path3); + break; + case 0x02: + cp = check_path(path1, &acc); + if (acc) break; + path3 = host_gc_append_path(host_root, cp); + + acc = fst_destroy(class, path3); + break; + case 0x04: + + cp = check_path(path1, &acc); + if (acc) break; + path3 = host_gc_append_path(host_root, cp); + + cp = check_path(path2, &acc); + if (acc) break; + path4 = host_gc_append_path(host_root, cp); + + acc = fst_change_path(class, path3, path4); + break; + case 0x05: + cp = check_path(path1, &acc); + if (acc) break; + path3 = host_gc_append_path(host_root, cp); + + acc = fst_set_file_info(class, path3); + break; + case 0x06: + cp = check_path(path1, &acc); + if (acc) break; + path3 = host_gc_append_path(host_root, cp); + acc = fst_get_file_info(class, path3); + break; + case 0x07: + acc = fst_judge_name(class, path1); + break; + case 0x08: + acc = fst_volume(class); + break; + case 0x0b: + cp = check_path(path1, &acc); + if (acc) break; + path3 = host_gc_append_path(host_root, cp); + acc = fst_clear_backup(class, path3); + break; + case 0x10: + cp = check_path(path1, &acc); + if (acc) break; + path3 = host_gc_append_path(host_root, cp); + acc = fst_open(class, path3); + break; + case 0x012: + acc = fst_read(class); + break; + case 0x013: + acc = fst_write(class); + break; + case 0x14: + acc = fst_close(class); + break; + case 0x15: + acc = fst_flush(class); + break; + case 0x16: + acc = fst_set_mark(class); + break; + case 0x17: + acc = fst_get_mark(class); + break; + case 0x18: + acc = fst_set_eof(class); + break; + case 0x19: + acc = fst_get_eof(class); + break; + case 0x1c: + acc = fst_get_dir_entry(class); + break; + case 0x24: + acc = fst_format(class); + break; + case 0x25: + acc = fst_erase(class); + break; + + default: + acc = invalidFSTop; + break; + } + fputs("\n", stderr); + } + + if (acc) fprintf(stderr, " %02x %s\n", acc, host_error_name(acc)); + + host_gc_free(); + + engine.acc = acc; + if (acc) SEC(); + else CLC(); +} diff --git a/src/host_mli.c b/src/host_mli.c new file mode 100644 index 0000000..7ad456f --- /dev/null +++ b/src/host_mli.c @@ -0,0 +1,1567 @@ +/* + GSport - an Apple //gs Emulator + Copyright (C) 2010 - 2019 by GSport contributors + Copyright (C) 2016 - 2018 Dagen Brock + + Based on the KEGS emulator written by and Copyright (C) 2003 Kent Dickey + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 2 of the License, or (at your + option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#define _BSD_SOURCE + +#ifdef _WIN32 +#include +#else + +#include +#include +#include +#include +#include + +#endif + +#include +#include +#include +#include + + +#include "defc.h" +#include "gsos.h" +#include "fst.h" + + +#include "host_common.h" + + +#define LEVEL 0xBFD8 // current file level +#define DEVNUM 0xBF30 // last slot / drive +#define DEVCNT 0xBF31 // count - 1 +#define DEVLST 0xBF32 // active device list +#define PFIXPTR 0xbf9a // active prefix? + +/* bf97 is appletalk prefix? */ + + +#define ENTRY_LENGTH 0x27 +#define ENTRIES_PER_BLOCK 0x0d + + +static unsigned saved_call; +static unsigned saved_dcb; +static unsigned saved_p; +static unsigned saved_patch_address; +static unsigned saved_mli_address; +static unsigned saved_unit; +static char *saved_prefix; + + + +enum { + CREATE = 0xc0, + DESTROY = 0xc1, + RENAME = 0xc2, + SET_FILE_INFO = 0xc3, + GET_FILE_INFO = 0xc4, + ONLINE = 0xc5, + SET_PREFIX = 0xc6, + GET_PREFIX = 0xc7, + OPEN = 0xc8, + NEWLINE = 0xc9, + READ = 0xca, + WRITE = 0xcb, + CLOSE = 0xcc, + FLUSH = 0xcd, + SET_MARK = 0xce, + GET_MARK = 0xcf, + SET_EOF = 0xd0, + GET_EOF = 0xd1, + SET_BUF = 0xd2, + GET_BUF = 0xd3, + ALLOC_INTERRUPT = 0x40, + DEALLOC_INTERRUPT = 0x41, + ATINIT = 0x99, + READ_BLOCK = 0x80, + WRITE_BLOCK = 0x81, + GET_TIME = 0x82, + QUIT = 0x65 +}; + +#define badBufferAddress 0x56 + +struct file_entry { + unsigned type; + unsigned translate; + +#ifdef _WIN32 + HANDLE h; +#else + int fd; +#endif + + unsigned buffer; + unsigned level; + unsigned newline_mask; + unsigned newline_char; + + /* directory stuff */ + unsigned mark; + unsigned eof; + unsigned char *directory_buffer; +}; + +#define MAX_FILES 8 +#define MIN_FILE 0x40 +#define MAX_FILE 0x48 +struct file_entry files[MAX_FILES]; + + + + +#if _WIN32 +static word16 file_open(const char *path, struct file_entry *file) { + + HANDLE h; + + if (g_cfg_host_read_only) { + h = CreateFile(path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + } else { + h = CreateFile(path, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + if (h == INVALID_HANDLE_VALUE) { + h = CreateFile(path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + } + } + + if (h == INVALID_HANDLE_VALUE) return host_map_win32_error(GetLastError()); + + file->h = h; + return 0; +} + +static word16 file_close(struct file_entry *file) { + + if (!file->type) return invalidRefNum; + + if (file->h != INVALID_HANDLE_VALUE) CloseHandle(file->h); + + if (file->directory_buffer) free(file->directory_buffer); + memset(file, 0, sizeof(*file)); + file->h = INVALID_HANDLE_VALUE; + + return 0; +} + +static word16 file_flush(struct file_entry *file) { + if (!file->type) return invalidRefNum; + + if (file->h != INVALID_HANDLE_VALUE) + FlushFileBuffers(file->h); + + return 0; +} + +static word16 file_eof(struct file_entry *file) { + LARGE_INTEGER li; + if (!GetFileSizeEx(file->h, &li)) + return host_map_win32_error(GetLastError()); + if (li.QuadPart > 0xffffff) { + file->eof = 0xffffff; + return outOfRange; + } + file->eof = li.QuadPart; + return 0; +} + + +#else + +static word16 file_open(const char *path, struct file_entry *file) { + + int fd; + + if (g_cfg_host_read_only) { + fd = open(path, O_RDONLY | O_NONBLOCK); + } else { + fd = open(path, O_RDWR | O_NONBLOCK); + if (fd < 0) { + fd = open(path, O_RDONLY | O_NONBLOCK); + } + } + if (fd < 0) return host_map_errno_path(errno, path); + + file->fd = fd; + return 0; +} + +static word16 file_close(struct file_entry *file) { + + if (!file->type) return invalidRefNum; + + if (file->fd >= 0) close(file->fd); + + if (file->directory_buffer) free(file->directory_buffer); + memset(file, 0, sizeof(*file)); + file->fd = -1; + return 0; +} + +static word16 file_flush(struct file_entry *file) { + if (!file->type) return invalidRefNum; + + if (file->fd >= 0) + fsync(file->fd); + + return 0; +} + +static word16 file_eof(struct file_entry *file) { + off_t eof; + eof = lseek(file->fd, 0, SEEK_END); + if (eof < 0) return host_map_errno(errno); + if (eof > 0xffffff) { + file->eof = 0xffffff; + return outOfRange; + } + file->eof = eof; + return 0; +} + +#endif + + + + +static char *get_pstr(word32 ptr) { + if (!ptr) return NULL; + int length = get_memory_c(ptr, 0); + ptr += 1; + char *str = host_gc_malloc(length + 1); + for (int i = 0; i < length; ++i) { + char c = get_memory_c(ptr+i, 0) & 0x7f; + str[i] = c; + } + str[length] = 0; + return str; +} + +static word32 set_pstr(word32 ptr, const char *str) { + + if (!ptr) return paramRangeErr; + + int l = str ? strlen(str) : 0; + + if (l > 255) return buffTooSmall; + // / is the pascal separator. + set_memory_c(ptr++, l, 0); + for (int i = 0; i < l; ++i) { + set_memory_c(ptr++, *str++, 0); + } + return 0; +} + + + +static char *is_host_path(unsigned pathname) { + /* add + 5 below to skip past the /HOST/ part */ + /* (prefix may be missing trailing / ) */ + char *p = get_pstr(pathname); + if (!p) return NULL; + if (*p == '/') { + if (!strncasecmp(p, "/HOST", 5)) { + if (p[5] == 0) return "/"; + if (p[5] == '/') return p + 5; + } + return NULL; + } + + if (saved_prefix) { + return host_gc_append_path(saved_prefix + 5, p); + } + return NULL; +} + + +static unsigned lowercase_bits(const char *name) { + unsigned rv = 0x8000; + unsigned bit = 0x4000; + for(unsigned i = 0; i < 15; ++i, bit >>= 1) { + char c = name[i]; + if (c == 0) break; + if (islower(c)) rv |= bit; + } + return rv; +} + +/* name is relative to the host directory. */ + +void *create_directory_file(const char *name, const char *path, word16 *error_ptr, unsigned *block_ptr) { + + + byte *data = NULL; + int capacity = 0; + int count = 0; + unsigned offset = 0; + int i; + struct file_info fi; + unsigned blocks = 1; + unsigned terr; + + word32 w32; + + char **entries = NULL; + size_t entry_count = 0; + terr = host_scan_directory(path, &entries, &entry_count, 1); + if (terr) { + *error_ptr = terr; + return NULL; + } + + /* also need space for volume/directory header */ + capacity = 1 + (1 + entry_count) / ENTRIES_PER_BLOCK; + capacity *= 512; + + data = malloc(capacity); + if (!data) { + *error_ptr = outOfMem; + goto exit; + } + memset(data, 0, capacity); + + + terr = host_get_file_info(path, &fi); + if (terr) { + *error_ptr = terr; + goto exit; + } + + /* trailing /s should already be stripped */ + const char *base_name = strchr(name, '/'); + base_name = base_name ? base_name + 1 : name; + if (!base_name || !*base_name) base_name = "HOST"; + + int len = strlen(base_name); + if (len > 15) len = 15; + /* previous / next pointers */ + data[0] = 0; + data[1] = 0; + data[2] = 0; + data[3] = 0; + offset = 4; + + int root = fi.storage_type == 0x0f; + if (root) { + data[offset++] = 0xf0 | len; + } else { + data[offset++] = 0xe0 | len; + } + for (i = 0; i < len; ++i) { + data[offset++] = toupper(base_name[i]); + } + for(; i < 15; ++i) { data[offset++] = 0; } + if (root) { + data[offset++] = 0; /* reserved */ + data[offset++] = 0; + + w32 = host_convert_date_time(fi.modified_date); + + data[offset++] = (w32 >> 0) & 0xff; /* last modified... */ + data[offset++] = (w32 >> 8) & 0xff; + data[offset++] = (w32 >> 16) & 0xff; + data[offset++] = (w32 >> 24) & 0xff; + + w32 = lowercase_bits(base_name); + data[offset++] = (w32 >> 0) & 0xff; /* file name case bits */ + data[offset++] = (w32 >> 8) & 0xff; + + + } else { + data[offset++] = 0x75; /* password enabled */ + for (i = 0; i < 7; ++i) data[offset++] = 0; /* password */ + } + + w32 = host_convert_date_time(fi.create_date); + + data[offset++] = (w32 >> 0) & 0xff; /* creation... */ + data[offset++] = (w32 >> 8) & 0xff; + data[offset++] = (w32 >> 16) & 0xff; + data[offset++] = (w32 >> 24) & 0xff; + + data[offset++] = 0; /* version */ + data[offset++] = 0; /* min version */ + data[offset++] = fi.access; /* access */ + data[offset++] = ENTRY_LENGTH; /* entry length */ + data[offset++] = ENTRIES_PER_BLOCK; /* entries per block */ + + data[offset++] = 0; /* file count (placeholder) */ + data[offset++] = 0; + + data[offset++] = 0; /* bitmap ptr, parent ptr, etc */ + data[offset++] = 0; + data[offset++] = 0; + data[offset++] = 0; + + + + int path_len = strlen(path); + + count = 0; + blocks = 1; + for (int j = 0; j < entry_count; ++j) { + + char *name = entries[j]; + int len = strlen(name); + char *tmp = malloc(path_len + 2 + len); + if (!tmp) continue; + + memcpy(tmp, path, path_len); + tmp[path_len] = '/'; + strcpy(tmp + path_len + 1, name); + + unsigned terr = host_get_file_info(tmp, &fi); + free(tmp); + if (terr) continue; + + /* wrap to next block ? */ + if ((offset + ENTRY_LENGTH) >> 9 == blocks) { + blocks++; + offset = (offset + 511) & ~511; + data[offset++] = 0; /* next/previous block pointers */ + data[offset++] = 0; + data[offset++] = 0; + data[offset++] = 0; + } + + assert(offset + ENTRY_LENGTH < capacity); + + /* create a prodos entry... */ + + + if (fi.storage_type == extendedFile) + fi.storage_type = 1; + int st = fi.storage_type << 4; + + data[offset++] = st | len; + for(i = 0; i < len; ++i) { + data[offset++] = toupper(name[i]); + } + for(; i < 15; ++i) data[offset++] = 0; + data[offset++] = fi.file_type; + data[offset++] = 0; /* key ptr */ + data[offset++] = 0; /* key ptr */ + data[offset++] = fi.blocks & 0xff; + data[offset++] = (fi.blocks >> 8) & 0xff; + data[offset++] = fi.eof & 0xff; + data[offset++] = (fi.eof >> 8) & 0xff; + data[offset++] = (fi.eof >> 16) & 0xff; + + w32 = host_convert_date_time(fi.create_date); + + data[offset++] = (w32 >> 0) & 0xff; /* creation... */ + data[offset++] = (w32 >> 8) & 0xff; + data[offset++] = (w32 >> 16) & 0xff; + data[offset++] = (w32 >> 24) & 0xff; + + w32 = lowercase_bits(name); + data[offset++] = (w32 >> 0) & 0xff; /* file name case bits */ + data[offset++] = (w32 >> 8) & 0xff; + + data[offset++] = fi.access; + data[offset++] = fi.aux_type & 0xff; + data[offset++] = (fi.aux_type >> 8) & 0xff; + + w32 = host_convert_date_time(fi.modified_date); + data[offset++] = (w32 >> 0) & 0xff; /* last mod... */ + data[offset++] = (w32 >> 8) & 0xff; + data[offset++] = (w32 >> 16) & 0xff; + data[offset++] = (w32 >> 24) & 0xff; + + data[offset++] = 0; /* header ptr */ + data[offset++] = 0; + count++; + } + + data[4 + 0x21] = count & 0xff; + data[4 + 0x22] = (count >> 8)& 0xff; + *block_ptr = blocks; + +exit: + if (entries) host_free_directory(entries, entry_count); + return data; +} + + + +static int mli_atinit(unsigned dcb) { + unsigned pcount = get_memory_c(dcb, 0); + + if (pcount < 3|| pcount > 4) return invalidPcount; + + unsigned version = get_memory_c(dcb + 1, 0); + saved_mli_address = get_memory16_c(dcb + 2, 0); + saved_patch_address = get_memory16_c(dcb + 4, 0); + if (!saved_patch_address) return paramRangeErr; + if (!saved_mli_address) return paramRangeErr; + + saved_unit = 0x80; + if (pcount >= 4) saved_unit = get_memory_c(dcb + 6, 0) & 0xf0; + + if (!saved_unit) return paramRangeErr; + + saved_prefix = 0; + + memset(files, 0, sizeof(files)); /* ??? */ + + return host_startup(); +} + + +enum { + FILE_INFO_pcount = 0, + FILE_INFO_pathname = 1, + FILE_INFO_access = 3, + FILE_INFO_file_type = 4, + FILE_INFO_aux_type = 5, + FILE_INFO_storage_type = 7, + FILE_INFO_blocks = 8, + FILE_INFO_mod_date = 10, + FILE_INFO_mod_time = 12, + FILE_INFO_create_date = 14, + FILE_INFO_create_time = 16 +}; + +static int mli_set_file_info(unsigned dcb, const char *path) { + + + struct file_info fi; + memset(&fi, 0, sizeof(fi)); + + fi.access = get_memory_c(dcb + FILE_INFO_access, 0); + fi.file_type = get_memory_c(dcb + FILE_INFO_file_type, 0); + fi.aux_type = get_memory16_c(dcb + FILE_INFO_aux_type, 0); + fi.modified_date = host_get_date_time(dcb + FILE_INFO_mod_date); + + return host_set_file_info(path, &fi); +} + +static int mli_get_file_info(unsigned dcb, const char *path) { + + struct file_info fi; + int rv = host_get_file_info(path, &fi); + if (rv) return rv; + + /* ignore resource fork */ + if (fi.storage_type == extendedFile) + fi.storage_type = seedling; + + set_memory_c(dcb + FILE_INFO_access, fi.access, 0); + set_memory_c(dcb + FILE_INFO_file_type, fi.file_type, 0); + set_memory16_c(dcb + FILE_INFO_aux_type, fi.aux_type, 0); + set_memory_c(dcb + FILE_INFO_storage_type, fi.storage_type, 0); + set_memory16_c(dcb + FILE_INFO_blocks, fi.blocks, 0); + host_set_date_time(dcb + FILE_INFO_mod_date, fi.modified_date); + host_set_date_time(dcb + FILE_INFO_create_date, fi.create_date); + + return 0; +} + +enum { + CREATE_pcount = 0, + CREATE_pathname = 1, + CREATE_access = 3, + CREATE_file_type = 4, + CREATE_aux_type = 5, + CREATE_storage_type = 7, + CREATE_create_date = 8, + CREATE_create_time = 10 +}; + +static int mli_create(unsigned dcb, const char *path) { + + struct file_info fi; + memset(&fi, 0, sizeof(fi)); + + fi.access = get_memory_c(dcb + CREATE_access, 0); + fi.file_type = get_memory_c(dcb + CREATE_file_type, 0); + fi.aux_type = get_memory16_c(dcb + CREATE_aux_type, 0); + fi.storage_type = get_memory_c(dcb + CREATE_storage_type, 0); + fi.create_date = host_get_date_time(dcb + CREATE_create_date); + + if (g_cfg_host_read_only) return drvrWrtProt; + + /* + * actual prodos needs the correct storage type and file type + * for a usable directory. this just does the right thing. + * TODO - does ProDOS update the storage type in the dcb? + */ + switch(fi.storage_type) { + case 0x0d: + fi.file_type = 0x0f; + break; + case 0x01: + case 0x02: + case 0x03: + fi.storage_type = 0x01; + break; + case 0x00: + if (fi.file_type == 0x0f) fi.storage_type = 0x0d; + else fi.storage_type = 0x01; + break; + default: + return badStoreType; + } + // todo -- remap access. + + if (fi.storage_type == 0x0d) { +#if _WIN32 + if (!CreateDirectory(path, NULL)) + return host_map_win32_error(GetLastError()); +#else + if (mkdir(path, 0777) < 0) + return host_map_errno_path(errno, path); +#endif + } else { +#if _WIN32 + HANDLE h = CreateFile(path, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL); + if (h == INVALID_HANDLE_VALUE) return host_map_win32_error(GetLastError()); + + afp_init(&fi.afp, fi.file_type, fi.aux_type); + fi.has_fi = 1; + + // set ftype, auxtype... + host_set_file_info(path, &fi); + CloseHandle(h); +#else + int fd = open(path, O_CREAT | O_EXCL | O_RDONLY, 0666); + if (fd < 0) + return host_map_errno_path(errno, path); + + host_file_type_to_finder_info(fi.finder_info, fi.file_type, fi.aux_type); + fi.has_fi = 1; + host_set_file_info(path, &fi); + close(fd); +#endif + } + + return 0; +} + +static int mli_destroy(unsigned dcb, const char *path) { + + word16 terr = 0; + unsigned type = host_storage_type(path, &terr); + if (type == 0) return terr; + + switch(type) { + case 0: return terr; + case 0x0f: return badPathSyntax; /* root directory */ + case 0x0d: +#if _WIN32 + if (!RemoveDirectory(path)) + return host_map_win32_error(GetLastError()); +#else + if (rmdir(path) < 0) + return host_map_errno_path(errno, path); +#endif + break; + case 1: + case 2: + case 3: + case 5: +#if _WIN32 + if (!DeleteFile(path)) + return host_map_win32_error(GetLastError()); +#else + if (unlink(path) < 0) + return host_map_errno_path(errno, path); +#endif + default: + return badStoreType; + } + return 0; +} + +static int mli_rename(unsigned dcb, const char *path1, const char *path2) { + /* can't rename the root directory */ + word16 terr = 0; + unsigned type; + + if (!path1 || !path2) return badPathSyntax; + + + type = host_storage_type(path1, &terr); + if (!type) return terr; + if (type == 0x0f) return badPathSyntax; + + type = host_storage_type(path2, &terr); + if (type) return dupPathname; + +#if _WIN32 + if (!MoveFile(path1, path2)) + return host_map_win32_error(GetLastError()); +#else + if (rename(path1, path2) < 0) + return host_map_errno(errno); +#endif + return 0; +} + + +static int mli_write(unsigned dcb, struct file_entry *file) { + + /* todo -- translate */ + + set_memory16_c(dcb + 6, 0, 0); + + if (!file->type) return invalidRefNum; + if (file->type != file_regular) return invalidAccess; + + unsigned data_buffer = get_memory16_c(dcb + 2, 0); + unsigned request_count = get_memory16_c(dcb + 4, 0); + + if (!data_buffer) return badBufferAddress; + + byte *data = host_gc_malloc(request_count); + if (!data) return drvrIOError; + + for (unsigned i = 0; i < request_count; ++i) { + data[i] = get_memory_c(data_buffer + i, 0); + } + + switch (file->translate) { + case translate_crlf: + host_cr_to_lf(data, request_count); + break; + case translate_merlin: + host_merlin_to_text(data, request_count); + break; + } + +#if _WIN32 + DWORD rv; + LARGE_INTEGER li; + li.QuadPart = file->mark; + if (!SetFilePointerEx(file->h, li, NULL, FILE_BEGIN)) + return host_map_win32_error(GetLastError()); + if (!WriteFile(file->h, data, request_count, &rv, NULL)) + return host_map_win32_error(GetLastError()); +#else + int rv = pwrite(file->fd, data, request_count, file->mark); + if (rv < 0) return host_map_errno(errno); +#endif + set_memory16_c(dcb + 6, rv, 0); + file->mark += rv; + + return 0; +} + + +static int mli_read(unsigned dcb, struct file_entry *file) { + + /* todo -- translate */ + + set_memory16_c(dcb + 6, 0, 0); + + if (!file->type) return invalidRefNum; + + unsigned data_buffer = get_memory16_c(dcb + 2, 0); + unsigned request_count = get_memory16_c(dcb + 4, 0); + + if (!data_buffer) return badBufferAddress; + + unsigned count = 0; + unsigned mask = file->newline_mask; + unsigned nl = file->newline_char; + + if (file->type == file_directory) { + unsigned mark = file->mark; + if (mark >= file->eof) return eofEncountered; + /* support newline mode ... */ + + if (mark + request_count > file->eof) + request_count = file->eof - mark; + + + for (count = 0; count < request_count; ++count) { + byte b = file->directory_buffer[mark++]; + set_memory_c(data_buffer + count, b, 0); + if (mask && (b & mask) == nl) break; + } + file->mark = mark; + set_memory16_c(dcb + 6, count, 0); + return 0; + } + + if (file->type != file_regular) return invalidAccess; + + byte *data = host_gc_malloc(request_count); + if (!data) return drvrIOError; + +#if _WIN32 + LARGE_INTEGER li; + DWORD rv; + li.QuadPart = file->mark; + if (!SetFilePointerEx(file->h, li, NULL, FILE_BEGIN)) + return host_map_win32_error(GetLastError()); + + if (!ReadFile(file->h, data, request_count, &rv, NULL)) + return host_map_win32_error(GetLastError()); +#else + int rv = pread(file->fd, data, request_count, file->mark); + if (rv < 0) return host_map_errno(errno); +#endif + + if (rv == 0) return eofEncountered; + count = rv; + + switch (file->translate) { + case translate_crlf: + host_lf_to_cr(data, count); + break; + case translate_merlin: + host_text_to_merlin(data, count); + break; + } + + + if (mask) { + for (int count = 0; count < rv; ) { + byte b = data[count++]; + if ((b & mask) == nl) break; + } + } + for (unsigned i = 0; i < count; ++i) + set_memory_c(data_buffer + i, data[i], 0); + + file->mark += count; + set_memory16_c(dcb + 6, count, 0); + return 0; +} + + + +static int mli_get_buf(unsigned dcb, struct file_entry *file) { + + if (!file->type) return invalidRefNum; + set_memory16_c(dcb + 2, file->buffer, 0); + return 0; +} + +static int mli_set_buf(unsigned dcb, struct file_entry *file) { + + unsigned buffer = get_memory16_c(dcb + 2, 0); + if (!file->type) return invalidRefNum; + //if (!buffer) return badBufferAddress; + if (buffer & 0xff) return badBufferAddress; + + file->buffer = buffer; + return 0; +} + +static int mli_get_eof(unsigned dcb, struct file_entry *file) { + + word16 terr = 0; + + switch (file->type) { + default: + return invalidRefNum; + + case file_directory: + break; + + case file_regular: + terr = file_eof(file); + if (terr) return terr; + break; + } + + set_memory24_c(dcb + 2, file->eof, 0); + return 0; +} + + +static int mli_set_eof(unsigned dcb, struct file_entry *file) { + + off_t eof = get_memory24_c(dcb + 2, 0); +#if _WIN32 + LARGE_INTEGER tmp; +#endif + + switch (file->type) { + default: + return invalidRefNum; + + case file_directory: + return invalidAccess; + break; + + case file_regular: +#if _WIN32 + tmp.QuadPart = eof; + if (!SetFilePointerEx(file->h, tmp, NULL, FILE_BEGIN)) + return host_map_win32_error(GetLastError()); + if (!SetEndOfFile(file->h)) + return host_map_win32_error(GetLastError()); +#else + if (ftruncate(file->fd, eof) < 0) + return host_map_errno(errno); +#endif + break; + } + return 0; +} + +static int mli_get_mark(unsigned dcb, struct file_entry *file) { + + off_t position = 0; + + switch (file->type) { + default: + return invalidRefNum; + + case file_directory: + case file_regular: + position = file->mark; + break; + } + if (position > 0xffffff) return outOfRange; + set_memory24_c(dcb + 2, position, 0); + return 0; + +} + +static int mli_set_mark(unsigned dcb, struct file_entry *file) { + + word16 terr = 0; + + word32 position = get_memory24_c(dcb + 2, 0); + + switch (file->type) { + default: + return invalidRefNum; + case file_directory: + break; + case file_regular: + terr = file_eof(file); + if (terr) return terr; + break; + } + + if (position > file->eof) return outOfRange; + file->mark = position; + + return 0; +} + +static int mli_newline(unsigned dcb, struct file_entry *file) { + if (!file->type) return invalidRefNum; + + file->newline_mask = get_memory_c(dcb + 2, 0); + file->newline_char = get_memory_c(dcb + 3, 0); + return 0; +} + + + +static int mli_close(unsigned dcb, struct file_entry *file) { + + if (!file) { + unsigned level = get_memory_c(LEVEL, 0); + unsigned i; + for (i = 0; i < MAX_FILES; ++i) { + file = &files[i]; + if (!file->type) continue; + if (file->level < level) continue; + file_close(file); + } + return -1; /* pass to prodos mli */ + } + + return file_close(file); +} + + +static int mli_flush(unsigned dcb, struct file_entry *file) { + + if (!file) { + unsigned level = get_memory_c(LEVEL, 0); + unsigned i; + for (i = 0; i < MAX_FILES; ++i) { + file = &files[i]; + if (!file->type) continue; + if (file->level < level) continue; + + file_flush(file); + } + return -1; /* pass to prodos mli */ + } + return file_flush(file); +} + + +/* + * quit + * close all open files. + */ +static int mli_quit(unsigned dcb) { + unsigned i; + for (i = 0; i < MAX_FILES; ++i) { + struct file_entry *file = &files[i]; + if (!file->type) continue; + +#if _WIN32 + if (file->h != INVALID_HANDLE_VALUE) CloseHandle(file->h); +#else + if (file->fd >= 0) close(file->fd); +#endif + + if (file->directory_buffer) free(file->directory_buffer); + memset(file, 0, sizeof(*file)); + +#if _WIN32 + file->h = INVALID_HANDLE_VALUE; +#else + file->fd = -1; +#endif + + + } + /* need a better way to know... */ + /* host_shutdown(); */ + return -1; +} + + + + +static int mli_open(unsigned dcb, const char *name, const char *path) { + + int refnum = 0; + + struct file_entry *file = NULL; + for (unsigned i = 0; i < MAX_FILES; ++i) { + file = &files[i]; + if (!file->type) { + refnum = MIN_FILE + i; + break; + } + } + if (!refnum) return tooManyFilesOpen; + + unsigned buffer = get_memory_c(dcb + 3, 0); + //if (buffer == 0) return badBufferAddress; + if (buffer & 0xff) return badBufferAddress; + + struct file_info fi; + word16 terr = host_get_file_info(path, &fi); + if (terr) return terr; + + + if (fi.storage_type == 0x0f || fi.storage_type == 0x0d) { + unsigned blocks; + void *tmp; + tmp = create_directory_file(name, path, &terr, &blocks); + if (!tmp) return terr; + file->type = file_directory; + file->directory_buffer = tmp; + file->eof = blocks * 512; + } else { + terr = file_open(path, file); + if (terr) return terr; + + file->type = file_regular; + + if (g_cfg_host_crlf) { + if (fi.file_type == 0x04 || fi.file_type == 0xb0) + file->translate = translate_crlf; + } + + if (g_cfg_host_merlin && fi.file_type == 0x04) { + int n = strlen(path); + if (n >= 3 && path[n-1] == 'S' && path[n-2] == '.') + file->translate = translate_merlin; + } + } + + file->level = get_memory_c(LEVEL, 0); + file->buffer = buffer; + file->mark = 0; + set_memory_c(dcb + 5, refnum, 0); + return 0; +} + + +static int mli_get_prefix(unsigned dcb) { + if (!saved_prefix) return -1; + unsigned buffer = get_memory16_c(dcb + 1, 0); + if (!buffer) return badBufferAddress; + + set_pstr(buffer, saved_prefix); + return 0; +} + +/* + * name is relative the the /HOST device. + * path is the path on the native fs. + */ +static int mli_set_prefix(unsigned dcb, char *name, char *path) { + /* + * IF path is null, tail patch if we own the prefix. + * otherwise, handle it or forward to mli. + */ + if (!path) { + return saved_prefix ? -2 : -1; + } + + unsigned type; + word16 terr; + + type = host_storage_type(path, &terr); + switch(type) { + case 0x0f: + case 0x0d: + break; + case 0: return terr; + default: return badStoreType; + } + + /* /HOST/ was previously stripped... add it back. */ + name = host_gc_append_path("/HOST", name); + + int l = strlen(name); + /* trim trailing / */ + while (l > 1 && name[l-1] == '/') --l; + name[l] = 0; + + if (l > 63) return badPathSyntax; + + + if (saved_prefix) + free(saved_prefix); + saved_prefix = strdup(name); + set_memory_c(PFIXPTR, 1, 0); + return 0; +} + +static int mli_online(unsigned dcb) { + /* not yet ... */ + unsigned unit = get_memory_c(dcb + 1, 0); + unsigned buffer = get_memory16_c(dcb + 2, 0); + if (unit == saved_unit) { + if (!buffer) return badBufferAddress; + /* slot 2, drive 1 ... why not*/ + set_memory_c(buffer++, saved_unit | 0x04, 0); + set_memory_c(buffer++, 'H', 0); + set_memory_c(buffer++, 'O', 0); + set_memory_c(buffer++, 'S', 0); + set_memory_c(buffer++, 'T', 0); + return 0; + } + if (unit == 0) return -2; + return -1; +} + +static int mli_online_tail(unsigned dcb) { + unsigned buffer = get_memory16_c(dcb + 2, 0); + + host_hexdump(buffer, 256); + + /* if there was an error with the device + there will be an error code instead of a name (length = 0) + */ + + for (unsigned i = 0; i < 16; ++i, buffer += 16) { + unsigned x = get_memory_c(buffer, 0); + if (x == 0 || ((x & 0xf0) == saved_unit)) { + set_memory_c(buffer++, saved_unit | 0x04, 0); + set_memory_c(buffer++, 'H', 0); + set_memory_c(buffer++, 'O', 0); + set_memory_c(buffer++, 'S', 0); + set_memory_c(buffer++, 'T', 0); + break; + } + } + + return 0; +} + +static int mli_rw_block(unsigned dcb) { + unsigned unit = get_memory_c(dcb + 1, 0); + unsigned buffer = get_memory16_c(dcb + 2, 0); + + if (unit == saved_unit) { + if (!buffer) return badBufferAddress; + return notBlockDev; /* network error? */ + } + return -1; +} + + +static unsigned call_pcount(unsigned call) { + switch (call) { + case CREATE: return 7; + case DESTROY: return 1; + case RENAME: return 2; + case SET_FILE_INFO: return 7; + case GET_FILE_INFO: return 10; + case ONLINE: return 2; + case SET_PREFIX: return 1; + case GET_PREFIX: return 1; + case OPEN: return 3; + case NEWLINE: return 3; + case READ: return 4; + case WRITE: return 4; + case CLOSE: return 1; + case FLUSH: return 1; + case SET_MARK: return 2; + case GET_MARK: return 2; + case SET_EOF: return 2; + case GET_EOF: return 2; + case SET_BUF: return 2; + case GET_BUF: return 2; + + default: return 0; + } +} + + +static const char *call_name(unsigned call) { + + switch (call) { + case CREATE: return "CREATE"; + case DESTROY: return "DESTROY"; + case RENAME: return "RENAME"; + case SET_FILE_INFO: return "SET_FILE_INFO"; + case GET_FILE_INFO: return "GET_FILE_INFO"; + case ONLINE: return "ONLINE"; + case SET_PREFIX: return "SET_PREFIX"; + case GET_PREFIX: return "GET_PREFIX"; + case OPEN: return "OPEN"; + case NEWLINE: return "NEWLINE"; + case READ: return "READ"; + case WRITE: return "WRITE"; + case CLOSE: return "CLOSE"; + case FLUSH: return "FLUSH"; + case SET_MARK: return "SET_MARK"; + case GET_MARK: return "GET_MARK"; + case SET_EOF: return "SET_EOF"; + case GET_EOF: return "GET_EOF"; + case SET_BUF: return "SET_BUF"; + case GET_BUF: return "GET_BUF"; + case ATINIT: return "ATINIT"; + + default: return ""; + } +} + + +#ifdef __CYGWIN__ + +#include + +static char *expand_path(const char *path, word32 *error) { + + char buffer[PATH_MAX]; + if (!path) return path; + + ssize_t ok = cygwin_conv_path(CCP_POSIX_TO_WIN_A, path, buffer, sizeof(buffer)); + if (ok < 0) { + if (error) *error = fstError; + return NULL; + } + return host_gc_strdup(buffer); +} + + +#else +#define expand_path(x, y) (x) +#endif + + +/* + * mli head patch. called before ProDOS mli. + * this call will either + * 1. handle and return + * 2. redirect to the real mli + * 3. call real mli, then call host_mli_tail after + */ +void host_mli_head() { + + word32 rts = get_memory16_c(engine.stack+1, 0); + saved_call = get_memory_c(rts + 1, 0); + saved_dcb = get_memory16_c(rts + 2, 0); + saved_p = engine.psr; + word16 terr = 0; + + /* do pcount / path stuff here */ + char *path1 = NULL; + char *path2 = NULL; + char *path3 = NULL; + char *path4 = NULL; + + struct file_entry *file = NULL; + + unsigned pcount = get_memory_c(saved_dcb, 0); + unsigned xpcount = call_pcount(saved_call); + int acc = 0; + int refnum = 0; + + if (xpcount && xpcount != pcount) { + acc = invalidPcount; + goto cleanup; + } + + switch(saved_call) { + case CREATE: + case DESTROY: + case SET_FILE_INFO: + case GET_FILE_INFO: + case OPEN: + path1 = is_host_path(get_memory16_c(saved_dcb + 1, 0)); + if (!path1) goto prodos_mli; + path3 = host_gc_append_path(host_root, path1); + path3 = expand_path(path3, &terr); + break; + + case RENAME: + path1 = is_host_path(get_memory16_c(saved_dcb + 1,0)); + path2 = is_host_path(get_memory16_c(saved_dcb + 3,0)); + if (!path1 && !path2) goto prodos_mli; + if (path1) path3 = host_gc_append_path(host_root, path1); + if (path2) path4 = host_gc_append_path(host_root, path2); + path3 = expand_path(path3, &terr); + path4 = expand_path(path4, &terr); + break; + + case SET_PREFIX: + path1 = is_host_path(get_memory16_c(saved_dcb + 1,0)); + if (!path1 && !saved_prefix) goto prodos_mli; + if (path1) path3 = host_gc_append_path(host_root, path1); + path3 = expand_path(path3, &terr); + break; + + case GET_PREFIX: + if (!saved_prefix) goto prodos_mli; + break; + + /* refnum based */ + case NEWLINE: + case READ: + case WRITE: + case SET_MARK: + case GET_MARK: + case SET_EOF: + case GET_EOF: + case SET_BUF: + case GET_BUF: + refnum = get_memory_c(saved_dcb + 1, 0); + + if (refnum >= MIN_FILE && refnum < MAX_FILE) { + file = &files[refnum - MIN_FILE]; + } else { + goto prodos_mli; + } + break; + + case CLOSE: + case FLUSH: + /* special case for refnum == 0 */ + refnum = get_memory_c(saved_dcb + 1, 0); + + if (refnum >= MIN_FILE && refnum < MAX_FILE) { + file = &files[refnum - MIN_FILE]; + } else if (refnum) { + goto prodos_mli; + } + + break; + + } + + fprintf(stderr, "MLI: %02x %s", saved_call, call_name(saved_call)); + if (path1) fprintf(stderr, " - %s", path1); + if (path2) fprintf(stderr, " - %s", path2); + + switch (saved_call) { + default: + engine.kpc = saved_mli_address; + return; + + case ATINIT: + acc = mli_atinit(saved_dcb); + break; + + case CREATE: + acc = mli_create(saved_dcb, path3); + break; + + case DESTROY: + acc = mli_destroy(saved_dcb, path3); + break; + + case SET_FILE_INFO: + acc = mli_set_file_info(saved_dcb, path3); + break; + + case GET_FILE_INFO: + acc = mli_get_file_info(saved_dcb, path3); + break; + + case OPEN: + acc = mli_open(saved_dcb, path1, path3); + break; + + case RENAME: + acc = mli_rename(saved_dcb, path3, path4); + break; + + case SET_PREFIX: + acc = mli_set_prefix(saved_dcb, path1, path3); + break; + + case GET_PREFIX: + acc = mli_get_prefix(saved_dcb); + break; + + case ONLINE: + acc = mli_online(saved_dcb); + break; + + case NEWLINE: + acc = mli_newline(saved_dcb, file); + break; + + case READ: + acc = mli_read(saved_dcb, file); + break; + + case WRITE: + acc = mli_write(saved_dcb, file); + break; + + case SET_MARK: + acc = mli_set_mark(saved_dcb, file); + break; + + case GET_MARK: + acc = mli_get_mark(saved_dcb, file); + break; + + case SET_EOF: + acc = mli_set_eof(saved_dcb, file); + break; + + case GET_EOF: + acc = mli_get_eof(saved_dcb, file); + break; + + case SET_BUF: + acc = mli_set_buf(saved_dcb, file); + break; + + case GET_BUF: + acc = mli_get_buf(saved_dcb, file); + break; + + case CLOSE: + acc = mli_close(saved_dcb, file); + break; + + case FLUSH: + acc = mli_flush(saved_dcb, file); + break; + + case WRITE_BLOCK: + case READ_BLOCK: + acc = mli_rw_block(saved_dcb); + break; + + + case QUIT: + acc = mli_quit(saved_dcb); + break; + + } + fputs("\n", stderr); + fflush(stderr); + host_gc_free(); + + + if (acc == -2) { + /* tail call needed */ + /* + jsr xxxx + dc.b xx + dc.w xxxx + wdm .. + rts + */ + SEI(); + set_memory_c(saved_patch_address + 0, saved_call, 0); + set_memory16_c(saved_patch_address + 1, saved_dcb, 0); + set_memory16_c(engine.stack+1, rts + 3, 0); + return; + } + if (acc < 0) { +prodos_mli: + host_gc_free(); + /* pass to normal dispatcher */ + engine.kpc = saved_mli_address; + return; + } +cleanup: + /* fixup */ + acc &= 0xff; + + if (acc) fprintf(stderr, " %02x %s\n", acc, host_error_name(acc)); + if (acc == 0 && saved_call != ATINIT) { + set_memory_c(DEVNUM, saved_unit, 0); + } + engine.acc &= 0xff00; + engine.acc |= acc; + if (acc) { + SEC(); + CLZ(); + } else { + CLC(); + SEZ(); + } + engine.kpc = rts + 4; + engine.stack += 2; + return; + +} + +void host_mli_tail() { + + if (!(engine.psr & C)) { + + switch(saved_call) { + case SET_PREFIX: + free(saved_prefix); + saved_prefix = NULL; + break; + case ONLINE: + mli_online_tail(saved_dcb); + break; + } + } + + // clean up I bit (set in head) + engine.psr &= ~I; + engine.psr |= (saved_p & I); + host_gc_free(); +} \ No newline at end of file diff --git a/src/icongs.h b/src/icongs.h new file mode 100644 index 0000000..ceb7622 --- /dev/null +++ b/src/icongs.h @@ -0,0 +1,2078 @@ +/* + GSport - an Apple //gs Emulator + Copyright (C) 2010 - 2019 by GSport contributors + Copyright (C) 2016 - 2018 Dagen Brock + + Based on the KEGS emulator written by and Copyright (C) 2003 Kent Dickey + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 2 of the License, or (at your + option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +/* + * This is the icon data in raw RGBA format. + * + * This data is generated using 'assets/dump_icon.py' script. + * To enable the icon, add compiler flag "-DHAVE_ICON" (OSX SDL2 Only, for now.) + */ +unsigned int icon_pixels[256*256] = { +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000098ff, 0x000098ff, +0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000097ff, 0x000096ff, 0x000097ff, 0x000097ff, 0x000096ff, 0x000097ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000098ff, 0x000095ff, 0x000095ff, 0x000095ff, 0x060697ff, 0x13139aff, 0x101099ff, 0x101099ff, 0x111199ff, 0x0e0e99ff, 0x090998ff, 0x080898ff, 0x090998ff, +0x090998ff, 0x090998ff, 0x090998ff, 0x090998ff, 0x090998ff, 0x090998ff, 0x090998ff, 0x090998ff, 0x090998ff, 0x0a0a98ff, 0x040498ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, +0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000098ff, 0x000096ff, 0x000096ff, 0x000096ff, 0x000094ff, 0x040498ff, 0x1d1d9eff, 0x19199dff, 0x18189aff, 0x6c6cbfff, 0xb4b4d9ff, 0xa7a7d4ff, 0xa7a7d4ff, 0xacacdaff, 0x9696c4ff, 0x656592ff, 0x5d5d89ff, 0x60608cff, +0x5f5f8cff, 0x5f5f8cff, 0x5f5f8cff, 0x5f5f8cff, 0x5f5f8cff, 0x5f5f8cff, 0x5f5f8cff, 0x5f5f8cff, 0x5f5f8cff, 0x67678aff, 0x42428fff, 0x111197ff, 0x0d0d97ff, 0x0f0f97ff, 0x0f0f97ff, 0x0f0f97ff, 0x0f0f97ff, 0x0f0f97ff, 0x0f0f97ff, 0x0f0f97ff, 0x0f0f97ff, 0x0f0f97ff, 0x0f0f97ff, 0x0f0f97ff, 0x0e0e97ff, 0x111197ff, 0x030398ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x00009bff, 0x00009dff, 0x00009aff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000098ff, 0x000095ff, 0x000092ff, 0x000096ff, 0x1a1a9eff, 0x20209dff, 0x1e1e9cff, 0x1b1b9cff, 0x5656b6ff, 0xbabadcff, 0xb3b3d9ff, 0xadadd7ff, 0xe5e5eaff, 0xfffff7ff, 0xfffff5ff, 0xfffff4ff, 0xfffffcff, 0xe7e7dbff, 0x9c9c8eff, 0x8f8f81ff, 0x939386ff, +0x939385ff, 0x939385ff, 0x939385ff, 0x939385ff, 0x939385ff, 0x939385ff, 0x939385ff, 0x939385ff, 0x939385ff, 0x979785ff, 0x858587ff, 0x65658bff, 0x65658bff, 0x66668bff, 0x66668bff, 0x66668bff, 0x66668bff, 0x66668bff, 0x66668bff, 0x66668bff, 0x66668bff, 0x66668bff, 0x66668bff, 0x66668bff, 0x66668bff, 0x6f6f89ff, 0x353591ff, 0x0e0e98ff, 0x141496ff, 0x141496ff, 0x141496ff, 0x141496ff, +0x141496ff, 0x141496ff, 0x141496ff, 0x141496ff, 0x141496ff, 0x161698ff, 0x0c0c90ff, 0x040489ff, 0x000095ff, 0x00009bff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, +0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000096ff, 0x000092ff, 0x000092ff, 0x000092ff, 0x000092ff, 0x1a1aa0ff, 0x2e2ea5ff, 0x4545aeff, 0x9f9fcfff, 0xb1b1cbff, 0xaeaecbff, 0xb6b6d9ff, 0xd7d7e6ff, 0xfffff5ff, 0xfffff4ff, 0xfffff4ff, 0xf4f4f0ff, 0xececedff, 0xececedff, 0xececedff, 0xf4f4f4ff, 0xd6d6d6ff, 0x8e8e8fff, 0x838384ff, 0x878788ff, +0x878788ff, 0x878788ff, 0x878788ff, 0x878788ff, 0x878788ff, 0x878788ff, 0x878788ff, 0x878788ff, 0x878788ff, 0x868688ff, 0x8b8b87ff, 0x919186ff, 0x929286ff, 0x919186ff, 0x919186ff, 0x919186ff, 0x919186ff, 0x919186ff, 0x919186ff, 0x919186ff, 0x919186ff, 0x919186ff, 0x919186ff, 0x919186ff, 0x919186ff, 0x969685ff, 0x7d7d88ff, 0x68688bff, 0x6d6d8aff, 0x6d6d8aff, 0x6d6d8aff, 0x6d6d8aff, +0x6d6d8aff, 0x6d6d8aff, 0x6d6d8aff, 0x6d6d8aff, 0x6c6c8aff, 0x727290ff, 0x555572ff, 0x3d3d57ff, 0x262682ff, 0x17179aff, 0x1a1a95ff, 0x1a1a96ff, 0x1a1a96ff, 0x1a1a96ff, 0x1a1a96ff, 0x1a1a96ff, 0x1a1a96ff, 0x1a1a96ff, 0x1a1a96ff, 0x1a1a96ff, 0x1a1a96ff, 0x1b1b96ff, 0x171796ff, 0x010198ff, 0x00009aff, 0x00009aff, 0x00009aff, 0x00009aff, 0x00009aff, 0x00009aff, 0x00009aff, 0x00009aff, +0x00009aff, 0x00009aff, 0x00009aff, 0x00009aff, 0x00009aff, 0x00009aff, 0x000099ff, 0x000099ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000098ff, 0x000094ff, 0x000090ff, 0x0c0c9bff, 0x3e3eacff, 0x3838a9ff, 0x3636a9ff, 0x3b3baaff, 0x9898d0ff, 0xd1d1e4ff, 0xd1d1e3ff, 0xf4f4eeff, 0xf9f9eeff, 0xf7f7edff, 0xfdfdf3ff, 0xf6f6f1ff, 0xedededff, 0xedededff, 0xedededff, 0xedededff, 0xeeeeeeff, 0xeeeeeeff, 0xedededff, 0xf5f5f5ff, 0xd7d7d7ff, 0x8f8f8fff, 0x838383ff, 0x888888ff, +0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x878788ff, 0x878788ff, 0x878788ff, 0x878788ff, 0x878788ff, 0x878788ff, 0x878788ff, 0x878788ff, 0x878788ff, 0x878788ff, 0x878788ff, 0x878788ff, 0x878788ff, 0x878788ff, 0x878788ff, 0x878788ff, 0x8c8c87ff, 0x919186ff, 0x909086ff, 0x909086ff, 0x909086ff, 0x909086ff, +0x909086ff, 0x909086ff, 0x909086ff, 0x909086ff, 0x909086ff, 0x929289ff, 0x89897eff, 0x818175ff, 0x787883ff, 0x71718bff, 0x737389ff, 0x737389ff, 0x737389ff, 0x737389ff, 0x737389ff, 0x737389ff, 0x737389ff, 0x737389ff, 0x737389ff, 0x737389ff, 0x737389ff, 0x767689ff, 0x6b6b8aff, 0x313192ff, 0x1c1c95ff, 0x202095ff, 0x202095ff, 0x202095ff, 0x202095ff, 0x202095ff, 0x202095ff, 0x202095ff, +0x202095ff, 0x202095ff, 0x202095ff, 0x202095ff, 0x1f1f95ff, 0x232394ff, 0x131396ff, 0x00009aff, 0x00009aff, 0x00009aff, 0x00009aff, 0x00009aff, 0x00009aff, 0x00009aff, 0x00009aff, 0x00009aff, 0x00009aff, 0x00009bff, 0x00009cff, 0x00009cff, 0x00009dff, 0x00009aff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, +0x000098ff, 0x000098ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000097ff, 0x000091ff, 0x030395ff, 0x3535a6ff, 0x3838a9ff, 0x7979c4ff, 0xdddde9ff, 0xd6d6e5ff, 0xd5d5e5ff, 0xd4d4e4ff, 0xeeeeeeff, 0xfdfdf3ff, 0xf7f7f1ff, 0xf0f0eeff, 0xeeeeefff, 0xeeeeeeff, 0xedededff, 0xedededff, 0xededeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xedededff, 0xf5f5f5ff, 0xd7d7d7ff, 0x8f8f8fff, 0x838383ff, 0x888888ff, +0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x878788ff, 0x878788ff, 0x878788ff, 0x878788ff, 0x878788ff, 0x878788ff, +0x878788ff, 0x878788ff, 0x878788ff, 0x878788ff, 0x878788ff, 0x878787ff, 0x89898aff, 0x8b8b8cff, 0x8d8d88ff, 0x8f8f86ff, 0x8f8f86ff, 0x8f8f86ff, 0x8f8f86ff, 0x8f8f86ff, 0x8f8f86ff, 0x8f8f86ff, 0x8f8f86ff, 0x8f8f86ff, 0x8f8f86ff, 0x8f8f86ff, 0x8e8e86ff, 0x8f8f86ff, 0x8d8d87ff, 0x7e7e89ff, 0x787888ff, 0x7a7a88ff, 0x7a7a88ff, 0x7b7b89ff, 0x7d7d8cff, 0x7b7b8aff, 0x7b7b8aff, 0x7d7d8cff, +0x7d7d8cff, 0x7d7d8cff, 0x7d7d8cff, 0x7d7d8cff, 0x7c7c8cff, 0x818188ff, 0x61618cff, 0x292994ff, 0x232394ff, 0x252594ff, 0x252594ff, 0x252594ff, 0x252594ff, 0x252594ff, 0x272796ff, 0x292997ff, 0x292997ff, 0x262694ff, 0x1c1c8dff, 0x1b1b8bff, 0x202089ff, 0x0c0c93ff, 0x00009eff, 0x00009dff, 0x00009dff, 0x00009dff, 0x00009dff, 0x00009dff, 0x00009dff, 0x00009dff, 0x00009dff, 0x00009dff, +0x00009dff, 0x00009aff, 0x000098ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000097ff, 0x0d0d9cff, 0x3b3baeff, 0x6c6cb9ff, 0xc3c3d1ff, 0xe1e1e8ff, 0xebebedff, 0xf9f9f2ff, 0xf7f7f1ff, 0xf7f7f1ff, 0xf6f6f1ff, 0xf0f0eeff, 0xedededff, 0xedededff, 0xedededff, 0xedededff, 0xedededff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xedededff, 0xf5f5f5ff, 0xd7d7d7ff, 0x8f8f8fff, 0x838383ff, 0x888888ff, +0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, +0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x878787ff, 0x878787ff, 0x878788ff, 0x878788ff, 0x878788ff, 0x878788ff, 0x878788ff, 0x878788ff, 0x878788ff, 0x878788ff, 0x878788ff, 0x878788ff, 0x878788ff, 0x878788ff, 0x878788ff, 0x878788ff, 0x888888ff, 0x8c8c87ff, 0x8d8d86ff, 0x8d8d86ff, 0x8f8f88ff, 0x898982ff, 0x7d7d76ff, 0x878780ff, 0x878781ff, 0x7e7e78ff, +0x83837dff, 0x83837dff, 0x83837dff, 0x82827bff, 0x84847eff, 0x909088ff, 0x8e8e8bff, 0x84848cff, 0x83838cff, 0x84848cff, 0x84848cff, 0x84848cff, 0x84848cff, 0x83838bff, 0x7a7a81ff, 0x75757cff, 0x77777fff, 0x717179ff, 0x626269ff, 0x5f5f67ff, 0x666664ff, 0x454576ff, 0x1b1b8cff, 0x202089ff, 0x202089ff, 0x202089ff, 0x202089ff, 0x202089ff, 0x202089ff, 0x202089ff, 0x202088ff, 0x202089ff, +0x242486ff, 0x0e0e91ff, 0x00009dff, 0x000098ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000094ff, 0x2d2da6ff, 0xc2c2dfff, 0xe5e5dfff, 0xdcdcd7ff, 0xf5f5efff, 0xf2f2efff, 0xedededff, 0xedededff, 0xedededff, 0xedededff, 0xedededff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xedededff, 0xf5f5f5ff, 0xd7d7d7ff, 0x8f8f8fff, 0x838383ff, 0x888888ff, +0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, +0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x878788ff, 0x878788ff, 0x878788ff, 0x878787ff, 0x89898aff, 0x808080ff, 0x6f6f6fff, 0x808080ff, 0x838384ff, 0x696969ff, +0x636363ff, 0x646465ff, 0x646465ff, 0x646464ff, 0x686868ff, 0x787878ff, 0x7d7d7cff, 0x7f7f7bff, 0x80807bff, 0x80807bff, 0x80807bff, 0x80807bff, 0x80807bff, 0x7f7f7aff, 0x6f6f6aff, 0x676762ff, 0x696964ff, 0x696964ff, 0x686863ff, 0x696964ff, 0x696963ff, 0x686864ff, 0x646465ff, 0x656564ff, 0x656564ff, 0x656564ff, 0x656564ff, 0x656564ff, 0x656564ff, 0x676766ff, 0x696968ff, 0x696968ff, +0x6f6f65ff, 0x515172ff, 0x101091ff, 0x00009aff, 0x000098ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000094ff, 0x2f2fa7ff, 0xc4c4dbff, 0xdbdbd1ff, 0xd3d3d3ff, 0xececedff, 0xeeeeeeff, 0xededeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xedededff, 0xf5f5f5ff, 0xd7d7d7ff, 0x8f8f8fff, 0x838383ff, 0x888888ff, +0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, +0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x878787ff, 0x888888ff, 0x898989ff, 0x818181ff, 0x747474ff, 0x797979ff, 0x6c6c6cff, +0x616161ff, 0x656565ff, 0x656565ff, 0x656565ff, 0x646464ff, 0x636363ff, 0x636363ff, 0x636363ff, 0x636363ff, 0x636363ff, 0x636363ff, 0x636363ff, 0x636363ff, 0x626263ff, 0x646464ff, 0x646465ff, 0x656565ff, 0x656565ff, 0x656565ff, 0x656566ff, 0x656566ff, 0x666665ff, 0x686864ff, 0x676764ff, 0x676764ff, 0x676764ff, 0x676764ff, 0x676764ff, 0x686865ff, 0x656562ff, 0x5b5b58ff, 0x595956ff, +0x575754ff, 0x6e6e54ff, 0x343481ff, 0x0000a2ff, 0x000098ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000094ff, 0x2d2da6ff, 0xc1c1daff, 0xd8d8d0ff, 0xd3d3d3ff, 0xedededff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xedededff, 0xf5f5f5ff, 0xd7d7d7ff, 0x8f8f8fff, 0x838383ff, 0x888888ff, +0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, +0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x878787ff, 0x878787ff, 0x878787ff, 0x8a8a8aff, 0x7f7f7fff, 0x717171ff, 0x787878ff, 0x6c6c6cff, +0x626262ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x656565ff, 0x656565ff, 0x656565ff, 0x656565ff, 0x656565ff, 0x656565ff, 0x656565ff, 0x656565ff, 0x656565ff, 0x656565ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x656566ff, 0x656566ff, 0x656566ff, 0x656566ff, 0x656566ff, 0x656566ff, 0x656565ff, 0x686868ff, 0x5d5d5eff, 0x444444ff, 0x3d3d3dff, +0x3a3a3bff, 0x58584dff, 0x585873ff, 0x0d0d92ff, 0x00009bff, 0x000098ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000094ff, 0x2e2ea7ff, 0xc2c2daff, 0xd8d8d1ff, 0xd3d3d3ff, 0xedededff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xedededff, 0xf5f5f5ff, 0xd7d7d7ff, 0x8f8f8fff, 0x838383ff, 0x888888ff, +0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x878787ff, 0x878787ff, 0x878787ff, 0x878787ff, 0x878787ff, 0x878787ff, 0x878787ff, 0x878787ff, 0x878787ff, 0x878787ff, 0x878787ff, 0x878787ff, 0x878787ff, 0x878787ff, 0x878787ff, 0x878787ff, 0x878787ff, 0x878787ff, 0x878787ff, 0x878787ff, 0x878787ff, 0x878787ff, 0x888888ff, 0x888888ff, 0x888888ff, +0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x878787ff, 0x878787ff, 0x878787ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x898989ff, 0x8e8e8eff, 0x858585ff, 0x797979ff, 0x6e6e6eff, +0x626262ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x656565ff, 0x686868ff, 0x616161ff, 0x474747ff, 0x424242ff, +0x414141ff, 0x464648ff, 0x727251ff, 0x373780ff, 0x00009fff, 0x000098ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000094ff, 0x2e2ea7ff, 0xc2c2daff, 0xd8d8d1ff, 0xd3d3d3ff, 0xedededff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xedededff, 0xf5f5f5ff, 0xd7d7d7ff, 0x8f8f8fff, 0x838383ff, 0x888888ff, +0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x878787ff, 0x888888ff, 0x898989ff, 0x8a8a8aff, 0x8a8a8aff, 0x8a8a8aff, 0x8a8a8aff, 0x8a8a8aff, 0x8a8a8aff, 0x8a8a8aff, 0x8a8a8aff, 0x8a8a8aff, 0x8a8a8aff, 0x8a8a8aff, 0x898989ff, 0x898989ff, 0x898989ff, 0x898989ff, 0x898989ff, 0x898989ff, 0x898989ff, 0x898989ff, 0x888888ff, 0x878787ff, 0x878787ff, 0x878787ff, +0x878787ff, 0x878787ff, 0x878787ff, 0x878787ff, 0x878787ff, 0x878787ff, 0x878787ff, 0x878787ff, 0x878787ff, 0x878787ff, 0x878787ff, 0x878787ff, 0x878787ff, 0x878787ff, 0x878787ff, 0x878787ff, 0x878787ff, 0x878787ff, 0x878787ff, 0x878787ff, 0x878787ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x898989ff, 0x898989ff, 0x8b8b8bff, 0x818181ff, 0x757575ff, 0x6a6a6aff, 0x5e5e5eff, 0x626262ff, +0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x656565ff, 0x666666ff, 0x646464ff, 0x515151ff, 0x424242ff, 0x424242ff, +0x444444ff, 0x3c3c3dff, 0x5e5e49ff, 0x323287ff, 0x00009fff, 0x000098ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000094ff, 0x2e2ea7ff, 0xc2c2daff, 0xd8d8d1ff, 0xd3d3d3ff, 0xedededff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xedededff, 0xf5f5f5ff, 0xd7d7d7ff, 0x8f8f8fff, 0x838383ff, 0x888888ff, +0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x878787ff, 0x888888ff, 0x898989ff, 0x878787ff, 0x878787ff, 0x878787ff, 0x878787ff, 0x878787ff, 0x878787ff, 0x878787ff, 0x878787ff, 0x878787ff, 0x878787ff, 0x878787ff, 0x878787ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x8b8b8bff, 0x8b8b8bff, 0x8b8b8bff, 0x8b8b8bff, +0x8b8b8bff, 0x8b8b8bff, 0x8b8b8bff, 0x8b8b8bff, 0x8b8b8bff, 0x8b8b8bff, 0x8b8b8bff, 0x898989ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x878787ff, 0x878787ff, 0x898989ff, 0x838383ff, 0x737373ff, 0x717171ff, 0x6c6c6cff, 0x616161ff, 0x636363ff, 0x666666ff, 0x666666ff, +0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x656565ff, 0x676767ff, 0x5f5f5fff, 0x464646ff, 0x404040ff, 0x444444ff, +0x444444ff, 0x3d3d3eff, 0x61614bff, 0x323287ff, 0x00009fff, 0x000098ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000094ff, 0x2d2da6ff, 0xc1c1daff, 0xd8d8d1ff, 0xd3d3d3ff, 0xedededff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xedededff, 0xf5f5f5ff, 0xd7d7d7ff, 0x8f8f8fff, 0x838383ff, 0x888888ff, +0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x878787ff, 0x888888ff, 0x8b8b8bff, 0x787878ff, 0x484848ff, 0x3d3d3dff, 0x404040ff, 0x404040ff, 0x404040ff, 0x404040ff, 0x404040ff, 0x404040ff, 0x404040ff, 0x404040ff, 0x3e3e3eff, 0x424242ff, 0x535353ff, 0x565656ff, 0x565656ff, 0x565656ff, 0x565656ff, 0x565656ff, 0x565656ff, 0x545454ff, 0x727272ff, 0x848484ff, 0x808080ff, 0x808080ff, +0x808080ff, 0x808080ff, 0x808080ff, 0x808080ff, 0x808080ff, 0x808080ff, 0x808080ff, 0x868686ff, 0x8a8a8aff, 0x898989ff, 0x898989ff, 0x898989ff, 0x898989ff, 0x898989ff, 0x898989ff, 0x898989ff, 0x898989ff, 0x898989ff, 0x898989ff, 0x898989ff, 0x898989ff, 0x797979ff, 0x737373ff, 0x808080ff, 0x757575ff, 0x656565ff, 0x636363ff, 0x636363ff, 0x666666ff, 0x666666ff, 0x656565ff, 0x656565ff, +0x656565ff, 0x656565ff, 0x656565ff, 0x656565ff, 0x656565ff, 0x656565ff, 0x656565ff, 0x656565ff, 0x656565ff, 0x656565ff, 0x656565ff, 0x656565ff, 0x656565ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x656565ff, 0x666666ff, 0x646464ff, 0x515151ff, 0x434343ff, 0x434343ff, 0x444444ff, +0x444444ff, 0x3d3d3eff, 0x61614bff, 0x323287ff, 0x00009fff, 0x000098ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000094ff, 0x2e2ea7ff, 0xc3c3dbff, 0xd8d8d1ff, 0xd3d3d3ff, 0xedededff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xedededff, 0xf5f5f5ff, 0xd7d7d7ff, 0x8f8f8fff, 0x838383ff, 0x888888ff, +0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x878787ff, 0x8a8a8aff, 0x848484ff, 0x535353ff, 0x1d1d1dff, 0x151515ff, 0x191919ff, 0x1a1a1aff, 0x1a1a1aff, 0x1a1a1aff, 0x1a1a1aff, 0x1a1a1aff, 0x1a1a1aff, 0x191919ff, 0x181818ff, 0x1a1a1aff, 0x222222ff, 0x232323ff, 0x232323ff, 0x232323ff, 0x232323ff, 0x222222ff, 0x212121ff, 0x1f1f1fff, 0x343434ff, 0x414141ff, 0x3d3d3dff, 0x3d3d3dff, +0x3d3d3dff, 0x3d3d3dff, 0x3d3d3dff, 0x3d3d3dff, 0x3d3d3dff, 0x3d3d3dff, 0x3b3b3bff, 0x555555ff, 0x696969ff, 0x656565ff, 0x656565ff, 0x656565ff, 0x656565ff, 0x666666ff, 0x666666ff, 0x656565ff, 0x666666ff, 0x676767ff, 0x676767ff, 0x676767ff, 0x676767ff, 0x5f5f5fff, 0x5c5c5cff, 0x626262ff, 0x5f5f5fff, 0x5c5c5cff, 0x626262ff, 0x696969ff, 0x696969ff, 0x696969ff, 0x696969ff, 0x696969ff, +0x696969ff, 0x696969ff, 0x696969ff, 0x696969ff, 0x696969ff, 0x696969ff, 0x696969ff, 0x696969ff, 0x696969ff, 0x696969ff, 0x696969ff, 0x696969ff, 0x676767ff, 0x656565ff, 0x656565ff, 0x656565ff, 0x656565ff, 0x656565ff, 0x656565ff, 0x656565ff, 0x656565ff, 0x656565ff, 0x656565ff, 0x656565ff, 0x656565ff, 0x666666ff, 0x676767ff, 0x5e5e5eff, 0x464646ff, 0x404040ff, 0x444444ff, 0x444444ff, +0x444444ff, 0x3d3d3eff, 0x61614bff, 0x323287ff, 0x00009fff, 0x000098ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000098ff, 0x000098ff, +0x000099ff, 0x000094ff, 0x2c2ca6ff, 0xbcbcd5ff, 0xd7d7cfff, 0xd3d3d4ff, 0xedededff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xedededff, 0xf5f5f5ff, 0xd7d7d7ff, 0x8f8f8fff, 0x838383ff, 0x888888ff, +0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x878787ff, 0x8a8a8aff, 0x808080ff, 0x474747ff, 0x202020ff, 0x212121ff, 0x212121ff, 0x1c1c1cff, 0x1d1d1dff, 0x1d1d1dff, 0x1d1d1dff, 0x1d1d1dff, 0x1d1d1dff, 0x222222ff, 0x252525ff, 0x232323ff, 0x212121ff, 0x212121ff, 0x212121ff, 0x212121ff, 0x202020ff, 0x242424ff, 0x292929ff, 0x272727ff, 0x333333ff, 0x3b3b3bff, 0x393939ff, 0x393939ff, +0x373737ff, 0x363636ff, 0x363636ff, 0x363636ff, 0x363636ff, 0x363636ff, 0x363636ff, 0x343434ff, 0x333333ff, 0x313131ff, 0x303030ff, 0x303030ff, 0x313131ff, 0x2e2e2eff, 0x2c2c2cff, 0x313131ff, 0x2e2e2eff, 0x292929ff, 0x292929ff, 0x292929ff, 0x292929ff, 0x2d2d2dff, 0x2e2e2eff, 0x2d2d2dff, 0x2e2e2eff, 0x2b2b2bff, 0x3c3c3cff, 0x595959ff, 0x5c5c5cff, 0x5b5b5bff, 0x5b5b5bff, 0x5b5b5bff, +0x5b5b5bff, 0x5b5b5bff, 0x5b5b5bff, 0x5b5b5bff, 0x5b5b5bff, 0x5b5b5bff, 0x5b5b5bff, 0x5b5b5bff, 0x5b5b5bff, 0x5b5b5bff, 0x5b5b5bff, 0x5a5a5aff, 0x656565ff, 0x6b6b6bff, 0x6a6a6aff, 0x6a6a6aff, 0x6a6a6aff, 0x6a6a6aff, 0x6a6a6aff, 0x6a6a6aff, 0x6a6a6aff, 0x6a6a6aff, 0x6a6a6aff, 0x6a6a6aff, 0x676767ff, 0x666666ff, 0x656565ff, 0x555555ff, 0x444444ff, 0x424242ff, 0x444444ff, 0x444444ff, +0x444444ff, 0x3d3d3eff, 0x61614bff, 0x323287ff, 0x00009fff, 0x000098ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000099ff, 0x000099ff, 0x00009cff, 0x00009fff, +0x000096ff, 0x00008fff, 0x2323a2ff, 0xb3b3ceff, 0xd6d6cdff, 0xd3d3d4ff, 0xedededff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xedededff, 0xf5f5f5ff, 0xd7d7d7ff, 0x8f8f8fff, 0x838383ff, 0x888888ff, +0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x878787ff, 0x8a8a8aff, 0x818181ff, 0x4a4a4aff, 0x202020ff, 0x222222ff, 0x181818ff, 0x060606ff, 0x060606ff, 0x060606ff, 0x060606ff, 0x060606ff, 0x070707ff, 0x141414ff, 0x1d1d1dff, 0x1b1b1bff, 0x1b1b1bff, 0x1b1b1bff, 0x1b1b1bff, 0x1b1b1bff, 0x181818ff, 0x242424ff, 0x333333ff, 0x313131ff, 0x363636ff, 0x393939ff, 0x373737ff, 0x3a3a3aff, +0x404040ff, 0x424242ff, 0x424242ff, 0x424242ff, 0x424242ff, 0x424242ff, 0x434343ff, 0x3a3a3aff, 0x343434ff, 0x3c3c3cff, 0x404040ff, 0x3e3e3eff, 0x414141ff, 0x373737ff, 0x313131ff, 0x404040ff, 0x353535ff, 0x242424ff, 0x262626ff, 0x262626ff, 0x262626ff, 0x1f1f1fff, 0x1b1b1bff, 0x1d1d1dff, 0x1d1d1dff, 0x1b1b1bff, 0x202020ff, 0x2b2b2bff, 0x2b2b2bff, 0x2b2b2bff, 0x2b2b2bff, 0x2b2b2bff, +0x2b2b2bff, 0x2b2b2bff, 0x2b2b2bff, 0x2b2b2bff, 0x2b2b2bff, 0x2b2b2bff, 0x2b2b2bff, 0x2b2b2bff, 0x2b2b2bff, 0x2b2b2bff, 0x2b2b2bff, 0x282828ff, 0x474747ff, 0x5b5b5bff, 0x585858ff, 0x585858ff, 0x585858ff, 0x585858ff, 0x585858ff, 0x585858ff, 0x585858ff, 0x585858ff, 0x585858ff, 0x565656ff, 0x616161ff, 0x686868ff, 0x666666ff, 0x595959ff, 0x454545ff, 0x424242ff, 0x444444ff, 0x444444ff, +0x444444ff, 0x3d3d3eff, 0x61614bff, 0x323287ff, 0x00009fff, 0x000098ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000099ff, 0x000099ff, 0x00009bff, 0x0000a1ff, 0x00009bff, 0x000090ff, 0x000093ff, 0x00007fff, 0x060671ff, +0x3636a0ff, 0x4949b3ff, 0x4c4ca8ff, 0xbbbbceff, 0xd4d4ceff, 0xd3d3d4ff, 0xedededff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xedededff, 0xf5f5f5ff, 0xd7d7d7ff, 0x8f8f8fff, 0x838383ff, 0x888888ff, +0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x878787ff, 0x8a8a8aff, 0x818181ff, 0x4a4a4aff, 0x202020ff, 0x232323ff, 0x161616ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x020202ff, 0x050505ff, 0x050505ff, 0x050505ff, 0x050505ff, 0x050505ff, 0x050505ff, 0x030303ff, 0x070707ff, 0x0c0c0cff, 0x0b0b0bff, 0x0a0a0aff, 0x090909ff, 0x090909ff, 0x0b0b0bff, +0x181818ff, 0x1c1c1cff, 0x1c1c1cff, 0x1c1c1cff, 0x1c1c1cff, 0x1c1c1cff, 0x1c1c1cff, 0x1d1d1dff, 0x1e1e1eff, 0x2d2d2dff, 0x373737ff, 0x343434ff, 0x353535ff, 0x333333ff, 0x313131ff, 0x333333ff, 0x363636ff, 0x3b3b3bff, 0x3b3b3bff, 0x3b3b3bff, 0x3b3b3bff, 0x2b2b2bff, 0x232323ff, 0x252525ff, 0x252525ff, 0x252525ff, 0x232323ff, 0x212121ff, 0x202020ff, 0x202020ff, 0x202020ff, 0x202020ff, +0x202020ff, 0x1f1f1fff, 0x1d1d1dff, 0x1d1d1dff, 0x1d1d1dff, 0x1d1d1dff, 0x1d1d1dff, 0x1d1d1dff, 0x1d1d1dff, 0x1d1d1dff, 0x1d1d1dff, 0x1c1c1cff, 0x242424ff, 0x292929ff, 0x282828ff, 0x282828ff, 0x282828ff, 0x282828ff, 0x282828ff, 0x282828ff, 0x282828ff, 0x282828ff, 0x272727ff, 0x1e1e1eff, 0x494949ff, 0x6b6b6bff, 0x5c5c5cff, 0x4b4b4bff, 0x424242ff, 0x434343ff, 0x444444ff, 0x444444ff, +0x444444ff, 0x3d3d3eff, 0x61614bff, 0x323287ff, 0x00009fff, 0x000098ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x00009aff, 0x00009fff, 0x00009fff, 0x000093ff, 0x000092ff, 0x000086ff, 0x000067ff, 0x202089ff, 0x5050b6ff, 0x4747b6ff, 0x5c5c8eff, 0x7f7f78ff, +0x7f7fb1ff, 0x3838a2ff, 0xa2a2a1ff, 0xc1c1c1ff, 0xd0d0cfff, 0xd4d4d4ff, 0xedededff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xedededff, 0xf5f5f5ff, 0xd7d7d7ff, 0x8f8f8fff, 0x838383ff, 0x888888ff, +0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x878787ff, 0x8a8a8aff, 0x818181ff, 0x4a4a4aff, 0x202020ff, 0x232323ff, 0x161616ff, 0x010101ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, +0x000000ff, 0x020202ff, 0x010101ff, 0x010101ff, 0x010101ff, 0x010101ff, 0x010101ff, 0x010101ff, 0x010101ff, 0x050505ff, 0x070707ff, 0x070707ff, 0x070707ff, 0x070707ff, 0x080808ff, 0x060606ff, 0x0c0c0cff, 0x1b1b1bff, 0x1a1a1aff, 0x1a1a1aff, 0x1a1a1aff, 0x181818ff, 0x171717ff, 0x171717ff, 0x171717ff, 0x171717ff, 0x171717ff, 0x171717ff, 0x181818ff, 0x181818ff, 0x181818ff, 0x181818ff, +0x161616ff, 0x212121ff, 0x262626ff, 0x252525ff, 0x252525ff, 0x252525ff, 0x252525ff, 0x252525ff, 0x252525ff, 0x252525ff, 0x252525ff, 0x252525ff, 0x212121ff, 0x1e1e1eff, 0x1e1e1eff, 0x1e1e1eff, 0x1e1e1eff, 0x1e1e1eff, 0x1e1e1eff, 0x1e1e1eff, 0x1f1f1fff, 0x1b1b1bff, 0x1e1e1eff, 0x272727ff, 0x545454ff, 0x6c6c6cff, 0x545454ff, 0x434343ff, 0x414141ff, 0x444444ff, 0x444444ff, 0x444444ff, +0x444444ff, 0x3d3d3eff, 0x61614bff, 0x323287ff, 0x00009fff, 0x000098ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000096ff, 0x000092ff, 0x000092ff, 0x000090ff, 0x000090ff, 0x00008dff, 0x00006eff, 0x151572ff, 0x4b4bacff, 0x5959c1ff, 0x6464a9ff, 0x757577ff, 0xaeaeadff, 0xf3f3f9ff, 0xececefff, 0xecece8ff, 0xefefe7ff, +0xe9e9efff, 0xb4b4c8ff, 0x898982ff, 0xb9b9b8ff, 0xd3d3d3ff, 0xd3d3d3ff, 0xedededff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xedededff, 0xf5f5f5ff, 0xd7d7d7ff, 0x8f8f8fff, 0x838383ff, 0x888888ff, +0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x878787ff, 0x8a8a8aff, 0x818181ff, 0x4a4a4aff, 0x202020ff, 0x232323ff, 0x161616ff, 0x010101ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, +0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x010101ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x010101ff, 0x020202ff, 0x020202ff, 0x020202ff, 0x020202ff, 0x020202ff, 0x020202ff, 0x020202ff, 0x020202ff, 0x020202ff, 0x020202ff, +0x020202ff, 0x0e0e0eff, 0x181818ff, 0x161616ff, 0x161616ff, 0x161616ff, 0x161616ff, 0x161616ff, 0x161616ff, 0x161616ff, 0x161616ff, 0x131313ff, 0x1f1f1fff, 0x272727ff, 0x252525ff, 0x252525ff, 0x252525ff, 0x262626ff, 0x242424ff, 0x212121ff, 0x1b1b1bff, 0x1b1b1bff, 0x353535ff, 0x5b5b5bff, 0x8f8f8fff, 0x7f7f7fff, 0x5c5c5cff, 0x4c4c4cff, 0x404040ff, 0x444444ff, 0x444444ff, 0x444444ff, +0x444444ff, 0x3d3d3eff, 0x61614bff, 0x323287ff, 0x00009fff, 0x000098ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000097ff, 0x000093ff, 0x000090ff, 0x00008eff, 0x00008bff, 0x0e0e99ff, 0x5454a9ff, 0x5b5ba9ff, 0x6767b7ff, 0x6161c0ff, 0x6666baff, 0x7d7d8fff, 0x9f9f92ff, 0xdbdbd5ff, 0xedede8ff, 0xe8e8e3ff, 0xe6e6e2ff, 0xe6e6e3ff, 0xe2e2dfff, 0xf2f2efff, 0xffffffff, 0xffffffff, +0xffffffff, 0xdddddbff, 0x777778ff, 0xacacacff, 0xd0d0d0ff, 0xd5d5d5ff, 0xedededff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xedededff, 0xf5f5f5ff, 0xd7d7d7ff, 0x8f8f8fff, 0x838383ff, 0x888888ff, +0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x878787ff, 0x8a8a8aff, 0x818181ff, 0x4a4a4aff, 0x202020ff, 0x232323ff, 0x161616ff, 0x010101ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, +0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, +0x000000ff, 0x000000ff, 0x010101ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x0b0b0bff, 0x161616ff, 0x141414ff, 0x141414ff, 0x141414ff, 0x121212ff, 0x161616ff, 0x242424ff, 0x2f2f2fff, 0x484848ff, 0x626262ff, 0x8c8c8cff, 0xc7c7c7ff, 0x8f8f8fff, 0x595959ff, 0x4c4c4cff, 0x404040ff, 0x444444ff, 0x444444ff, 0x444444ff, +0x444444ff, 0x3d3d3eff, 0x61614bff, 0x323287ff, 0x00009fff, 0x000098ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000094ff, 0x000090ff, 0x000091ff, 0x000091ff, 0x00008cff, 0x000092ff, 0x4040a4ff, 0x5f5fb0ff, 0x6969beff, 0x5f5fbfff, 0xa1a1d1ff, 0xffffe8ff, 0x9a9ad6ff, 0xaeaedbff, 0xffffe8ff, 0xf1f1e7ff, 0xf1f1ebff, 0xe8e8e6ff, 0xd8d8d7ff, 0xd4d4d3ff, 0xd8d8d7ff, 0xdadadbff, 0xdcdcdcff, 0xdbdbdbff, 0xcdcdceff, 0xb2b2b2ff, 0x969696ff, +0x929292ff, 0x808080ff, 0x646464ff, 0xaeaeaeff, 0xcfcfcfff, 0xd5d5d5ff, 0xedededff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xedededff, 0xf5f5f5ff, 0xd7d7d7ff, 0x8f8f8fff, 0x838383ff, 0x888888ff, +0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x878787ff, 0x8a8a8aff, 0x818181ff, 0x4a4a4aff, 0x202020ff, 0x232323ff, 0x161616ff, 0x010101ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, +0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, +0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x040404ff, 0x262626ff, 0x565656ff, 0x7a7a7aff, 0x939393ff, 0xc5c5c5ff, 0xd6d6d6ff, 0x8a8a8aff, 0x595959ff, 0x4c4c4cff, 0x404040ff, 0x444444ff, 0x444444ff, 0x444444ff, +0x444444ff, 0x3d3d3eff, 0x61614bff, 0x323287ff, 0x00009fff, 0x000098ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000098ff, 0x000095ff, 0x000092ff, 0x00008eff, 0x2e2ea3ff, 0x7676b3ff, 0x6767b0ff, 0x6a6ab3ff, 0x7474c2ff, 0x9999d0ff, 0xe9e9e2ff, 0xfffff0ff, 0xfffff4ff, 0xfdfde8ff, 0xefefe3ff, 0xf0f0e3ff, 0x8b8bd8ff, 0x9393d0ff, 0xddddd1ff, 0xd2d2d2ff, 0xd6d6d6ff, 0xccccccff, 0xb2b2b2ff, 0x9f9f9fff, 0x909090ff, 0x818181ff, 0x717171ff, 0x838383ff, 0x717171ff, 0x656565ff, 0x777777ff, +0x7b7b7bff, 0x797979ff, 0x6a6a6aff, 0xbebebeff, 0xd3d3d3ff, 0xd3d3d3ff, 0xedededff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xedededff, 0xf5f5f5ff, 0xd7d7d7ff, 0x8f8f8fff, 0x838383ff, 0x888888ff, +0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x878787ff, 0x8a8a8aff, 0x818181ff, 0x4a4a4aff, 0x202020ff, 0x232323ff, 0x161616ff, 0x010101ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, +0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, +0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x060606ff, 0x222222ff, 0x636363ff, 0xa4a4a4ff, 0xc2c2c2ff, 0xd5d5d5ff, 0xcfcfcfff, 0x8a8a8aff, 0x595959ff, 0x4c4c4cff, 0x404040ff, 0x444444ff, 0x444444ff, 0x444444ff, +0x444444ff, 0x3d3d3eff, 0x61614bff, 0x323287ff, 0x00009fff, 0x000098ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000093ff, 0x2828a1ff, 0x7b7bb4ff, 0x7575beff, 0xd0d0e0ff, 0xffffecff, 0xfcfceaff, 0xfcfce9ff, 0xfafae7ff, 0xf4f4e5ff, 0xe4e4e2ff, 0xe0e0e1ff, 0xd7d7d8ff, 0xcbcbccff, 0xcbcbccff, 0xcfcfd1ff, 0xc5c5b6ff, 0x9c9c90ff, 0x878788ff, 0x7a7a7aff, 0x717171ff, 0x707070ff, 0x656565ff, 0x686868ff, 0x868686ff, 0x919191ff, 0x838383ff, 0x8d8d8dff, 0x9b9b9bff, 0xb7b7b7ff, 0xd9d9d9ff, +0xe6e6e6ff, 0xc3c3c3ff, 0x7e7e7eff, 0xc6c6c6ff, 0xd6d6d6ff, 0xd3d3d3ff, 0xedededff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xedededff, 0xf5f5f5ff, 0xd7d7d7ff, 0x8f8f8fff, 0x838383ff, 0x888888ff, +0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x878787ff, 0x8a8a8aff, 0x818181ff, 0x4a4a4aff, 0x202020ff, 0x232323ff, 0x161616ff, 0x010101ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, +0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, +0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x131313ff, 0x666666ff, 0xc3c3c3ff, 0xd4d4d4ff, 0xccccccff, 0xd0d0d0ff, 0x8a8a8aff, 0x595959ff, 0x4c4c4cff, 0x404040ff, 0x444444ff, 0x444444ff, 0x444444ff, +0x444444ff, 0x3d3d3eff, 0x61614bff, 0x323287ff, 0x00009fff, 0x000098ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000093ff, 0x2c2caaff, 0xc0c0dbff, 0xffffebff, 0xf9f9e7ff, 0xe4e4dcff, 0xd6d6d8ff, 0xd9d9daff, 0xd5d5d6ff, 0xc8c8c9ff, 0xbdbdbeff, 0xb4b4b4ff, 0xa2a2a2ff, 0x888888ff, 0x7d7d7dff, 0x717171ff, 0x747474ff, 0x6e6e6fff, 0x5d5d5eff, 0x767676ff, 0x848484ff, 0x878787ff, 0x969696ff, 0xa0a0a0ff, 0xb0b0b0ff, 0xcececeff, 0xdadadaff, 0xdbdbdbff, 0xd6d6d6ff, 0xd4d4d4ff, 0xddddddff, 0xe2e2e2ff, +0xe2e2e2ff, 0xb6b6b6ff, 0x747474ff, 0xb6b6b6ff, 0xd2d2d2ff, 0xd4d4d4ff, 0xedededff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xedededff, 0xf5f5f5ff, 0xd7d7d7ff, 0x8f8f8fff, 0x838383ff, 0x888888ff, +0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x878787ff, 0x8a8a8aff, 0x818181ff, 0x4a4a4aff, 0x202020ff, 0x232323ff, 0x161616ff, 0x010101ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, +0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, +0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x090909ff, 0x636363ff, 0xbebebeff, 0xcfcfcfff, 0xcdcdcdff, 0xd0d0d0ff, 0x8a8a8aff, 0x595959ff, 0x4c4c4cff, 0x404040ff, 0x444444ff, 0x444444ff, 0x444444ff, +0x444444ff, 0x3d3d3eff, 0x61614bff, 0x323287ff, 0x00009fff, 0x000098ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000098ff, 0x00009aff, +0x0d0d8eff, 0x8484a3ff, 0xe2e2d4ff, 0xd6d6d7ff, 0xcccccdff, 0xa9a9aaff, 0x989898ff, 0x8c8c8cff, 0x818181ff, 0x777777ff, 0x6d6d6dff, 0x6f6f6fff, 0x717171ff, 0x6d6d6dff, 0x6f6f6fff, 0x7f7f7fff, 0x9c9c9cff, 0xa3a3a3ff, 0xaeaeaeff, 0xbbbbbbff, 0xc4c4c4ff, 0xcbcbcbff, 0xcfcfcfff, 0xccccccff, 0xcececeff, 0xbababaff, 0x8d8d8dff, 0x818181ff, 0x868686ff, 0x959595ff, 0x9b9b9bff, 0x949494ff, +0x878787ff, 0x686868ff, 0x5d5d5dff, 0xafafafff, 0xcfcfcfff, 0xd5d5d5ff, 0xedededff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xedededff, 0xf5f5f5ff, 0xd7d7d7ff, 0x8f8f8fff, 0x838383ff, 0x888888ff, +0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x878787ff, 0x8a8a8aff, 0x818181ff, 0x4a4a4aff, 0x202020ff, 0x232323ff, 0x161616ff, 0x010101ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, +0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, +0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x0b0b0bff, 0x656565ff, 0xbebebeff, 0xcfcfcfff, 0xcdcdcdff, 0xd0d0d0ff, 0x8a8a8aff, 0x595959ff, 0x4c4c4cff, 0x404040ff, 0x444444ff, 0x444444ff, 0x444444ff, +0x444444ff, 0x3d3d3eff, 0x61614bff, 0x323287ff, 0x00009fff, 0x000098ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000098ff, 0x00009bff, +0x22228bff, 0x787875ff, 0x92928dff, 0x9c9c9cff, 0x9c9c9cff, 0xacacacff, 0xb9b9b9ff, 0xb2b2b2ff, 0xacacacff, 0xa6a6a6ff, 0xa2a2a2ff, 0xa4a4a4ff, 0xa9a9a9ff, 0xabababff, 0xaeaeaeff, 0xb7b7b7ff, 0xc9c9c9ff, 0xbababaff, 0xaeaeaeff, 0x949494ff, 0x737373ff, 0x707070ff, 0x717171ff, 0x777777ff, 0x878787ff, 0x838383ff, 0x666666ff, 0x7e7e7eff, 0xabababff, 0xaeaeaeff, 0xb1b1b1ff, 0xadadadff, +0xabababff, 0x949494ff, 0x6d6d6dff, 0xb3b3b3ff, 0xd0d0d0ff, 0xd5d5d5ff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xedededff, 0xf5f5f5ff, 0xd7d7d7ff, 0x8f8f8fff, 0x838383ff, 0x888888ff, +0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x878787ff, 0x8a8a8aff, 0x818181ff, 0x4a4a4aff, 0x202020ff, 0x232323ff, 0x161616ff, 0x010101ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, +0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, +0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x0b0b0bff, 0x646464ff, 0xbebebeff, 0xcfcfcfff, 0xcdcdcdff, 0xd0d0d0ff, 0x8a8a8aff, 0x595959ff, 0x4c4c4cff, 0x404040ff, 0x444444ff, 0x444444ff, 0x444444ff, +0x444444ff, 0x3d3d3eff, 0x61614bff, 0x323287ff, 0x00009fff, 0x000098ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000098ff, 0x00009bff, +0x20208eff, 0x8d8d91ff, 0xbebebaff, 0xc3c3c3ff, 0xbbbbbbff, 0xc9c9c9ff, 0xccccccff, 0xc2c2c2ff, 0xbfbfbfff, 0xbcbcbcff, 0xb8b8b8ff, 0xacacacff, 0x9a9a9aff, 0x858585ff, 0x7e7e7eff, 0x707070ff, 0x717171ff, 0x787878ff, 0x7f7f7fff, 0x8e8e8eff, 0x939393ff, 0x9c9c9cff, 0xa4a4a4ff, 0xa7a7a7ff, 0xb0b0b0ff, 0xb6b6b6ff, 0xb8b8b8ff, 0xcacacaff, 0xe0e0e0ff, 0xdbdbdbff, 0xdfdfdfff, 0xdededeff, +0xe1e1e1ff, 0xbcbcbcff, 0x797979ff, 0xbcbcbcff, 0xd4d4d4ff, 0xd1d1d1ff, 0xe8e8e8ff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xedededff, 0xf5f5f5ff, 0xd7d7d7ff, 0x8f8f8fff, 0x838383ff, 0x888888ff, +0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x878787ff, 0x8a8a8aff, 0x818181ff, 0x4a4a4aff, 0x202020ff, 0x232323ff, 0x161616ff, 0x010101ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, +0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, +0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x0c0c0cff, 0x666666ff, 0xbebebeff, 0xcfcfcfff, 0xcdcdcdff, 0xd0d0d0ff, 0x8a8a8aff, 0x595959ff, 0x4c4c4cff, 0x404040ff, 0x444444ff, 0x444444ff, 0x444444ff, +0x444444ff, 0x3d3d3eff, 0x61614bff, 0x323287ff, 0x00009fff, 0x000098ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000098ff, 0x00009bff, +0x22228fff, 0x8f8f94ff, 0xb7b7b3ff, 0xb4b4b4ff, 0xa3a3a3ff, 0x939393ff, 0x7b7b7bff, 0x6a6a6aff, 0x6a6a6aff, 0x6a6a6aff, 0x6d6d6dff, 0x727272ff, 0x757575ff, 0x808080ff, 0x979797ff, 0x9e9e9eff, 0xacacacff, 0xb4b4b4ff, 0xbcbcbcff, 0xcbcbcbff, 0xd7d7d7ff, 0xdcdcdcff, 0xe2e2e2ff, 0xdbdbdbff, 0xc9c9c9ff, 0xc0c0c0ff, 0xb8b8b8ff, 0xabababff, 0xa7a7a7ff, 0xa9a9a9ff, 0x969696ff, 0x818181ff, +0x818181ff, 0x6f6f6fff, 0x636363ff, 0xb7b7b7ff, 0xd3d3d3ff, 0xccccccff, 0xe0e0e0ff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xedededff, 0xf5f5f5ff, 0xd7d7d7ff, 0x8f8f8fff, 0x838383ff, 0x888888ff, +0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x878787ff, 0x8a8a8aff, 0x818181ff, 0x4a4a4aff, 0x202020ff, 0x232323ff, 0x161616ff, 0x010101ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, +0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, +0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x090909ff, 0x606060ff, 0xbebebeff, 0xcfcfcfff, 0xcdcdcdff, 0xd0d0d0ff, 0x8a8a8aff, 0x595959ff, 0x4c4c4cff, 0x404040ff, 0x444444ff, 0x444444ff, 0x444444ff, +0x444444ff, 0x3d3d3eff, 0x61614bff, 0x323287ff, 0x00009fff, 0x000098ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000098ff, 0x00009cff, +0x1d1d8bff, 0x606065ff, 0x60605cff, 0x606060ff, 0x6b6b6bff, 0x6c6c6cff, 0x727272ff, 0x797979ff, 0x919191ff, 0xa2a2a2ff, 0xafafafff, 0xbcbcbcff, 0xc2c2c2ff, 0xcbcbcbff, 0xd6d6d6ff, 0xdcdcdcff, 0xe3e3e3ff, 0xd2d2d2ff, 0xc3c3c3ff, 0xb9b9b9ff, 0xafafafff, 0xa4a4a4ff, 0xa0a0a0ff, 0x999999ff, 0x7b7b7bff, 0x6a6a6aff, 0x727272ff, 0x737373ff, 0x727272ff, 0x727272ff, 0x777777ff, 0x848484ff, +0x929292ff, 0x929292ff, 0x6e6e6eff, 0xacacacff, 0xd1d1d1ff, 0xcfcfcfff, 0xe4e4e4ff, 0xf1f1f1ff, 0xedededff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xedededff, 0xf5f5f5ff, 0xd7d7d7ff, 0x8f8f8fff, 0x838383ff, 0x888888ff, +0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x878787ff, 0x8a8a8aff, 0x818181ff, 0x4a4a4aff, 0x202020ff, 0x232323ff, 0x161616ff, 0x010101ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, +0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, +0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x505050ff, 0xbfbfbfff, 0xcfcfcfff, 0xcdcdcdff, 0xd0d0d0ff, 0x8a8a8aff, 0x595959ff, 0x4c4c4cff, 0x404040ff, 0x444444ff, 0x444444ff, 0x444444ff, +0x444444ff, 0x3d3d3eff, 0x61614bff, 0x323287ff, 0x00009fff, 0x000098ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000098ff, 0x00009cff, +0x1d1d8aff, 0x707074ff, 0x888884ff, 0x9a9a9aff, 0xbbbbbbff, 0xc7c7c7ff, 0xcbcbcbff, 0xd2d2d2ff, 0xd9d9d9ff, 0xdededeff, 0xdadadaff, 0xc9c9c9ff, 0xbdbdbdff, 0xb2b2b2ff, 0xa8a8a8ff, 0x9b9b9bff, 0x9c9c9cff, 0x7d7d7dff, 0x6d6d6dff, 0x737373ff, 0x6d6d6dff, 0x707070ff, 0x717171ff, 0x767676ff, 0x7b7b7bff, 0x808080ff, 0xa2a2a2ff, 0xbdbdbdff, 0xbcbcbcff, 0xbbbbbbff, 0xc4c4c4ff, 0xcfcfcfff, +0xe4e4e4ff, 0xcfcfcfff, 0x7d7d7dff, 0xb5b5b5ff, 0xd5d5d5ff, 0xc9c9c9ff, 0xd3d3d3ff, 0xe6e6e6ff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xedededff, 0xf5f5f5ff, 0xd7d7d7ff, 0x8f8f8fff, 0x838383ff, 0x888888ff, +0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x878787ff, 0x8a8a8aff, 0x818181ff, 0x4a4a4aff, 0x202020ff, 0x232323ff, 0x161616ff, 0x010101ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, +0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, +0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x4e4e4eff, 0xc1c1c1ff, 0xcfcfcfff, 0xcdcdcdff, 0xd0d0d0ff, 0x8a8a8aff, 0x595959ff, 0x4c4c4cff, 0x404040ff, 0x444444ff, 0x444444ff, 0x444444ff, +0x444444ff, 0x3d3d3eff, 0x61614bff, 0x323287ff, 0x00009fff, 0x000098ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000098ff, 0x00009bff, +0x222290ff, 0x939397ff, 0xcdcdc9ff, 0xcbcbcbff, 0xb2b2b2ff, 0xb3b3b3ff, 0xa8a8a8ff, 0x969696ff, 0x8f8f8fff, 0x929292ff, 0x868686ff, 0x6d6d6dff, 0x666666ff, 0x636363ff, 0x5d5d5dff, 0x606060ff, 0x757575ff, 0x717171ff, 0x838383ff, 0x9e9e9eff, 0xacacacff, 0xc9c9c9ff, 0xd7d7d7ff, 0xd5d5d5ff, 0xd6d6d6ff, 0xd4d4d4ff, 0xd6d6d6ff, 0xd6d6d6ff, 0xd0d0d0ff, 0xd3d3d3ff, 0xbdbdbdff, 0xacacacff, +0xb9b9b9ff, 0xa2a2a2ff, 0x727272ff, 0xbdbdbdff, 0xd6d6d6ff, 0xc7c7c7ff, 0xccccccff, 0xe1e1e1ff, 0xefefefff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xedededff, 0xf5f5f5ff, 0xd7d7d7ff, 0x8f8f8fff, 0x838383ff, 0x888888ff, +0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x878787ff, 0x8a8a8aff, 0x818181ff, 0x4a4a4aff, 0x202020ff, 0x232323ff, 0x161616ff, 0x010101ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, +0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, +0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x4a4a4aff, 0xbababaff, 0xd1d1d1ff, 0xcdcdcdff, 0xd0d0d0ff, 0x8a8a8aff, 0x595959ff, 0x4c4c4cff, 0x404040ff, 0x444444ff, 0x444444ff, 0x444444ff, +0x444444ff, 0x3d3d3eff, 0x61614bff, 0x323287ff, 0x00009fff, 0x000098ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000098ff, 0x00009bff, +0x232391ff, 0x929297ff, 0xb9b9b5ff, 0x939394ff, 0x898989ff, 0xa3a3a3ff, 0x909090ff, 0x777777ff, 0x6f6f6fff, 0x737373ff, 0x767676ff, 0x7f7f7fff, 0x8f8f8fff, 0x9f9f9fff, 0xacacacff, 0xc3c3c3ff, 0xe5e5e5ff, 0xcbcbcbff, 0xb7b7b7ff, 0xacacacff, 0x969696ff, 0x8c8c8cff, 0x8b8b8bff, 0x898989ff, 0x8d8d8dff, 0x9f9f9fff, 0xa6a6a6ff, 0xb6b6b6ff, 0xcececeff, 0xcececeff, 0xb0b0b0ff, 0x999999ff, +0x909090ff, 0x757575ff, 0x626262ff, 0xb1b1b1ff, 0xd4d4d4ff, 0xc7c7c7ff, 0xd7d7d7ff, 0xefefefff, 0xeeeeeeff, 0xedededff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xedededff, 0xf5f5f5ff, 0xd7d7d7ff, 0x8f8f8fff, 0x838383ff, 0x888888ff, +0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x878787ff, 0x8a8a8aff, 0x818181ff, 0x4a4a4aff, 0x202020ff, 0x232323ff, 0x161616ff, 0x010101ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, +0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x060006ff, 0x0f050fff, 0x0b300bff, 0x021402ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, +0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x010101ff, 0x383838ff, 0xa0a0a0ff, 0xd4d4d4ff, 0xcdcdcdff, 0xd0d0d0ff, 0x8a8a8aff, 0x595959ff, 0x4c4c4cff, 0x404040ff, 0x444444ff, 0x444444ff, 0x444444ff, +0x444444ff, 0x3d3d3eff, 0x61614bff, 0x323287ff, 0x00009fff, 0x000098ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000098ff, 0x00009aff, +0x272794ff, 0x7b7b7fff, 0x8a8a86ff, 0xa1a1a2ff, 0xc3c3c3ff, 0xe0e0e0ff, 0xe0e0e0ff, 0xe4e4e4ff, 0xeaeaeaff, 0xe2e2e2ff, 0xc8c8c8ff, 0xbfbfbfff, 0xb9b9b9ff, 0xa1a1a1ff, 0x8f8f8fff, 0x878787ff, 0x858585ff, 0x666666ff, 0x5a5a5aff, 0x585858ff, 0x4f4f4fff, 0x686868ff, 0x757575ff, 0x707070ff, 0x767676ff, 0x8f8f8fff, 0x999999ff, 0xb0b0b0ff, 0xcececeff, 0xcbcbcbff, 0xcdcdcdff, 0xd5d5d5ff, +0xf0f0f0ff, 0xd8d8d8ff, 0x7b7b7bff, 0xacacacff, 0xd3d3d3ff, 0xc7c7c7ff, 0xd9d9d9ff, 0xf4f4f4ff, 0xf3f3f3ff, 0xf0f0f0ff, 0xedededff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xedededff, 0xf5f5f5ff, 0xd7d7d7ff, 0x8f8f8fff, 0x838383ff, 0x888888ff, +0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x878787ff, 0x8a8a8aff, 0x818181ff, 0x4a4a4aff, 0x202020ff, 0x232323ff, 0x161616ff, 0x010101ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, +0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x060006ff, 0x1f431fff, 0x278b27ff, 0x1ea31eff, 0x073307ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, +0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x030303ff, 0x2c2c2cff, 0x929292ff, 0xd5d5d5ff, 0xcdcdcdff, 0xd0d0d0ff, 0x8a8a8aff, 0x595959ff, 0x4c4c4cff, 0x404040ff, 0x444444ff, 0x444444ff, 0x444444ff, +0x444444ff, 0x3d3d3eff, 0x61614bff, 0x323287ff, 0x00009fff, 0x000098ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000098ff, 0x00009aff, +0x262693ff, 0x949498ff, 0xd0d0ccff, 0xd3d3d3ff, 0xb2b2b2ff, 0xa0a0a0ff, 0x949494ff, 0x868686ff, 0x7c7c7cff, 0x777777ff, 0x545454ff, 0x505050ff, 0x595959ff, 0x4f4f4fff, 0x494949ff, 0x5f5f5fff, 0x7c7c7cff, 0x7b7b7bff, 0x8f8f8fff, 0x999999ff, 0xb0b0b0ff, 0xd4d4d4ff, 0xdfdfdfff, 0xddddddff, 0xdededeff, 0xdfdfdfff, 0xdfdfdfff, 0xdbdbdbff, 0xd8d8d8ff, 0xdadadaff, 0xdadadaff, 0xbcbcbcff, +0xb8b8b8ff, 0x9f9f9fff, 0x696969ff, 0xafafafff, 0xd3d3d3ff, 0xc9c9c9ff, 0xcfcfcfff, 0xd9d9d9ff, 0xd4d4d4ff, 0xe4e4e4ff, 0xf0f0f0ff, 0xedededff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xedededff, 0xf5f5f5ff, 0xd7d7d7ff, 0x8f8f8fff, 0x838383ff, 0x888888ff, +0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x878787ff, 0x8a8a8aff, 0x818181ff, 0x4a4a4aff, 0x202020ff, 0x232323ff, 0x161616ff, 0x010101ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, +0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x072e07ff, 0x208220ff, 0x24c024ff, 0x23f323ff, 0x1dbf1dff, 0x062e06ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, +0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x030303ff, 0x2d2d2dff, 0x939393ff, 0xd5d5d5ff, 0xcdcdcdff, 0xd0d0d0ff, 0x8a8a8aff, 0x595959ff, 0x4c4c4cff, 0x404040ff, 0x444444ff, 0x444444ff, 0x444444ff, +0x444444ff, 0x3d3d3eff, 0x61614bff, 0x323287ff, 0x00009fff, 0x000098ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000098ff, 0x00009dff, +0x171784ff, 0x656569ff, 0x83837eff, 0x666666ff, 0x4b4b4bff, 0x505050ff, 0x525252ff, 0x545454ff, 0x535353ff, 0x5c5c5cff, 0x808080ff, 0x929292ff, 0x9b9b9bff, 0xabababff, 0xb7b7b7ff, 0xcacacaff, 0xe4e4e4ff, 0xe1e1e1ff, 0xe0e0e0ff, 0xdededeff, 0xdbdbdbff, 0xd4d4d4ff, 0xd1d1d1ff, 0xd4d4d4ff, 0xc7c7c7ff, 0xa0a0a0ff, 0x8b8b8bff, 0x8c8c8cff, 0x808080ff, 0x707070ff, 0x737373ff, 0x676767ff, +0x626262ff, 0x585858ff, 0x5d5d5dff, 0xb3b3b3ff, 0xd3d3d3ff, 0xc9c9c9ff, 0xd1d1d1ff, 0xdededeff, 0xd8d8d8ff, 0xe5e5e5ff, 0xf0f0f0ff, 0xedededff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xedededff, 0xf5f5f5ff, 0xd7d7d7ff, 0x8f8f8fff, 0x838383ff, 0x888888ff, +0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x878787ff, 0x8a8a8aff, 0x818181ff, 0x4a4a4aff, 0x202020ff, 0x232323ff, 0x161616ff, 0x010101ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, +0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x062b06ff, 0x20c520ff, 0x25eb25ff, 0x21d521ff, 0x24c924ff, 0x1e711eff, 0x070e07ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, +0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x030303ff, 0x2d2d2dff, 0x939393ff, 0xd5d5d5ff, 0xcdcdcdff, 0xd0d0d0ff, 0x8a8a8aff, 0x595959ff, 0x4c4c4cff, 0x404040ff, 0x444444ff, 0x444444ff, 0x444444ff, +0x444444ff, 0x3d3d3eff, 0x61614bff, 0x323287ff, 0x00009fff, 0x000098ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000098ff, 0x00009dff, +0x1d1d8bff, 0x606065ff, 0x61615dff, 0x5e5e5eff, 0x7b7b7bff, 0xa5a5a5ff, 0xacacacff, 0xb8b8b8ff, 0xc0c0c0ff, 0xc3c3c3ff, 0xd8d8d8ff, 0xdededeff, 0xdadadaff, 0xd7d7d7ff, 0xd3d3d3ff, 0xcececeff, 0xcececeff, 0xb0b0b0ff, 0x989898ff, 0x8e8e8eff, 0x757575ff, 0x707070ff, 0x727272ff, 0x737373ff, 0x717171ff, 0x616161ff, 0x5a5a5aff, 0x828282ff, 0x969696ff, 0x878787ff, 0x8a8a8aff, 0x9a9a9aff, +0xacacacff, 0xa0a0a0ff, 0x707070ff, 0xaeaeaeff, 0xd3d3d3ff, 0xcacacaff, 0xcfcfcfff, 0xe5e5e5ff, 0xf4f4f4ff, 0xf0f0f0ff, 0xeeeeeeff, 0xedededff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xedededff, 0xf5f5f5ff, 0xd7d7d7ff, 0x8f8f8fff, 0x838383ff, 0x888888ff, +0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x878787ff, 0x8a8a8aff, 0x818181ff, 0x4a4a4aff, 0x202020ff, 0x232323ff, 0x161616ff, 0x010101ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, +0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x062a06ff, 0x20c320ff, 0x25de25ff, 0x21cc21ff, 0x23d923ff, 0x20ba20ff, 0x0e2d0eff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, +0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x030303ff, 0x2e2e2eff, 0x949494ff, 0xd6d6d6ff, 0xcdcdcdff, 0xd0d0d0ff, 0x8a8a8aff, 0x595959ff, 0x4c4c4cff, 0x404040ff, 0x444444ff, 0x444444ff, 0x444444ff, +0x444444ff, 0x3d3d3eff, 0x61614bff, 0x323287ff, 0x00009fff, 0x000098ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000098ff, 0x00009aff, +0x2a2a96ff, 0x86868bff, 0xa3a3a0ff, 0xbbbbbbff, 0xc9c9c9ff, 0xd5d5d5ff, 0xccccccff, 0xc9c9c9ff, 0xcacacaff, 0xc1c1c1ff, 0x9e9e9eff, 0x939393ff, 0x929292ff, 0x7b7b7bff, 0x6b6b6bff, 0x6e6e6eff, 0x767676ff, 0x626262ff, 0x626262ff, 0x686868ff, 0x666666ff, 0x717171ff, 0x8e8e8eff, 0x989898ff, 0x9d9d9dff, 0xabababff, 0xb2b2b2ff, 0xc9c9c9ff, 0xdcdcdcff, 0xdadadaff, 0xdadadaff, 0xd7d7d7ff, +0xd8d8d8ff, 0xb8b8b8ff, 0x737373ff, 0xadadadff, 0xd3d3d3ff, 0xccccccff, 0xc5c5c5ff, 0xd5d5d5ff, 0xeeeeeeff, 0xecececff, 0xecececff, 0xeeeeeeff, 0xedededff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xedededff, 0xf5f5f5ff, 0xd7d7d7ff, 0x8f8f8fff, 0x838383ff, 0x888888ff, +0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x878787ff, 0x8a8a8aff, 0x818181ff, 0x4a4a4aff, 0x202020ff, 0x232323ff, 0x161616ff, 0x010101ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, +0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x106510ff, 0x28f828ff, 0x22d322ff, 0x23cf23ff, 0x20bf20ff, 0x0e5f0eff, 0x000700ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, +0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x030303ff, 0x2e2e2eff, 0x919191ff, 0xd6d6d6ff, 0xcdcdcdff, 0xd0d0d0ff, 0x8a8a8aff, 0x595959ff, 0x4c4c4cff, 0x404040ff, 0x444444ff, 0x444444ff, 0x444444ff, +0x444444ff, 0x3d3d3eff, 0x61614bff, 0x323287ff, 0x00009fff, 0x000098ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000098ff, 0x00009aff, +0x272794ff, 0x808085ff, 0x939390ff, 0x9e9e9fff, 0x9f9f9fff, 0x949494ff, 0x787878ff, 0x6f6f6fff, 0x747474ff, 0x717171ff, 0x606060ff, 0x626262ff, 0x6e6e6eff, 0x6e6e6eff, 0x707070ff, 0x878787ff, 0xa6a6a6ff, 0x9e9e9eff, 0xa5a5a5ff, 0xabababff, 0xadadadff, 0xb4b4b4ff, 0xc2c2c2ff, 0xc9c9c9ff, 0xc5c5c5ff, 0xc4c4c4ff, 0xc8c8c8ff, 0xc5c5c5ff, 0xc5c5c5ff, 0xccccccff, 0xcbcbcbff, 0xcacacaff, +0xb0b0b0ff, 0x8b8b8bff, 0x6a6a6aff, 0xafafafff, 0xd3d3d3ff, 0xcbcbcbff, 0xcbcbcbff, 0xd2d2d2ff, 0xe6e6e6ff, 0xe4e4e4ff, 0xe3e3e3ff, 0xf0f0f0ff, 0xedededff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xedededff, 0xf5f5f5ff, 0xd7d7d7ff, 0x8f8f8fff, 0x838383ff, 0x888888ff, +0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x878787ff, 0x8a8a8aff, 0x818181ff, 0x4a4a4aff, 0x202020ff, 0x232323ff, 0x161616ff, 0x010101ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, +0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x021002ff, 0x051c05ff, 0x041a04ff, 0x041a04ff, 0x051d05ff, 0x020d02ff, 0x000000ff, 0x0c4a0cff, 0x22d022ff, 0x1db91dff, 0x1d6d1dff, 0x0d2e0dff, 0x000200ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, +0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x070707ff, 0x262626ff, 0x757575ff, 0xc8c8c8ff, 0xcfcfcfff, 0xd0d0d0ff, 0x8a8a8aff, 0x595959ff, 0x4c4c4cff, 0x404040ff, 0x444444ff, 0x444444ff, 0x444444ff, +0x444444ff, 0x3d3d3eff, 0x61614bff, 0x323287ff, 0x00009fff, 0x000098ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000098ff, 0x00009aff, +0x272794ff, 0x838387ff, 0x868682ff, 0x828282ff, 0xa8a8a8ff, 0xbebebeff, 0xadadadff, 0xabababff, 0xaaaaaaff, 0xa2a2a2ff, 0xa0a0a0ff, 0xa3a3a3ff, 0xa6a6a6ff, 0xaaaaaaff, 0xabababff, 0xb2b2b2ff, 0xc4c4c4ff, 0xa3a3a3ff, 0x8e8e8eff, 0x858585ff, 0x6e6e6eff, 0x6a6a6aff, 0x717171ff, 0x727272ff, 0x6f6f6fff, 0x777777ff, 0x8f8f8fff, 0x9a9a9aff, 0xb2b2b2ff, 0xd0d0d0ff, 0xcbcbcbff, 0xcacacaff, +0xc3c3c3ff, 0xa4a4a4ff, 0x6f6f6fff, 0xaeaeaeff, 0xd3d3d3ff, 0xc9c9c9ff, 0xd2d2d2ff, 0xe0e0e0ff, 0xe5e5e5ff, 0xe2e2e2ff, 0xe5e5e5ff, 0xf0f0f0ff, 0xedededff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xedededff, 0xf5f5f5ff, 0xd7d7d7ff, 0x8f8f8fff, 0x838383ff, 0x888888ff, +0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x878787ff, 0x8a8a8aff, 0x818181ff, 0x4a4a4aff, 0x202020ff, 0x232323ff, 0x161616ff, 0x010101ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, +0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x020e02ff, 0x083008ff, 0x137a13ff, 0x1ca61cff, 0x1a9d1aff, 0x1a9d1aff, 0x1ca91cff, 0x126f12ff, 0x062606ff, 0x031903ff, 0x083108ff, 0x083608ff, 0x0b2c0bff, 0x051805ff, 0x052005ff, 0x052205ff, 0x062506ff, 0x031703ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, +0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x060606ff, 0x1d1d1dff, 0x686868ff, 0xc2c2c2ff, 0xd1d1d1ff, 0xd0d0d0ff, 0x8a8a8aff, 0x595959ff, 0x4c4c4cff, 0x404040ff, 0x444444ff, 0x444444ff, 0x444444ff, +0x444444ff, 0x3d3d3eff, 0x61614bff, 0x323287ff, 0x00009fff, 0x000098ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000098ff, 0x00009aff, +0x292995ff, 0x88888dff, 0x8c8c87ff, 0x9f9f9fff, 0xc1c1c1ff, 0xbcbcbcff, 0xb7b7b7ff, 0xbbbbbbff, 0xb4b4b4ff, 0x929292ff, 0x868686ff, 0x888888ff, 0x7b7b7bff, 0x707070ff, 0x646464ff, 0x6a6a6aff, 0x767676ff, 0x676767ff, 0x6d6d6dff, 0x747474ff, 0x777777ff, 0x838383ff, 0xa1a1a1ff, 0xacacacff, 0xa8a8a8ff, 0xadadadff, 0xbbbbbbff, 0xc0c0c0ff, 0xcbcbcbff, 0xd8d8d8ff, 0xd6d6d6ff, 0xd6d6d6ff, +0xdededeff, 0xb7b7b7ff, 0x707070ff, 0xaeaeaeff, 0xd3d3d3ff, 0xcacacaff, 0xcdcdcdff, 0xd3d3d3ff, 0xd1d1d1ff, 0xd3d3d3ff, 0xe5e5e5ff, 0xf0f0f0ff, 0xedededff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xedededff, 0xf5f5f5ff, 0xd7d7d7ff, 0x8f8f8fff, 0x838383ff, 0x888888ff, +0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x878787ff, 0x8a8a8aff, 0x818181ff, 0x4a4a4aff, 0x202020ff, 0x232323ff, 0x161616ff, 0x010101ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, +0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x030003ff, 0x081507ff, 0x137a12ff, 0x1fb51eff, 0x22cd22ff, 0x25de25ff, 0x24d924ff, 0x24d924ff, 0x25df25ff, 0x21c921ff, 0x1eb41eff, 0x106510ff, 0x021202ff, 0x0f610fff, 0x1baf1bff, 0x1ba61bff, 0x1ca71cff, 0x1ba71bff, 0x1eb01eff, 0x168816ff, 0x093b09ff, 0x031303ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, +0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x101010ff, 0x6c6c6cff, 0xc3c3c3ff, 0xd0d0d0ff, 0xd0d0d0ff, 0x8a8a8aff, 0x595959ff, 0x4c4c4cff, 0x404040ff, 0x444444ff, 0x444444ff, 0x444444ff, +0x444444ff, 0x3d3d3eff, 0x61614bff, 0x323287ff, 0x00009fff, 0x000098ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000098ff, 0x00009cff, +0x21218eff, 0x6f6f74ff, 0x74746fff, 0x757576ff, 0x757575ff, 0x5a5a5aff, 0x565656ff, 0x5e5e5eff, 0x5d5d5dff, 0x626262ff, 0x696969ff, 0x777777ff, 0x757575ff, 0x7a7a7aff, 0x818181ff, 0x989898ff, 0xb5b5b5ff, 0xb6b6b6ff, 0xc1c1c1ff, 0xc6c6c6ff, 0xcdcdcdff, 0xd4d4d4ff, 0xddddddff, 0xe0e0e0ff, 0xe1e1e1ff, 0xd9d9d9ff, 0xc1c1c1ff, 0xb7b7b7ff, 0xb0b0b0ff, 0xa2a2a2ff, 0xa1a1a1ff, 0xa1a1a1ff, +0xa2a2a2ff, 0x7b7b7bff, 0x606060ff, 0xb2b2b2ff, 0xd3d3d3ff, 0xcbcbcbff, 0xcacacaff, 0xc9c9c9ff, 0xc3c3c3ff, 0xd7d7d7ff, 0xeeeeeeff, 0xeeeeeeff, 0xedededff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xedededff, 0xf5f5f5ff, 0xd7d7d7ff, 0x8f8f8fff, 0x838383ff, 0x888888ff, +0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x878787ff, 0x8a8a8aff, 0x818181ff, 0x4a4a4aff, 0x202020ff, 0x232323ff, 0x161616ff, 0x010101ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, +0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x10110eff, 0x168d20ff, 0x0dd621ff, 0x13db24ff, 0x1ece22ff, 0x1fca21ff, 0x17cb21ff, 0x1fcb21ff, 0x23ca21ff, 0x23cf22ff, 0x26dc24ff, 0x22c721ff, 0x1ca71bff, 0x22c921ff, 0x26dd25ff, 0x25d723ff, 0x25d723ff, 0x25d723ff, 0x25db24ff, 0x24cf22ff, 0x20bf1fff, 0x178917ff, 0x031903ff, 0x000000ff, 0x000000ff, 0x000000ff, +0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x0b0b0bff, 0x6c6c6cff, 0xc3c3c3ff, 0xd0d0d0ff, 0xd0d0d0ff, 0x8a8a8aff, 0x595959ff, 0x4c4c4cff, 0x404040ff, 0x444444ff, 0x444444ff, 0x444444ff, +0x444444ff, 0x3d3d3eff, 0x61614bff, 0x323287ff, 0x00009fff, 0x000098ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000098ff, 0x00009dff, +0x191987ff, 0x59595eff, 0x575753ff, 0x5b5b5bff, 0x767676ff, 0x7a7a7aff, 0x848484ff, 0x8e8e8eff, 0x939393ff, 0xb6b6b6ff, 0xc9c9c9ff, 0xcacacaff, 0xcececeff, 0xd3d3d3ff, 0xd6d6d6ff, 0xdadadaff, 0xe4e4e4ff, 0xd1d1d1ff, 0xc3c3c3ff, 0xbababaff, 0xafafafff, 0xa6a6a6ff, 0x9e9e9eff, 0x999999ff, 0x9b9b9bff, 0x919191ff, 0x6f6f6fff, 0x686868ff, 0x626262ff, 0x646464ff, 0x757575ff, 0x717171ff, +0x777777ff, 0x6f6f6fff, 0x646464ff, 0xb2b2b2ff, 0xd3d3d3ff, 0xcbcbcbff, 0xccccccff, 0xcacacaff, 0xcdcdcdff, 0xe7e7e7ff, 0xf3f3f3ff, 0xedededff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xedededff, 0xf5f5f5ff, 0xd7d7d7ff, 0x8f8f8fff, 0x838383ff, 0x888888ff, +0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x878787ff, 0x8a8a8aff, 0x818181ff, 0x4a4a4aff, 0x202020ff, 0x232323ff, 0x161616ff, 0x010101ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, +0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000c00ff, 0x008817ff, 0x42d926ff, 0x6bcb22ff, 0x5bc621ff, 0x1dcb21ff, 0x17cc22ff, 0x41c922ff, 0x1acc22ff, 0x09cd22ff, 0x0dcd21ff, 0x0ccc21ff, 0x0dd122ff, 0x0ed823ff, 0x0dd122ff, 0x0ccc21ff, 0x0ccc21ff, 0x0ccc21ff, 0x0ccc21ff, 0x0ccc21ff, 0x0dcf22ff, 0x0dd823ff, 0x17da23ff, 0x168e17ff, 0x041c04ff, 0x000000ff, 0x000000ff, +0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x0c0c0cff, 0x6c6c6cff, 0xc3c3c3ff, 0xd0d0d0ff, 0xd0d0d0ff, 0x8a8a8aff, 0x595959ff, 0x4c4c4cff, 0x404040ff, 0x444444ff, 0x444444ff, 0x444444ff, +0x444444ff, 0x3d3d3eff, 0x61614bff, 0x323287ff, 0x00009fff, 0x000098ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000098ff, 0x00009bff, +0x292996ff, 0x838388ff, 0x959590ff, 0xb9b9baff, 0xd6d6d6ff, 0xd3d3d3ff, 0xd3d3d3ff, 0xd6d6d6ff, 0xd1d1d1ff, 0xbbbbbbff, 0xb1b1b1ff, 0xb0b0b0ff, 0xa1a1a1ff, 0x949494ff, 0x939393ff, 0x919191ff, 0x969696ff, 0x777777ff, 0x5f5f5fff, 0x606060ff, 0x636363ff, 0x5a5a5aff, 0x575757ff, 0x6e6e6eff, 0x717171ff, 0x797979ff, 0x848484ff, 0x929292ff, 0x9e9e9eff, 0xbcbcbcff, 0xd8d8d8ff, 0xd2d2d2ff, +0xd9d9d9ff, 0xbebebeff, 0x767676ff, 0xadadadff, 0xd3d3d3ff, 0xcbcbcbff, 0xccccccff, 0xc8c8c8ff, 0xd4d4d4ff, 0xe3e3e3ff, 0xeaeaeaff, 0xf1f1f1ff, 0xedededff, 0xedededff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xedededff, 0xf5f5f5ff, 0xd7d7d7ff, 0x8f8f8fff, 0x838383ff, 0x888888ff, +0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x878787ff, 0x8a8a8aff, 0x818181ff, 0x4a4a4aff, 0x202020ff, 0x232323ff, 0x161616ff, 0x010101ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, +0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000002ff, 0x285014ff, 0x6ce024ff, 0xbec322ff, 0xf6b821ff, 0xe3bb22ff, 0x8ac422ff, 0x7dc422ff, 0xc5bf22ff, 0x82c522ff, 0x64c622ff, 0x6ac622ff, 0x6ac622ff, 0x6ac521ff, 0x6ac521ff, 0x6ac521ff, 0x6ac622ff, 0x6ac622ff, 0x6ac622ff, 0x6ac622ff, 0x6ac622ff, 0x69c621ff, 0x73c321ff, 0x49ca22ff, 0x16ee27ff, 0x137a14ff, 0x000000ff, 0x000000ff, +0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x0c0c0cff, 0x6c6c6cff, 0xc3c3c3ff, 0xd0d0d0ff, 0xd0d0d0ff, 0x8a8a8aff, 0x595959ff, 0x4c4c4cff, 0x404040ff, 0x444444ff, 0x444444ff, 0x444444ff, +0x444444ff, 0x3d3d3eff, 0x61614bff, 0x323287ff, 0x00009fff, 0x000098ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000098ff, 0x00009dff, +0x1d1d8bff, 0x616166ff, 0x797976ff, 0x9e9e9eff, 0xa1a1a1ff, 0xa5a5a5ff, 0xadadadff, 0xabababff, 0xaaaaaaff, 0xa1a1a1ff, 0x9d9d9dff, 0x9a9a9aff, 0x858585ff, 0x727272ff, 0x717171ff, 0x717171ff, 0x727272ff, 0x737373ff, 0x757575ff, 0x8a8a8aff, 0xa8a8a8ff, 0xadadadff, 0xb6b6b6ff, 0xd5d5d5ff, 0xdfdfdfff, 0xd8d8d8ff, 0xcececeff, 0xbcbcbcff, 0xa5a5a5ff, 0x969696ff, 0x8b8b8bff, 0x8c8c8cff, +0x909090ff, 0x7e7e7eff, 0x656565ff, 0xb1b1b1ff, 0xd3d3d3ff, 0xcbcbcbff, 0xccccccff, 0xcbcbcbff, 0xcacacaff, 0xc9c9c9ff, 0xd7d7d7ff, 0xedededff, 0xf2f2f2ff, 0xefefefff, 0xedededff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xedededff, 0xf5f5f5ff, 0xd7d7d7ff, 0x8f8f8fff, 0x838383ff, 0x888888ff, +0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x878787ff, 0x8a8a8aff, 0x818181ff, 0x4a4a4aff, 0x202020ff, 0x232323ff, 0x161616ff, 0x010101ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, +0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x20180dff, 0xc49024ff, 0xfdc822ff, 0xfeb821ff, 0xffb922ff, 0xffba22ff, 0xf9ba22ff, 0xf7b822ff, 0xffb922ff, 0xf8b922ff, 0xf5b922ff, 0xf6b922ff, 0xf6b922ff, 0xf6b922ff, 0xf6b922ff, 0xf6b922ff, 0xf6b922ff, 0xf6b922ff, 0xf6b922ff, 0xf6b922ff, 0xf6b922ff, 0xf6b922ff, 0xfab621ff, 0xe5cc24ff, 0x63c822ff, 0x01450aff, 0x000000ff, 0x000000ff, +0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x0c0c0cff, 0x6c6c6cff, 0xc3c3c3ff, 0xd0d0d0ff, 0xd0d0d0ff, 0x8a8a8aff, 0x595959ff, 0x4c4c4cff, 0x404040ff, 0x444444ff, 0x444444ff, 0x444444ff, +0x444444ff, 0x3d3d3eff, 0x61614bff, 0x323287ff, 0x00009fff, 0x000098ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000098ff, 0x00009dff, +0x191988ff, 0x55555aff, 0x51514cff, 0x515152ff, 0x757575ff, 0x999999ff, 0xa0a0a0ff, 0x9d9d9dff, 0xa9a9a9ff, 0xcbcbcbff, 0xdcdcdcff, 0xdbdbdbff, 0xe0e0e0ff, 0xe4e4e4ff, 0xe6e6e6ff, 0xe6e6e6ff, 0xe8e8e8ff, 0xdcdcdcff, 0xcfcfcfff, 0xb6b6b6ff, 0xa1a1a1ff, 0x929292ff, 0x878787ff, 0x838383ff, 0x848484ff, 0x797979ff, 0x777777ff, 0x696969ff, 0x5f5f5fff, 0x797979ff, 0x717171ff, 0x727272ff, +0x757575ff, 0x676767ff, 0x5f5f5fff, 0xb2b2b2ff, 0xd3d3d3ff, 0xcbcbcbff, 0xccccccff, 0xccccccff, 0xcbcbcbff, 0xcbcbcbff, 0xc7c7c7ff, 0xd6d6d6ff, 0xe3e3e3ff, 0xecececff, 0xf0f0f0ff, 0xedededff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xedededff, 0xf5f5f5ff, 0xd7d7d7ff, 0x8f8f8fff, 0x838383ff, 0x888888ff, +0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x878787ff, 0x8a8a8aff, 0x818181ff, 0x4a4a4aff, 0x202020ff, 0x232323ff, 0x161616ff, 0x010101ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, +0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x6f530dff, 0xffd924ff, 0xffc321ff, 0xffc322ff, 0xffc322ff, 0xffc322ff, 0xffc322ff, 0xffc322ff, 0xffc322ff, 0xffc322ff, 0xffc322ff, 0xffc322ff, 0xffc322ff, 0xffc322ff, 0xffc322ff, 0xffc322ff, 0xffc322ff, 0xffbc22ff, 0xffb922ff, 0xffbc22ff, 0xffc122ff, 0xffc221ff, 0xffd024ff, 0xffba20ff, 0x5f390aff, 0x000000ff, 0x000000ff, 0x000000ff, +0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x0c0c0cff, 0x6c6c6cff, 0xc3c3c3ff, 0xd0d0d0ff, 0xd0d0d0ff, 0x8a8a8aff, 0x595959ff, 0x4c4c4cff, 0x404040ff, 0x444444ff, 0x444444ff, 0x444444ff, +0x444444ff, 0x3d3d3eff, 0x61614bff, 0x323287ff, 0x00009fff, 0x000098ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000098ff, 0x00009aff, +0x262693ff, 0x97979cff, 0xbebebbff, 0xb6b6b6ff, 0xd0d0d0ff, 0xeaeaeaff, 0xe3e3e3ff, 0xe2e2e2ff, 0xc3c3c3ff, 0xb1b1b1ff, 0xacacacff, 0x9e9e9eff, 0x8f8f8fff, 0x7e7e7eff, 0x7b7b7bff, 0x797979ff, 0x7a7a7aff, 0x6a6a6aff, 0x6e6e6eff, 0x5d5d5dff, 0x4b4b4bff, 0x5c5c5cff, 0x666666ff, 0x737373ff, 0x777777ff, 0x767676ff, 0x818181ff, 0x8f8f8fff, 0xa9a9a9ff, 0xd6d6d6ff, 0xddddddff, 0xdbdbdbff, +0xe2e2e2ff, 0xc5c5c5ff, 0x767676ff, 0xacacacff, 0xd3d3d3ff, 0xcbcbcbff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xc4c4c4ff, 0xc3c3c3ff, 0xd5d5d5ff, 0xebebebff, 0xf0f0f0ff, 0xeeeeeeff, 0xedededff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xedededff, 0xf5f5f5ff, 0xd7d7d7ff, 0x8f8f8fff, 0x838383ff, 0x888888ff, +0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x878787ff, 0x8a8a8aff, 0x818181ff, 0x4a4a4aff, 0x202020ff, 0x232323ff, 0x161616ff, 0x010101ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, +0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x683e0dff, 0xffa724ff, 0xff9822ff, 0xff9922ff, 0xff9922ff, 0xff9922ff, 0xff9922ff, 0xff9922ff, 0xff9922ff, 0xff9922ff, 0xff9922ff, 0xff9922ff, 0xff9922ff, 0xff9922ff, 0xff9922ff, 0xff9922ff, 0xff9822ff, 0xffb522ff, 0xffc722ff, 0xffbc22ff, 0xffa021ff, 0xff9b23ff, 0xe6911eff, 0x4c3509ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, +0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x0c0c0cff, 0x6c6c6cff, 0xc3c3c3ff, 0xd0d0d0ff, 0xd0d0d0ff, 0x8a8a8aff, 0x595959ff, 0x4c4c4cff, 0x404040ff, 0x444444ff, 0x444444ff, 0x444444ff, +0x444444ff, 0x3d3d3eff, 0x61614bff, 0x323287ff, 0x00009fff, 0x000098ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000098ff, 0x00009bff, +0x242491ff, 0x949498ff, 0xaaaaa7ff, 0x9b9b9bff, 0x898989ff, 0x757575ff, 0x777777ff, 0x747474ff, 0x585858ff, 0x4a4a4aff, 0x4e4e4eff, 0x4d4d4dff, 0x565656ff, 0x686868ff, 0x676767ff, 0x727272ff, 0x808080ff, 0x818181ff, 0x919191ff, 0x9e9e9eff, 0xa5a5a5ff, 0xc1c1c1ff, 0xd3d3d3ff, 0xdcdcdcff, 0xe0e0e0ff, 0xe0e0e0ff, 0xdfdfdfff, 0xddddddff, 0xdadadaff, 0xd4d4d4ff, 0xd3d3d3ff, 0xd2d2d2ff, +0xd9d9d9ff, 0xbdbdbdff, 0x747474ff, 0xadadadff, 0xd3d3d3ff, 0xcbcbcbff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xcacacaff, 0xd9d9d9ff, 0xe1e1e1ff, 0xdededeff, 0xe5e5e5ff, 0xe0e0e0ff, 0xeaeaeaff, 0xeeeeeeff, 0xedededff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xedededff, 0xf5f5f5ff, 0xd7d7d7ff, 0x8f8f8fff, 0x838383ff, 0x888888ff, +0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x878787ff, 0x8a8a8aff, 0x818181ff, 0x4a4a4aff, 0x202020ff, 0x232323ff, 0x161616ff, 0x010101ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, +0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x682c0dff, 0xff7924ff, 0xff6c22ff, 0xff6d22ff, 0xff6d22ff, 0xff6d22ff, 0xff6d22ff, 0xff6d22ff, 0xff6d22ff, 0xff6d22ff, 0xff6d22ff, 0xff6d22ff, 0xff6d22ff, 0xff6d22ff, 0xff6d22ff, 0xff6c22ff, 0xff6c22ff, 0xff8622ff, 0xff9822ff, 0xff8e21ff, 0xff7421ff, 0xff7724ff, 0xa54715ff, 0x0b0101ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, +0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x0c0c0cff, 0x6c6c6cff, 0xc3c3c3ff, 0xd0d0d0ff, 0xd0d0d0ff, 0x8a8a8aff, 0x595959ff, 0x4c4c4cff, 0x404040ff, 0x444444ff, 0x444444ff, 0x444444ff, +0x444444ff, 0x3d3d3eff, 0x61614bff, 0x323287ff, 0x00009fff, 0x000098ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000098ff, 0x00009bff, +0x232390ff, 0x626267ff, 0x565653ff, 0x585858ff, 0x4a4a4aff, 0x4f4f4fff, 0x5d5d5dff, 0x606060ff, 0x838383ff, 0x959595ff, 0x979797ff, 0xa2a2a2ff, 0xb4b4b4ff, 0xcdcdcdff, 0xcfcfcfff, 0xd6d6d6ff, 0xe1e1e1ff, 0xdfdfdfff, 0xddddddff, 0xdadadaff, 0xd9d9d9ff, 0xd3d3d3ff, 0xcececeff, 0xcbcbcbff, 0xcacacaff, 0xcdcdcdff, 0xc1c1c1ff, 0xb8b8b8ff, 0xa2a2a2ff, 0x777777ff, 0x707070ff, 0x727272ff, +0x747474ff, 0x676767ff, 0x5f5f5fff, 0xb2b2b2ff, 0xd3d3d3ff, 0xcbcbcbff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xc9c9c9ff, 0xd5d5d5ff, 0xecececff, 0xf4f4f4ff, 0xe6e6e6ff, 0xd5d5d5ff, 0xe6e6e6ff, 0xf0f0f0ff, 0xedededff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xedededff, 0xf5f5f5ff, 0xd7d7d7ff, 0x8f8f8fff, 0x838383ff, 0x888888ff, +0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x878787ff, 0x8a8a8aff, 0x818181ff, 0x4a4a4aff, 0x202020ff, 0x232323ff, 0x161616ff, 0x010101ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, +0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x682f0dff, 0xff8324ff, 0xff7921ff, 0xff7921ff, 0xff7921ff, 0xff7921ff, 0xff7921ff, 0xff7921ff, 0xff7921ff, 0xff7921ff, 0xff7921ff, 0xff7921ff, 0xff7921ff, 0xff7921ff, 0xff7921ff, 0xff7921ff, 0xff7821ff, 0xff7221ff, 0xff7021ff, 0xfd7121ff, 0xfc7620ff, 0xff8224ff, 0xb25617ff, 0x150902ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, +0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x0c0c0cff, 0x6c6c6cff, 0xc3c3c3ff, 0xd0d0d0ff, 0xd0d0d0ff, 0x8a8a8aff, 0x595959ff, 0x4c4c4cff, 0x404040ff, 0x444444ff, 0x444444ff, 0x444444ff, +0x444444ff, 0x3d3d3eff, 0x61614bff, 0x323287ff, 0x00009fff, 0x000098ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000098ff, 0x00009bff, +0x252592ff, 0x6c6c71ff, 0x8f8f8bff, 0x9e9e9eff, 0x7d7d7dff, 0x8a8a8aff, 0xb1b1b1ff, 0xc1c1c1ff, 0xcdcdcdff, 0xd8d8d8ff, 0xd5d5d5ff, 0xd1d1d1ff, 0xccccccff, 0xc6c6c6ff, 0xc6c6c6ff, 0xc4c4c4ff, 0xc5c5c5ff, 0xb5b5b5ff, 0xaaaaaaff, 0x919191ff, 0x7d7d7dff, 0x757575ff, 0x6f6f6fff, 0x717171ff, 0x727272ff, 0x747474ff, 0x6b6b6bff, 0x717171ff, 0x6d6d6dff, 0x6b6b6bff, 0x8f8f8fff, 0x989898ff, +0x999999ff, 0x868686ff, 0x676767ff, 0xb0b0b0ff, 0xd3d3d3ff, 0xcbcbcbff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xcacacaff, 0xcacacaff, 0xdfdfdfff, 0xe3e3e3ff, 0xe4e4e4ff, 0xe5e5e5ff, 0xebebebff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xedededff, 0xf5f5f5ff, 0xd7d7d7ff, 0x8f8f8fff, 0x838383ff, 0x888888ff, +0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x878787ff, 0x8a8a8aff, 0x818181ff, 0x4a4a4aff, 0x202020ff, 0x232323ff, 0x161616ff, 0x010101ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, +0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x69310cff, 0xff8225ff, 0xfa7321ff, 0xfa7421ff, 0xfa7421ff, 0xfa7421ff, 0xfa7421ff, 0xfa7421ff, 0xfa7421ff, 0xfa7421ff, 0xfa7421ff, 0xfa7421ff, 0xfa7421ff, 0xfa7421ff, 0xfa7421ff, 0xfa7421ff, 0xfa7421ff, 0xfb7721ff, 0xf76f22ff, 0xe4492aff, 0xd9392dff, 0xf04231ff, 0x9b2c1fff, 0x0e0403ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, +0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x0c0c0cff, 0x6c6c6cff, 0xc3c3c3ff, 0xd0d0d0ff, 0xd0d0d0ff, 0x8a8a8aff, 0x595959ff, 0x4c4c4cff, 0x404040ff, 0x444444ff, 0x444444ff, 0x444444ff, +0x444444ff, 0x3d3d3eff, 0x61614bff, 0x323287ff, 0x00009fff, 0x000098ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000098ff, 0x00009bff, +0x242491ff, 0x8f8f94ff, 0xc5c5c0ff, 0xc2c2c2ff, 0xb3b3b3ff, 0xb3b3b3ff, 0xbfbfbfff, 0xadadadff, 0x999999ff, 0x9f9f9fff, 0x999999ff, 0x8c8c8cff, 0x818181ff, 0x737373ff, 0x717171ff, 0x727272ff, 0x737373ff, 0x6b6b6bff, 0x666666ff, 0x666666ff, 0x6a6a6aff, 0x7f7f7fff, 0x8e8e8eff, 0x9c9c9cff, 0xa0a0a0ff, 0xa0a0a0ff, 0x9e9e9eff, 0xa4a4a4ff, 0xa7a7a7ff, 0xb7b7b7ff, 0xccccccff, 0xcacacaff, +0xcececeff, 0xb3b3b3ff, 0x737373ff, 0xaeaeaeff, 0xd3d3d3ff, 0xcbcbcbff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xcbcbcbff, 0xccccccff, 0xe3e3e3ff, 0xebebebff, 0xe6e6e6ff, 0xe2e2e2ff, 0xecececff, 0xefefefff, 0xedededff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xedededff, 0xf5f5f5ff, 0xd7d7d7ff, 0x8f8f8fff, 0x838383ff, 0x888888ff, +0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x878787ff, 0x8a8a8aff, 0x818181ff, 0x4a4a4aff, 0x202020ff, 0x232323ff, 0x161616ff, 0x010101ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, +0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x6c340dff, 0xff622dff, 0xd4312fff, 0xd9392dff, 0xd9382dff, 0xd9382dff, 0xd9382dff, 0xd9382dff, 0xd9382dff, 0xd9382dff, 0xd9382dff, 0xd9382dff, 0xd9382dff, 0xd9382dff, 0xd9382dff, 0xd9382dff, 0xd9382dff, 0xda3a2dff, 0xd8352eff, 0xcb2032ff, 0xc51734ff, 0xd51b38ff, 0x941327ff, 0x1b0308ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, +0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x0c0c0cff, 0x6c6c6cff, 0xc3c3c3ff, 0xd0d0d0ff, 0xd0d0d0ff, 0x8a8a8aff, 0x595959ff, 0x4c4c4cff, 0x404040ff, 0x444444ff, 0x444444ff, 0x444444ff, +0x444444ff, 0x3d3d3eff, 0x61614bff, 0x323287ff, 0x00009fff, 0x000098ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000098ff, 0x00009bff, +0x1f1f8cff, 0x757579ff, 0x858581ff, 0x7b7b7bff, 0x8b8b8bff, 0xa2a2a2ff, 0xa4a4a4ff, 0x959595ff, 0xabababff, 0xbebebeff, 0xb9b9b9ff, 0xb4b4b4ff, 0xafafafff, 0xa9a9a9ff, 0xa9a9a9ff, 0xa9a9a9ff, 0xaaaaaaff, 0xa7a7a7ff, 0xa6a6a6ff, 0xa7a7a7ff, 0xa9a9a9ff, 0xb2b2b2ff, 0xb8b8b8ff, 0xbebebeff, 0xbfbfbfff, 0xc2c2c2ff, 0xb6b6b6ff, 0xaeaeaeff, 0x999999ff, 0x777777ff, 0x707070ff, 0x6f6f6fff, +0x757575ff, 0x676767ff, 0x5f5f5fff, 0xb2b2b2ff, 0xd3d3d3ff, 0xcbcbcbff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xcbcbcbff, 0xcbcbcbff, 0xe0e0e0ff, 0xeeeeeeff, 0xe8e8e8ff, 0xe5e5e5ff, 0xe7e7e7ff, 0xecececff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xedededff, 0xf5f5f5ff, 0xd7d7d7ff, 0x8f8f8fff, 0x838383ff, 0x888888ff, +0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x878787ff, 0x8a8a8aff, 0x818181ff, 0x4a4a4aff, 0x202020ff, 0x232323ff, 0x161616ff, 0x010101ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, +0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x48150eff, 0xd32b31ff, 0xc91735ff, 0xc61a34ff, 0xc71a34ff, 0xc71a34ff, 0xc71a34ff, 0xc71a34ff, 0xc71a34ff, 0xc71a34ff, 0xc71a34ff, 0xc71a34ff, 0xc71a34ff, 0xc71a34ff, 0xc71a34ff, 0xc71a34ff, 0xc71a34ff, 0xc61a34ff, 0xc81b34ff, 0xca2033ff, 0xcb2233ff, 0xd02334ff, 0xce2130ff, 0x630f15ff, 0x010000ff, 0x000000ff, 0x000000ff, 0x000000ff, +0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x0c0c0cff, 0x6c6c6cff, 0xc3c3c3ff, 0xd0d0d0ff, 0xd0d0d0ff, 0x8a8a8aff, 0x595959ff, 0x4c4c4cff, 0x404040ff, 0x444444ff, 0x444444ff, 0x444444ff, +0x444444ff, 0x3d3d3eff, 0x61614bff, 0x323287ff, 0x00009fff, 0x000098ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000098ff, 0x00009bff, +0x262692ff, 0x7a7a7eff, 0x878784ff, 0x8f8f8fff, 0x8f8f8fff, 0xb2b2b2ff, 0xbebebeff, 0xb6b6b6ff, 0xc6c6c6ff, 0xcacacaff, 0xc3c3c3ff, 0xbfbfbfff, 0xb9b9b9ff, 0xb9b9b9ff, 0xbbbbbbff, 0xb8b8b8ff, 0xb8b8b8ff, 0xa8a8a8ff, 0x9c9c9cff, 0x858585ff, 0x747474ff, 0x6f6f6fff, 0x6d6d6dff, 0x717171ff, 0x727272ff, 0x737373ff, 0x6c6c6cff, 0x747474ff, 0x797979ff, 0x696969ff, 0x838383ff, 0xa4a4a4ff, +0xaeaeaeff, 0x979797ff, 0x6b6b6bff, 0xafafafff, 0xd3d3d3ff, 0xcbcbcbff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xcbcbcbff, 0xcfcfcfff, 0xd0d0d0ff, 0xd7d7d7ff, 0xe4e4e4ff, 0xd2d2d2ff, 0xd3d3d3ff, 0xe7e7e7ff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xedededff, 0xf5f5f5ff, 0xd7d7d7ff, 0x8f8f8fff, 0x838383ff, 0x888888ff, +0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x878787ff, 0x8a8a8aff, 0x818181ff, 0x4a4a4aff, 0x202020ff, 0x232323ff, 0x161616ff, 0x010101ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, +0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x020001ff, 0x781020ff, 0xe92634ff, 0xcc2029ff, 0xce202aff, 0xce202aff, 0xce202aff, 0xce202aff, 0xce202aff, 0xce202aff, 0xce202aff, 0xce202aff, 0xce202aff, 0xce202aff, 0xce202aff, 0xce202aff, 0xce202aff, 0xce202aff, 0xce202aff, 0xce202aff, 0xce202aff, 0xce1f27ff, 0xdf2539ff, 0x9d1b32ff, 0x180200ff, 0x000000ff, 0x000000ff, 0x000000ff, +0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x0c0c0cff, 0x6c6c6cff, 0xc3c3c3ff, 0xd0d0d0ff, 0xd0d0d0ff, 0x8a8a8aff, 0x595959ff, 0x4c4c4cff, 0x404040ff, 0x444444ff, 0x444444ff, 0x444444ff, +0x444444ff, 0x3d3d3eff, 0x61614bff, 0x323287ff, 0x00009fff, 0x000098ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000098ff, 0x00009bff, +0x272793ff, 0x76767cff, 0x8c8c89ff, 0xa5a5a5ff, 0x9c9c9cff, 0xa7a7a7ff, 0x909090ff, 0x787878ff, 0x797979ff, 0x747474ff, 0x6d6d6dff, 0x676767ff, 0x5f5f5fff, 0x5d5d5dff, 0x5b5b5bff, 0x656565ff, 0x757575ff, 0x6d6d6dff, 0x6a6a6aff, 0x6f6f6fff, 0x787878ff, 0x8f8f8fff, 0xa0a0a0ff, 0xacacacff, 0xb1b1b1ff, 0xb0b0b0ff, 0xb0b0b0ff, 0xb7b7b7ff, 0xc1c1c1ff, 0xc2c2c2ff, 0xcececeff, 0xdededeff, +0xe7e7e7ff, 0xc9c9c9ff, 0x777777ff, 0xacacacff, 0xd3d3d3ff, 0xcbcbcbff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xcacacaff, 0xc7c7c7ff, 0xcfcfcfff, 0xe2e2e2ff, 0xd5d5d5ff, 0xcececeff, 0xdededeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xedededff, 0xf5f5f5ff, 0xd7d7d7ff, 0x8f8f8fff, 0x838383ff, 0x888888ff, +0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x878787ff, 0x8a8a8aff, 0x818181ff, 0x4a4a4aff, 0x202020ff, 0x232323ff, 0x161616ff, 0x010101ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, +0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x370808ff, 0xd02648ff, 0xcf2857ff, 0xc3244aff, 0xc4244cff, 0xc4244cff, 0xc4244cff, 0xc4244cff, 0xc4244cff, 0xc4244cff, 0xc4244cff, 0xc4244cff, 0xc4244cff, 0xc4244cff, 0xc4244cff, 0xc4244cff, 0xc4244cff, 0xc4244cff, 0xc4244cff, 0xc4244cff, 0xc62346ff, 0xbe2a69ff, 0xb92c7eff, 0x781a3fff, 0x0b030dff, 0x000000ff, 0x000000ff, +0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x0c0c0cff, 0x6c6c6cff, 0xc3c3c3ff, 0xd0d0d0ff, 0xd0d0d0ff, 0x8a8a8aff, 0x595959ff, 0x4c4c4cff, 0x404040ff, 0x444444ff, 0x444444ff, 0x444444ff, +0x444444ff, 0x3d3d3eff, 0x61614bff, 0x323287ff, 0x00009fff, 0x000098ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000098ff, 0x00009cff, +0x1f1f8cff, 0x58585dff, 0x4e4e4aff, 0x606060ff, 0x6f6f6fff, 0x6c6c6cff, 0x626262ff, 0x5d5d5dff, 0x656565ff, 0x6d6d6dff, 0x767676ff, 0x808080ff, 0x8a8a8aff, 0x8d8d8dff, 0x878787ff, 0x9e9e9eff, 0xbfbfbfff, 0xc0c0c0ff, 0xc1c1c1ff, 0xc7c7c7ff, 0xcececeff, 0xd7d7d7ff, 0xddddddff, 0xdededeff, 0xe0e0e0ff, 0xe0e0e0ff, 0xe3e3e3ff, 0xd5d5d5ff, 0xc4c4c4ff, 0xc5c5c5ff, 0xb9b9b9ff, 0xa5a5a5ff, +0x9f9f9fff, 0x8a8a8aff, 0x686868ff, 0xb0b0b0ff, 0xd3d3d3ff, 0xcbcbcbff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xcacacaff, 0xd0d0d0ff, 0xe9e9e9ff, 0xeeeeeeff, 0xe9e9e9ff, 0xeaeaeaff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xedededff, 0xf5f5f5ff, 0xd7d7d7ff, 0x8f8f8fff, 0x838383ff, 0x888888ff, +0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x878787ff, 0x8a8a8aff, 0x818181ff, 0x4a4a4aff, 0x202020ff, 0x232323ff, 0x161616ff, 0x010101ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, +0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x040000ff, 0x481239ff, 0xaf32a2ff, 0xb834abff, 0xaa309eff, 0xab319fff, 0xab319fff, 0xab319fff, 0xab319fff, 0xab319fff, 0xab319fff, 0xab319fff, 0xab319fff, 0xab319fff, 0xab319fff, 0xab319fff, 0xab319fff, 0xab319fff, 0xab319fff, 0xab31a0ff, 0xab309eff, 0xa831a5ff, 0xae33acff, 0xb533a9ff, 0x762379ff, 0x170717ff, 0x000000ff, +0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x0c0c0cff, 0x6c6c6cff, 0xc3c3c3ff, 0xd0d0d0ff, 0xd0d0d0ff, 0x8a8a8aff, 0x595959ff, 0x4c4c4cff, 0x404040ff, 0x444444ff, 0x444444ff, 0x444444ff, +0x444444ff, 0x3d3d3eff, 0x61614bff, 0x323287ff, 0x00009fff, 0x000098ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000098ff, 0x00009cff, +0x1f1f8dff, 0x6f6f72ff, 0x73736fff, 0x838384ff, 0xa0a0a0ff, 0x9e9e9eff, 0xa2a2a2ff, 0xaeaeaeff, 0xc4c4c4ff, 0xcfcfcfff, 0xd3d3d3ff, 0xd7d7d7ff, 0xdadadaff, 0xdbdbdbff, 0xd9d9d9ff, 0xe0e0e0ff, 0xd3d3d3ff, 0xc0c0c0ff, 0xc4c4c4ff, 0xb9b9b9ff, 0xaeaeaeff, 0xa2a2a2ff, 0x9a9a9aff, 0x979797ff, 0x939393ff, 0x919191ff, 0x979797ff, 0x808080ff, 0x616161ff, 0x6e6e6eff, 0x676767ff, 0x565656ff, +0x6c6c6cff, 0x696969ff, 0x5f5f5fff, 0xb2b2b2ff, 0xd3d3d3ff, 0xcbcbcbff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xc9c9c9ff, 0xd1d1d1ff, 0xe7e7e7ff, 0xe9e9e9ff, 0xedededff, 0xefefefff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xedededff, 0xf5f5f5ff, 0xd7d7d7ff, 0x8f8f8fff, 0x838383ff, 0x888888ff, +0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x878787ff, 0x8a8a8aff, 0x818181ff, 0x4a4a4aff, 0x202020ff, 0x232323ff, 0x161616ff, 0x010101ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, +0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000004ff, 0x421548ff, 0xab33b0ff, 0xbf3ab6ff, 0xb938a8ff, 0xb938aaff, 0xb938aaff, 0xb938aaff, 0xb938aaff, 0xb938aaff, 0xb938aaff, 0xb938aaff, 0xb938aaff, 0xb938aaff, 0xb938aaff, 0xb938aaff, 0xb938aaff, 0xb938aaff, 0xb938aaff, 0xb938aaff, 0xba38a8ff, 0xb938a6ff, 0xc53bb3ff, 0xab329fff, 0x2a0e2bff, 0x000000ff, +0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x0c0c0cff, 0x6c6c6cff, 0xc3c3c3ff, 0xd0d0d0ff, 0xd0d0d0ff, 0x8a8a8aff, 0x595959ff, 0x4c4c4cff, 0x404040ff, 0x444444ff, 0x444444ff, 0x444444ff, +0x444444ff, 0x3d3d3eff, 0x61614bff, 0x323287ff, 0x00009fff, 0x000098ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000098ff, 0x00009bff, +0x242491ff, 0x8e8e92ff, 0xb5b5b0ff, 0xbdbdbdff, 0xbfbfbfff, 0xb3b3b3ff, 0xa9a9a9ff, 0xb9b9b9ff, 0xbebebeff, 0xa7a7a7ff, 0x989898ff, 0x8f8f8fff, 0x8b8b8bff, 0x8c8c8cff, 0x8c8c8cff, 0x909090ff, 0x757575ff, 0x585858ff, 0x5d5d5dff, 0x4f4f4fff, 0x4e4e4eff, 0x4a4a4aff, 0x4a4a4aff, 0x595959ff, 0x6e6e6eff, 0x737373ff, 0x727272ff, 0x717171ff, 0x717171ff, 0x868686ff, 0x939393ff, 0xa1a1a1ff, +0xd2d2d2ff, 0xc6c6c6ff, 0x777777ff, 0xadadadff, 0xd3d3d3ff, 0xcbcbcbff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xcacacaff, 0xcfcfcfff, 0xd5d5d5ff, 0xd4d4d4ff, 0xe8e8e8ff, 0xefefefff, 0xedededff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xedededff, 0xf5f5f5ff, 0xd7d7d7ff, 0x8f8f8fff, 0x838383ff, 0x888888ff, +0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x878787ff, 0x8a8a8aff, 0x818181ff, 0x4a4a4aff, 0x202020ff, 0x232323ff, 0x161616ff, 0x010101ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, +0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x020100ff, 0x441444ff, 0x7522b4ff, 0x6a1fc3ff, 0x6b1fb4ff, 0x6b1fb5ff, 0x6b1fb5ff, 0x6b1fb5ff, 0x6b1fb5ff, 0x6b1fb5ff, 0x6b1fb5ff, 0x6b1fb5ff, 0x6b1fb5ff, 0x6b1fb5ff, 0x6b1fb5ff, 0x6b1fb5ff, 0x6b1fb5ff, 0x6b1fb5ff, 0x6b1fb5ff, 0x6b1fb6ff, 0x6a1fb3ff, 0x7523d4ff, 0x3e1275ff, 0x010000ff, 0x000000ff, +0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x0c0c0cff, 0x6c6c6cff, 0xc3c3c3ff, 0xd0d0d0ff, 0xd0d0d0ff, 0x8a8a8aff, 0x595959ff, 0x4c4c4cff, 0x404040ff, 0x444444ff, 0x444444ff, 0x444444ff, +0x444444ff, 0x3d3d3eff, 0x61614bff, 0x323287ff, 0x00009fff, 0x000098ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000098ff, 0x00009bff, +0x232392ff, 0x8c8c91ff, 0xb7b7b2ff, 0xc2c2c2ff, 0xc2c2c2ff, 0xb2b2b2ff, 0xa6a6a6ff, 0xb5b5b5ff, 0xb4b4b4ff, 0x939393ff, 0x818181ff, 0x757575ff, 0x717171ff, 0x717171ff, 0x717171ff, 0x717171ff, 0x777777ff, 0x7f7f7fff, 0x7e7e7eff, 0x838383ff, 0x949494ff, 0xa4a4a4ff, 0xb0b0b0ff, 0xc1c1c1ff, 0xdfdfdfff, 0xe6e6e6ff, 0xe4e4e4ff, 0xe9e9e9ff, 0xd4d4d4ff, 0xbababaff, 0xafafafff, 0xa5a5a5ff, +0x979797ff, 0x797979ff, 0x636363ff, 0xb1b1b1ff, 0xd3d3d3ff, 0xcbcbcbff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xcbcbcbff, 0xcacacaff, 0xcbcbcbff, 0xe0e0e0ff, 0xefefefff, 0xefefefff, 0xedededff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xedededff, 0xf5f5f5ff, 0xd7d7d7ff, 0x8f8f8fff, 0x838383ff, 0x888888ff, +0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x878787ff, 0x8a8a8aff, 0x818181ff, 0x4a4a4aff, 0x202020ff, 0x232323ff, 0x161616ff, 0x010101ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, +0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000002ff, 0x010055ff, 0x0000d0ff, 0x0000dbff, 0x0000ccff, 0x0000cdff, 0x0000ceff, 0x0000ceff, 0x0000ceff, 0x0000cdff, 0x0000cdff, 0x0000ccff, 0x0000ccff, 0x0000cdff, 0x0000cdff, 0x0000cdff, 0x0000ceff, 0x0000cdff, 0x0000ccff, 0x0000e0ff, 0x0100caff, 0x00003bff, 0x000000ff, 0x000000ff, +0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x0c0c0cff, 0x6c6c6cff, 0xc3c3c3ff, 0xd0d0d0ff, 0xd0d0d0ff, 0x8a8a8aff, 0x595959ff, 0x4c4c4cff, 0x404040ff, 0x444444ff, 0x444444ff, 0x444444ff, +0x444444ff, 0x3d3d3eff, 0x61614bff, 0x323287ff, 0x00009fff, 0x000098ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000098ff, 0x00009bff, +0x232391ff, 0x8e8e92ff, 0xadada8ff, 0xa5a5a5ff, 0xa5a5a5ff, 0xa7a7a7ff, 0xa8a8a8ff, 0xb9b9b9ff, 0xd6d6d6ff, 0xe3e3e3ff, 0xe6e6e6ff, 0xeaeaeaff, 0xebebebff, 0xebebebff, 0xebebebff, 0xf0f0f0ff, 0xd7d7d7ff, 0xbdbdbdff, 0xc2c2c2ff, 0xb2b2b2ff, 0xa3a3a3ff, 0x959595ff, 0x8c8c8cff, 0x858585ff, 0x7d7d7dff, 0x797979ff, 0x797979ff, 0x7e7e7eff, 0x646464ff, 0x565656ff, 0x575757ff, 0x4a4a4aff, +0x525252ff, 0x5f5f5fff, 0x626262ff, 0xb2b2b2ff, 0xd3d3d3ff, 0xcbcbcbff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xcacacaff, 0xcfcfcfff, 0xdbdbdbff, 0xe3e3e3ff, 0xecececff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xedededff, 0xf5f5f5ff, 0xd7d7d7ff, 0x8f8f8fff, 0x838383ff, 0x888888ff, +0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x878787ff, 0x8a8a8aff, 0x818181ff, 0x4a4a4aff, 0x202020ff, 0x232323ff, 0x161616ff, 0x010101ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, +0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000052ff, 0x0000d4ff, 0x0000e6ff, 0x0000cfff, 0x0000ccff, 0x0000ccff, 0x0000ccff, 0x0000cbff, 0x0000d9ff, 0x0000e6ff, 0x0000e5ff, 0x0000e2ff, 0x0000d4ff, 0x0000cbff, 0x0000ccff, 0x0000cbff, 0x0000ddff, 0x0000c5ff, 0x000036ff, 0x000000ff, 0x000000ff, 0x000000ff, +0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x0a0a0aff, 0x6c6c6cff, 0xc3c3c3ff, 0xd0d0d0ff, 0xd0d0d0ff, 0x8a8a8aff, 0x595959ff, 0x4c4c4cff, 0x404040ff, 0x444444ff, 0x444444ff, 0x444444ff, +0x444444ff, 0x3d3d3eff, 0x61614bff, 0x323287ff, 0x00009fff, 0x000098ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000098ff, 0x00009bff, +0x252591ff, 0x909095ff, 0xb1b1aeff, 0xb1b1b1ff, 0xb1b1b1ff, 0xb1b1b1ff, 0xb1b1b1ff, 0xacacacff, 0x9a9a9aff, 0x8b8b8bff, 0x7e7e7eff, 0x777777ff, 0x767676ff, 0x767676ff, 0x767676ff, 0x797979ff, 0x606060ff, 0x474747ff, 0x4c4c4cff, 0x4e4e4eff, 0x4c4c4cff, 0x424242ff, 0x494949ff, 0x5c5c5cff, 0x787878ff, 0x808080ff, 0x7d7d7dff, 0x7d7d7dff, 0x7f7f7fff, 0x939393ff, 0xa1a1a1ff, 0x9e9e9eff, +0xbababaff, 0xbfbfbfff, 0x797979ff, 0xacacacff, 0xd3d3d3ff, 0xcbcbcbff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xc9c9c9ff, 0xc2c2c2ff, 0xcfcfcfff, 0xecececff, 0xeeeeeeff, 0xedededff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xedededff, 0xf5f5f5ff, 0xd7d7d7ff, 0x8f8f8fff, 0x838383ff, 0x888888ff, +0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x878787ff, 0x8a8a8aff, 0x818181ff, 0x4a4a4aff, 0x202020ff, 0x232323ff, 0x161616ff, 0x010101ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, +0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000002ff, 0x000036ff, 0x000079ff, 0x0000cbff, 0x0000e1ff, 0x0000dbff, 0x0000dbff, 0x0000ebff, 0x000097ff, 0x000049ff, 0x000056ff, 0x00005eff, 0x0000b8ff, 0x0000e5ff, 0x0000dbff, 0x0000e5ff, 0x0000c0ff, 0x000033ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, +0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x010101ff, 0x181818ff, 0x6b6b6bff, 0xc3c3c3ff, 0xd0d0d0ff, 0xd0d0d0ff, 0x8a8a8aff, 0x595959ff, 0x4c4c4cff, 0x404040ff, 0x444444ff, 0x444444ff, 0x444444ff, +0x444444ff, 0x3d3d3eff, 0x61614bff, 0x323287ff, 0x00009fff, 0x000098ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000098ff, 0x00009cff, +0x1d1d8aff, 0x7c7c81ff, 0x868681ff, 0x656565ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x636363ff, 0x4c4c4cff, 0x4b4b4bff, 0x474747ff, 0x484848ff, 0x585858ff, 0x5b5b5bff, 0x565656ff, 0x6c6c6cff, 0x909090ff, 0x919191ff, 0x909090ff, 0xa0a0a0ff, 0xaaaaaaff, 0xacacacff, 0xb8b8b8ff, 0xc6c6c6ff, 0xdcdcdcff, 0xe1e1e1ff, 0xe0e0e0ff, 0xe0e0e0ff, 0xe0e0e0ff, 0xddddddff, 0xdbdbdbff, 0xdbdbdbff, +0xddddddff, 0xbababaff, 0x737373ff, 0xadadadff, 0xd3d3d3ff, 0xcbcbcbff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xcacacaff, 0xcfcfcfff, 0xdededeff, 0xe5e5e5ff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xedededff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xedededff, 0xf5f5f5ff, 0xd7d7d7ff, 0x8f8f8fff, 0x838383ff, 0x888888ff, +0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x878787ff, 0x8a8a8aff, 0x818181ff, 0x4a4a4aff, 0x202020ff, 0x232323ff, 0x161616ff, 0x010101ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, +0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000004ff, 0x000041ff, 0x000054ff, 0x00004fff, 0x00004fff, 0x00005bff, 0x000018ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000031ff, 0x000056ff, 0x00004fff, 0x000057ff, 0x00002fff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, +0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x090909ff, 0x242424ff, 0x6b6b6bff, 0xc3c3c3ff, 0xd0d0d0ff, 0xd0d0d0ff, 0x8a8a8aff, 0x595959ff, 0x4c4c4cff, 0x404040ff, 0x444444ff, 0x444444ff, 0x444444ff, +0x444444ff, 0x3d3d3eff, 0x61614bff, 0x323287ff, 0x00009fff, 0x000098ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000098ff, 0x00009dff, +0x171785ff, 0x76767cff, 0x969692ff, 0x7e7e7fff, 0x7f7f7fff, 0x7e7e7eff, 0x8f8f8fff, 0x9a9a9aff, 0x9c9c9cff, 0xabababff, 0xb1b1b1ff, 0xb4b4b4ff, 0xbebebeff, 0xc0c0c0ff, 0xbcbcbcff, 0xcbcbcbff, 0xdcdcdcff, 0xd6d6d6ff, 0xd7d7d7ff, 0xd3d3d3ff, 0xd1d1d1ff, 0xd0d0d0ff, 0xcdcdcdff, 0xc9c9c9ff, 0xc5c5c5ff, 0xc3c3c3ff, 0xc4c4c4ff, 0xc3c3c3ff, 0xc9c9c9ff, 0xabababff, 0x939393ff, 0x989898ff, +0x8d8d8dff, 0x767676ff, 0x646464ff, 0xb2b2b2ff, 0xd3d3d3ff, 0xcbcbcbff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xc9c9c9ff, 0xd4d4d4ff, 0xe4e4e4ff, 0xe3e3e3ff, 0xedededff, 0xeeeeeeff, 0xecececff, 0xeeeeeeff, 0xedededff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xedededff, 0xf5f5f5ff, 0xd7d7d7ff, 0x8f8f8fff, 0x838383ff, 0x888888ff, +0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x878787ff, 0x8a8a8aff, 0x818181ff, 0x4a4a4aff, 0x202020ff, 0x232323ff, 0x161616ff, 0x010101ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, +0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, +0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x070707ff, 0x212121ff, 0x6a6a6aff, 0xc3c3c3ff, 0xd0d0d0ff, 0xd0d0d0ff, 0x8a8a8aff, 0x595959ff, 0x4c4c4cff, 0x404040ff, 0x444444ff, 0x444444ff, 0x444444ff, +0x444444ff, 0x3d3d3eff, 0x61614bff, 0x323287ff, 0x00009fff, 0x000098ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000098ff, 0x00009cff, +0x1f1f8cff, 0x818185ff, 0xa8a8a4ff, 0xa9a9a9ff, 0xa8a8a8ff, 0xa6a6a6ff, 0xbdbdbdff, 0xcececeff, 0xcbcbcbff, 0xcbcbcbff, 0xcacacaff, 0xccccccff, 0xcacacaff, 0xcacacaff, 0xc9c9c9ff, 0xcfcfcfff, 0xb6b6b6ff, 0x989898ff, 0x9e9e9eff, 0x8f8f8fff, 0x878787ff, 0x858585ff, 0x777777ff, 0x717171ff, 0x727272ff, 0x727272ff, 0x727272ff, 0x727272ff, 0x757575ff, 0x636363ff, 0x575757ff, 0x696969ff, +0x6f6f6fff, 0x676767ff, 0x636363ff, 0xb2b2b2ff, 0xd3d3d3ff, 0xcbcbcbff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xcacacaff, 0xcececeff, 0xcdcdcdff, 0xd3d3d3ff, 0xebebebff, 0xe1e1e1ff, 0xdfdfdfff, 0xf0f0f0ff, 0xedededff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xedededff, 0xf5f5f5ff, 0xd7d7d7ff, 0x8f8f8fff, 0x838383ff, 0x888888ff, +0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x878787ff, 0x8a8a8aff, 0x818181ff, 0x4a4a4aff, 0x202020ff, 0x232323ff, 0x161616ff, 0x010101ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, +0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, +0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x070707ff, 0x222222ff, 0x6e6e6eff, 0xc5c5c5ff, 0xd0d0d0ff, 0xd0d0d0ff, 0x8a8a8aff, 0x595959ff, 0x4c4c4cff, 0x404040ff, 0x444444ff, 0x444444ff, 0x444444ff, +0x444444ff, 0x3d3d3eff, 0x61614bff, 0x323287ff, 0x00009fff, 0x000098ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000098ff, 0x00009dff, +0x181886ff, 0x5c5c60ff, 0x6a6a66ff, 0x666666ff, 0x666666ff, 0x656565ff, 0x6d6d6dff, 0x747474ff, 0x818181ff, 0x878787ff, 0x8b8b8bff, 0x9b9b9bff, 0x9e9e9eff, 0x9e9e9eff, 0x989898ff, 0xb3b3b3ff, 0xc7c7c7ff, 0xb6b6b6ff, 0xb9b9b9ff, 0xb2b2b2ff, 0xafafafff, 0xafafafff, 0xa9a9a9ff, 0xa7a7a7ff, 0xa7a7a7ff, 0xa7a7a7ff, 0xa7a7a7ff, 0xa7a7a7ff, 0xa7a7a7ff, 0xacacacff, 0xa6a6a6ff, 0xa8a8a8ff, +0xb5b5b5ff, 0x9e9e9eff, 0x6e6e6eff, 0xafafafff, 0xd3d3d3ff, 0xcbcbcbff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xcbcbcbff, 0xc8c8c8ff, 0xcbcbcbff, 0xd3d3d3ff, 0xdadadaff, 0xe7e7e7ff, 0xefefefff, 0xedededff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xedededff, 0xf5f5f5ff, 0xd7d7d7ff, 0x8f8f8fff, 0x838383ff, 0x888888ff, +0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x878787ff, 0x8a8a8aff, 0x818181ff, 0x4a4a4aff, 0x202020ff, 0x232323ff, 0x161616ff, 0x010101ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, +0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, +0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x040404ff, 0x2c2c2cff, 0x868686ff, 0xcececeff, 0xcececeff, 0xd0d0d0ff, 0x8a8a8aff, 0x595959ff, 0x4c4c4cff, 0x404040ff, 0x444444ff, 0x444444ff, 0x444444ff, +0x444444ff, 0x3d3d3eff, 0x61614bff, 0x323287ff, 0x00009fff, 0x000098ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000098ff, 0x00009eff, +0x141482ff, 0x67676aff, 0x91918dff, 0x8e8e8eff, 0x8d8d8dff, 0x8e8e8eff, 0xa4a4a4ff, 0xb2b2b2ff, 0xb6b6b6ff, 0xb9b9b9ff, 0xbbbbbbff, 0xc1c1c1ff, 0xc3c3c3ff, 0xc3c3c3ff, 0xc0c0c0ff, 0xcbcbcbff, 0xd3d3d3ff, 0xc9c9c9ff, 0xcbcbcbff, 0xc5c5c5ff, 0xc3c3c3ff, 0xc4c4c4ff, 0xbebebeff, 0xbcbcbcff, 0xbbbbbbff, 0xb8b8b8ff, 0xb7b7b7ff, 0xb7b7b7ff, 0xb7b7b7ff, 0xbababaff, 0x9c9c9cff, 0x858585ff, +0x8e8e8eff, 0x727272ff, 0x5f5f5fff, 0xb2b2b2ff, 0xd3d3d3ff, 0xcbcbcbff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xcacacaff, 0xc8c8c8ff, 0xd4d4d4ff, 0xeaeaeaff, 0xf2f2f2ff, 0xefefefff, 0xedededff, 0xeeeeeeff, 0xeeeeeeff, 0xeeeeeeff, 0xedededff, 0xf5f5f5ff, 0xd7d7d7ff, 0x8f8f8fff, 0x838383ff, 0x888888ff, +0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x878787ff, 0x8a8a8aff, 0x818181ff, 0x4a4a4aff, 0x202020ff, 0x232323ff, 0x161616ff, 0x010101ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, +0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, +0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x030303ff, 0x313131ff, 0x898989ff, 0xcacacaff, 0xcececeff, 0xd0d0d0ff, 0x8a8a8aff, 0x595959ff, 0x4c4c4cff, 0x404040ff, 0x444444ff, 0x444444ff, 0x444444ff, +0x444444ff, 0x3d3d3eff, 0x61614bff, 0x323287ff, 0x00009fff, 0x000098ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000098ff, 0x00009cff, +0x1c1c89ff, 0x86868bff, 0xbcbcb8ff, 0xb9b9b9ff, 0xbbbbbbff, 0xacacacff, 0xb5b5b5ff, 0xc4c4c4ff, 0xb6b6b6ff, 0xb1b1b1ff, 0xb1b1b1ff, 0xaeaeaeff, 0xaeaeaeff, 0xaeaeaeff, 0xaeaeaeff, 0xafafafff, 0x8f8f8fff, 0x727272ff, 0x787878ff, 0x6f6f6fff, 0x6b6b6bff, 0x686868ff, 0x5a5a5aff, 0x5a5a5aff, 0x646464ff, 0x717171ff, 0x727272ff, 0x727272ff, 0x727272ff, 0x737373ff, 0x696969ff, 0x636363ff, +0x767676ff, 0x6c6c6cff, 0x5f5f5fff, 0xb2b2b2ff, 0xd3d3d3ff, 0xcbcbcbff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xcbcbcbff, 0xcbcbcbff, 0xdadadaff, 0xeeeeeeff, 0xebebebff, 0xe1e1e1ff, 0xe8e8e8ff, 0xefefefff, 0xedededff, 0xeeeeeeff, 0xeeeeeeff, 0xedededff, 0xf5f5f5ff, 0xd7d7d7ff, 0x8f8f8fff, 0x838383ff, 0x888888ff, +0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x878787ff, 0x8a8a8aff, 0x818181ff, 0x4a4a4aff, 0x202020ff, 0x232323ff, 0x161616ff, 0x010101ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, +0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, +0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x030303ff, 0x2d2d2dff, 0x8e8e8eff, 0xd1d1d1ff, 0xcdcdcdff, 0xd0d0d0ff, 0x8a8a8aff, 0x595959ff, 0x4c4c4cff, 0x404040ff, 0x444444ff, 0x444444ff, 0x444444ff, +0x444444ff, 0x3d3d3eff, 0x61614bff, 0x323287ff, 0x00009fff, 0x000098ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000098ff, 0x00009cff, +0x1e1e8bff, 0x737377ff, 0x898985ff, 0x858585ff, 0x898989ff, 0x6b6b6bff, 0x555555ff, 0x626262ff, 0x5a5a5aff, 0x555555ff, 0x5f5f5fff, 0x606060ff, 0x5c5c5cff, 0x5b5b5bff, 0x585858ff, 0x666666ff, 0x707070ff, 0x666666ff, 0x686868ff, 0x747474ff, 0x7b7b7bff, 0x787878ff, 0x797979ff, 0x848484ff, 0x969696ff, 0xb4b4b4ff, 0xb7b7b7ff, 0xb7b7b7ff, 0xb7b7b7ff, 0xb7b7b7ff, 0xb9b9b9ff, 0xbbbbbbff, +0xc8c8c8ff, 0xb3b3b3ff, 0x737373ff, 0xaeaeaeff, 0xd3d3d3ff, 0xcbcbcbff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xcacacaff, 0xd0d0d0ff, 0xe0e0e0ff, 0xedededff, 0xe6e6e6ff, 0xd2d2d2ff, 0xe2e2e2ff, 0xf0f0f0ff, 0xedededff, 0xeeeeeeff, 0xeeeeeeff, 0xedededff, 0xf5f5f5ff, 0xd7d7d7ff, 0x8f8f8fff, 0x838383ff, 0x888888ff, +0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x878787ff, 0x8a8a8aff, 0x818181ff, 0x4a4a4aff, 0x202020ff, 0x232323ff, 0x161616ff, 0x010101ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, +0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, +0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x030303ff, 0x313131ff, 0x989898ff, 0xd6d6d6ff, 0xcdcdcdff, 0xd0d0d0ff, 0x8a8a8aff, 0x595959ff, 0x4c4c4cff, 0x404040ff, 0x444444ff, 0x444444ff, 0x444444ff, +0x444444ff, 0x3d3d3eff, 0x61614bff, 0x323287ff, 0x00009fff, 0x000098ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000098ff, 0x00009eff, +0x131382ff, 0x545458ff, 0x686865ff, 0x666666ff, 0x676767ff, 0x5f5f5fff, 0x646464ff, 0x787878ff, 0x6a6a6aff, 0x616161ff, 0x717171ff, 0x7e7e7eff, 0x909090ff, 0x959595ff, 0x8e8e8eff, 0xa5a5a5ff, 0xc9c9c9ff, 0xcacacaff, 0xcacacaff, 0xcdcdcdff, 0xd1d1d1ff, 0xd2d2d2ff, 0xd6d6d6ff, 0xd8d8d8ff, 0xdcdcdcff, 0xe0e0e0ff, 0xe0e0e0ff, 0xe0e0e0ff, 0xe0e0e0ff, 0xe0e0e0ff, 0xe0e0e0ff, 0xdfdfdfff, +0xd0d0d0ff, 0xabababff, 0x717171ff, 0xaeaeaeff, 0xd3d3d3ff, 0xcbcbcbff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xcbcbcbff, 0xccccccff, 0xcacacaff, 0xd0d0d0ff, 0xe5e5e5ff, 0xecececff, 0xecececff, 0xeeeeeeff, 0xedededff, 0xeeeeeeff, 0xeeeeeeff, 0xedededff, 0xf5f5f5ff, 0xd7d7d7ff, 0x8f8f8fff, 0x838383ff, 0x888888ff, +0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x878787ff, 0x8a8a8aff, 0x818181ff, 0x4a4a4aff, 0x202020ff, 0x232323ff, 0x161616ff, 0x010101ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, +0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, +0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x424242ff, 0xafafafff, 0xd2d2d2ff, 0xcdcdcdff, 0xd0d0d0ff, 0x8a8a8aff, 0x595959ff, 0x4c4c4cff, 0x404040ff, 0x444444ff, 0x444444ff, 0x444444ff, +0x444444ff, 0x3d3d3eff, 0x61614bff, 0x323287ff, 0x00009fff, 0x000098ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000098ff, 0x00009bff, +0x1e1e8cff, 0x86868bff, 0xb5b5b1ff, 0xb3b3b3ff, 0xb0b0b0ff, 0xbcbcbcff, 0xd3d3d3ff, 0xd8d8d8ff, 0xb9b9b9ff, 0xa8a8a8ff, 0xa8a8a8ff, 0xb4b4b4ff, 0xd1d1d1ff, 0xd8d8d8ff, 0xd1d1d1ff, 0xd2d2d2ff, 0xc1c1c1ff, 0xabababff, 0xb0b0b0ff, 0xafafafff, 0xa4a4a4ff, 0x9b9b9bff, 0x929292ff, 0x8d8d8dff, 0x8d8d8dff, 0x8c8c8cff, 0x8b8b8bff, 0x8b8b8bff, 0x8b8b8bff, 0x8b8b8bff, 0x8c8c8cff, 0x8a8a8aff, +0x6e6e6eff, 0x535353ff, 0x5c5c5cff, 0xb3b3b3ff, 0xd3d3d3ff, 0xcbcbcbff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xcacacaff, 0xcececeff, 0xd9d9d9ff, 0xddddddff, 0xe7e7e7ff, 0xf2f2f2ff, 0xf1f1f1ff, 0xefefefff, 0xedededff, 0xedededff, 0xedededff, 0xf5f5f5ff, 0xd7d7d7ff, 0x8f8f8fff, 0x838383ff, 0x888888ff, +0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x878787ff, 0x8a8a8aff, 0x818181ff, 0x4a4a4aff, 0x202020ff, 0x232323ff, 0x161616ff, 0x010101ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, +0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, +0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x4c4c4cff, 0xc0c0c0ff, 0xd0d0d0ff, 0xcdcdcdff, 0xd0d0d0ff, 0x8a8a8aff, 0x595959ff, 0x4c4c4cff, 0x404040ff, 0x444444ff, 0x444444ff, 0x444444ff, +0x444444ff, 0x3d3d3eff, 0x61614bff, 0x323287ff, 0x00009fff, 0x000098ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000098ff, 0x00009dff, +0x1b1b89ff, 0x68686dff, 0x797975ff, 0x757576ff, 0x737373ff, 0x7e7e7eff, 0x999999ff, 0xa3a3a3ff, 0xa1a1a1ff, 0xa5a5a5ff, 0xaeaeaeff, 0xadadadff, 0xa9a9a9ff, 0xa5a5a5ff, 0xb5b5b5ff, 0xd2d2d2ff, 0xb5b5b5ff, 0x989898ff, 0x9e9e9eff, 0x9e9e9eff, 0x909090ff, 0x838383ff, 0x777777ff, 0x717171ff, 0x717171ff, 0x717171ff, 0x717171ff, 0x717171ff, 0x717171ff, 0x717171ff, 0x717171ff, 0x717171ff, +0x777777ff, 0x6e6e6eff, 0x626262ff, 0xb2b2b2ff, 0xd3d3d3ff, 0xcbcbcbff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xcacacaff, 0xd1d1d1ff, 0xe3e3e3ff, 0xd5d5d5ff, 0xd9d9d9ff, 0xe7e7e7ff, 0xdbdbdbff, 0xebebebff, 0xf4f4f4ff, 0xf1f1f1ff, 0xefefefff, 0xf7f7f7ff, 0xd7d7d7ff, 0x8f8f8fff, 0x838383ff, 0x888888ff, +0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x878787ff, 0x8a8a8aff, 0x818181ff, 0x4a4a4aff, 0x202020ff, 0x232323ff, 0x161616ff, 0x010101ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, +0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, +0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x030303ff, 0x575757ff, 0xbebebeff, 0xcfcfcfff, 0xcdcdcdff, 0xd0d0d0ff, 0x8a8a8aff, 0x595959ff, 0x4c4c4cff, 0x404040ff, 0x444444ff, 0x444444ff, 0x444444ff, +0x444444ff, 0x3d3d3eff, 0x61614bff, 0x323287ff, 0x00009fff, 0x000098ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000098ff, 0x00009dff, +0x191986ff, 0x5d5d60ff, 0x6b6b66ff, 0x676767ff, 0x646464ff, 0x707070ff, 0x6a6a6aff, 0x5e5e5eff, 0x616161ff, 0x626262ff, 0x7a7a7aff, 0x9a9a9aff, 0xa1a1a1ff, 0x9b9b9bff, 0xb3b3b3ff, 0xd6d6d6ff, 0xd8d8d8ff, 0xdbdbdbff, 0xdbdbdbff, 0xddddddff, 0xe1e1e1ff, 0xe2e2e2ff, 0xe6e6e6ff, 0xeaeaeaff, 0xebebebff, 0xebebebff, 0xebebebff, 0xebebebff, 0xebebebff, 0xebebebff, 0xebebebff, 0xebebebff, +0xedededff, 0xb8b8b8ff, 0x6f6f6fff, 0xafafafff, 0xd3d3d3ff, 0xcbcbcbff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xcacacaff, 0xc7c7c7ff, 0xc4c4c4ff, 0xdcdcdcff, 0xebebebff, 0xcacacaff, 0xd2d2d2ff, 0xdfdfdfff, 0xddddddff, 0xe5e5e5ff, 0xecececff, 0xd3d3d3ff, 0x8f8f8fff, 0x838383ff, 0x888888ff, +0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x878787ff, 0x8a8a8aff, 0x818181ff, 0x4a4a4aff, 0x202020ff, 0x232323ff, 0x161616ff, 0x010101ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, +0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, +0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x0c0c0cff, 0x666666ff, 0xbebebeff, 0xcfcfcfff, 0xcdcdcdff, 0xd0d0d0ff, 0x8a8a8aff, 0x595959ff, 0x4c4c4cff, 0x404040ff, 0x444444ff, 0x444444ff, 0x444444ff, +0x444444ff, 0x3d3d3eff, 0x61614bff, 0x323287ff, 0x00009fff, 0x000098ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000098ff, 0x00009aff, +0x282895ff, 0x9a9aa0ff, 0xbebebbff, 0xbebebeff, 0xbababaff, 0xd9d9d9ff, 0xd4d4d4ff, 0xbbbbbbff, 0xbebebeff, 0xbbbbbbff, 0xc1c1c1ff, 0xdadadaff, 0xe2e2e2ff, 0xe3e3e3ff, 0xccccccff, 0xa9a9a9ff, 0xaaaaaaff, 0xaaaaaaff, 0xaaaaaaff, 0x9b9b9bff, 0x919191ff, 0x929292ff, 0x8e8e8eff, 0x7c7c7cff, 0x777777ff, 0x777777ff, 0x757575ff, 0x727272ff, 0x727272ff, 0x727272ff, 0x727272ff, 0x727272ff, +0x717171ff, 0x4f4f4fff, 0x555555ff, 0xb4b4b4ff, 0xd3d3d3ff, 0xcbcbcbff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xc7c7c7ff, 0xddddddff, 0xe9e9e9ff, 0xe0e0e0ff, 0xcfcfcfff, 0xc4c4c4ff, 0xd9d9d9ff, 0xe1e1e1ff, 0xddddddff, 0xd0d0d0ff, 0x919191ff, 0x838383ff, 0x888888ff, +0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x878787ff, 0x8a8a8aff, 0x818181ff, 0x4a4a4aff, 0x202020ff, 0x232323ff, 0x161616ff, 0x010101ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, +0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, +0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x0a0a0aff, 0x656565ff, 0xbebebeff, 0xcfcfcfff, 0xcdcdcdff, 0xd0d0d0ff, 0x8a8a8aff, 0x595959ff, 0x4c4c4cff, 0x404040ff, 0x444444ff, 0x444444ff, 0x444444ff, +0x444444ff, 0x3d3d3eff, 0x61614bff, 0x323287ff, 0x00009fff, 0x000098ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000098ff, 0x00009cff, +0x1c1c89ff, 0x868689ff, 0x9e9e9aff, 0x7d7d7dff, 0x7f7f7fff, 0x787878ff, 0x797979ff, 0x7d7d7dff, 0x7d7d7dff, 0x7c7c7cff, 0x7a7a7aff, 0x757575ff, 0x727272ff, 0x767676ff, 0x666666ff, 0x4e4e4eff, 0x4f4f4fff, 0x4f4f4fff, 0x4f4f4fff, 0x444444ff, 0x4c4c4cff, 0x575757ff, 0x4f4f4fff, 0x4a4a4aff, 0x555555ff, 0x565656ff, 0x686868ff, 0x878787ff, 0x858585ff, 0x858585ff, 0x858585ff, 0x858585ff, +0x8a8a8aff, 0x7d7d7dff, 0x666666ff, 0xb1b1b1ff, 0xd3d3d3ff, 0xcbcbcbff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xc7c7c7ff, 0xe0e0e0ff, 0xdcdcdcff, 0xcfcfcfff, 0xd2d2d2ff, 0xcacacaff, 0xe8e8e8ff, 0xeaeaeaff, 0xdfdfdfff, 0xd0d0d0ff, 0x919191ff, 0x838383ff, 0x888888ff, +0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x878787ff, 0x8a8a8aff, 0x818181ff, 0x4a4a4aff, 0x202020ff, 0x232323ff, 0x161616ff, 0x010101ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, +0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, +0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x0a0a0aff, 0x626262ff, 0xbebebeff, 0xcfcfcfff, 0xcdcdcdff, 0xd0d0d0ff, 0x8a8a8aff, 0x595959ff, 0x4c4c4cff, 0x404040ff, 0x444444ff, 0x444444ff, 0x444444ff, +0x444444ff, 0x3d3d3eff, 0x61614bff, 0x323287ff, 0x00009fff, 0x000098ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000098ff, 0x00009eff, +0x121281ff, 0x56565aff, 0x60605cff, 0x474747ff, 0x585858ff, 0x595959ff, 0x4b4b4bff, 0x4f4f4fff, 0x6d6d6dff, 0x7d7d7dff, 0x7a7a7aff, 0x7a7a7aff, 0x787878ff, 0x828282ff, 0x959595ff, 0x9a9a9aff, 0x9a9a9aff, 0x9a9a9aff, 0x9a9a9aff, 0x9d9d9dff, 0xa9a9a9ff, 0xafafafff, 0xacacacff, 0xb3b3b3ff, 0xbebebeff, 0xbdbdbdff, 0xc9c9c9ff, 0xdededeff, 0xdbdbdbff, 0xdbdbdbff, 0xdbdbdbff, 0xdbdbdbff, +0xe2e2e2ff, 0xc4c4c4ff, 0x767676ff, 0xacacacff, 0xd3d3d3ff, 0xcbcbcbff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xc9c9c9ff, 0xd2d2d2ff, 0xd2d2d2ff, 0xc7c7c7ff, 0xc8c8c8ff, 0xcdcdcdff, 0xe7e7e7ff, 0xe9e9e9ff, 0xdededeff, 0xd0d0d0ff, 0x919191ff, 0x838383ff, 0x888888ff, +0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x878787ff, 0x8a8a8aff, 0x818181ff, 0x4a4a4aff, 0x202020ff, 0x232323ff, 0x141414ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, +0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, +0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x161616ff, 0x666666ff, 0xbebebeff, 0xcfcfcfff, 0xcdcdcdff, 0xd0d0d0ff, 0x8a8a8aff, 0x595959ff, 0x4c4c4cff, 0x404040ff, 0x444444ff, 0x444444ff, 0x444444ff, +0x444444ff, 0x3d3d3eff, 0x61614bff, 0x323287ff, 0x00009fff, 0x000098ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000098ff, 0x00009eff, +0x161684ff, 0x626267ff, 0x868681ff, 0x838383ff, 0x878787ff, 0x939393ff, 0x929292ff, 0x919191ff, 0xa2a2a2ff, 0xacacacff, 0xaaaaaaff, 0xaaaaaaff, 0xa7a7a7ff, 0xb5b5b5ff, 0xcdcdcdff, 0xcdcdcdff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xc9c9c9ff, 0xcbcbcbff, 0xccccccff, 0xc9c9c9ff, 0xc9c9c9ff, 0xcbcbcbff, 0xc7c7c7ff, 0xc7c7c7ff, 0xcbcbcbff, 0xcbcbcbff, 0xcbcbcbff, 0xcacacaff, +0xd0d0d0ff, 0xb5b5b5ff, 0x727272ff, 0xadadadff, 0xd3d3d3ff, 0xcbcbcbff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xcbcbcbff, 0xcbcbcbff, 0xc9c9c9ff, 0xc9c9c9ff, 0xccccccff, 0xcacacaff, 0xdbdbdbff, 0xecececff, 0xe7e7e7ff, 0xe1e1e1ff, 0xd1d1d1ff, 0x909090ff, 0x838383ff, 0x888888ff, +0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x878787ff, 0x8a8a8aff, 0x818181ff, 0x4a4a4aff, 0x1f1f1fff, 0x202020ff, 0x161616ff, 0x080808ff, 0x0b0b0bff, 0x0e0e0eff, 0x0e0e0eff, 0x0e0e0eff, 0x0e0e0eff, 0x0e0e0eff, 0x0e0e0eff, 0x0e0e0eff, 0x0e0e0eff, 0x0e0e0eff, 0x0e0e0eff, 0x0e0e0eff, 0x0e0e0eff, 0x0e0e0eff, 0x0e0e0eff, 0x0e0e0eff, 0x0e0e0eff, 0x0e0e0eff, 0x0e0e0eff, 0x0e0e0eff, +0x0f0f0fff, 0x0f0f0fff, 0x0f0f0fff, 0x0f0f0fff, 0x0f0f0fff, 0x0f0f0fff, 0x0f0f0fff, 0x0f0f0fff, 0x0f0f0fff, 0x0f0f0fff, 0x0f0f0fff, 0x0f0f0fff, 0x0f0f0fff, 0x0f0f0fff, 0x0f0f0fff, 0x0f0f0fff, 0x0f0f0fff, 0x0f0f0fff, 0x0f0f0fff, 0x0f0f0fff, 0x0f0f0fff, 0x0f0f0fff, 0x0f0f0fff, 0x0f0f0fff, 0x0f0f0fff, 0x0f0f0fff, 0x0f0f0fff, 0x0f0f0fff, 0x0f0f0fff, 0x0f0f0fff, 0x0f0f0fff, 0x0f0f0fff, +0x0f0f0fff, 0x0f0f0fff, 0x0f0f0fff, 0x0f0f0fff, 0x0f0f0fff, 0x0f0f0fff, 0x0f0f0fff, 0x0f0f0fff, 0x0f0f0fff, 0x0f0f0fff, 0x0f0f0fff, 0x0f0f0fff, 0x0f0f0fff, 0x0f0f0fff, 0x0f0f0fff, 0x0f0f0fff, 0x0f0f0fff, 0x0e0e0eff, 0x0e0e0eff, 0x373737ff, 0x8c8c8cff, 0xc9c9c9ff, 0xd1d1d1ff, 0xcececeff, 0xcfcfcfff, 0x8a8a8aff, 0x595959ff, 0x4c4c4cff, 0x404040ff, 0x444444ff, 0x444444ff, 0x444444ff, +0x444444ff, 0x3d3d3eff, 0x61614bff, 0x323287ff, 0x00009fff, 0x000098ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000098ff, 0x00009dff, +0x1b1b89ff, 0x65656bff, 0x7b7b76ff, 0x6f6f6fff, 0x636363ff, 0x626262ff, 0x626262ff, 0x696969ff, 0x686868ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x656565ff, 0x676767ff, 0x6e6e6eff, 0x727272ff, 0x717171ff, 0x717171ff, 0x717171ff, 0x717171ff, 0x747474ff, 0x828282ff, 0x8a8a8aff, 0x858585ff, 0x8e8e8eff, 0x9c9c9cff, 0x9b9b9bff, 0xb0b0b0ff, 0xcececeff, 0xcbcbcbff, 0xcbcbcbff, 0xcbcbcbff, +0xd1d1d1ff, 0xb5b5b5ff, 0x727272ff, 0xadadadff, 0xd3d3d3ff, 0xcbcbcbff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xcbcbcbff, 0xcececeff, 0xcececeff, 0xcbcbcbff, 0xccccccff, 0xcacacaff, 0xc9c9c9ff, 0xd2d2d2ff, 0xd9d9d9ff, 0xe6e6e6ff, 0xefefefff, 0xd4d4d4ff, 0x8f8f8fff, 0x838383ff, 0x888888ff, +0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x878787ff, 0x8a8a8aff, 0x808080ff, 0x474747ff, 0x202020ff, 0x2b2b2bff, 0x454545ff, 0x4c4c4cff, 0x585858ff, 0x666666ff, 0x656565ff, 0x656565ff, 0x656565ff, 0x656565ff, 0x656565ff, 0x656565ff, 0x656565ff, 0x656565ff, 0x656565ff, 0x656565ff, 0x656565ff, 0x656565ff, 0x656565ff, 0x656565ff, 0x666666ff, 0x666666ff, 0x676767ff, 0x666666ff, +0x636363ff, 0x616161ff, 0x626262ff, 0x626262ff, 0x626262ff, 0x626262ff, 0x626262ff, 0x626262ff, 0x626262ff, 0x626262ff, 0x626262ff, 0x626262ff, 0x626262ff, 0x626262ff, 0x626262ff, 0x626262ff, 0x626262ff, 0x626262ff, 0x626262ff, 0x626262ff, 0x626262ff, 0x626262ff, 0x626262ff, 0x626262ff, 0x626262ff, 0x626262ff, 0x626262ff, 0x626262ff, 0x626262ff, 0x626262ff, 0x626262ff, 0x626262ff, +0x626262ff, 0x626262ff, 0x626262ff, 0x626262ff, 0x626262ff, 0x626262ff, 0x626262ff, 0x626262ff, 0x626262ff, 0x626262ff, 0x626262ff, 0x626262ff, 0x626262ff, 0x626262ff, 0x626262ff, 0x626262ff, 0x626262ff, 0x606060ff, 0x606060ff, 0x767676ff, 0x8f8f8fff, 0xadadadff, 0xc7c7c7ff, 0xcbcbcbff, 0xd4d4d4ff, 0x8b8b8bff, 0x585858ff, 0x4c4c4cff, 0x404040ff, 0x444444ff, 0x444444ff, 0x444444ff, +0x444444ff, 0x3d3d3eff, 0x61614bff, 0x323287ff, 0x00009fff, 0x000098ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000098ff, 0x00009eff, +0x151584ff, 0x4e4e52ff, 0x555551ff, 0x585859ff, 0x616161ff, 0x606060ff, 0x606060ff, 0x7b7b7bff, 0x8d8d8dff, 0x8a8a8aff, 0x8c8c8cff, 0x8d8d8dff, 0x8c8c8cff, 0x8c8c8cff, 0x999999ff, 0xa9a9a9ff, 0xa7a7a7ff, 0xa7a7a7ff, 0xa7a7a7ff, 0xa7a7a7ff, 0xabababff, 0xb4b4b4ff, 0xb6b6b6ff, 0xb5b5b5ff, 0xbababaff, 0xc1c1c1ff, 0xc0c0c0ff, 0xc9c9c9ff, 0xd6d6d6ff, 0xd5d5d5ff, 0xd5d5d5ff, 0xd5d5d5ff, +0xdbdbdbff, 0xbebebeff, 0x747474ff, 0xacacacff, 0xd3d3d3ff, 0xcbcbcbff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xc9c9c9ff, 0xd4d4d4ff, 0xd9d9d9ff, 0xc9c9c9ff, 0xc9c9c9ff, 0xcececeff, 0xcfcfcfff, 0xc7c7c7ff, 0xccccccff, 0xdbdbdbff, 0xe5e5e5ff, 0xd2d2d2ff, 0x909090ff, 0x838383ff, 0x888888ff, +0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x878787ff, 0x8a8a8aff, 0x808080ff, 0x555555ff, 0x464646ff, 0x636363ff, 0x818181ff, 0x8a8a8aff, 0x8e8e8eff, 0x959595ff, 0x949494ff, 0x949494ff, 0x949494ff, 0x949494ff, 0x949494ff, 0x949494ff, 0x949494ff, 0x949494ff, 0x949494ff, 0x949494ff, 0x949494ff, 0x949494ff, 0x949494ff, 0x949494ff, 0x8f8f8fff, 0x909090ff, 0x909090ff, 0x888888ff, +0x7a7a7aff, 0x757575ff, 0x767676ff, 0x767676ff, 0x767676ff, 0x767676ff, 0x767676ff, 0x767676ff, 0x767676ff, 0x767676ff, 0x767676ff, 0x767676ff, 0x767676ff, 0x767676ff, 0x767676ff, 0x767676ff, 0x767676ff, 0x767676ff, 0x767676ff, 0x767676ff, 0x767676ff, 0x767676ff, 0x767676ff, 0x767676ff, 0x767676ff, 0x767676ff, 0x767676ff, 0x767676ff, 0x767676ff, 0x767676ff, 0x767676ff, 0x767676ff, +0x767676ff, 0x767676ff, 0x767676ff, 0x767676ff, 0x767676ff, 0x767676ff, 0x767676ff, 0x767676ff, 0x767676ff, 0x767676ff, 0x767676ff, 0x767676ff, 0x767676ff, 0x767676ff, 0x767676ff, 0x767676ff, 0x767676ff, 0x777777ff, 0x838383ff, 0x8c8c8cff, 0x818181ff, 0x8c8c8cff, 0x949494ff, 0xb0b0b0ff, 0xcbcbcbff, 0x868686ff, 0x5b5b5bff, 0x4d4d4dff, 0x404040ff, 0x444444ff, 0x444444ff, 0x444444ff, +0x444444ff, 0x3d3d3eff, 0x61614bff, 0x323287ff, 0x00009fff, 0x000098ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000098ff, 0x00009eff, +0x161683ff, 0x707074ff, 0xa0a09cff, 0xa4a4a4ff, 0xaaaaaaff, 0xaaaaaaff, 0xaaaaaaff, 0xbababaff, 0xc5c5c5ff, 0xc0c0c0ff, 0xbababaff, 0xb9b9b9ff, 0xb7b7b7ff, 0xbebebeff, 0xd1d1d1ff, 0xd7d7d7ff, 0xd6d6d6ff, 0xd6d6d6ff, 0xd7d7d7ff, 0xd6d6d6ff, 0xc8c8c8ff, 0xc0c0c0ff, 0xc0c0c0ff, 0xbdbdbdff, 0xb5b5b5ff, 0xb0b0b0ff, 0xb0b0b0ff, 0xaeaeaeff, 0xa8a8a8ff, 0xa5a5a5ff, 0xa6a6a6ff, 0xa5a5a5ff, +0xaaaaaaff, 0x959595ff, 0x6a6a6aff, 0xafafafff, 0xd3d3d3ff, 0xcbcbcbff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xcbcbcbff, 0xcececeff, 0xd0d0d0ff, 0xc9c9c9ff, 0xcfcfcfff, 0xdededeff, 0xd5d5d5ff, 0xc8c8c8ff, 0xcdcdcdff, 0xd0d0d0ff, 0xdadadaff, 0xd0d0d0ff, 0x919191ff, 0x838383ff, 0x888888ff, +0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x878787ff, 0x888888ff, 0x878787ff, 0x7e7e7eff, 0x7f7f7fff, 0x858585ff, 0x848484ff, 0x838383ff, 0x818281ff, 0x808080ff, 0x808080ff, 0x808080ff, 0x808080ff, 0x808080ff, 0x808080ff, 0x808080ff, 0x808080ff, 0x808080ff, 0x808080ff, 0x808080ff, 0x808080ff, 0x808080ff, 0x808080ff, 0x808080ff, 0x727272ff, 0x757575ff, 0x717171ff, 0x676767ff, +0x636363ff, 0x626262ff, 0x626262ff, 0x626262ff, 0x626262ff, 0x626262ff, 0x626262ff, 0x626262ff, 0x626262ff, 0x626262ff, 0x626262ff, 0x626262ff, 0x626262ff, 0x626262ff, 0x626262ff, 0x626262ff, 0x626262ff, 0x626262ff, 0x626262ff, 0x626262ff, 0x626262ff, 0x626262ff, 0x626262ff, 0x626262ff, 0x626262ff, 0x626262ff, 0x626262ff, 0x626262ff, 0x626262ff, 0x626262ff, 0x626262ff, 0x626262ff, +0x626262ff, 0x626262ff, 0x626262ff, 0x626262ff, 0x626262ff, 0x626262ff, 0x626262ff, 0x626262ff, 0x626262ff, 0x626262ff, 0x626262ff, 0x626262ff, 0x626262ff, 0x626262ff, 0x626262ff, 0x626262ff, 0x616161ff, 0x666666ff, 0x7a7a7aff, 0x787878ff, 0x727272ff, 0x828282ff, 0x808080ff, 0x888888ff, 0x909090ff, 0x787878ff, 0x5d5d5dff, 0x494949ff, 0x414141ff, 0x444444ff, 0x444444ff, 0x444444ff, +0x444444ff, 0x3d3d3eff, 0x61614bff, 0x323287ff, 0x00009fff, 0x000098ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000098ff, 0x00009dff, +0x191986ff, 0x77777cff, 0x9e9e9aff, 0x929292ff, 0x909090ff, 0x909090ff, 0x8d8d8dff, 0x979797ff, 0x9f9f9fff, 0x999999ff, 0x8b8b8bff, 0x868686ff, 0x868686ff, 0x888888ff, 0x8a8a8aff, 0x878787ff, 0x878787ff, 0x878787ff, 0x878787ff, 0x868686ff, 0x686868ff, 0x585858ff, 0x666666ff, 0x616161ff, 0x555555ff, 0x595959ff, 0x5c5c5cff, 0x595959ff, 0x666666ff, 0x757575ff, 0x727272ff, 0x727272ff, +0x757575ff, 0x676767ff, 0x5f5f5fff, 0xb2b2b2ff, 0xd3d3d3ff, 0xcbcbcbff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xcbcbcbff, 0xcacacaff, 0xc8c8c8ff, 0xd8d8d8ff, 0xdadadaff, 0xccccccff, 0xc9c9c9ff, 0xcfcfcfff, 0xdbdbdbff, 0xe0e0e0ff, 0xd0d0d0ff, 0x919191ff, 0x838383ff, 0x888888ff, +0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x878787ff, 0x888888ff, 0x8a8a8aff, 0x8e8e8eff, 0x828282ff, 0x6a6a69ff, 0x6b646aff, 0x6d636cff, 0x686968ff, 0x686868ff, 0x686868ff, 0x686868ff, 0x686868ff, 0x686868ff, 0x686868ff, 0x686868ff, 0x686868ff, 0x686868ff, 0x686868ff, 0x686868ff, 0x686868ff, 0x686868ff, 0x686868ff, 0x656565ff, 0x666666ff, 0x656565ff, 0x636363ff, +0x656565ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, +0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x656565ff, 0x666666ff, 0x696969ff, 0x666666ff, 0x676767ff, 0x5f5f5fff, 0x4d4d4dff, 0x5e5e5eff, 0x5d5d5dff, 0x4e4e4eff, 0x494949ff, 0x434343ff, 0x434343ff, 0x444444ff, 0x444444ff, 0x444444ff, +0x444444ff, 0x3d3d3eff, 0x61614bff, 0x323287ff, 0x00009fff, 0x000098ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000098ff, 0x00009dff, +0x1c1c8bff, 0x626267ff, 0x5c5c58ff, 0x4a4a4aff, 0x4b4b4bff, 0x494949ff, 0x5c5c5cff, 0x6b6b6bff, 0x6a6a6aff, 0x686868ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x646464ff, 0x686868ff, 0x6f6f6fff, 0x6e6e6eff, 0x6e6e6eff, 0x6e6e6eff, 0x6e6e6eff, 0x686868ff, 0x696969ff, 0x7a7a7aff, 0x7d7d7dff, 0x818181ff, 0x909090ff, 0x929292ff, 0x8c8c8cff, 0xa6a6a6ff, 0xc3c3c3ff, 0xbdbdbdff, 0xbebebeff, +0xc4c4c4ff, 0xabababff, 0x707070ff, 0xaeaeaeff, 0xd3d3d3ff, 0xcbcbcbff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xcbcbcbff, 0xcdcdcdff, 0xcbcbcbff, 0xcacacaff, 0xcacacaff, 0xd0d0d0ff, 0xe0e0e0ff, 0xe2e2e2ff, 0xd0d0d0ff, 0x919191ff, 0x838383ff, 0x888888ff, +0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x878787ff, 0x878787ff, 0x888787ff, 0x727478ff, 0x62576dff, 0x546b5eff, 0x4a7956ff, 0x676066ff, 0x646464ff, 0x646464ff, 0x646464ff, 0x646464ff, 0x646464ff, 0x646464ff, 0x646464ff, 0x646464ff, 0x646464ff, 0x646464ff, 0x646464ff, 0x646464ff, 0x646464ff, 0x646464ff, 0x656565ff, 0x656565ff, 0x656565ff, 0x666666ff, +0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, +0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x656565ff, 0x646464ff, 0x646464ff, 0x6a6a6aff, 0x515151ff, 0x2f2f2fff, 0x555555ff, 0x3c3c3cff, 0x282828ff, 0x3f3f3fff, 0x424242ff, 0x444444ff, 0x444444ff, 0x444444ff, 0x444444ff, +0x444444ff, 0x3d3d3eff, 0x61614bff, 0x323287ff, 0x00009fff, 0x000098ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000098ff, 0x00009dff, +0x1c1c8aff, 0x6f6f74ff, 0x888884ff, 0x848485ff, 0x858585ff, 0x828282ff, 0xa0a0a0ff, 0xb4b4b4ff, 0xb0b0b0ff, 0xb0b0b0ff, 0xb1b1b1ff, 0xb1b1b1ff, 0xb1b1b1ff, 0xaeaeaeff, 0xbfbfbfff, 0xd9d9d9ff, 0xd8d8d8ff, 0xd8d8d8ff, 0xd8d8d8ff, 0xd8d8d8ff, 0xd9d9d9ff, 0xdadadaff, 0xdadadaff, 0xd7d7d7ff, 0xd8d8d8ff, 0xd9d9d9ff, 0xdadadaff, 0xd7d7d7ff, 0xd6d6d6ff, 0xd9d9d9ff, 0xd4d4d4ff, 0xcfcfcfff, +0xd6d6d6ff, 0xbababaff, 0x737373ff, 0xadadadff, 0xd3d3d3ff, 0xcbcbcbff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xcbcbcbff, 0xcbcbcbff, 0xccccccff, 0xcacacaff, 0xd0d0d0ff, 0xdfdfdfff, 0xe1e1e1ff, 0xd0d0d0ff, 0x919191ff, 0x838383ff, 0x888888ff, +0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x8a8a8aff, 0x8e8e8dff, 0x787f87ff, 0x767166ff, 0x6e8352ff, 0x4fb235ff, 0x63a33eff, 0x5a5a71ff, 0x676665ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, +0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, +0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x656565ff, 0x616161ff, 0x686868ff, 0x484848ff, 0x4e4e4eff, 0x585858ff, 0x444444ff, 0x424242ff, 0x444444ff, 0x444444ff, 0x444444ff, +0x444444ff, 0x3d3d3eff, 0x61614bff, 0x323287ff, 0x00009fff, 0x000098ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000098ff, 0x00009eff, +0x141482ff, 0x616164ff, 0x84847fff, 0x828282ff, 0x828282ff, 0x7c7c7cff, 0x777777ff, 0x777777ff, 0x777777ff, 0x777777ff, 0x777777ff, 0x777777ff, 0x777777ff, 0x747474ff, 0x7b7b7bff, 0x898989ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x878787ff, 0x8a8a8aff, 0x969696ff, 0x999999ff, 0x989898ff, 0x969696ff, 0x9f9f9fff, 0xa9a9a9ff, 0xa5a5a5ff, 0xbcbcbcff, 0xcfcfcfff, +0xd1d1d1ff, 0xb5b5b5ff, 0x727272ff, 0xadadadff, 0xd3d3d3ff, 0xcbcbcbff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xcacacaff, 0xd0d0d0ff, 0xdfdfdfff, 0xe1e1e1ff, 0xd0d0d0ff, 0x919191ff, 0x838383ff, 0x888888ff, +0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x878787ff, 0x7d7c7cff, 0x76797bff, 0x7c7673ff, 0xca8440ff, 0xccae1dff, 0xbcbc19ff, 0xf59229ff, 0x886457ff, 0x5b646aff, 0x666665ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, +0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, +0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x656565ff, 0x666666ff, 0x676767ff, 0x666666ff, 0x676767ff, 0x686868ff, 0x656565ff, 0x4a4a4aff, 0x404040ff, 0x444444ff, 0x444444ff, 0x444444ff, +0x444444ff, 0x3d3d3eff, 0x61614bff, 0x323287ff, 0x00009fff, 0x000098ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000098ff, 0x00009eff, +0x171785ff, 0x47474cff, 0x43433fff, 0x404040ff, 0x3c3c3cff, 0x565656ff, 0x6b6b6bff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x646464ff, 0x6d6d6dff, 0x787878ff, 0x777777ff, 0x777777ff, 0x747474ff, 0x727272ff, 0x727272ff, 0x727272ff, 0x717171ff, 0x767676ff, 0x848484ff, 0x888888ff, 0x888888ff, 0x868686ff, 0x919191ff, 0x9f9f9fff, 0x9b9b9bff, 0xb8b8b8ff, 0xd0d0d0ff, +0xd0d0d0ff, 0xb5b5b5ff, 0x727272ff, 0xadadadff, 0xd3d3d3ff, 0xcbcbcbff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xcacacaff, 0xd0d0d0ff, 0xe2e2e2ff, 0xe3e3e3ff, 0xd0d0d0ff, 0x919191ff, 0x838383ff, 0x888888ff, +0x888888ff, 0x888888ff, 0x888888ff, 0x878787ff, 0x898989ff, 0x878787ff, 0x6d6c6cff, 0x556164ff, 0x845f4fff, 0xe84f1cff, 0xfb4914ff, 0xfb4315ff, 0xe75d1cff, 0x8f724bff, 0x5a636bff, 0x666665ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, +0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, +0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x656565ff, 0x656565ff, 0x656565ff, 0x666666ff, 0x666666ff, 0x656565ff, 0x565656ff, 0x444444ff, 0x424242ff, 0x444444ff, 0x444444ff, +0x444444ff, 0x3d3d3eff, 0x61614bff, 0x323287ff, 0x00009fff, 0x000098ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000098ff, 0x00009dff, +0x1b1b89ff, 0x737377ff, 0x939390ff, 0x909090ff, 0x8c8c8cff, 0xa6a6a6ff, 0xbdbdbdff, 0xb8b8b8ff, 0xb8b8b8ff, 0xb8b8b8ff, 0xb8b8b8ff, 0xb8b8b8ff, 0xb6b6b6ff, 0xbebebeff, 0xccccccff, 0xccccccff, 0xc9c9c9ff, 0xd9d9d9ff, 0xe4e4e4ff, 0xe2e2e2ff, 0xe7e7e7ff, 0xe8e8e8ff, 0xe8e8e8ff, 0xe4e4e4ff, 0xe3e3e3ff, 0xe3e3e3ff, 0xe3e3e3ff, 0xe1e1e1ff, 0xe0e0e0ff, 0xe2e2e2ff, 0xddddddff, 0xd8d8d8ff, +0xdfdfdfff, 0xc2c2c2ff, 0x757575ff, 0xadadadff, 0xd3d3d3ff, 0xcbcbcbff, 0xcbcbcbff, 0xcbcbcbff, 0xcbcbcbff, 0xcbcbcbff, 0xcbcbcbff, 0xcbcbcbff, 0xcbcbcbff, 0xcbcbcbff, 0xcbcbcbff, 0xcbcbcbff, 0xcbcbcbff, 0xcbcbcbff, 0xcbcbcbff, 0xcbcbcbff, 0xcbcbcbff, 0xcbcbcbff, 0xcbcbcbff, 0xcbcbcbff, 0xcacacaff, 0xcdcdcdff, 0xd2d2d2ff, 0xddddddff, 0xd1d1d1ff, 0x919191ff, 0x838383ff, 0x888888ff, +0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x8a8a8aff, 0x797979ff, 0x676666ff, 0x5e6762ff, 0x78546cff, 0xb52577ff, 0xc42074ff, 0xc71f6eff, 0xa82c89ff, 0x6b5683ff, 0x60695eff, 0x666566ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, +0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, +0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x656565ff, 0x656565ff, 0x686868ff, 0x676767ff, 0x4c4c4cff, 0x414141ff, 0x444444ff, 0x444444ff, +0x444444ff, 0x3d3d3eff, 0x61614bff, 0x323287ff, 0x00009fff, 0x000098ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000098ff, 0x00009dff, +0x171784ff, 0x7d7d81ff, 0xb8b8b4ff, 0xb6b6b6ff, 0xb6b6b6ff, 0xb1b1b1ff, 0xacacacff, 0xadadadff, 0xadadadff, 0xadadadff, 0xadadadff, 0xadadadff, 0xacacacff, 0xaaaaaaff, 0xa7a7a7ff, 0xa7a7a7ff, 0xa5a5a5ff, 0xb0b0b0ff, 0xbbbbbbff, 0xb8b8b8ff, 0x999999ff, 0x8a8a8aff, 0x8d8d8dff, 0x8c8c8cff, 0x8c8c8cff, 0x8c8c8cff, 0x8c8c8cff, 0x8e8e8eff, 0x818181ff, 0x717171ff, 0x747474ff, 0x747474ff, +0x787878ff, 0x696969ff, 0x5f5f5fff, 0xb4b4b4ff, 0xd6d6d6ff, 0xcececeff, 0xcececeff, 0xcececeff, 0xcececeff, 0xcececeff, 0xcececeff, 0xcececeff, 0xcececeff, 0xcececeff, 0xcececeff, 0xcececeff, 0xcececeff, 0xcececeff, 0xcececeff, 0xcececeff, 0xcececeff, 0xcececeff, 0xcececeff, 0xcececeff, 0xcececeff, 0xcdcdcdff, 0xc8c8c8ff, 0xdadadaff, 0xd5d5d5ff, 0x929292ff, 0x838383ff, 0x888888ff, +0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x797979ff, 0x646464ff, 0x626262ff, 0x646664ff, 0x6e6669ff, 0x69429dff, 0x3f13d1ff, 0x310adbff, 0x5f25b7ff, 0x7f5e71ff, 0x606860ff, 0x666566ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, +0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, +0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x646464ff, 0x545454ff, 0x434343ff, 0x424242ff, 0x444444ff, 0x444444ff, +0x444444ff, 0x3d3d3eff, 0x60604bff, 0x323287ff, 0x00009fff, 0x000098ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000098ff, 0x00009eff, +0x131382ff, 0x545459ff, 0x6a6a65ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x676767ff, 0x696969ff, 0x696969ff, 0x686868ff, 0x696969ff, 0x666666ff, 0x636363ff, 0x616161ff, 0x4c4c4cff, 0x3f3f3fff, 0x474747ff, 0x555555ff, 0x595959ff, 0x595959ff, 0x565656ff, 0x626262ff, 0x696969ff, 0x5d5d5dff, 0x5f5f5fff, 0x5f5f5fff, +0x616161ff, 0x565656ff, 0x5c5c5cff, 0xb1b1b1ff, 0xd1d1d1ff, 0xcbcbcbff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xcbcbcbff, 0xcacacaff, 0xcacacaff, 0xcbcbcbff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xcbcbcbff, 0xcbcbcbff, 0xc5c5c5ff, 0xa8a8a8ff, 0x888888ff, 0x868686ff, 0x878787ff, +0x878787ff, 0x878787ff, 0x888888ff, 0x878787ff, 0x6d6d6dff, 0x606060ff, 0x666666ff, 0x656566ff, 0x676a60ff, 0x525d6aff, 0x303d89ff, 0x283592ff, 0x414f78ff, 0x656c5cff, 0x666566ff, 0x656565ff, 0x656565ff, 0x656565ff, 0x656565ff, 0x656565ff, 0x656565ff, 0x656565ff, 0x656565ff, 0x656565ff, 0x656565ff, 0x656565ff, 0x656565ff, 0x656565ff, 0x656565ff, 0x656565ff, 0x656565ff, 0x656565ff, +0x656565ff, 0x656565ff, 0x656565ff, 0x656565ff, 0x656565ff, 0x656565ff, 0x656565ff, 0x656565ff, 0x656565ff, 0x656565ff, 0x656565ff, 0x656565ff, 0x656565ff, 0x656565ff, 0x656565ff, 0x656565ff, 0x656565ff, 0x656565ff, 0x656565ff, 0x656565ff, 0x656565ff, 0x656565ff, 0x656565ff, 0x656565ff, 0x656565ff, 0x656565ff, 0x656565ff, 0x656565ff, 0x656565ff, 0x656565ff, 0x656565ff, 0x656565ff, +0x656565ff, 0x656565ff, 0x656565ff, 0x656565ff, 0x656565ff, 0x656565ff, 0x656565ff, 0x656565ff, 0x656565ff, 0x656565ff, 0x656565ff, 0x656565ff, 0x656565ff, 0x656565ff, 0x656565ff, 0x656565ff, 0x656565ff, 0x656565ff, 0x656565ff, 0x656565ff, 0x656565ff, 0x656565ff, 0x656565ff, 0x656565ff, 0x656565ff, 0x666666ff, 0x626262ff, 0x494949ff, 0x404040ff, 0x434343ff, 0x434343ff, 0x434343ff, +0x444444ff, 0x3d3d3eff, 0x62624aff, 0x333386ff, 0x00009fff, 0x000098ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000098ff, 0x00009eff, +0x191984ff, 0x5c5c5dff, 0x6d6d68ff, 0x696969ff, 0x696969ff, 0x696969ff, 0x686868ff, 0x676767ff, 0x676767ff, 0x676767ff, 0x686868ff, 0x656565ff, 0x737373ff, 0x949494ff, 0x969696ff, 0x969696ff, 0x979797ff, 0x969696ff, 0x9b9b9bff, 0x9e9e9eff, 0xa2a2a2ff, 0xa4a4a4ff, 0xa6a6a6ff, 0xb0b0b0ff, 0xb3b3b3ff, 0xb3b3b3ff, 0xb0b0b0ff, 0xb7b7b7ff, 0xc3c3c3ff, 0xc4c4c4ff, 0xc4c4c4ff, 0xc4c4c4ff, +0xc6c6c6ff, 0xc4c4c4ff, 0xa6a6a6ff, 0x7c7c7cff, 0x6f6f6fff, 0x6e6e6eff, 0x6e6e6eff, 0x6e6e6eff, 0x6e6e6eff, 0x6e6e6eff, 0x6e6e6eff, 0x6f6f6fff, 0x717171ff, 0x707070ff, 0x6e6e6eff, 0x6e6e6eff, 0x6e6e6eff, 0x6e6e6eff, 0x6e6e6eff, 0x6e6e6eff, 0x6e6e6eff, 0x6e6e6eff, 0x6e6e6eff, 0x6e6e6eff, 0x6e6e6eff, 0x6e6e6eff, 0x717171ff, 0x767676ff, 0x818181ff, 0x8b8b8bff, 0x8c8c8cff, 0x8c8c8cff, +0x8b8b8bff, 0x8c8c8cff, 0x8f8f8fff, 0x7d7d7dff, 0x6b6b6bff, 0x696969ff, 0x6a6a6aff, 0x6a6a6aff, 0x69696aff, 0x6d6d66ff, 0x747360ff, 0x75755eff, 0x706f63ff, 0x69696aff, 0x6a6a6aff, 0x6a6a6aff, 0x6a6a6aff, 0x6a6a6aff, 0x6a6a6aff, 0x6a6a6aff, 0x6a6a6aff, 0x6a6a6aff, 0x6a6a6aff, 0x6a6a6aff, 0x6a6a6aff, 0x6a6a6aff, 0x6a6a6aff, 0x6a6a6aff, 0x6a6a6aff, 0x6a6a6aff, 0x6a6a6aff, 0x6a6a6aff, +0x6a6a6aff, 0x6a6a6aff, 0x6a6a6aff, 0x6a6a6aff, 0x6a6a6aff, 0x6a6a6aff, 0x6a6a6aff, 0x6a6a6aff, 0x6a6a6aff, 0x6a6a6aff, 0x6a6a6aff, 0x6a6a6aff, 0x6a6a6aff, 0x6a6a6aff, 0x6a6a6aff, 0x6a6a6aff, 0x6a6a6aff, 0x6a6a6aff, 0x6a6a6aff, 0x6a6a6aff, 0x6a6a6aff, 0x6a6a6aff, 0x6a6a6aff, 0x6a6a6aff, 0x6a6a6aff, 0x6a6a6aff, 0x6a6a6aff, 0x6a6a6aff, 0x6a6a6aff, 0x6a6a6aff, 0x6a6a6aff, 0x6a6a6aff, +0x6a6a6aff, 0x6a6a6aff, 0x6a6a6aff, 0x6a6a6aff, 0x6a6a6aff, 0x6a6a6aff, 0x6a6a6aff, 0x6a6a6aff, 0x6a6a6aff, 0x6a6a6aff, 0x6a6a6aff, 0x6a6a6aff, 0x6a6a6aff, 0x6a6a6aff, 0x6a6a6aff, 0x6a6a6aff, 0x6a6a6aff, 0x6a6a6aff, 0x6a6a6aff, 0x6a6a6aff, 0x6a6a6aff, 0x6a6a6aff, 0x6a6a6aff, 0x6a6a6aff, 0x6a6a6aff, 0x6a6a6aff, 0x6a6a6aff, 0x626262ff, 0x595959ff, 0x494949ff, 0x444444ff, 0x444445ff, +0x454543ff, 0x42423aff, 0x5f5f4bff, 0x2e2e88ff, 0x00009eff, 0x000098ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000098ff, 0x00009cff, +0x18188bff, 0x6b6b78ff, 0x949486ff, 0x90908bff, 0x8e8e8fff, 0x8e8e8eff, 0x939393ff, 0x969696ff, 0x959595ff, 0x959595ff, 0x959595ff, 0x949494ff, 0x9a9a9aff, 0xa7a7a7ff, 0xa7a7a7ff, 0xa4a4a4ff, 0xa0a0a0ff, 0x9e9e9eff, 0xbcbcbcff, 0xd3d3d3ff, 0xcdcdcdff, 0xcececeff, 0xccccccff, 0xcacacaff, 0xcacacaff, 0xcacacaff, 0xcacacaff, 0xc8c8c8ff, 0xc6c6c6ff, 0xc6c6c6ff, 0xc6c6c6ff, 0xc6c6c6ff, +0xc2c2c2ff, 0xc6c6c6ff, 0xb7b7b7ff, 0x757575ff, 0x505050ff, 0x383838ff, 0x333333ff, 0x353535ff, 0x353535ff, 0x343434ff, 0x343434ff, 0x434343ff, 0x4d4d4dff, 0x474747ff, 0x3a3a3aff, 0x343434ff, 0x353535ff, 0x343434ff, 0x343434ff, 0x353535ff, 0x353535ff, 0x353535ff, 0x353535ff, 0x353535ff, 0x333333ff, 0x393939ff, 0x565656ff, 0x6a6a6aff, 0x7c7c7cff, 0x818181ff, 0x808080ff, 0x808080ff, +0x818181ff, 0x7d7d7dff, 0x7c7c7cff, 0x656565ff, 0x575757ff, 0x5c5c5cff, 0x5c5c5cff, 0x5c5c5cff, 0x5c5c5cff, 0x5b5b5cff, 0x5b5b5cff, 0x5b5b5cff, 0x5b5b5cff, 0x5c5c5cff, 0x5c5c5cff, 0x5c5c5cff, 0x5c5c5cff, 0x5c5c5cff, 0x5c5c5cff, 0x5c5c5cff, 0x5c5c5cff, 0x5c5c5cff, 0x5c5c5cff, 0x5c5c5cff, 0x5c5c5cff, 0x5c5c5cff, 0x5c5c5cff, 0x5c5c5cff, 0x5c5c5cff, 0x5c5c5cff, 0x5c5c5cff, 0x5c5c5cff, +0x5c5c5cff, 0x5c5c5cff, 0x5c5c5cff, 0x5c5c5cff, 0x5c5c5cff, 0x5c5c5cff, 0x5c5c5cff, 0x5c5c5cff, 0x5c5c5cff, 0x5c5c5cff, 0x5c5c5cff, 0x5c5c5cff, 0x5c5c5cff, 0x5c5c5cff, 0x5c5c5cff, 0x5c5c5cff, 0x5c5c5cff, 0x5c5c5cff, 0x5c5c5cff, 0x5c5c5cff, 0x5c5c5cff, 0x5c5c5cff, 0x5c5c5cff, 0x5c5c5cff, 0x5c5c5cff, 0x5c5c5cff, 0x5c5c5cff, 0x5c5c5cff, 0x5c5c5cff, 0x5c5c5cff, 0x5c5c5cff, 0x5c5c5cff, +0x5c5c5cff, 0x5c5c5cff, 0x5c5c5cff, 0x5c5c5cff, 0x5c5c5cff, 0x5c5c5cff, 0x5c5c5cff, 0x5c5c5cff, 0x5c5c5cff, 0x5c5c5cff, 0x5c5c5cff, 0x5c5c5cff, 0x5c5c5cff, 0x5c5c5cff, 0x5c5c5cff, 0x5c5c5cff, 0x5c5c5cff, 0x5c5c5cff, 0x5c5c5cff, 0x5c5c5cff, 0x5c5c5cff, 0x5c5c5cff, 0x5c5c5cff, 0x5c5c5cff, 0x5c5c5cff, 0x5b5b5bff, 0x5d5d5dff, 0x5c5c5cff, 0x4a4a4aff, 0x3d3d3dff, 0x3e3e3cff, 0x44443aff, +0x444443ff, 0x404045ff, 0x303065ff, 0x09099bff, 0x00009aff, 0x000098ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000098ff, 0x000099ff, +0x020298ff, 0x2b2b86ff, 0x585879ff, 0x5c5c6dff, 0x5f5f5bff, 0x5d5d5eff, 0x676767ff, 0x6f6f6fff, 0x6f6f6fff, 0x707070ff, 0x6e6e6eff, 0x6f6f6fff, 0x666666ff, 0x585858ff, 0x5d5d5dff, 0x515151ff, 0x434343ff, 0x434343ff, 0x515151ff, 0x5b5b5bff, 0x585858ff, 0x585858ff, 0x585858ff, 0x595959ff, 0x595959ff, 0x595959ff, 0x595959ff, 0x595959ff, 0x595959ff, 0x595959ff, 0x595959ff, 0x585858ff, +0x4b4b4bff, 0x434343ff, 0x3f3f3fff, 0x3e3e3eff, 0x363636ff, 0x272727ff, 0x252525ff, 0x262626ff, 0x262626ff, 0x262626ff, 0x262626ff, 0x272727ff, 0x333333ff, 0x323232ff, 0x282828ff, 0x262626ff, 0x252525ff, 0x2a2a2aff, 0x292929ff, 0x242424ff, 0x242424ff, 0x242424ff, 0x242424ff, 0x242424ff, 0x232323ff, 0x252525ff, 0x333333ff, 0x373737ff, 0x323232ff, 0x313131ff, 0x313131ff, 0x313131ff, +0x333333ff, 0x252525ff, 0x1f1f1fff, 0x1a1a1aff, 0x171717ff, 0x181818ff, 0x181818ff, 0x181818ff, 0x181818ff, 0x181818ff, 0x181818ff, 0x181818ff, 0x181818ff, 0x181818ff, 0x181818ff, 0x181818ff, 0x181818ff, 0x181818ff, 0x181818ff, 0x181818ff, 0x181818ff, 0x181818ff, 0x181818ff, 0x181818ff, 0x181818ff, 0x181818ff, 0x181818ff, 0x181818ff, 0x181818ff, 0x181818ff, 0x181818ff, 0x181818ff, +0x181818ff, 0x181818ff, 0x181818ff, 0x181818ff, 0x181818ff, 0x181818ff, 0x181818ff, 0x181818ff, 0x181818ff, 0x181818ff, 0x181818ff, 0x181818ff, 0x181818ff, 0x181818ff, 0x181818ff, 0x181818ff, 0x181818ff, 0x181818ff, 0x181818ff, 0x181818ff, 0x181818ff, 0x181818ff, 0x181818ff, 0x181818ff, 0x181818ff, 0x181818ff, 0x181818ff, 0x181818ff, 0x181818ff, 0x181818ff, 0x181818ff, 0x181818ff, +0x181818ff, 0x181818ff, 0x181818ff, 0x181818ff, 0x181818ff, 0x181818ff, 0x181818ff, 0x181818ff, 0x181818ff, 0x181818ff, 0x181818ff, 0x181818ff, 0x181818ff, 0x181818ff, 0x181818ff, 0x181818ff, 0x181818ff, 0x181818ff, 0x181818ff, 0x181818ff, 0x181818ff, 0x181818ff, 0x181818ff, 0x181818ff, 0x181818ff, 0x181818ff, 0x181818ff, 0x171717ff, 0x0d0d0dff, 0x181813ff, 0x292929ff, 0x2f2f3bff, +0x282863ff, 0x121286ff, 0x030390ff, 0x00009eff, 0x000098ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000098ff, +0x00009dff, 0x010194ff, 0x191985ff, 0x22225bff, 0x313127ff, 0x2f2f30ff, 0x262626ff, 0x1e1e1eff, 0x191919ff, 0x171717ff, 0x1e1e1eff, 0x222222ff, 0x1a1a1aff, 0x181818ff, 0x252525ff, 0x232323ff, 0x1e1e1eff, 0x1e1e1eff, 0x1c1c1cff, 0x191919ff, 0x191919ff, 0x191919ff, 0x191919ff, 0x191919ff, 0x191919ff, 0x191919ff, 0x191919ff, 0x191919ff, 0x191919ff, 0x191919ff, 0x1a1a1aff, 0x1a1a1aff, +0x0f0f0fff, 0x040404ff, 0x000000ff, 0x080808ff, 0x080808ff, 0x050505ff, 0x070707ff, 0x070707ff, 0x070707ff, 0x070707ff, 0x060606ff, 0x000000ff, 0x090909ff, 0x0e0e0eff, 0x040404ff, 0x070707ff, 0x040404ff, 0x121212ff, 0x080808ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, +0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, +0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, +0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x191918ff, 0x212155ff, 0x0c0c82ff, +0x050593ff, 0x00009fff, 0x00009bff, 0x000098ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000098ff, 0x00009aff, +0x020296ff, 0x2f2f86ff, 0x6a6a84ff, 0x737381ff, 0x767673ff, 0x767676ff, 0x707070ff, 0x6b6b6bff, 0x5c5c5cff, 0x595959ff, 0x686868ff, 0x707070ff, 0x676767ff, 0x5c5c5cff, 0x5e5e5eff, 0x606060ff, 0x616161ff, 0x606060ff, 0x5e5e5eff, 0x5e5e5eff, 0x5e5e5eff, 0x5e5e5eff, 0x5e5e5eff, 0x5e5e5eff, 0x5e5e5eff, 0x5e5e5eff, 0x5e5e5eff, 0x5e5e5eff, 0x5e5e5eff, 0x5e5e5eff, 0x5f5f5fff, 0x5e5e5eff, +0x515151ff, 0x474747ff, 0x464646ff, 0x494949ff, 0x494949ff, 0x474747ff, 0x474747ff, 0x474747ff, 0x474747ff, 0x474747ff, 0x474747ff, 0x434343ff, 0x494949ff, 0x494949ff, 0x464646ff, 0x474747ff, 0x464646ff, 0x4b4b4bff, 0x404040ff, 0x343434ff, 0x353535ff, 0x353535ff, 0x353535ff, 0x353535ff, 0x353535ff, 0x353535ff, 0x353535ff, 0x353535ff, 0x353535ff, 0x343434ff, 0x383838ff, 0x3f3f3fff, +0x494949ff, 0x4b4b4bff, 0x2d2d2dff, 0x1a1a1aff, 0x191919ff, 0x1b1b1bff, 0x1b1b1bff, 0x1b1b1bff, 0x1b1b1bff, 0x1b1b1bff, 0x1b1b1bff, 0x1b1b1bff, 0x1b1b1bff, 0x1b1b1bff, 0x1b1b1bff, 0x1b1b1bff, 0x1b1b1bff, 0x1b1b1bff, 0x1b1b1bff, 0x1b1b1bff, 0x1b1b1bff, 0x1b1b1bff, 0x1b1b1bff, 0x1b1b1bff, 0x1b1b1bff, 0x1b1b1bff, 0x1b1b1bff, 0x1b1b1bff, 0x1b1b1bff, 0x1b1b1bff, 0x1b1b1bff, 0x1b1b1bff, +0x1b1b1bff, 0x1b1b1bff, 0x1b1b1bff, 0x1b1b1bff, 0x1b1b1bff, 0x1b1b1bff, 0x1b1b1bff, 0x1b1b1bff, 0x1b1b1bff, 0x1b1b1bff, 0x1b1b1bff, 0x1b1b1bff, 0x1b1b1bff, 0x1b1b1bff, 0x1b1b1bff, 0x1b1b1bff, 0x1b1b1bff, 0x1b1b1bff, 0x1b1b1bff, 0x1b1b1bff, 0x1b1b1bff, 0x1b1b1bff, 0x1b1b1bff, 0x1b1b1bff, 0x1b1b1bff, 0x1b1b1bff, 0x1b1b1bff, 0x1b1b1bff, 0x1b1b1bff, 0x1b1b1bff, 0x1b1b1bff, 0x1b1b1bff, +0x1b1b1bff, 0x1b1b1bff, 0x1b1b1bff, 0x1b1b1bff, 0x1b1b1bff, 0x1b1b1bff, 0x1b1b1bff, 0x1b1b1bff, 0x1b1b1bff, 0x1b1b1bff, 0x1b1b1bff, 0x1b1b1bff, 0x1b1b1bff, 0x1b1b1bff, 0x1b1b1bff, 0x1b1b1bff, 0x1b1b1bff, 0x1b1b1bff, 0x1b1b1bff, 0x1b1b1bff, 0x1b1b1bff, 0x1b1b1bff, 0x1b1b1bff, 0x1b1b1bff, 0x1b1b1bff, 0x1b1b1bff, 0x1b1b1bff, 0x1a1a1bff, 0x1c1c14ff, 0x181836ff, 0x0a0a8eff, 0x0000a5ff, +0x00009cff, 0x000098ff, 0x000098ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000098ff, 0x00009dff, +0x141487ff, 0x71717bff, 0xb7b7aaff, 0xc1c1bdff, 0xbebebfff, 0xbebebeff, 0xc0c0c0ff, 0xc0c0c0ff, 0xbdbdbdff, 0xbababaff, 0xbcbcbcff, 0xbdbdbdff, 0xbcbcbcff, 0xb9b9b9ff, 0xb7b7b7ff, 0xb7b7b7ff, 0xb5b5b5ff, 0xbebebeff, 0xc5c5c5ff, 0xc4c4c4ff, 0xc4c4c4ff, 0xc4c4c4ff, 0xc4c4c4ff, 0xc4c4c4ff, 0xc4c4c4ff, 0xc4c4c4ff, 0xc4c4c4ff, 0xc4c4c4ff, 0xc4c4c4ff, 0xc4c4c4ff, 0xc4c4c4ff, 0xc3c3c3ff, +0xc1c1c1ff, 0xc0c0c0ff, 0xc1c1c1ff, 0xc0c0c0ff, 0xc1c1c1ff, 0xc1c1c1ff, 0xc1c1c1ff, 0xc1c1c1ff, 0xc1c1c1ff, 0xc1c1c1ff, 0xc1c1c1ff, 0xc2c2c2ff, 0xc1c1c1ff, 0xc0c0c0ff, 0xc1c1c1ff, 0xc1c1c1ff, 0xc1c1c1ff, 0xc1c1c1ff, 0xc0c0c0ff, 0xbdbdbdff, 0xbdbdbdff, 0xbdbdbdff, 0xbdbdbdff, 0xbdbdbdff, 0xbdbdbdff, 0xbdbdbdff, 0xbebebeff, 0xbebebeff, 0xbebebeff, 0xbbbbbbff, 0xc5c5c5ff, 0xd3d3d3ff, +0xdededeff, 0xc0c0c0ff, 0x888888ff, 0x676767ff, 0x5c5c5cff, 0x5f5f5fff, 0x5f5f5fff, 0x5f5f5fff, 0x5f5f5fff, 0x5f5f5fff, 0x5f5f5fff, 0x5f5f5fff, 0x5f5f5fff, 0x5f5f5fff, 0x5f5f5fff, 0x5f5f5fff, 0x5f5f5fff, 0x5f5f5fff, 0x5f5f5fff, 0x5f5f5fff, 0x5f5f5fff, 0x5f5f5fff, 0x5f5f5fff, 0x5f5f5fff, 0x5f5f5fff, 0x5f5f5fff, 0x5f5f5fff, 0x5f5f5fff, 0x5f5f5fff, 0x5f5f5fff, 0x5f5f5fff, 0x5f5f5fff, +0x5f5f5fff, 0x5f5f5fff, 0x5f5f5fff, 0x5f5f5fff, 0x5f5f5fff, 0x5f5f5fff, 0x5f5f5fff, 0x5f5f5fff, 0x5f5f5fff, 0x5f5f5fff, 0x5f5f5fff, 0x5f5f5fff, 0x5f5f5fff, 0x5f5f5fff, 0x5f5f5fff, 0x5f5f5fff, 0x5f5f5fff, 0x5f5f5fff, 0x5f5f5fff, 0x5f5f5fff, 0x5f5f5fff, 0x5f5f5fff, 0x5f5f5fff, 0x5f5f5fff, 0x5f5f5fff, 0x5f5f5fff, 0x5f5f5fff, 0x5f5f5fff, 0x5f5f5fff, 0x5f5f5fff, 0x5f5f5fff, 0x5f5f5fff, +0x5f5f5fff, 0x5f5f5fff, 0x5f5f5fff, 0x5f5f5fff, 0x5f5f5fff, 0x5f5f5fff, 0x5f5f5fff, 0x5f5f5fff, 0x5f5f5fff, 0x5f5f5fff, 0x5f5f5fff, 0x5f5f5fff, 0x5f5f5fff, 0x5f5f5fff, 0x5f5f5fff, 0x5f5f5fff, 0x5f5f5fff, 0x5f5f5fff, 0x5f5f5fff, 0x5f5f5fff, 0x5f5f5fff, 0x5f5f5fff, 0x5f5f5fff, 0x5f5f5fff, 0x5f5f5fff, 0x5f5f5fff, 0x5f5f5fff, 0x606061ff, 0x5a5a54ff, 0x333347ff, 0x090978ff, 0x000099ff, +0x00009aff, 0x000098ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000098ff, 0x00009dff, +0x181883ff, 0x7a7a7cff, 0xb0b0acff, 0xaeaeaeff, 0xacacacff, 0xacacacff, 0xacacacff, 0xacacacff, 0xafafafff, 0xbababaff, 0xbebebeff, 0xbcbcbcff, 0xbdbdbdff, 0xbdbdbdff, 0xc1c1c1ff, 0xc1c1c1ff, 0xbfbfbfff, 0xd2d2d2ff, 0xdededeff, 0xd9d9d9ff, 0xdadadaff, 0xdcdcdcff, 0xdbdbdbff, 0xdbdbdbff, 0xdbdbdbff, 0xdbdbdbff, 0xdbdbdbff, 0xdbdbdbff, 0xdbdbdbff, 0xdbdbdbff, 0xdbdbdbff, 0xdcdcdcff, +0xdcdcdcff, 0xddddddff, 0xddddddff, 0xddddddff, 0xddddddff, 0xddddddff, 0xddddddff, 0xddddddff, 0xddddddff, 0xddddddff, 0xddddddff, 0xddddddff, 0xddddddff, 0xddddddff, 0xddddddff, 0xddddddff, 0xddddddff, 0xddddddff, 0xddddddff, 0xdededeff, 0xdededeff, 0xe0e0e0ff, 0xe2e2e2ff, 0xe2e2e2ff, 0xdededeff, 0xdadadaff, 0xd4d4d4ff, 0xd2d2d2ff, 0xd2d2d2ff, 0xd2d2d2ff, 0xd3d3d3ff, 0xd2d2d2ff, +0xe0e0e0ff, 0x9d9d9dff, 0x757575ff, 0x7a7a7aff, 0x656565ff, 0x696969ff, 0x696969ff, 0x696969ff, 0x696969ff, 0x696969ff, 0x696969ff, 0x696969ff, 0x696969ff, 0x696969ff, 0x696969ff, 0x696969ff, 0x696969ff, 0x696969ff, 0x696969ff, 0x696969ff, 0x696969ff, 0x696969ff, 0x696969ff, 0x696969ff, 0x696969ff, 0x696969ff, 0x696969ff, 0x696969ff, 0x696969ff, 0x696969ff, 0x696969ff, 0x696969ff, +0x696969ff, 0x696969ff, 0x696969ff, 0x696969ff, 0x696969ff, 0x696969ff, 0x696969ff, 0x696969ff, 0x696969ff, 0x696969ff, 0x696969ff, 0x696969ff, 0x696969ff, 0x696969ff, 0x696969ff, 0x696969ff, 0x696969ff, 0x696969ff, 0x696969ff, 0x696969ff, 0x696969ff, 0x696969ff, 0x696969ff, 0x696969ff, 0x696969ff, 0x696969ff, 0x696969ff, 0x696969ff, 0x696969ff, 0x696969ff, 0x696969ff, 0x696969ff, +0x696969ff, 0x696969ff, 0x696969ff, 0x696969ff, 0x696969ff, 0x696969ff, 0x696969ff, 0x696969ff, 0x696969ff, 0x696969ff, 0x696969ff, 0x696969ff, 0x696969ff, 0x696969ff, 0x696969ff, 0x696969ff, 0x696969ff, 0x696969ff, 0x696969ff, 0x696969ff, 0x696969ff, 0x696969ff, 0x696969ff, 0x696969ff, 0x696969ff, 0x696969ff, 0x696969ff, 0x696969ff, 0x6d6d6dff, 0x59594eff, 0x1e1e48ff, 0x00008fff, +0x00009dff, 0x000098ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000098ff, 0x00009dff, +0x161683ff, 0x78787dff, 0xadada9ff, 0xa9a9a9ff, 0xa8a8a8ff, 0xa8a8a8ff, 0xa9a9a9ff, 0xa7a7a7ff, 0xaaaaaaff, 0xbababaff, 0xc1c1c1ff, 0xbfbfbfff, 0xbfbfbfff, 0xc2c2c2ff, 0xaeaeaeff, 0xaeaeaeff, 0xafafafff, 0x939393ff, 0x989898ff, 0xa3a3a3ff, 0x9e9e9eff, 0x959595ff, 0x979797ff, 0x979797ff, 0x979797ff, 0x979797ff, 0x979797ff, 0x979797ff, 0x979797ff, 0x979797ff, 0x979797ff, 0x979797ff, +0x979797ff, 0x979797ff, 0x979797ff, 0x979797ff, 0x979797ff, 0x979797ff, 0x979797ff, 0x979797ff, 0x979797ff, 0x979797ff, 0x979797ff, 0x979797ff, 0x979797ff, 0x979797ff, 0x979797ff, 0x979797ff, 0x979797ff, 0x979797ff, 0x979797ff, 0x979797ff, 0x999999ff, 0x8f8f8fff, 0x848484ff, 0x868686ff, 0x919191ff, 0xa9a9a9ff, 0xc4c4c4ff, 0xcdcdcdff, 0xcbcbcbff, 0xcbcbcbff, 0xcbcbcbff, 0xcacacaff, +0xd7d7d7ff, 0x929292ff, 0x6c6c6cff, 0x777777ff, 0x616161ff, 0x666666ff, 0x656565ff, 0x656565ff, 0x656565ff, 0x656565ff, 0x656565ff, 0x656565ff, 0x656565ff, 0x656565ff, 0x656565ff, 0x656565ff, 0x656565ff, 0x656565ff, 0x656565ff, 0x656565ff, 0x656565ff, 0x656565ff, 0x656565ff, 0x656565ff, 0x656565ff, 0x656565ff, 0x656565ff, 0x656565ff, 0x656565ff, 0x656565ff, 0x656565ff, 0x656565ff, +0x656565ff, 0x656565ff, 0x656565ff, 0x656565ff, 0x656565ff, 0x656565ff, 0x656565ff, 0x656565ff, 0x656565ff, 0x656565ff, 0x656565ff, 0x656565ff, 0x656565ff, 0x656565ff, 0x656565ff, 0x656565ff, 0x656565ff, 0x656565ff, 0x656565ff, 0x656565ff, 0x656565ff, 0x656565ff, 0x656565ff, 0x656565ff, 0x656565ff, 0x656565ff, 0x656565ff, 0x656565ff, 0x656565ff, 0x656565ff, 0x656565ff, 0x656565ff, +0x656565ff, 0x656565ff, 0x656565ff, 0x656565ff, 0x656565ff, 0x656565ff, 0x656565ff, 0x656565ff, 0x656565ff, 0x656565ff, 0x656565ff, 0x656565ff, 0x656565ff, 0x656565ff, 0x656565ff, 0x656565ff, 0x656565ff, 0x656565ff, 0x656565ff, 0x656565ff, 0x656565ff, 0x656565ff, 0x656565ff, 0x656565ff, 0x656565ff, 0x656565ff, 0x656565ff, 0x656565ff, 0x6a6a6bff, 0x5c5c4eff, 0x1f1f44ff, 0x00008fff, +0x00009dff, 0x000098ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000098ff, 0x00009dff, +0x161683ff, 0x78787cff, 0xaeaea9ff, 0xa9a9aaff, 0xa9a9a9ff, 0xa9a9a9ff, 0xa9a9a9ff, 0xa9a9a9ff, 0xa8a8a8ff, 0xa7a7a7ff, 0xa6a6a6ff, 0xa6a6a6ff, 0xa4a4a4ff, 0xa6a6a6ff, 0x8d8d8dff, 0x888888ff, 0x9a9a9aff, 0x858585ff, 0x888888ff, 0x969696ff, 0x919191ff, 0x868686ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, +0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x8b8b8bff, 0x7e7e7eff, 0x707070ff, 0x727272ff, 0x818181ff, 0x9f9f9fff, 0xc2c2c2ff, 0xcececeff, 0xcbcbcbff, 0xccccccff, 0xccccccff, 0xcbcbcbff, +0xd8d8d8ff, 0x949494ff, 0x6e6e6eff, 0x777777ff, 0x616161ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, +0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, +0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x656565ff, 0x6a6a6bff, 0x5b5b4eff, 0x1f1f46ff, 0x00008fff, +0x00009dff, 0x000098ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000098ff, 0x00009dff, +0x181885ff, 0x7d7d82ff, 0xb7b7b4ff, 0xb4b4b4ff, 0xb4b4b4ff, 0xb4b4b4ff, 0xb4b4b4ff, 0xb4b4b4ff, 0xb4b4b4ff, 0xb4b4b4ff, 0xb4b4b4ff, 0xb2b2b2ff, 0xb9b9b9ff, 0xc5c5c5ff, 0xcacacaff, 0xc8c8c8ff, 0xd5d5d5ff, 0xe6e6e6ff, 0xe3e3e3ff, 0xe1e1e1ff, 0xe1e1e1ff, 0xe3e3e3ff, 0xe1e1e1ff, 0xe0e0e0ff, 0xe0e0e0ff, 0xe0e0e0ff, 0xe0e0e0ff, 0xe0e0e0ff, 0xe0e0e0ff, 0xe0e0e0ff, 0xdcdcdcff, 0xd9d9d9ff, +0xd9d9d9ff, 0xd9d9d9ff, 0xd9d9d9ff, 0xd9d9d9ff, 0xd9d9d9ff, 0xd9d9d9ff, 0xd9d9d9ff, 0xd9d9d9ff, 0xd9d9d9ff, 0xd9d9d9ff, 0xd9d9d9ff, 0xd9d9d9ff, 0xd9d9d9ff, 0xd9d9d9ff, 0xd9d9d9ff, 0xd9d9d9ff, 0xd9d9d9ff, 0xd9d9d9ff, 0xd9d9d9ff, 0xd9d9d9ff, 0xd9d9d9ff, 0xdbdbdbff, 0xddddddff, 0xddddddff, 0xd9d9d9ff, 0xd4d4d4ff, 0xcdcdcdff, 0xcbcbcbff, 0xcbcbcbff, 0xccccccff, 0xccccccff, 0xcbcbcbff, +0xd8d8d8ff, 0x949494ff, 0x6e6e6eff, 0x777777ff, 0x616161ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, +0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, +0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x656565ff, 0x6a6a6bff, 0x5b5b4eff, 0x1f1f46ff, 0x00008fff, +0x00009dff, 0x000098ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000098ff, 0x00009eff, +0x131381ff, 0x565659ff, 0x6b6b66ff, 0x666667ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x676767ff, 0x686868ff, 0x666666ff, 0x727272ff, 0x8f8f8fff, 0x939393ff, 0x919191ff, 0x909090ff, 0x8d8d8dff, 0x8d8d8dff, 0x8d8d8dff, 0x8c8c8cff, 0x8e8e8eff, 0x9e9e9eff, 0xa4a4a4ff, 0xa3a3a3ff, 0xa3a3a3ff, 0xa3a3a3ff, 0xa3a3a3ff, 0xa3a3a3ff, 0xa0a0a0ff, 0xbdbdbdff, 0xd4d4d4ff, +0xcfcfcfff, 0xcfcfcfff, 0xcfcfcfff, 0xcfcfcfff, 0xcfcfcfff, 0xcfcfcfff, 0xcfcfcfff, 0xcfcfcfff, 0xcfcfcfff, 0xd0d0d0ff, 0xd1d1d1ff, 0xd1d1d1ff, 0xd1d1d1ff, 0xd1d1d1ff, 0xd1d1d1ff, 0xd0d0d0ff, 0xd0d0d0ff, 0xd0d0d0ff, 0xcfcfcfff, 0xcfcfcfff, 0xcfcfcfff, 0xcfcfcfff, 0xcfcfcfff, 0xcfcfcfff, 0xcececeff, 0xcdcdcdff, 0xcdcdcdff, 0xcbcbcbff, 0xccccccff, 0xccccccff, 0xccccccff, 0xcbcbcbff, +0xd8d8d8ff, 0x949494ff, 0x6e6e6eff, 0x777777ff, 0x616161ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, +0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, +0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x656565ff, 0x6a6a6bff, 0x5b5b4eff, 0x1f1f46ff, 0x00008fff, +0x00009dff, 0x000098ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000098ff, 0x00009eff, +0x151583ff, 0x5d5d62ff, 0x7a7a76ff, 0x797979ff, 0x787878ff, 0x787878ff, 0x787878ff, 0x787878ff, 0x7a7a7aff, 0x727272ff, 0x525252ff, 0x565656ff, 0x6b6b6bff, 0x575757ff, 0x6b6b6bff, 0x727272ff, 0x535353ff, 0x585858ff, 0x585858ff, 0x585858ff, 0x585858ff, 0x5a5a5aff, 0x646464ff, 0x686868ff, 0x686868ff, 0x686868ff, 0x686868ff, 0x686868ff, 0x686868ff, 0x666666ff, 0x7b7b7bff, 0x8c8c8cff, +0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x8b8b8bff, 0x7c7c7cff, 0x707070ff, 0x727272ff, 0x727272ff, 0x727272ff, 0x717171ff, 0x787878ff, 0x7e7e7eff, 0x7b7b7bff, 0x878787ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x8a8a8aff, 0xaaaaaaff, 0xc9c9c9ff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xcbcbcbff, +0xd8d8d8ff, 0x949494ff, 0x6e6e6eff, 0x777777ff, 0x616161ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, +0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, +0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x656565ff, 0x6a6a6bff, 0x5b5b4eff, 0x1f1f46ff, 0x00008fff, +0x00009dff, 0x000098ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000098ff, 0x00009dff, +0x1b1b89ff, 0x6b6b6fff, 0x9c9c98ff, 0xb7b7b8ff, 0xb4b4b4ff, 0xb4b4b4ff, 0xb4b4b4ff, 0xb4b4b4ff, 0xb6b6b6ff, 0xb1b1b1ff, 0x9b9b9bff, 0x9f9f9fff, 0xadadadff, 0x999999ff, 0xa7a7a7ff, 0xaaaaaaff, 0xa2a2a2ff, 0xb3b3b3ff, 0xb0b0b0ff, 0xb0b0b0ff, 0xb0b0b0ff, 0xafafafff, 0xadadadff, 0xacacacff, 0xacacacff, 0xacacacff, 0xadadadff, 0xadadadff, 0xadadadff, 0xadadadff, 0xa8a8a8ff, 0xa4a4a4ff, +0xa5a5a5ff, 0xa5a5a5ff, 0xa6a6a6ff, 0xa6a6a6ff, 0xa6a6a6ff, 0xa6a6a6ff, 0xa6a6a6ff, 0xa5a5a5ff, 0xa7a7a7ff, 0x9e9e9eff, 0x959595ff, 0x969696ff, 0x969696ff, 0x969696ff, 0x969696ff, 0x9a9a9aff, 0x9e9e9eff, 0x9c9c9cff, 0xa2a2a2ff, 0xa3a3a3ff, 0xa3a3a3ff, 0xa3a3a3ff, 0xa3a3a3ff, 0xa2a2a2ff, 0xa4a4a4ff, 0xb7b7b7ff, 0xcacacaff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xcbcbcbff, +0xd8d8d8ff, 0x949494ff, 0x6e6e6eff, 0x777777ff, 0x616161ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, +0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, +0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x656565ff, 0x6a6a6bff, 0x5b5b4eff, 0x1f1f46ff, 0x00008fff, +0x00009dff, 0x000098ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000098ff, 0x00009dff, +0x181886ff, 0x6d6d72ff, 0x9e9e99ff, 0xababacff, 0xa9a9a9ff, 0xa9a9a9ff, 0xa9a9a9ff, 0xa9a9a9ff, 0xa9a9a9ff, 0xaaaaaaff, 0xafafafff, 0xaaaaaaff, 0xa9a9a9ff, 0xbababaff, 0xbababaff, 0xb7b7b7ff, 0xc2c2c2ff, 0xc9c9c9ff, 0xc6c6c6ff, 0xc7c7c7ff, 0xc7c7c7ff, 0xc7c7c7ff, 0xc7c7c7ff, 0xc7c7c7ff, 0xc8c8c8ff, 0xc6c6c6ff, 0xc2c2c2ff, 0xc2c2c2ff, 0xc2c2c2ff, 0xc2c2c2ff, 0xc6c6c6ff, 0xc8c8c8ff, +0xc7c7c7ff, 0xc4c4c4ff, 0xc2c2c2ff, 0xc3c3c3ff, 0xc3c3c3ff, 0xc3c3c3ff, 0xc2c2c2ff, 0xc5c5c5ff, 0xc5c5c5ff, 0xc6c6c6ff, 0xcbcbcbff, 0xcacacaff, 0xcbcbcbff, 0xcacacaff, 0xcbcbcbff, 0xccccccff, 0xccccccff, 0xcdcdcdff, 0xd1d1d1ff, 0xd0d0d0ff, 0xd0d0d0ff, 0xd0d0d0ff, 0xd1d1d1ff, 0xd2d2d2ff, 0xd1d1d1ff, 0xcfcfcfff, 0xcdcdcdff, 0xcbcbcbff, 0xccccccff, 0xccccccff, 0xccccccff, 0xcbcbcbff, +0xd8d8d8ff, 0x949494ff, 0x6e6e6eff, 0x777777ff, 0x616161ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, +0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, +0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x656565ff, 0x6a6a6bff, 0x5b5b4eff, 0x1f1f46ff, 0x00008fff, +0x00009dff, 0x000098ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000098ff, 0x00009dff, +0x161683ff, 0x79797eff, 0xb1b1acff, 0xaaaaaaff, 0xa9a9a9ff, 0xa9a9a9ff, 0xa9a9a9ff, 0xa9a9a9ff, 0xa9a9a9ff, 0xa9a9a9ff, 0xacacacff, 0x9e9e9eff, 0x838383ff, 0x848484ff, 0x848484ff, 0x848484ff, 0x818181ff, 0x858585ff, 0x888888ff, 0x878787ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x878787ff, 0x8a8a8aff, 0x818181ff, 0x727272ff, 0x727272ff, 0x727272ff, 0x707070ff, 0x808080ff, 0x8a8a8aff, +0x878787ff, 0x787878ff, 0x707070ff, 0x727272ff, 0x727272ff, 0x727272ff, 0x6f6f6fff, 0x7d7d7dff, 0x7d7d7dff, 0x7c7c7cff, 0x8a8a8aff, 0x888888ff, 0x888888ff, 0x888888ff, 0x868686ff, 0x7d7d7dff, 0x787878ff, 0x818181ff, 0x909090ff, 0x929292ff, 0x919191ff, 0x929292ff, 0x8d8d8dff, 0x898989ff, 0x8e8e8eff, 0xbababaff, 0xd0d0d0ff, 0xcbcbcbff, 0xccccccff, 0xccccccff, 0xccccccff, 0xcbcbcbff, +0xd8d8d8ff, 0x949494ff, 0x6e6e6eff, 0x777777ff, 0x616161ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, +0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, +0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x656565ff, 0x6a6a6bff, 0x5b5b4eff, 0x1f1f46ff, 0x00008fff, +0x00009dff, 0x000098ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000098ff, 0x00009dff, +0x171784ff, 0x7c7c80ff, 0xb5b5b1ff, 0xb1b1b2ff, 0xb1b1b1ff, 0xb1b1b1ff, 0xb1b1b1ff, 0xb1b1b1ff, 0xb1b1b1ff, 0xb1b1b1ff, 0xb2b2b2ff, 0xaeaeaeff, 0xa0a0a0ff, 0xa0a0a0ff, 0xa5a5a5ff, 0xa4a4a4ff, 0xa1a1a1ff, 0xb1b1b1ff, 0xbcbcbcff, 0xb8b8b8ff, 0xb7b7b7ff, 0xb7b7b7ff, 0xb7b7b7ff, 0xb7b7b7ff, 0xb7b7b7ff, 0xb0b0b0ff, 0xaaaaaaff, 0xaaaaaaff, 0xaaaaaaff, 0xa9a9a9ff, 0xafafafff, 0xb3b3b3ff, +0xb2b2b2ff, 0xacacacff, 0xa9a9a9ff, 0xaaaaaaff, 0xaaaaaaff, 0xaaaaaaff, 0xa9a9a9ff, 0xaeaeaeff, 0xaeaeaeff, 0xaeaeaeff, 0xb3b3b3ff, 0xb2b2b2ff, 0xb2b2b2ff, 0xb5b5b5ff, 0xacacacff, 0x8e8e8eff, 0x848484ff, 0x898989ff, 0x8e8e8eff, 0x8f8f8fff, 0x8f8f8fff, 0x909090ff, 0x828282ff, 0x747474ff, 0x7c7c7cff, 0xb5b5b5ff, 0xd2d2d2ff, 0xcbcbcbff, 0xccccccff, 0xccccccff, 0xccccccff, 0xcbcbcbff, +0xd8d8d8ff, 0x949494ff, 0x6e6e6eff, 0x777777ff, 0x616161ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, +0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, +0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x656565ff, 0x6a6a6bff, 0x5b5b4eff, 0x1f1f46ff, 0x00008fff, +0x00009dff, 0x000098ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000098ff, 0x00009eff, +0x151583ff, 0x67676bff, 0x8c8c89ff, 0x898989ff, 0x898989ff, 0x898989ff, 0x898989ff, 0x898989ff, 0x898989ff, 0x898989ff, 0x898989ff, 0x8c8c8cff, 0x919191ff, 0x9a9a9aff, 0xaeaeaeff, 0xb6b6b6ff, 0xb4b4b4ff, 0xb8b8b8ff, 0xbbbbbbff, 0xc2c2c2ff, 0xc7c7c7ff, 0xc5c5c5ff, 0xc6c6c6ff, 0xc6c6c6ff, 0xcececeff, 0xdcdcdcff, 0xdededeff, 0xe0e0e0ff, 0xe0e0e0ff, 0xe0e0e0ff, 0xdfdfdfff, 0xdededeff, +0xdededeff, 0xdfdfdfff, 0xe0e0e0ff, 0xddddddff, 0xddddddff, 0xddddddff, 0xddddddff, 0xdbdbdbff, 0xdcdcdcff, 0xdadadaff, 0xd7d7d7ff, 0xd7d7d7ff, 0xd7d7d7ff, 0xd8d8d8ff, 0xd5d5d5ff, 0xc8c8c8ff, 0xc4c4c4ff, 0xc4c4c4ff, 0xc3c3c3ff, 0xc3c3c3ff, 0xc3c3c3ff, 0xc4c4c4ff, 0xbfbfbfff, 0xbbbbbbff, 0xbcbcbcff, 0xc8c8c8ff, 0xcdcdcdff, 0xcbcbcbff, 0xccccccff, 0xccccccff, 0xccccccff, 0xcbcbcbff, +0xd8d8d8ff, 0x949494ff, 0x6e6e6eff, 0x777777ff, 0x616161ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, +0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, +0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x656565ff, 0x6a6a6bff, 0x5b5b4eff, 0x1f1f46ff, 0x00008fff, +0x00009dff, 0x000098ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000098ff, 0x00009eff, +0x131382ff, 0x555558ff, 0x6a6a66ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x686868ff, 0x606060ff, 0x4f4f4fff, 0x4b4b4bff, 0x595959ff, 0x696969ff, 0x676767ff, 0x666666ff, 0x636363ff, 0x707070ff, 0x7b7b7bff, 0x797979ff, 0x777777ff, 0x6a6a6aff, 0x767676ff, 0x9b9b9bff, 0xa1a1a1ff, 0x989898ff, 0x989898ff, 0x989898ff, 0x989898ff, 0x989898ff, +0x989898ff, 0x989898ff, 0x9a9a9aff, 0xa2a2a2ff, 0xa5a5a5ff, 0xa4a4a4ff, 0xa7a7a7ff, 0xabababff, 0xaaaaaaff, 0xb3b3b3ff, 0xbababaff, 0xb9b9b9ff, 0xb9b9b9ff, 0xbababaff, 0xc0c0c0ff, 0xd4d4d4ff, 0xdadadaff, 0xd9d9d9ff, 0xd9d9d9ff, 0xd9d9d9ff, 0xd9d9d9ff, 0xd9d9d9ff, 0xdadadaff, 0xdbdbdbff, 0xdadadaff, 0xd4d4d4ff, 0xcdcdcdff, 0xcbcbcbff, 0xccccccff, 0xccccccff, 0xccccccff, 0xcbcbcbff, +0xd8d8d8ff, 0x949494ff, 0x6e6e6eff, 0x777777ff, 0x616161ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, +0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, +0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x656565ff, 0x6a6a6bff, 0x5b5b4eff, 0x1f1f46ff, 0x00008fff, +0x00009dff, 0x000098ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000098ff, 0x00009dff, +0x171784ff, 0x78787cff, 0xaaaaa7ff, 0xa4a4a4ff, 0xa3a3a3ff, 0xa3a3a3ff, 0xa2a2a2ff, 0xa2a2a2ff, 0xa3a3a3ff, 0xa3a3a3ff, 0xa6a6a6ff, 0x999999ff, 0x7c7c7cff, 0x747474ff, 0x767676ff, 0x787878ff, 0x787878ff, 0x767676ff, 0x818181ff, 0x8a8a8aff, 0x888888ff, 0x868686ff, 0x808080ff, 0x717171ff, 0x6c6c6cff, 0x7c7c7cff, 0x818181ff, 0x727272ff, 0x727272ff, 0x727272ff, 0x727272ff, 0x727272ff, +0x727272ff, 0x727272ff, 0x767676ff, 0x858585ff, 0x898989ff, 0x8a8a8aff, 0x7e7e7eff, 0x6a6a6aff, 0x686868ff, 0x777777ff, 0x848484ff, 0x818181ff, 0x818181ff, 0x757575ff, 0x787878ff, 0x979797ff, 0xa1a1a1ff, 0x9f9f9fff, 0x9f9f9fff, 0x9f9f9fff, 0x9f9f9fff, 0x9f9f9fff, 0x9f9f9fff, 0x9e9e9eff, 0x9f9f9fff, 0xacacacff, 0xc5c5c5ff, 0xcdcdcdff, 0xcbcbcbff, 0xccccccff, 0xccccccff, 0xcbcbcbff, +0xd8d8d8ff, 0x949494ff, 0x6e6e6eff, 0x777777ff, 0x616161ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, +0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, +0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x656565ff, 0x6a6a6bff, 0x5b5b4eff, 0x1f1f46ff, 0x00008fff, +0x00009dff, 0x000098ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000098ff, 0x00009dff, +0x191987ff, 0x6b6b70ff, 0x9b9b97ff, 0xb3b3b3ff, 0xb5b5b5ff, 0xb7b7b7ff, 0xb9b9b9ff, 0xb9b9b9ff, 0xb4b4b4ff, 0xadadadff, 0xacacacff, 0xacacacff, 0xabababff, 0xacacacff, 0xacacacff, 0xabababff, 0xabababff, 0xaaaaaaff, 0xb8b8b8ff, 0xc3c3c3ff, 0xc1c1c1ff, 0xcacacaff, 0xcececeff, 0xcdcdcdff, 0xccccccff, 0xcbcbcbff, 0xcbcbcbff, 0xcbcbcbff, 0xcbcbcbff, 0xcbcbcbff, 0xcbcbcbff, 0xcbcbcbff, +0xcbcbcbff, 0xcbcbcbff, 0xccccccff, 0xcbcbcbff, 0xcbcbcbff, 0xcececeff, 0xbcbcbcff, 0x9e9e9eff, 0x9f9f9fff, 0x9f9f9fff, 0x9f9f9fff, 0x9f9f9fff, 0x9e9e9eff, 0x8e8e8eff, 0x878787ff, 0x898989ff, 0x898989ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x888888ff, 0x898989ff, 0x9d9d9dff, 0xc2c2c2ff, 0xcececeff, 0xcbcbcbff, 0xccccccff, 0xccccccff, 0xcbcbcbff, +0xd8d8d8ff, 0x949494ff, 0x6e6e6eff, 0x777777ff, 0x616161ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, +0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, +0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x656565ff, 0x6a6a6bff, 0x5b5b4eff, 0x1f1f46ff, 0x00008fff, +0x00009dff, 0x000098ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000098ff, 0x00009dff, +0x1a1a88ff, 0x656569ff, 0x959590ff, 0x9b9b9cff, 0x828282ff, 0x777777ff, 0x6b6b6bff, 0x717171ff, 0x898989ff, 0xafafafff, 0xb9b9b9ff, 0xb5b5b5ff, 0xb3b3b3ff, 0xb1b1b1ff, 0xaaaaaaff, 0xaaaaaaff, 0xaaaaaaff, 0xaaaaaaff, 0xa8a8a8ff, 0xa7a7a7ff, 0xabababff, 0xc7c7c7ff, 0xd4d4d4ff, 0xd2d2d2ff, 0xd2d2d2ff, 0xd2d2d2ff, 0xd0d0d0ff, 0xcdcdcdff, 0xcececeff, 0xcececeff, 0xcececeff, 0xcececeff, +0xcececeff, 0xcececeff, 0xcececeff, 0xcdcdcdff, 0xcdcdcdff, 0xcdcdcdff, 0xcfcfcfff, 0xd1d1d1ff, 0xd1d1d1ff, 0xd1d1d1ff, 0xd0d0d0ff, 0xd0d0d0ff, 0xd0d0d0ff, 0xd1d1d1ff, 0xd2d2d2ff, 0xd1d1d1ff, 0xd1d1d1ff, 0xd1d1d1ff, 0xd1d1d1ff, 0xd1d1d1ff, 0xd1d1d1ff, 0xd1d1d1ff, 0xd1d1d1ff, 0xd1d1d1ff, 0xd1d1d1ff, 0xcfcfcfff, 0xccccccff, 0xccccccff, 0xcbcbcbff, 0xccccccff, 0xccccccff, 0xcbcbcbff, +0xd8d8d8ff, 0x949494ff, 0x6e6e6eff, 0x777777ff, 0x616161ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666665ff, 0x666665ff, 0x656665ff, 0x656665ff, 0x666665ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, +0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, +0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x656565ff, 0x6a6a6bff, 0x5b5b4eff, 0x1f1f46ff, 0x00008fff, +0x00009dff, 0x000098ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000098ff, 0x00009dff, +0x181885ff, 0x818186ff, 0xbfbfbbff, 0xa1a1a1ff, 0x7f7f7fff, 0x808080ff, 0x737373ff, 0x666666ff, 0x5a5a5aff, 0x616161ff, 0x6c6c6cff, 0x747474ff, 0x828282ff, 0x989898ff, 0xb5b5b5ff, 0xb5b5b5ff, 0xb3b3b3ff, 0xadadadff, 0xaaaaaaff, 0xaaaaaaff, 0xa9a9a9ff, 0xb6b6b6ff, 0xbcbcbcff, 0xbababaff, 0xbababaff, 0xb8b8b8ff, 0xc2c2c2ff, 0xcfcfcfff, 0xcececeff, 0xcbcbcbff, 0xccccccff, 0xccccccff, +0xcbcbcbff, 0xcbcbcbff, 0xcbcbcbff, 0xcbcbcbff, 0xcbcbcbff, 0xcbcbcbff, 0xcbcbcbff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xcbcbcbff, 0xccccccff, 0xccccccff, 0xccccccff, 0xcbcbcbff, +0xd8d8d8ff, 0x949494ff, 0x6e6e6eff, 0x777777ff, 0x616161ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666665ff, 0x656566ff, 0x656665ff, 0x696069ff, 0x695e6aff, 0x656665ff, 0x666665ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x656565ff, 0x656565ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, +0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, +0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x656565ff, 0x6a6a6bff, 0x5b5b4eff, 0x1f1f46ff, 0x00008fff, +0x00009dff, 0x000098ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x00009eff, +0x131382ff, 0x545457ff, 0x757571ff, 0x818182ff, 0x9e9e9eff, 0xcbcbcbff, 0xc5c5c5ff, 0xbababaff, 0xadadadff, 0x8a8a8aff, 0x646464ff, 0x5c5c5cff, 0x4f4f4fff, 0x4d4d4dff, 0x666666ff, 0x676767ff, 0x6f6f6fff, 0x9d9d9dff, 0xb3b3b3ff, 0xafafafff, 0xaeaeaeff, 0xa8a8a8ff, 0xa5a5a5ff, 0xa5a5a5ff, 0xa5a5a5ff, 0xa3a3a3ff, 0xacacacff, 0xb7b7b7ff, 0xc1c1c1ff, 0xd1d1d1ff, 0xcececeff, 0xcececeff, +0xcdcdcdff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xcbcbcbff, 0xcbcbcbff, 0xcbcbcbff, 0xcbcbcbff, 0xcbcbcbff, 0xcbcbcbff, 0xcbcbcbff, 0xcbcbcbff, 0xcbcbcbff, 0xcbcbcbff, 0xcbcbcbff, 0xcbcbcbff, 0xcbcbcbff, 0xcbcbcbff, 0xcbcbcbff, 0xcbcbcbff, 0xcbcbcbff, 0xcbcbcbff, 0xcbcbcbff, 0xcbcbcbff, 0xcbcbcbff, 0xcbcbcbff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xcbcbcbff, +0xd8d8d8ff, 0x949494ff, 0x6e6e6eff, 0x777777ff, 0x616161ff, 0x666666ff, 0x666666ff, 0x666665ff, 0x656566ff, 0x616367ff, 0x64596eff, 0x4c7f56ff, 0x428d4bff, 0x675e6aff, 0x666665ff, 0x666666ff, 0x656565ff, 0x656565ff, 0x656565ff, 0x656565ff, 0x656565ff, 0x656565ff, 0x656565ff, 0x656565ff, 0x666666ff, 0x666666ff, 0x656565ff, 0x656565ff, 0x656565ff, 0x666666ff, 0x666666ff, 0x666666ff, +0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, +0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x656565ff, 0x6a6a6bff, 0x5b5b4eff, 0x1f1f46ff, 0x00008fff, +0x00009dff, 0x000098ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000098ff, 0x000099ff, 0x00009aff, 0x00009bff, 0x00009bff, 0x00009bff, 0x00009bff, 0x00009bff, 0x00009bff, 0x00009bff, 0x00009bff, 0x00009bff, 0x00009bff, 0x00009bff, 0x00009bff, 0x00009bff, 0x00009bff, 0x00009bff, 0x00009aff, 0x00009aff, 0x00009aff, 0x00009aff, 0x00009aff, 0x00009aff, 0x00009aff, 0x00009aff, 0x00009aff, 0x00009aff, 0x00009aff, 0x00009fff, +0x161686ff, 0x535359ff, 0x6d6d69ff, 0x666666ff, 0x6a6a6aff, 0x7e7e7eff, 0x7a7a7aff, 0x7d7d7dff, 0x929292ff, 0xa7a7a7ff, 0x999999ff, 0x878787ff, 0x858585ff, 0x969696ff, 0x7f7f7fff, 0x606060ff, 0x5d5d5dff, 0x626262ff, 0x676767ff, 0x666666ff, 0x7b7b7bff, 0x9f9f9fff, 0xadadadff, 0xaaaaaaff, 0xabababff, 0xadadadff, 0xabababff, 0xa5a5a5ff, 0xaeaeaeff, 0xb8b8b8ff, 0xb6b6b6ff, 0xb6b6b6ff, +0xc5c5c5ff, 0xcfcfcfff, 0xccccccff, 0xccccccff, 0xccccccff, 0xcdcdcdff, 0xcdcdcdff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xcbcbcbff, 0xcbcbcbff, 0xcbcbcbff, 0xcbcbcbff, 0xcbcbcbff, 0xcbcbcbff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xcbcbcbff, +0xd8d8d8ff, 0x949494ff, 0x6e6e6eff, 0x777777ff, 0x616161ff, 0x666666ff, 0x666665ff, 0x656666ff, 0x5c6269ff, 0x8b765aff, 0x899b40ff, 0x69c425ff, 0x8fa636ff, 0x615b6dff, 0x646666ff, 0x666665ff, 0x676767ff, 0x676767ff, 0x676767ff, 0x676767ff, 0x676767ff, 0x676767ff, 0x676767ff, 0x676767ff, 0x666666ff, 0x676767ff, 0x676767ff, 0x666666ff, 0x666666ff, 0x656565ff, 0x666666ff, 0x666666ff, +0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, +0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x656565ff, 0x6a6a6bff, 0x5b5b4eff, 0x1f1f46ff, 0x00008fff, +0x00009dff, 0x000098ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000098ff, 0x00009aff, 0x00009bff, 0x000095ff, 0x030392ff, 0x000092ff, 0x000091ff, 0x000091ff, 0x000091ff, 0x000091ff, 0x000091ff, 0x000091ff, 0x000091ff, 0x000091ff, 0x000091ff, 0x000091ff, 0x000091ff, 0x000091ff, 0x010191ff, 0x040493ff, 0x040493ff, 0x040493ff, 0x040493ff, 0x040493ff, 0x040493ff, 0x040493ff, 0x040493ff, 0x040493ff, 0x040493ff, 0x040494ff, 0x02029aff, +0x1f1f87ff, 0x67676dff, 0x848481ff, 0x878787ff, 0x787878ff, 0x757575ff, 0x757575ff, 0x737373ff, 0x646464ff, 0x656565ff, 0x6f6f6fff, 0x6e6e6eff, 0x838383ff, 0xacacacff, 0xa3a3a3ff, 0x8b8b8bff, 0x9b9b9bff, 0x9b9b9bff, 0x929292ff, 0x737373ff, 0x5b5b5bff, 0x717171ff, 0x686868ff, 0x656565ff, 0x717171ff, 0x838383ff, 0xa0a0a0ff, 0xa3a3a3ff, 0xa3a3a3ff, 0xa3a3a3ff, 0xa2a2a2ff, 0xa3a3a3ff, +0xadadadff, 0xb3b3b3ff, 0xb0b0b0ff, 0xb6b6b6ff, 0xc6c6c6ff, 0xc8c8c8ff, 0xc7c7c7ff, 0xc9c9c9ff, 0xcacacaff, 0xcacacaff, 0xcacacaff, 0xcacacaff, 0xcacacaff, 0xcacacaff, 0xcacacaff, 0xcacacaff, 0xcacacaff, 0xcacacaff, 0xcacacaff, 0xcacacaff, 0xcacacaff, 0xccccccff, 0xcececeff, 0xcececeff, 0xcececeff, 0xcececeff, 0xcdcdcdff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xcbcbcbff, +0xd8d8d8ff, 0x949494ff, 0x6e6e6eff, 0x777777ff, 0x616161ff, 0x666666ff, 0x666665ff, 0x5f6668ff, 0x77655cff, 0xde7630ff, 0xe79415ff, 0xde9615ff, 0xff7f23ff, 0x916a50ff, 0x5a646bff, 0x666665ff, 0x626262ff, 0x626262ff, 0x636363ff, 0x626262ff, 0x626262ff, 0x626262ff, 0x606060ff, 0x686868ff, 0x4c4c4cff, 0x444444ff, 0x6a6a6aff, 0x636363ff, 0x646464ff, 0x666666ff, 0x656565ff, 0x666666ff, +0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, +0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x656565ff, 0x6a6a6bff, 0x5b5b4eff, 0x1f1f46ff, 0x00008fff, +0x00009dff, 0x000098ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000098ff, 0x00009bff, 0x020296ff, 0x0e0e8eff, 0x232369ff, 0x333357ff, 0x373762ff, 0x393963ff, 0x383863ff, 0x383863ff, 0x383863ff, 0x383863ff, 0x383863ff, 0x383863ff, 0x383863ff, 0x383863ff, 0x383863ff, 0x383863ff, 0x363661ff, 0x3e3e68ff, 0x4c4c77ff, 0x4e4e79ff, 0x4e4e79ff, 0x4e4e79ff, 0x4e4e79ff, 0x4e4e79ff, 0x4f4f7aff, 0x50507bff, 0x50507aff, 0x50507bff, 0x4e4e79ff, 0x454574ff, +0x4d4d6cff, 0x696969ff, 0x7d7d7bff, 0x868686ff, 0x878787ff, 0x888888ff, 0x888888ff, 0x878787ff, 0x7e7e7eff, 0x777777ff, 0x777777ff, 0x757575ff, 0x777777ff, 0x7a7a7aff, 0x7e7e7eff, 0x7f7f7fff, 0x9a9a9aff, 0xb4b4b4ff, 0xdededeff, 0xbebebcff, 0x8f8f89ff, 0x9a9a9aff, 0x878783ff, 0x7a7a72ff, 0x76766eff, 0x74746cff, 0x818179ff, 0x8b8b83ff, 0xa3a39bff, 0xb3b3b3ff, 0xadadadff, 0xaeaeaeff, +0xacacacff, 0xaaaaaaff, 0xaaaaaaff, 0xadadadff, 0xb5b5b5ff, 0xb7b7b7ff, 0xb4b4b4ff, 0xbfbfbfff, 0xcececeff, 0xcdcdcdff, 0xcdcdcdff, 0xcdcdcdff, 0xcdcdcdff, 0xcdcdcdff, 0xcdcdcdff, 0xcdcdcdff, 0xcdcdcdff, 0xcdcdcdff, 0xcdcdcdff, 0xcdcdcdff, 0xcfcfcfff, 0xc6c6c6ff, 0xc4c4c4ff, 0xcacacaff, 0xc9c9c9ff, 0xc7c7c7ff, 0xc9c9c9ff, 0xcbcbcbff, 0xccccccff, 0xccccccff, 0xccccccff, 0xcbcbcbff, +0xd8d8d8ff, 0x949494ff, 0x6e6e6eff, 0x777777ff, 0x616161ff, 0x666666ff, 0x666565ff, 0x5d6768ff, 0x835b5aff, 0xd93c39ff, 0xed3433ff, 0xef3031ff, 0xcf4940ff, 0x82695fff, 0x5d6567ff, 0x676666ff, 0x474747ff, 0x2f2f2fff, 0x313131ff, 0x353535ff, 0x333333ff, 0x373737ff, 0x353535ff, 0x505050ff, 0x474747ff, 0x202020ff, 0x585858ff, 0x4d4d4dff, 0x515151ff, 0x696969ff, 0x656565ff, 0x666666ff, +0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, +0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x656565ff, 0x6a6a6bff, 0x5b5b4eff, 0x1f1f46ff, 0x00008fff, +0x00009dff, 0x000098ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x00009aff, 0x040492ff, 0x242469ff, 0x696981ff, 0x8c8c8cff, 0x969686ff, 0xb3b3a6ff, 0xbdbdb0ff, 0xbabaadff, 0xbabaadff, 0xbabaadff, 0xbabaadff, 0xbabaadff, 0xbabaadff, 0xbabaadff, 0xbabaadff, 0xbabaadff, 0xbabaadff, 0xb9b9acff, 0xbcbcb0ff, 0xc3c3b7ff, 0xc5c5b8ff, 0xc5c5b8ff, 0xc5c5b8ff, 0xc5c5b8ff, 0xc5c5b8ff, 0xc1c1b4ff, 0xbebeb1ff, 0xbfbfb1ff, 0xc0c0b3ff, 0xb5b5a8ff, 0x9b9b8dff, +0x8e8e85ff, 0x8d8d8cff, 0x919191ff, 0x8f8f8fff, 0x8f8f8fff, 0x8f8f8fff, 0x8f8f8fff, 0x8f8f8fff, 0x919191ff, 0x929292ff, 0x929292ff, 0x939393ff, 0x979797ff, 0x969696ff, 0x979797ff, 0x8a8a8aff, 0xa6a6a6ff, 0xccccccff, 0xdededcff, 0xcacadaff, 0x8484bcff, 0xfffff7ff, 0xb5b5d6ff, 0x6666b1ff, 0x6666acff, 0x5c5ca2ff, 0x56569cff, 0x5a5aa1ff, 0x5a5aa8ff, 0xf8f8f0ff, 0xe8e8e8ff, 0xe8e8e8ff, +0xe8e8e8ff, 0xe8e8e8ff, 0xe8e8e8ff, 0xe7e7e7ff, 0xe5e5e5ff, 0xe5e5e5ff, 0xe3e3e3ff, 0xe9e9e9ff, 0xf1f1f1ff, 0xf0f0f0ff, 0xf0f0f0ff, 0xf0f0f0ff, 0xf0f0f0ff, 0xf0f0f0ff, 0xf0f0f0ff, 0xf0f0f0ff, 0xf0f0f0ff, 0xf0f0f0ff, 0xf0f0f0ff, 0xefefefff, 0xf7f7f7ff, 0xd1d1d1ff, 0x939393ff, 0x8b8b8bff, 0x8d8d8dff, 0x959595ff, 0xacacacff, 0xc7c7c7ff, 0xccccccff, 0xcbcbcbff, 0xcbcbcbff, 0xcbcbcbff, +0xd8d8d8ff, 0x949494ff, 0x6e6e6eff, 0x777777ff, 0x616161ff, 0x666666ff, 0x666566ff, 0x616864ff, 0x745a6cff, 0x9a2e89ff, 0x951a9bff, 0x91169aff, 0x8f279eff, 0x74587fff, 0x60695fff, 0x686768ff, 0x565656ff, 0x2d2d2dff, 0x282828ff, 0x3d3d3dff, 0x373737ff, 0x494949ff, 0x4f4f4fff, 0x5a5a5aff, 0x616161ff, 0x4f4f4fff, 0x5e5e5eff, 0x5a5a5aff, 0x5c5c5cff, 0x676767ff, 0x656565ff, 0x666666ff, +0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, +0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x656565ff, 0x6a6a6bff, 0x5b5b4eff, 0x1f1f46ff, 0x00008fff, +0x00009dff, 0x000098ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x00009eff, 0x1c1c6dff, 0x48483dff, 0xadad9fff, 0xe0e0ddff, 0xd6d6d7ff, 0xe2e2e3ff, 0xe6e6e6ff, 0xe5e5e5ff, 0xe5e5e6ff, 0xe5e5e6ff, 0xe5e5e6ff, 0xe5e5e6ff, 0xe5e5e6ff, 0xe5e5e6ff, 0xe5e5e6ff, 0xe5e5e6ff, 0xe5e5e6ff, 0xe5e5e6ff, 0xe4e4e5ff, 0xe3e3e3ff, 0xe2e2e3ff, 0xe2e2e3ff, 0xe2e2e3ff, 0xe2e2e3ff, 0xe4e4e5ff, 0xd5d5d6ff, 0xcacacbff, 0xccccccff, 0xcececfff, 0xcbcbccff, 0xb4b4b5ff, +0xb4b4b4ff, 0xc0c0c0ff, 0xbfbfbfff, 0xbfbfbfff, 0xbfbfbfff, 0xbfbfbfff, 0xbfbfbfff, 0xbfbfbfff, 0xbfbfbfff, 0xbfbfbfff, 0xbebebeff, 0xc4c4c4ff, 0xd2d2d2ff, 0xdcdcdcff, 0xcfcfcfff, 0x949494ff, 0x838383ff, 0x989898ff, 0x939390ff, 0x9c9cb1ff, 0x6565acff, 0xe7e7dcff, 0x9191baff, 0x3c3c9aff, 0x45459eff, 0x46469fff, 0x47479fff, 0x46469fff, 0x353597ff, 0xe5e5dbff, 0xd5d5d5ff, 0xd5d5d5ff, +0xd5d5d5ff, 0xd5d5d5ff, 0xd5d5d5ff, 0xd5d5d5ff, 0xd5d5d5ff, 0xd5d5d5ff, 0xd5d5d5ff, 0xd4d4d4ff, 0xd3d3d3ff, 0xd3d3d3ff, 0xd3d3d3ff, 0xd3d3d3ff, 0xd3d3d3ff, 0xd3d3d3ff, 0xd3d3d3ff, 0xd3d3d3ff, 0xd3d3d3ff, 0xd3d3d3ff, 0xd3d3d3ff, 0xd2d2d2ff, 0xd6d6d6ff, 0xcfcfcfff, 0x757575ff, 0x3e3e3eff, 0x4c4c4cff, 0x717171ff, 0x989898ff, 0xc5c5c5ff, 0xd4d4d4ff, 0xcfcfcfff, 0xccccccff, 0xcbcbcbff, +0xd8d8d8ff, 0x949494ff, 0x6e6e6eff, 0x777777ff, 0x616161ff, 0x666666ff, 0x666666ff, 0x646664ff, 0x6c6865ff, 0x5c4c89ff, 0x311ebaff, 0x2413c5ff, 0x4e33a1ff, 0x756468ff, 0x626763ff, 0x676667ff, 0x686868ff, 0x5e5e5eff, 0x5a5a5aff, 0x646464ff, 0x616161ff, 0x686868ff, 0x6c6c6cff, 0x686868ff, 0x686868ff, 0x6b6b6bff, 0x686868ff, 0x686868ff, 0x686868ff, 0x656565ff, 0x666666ff, 0x666666ff, +0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, +0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x656565ff, 0x6a6a6bff, 0x5b5b4eff, 0x1f1f46ff, 0x00008fff, +0x00009dff, 0x000098ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x0000a0ff, 0x2b2b5cff, 0x56563cff, 0x9d9da0ff, 0xcacacaff, 0xbfbfbfff, 0xbdbdbdff, 0xbbbbbbff, 0xbababaff, 0xb7b7b7ff, 0xb3b3b3ff, 0xb3b3b3ff, 0xb3b3b3ff, 0xb3b3b3ff, 0xb3b3b3ff, 0xb3b3b3ff, 0xb3b3b3ff, 0xb3b3b3ff, 0xb3b3b3ff, 0xb3b3b3ff, 0xb3b3b3ff, 0xb3b3b3ff, 0xb3b3b3ff, 0xb3b3b3ff, 0xb3b3b3ff, 0xb4b4b4ff, 0xafafafff, 0xacacacff, 0xabababff, 0xb3b3b3ff, 0xc1c1c1ff, 0xaaaaaaff, +0xafafafff, 0xcdcdcdff, 0xd3d3d3ff, 0xd3d3d3ff, 0xcfcfcfff, 0xd0d0d0ff, 0xd0d0d0ff, 0xd0d0d0ff, 0xd0d0d0ff, 0xd0d0d0ff, 0xcfcfcfff, 0xd1d1d1ff, 0xd6d6d6ff, 0xd9d9d9ff, 0xaeaeaeff, 0x616161ff, 0x444444ff, 0x454545ff, 0x444444ff, 0x565654ff, 0x666660ff, 0x595959ff, 0x61615cff, 0x696960ff, 0x696960ff, 0x696960ff, 0x696960ff, 0x696960ff, 0x696960ff, 0x595959ff, 0x595959ff, 0x595959ff, +0x595959ff, 0x595959ff, 0x595959ff, 0x595959ff, 0x595959ff, 0x595959ff, 0x595959ff, 0x595959ff, 0x595959ff, 0x595959ff, 0x595959ff, 0x595959ff, 0x595959ff, 0x595959ff, 0x595959ff, 0x595959ff, 0x595959ff, 0x595959ff, 0x595959ff, 0x595959ff, 0x595959ff, 0x606060ff, 0x4d4d4dff, 0x373737ff, 0x414141ff, 0x707070ff, 0x909090ff, 0xb5b5b5ff, 0xc2c2c2ff, 0xc4c4c4ff, 0xcfcfcfff, 0xccccccff, +0xd8d8d8ff, 0x949494ff, 0x6e6e6eff, 0x777777ff, 0x616161ff, 0x666666ff, 0x666666ff, 0x666566ff, 0x666863ff, 0x5d6365ff, 0x4e5573ff, 0x4b5277ff, 0x555d6cff, 0x656961ff, 0x666566ff, 0x656565ff, 0x656565ff, 0x696969ff, 0x696969ff, 0x676767ff, 0x686868ff, 0x666666ff, 0x656565ff, 0x656565ff, 0x656565ff, 0x656565ff, 0x656565ff, 0x656565ff, 0x656565ff, 0x666666ff, 0x666666ff, 0x666666ff, +0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, +0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x656565ff, 0x6a6a6bff, 0x5b5b4eff, 0x1f1f46ff, 0x00008fff, +0x00009cff, 0x000098ff, 0x000098ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000099ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000099ff, +0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x00009dff, 0x191972ff, 0x505052ff, 0x7d7d7aff, 0x8c8c8cff, 0x878787ff, 0x868686ff, 0x8b8b8bff, 0x929292ff, 0xa0a0a0ff, 0xb1b1b1ff, 0xb0b0b0ff, 0xb0b0b0ff, 0xb0b0b0ff, 0xb0b0b0ff, 0xb0b0b0ff, 0xb0b0b0ff, 0xb0b0b0ff, 0xb0b0b0ff, 0xaeaeaeff, 0xacacacff, 0xacacacff, 0xacacacff, 0xa9a9a9ff, 0xa5a5a5ff, 0xa5a5a5ff, 0xa6a6a6ff, 0xa4a4a4ff, 0xa2a2a2ff, 0xa7a7a7ff, 0xb8b8b8ff, 0xb6b6b6ff, +0xb9b9b9ff, 0xccccccff, 0xbfbfbfff, 0xbababaff, 0xcdcdcdff, 0xcbcbcbff, 0xcbcbcbff, 0xcbcbcbff, 0xcbcbcbff, 0xcbcbcbff, 0xcbcbcbff, 0xcacacaff, 0xcfcfcfff, 0xbbbbbbff, 0x7f7f7fff, 0x4e4e4eff, 0x3c3c3cff, 0x414141ff, 0x3f3f3fff, 0x383838ff, 0x333333ff, 0x333333ff, 0x333333ff, 0x333333ff, 0x333333ff, 0x333333ff, 0x333333ff, 0x333333ff, 0x333333ff, 0x333333ff, 0x333333ff, 0x333333ff, +0x333333ff, 0x353535ff, 0x373737ff, 0x373737ff, 0x373737ff, 0x373737ff, 0x373737ff, 0x373737ff, 0x373737ff, 0x373737ff, 0x373737ff, 0x373737ff, 0x373737ff, 0x373737ff, 0x373737ff, 0x373737ff, 0x373737ff, 0x373737ff, 0x373737ff, 0x363636ff, 0x383838ff, 0x3a3a3aff, 0x3f3f3fff, 0x494949ff, 0x4c4c4cff, 0x6f6f6fff, 0x707070ff, 0x757575ff, 0x838383ff, 0x939393ff, 0xbdbdbdff, 0xcdcdcdff, +0xd9d9d9ff, 0x949494ff, 0x6e6e6eff, 0x777777ff, 0x616161ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x656566ff, 0x676764ff, 0x6a6a61ff, 0x6b6b60ff, 0x696862ff, 0x656566ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x656565ff, 0x656565ff, 0x656565ff, 0x656565ff, 0x656565ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, +0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, +0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x6b6b6bff, 0x5c5c4fff, 0x1c1c47ff, 0x000096ff, +0x0000a5ff, 0x0000a3ff, 0x00009eff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x00009aff, 0x00009eff, 0x0000a1ff, 0x0000a1ff, 0x0000a1ff, 0x0000a1ff, 0x00009dff, 0x000097ff, 0x00009cff, 0x0000a1ff, 0x0000a1ff, 0x0000a1ff, 0x00009fff, 0x00009bff, 0x00009fff, 0x0000a1ff, 0x0000a1ff, 0x00009dff, 0x00009bff, 0x0000a1ff, 0x0000a1ff, 0x0000a1ff, 0x0000a0ff, 0x00009aff, 0x000098ff, +0x00009aff, 0x00009eff, 0x00009eff, 0x00009aff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x00009aff, 0x01019dff, 0x282862ff, 0x4f4f40ff, 0x4c4c4cff, 0x4a4a4aff, 0x484848ff, 0x515151ff, 0x575757ff, 0x636363ff, 0x7f7f7fff, 0x7e7e7eff, 0x7e7e7eff, 0x7e7e7eff, 0x7e7e7eff, 0x7e7e7eff, 0x7e7e7eff, 0x7e7e7eff, 0x7f7f7fff, 0x888888ff, 0x939393ff, 0x959595ff, 0x929292ff, 0xa5a5a5ff, 0xb8b8b8ff, 0xb5b5b5ff, 0xb5b5b5ff, 0xbebebeff, 0xc4c4c4ff, 0xc3c3c3ff, 0xc4c4c4ff, 0xc5c5c5ff, +0xccccccff, 0xdcdcdcff, 0xc2c2c2ff, 0xbbbbbbff, 0xd9d9d9ff, 0xd3d3d3ff, 0xd3d3d3ff, 0xd3d3d3ff, 0xd2d2d2ff, 0xcdcdcdff, 0xcbcbcbff, 0xc9c9c9ff, 0xcececeff, 0xb2b2b2ff, 0x787878ff, 0x515151ff, 0x3d3d3dff, 0x444444ff, 0x404040ff, 0x585858ff, 0x666666ff, 0x636363ff, 0x636363ff, 0x636363ff, 0x636363ff, 0x636363ff, 0x636363ff, 0x636363ff, 0x636363ff, 0x636363ff, 0x636363ff, 0x646464ff, +0x636363ff, 0x585858ff, 0x545454ff, 0x555555ff, 0x555555ff, 0x555555ff, 0x555555ff, 0x555555ff, 0x555555ff, 0x555555ff, 0x555555ff, 0x555555ff, 0x555555ff, 0x555555ff, 0x555555ff, 0x555555ff, 0x555555ff, 0x555555ff, 0x555555ff, 0x575757ff, 0x4f4f4fff, 0x444444ff, 0x424242ff, 0x4e4e4eff, 0x515151ff, 0x6d6d6dff, 0x595959ff, 0x464646ff, 0x545454ff, 0x616161ff, 0x9f9f9fff, 0xcbcbcbff, +0xd5d5d5ff, 0x919191ff, 0x6d6d6dff, 0x747474ff, 0x5f5f5fff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x656566ff, 0x656566ff, 0x656566ff, 0x656566ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, +0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, +0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x646464ff, 0x626262ff, 0x666666ff, 0x666666ff, 0x636363ff, 0x606060ff, 0x636363ff, 0x626262ff, 0x616161ff, 0x636363ff, 0x616161ff, 0x5d5d5dff, 0x5e5e5eff, 0x5b5b5bff, 0x5d5d5dff, 0x626262ff, 0x5e5e5eff, 0x595959ff, 0x5a5a5aff, 0x595959ff, 0x575757ff, 0x5b5b5bff, 0x606060ff, 0x4d4d46ff, 0x22223dff, 0x0c0c6dff, +0x060672ff, 0x000060ff, 0x00007aff, 0x0000a4ff, 0x00009dff, 0x00009eff, 0x0000a0ff, 0x000098ff, 0x030378ff, 0x060669ff, 0x090970ff, 0x0d0d75ff, 0x121273ff, 0x09098bff, 0x0000adff, 0x06068dff, 0x0d0d6cff, 0x0c0c74ff, 0x121277ff, 0x101081ff, 0x030395ff, 0x0a0a81ff, 0x0f0f74ff, 0x121274ff, 0x06068bff, 0x010193ff, 0x151578ff, 0x101078ff, 0x0e0e76ff, 0x111178ff, 0x020294ff, 0x0000a6ff, +0x00009dff, 0x111181ff, 0x08087bff, 0x000093ff, 0x000097ff, 0x000096ff, 0x000095ff, 0x000097ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x00009bff, 0x0b0b88ff, 0x3e3e5cff, 0x73736aff, 0x808080ff, 0x7c7c7cff, 0x7c7c7cff, 0x7e7e7eff, 0x757575ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x686868ff, 0x5f5f5fff, 0x4e4e4eff, 0x595959ff, 0x5e5e5eff, 0x505050ff, 0x5e5e5eff, 0x7c7c7cff, 0x787878ff, 0x787878ff, 0x868686ff, 0x8e8e8eff, 0x8c8c8cff, 0x8c8c8cff, 0x898989ff, +0x888888ff, 0x909090ff, 0x9a9a9aff, 0x979797ff, 0xa3a3a3ff, 0xacacacff, 0xaaaaaaff, 0xa9a9a9ff, 0xadadadff, 0xc3c3c3ff, 0xcfcfcfff, 0xd6d6d6ff, 0xecececff, 0xdededeff, 0x8f8f8fff, 0x5b5b5bff, 0x4c4c4cff, 0x3f3f3fff, 0x4d4d4dff, 0x626262ff, 0x696969ff, 0x686868ff, 0x686868ff, 0x686868ff, 0x686868ff, 0x686868ff, 0x686868ff, 0x686868ff, 0x686868ff, 0x686868ff, 0x686868ff, 0x686868ff, +0x676767ff, 0x575757ff, 0x505050ff, 0x525252ff, 0x525252ff, 0x525252ff, 0x525252ff, 0x525252ff, 0x525252ff, 0x525252ff, 0x525252ff, 0x525252ff, 0x525252ff, 0x525252ff, 0x525252ff, 0x525252ff, 0x525252ff, 0x525252ff, 0x525252ff, 0x515151ff, 0x3c3c3cff, 0x373737ff, 0x464646ff, 0x444444ff, 0x4e4e4eff, 0x767676ff, 0x505050ff, 0x2e2e2eff, 0x333333ff, 0x4b4b4bff, 0x959595ff, 0xd4d4d4ff, +0xfafafaff, 0xa9a9a9ff, 0x797979ff, 0x8e8e8eff, 0x696969ff, 0x636363ff, 0x676767ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x666666ff, +0x636363ff, 0x5a5a5aff, 0x5b5b5bff, 0x5d5d5dff, 0x575757ff, 0x545454ff, 0x545454ff, 0x545454ff, 0x585858ff, 0x5f5f5fff, 0x5f5f5fff, 0x5a5a5aff, 0x565656ff, 0x585858ff, 0x585858ff, 0x595959ff, 0x5c5c5cff, 0x616161ff, 0x5c5c5cff, 0x585858ff, 0x585858ff, 0x585858ff, 0x5a5a5aff, 0x5f5f5fff, 0x606060ff, 0x606060ff, 0x606060ff, 0x5e5e5eff, 0x585858ff, 0x5e5e5eff, 0x666666ff, 0x626262ff, +0x606060ff, 0x5f5f5fff, 0x5b5b5bff, 0x5a5a5aff, 0x636363ff, 0x676767ff, 0x6d6d6dff, 0x737373ff, 0x666666ff, 0x5e5e5eff, 0x6d6d6dff, 0x7d7d7dff, 0x6f6f6fff, 0x757575ff, 0x787878ff, 0x676767ff, 0x767676ff, 0x898989ff, 0x848484ff, 0x9a9a9aff, 0x8e8e8eff, 0x6f6f6fff, 0x838383ff, 0x9b9b9bff, 0x969696ff, 0x9a9a9aff, 0xa8a8a8ff, 0x989898ff, 0x747474ff, 0x616161ff, 0x5c5c5bff, 0x686867ff, +0x8e8e8cff, 0x919183ff, 0x4e4e78ff, 0x21218eff, 0x292987ff, 0x232383ff, 0x1e1e82ff, 0x2b2b80ff, 0x6c6c81ff, 0x8f8f88ff, 0x787875ff, 0x60605dff, 0x5d5d52ff, 0x2a2a4fff, 0x000059ff, 0x31315fff, 0x88887aff, 0x6e6e6dff, 0x51514aff, 0x3d3d4aff, 0x191956ff, 0x47475dff, 0x6a6a63ff, 0x66665aff, 0x383860ff, 0x262662ff, 0x4d4d45ff, 0x545453ff, 0x61615cff, 0x525250ff, 0x252564ff, 0x0c0c78ff, +0x111163ff, 0x35353eff, 0x5b5b6bff, 0x4b4ba2ff, 0x4343a6ff, 0x4444a3ff, 0x5555acff, 0x1d1da3ff, 0x000094ff, 0x000096ff, 0x000095ff, 0x000095ff, 0x000097ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x0000a0ff, 0x272760ff, 0x64644eff, 0x9c9c9cff, 0xb4b4b4ff, 0xaeaeaeff, 0xaeaeaeff, 0xaeaeaeff, 0xafafafff, 0xafafafff, 0xaeaeaeff, 0xaeaeaeff, 0xaeaeaeff, 0xaeaeaeff, 0xaeaeaeff, 0xaeaeaeff, 0xaeaeaeff, 0xb1b1b1ff, 0xa5a5a5ff, 0x868686ff, 0x7e7e7eff, 0x838383ff, 0x777777ff, 0x666666ff, 0x666666ff, 0x666666ff, 0x656565ff, 0x656565ff, 0x6f6f6fff, 0x696969ff, 0x676767ff, 0x767676ff, +0x777777ff, 0x7c7c7cff, 0x898989ff, 0x868686ff, 0x949494ff, 0xa1a1a1ff, 0x9e9e9eff, 0x9c9c9cff, 0xa2a2a2ff, 0xc2c2c2ff, 0xc7c7c7ff, 0xadadadff, 0xa1a1a1ff, 0xa8a8a8ff, 0xa1a1a1ff, 0x616161ff, 0x404040ff, 0x414141ff, 0x515151ff, 0x1f1f1fff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, +0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x0b0b0bff, 0x323232ff, 0x424242ff, 0x464646ff, 0x353535ff, 0x2c2c2cff, 0x424242ff, 0x2d2d2dff, 0x191919ff, 0x212121ff, 0x545454ff, 0xb1b1b1ff, 0xd8d8d8ff, +0xb5b5b5ff, 0x5c5c5cff, 0x222222ff, 0x404040ff, 0x5d5d5dff, 0x5c5c5cff, 0x535353ff, 0x565656ff, 0x565656ff, 0x535353ff, 0x535353ff, 0x525252ff, 0x555555ff, 0x585858ff, 0x575757ff, 0x575757ff, 0x545454ff, 0x535353ff, 0x555555ff, 0x555555ff, 0x575757ff, 0x5a5a5aff, 0x5c5c5cff, 0x565656ff, 0x545454ff, 0x575757ff, 0x575757ff, 0x585858ff, 0x5f5f5fff, 0x616161ff, 0x595959ff, 0x565656ff, +0x676767ff, 0x8e8e8eff, 0x858585ff, 0x808080ff, 0xa4a4a4ff, 0xb0b0b0ff, 0xafafafff, 0xadadadff, 0x999999ff, 0x737373ff, 0x747474ff, 0x9c9c9cff, 0xb0b0b0ff, 0xa5a5a5ff, 0x9c9c9cff, 0x959595ff, 0x898989ff, 0x767676ff, 0x909090ff, 0xa8a8a8ff, 0xa2a2a2ff, 0x9c9c9cff, 0x959595ff, 0x818181ff, 0x7a7a7aff, 0x7f7f7fff, 0x7d7d7dff, 0x858585ff, 0x9f9f9fff, 0x848484ff, 0x5e5e5eff, 0x707070ff, +0x7d7d7dff, 0x7d7d7dff, 0x8f8f8fff, 0x8e8e8eff, 0x656565ff, 0x525252ff, 0x656565ff, 0x626262ff, 0x5e5e5eff, 0x777777ff, 0x6c6c6cff, 0x646464ff, 0x575757ff, 0x535353ff, 0x6c6c6cff, 0x707070ff, 0x848484ff, 0x939393ff, 0x808080ff, 0x8b8b8bff, 0x858585ff, 0x7a7a7aff, 0x979797ff, 0xa7a7a7ff, 0xa3a3a3ff, 0x919191ff, 0x919191ff, 0xa9a9a9ff, 0x8c8c8cff, 0x707070ff, 0x7c7c7bff, 0x8a8a87ff, +0x959593ff, 0xa0a09dff, 0x6d6d68ff, 0x46463eff, 0x606056ff, 0x74746bff, 0x79796fff, 0x808077ff, 0xb0b0acff, 0xcdcdcbff, 0xb2b2afff, 0x91918fff, 0x848482ff, 0x71716cff, 0x6c6c62ff, 0x54544eff, 0x6f6f6cff, 0x979795ff, 0x8a8a87ff, 0x7d7d7aff, 0x81817aff, 0x82827fff, 0x71716eff, 0x656562ff, 0x5e5e5aff, 0x74746eff, 0x7d7d7aff, 0x838381ff, 0x91918eff, 0x82827eff, 0x66665fff, 0x63635aff, +0x606059ff, 0x62625eff, 0x999995ff, 0xa6a69dff, 0xa1a197ff, 0xa5a59bff, 0x898974ff, 0x5d5d84ff, 0x4747aaff, 0x4848a0ff, 0x5151a8ff, 0x4b4bacff, 0x0b0b9dff, 0x000094ff, 0x000095ff, 0x000097ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000098ff, 0x000098ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x0000a0ff, 0x242463ff, 0x62624fff, 0x989899ff, 0xafafafff, 0xaaaaaaff, 0xaaaaaaff, 0xaaaaaaff, 0xaaaaaaff, 0xaaaaaaff, 0xaaaaaaff, 0xaaaaaaff, 0xaaaaaaff, 0xaaaaaaff, 0xaaaaaaff, 0xaaaaaaff, 0xaaaaaaff, 0xaaaaaaff, 0xacacacff, 0xb0b0b0ff, 0xb1b1b1ff, 0xb1b1b1ff, 0xb3b3b3ff, 0xb4b4b4ff, 0xb4b4b4ff, 0xb4b4b4ff, 0xb4b4b4ff, 0xc2c2c2ff, 0xc7c7c7ff, 0xb4b4b4ff, 0xb3b3b3ff, 0xc1c1c1ff, +0xc5c5c5ff, 0xcbcbcbff, 0xd6d6d6ff, 0xd6d6d6ff, 0xd4d4d4ff, 0xd2d2d2ff, 0xd3d3d3ff, 0xd3d3d3ff, 0xd1d1d1ff, 0xd0d0d0ff, 0xc5c5c5ff, 0xa3a3a3ff, 0x828282ff, 0x777777ff, 0x868686ff, 0x565656ff, 0x2f2f2fff, 0x474747ff, 0x404040ff, 0x3f3f3fff, 0x3d3d3dff, 0x3c3c3cff, 0x3c3c3cff, 0x3c3c3cff, 0x3c3c3cff, 0x3c3c3cff, 0x3c3c3cff, 0x3c3c3cff, 0x3c3c3cff, 0x3c3c3cff, 0x3c3c3cff, 0x3c3c3cff, +0x3c3c3cff, 0x3c3c3cff, 0x3c3c3cff, 0x3c3c3cff, 0x3c3c3cff, 0x3c3c3cff, 0x3c3c3cff, 0x3c3c3cff, 0x3c3c3cff, 0x3c3c3cff, 0x3c3c3cff, 0x3c3c3cff, 0x3c3c3cff, 0x3c3c3cff, 0x3c3c3cff, 0x3c3c3cff, 0x3c3c3cff, 0x3c3c3cff, 0x3a3a3aff, 0x424242ff, 0x656565ff, 0x5c5c5cff, 0x3e3e3eff, 0x363636ff, 0x434343ff, 0x4a4a4aff, 0x292929ff, 0x202020ff, 0x202020ff, 0x4c4c4cff, 0xbdbdbdff, 0xd6d6d6ff, +0x989898ff, 0x8a8a8aff, 0x757575ff, 0x626262ff, 0x9e9e9eff, 0xb5b5b5ff, 0xa4a4a4ff, 0xa1a1a1ff, 0xa9a9a9ff, 0xb7b7b7ff, 0xbababaff, 0xbdbdbdff, 0xaaaaaaff, 0x939393ff, 0x9d9d9dff, 0xa6a6a6ff, 0xb4b4b4ff, 0xb9b9b9ff, 0xaeaeaeff, 0xa8a8a8ff, 0xa1a1a1ff, 0x919191ff, 0x8b8b8bff, 0xaeaeaeff, 0xb5b5b5ff, 0xa7a7a7ff, 0x9d9d9dff, 0x989898ff, 0x757575ff, 0x727272ff, 0x9d9d9dff, 0x9d9d9dff, +0x999999ff, 0xd6d6d6ff, 0xc3c3c3ff, 0x939393ff, 0xaaaaaaff, 0xbababaff, 0xbbbbbbff, 0xc9c9c9ff, 0xd9d9d9ff, 0xb8b8b8ff, 0x818181ff, 0x888888ff, 0x9c9c9cff, 0x919191ff, 0xa0a0a0ff, 0xd9d9d9ff, 0xacacacff, 0x545454ff, 0x7a7a7aff, 0x858585ff, 0x848484ff, 0xa7a7a7ff, 0xabababff, 0x797979ff, 0x5a5a5aff, 0x525252ff, 0x484848ff, 0x797979ff, 0xb8b8b8ff, 0x898989ff, 0x525252ff, 0x6b6b6bff, +0x616161ff, 0x606060ff, 0xb2b2b2ff, 0xcececeff, 0x7d7d7dff, 0x656565ff, 0x5c5c5cff, 0x353535ff, 0x606060ff, 0x909090ff, 0x6c6c6cff, 0x545454ff, 0x5e5e5eff, 0x434343ff, 0x606060ff, 0xabababff, 0xa7a7a7ff, 0x727272ff, 0x787878ff, 0x787878ff, 0x676767ff, 0x838383ff, 0x7e7e7eff, 0x676767ff, 0x6d6d6dff, 0x797979ff, 0x5c5c5cff, 0x777777ff, 0xabababff, 0x969696ff, 0x7c7c7cff, 0x858585ff, +0x848484ff, 0x828282ff, 0x8c8c8cff, 0x717170ff, 0x686867ff, 0x868685ff, 0x8e8e8dff, 0x898988ff, 0x818181ff, 0x7e7e7eff, 0x818181ff, 0x878787ff, 0x808081ff, 0xaeaeaeff, 0xf7f7f6ff, 0x9e9e9eff, 0x6c6c6cff, 0x727272ff, 0x555555ff, 0x616161ff, 0x898989ff, 0x868686ff, 0x5e5e5eff, 0x414141ff, 0x494949ff, 0x626262ff, 0x696969ff, 0x818181ff, 0x8c8c8cff, 0x7c7c7cff, 0x515150ff, 0x6a6a69ff, +0x888887ff, 0x848485ff, 0x848483ff, 0x6e6e6eff, 0x666665ff, 0x7e7e7dff, 0x545454ff, 0x606058ff, 0xc4c4b2ff, 0xbebeaeff, 0x9f9f8bff, 0x7a7a72ff, 0x616199ff, 0x5b5bb2ff, 0x5c5ca4ff, 0x33339eff, 0x000097ff, 0x000095ff, 0x000096ff, 0x000095ff, 0x000097ff, 0x000099ff, 0x000099ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x0000a0ff, 0x242463ff, 0x61614fff, 0x989899ff, 0xafafafff, 0xa9a9a9ff, 0xa9a9a9ff, 0xa9a9a9ff, 0xa9a9a9ff, 0xa9a9a9ff, 0xa9a9a9ff, 0xa9a9a9ff, 0xa9a9a9ff, 0xa9a9a9ff, 0xa9a9a9ff, 0xa9a9a9ff, 0xa9a9a9ff, 0xa9a9a9ff, 0xa9a9a9ff, 0xa9a9a9ff, 0xa9a9a9ff, 0xa9a9a9ff, 0xa9a9a9ff, 0xa9a9a9ff, 0xa9a9a9ff, 0xa9a9a9ff, 0xa8a8a8ff, 0xb3b3b3ff, 0xafafafff, 0xb8b8b8ff, 0xbfbfbfff, 0xb9b9b9ff, +0xb6b6b6ff, 0xbdbdbdff, 0xcbcbcbff, 0xcbcbcbff, 0xcbcbcbff, 0xcbcbcbff, 0xcbcbcbff, 0xcbcbcbff, 0xcbcbcbff, 0xcbcbcbff, 0xcdcdcdff, 0xd4d4d4ff, 0xe1e1e1ff, 0xc5c5c5ff, 0x7d7d7dff, 0x525252ff, 0x414141ff, 0x434343ff, 0x424242ff, 0x717171ff, 0x9e9e9eff, 0xa1a1a1ff, 0x9f9f9fff, 0x9f9f9fff, 0x9f9f9fff, 0x9f9f9fff, 0x9f9f9fff, 0x9f9f9fff, 0x9f9f9fff, 0x9f9f9fff, 0x9f9f9fff, 0x9f9f9fff, +0x9f9f9fff, 0x9f9f9fff, 0x9f9f9fff, 0x9f9f9fff, 0x9f9f9fff, 0x9f9f9fff, 0x9f9f9fff, 0x9f9f9fff, 0x9f9f9fff, 0x9f9f9fff, 0x9f9f9fff, 0x9f9f9fff, 0x9f9f9fff, 0x9f9f9fff, 0x9f9f9fff, 0x9f9f9fff, 0x9f9f9fff, 0x9f9f9fff, 0xa1a1a1ff, 0x999999ff, 0x6e6e6eff, 0x454545ff, 0x404040ff, 0x454545ff, 0x828282ff, 0x949494ff, 0x373737ff, 0x060606ff, 0x0a0a0aff, 0x272727ff, 0x717171ff, 0xa0a0a0ff, +0xd1d1d1ff, 0xd0d0d0ff, 0xd3d3d3ff, 0xfefefeff, 0xfafafaff, 0xffffffff, 0xf8f8f8ff, 0xb8b8b8ff, 0x959595ff, 0xadadadff, 0xa8a8a8ff, 0x9d9d9dff, 0xc3c3c3ff, 0xe7e7e7ff, 0xb7b7b7ff, 0x868686ff, 0x9c9c9cff, 0x9d9d9dff, 0x959595ff, 0xcdcdcdff, 0xdbdbdbff, 0x999999ff, 0x696969ff, 0x969696ff, 0x8f8f8fff, 0x747474ff, 0xc5c5c5ff, 0xe3e3e3ff, 0x888888ff, 0x656565ff, 0x919191ff, 0x7c7c7cff, +0x6a6a6aff, 0xa8a8a8ff, 0xbbbbbbff, 0x717171ff, 0x585858ff, 0x5b5b5bff, 0x393939ff, 0x474747ff, 0x9e9e9eff, 0xcdcdcdff, 0x888888ff, 0x555555ff, 0x4f4f4fff, 0x343434ff, 0x424242ff, 0xacacacff, 0xa4a4a4ff, 0x575757ff, 0x5e5e5eff, 0x3b3b3bff, 0x444444ff, 0x929292ff, 0xadadadff, 0x9b9b9bff, 0x8f8f8fff, 0x8a8a8aff, 0x717171ff, 0x7d7d7dff, 0xacacacff, 0xabababff, 0x858585ff, 0x8e8e8eff, +0x999999ff, 0x6f6f6fff, 0x898989ff, 0xc3c3c3ff, 0xb7b7b7ff, 0x929292ff, 0x929292ff, 0x919191ff, 0x7f7f7fff, 0x999999ff, 0xbfbfbfff, 0xa4a4a4ff, 0x8d8d8dff, 0x868686ff, 0x8d8d8dff, 0xa6a6a6ff, 0xb6b6b6ff, 0xa5a5a5ff, 0x868686ff, 0x7c7c7cff, 0x636363ff, 0x656565ff, 0x7f7f7fff, 0x909090ff, 0x7e7e7eff, 0x909090ff, 0x787878ff, 0x646464ff, 0xa0a0a0ff, 0xadadadff, 0x828282ff, 0x828282ff, +0x959595ff, 0x919191ff, 0xb1b1b1ff, 0xa4a4a4ff, 0x898989ff, 0x8a8a8aff, 0x8a8a8aff, 0x8a8a8aff, 0x8b8b8bff, 0x888888ff, 0x888888ff, 0x888888ff, 0x848484ff, 0x8e8e8eff, 0xb9b9b9ff, 0xe6e6e6ff, 0xd2d2d2ff, 0x5c5c5cff, 0x202020ff, 0x545454ff, 0x676767ff, 0x7a7a7aff, 0x8e8e8eff, 0x757575ff, 0x5e5e5eff, 0x616161ff, 0x676767ff, 0x7f7f7fff, 0x8b8b8bff, 0x7e7e7eff, 0x5e5e5eff, 0x494949ff, +0x454545ff, 0x565656ff, 0x757575ff, 0x696969ff, 0x575757ff, 0x545454ff, 0x5f5f5fff, 0x464646ff, 0x585859ff, 0x727272ff, 0x5e5e5fff, 0x474744ff, 0x636355ff, 0x82826cff, 0xb9b99eff, 0xababaeff, 0x6666a6ff, 0x6161a8ff, 0x6767a9ff, 0x7272abff, 0x2626a0ff, 0x000098ff, 0x00009aff, 0x00009bff, 0x00009aff, 0x00009aff, 0x00009aff, 0x000099ff, 0x000098ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x0000a0ff, 0x242463ff, 0x61614fff, 0x989899ff, 0xafafafff, 0xa9a9a9ff, 0xaaaaaaff, 0xaaaaaaff, 0xaaaaaaff, 0xaaaaaaff, 0xaaaaaaff, 0xaaaaaaff, 0xaaaaaaff, 0xaaaaaaff, 0xaaaaaaff, 0xaaaaaaff, 0xaaaaaaff, 0xaaaaaaff, 0xaaaaaaff, 0xaaaaaaff, 0xaaaaaaff, 0xaaaaaaff, 0xaaaaaaff, 0xaaaaaaff, 0xaaaaaaff, 0xaaaaaaff, 0xaaaaaaff, 0xa6a6a6ff, 0xa9a9a9ff, 0xb6b6b6ff, 0xb9b9b9ff, 0xbebebeff, +0xcececeff, 0xd0d0d0ff, 0xcbcbcbff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xcbcbcbff, 0xcbcbcbff, 0xd1d1d1ff, 0xb9b9b9ff, 0x7e7e7eff, 0x545454ff, 0x3f3f3fff, 0x444444ff, 0x414141ff, 0x494949ff, 0x585858ff, 0x5e5e5eff, 0x5c5c5cff, 0x5c5c5cff, 0x5c5c5cff, 0x5c5c5cff, 0x5c5c5cff, 0x5c5c5cff, 0x5c5c5cff, 0x5c5c5cff, 0x5c5c5cff, 0x5c5c5cff, +0x5c5c5cff, 0x5c5c5cff, 0x5c5c5cff, 0x5c5c5cff, 0x5c5c5cff, 0x5c5c5cff, 0x5c5c5cff, 0x5c5c5cff, 0x5c5c5cff, 0x5c5c5cff, 0x5c5c5cff, 0x5c5c5cff, 0x5c5c5cff, 0x5c5c5cff, 0x5c5c5cff, 0x5c5c5cff, 0x5c5c5cff, 0x5c5c5cff, 0x5c5c5cff, 0x616161ff, 0x525252ff, 0x3d3d3dff, 0x434343ff, 0x414141ff, 0x686868ff, 0x7e7e7eff, 0x383838ff, 0x060606ff, 0x030303ff, 0x1c1c1cff, 0x515151ff, 0x757575ff, +0xafafafff, 0xbcbcbcff, 0xa4a4a4ff, 0xe5e5e5ff, 0xf2f2f2ff, 0xf3f3f3ff, 0xe2e2e2ff, 0x6f6f6fff, 0x272727ff, 0x494949ff, 0x4a4a4aff, 0x474747ff, 0x7c7c7cff, 0xc7c7c7ff, 0x9d9d9dff, 0x5a5a5aff, 0x828282ff, 0x6c6c6cff, 0x3a3a3aff, 0x767676ff, 0xc0c0c0ff, 0x9f9f9fff, 0x5e5e5eff, 0x737373ff, 0x8f8f8fff, 0x676767ff, 0xa2a2a2ff, 0xd9d9d9ff, 0xb0b0b0ff, 0x808080ff, 0x8f8f8fff, 0x9e9e9eff, +0x969696ff, 0xb1b1b1ff, 0xc9c9c9ff, 0x9a9a9aff, 0x909090ff, 0xb6b6b6ff, 0x999999ff, 0x999999ff, 0xb4b4b4ff, 0xc9c9c9ff, 0xb9b9b9ff, 0x949494ff, 0x989898ff, 0x959595ff, 0x717171ff, 0x9c9c9cff, 0xccccccff, 0xa7a7a7ff, 0x8d8d8dff, 0x878787ff, 0x888888ff, 0xa5a5a5ff, 0xcececeff, 0xd6d6d6ff, 0xb3b3b3ff, 0xa3a3a3ff, 0x888888ff, 0x747474ff, 0x979797ff, 0xc8c8c8ff, 0xb4b4b4ff, 0x8a8a8aff, +0x9e9e9eff, 0x747474ff, 0x676767ff, 0xa2a2a2ff, 0xc1c1c1ff, 0x8d8d8dff, 0x797979ff, 0x747474ff, 0x6a6a6aff, 0x979797ff, 0xb0b0b0ff, 0x949494ff, 0x838383ff, 0x7a7a7aff, 0x717171ff, 0x787878ff, 0x8a8a8aff, 0x989898ff, 0x757575ff, 0x585858ff, 0x4a4a4aff, 0x5c5c5cff, 0x808080ff, 0x8b8b8bff, 0x7d7d7dff, 0x6d6d6dff, 0x656565ff, 0x676767ff, 0x757575ff, 0x909090ff, 0x9e9e9eff, 0x7a7a7aff, +0x636363ff, 0x606060ff, 0x767676ff, 0x858585ff, 0x8a8a8aff, 0x7a7a7aff, 0x6f6f6fff, 0x6f6f6fff, 0x757575ff, 0x868686ff, 0x8a8a8aff, 0x898989ff, 0x8c8c8cff, 0x787878ff, 0x818181ff, 0xacacacff, 0x909090ff, 0x717171ff, 0x909090ff, 0xc5c5c5ff, 0xc2c2c2ff, 0xbcbcbcff, 0x999999ff, 0x505050ff, 0x5a5a5aff, 0x777777ff, 0x7f7f7fff, 0x8a8a8aff, 0x888888ff, 0x7e7e7eff, 0x787878ff, 0x5e5e5eff, +0x505050ff, 0x6b6b6bff, 0x838383ff, 0x777777ff, 0x6b6b6bff, 0x5e5e5eff, 0x5b5b5bff, 0x6c6c6cff, 0x666666ff, 0x616161ff, 0x656565ff, 0x6c6c6cff, 0x5e5e5fff, 0x626263ff, 0x9c9c9eff, 0xb1b1acff, 0xa4a494ff, 0x8d8d7bff, 0x6f6f5eff, 0x747458ff, 0x676781ff, 0x4e4e92ff, 0x56568eff, 0x4e4e91ff, 0x161699ff, 0x00009dff, 0x00009bff, 0x00009bff, 0x000099ff, 0x000098ff, 0x000099ff, 0x000099ff, +0x0000a0ff, 0x242463ff, 0x61614fff, 0x989899ff, 0xafafafff, 0xa9a9a9ff, 0xaaaaaaff, 0xaaaaaaff, 0xaaaaaaff, 0xaaaaaaff, 0xaaaaaaff, 0xaaaaaaff, 0xaaaaaaff, 0xaaaaaaff, 0xaaaaaaff, 0xaaaaaaff, 0xaaaaaaff, 0xaaaaaaff, 0xaaaaaaff, 0xaaaaaaff, 0xaaaaaaff, 0xaaaaaaff, 0xaaaaaaff, 0xaaaaaaff, 0xaaaaaaff, 0xaaaaaaff, 0xaaaaaaff, 0xaaaaaaff, 0xa7a7a7ff, 0xa8a8a8ff, 0xb8b8b8ff, 0xc1c1c1ff, +0xc9c9c9ff, 0xccccccff, 0xcbcbcbff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xcbcbcbff, 0xd2d2d2ff, 0xb9b9b9ff, 0x7e7e7eff, 0x545454ff, 0x3f3f3fff, 0x444444ff, 0x444444ff, 0x414141ff, 0x3d3d3dff, 0x3b3b3bff, 0x3b3c3bff, 0x3b3c3bff, 0x3b3b3bff, 0x3b3b3bff, 0x3b3b3bff, 0x3b3b3bff, 0x3b3b3bff, 0x3b3b3bff, 0x3b3b3bff, 0x3b3b3bff, +0x3b3b3bff, 0x3b3b3bff, 0x3b3b3bff, 0x3b3b3bff, 0x3b3b3bff, 0x3b3b3bff, 0x3b3b3bff, 0x3b3b3bff, 0x3b3b3bff, 0x3b3b3bff, 0x3b3b3bff, 0x3b3b3bff, 0x3b3b3bff, 0x3b3b3bff, 0x3b3b3bff, 0x3b3b3bff, 0x3b3b3bff, 0x3b3b3bff, 0x3b3b3bff, 0x3b3b3bff, 0x3f3f3fff, 0x444444ff, 0x444444ff, 0x404040ff, 0x5e5e5eff, 0x777777ff, 0x3c3c3cff, 0x191919ff, 0x161616ff, 0x282828ff, 0x757575ff, 0xb4b4b4ff, +0xc2c2c2ff, 0xe9e9e9ff, 0xdcdcdcff, 0xd1d1d1ff, 0xd8d8d8ff, 0xeaeaeaff, 0xe5e5e5ff, 0xa0a0a0ff, 0x787878ff, 0xa7a7a7ff, 0xc5c5c5ff, 0xc7c7c7ff, 0x9b9b9bff, 0x878787ff, 0x8f8f8fff, 0xa0a0a0ff, 0xccccccff, 0xc1c1c1ff, 0x969696ff, 0x7f7f7fff, 0xb8b8b8ff, 0xe2e2e2ff, 0xb3b3b3ff, 0x8a8a8aff, 0x9e9e9eff, 0x9e9e9eff, 0x808080ff, 0xa2a2a2ff, 0xcbcbcbff, 0x999999ff, 0x878787ff, 0xa0a0a0ff, +0x959595ff, 0x909090ff, 0xb6b6b6ff, 0xb7b7b7ff, 0x9a9a9aff, 0xa6a6a6ff, 0x858585ff, 0x898989ff, 0xa3a3a3ff, 0xc4c4c4ff, 0xccccccff, 0x979797ff, 0x878787ff, 0x8e8e8eff, 0x808080ff, 0x898989ff, 0xbdbdbdff, 0xb5b5b5ff, 0x808080ff, 0x7b7b7bff, 0x6d6d6dff, 0x7d7d7dff, 0xb7b7b7ff, 0xccccccff, 0xaeaeaeff, 0x919191ff, 0x6b6b6bff, 0x757575ff, 0x9d9d9dff, 0xc2c2c2ff, 0xaeaeaeff, 0x6b6b6bff, +0x858585ff, 0x7f7f7fff, 0x8c8c8cff, 0xb6b6b6ff, 0xbebebeff, 0x8f8f8fff, 0x6a6a6aff, 0x5f5f5fff, 0x6f6f6fff, 0x999999ff, 0xbababaff, 0x999999ff, 0x808080ff, 0x7a7a7aff, 0x777777ff, 0x828282ff, 0x929292ff, 0xa7a7a7ff, 0x8e8e8eff, 0x787878ff, 0x7d7d7dff, 0x878787ff, 0x888888ff, 0xa5a5a5ff, 0xa1a1a1ff, 0x7b7b7bff, 0x787878ff, 0x828282ff, 0x808080ff, 0xa6a6a6ff, 0xbebebeff, 0x8b8b8bff, +0x747474ff, 0x818181ff, 0x898989ff, 0x858585ff, 0xa3a3a3ff, 0x8f8f8fff, 0x646464ff, 0x616161ff, 0x636363ff, 0x6b6b6bff, 0x6f6f6fff, 0x6c6c6cff, 0x767676ff, 0x7c7c7cff, 0x767676ff, 0x7e7e7eff, 0x818181ff, 0x898989ff, 0x919191ff, 0x999999ff, 0xa7a7a7ff, 0xd3d3d3ff, 0xb2b2b2ff, 0x505050ff, 0x646464ff, 0x9b9b9bff, 0xb0b0b0ff, 0xc2c2c2ff, 0x838383ff, 0x333333ff, 0x4d4d4dff, 0x797979ff, +0x848484ff, 0x8d8d8dff, 0x868686ff, 0x6d6d6dff, 0x696969ff, 0x6c6c6cff, 0x787878ff, 0x929292ff, 0x919191ff, 0x666666ff, 0x666666ff, 0x6d6d6dff, 0x676767ff, 0x8a8a8aff, 0x969696ff, 0x8d8d8dff, 0x7f7f7fff, 0x69696aff, 0x6e6e6fff, 0x8f8f91ff, 0x99998fff, 0x8a8a78ff, 0x7f7f6dff, 0x5d5d51ff, 0x1d1d3fff, 0x040436ff, 0x0d0d54ff, 0x040491ff, 0x00009eff, 0x000099ff, 0x000098ff, 0x000099ff, +0x0000a0ff, 0x242463ff, 0x61614fff, 0x989899ff, 0xafafafff, 0xa9a9a9ff, 0xaaaaaaff, 0xaaaaaaff, 0xaaaaaaff, 0xaaaaaaff, 0xaaaaaaff, 0xaaaaaaff, 0xaaaaaaff, 0xaaaaaaff, 0xaaaaaaff, 0xaaaaaaff, 0xaaaaaaff, 0xaaaaaaff, 0xaaaaaaff, 0xaaaaaaff, 0xaaaaaaff, 0xaaaaaaff, 0xaaaaaaff, 0xaaaaaaff, 0xaaaaaaff, 0xaaaaaaff, 0xa9a9a9ff, 0xa8a8a8ff, 0xaaaaaaff, 0xb2b2b2ff, 0xc8c8c8ff, 0xc7c7c7ff, +0xb2b2b2ff, 0xb8b8b8ff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xcbcbcbff, 0xd2d2d2ff, 0xb9b9b9ff, 0x7e7e7eff, 0x545454ff, 0x3f3f3fff, 0x444444ff, 0x444444ff, 0x444444ff, 0x444444ff, 0x444344ff, 0x454045ff, 0x444344ff, 0x444444ff, 0x444444ff, 0x444444ff, 0x444444ff, 0x444444ff, 0x444444ff, 0x444444ff, 0x444444ff, +0x444444ff, 0x444444ff, 0x444444ff, 0x444444ff, 0x444444ff, 0x444444ff, 0x444444ff, 0x444444ff, 0x444444ff, 0x444444ff, 0x444444ff, 0x444444ff, 0x444444ff, 0x444444ff, 0x444444ff, 0x444444ff, 0x444444ff, 0x444444ff, 0x444444ff, 0x444444ff, 0x444444ff, 0x444444ff, 0x444444ff, 0x404040ff, 0x606060ff, 0x7a7a7aff, 0x363636ff, 0x0c0c0cff, 0x181818ff, 0x313131ff, 0x737373ff, 0xbbbbbbff, +0xb9b9b9ff, 0xafafafff, 0xe0e0e0ff, 0xe1e1e1ff, 0xd9d9d9ff, 0xd8d8d8ff, 0xa2a2a2ff, 0xadadadff, 0xdcdcdcff, 0xf1f1f1ff, 0xffffffff, 0xfafafaff, 0x9e9e9eff, 0x484848ff, 0x6a6a6aff, 0x7a7a7aff, 0x747474ff, 0x757575ff, 0x727272ff, 0x656565ff, 0x909090ff, 0xcececeff, 0xbfbfbfff, 0x838383ff, 0x606060ff, 0x626262ff, 0x747474ff, 0x8e8e8eff, 0xbfbfbfff, 0xb5b5b5ff, 0x7a7a7aff, 0x676767ff, +0x6e6e6eff, 0x838383ff, 0xb9b9b9ff, 0xc8c8c8ff, 0xacacacff, 0xa9a9a9ff, 0x7b7b7bff, 0x818181ff, 0xafafafff, 0xccccccff, 0xcacacaff, 0x8f8f8fff, 0x818181ff, 0xa1a1a1ff, 0x979797ff, 0x929292ff, 0xc9c9c9ff, 0xb1b1b1ff, 0x7c7c7cff, 0x7e7e7eff, 0x797979ff, 0x838383ff, 0xa2a2a2ff, 0xc4c4c4ff, 0xaeaeaeff, 0x8d8d8dff, 0x878787ff, 0x9a9a9aff, 0xa6a6a6ff, 0xc2c2c2ff, 0xb7b7b7ff, 0x7c7c7cff, +0x8d8d8dff, 0x949494ff, 0x8e8e8eff, 0xa7a7a7ff, 0xb9b9b9ff, 0x919191ff, 0x7c7c7cff, 0x868686ff, 0x868686ff, 0x959595ff, 0xccccccff, 0xa8a8a8ff, 0x767676ff, 0x898989ff, 0x909090ff, 0x828282ff, 0x909090ff, 0xbdbdbdff, 0xa9a9a9ff, 0x8b8b8bff, 0x909090ff, 0x878787ff, 0x7e7e7eff, 0x939393ff, 0x929292ff, 0x989898ff, 0x919191ff, 0x7e7e7eff, 0x7c7c7cff, 0x858585ff, 0x848484ff, 0x7b7b7bff, +0x939393ff, 0x989898ff, 0x6c6c6cff, 0x6c6c6cff, 0x6f6f6fff, 0x737373ff, 0x828282ff, 0xa1a1a1ff, 0x787878ff, 0x4c4c4cff, 0x4b4b4bff, 0x4d4d4dff, 0x565656ff, 0x606060ff, 0x606060ff, 0x5b5b5bff, 0x595959ff, 0x5c5c5cff, 0x515151ff, 0x525252ff, 0x747474ff, 0x999999ff, 0x979797ff, 0x7d7d7dff, 0x959595ff, 0xc9c9c9ff, 0xd2d2d2ff, 0xddddddff, 0x8c8c8cff, 0x3c3c3cff, 0x727272ff, 0xbababaff, +0xccccccff, 0xb9b9b9ff, 0x858585ff, 0x4a4a4aff, 0x313131ff, 0x3b3b3bff, 0x515151ff, 0x585858ff, 0x585858ff, 0x474747ff, 0x4f4f4fff, 0x4e4e4eff, 0x474747ff, 0x7a7a7aff, 0x828282ff, 0x5d5d5dff, 0x575757ff, 0x555555ff, 0x7d7d7dff, 0xb5b5b5ff, 0x878787ff, 0x606061ff, 0x5f5f60ff, 0x3f3f3fff, 0x23231aff, 0x1c1c0aff, 0x202017ff, 0x131352ff, 0x03038fff, 0x00009bff, 0x000098ff, 0x000099ff, +0x0000a0ff, 0x242463ff, 0x61614fff, 0x989899ff, 0xafafafff, 0xa9a9a9ff, 0xaaaaaaff, 0xaaaaaaff, 0xaaaaaaff, 0xaaaaaaff, 0xaaaaaaff, 0xaaaaaaff, 0xaaaaaaff, 0xaaaaaaff, 0xaaaaaaff, 0xaaaaaaff, 0xaaaaaaff, 0xaaaaaaff, 0xaaaaaaff, 0xaaaaaaff, 0xaaaaaaff, 0xaaaaaaff, 0xaaaaaaff, 0xaaaaaaff, 0xaaaaaaff, 0xaaaaaaff, 0xa8a8a8ff, 0xaeaeaeff, 0xbbbbbbff, 0xbcbcbcff, 0xb3b3b3ff, 0xb2b2b2ff, +0xa9a9a9ff, 0xb4b4b4ff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xcbcbcbff, 0xd2d2d2ff, 0xb9b9b9ff, 0x7e7e7eff, 0x545454ff, 0x3f3f3fff, 0x444444ff, 0x444444ff, 0x434343ff, 0x3f3d45ff, 0x3e3f44ff, 0x3b4c41ff, 0x404642ff, 0x444244ff, 0x444444ff, 0x444444ff, 0x444444ff, 0x444444ff, 0x444444ff, 0x444444ff, 0x444444ff, +0x444444ff, 0x444444ff, 0x444444ff, 0x444444ff, 0x444444ff, 0x444444ff, 0x444444ff, 0x444444ff, 0x444444ff, 0x444444ff, 0x444444ff, 0x444444ff, 0x444444ff, 0x444444ff, 0x444444ff, 0x444444ff, 0x444444ff, 0x444444ff, 0x444444ff, 0x444444ff, 0x444444ff, 0x444444ff, 0x444444ff, 0x404040ff, 0x606060ff, 0x7b7b7bff, 0x333333ff, 0x020202ff, 0x141414ff, 0x323232ff, 0x646464ff, 0xa2a2a2ff, +0xcacacaff, 0xa0a0a0ff, 0xbbbbbbff, 0xdcdcdcff, 0xd5d5d5ff, 0xc6c6c6ff, 0xacacacff, 0xc7c7c7ff, 0xf1f1f1ff, 0xf2f2f2ff, 0xe8e8e8ff, 0xf5f5f5ff, 0xb4b4b4ff, 0x838383ff, 0xc8c8c8ff, 0xb9b9b9ff, 0x9f9f9fff, 0x787878ff, 0x616161ff, 0x767676ff, 0x919191ff, 0x9c9c9cff, 0xa2a2a2ff, 0xacacacff, 0xa5a5a5ff, 0x787878ff, 0x8a8a8aff, 0xb8b8b8ff, 0xb8b8b8ff, 0xa3a3a3ff, 0x8d8d8dff, 0x969696ff, +0x838383ff, 0x7b7b7bff, 0xa0a0a0ff, 0xb6b6b6ff, 0x9b9b9bff, 0x999999ff, 0x909090ff, 0x787878ff, 0x838383ff, 0xadadadff, 0xbdbdbdff, 0x8d8d8dff, 0x828282ff, 0x969696ff, 0x7a7a7aff, 0x8a8a8aff, 0xcececeff, 0xb1b1b1ff, 0x8f8f8fff, 0x909090ff, 0x7f7f7fff, 0x828282ff, 0xa6a6a6ff, 0xbfbfbfff, 0xa7a7a7ff, 0x818181ff, 0x999999ff, 0xb8b8b8ff, 0xaeaeaeff, 0xb4b4b4ff, 0xbbbbbbff, 0xa7a7a7ff, +0xa0a0a0ff, 0x8a8a8aff, 0x747474ff, 0x7e7e7eff, 0x8b8b8bff, 0x8f8f8fff, 0xa4a4a4ff, 0x9e9e9eff, 0x7b7b7bff, 0x6e6e6eff, 0x7a7a7aff, 0x838383ff, 0x8c8c8cff, 0xa7a7a7ff, 0x939393ff, 0x717171ff, 0x6b6b6bff, 0x6e6e6eff, 0x818181ff, 0xa3a3a3ff, 0x969696ff, 0x5e5e5eff, 0x505050ff, 0x4e4e4eff, 0x5c5c5cff, 0x8f8f8fff, 0xb6b6b6ff, 0x9b9b9bff, 0x636363ff, 0x4c4c4cff, 0x505050ff, 0x6a6a6aff, +0xa7a7a7ff, 0xb4b4b4ff, 0x6e6e6eff, 0x535353ff, 0x4f4f4fff, 0x595959ff, 0x7f7f7fff, 0xb4b4b4ff, 0x8d8d8dff, 0x5b5b5bff, 0x545454ff, 0x5c5c5cff, 0x6b6b6bff, 0x696969ff, 0x707070ff, 0x626262ff, 0x4f4f4fff, 0x626262ff, 0x6c6c6cff, 0x727272ff, 0x919191ff, 0x848484ff, 0x676767ff, 0x676767ff, 0x717171ff, 0x7a7a7aff, 0x848484ff, 0x969696ff, 0x838383ff, 0x8e8e8eff, 0xb0b0b0ff, 0xd0d0d0ff, +0xdededeff, 0xbebebeff, 0x828282ff, 0x505050ff, 0x363636ff, 0x3b3b3bff, 0x424242ff, 0x3f3f3fff, 0x3f3f3fff, 0x424242ff, 0x424242ff, 0x404040ff, 0x484848ff, 0x6a6a6aff, 0x737373ff, 0x4f4f4fff, 0x383838ff, 0x373737ff, 0x3e3e3eff, 0x4c4c4cff, 0x454545ff, 0x454545ff, 0x484848ff, 0x434343ff, 0x383838ff, 0x262628ff, 0x22221cff, 0x23231aff, 0x12125aff, 0x01019dff, 0x00009aff, 0x000098ff, +0x0000a0ff, 0x242463ff, 0x636350ff, 0x99999aff, 0xaeaeaeff, 0xa9a9a9ff, 0xaaaaaaff, 0xaaaaaaff, 0xaaaaaaff, 0xaaaaaaff, 0xaaaaaaff, 0xaaaaaaff, 0xaaaaaaff, 0xaaaaaaff, 0xaaaaaaff, 0xaaaaaaff, 0xaaaaaaff, 0xaaaaaaff, 0xaaaaaaff, 0xaaaaaaff, 0xaaaaaaff, 0xaaaaaaff, 0xaaaaaaff, 0xaaaaaaff, 0xaaaaaaff, 0xaaaaaaff, 0xa8a8a8ff, 0xb8b8b8ff, 0xbebebeff, 0xb5b5b5ff, 0xb1b1b1ff, 0xc0c0c0ff, +0xc5c5c5ff, 0xc6c6c6ff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xcbcbcbff, 0xd2d2d2ff, 0xb9b9b9ff, 0x7e7e7eff, 0x545454ff, 0x3f3f3fff, 0x444444ff, 0x424344ff, 0x3e4145ff, 0x514f41ff, 0x427039ff, 0x3f8f31ff, 0x3e563fff, 0x403d45ff, 0x444443ff, 0x444444ff, 0x444444ff, 0x444444ff, 0x444444ff, 0x444444ff, 0x444444ff, +0x444444ff, 0x444444ff, 0x444444ff, 0x444444ff, 0x444444ff, 0x444444ff, 0x444444ff, 0x444444ff, 0x444444ff, 0x444444ff, 0x444444ff, 0x444444ff, 0x444444ff, 0x444444ff, 0x444444ff, 0x444444ff, 0x444444ff, 0x444444ff, 0x444444ff, 0x444444ff, 0x444444ff, 0x444444ff, 0x444444ff, 0x404040ff, 0x606060ff, 0x7b7b7bff, 0x333333ff, 0x040404ff, 0x161616ff, 0x323232ff, 0x686868ff, 0xa3a3a3ff, +0xd5d5d5ff, 0xc3c3c3ff, 0xc0c0c0ff, 0xd0d0d0ff, 0xb9b9b9ff, 0xa2a2a2ff, 0xb9b9b9ff, 0xdadadaff, 0xf1f1f1ff, 0xe8e8e8ff, 0xd0d0d0ff, 0xdededeff, 0xd7d7d7ff, 0xd1d1d1ff, 0xf6f6f6ff, 0xf0f0f0ff, 0xcfcfcfff, 0xa0a0a0ff, 0x9e9e9eff, 0xc4c4c4ff, 0xdfdfdfff, 0xc4c4c4ff, 0x818181ff, 0x646464ff, 0x6e6e6eff, 0x656565ff, 0x616161ff, 0x7c7c7cff, 0x7e7e7eff, 0x737373ff, 0x747474ff, 0x7e7e7eff, +0x6d6d6dff, 0x5a5a5aff, 0x5d5d5dff, 0x868686ff, 0xa2a2a2ff, 0xa2a2a2ff, 0x8a8a8aff, 0x6d6d6dff, 0x616161ff, 0x717171ff, 0x8a8a8aff, 0xa4a4a4ff, 0x9a9a9aff, 0x6c6c6cff, 0x5a5a5aff, 0x686868ff, 0x7f7f7fff, 0x898989ff, 0x9e9e9eff, 0x9e9e9eff, 0x8d8d8dff, 0x939393ff, 0x919191ff, 0x838383ff, 0x878787ff, 0x909090ff, 0xbdbdbdff, 0xe4e4e4ff, 0xd3d3d3ff, 0x919191ff, 0x757575ff, 0x7f7f7fff, +0x828282ff, 0x757575ff, 0x6e6e6eff, 0x6e6e6eff, 0x6a6a6aff, 0x707070ff, 0x7a7a7aff, 0x797979ff, 0x686868ff, 0x585858ff, 0x555555ff, 0x5c5c5cff, 0x6c6c6cff, 0x747474ff, 0x686868ff, 0x5b5b5bff, 0x585858ff, 0x4b4b4bff, 0x454545ff, 0x5a5a5aff, 0x575757ff, 0x3f3f3fff, 0x3a3a3aff, 0x3a3a3aff, 0x3f3f3fff, 0x565656ff, 0x868686ff, 0x9e9e9eff, 0x6c6c6cff, 0x555555ff, 0x5f5f5fff, 0x646464ff, +0x7b7b7bff, 0x919191ff, 0x7a7a7aff, 0x5a5a5aff, 0x5e5e5eff, 0x555555ff, 0x515151ff, 0x6d6d6dff, 0x6f6f6fff, 0x606060ff, 0x505050ff, 0x505050ff, 0x575757ff, 0x555555ff, 0x656565ff, 0x606060ff, 0x4a4a4aff, 0x545454ff, 0x575757ff, 0x595959ff, 0x666666ff, 0x646464ff, 0x4d4d4dff, 0x474747ff, 0x494949ff, 0x404040ff, 0x3f3f3fff, 0x464646ff, 0x484848ff, 0x5a5a5aff, 0x5f5f5fff, 0x5f5f5fff, +0x606060ff, 0x565656ff, 0x4b4b4bff, 0x444444ff, 0x404040ff, 0x404040ff, 0x3e3e3eff, 0x3e3e3eff, 0x3e3e3eff, 0x3e3e3eff, 0x3e3e3eff, 0x3e3e3eff, 0x3f3f3fff, 0x404040ff, 0x373737ff, 0x2d2d2dff, 0x282828ff, 0x282828ff, 0x252525ff, 0x222222ff, 0x232323ff, 0x252525ff, 0x242424ff, 0x272727ff, 0x282828ff, 0x232323ff, 0x212122ff, 0x272718ff, 0x181836ff, 0x010185ff, 0x00009cff, 0x000098ff, +0x0000a0ff, 0x242463ff, 0x5c5c4aff, 0x949496ff, 0xafafafff, 0xa9a9a9ff, 0xa9a9a9ff, 0xa9a9a9ff, 0xa9a9a9ff, 0xaaaaaaff, 0xaaaaaaff, 0xaaaaaaff, 0xaaaaaaff, 0xaaaaaaff, 0xaaaaaaff, 0xaaaaaaff, 0xaaaaaaff, 0xaaaaaaff, 0xaaaaaaff, 0xaaaaaaff, 0xaaaaaaff, 0xaaaaaaff, 0xaaaaaaff, 0xaaaaaaff, 0xaaaaaaff, 0xaaaaaaff, 0xa6a6a6ff, 0xabababff, 0xb9b9b9ff, 0xc5c5c5ff, 0xcacacaff, 0xcececeff, +0xd0d0d0ff, 0xcdcdcdff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xcbcbcbff, 0xd2d2d2ff, 0xb9b9b9ff, 0x7d7d7dff, 0x525252ff, 0x3f3f3fff, 0x434444ff, 0x3e4144ff, 0x68513eff, 0xb98c2bff, 0x9bb821ff, 0xafab23ff, 0x866137ff, 0x443f44ff, 0x414344ff, 0x444444ff, 0x444444ff, 0x444444ff, 0x444444ff, 0x444444ff, 0x444444ff, +0x444444ff, 0x444444ff, 0x444444ff, 0x444444ff, 0x444444ff, 0x444444ff, 0x444444ff, 0x444444ff, 0x444444ff, 0x444444ff, 0x444444ff, 0x444444ff, 0x444444ff, 0x444444ff, 0x444444ff, 0x444444ff, 0x444444ff, 0x444444ff, 0x444444ff, 0x444444ff, 0x444444ff, 0x444444ff, 0x444444ff, 0x404040ff, 0x606060ff, 0x7b7b7bff, 0x333333ff, 0x040404ff, 0x141414ff, 0x303030ff, 0x646464ff, 0xa1a1a1ff, +0xd1d1d1ff, 0xcececeff, 0xccccccff, 0xd9d9d9ff, 0xdadadaff, 0xc4c4c4ff, 0xa6a6a6ff, 0xacacacff, 0xc7c7c7ff, 0xc3c3c3ff, 0xc9c9c9ff, 0xd1d1d1ff, 0xd6d6d6ff, 0xd2d2d2ff, 0xd0d0d0ff, 0xd0d0d0ff, 0xb6b6b6ff, 0xb6b6b6ff, 0xd5d5d5ff, 0xedededff, 0xfbfbfbff, 0xd4d4d4ff, 0x7a7a7aff, 0x636363ff, 0x797979ff, 0x727272ff, 0x87877cff, 0x6f6f6fff, 0x6c6c6cff, 0x7a7a7aff, 0x757575ff, 0x818181ff, +0xb8b8b8ff, 0xbdbdbdff, 0x878787ff, 0x797979ff, 0x888888ff, 0x9f9f9fff, 0xa8a8a8ff, 0xbbbbbbff, 0xdcdcdcff, 0xc0c0c0ff, 0x7a7a7aff, 0x727272ff, 0x777777ff, 0x666666ff, 0x646464ff, 0x656565ff, 0x585858ff, 0x525252ff, 0x5b5b5bff, 0x797979ff, 0xafafafff, 0xb8b8b8ff, 0x7a7a7aff, 0x5b5b5bff, 0x626262ff, 0x6d6d6dff, 0x9c9c9cff, 0xcececeff, 0xc7c7c7ff, 0x858585ff, 0x565656ff, 0x5f5f5fff, +0x585858ff, 0x555555ff, 0x595959ff, 0x595959ff, 0x5a5a5aff, 0x535353ff, 0x3e3e3eff, 0x474747ff, 0x555555ff, 0x4e4e4eff, 0x4e4e4eff, 0x4d4d4dff, 0x4b4b4bff, 0x484848ff, 0x4d4d4dff, 0x515151ff, 0x555555ff, 0x555555ff, 0x4e4e4eff, 0x484848ff, 0x4a4a4aff, 0x4e4e4eff, 0x505050ff, 0x505050ff, 0x4e4e4eff, 0x505050ff, 0x595959ff, 0x727272ff, 0x737373ff, 0x6a6a6aff, 0x646464ff, 0x606060ff, +0x5f5f5fff, 0x646464ff, 0x666666ff, 0x565656ff, 0x444444ff, 0x3b3b3bff, 0x373737ff, 0x3a3a3aff, 0x3e3e3eff, 0x3f3f3fff, 0x3a3a3aff, 0x393939ff, 0x383838ff, 0x363636ff, 0x3b3b3bff, 0x3c3c3cff, 0x393939ff, 0x393939ff, 0x373737ff, 0x363636ff, 0x363636ff, 0x3b3b3bff, 0x3b3b3bff, 0x3a3a3aff, 0x3d3d3dff, 0x323232ff, 0x212121ff, 0x212121ff, 0x212121ff, 0x1e1e1eff, 0x1c1c1cff, 0x1b1b1bff, +0x1a1a1aff, 0x1d1d1dff, 0x212121ff, 0x232323ff, 0x252525ff, 0x262626ff, 0x262626ff, 0x262626ff, 0x262626ff, 0x262626ff, 0x262626ff, 0x262626ff, 0x262626ff, 0x222222ff, 0x1c1c1cff, 0x1d1d1dff, 0x1f1f1fff, 0x1f1f1fff, 0x1f1f1fff, 0x1f1f1fff, 0x1f1f1fff, 0x1f1f1fff, 0x1f1f1fff, 0x1f1f1fff, 0x1f1f1fff, 0x212121ff, 0x1f1f1fff, 0x1d1d1bff, 0x181812ff, 0x060649ff, 0x00009dff, 0x00009aff, +0x0000a0ff, 0x29295eff, 0x545434ff, 0x939390ff, 0xbbbbbcff, 0xb2b2b2ff, 0xafafb0ff, 0xadadaeff, 0xaaaaabff, 0xa9a9a9ff, 0xa6a6a7ff, 0xa5a5a5ff, 0xa5a5a5ff, 0xa5a5a5ff, 0xa5a5a5ff, 0xa5a5a5ff, 0xa5a5a5ff, 0xa5a5a5ff, 0xa7a7a7ff, 0xa8a8a8ff, 0xaaaaaaff, 0xaaaaaaff, 0xaaaaaaff, 0xaaaaaaff, 0xaaaaaaff, 0xa8a8a8ff, 0xaeaeaeff, 0xb2b2b2ff, 0xb6b6b6ff, 0xbfbfbfff, 0xc4c4c4ff, 0xc6c6c6ff, +0xc4c4c4ff, 0xcbcbcbff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xcbcbcbff, 0xd2d2d2ff, 0xb9b9b9ff, 0x828282ff, 0x5a5a5aff, 0x3e3e3eff, 0x424444ff, 0x3e4243ff, 0xad522bff, 0xff6817ff, 0xee6d19ff, 0xf1681aff, 0xa95d29ff, 0x4b4740ff, 0x3f4244ff, 0x444444ff, 0x444444ff, 0x444444ff, 0x444444ff, 0x444444ff, 0x444444ff, +0x444444ff, 0x444444ff, 0x444444ff, 0x444444ff, 0x444444ff, 0x444444ff, 0x444444ff, 0x444444ff, 0x444444ff, 0x444444ff, 0x444444ff, 0x444444ff, 0x444444ff, 0x444444ff, 0x444444ff, 0x444444ff, 0x444444ff, 0x444444ff, 0x444444ff, 0x444444ff, 0x444444ff, 0x444444ff, 0x444444ff, 0x404040ff, 0x606060ff, 0x7b7b7bff, 0x333333ff, 0x030303ff, 0x181818ff, 0x3e3e3fff, 0x747474ff, 0xabababff, +0xd2d2d2ff, 0xcbcbcbff, 0xcbcbcbff, 0xcececeff, 0xd4d4d4ff, 0xddddddff, 0xccccccff, 0xb8b8b8ff, 0xa2a2a2ff, 0xa9a9a9ff, 0xbfbfbfff, 0xb3b3b3ff, 0xb2b2b2ff, 0xc5c5c5ff, 0xd3d3d3ff, 0xcfcfcfff, 0xd4d4d4ff, 0xd0d0d0ff, 0xd2d2d2ff, 0xe5e5e5ff, 0xedededff, 0xc0c0c0ff, 0x9f9f9fff, 0xc7c7c7ff, 0xe5e5e5ff, 0xeeeee4ff, 0x131393ff, 0xbebeb3ff, 0x686868ff, 0x686868ff, 0x666666ff, 0x727272ff, +0xaaaaaaff, 0xcececeff, 0xa4a4a4ff, 0x696969ff, 0x616161ff, 0x6a6a6aff, 0x6f6f6fff, 0x909090ff, 0xcbcbcbff, 0xbfbfbfff, 0x767676ff, 0x5a5a5aff, 0x616161ff, 0x646464ff, 0x656565ff, 0x686868ff, 0x666666ff, 0x606060ff, 0x5e5e5eff, 0x595959ff, 0x717171ff, 0x888888ff, 0x717171ff, 0x646464ff, 0x676767ff, 0x666666ff, 0x6d6d6dff, 0x7a7a7aff, 0x7b7b7bff, 0x727272ff, 0x6a6a6aff, 0x6e6e6eff, +0x5e5e5eff, 0x535353ff, 0x555555ff, 0x555555ff, 0x555555ff, 0x555555ff, 0x515151ff, 0x515151ff, 0x5c5c5cff, 0x666666ff, 0x666666ff, 0x666666ff, 0x676767ff, 0x666666ff, 0x5f5f5fff, 0x585858ff, 0x515151ff, 0x4f4f4fff, 0x515151ff, 0x515151ff, 0x515151ff, 0x515151ff, 0x515151ff, 0x515151ff, 0x515151ff, 0x4f4f4fff, 0x4e4e4eff, 0x505050ff, 0x535353ff, 0x4f4f4fff, 0x3f3f3fff, 0x3d3d3dff, +0x3d3d3dff, 0x3b3b3bff, 0x3d3d3dff, 0x3d3d3dff, 0x2a2a2aff, 0x212121ff, 0x242424ff, 0x232323ff, 0x222222ff, 0x222222ff, 0x232323ff, 0x242424ff, 0x242424ff, 0x242424ff, 0x232323ff, 0x232323ff, 0x242424ff, 0x242424ff, 0x242424ff, 0x242424ff, 0x242424ff, 0x232323ff, 0x232323ff, 0x242424ff, 0x252525ff, 0x222222ff, 0x1f1f1fff, 0x202020ff, 0x202020ff, 0x202020ff, 0x202020ff, 0x202020ff, +0x202020ff, 0x202020ff, 0x202020ff, 0x202020ff, 0x1f1f1fff, 0x1f1f1fff, 0x1f1f1fff, 0x1f1f1fff, 0x1f1f1fff, 0x1f1f1fff, 0x1f1f1fff, 0x1f1f1fff, 0x1f1f1fff, 0x202020ff, 0x212121ff, 0x222222ff, 0x222222ff, 0x222222ff, 0x222222ff, 0x222222ff, 0x222222ff, 0x222222ff, 0x222222ff, 0x222222ff, 0x222222ff, 0x222222ff, 0x1a1a1aff, 0x141415ff, 0x20200eff, 0x141445ff, 0x00009eff, 0x00009aff, +0x00009dff, 0x191974ff, 0x323256ff, 0x727277ff, 0x999983ff, 0x939383ff, 0x9a9a8aff, 0xa6a696ff, 0xb8b8a9ff, 0xbabaabff, 0xc0c0afff, 0xc9c9b9ff, 0xc4c4bdff, 0xbfbfc0ff, 0xbdbdbeff, 0xbbbbbcff, 0xb9b9baff, 0xbababbff, 0xb7b7b8ff, 0xaeaeaeff, 0xa9a9a9ff, 0xa5a5a5ff, 0xa6a6a6ff, 0xa7a7a7ff, 0xa4a4a4ff, 0xa3a3a3ff, 0xbcbcbcff, 0xcdcdcdff, 0xc6c6c6ff, 0xb7b7b7ff, 0xb9b9b9ff, 0xc0c0c0ff, +0xbdbdbdff, 0xc9c9c9ff, 0xcbcbcbff, 0xcbcbcbff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xccccccff, 0xcbcbcbff, 0xd2d2d2ff, 0xb7b7b7ff, 0x8d8d8dff, 0x6a6a6aff, 0x3c3b3bff, 0x424444ff, 0x3f4343ff, 0xa33355ff, 0xe22959ff, 0xdd2c50ff, 0xcc3059ff, 0x7e3f5eff, 0x434448ff, 0x414342ff, 0x444444ff, 0x444444ff, 0x444444ff, 0x444444ff, 0x444444ff, 0x444444ff, +0x444444ff, 0x444444ff, 0x444444ff, 0x444444ff, 0x444444ff, 0x444444ff, 0x444444ff, 0x444444ff, 0x444444ff, 0x444444ff, 0x444444ff, 0x444444ff, 0x444444ff, 0x444444ff, 0x444444ff, 0x444444ff, 0x444444ff, 0x444444ff, 0x444444ff, 0x444444ff, 0x444444ff, 0x444444ff, 0x434343ff, 0x3e3e3eff, 0x5e5e5eff, 0x7f7f80ff, 0x353536ff, 0x030300ff, 0x1e1e11ff, 0x4b4b41ff, 0x888887ff, 0xafafb0ff, +0xc7c7c7ff, 0xcdcdcdff, 0xcbcbcbff, 0xcacacaff, 0xc9c9c9ff, 0xccccccff, 0xcfcfcfff, 0xccccccff, 0xc5c5c5ff, 0xcececeff, 0xc5c5c5ff, 0xa1a1a1ff, 0x8c8c8cff, 0x959595ff, 0xb4b4b4ff, 0xb3b3b3ff, 0xcfcfcfff, 0xdadadaff, 0xd1d1d1ff, 0xd9d9d9ff, 0xdfdfdfff, 0xd1d1d1ff, 0xd4d4d4ff, 0xe7e7e7ff, 0xf7f7f7ff, 0xfffffbff, 0xa7a7daff, 0xbbbbb6ff, 0x696969ff, 0x646464ff, 0x686868ff, 0x656565ff, +0x606060ff, 0x787878ff, 0x7f7f7fff, 0x6b6b6bff, 0x6a6a6aff, 0x696969ff, 0x676767ff, 0x696969ff, 0x717171ff, 0x717171ff, 0x6d6d6dff, 0x6c6c6cff, 0x6d6d6dff, 0x6c6c6cff, 0x6e6e6eff, 0x676767ff, 0x5f5f5fff, 0x606060ff, 0x616161ff, 0x5b5b5bff, 0x595959ff, 0x5c5c5cff, 0x5e5e5eff, 0x5e5e5eff, 0x606060ff, 0x5b5b5bff, 0x4f4f4fff, 0x4a4a4aff, 0x4b4b4bff, 0x4e4e4eff, 0x515151ff, 0x515151ff, +0x4e4e4eff, 0x4d4d4dff, 0x4e4e4eff, 0x4e4e4eff, 0x4e4e4eff, 0x4e4e4eff, 0x4f4f4fff, 0x4e4e4eff, 0x4f4f4fff, 0x525252ff, 0x525252ff, 0x525252ff, 0x525252ff, 0x515151ff, 0x434343ff, 0x373737ff, 0x2a2a2aff, 0x242424ff, 0x252525ff, 0x252525ff, 0x252525ff, 0x252525ff, 0x252525ff, 0x252525ff, 0x252525ff, 0x252525ff, 0x252525ff, 0x242424ff, 0x242424ff, 0x242424ff, 0x212121ff, 0x202020ff, +0x212121ff, 0x212121ff, 0x202020ff, 0x222222ff, 0x202020ff, 0x1f1f1fff, 0x202020ff, 0x202020ff, 0x202020ff, 0x202020ff, 0x202020ff, 0x202020ff, 0x202020ff, 0x202020ff, 0x202020ff, 0x202020ff, 0x202020ff, 0x202020ff, 0x202020ff, 0x202020ff, 0x202020ff, 0x202020ff, 0x202020ff, 0x202020ff, 0x202020ff, 0x202020ff, 0x222222ff, 0x222222ff, 0x222222ff, 0x222222ff, 0x222222ff, 0x222222ff, +0x222222ff, 0x222222ff, 0x222222ff, 0x222222ff, 0x222222ff, 0x222222ff, 0x222222ff, 0x222222ff, 0x222222ff, 0x222222ff, 0x222222ff, 0x222222ff, 0x222222ff, 0x222222ff, 0x222222ff, 0x222222ff, 0x222222ff, 0x222222ff, 0x222222ff, 0x222222ff, 0x222222ff, 0x222222ff, 0x222222ff, 0x222222ff, 0x222222ff, 0x222222ff, 0x212121ff, 0x1f1f20ff, 0x252515ff, 0x16164dff, 0x01019eff, 0x00009aff, +0x000099ff, 0x010199ff, 0x050596ff, 0x1b1b73ff, 0x2d2d5cff, 0x2d2d65ff, 0x393970ff, 0x4b4b83ff, 0x68689fff, 0x6a6aa3ff, 0x7474abff, 0x7f7fc0ff, 0x9393a3ff, 0xb0b096ff, 0xb4b4a3ff, 0xbebeacff, 0xc4c4b3ff, 0xc3c3b2ff, 0xbfbfacff, 0xabab9eff, 0xadadadff, 0xc4c4c5ff, 0xbdbdbeff, 0xb9b9baff, 0xc6c6c7ff, 0xc2c2c4ff, 0xd3d3d4ff, 0xdededfff, 0xdbdbdcff, 0xd9d9daff, 0xd9d9daff, 0xdadadbff, +0xd8d8d9ff, 0xd5d5d7ff, 0xd3d3d3ff, 0xcfcfcfff, 0xcacacaff, 0xcbcbcbff, 0xcbcbcbff, 0xcbcbcbff, 0xcbcbcbff, 0xcbcbcbff, 0xcbcbcbff, 0xcbcbcbff, 0xd2d2d2ff, 0xb6b6b6ff, 0x8f8f8fff, 0x6c6c6cff, 0x3b3b3bff, 0x434444ff, 0x414440ff, 0x6c3a70ff, 0x721eb9ff, 0x5f12ceff, 0x6d1bbfff, 0x6e3482ff, 0x4a4348ff, 0x414441ff, 0x444444ff, 0x444444ff, 0x444444ff, 0x444444ff, 0x444444ff, 0x444444ff, +0x444444ff, 0x444444ff, 0x444444ff, 0x444444ff, 0x444444ff, 0x444444ff, 0x444444ff, 0x444444ff, 0x444444ff, 0x444444ff, 0x444444ff, 0x444444ff, 0x444444ff, 0x444444ff, 0x434344ff, 0x434344ff, 0x434344ff, 0x434344ff, 0x434344ff, 0x434344ff, 0x434344ff, 0x434344ff, 0x414142ff, 0x505047ff, 0x6e6e5cff, 0x727261ff, 0x31311cff, 0x040401ff, 0x0b0b3eff, 0x24244aff, 0x565647ff, 0x8f8f7bff, +0xcfcfc6ff, 0xdedee0ff, 0xd4d4d5ff, 0xcececeff, 0xcacacaff, 0xcbcbcbff, 0xcbcbcbff, 0xccccccff, 0xccccccff, 0xd5d5d5ff, 0xd7d7d7ff, 0xd5d5d5ff, 0xc1c1c1ff, 0x989898ff, 0xa1a1a1ff, 0x8a8a8aff, 0x8d8d8dff, 0x9e9e9eff, 0xa5a5a5ff, 0xa5a5a5ff, 0xaeaeaeff, 0xcdcdcdff, 0xe1e1e1ff, 0xe5e5e5ff, 0xebebebff, 0xf5f5f4ff, 0xe4e4dfff, 0x969696ff, 0x666666ff, 0x5f5f5fff, 0x606060ff, 0x545454ff, +0x4d4d4dff, 0x4e4e4eff, 0x505050ff, 0x505050ff, 0x4d4d4dff, 0x4e4e4eff, 0x4e4e4eff, 0x4c4c4cff, 0x4a4a4aff, 0x4a4a4aff, 0x4d4d4dff, 0x4d4d4dff, 0x4d4d4dff, 0x4d4d4dff, 0x505050ff, 0x464646ff, 0x363636ff, 0x363636ff, 0x363636ff, 0x373737ff, 0x373737ff, 0x363636ff, 0x363636ff, 0x363636ff, 0x383838ff, 0x313131ff, 0x232323ff, 0x202020ff, 0x212121ff, 0x202020ff, 0x202020ff, 0x202020ff, +0x212121ff, 0x212121ff, 0x212121ff, 0x212121ff, 0x212121ff, 0x212121ff, 0x212121ff, 0x212121ff, 0x212121ff, 0x202020ff, 0x202020ff, 0x202020ff, 0x202020ff, 0x202020ff, 0x1f1f1fff, 0x1e1e1eff, 0x1f1f1fff, 0x1f1f1fff, 0x1f1f1fff, 0x1f1f1fff, 0x1f1f1fff, 0x1f1f1fff, 0x1f1f1fff, 0x1f1f1fff, 0x1f1f1fff, 0x1f1f1fff, 0x1f1f1fff, 0x1f1f1fff, 0x1f1f1fff, 0x202020ff, 0x202020ff, 0x202020ff, +0x202020ff, 0x202020ff, 0x202020ff, 0x202020ff, 0x212121ff, 0x222222ff, 0x222222ff, 0x222222ff, 0x222222ff, 0x222222ff, 0x222222ff, 0x222222ff, 0x222222ff, 0x222222ff, 0x222222ff, 0x222222ff, 0x222222ff, 0x222222ff, 0x222222ff, 0x222222ff, 0x222222ff, 0x222222ff, 0x222222ff, 0x222222ff, 0x222222ff, 0x222222ff, 0x222222ff, 0x222222ff, 0x222222ff, 0x222222ff, 0x222222ff, 0x222222ff, +0x222222ff, 0x222222ff, 0x222222ff, 0x222222ff, 0x222222ff, 0x222222ff, 0x222222ff, 0x222222ff, 0x222222ff, 0x222222ff, 0x222222ff, 0x222222ff, 0x222222ff, 0x222222ff, 0x222222ff, 0x222222ff, 0x222222ff, 0x222222ff, 0x222222ff, 0x222222ff, 0x222222ff, 0x222222ff, 0x222222ff, 0x222222ff, 0x222222ff, 0x212121ff, 0x222222ff, 0x222223ff, 0x262617ff, 0x17174fff, 0x01019eff, 0x00009aff, +0x000098ff, 0x00009aff, 0x00009aff, 0x00009aff, 0x00009bff, 0x00009bff, 0x000099ff, 0x00009aff, 0x010197ff, 0x010196ff, 0x020295ff, 0x01019dff, 0x090977ff, 0x323265ff, 0x383877ff, 0x454583ff, 0x4e4e8dff, 0x4c4c8bff, 0x49498fff, 0x53537dff, 0x7c7c70ff, 0xa0a08bff, 0x959582ff, 0x90907dff, 0xa1a18eff, 0x9e9e8bff, 0x9e9e8aff, 0x9d9d89ff, 0x9d9d89ff, 0x9d9d8aff, 0x9d9d8aff, 0x9c9c88ff, +0xa0a08eff, 0xb5b5a0ff, 0xbabaaeff, 0xc7c7c8ff, 0xdfdfe0ff, 0xdcdcddff, 0xdcdcddff, 0xdcdcddff, 0xdcdcddff, 0xdcdcdcff, 0xd8d8d8ff, 0xd3d3d3ff, 0xdadadaff, 0xbababaff, 0x909090ff, 0x6d6d6dff, 0x3b3b3bff, 0x444444ff, 0x444441ff, 0x3d4343ff, 0x1d247eff, 0x0b12a3ff, 0x191f89ff, 0x393d4fff, 0x44453fff, 0x434344ff, 0x434344ff, 0x434344ff, 0x434344ff, 0x434344ff, 0x434344ff, 0x434344ff, +0x434344ff, 0x434344ff, 0x434344ff, 0x434344ff, 0x434344ff, 0x434344ff, 0x434344ff, 0x434344ff, 0x434344ff, 0x434344ff, 0x434344ff, 0x434344ff, 0x434344ff, 0x434344ff, 0x454542ff, 0x4a4a3aff, 0x4c4c38ff, 0x4c4c38ff, 0x4c4c38ff, 0x4c4c38ff, 0x4c4c38ff, 0x4c4c38ff, 0x4d4d35ff, 0x434363ff, 0x3a3a80ff, 0x2b2b68ff, 0x12124aff, 0x010151ff, 0x000096ff, 0x02028aff, 0x0f0f50ff, 0x38387cff, +0x737390ff, 0xa0a083ff, 0xbabaa9ff, 0xd3d3ccff, 0xd9d9dbff, 0xcfcfcfff, 0xcbcbcbff, 0xc7c7c7ff, 0xc6c6c6ff, 0xc7c7c7ff, 0xc8c8c8ff, 0xd6d6d6ff, 0xdcdcdcff, 0xcdcdcdff, 0xd1d1d1ff, 0xb2b2b2ff, 0x8c8c8cff, 0x8a8a8aff, 0xa7a7a7ff, 0xb2b2b2ff, 0xb6b6b6ff, 0xc7c7c7ff, 0xcfcfcfff, 0xbdbdbdff, 0x999999ff, 0x8e8e8eff, 0x656565ff, 0x444444ff, 0x2b2b2bff, 0x1f1f1fff, 0x1f1f1fff, 0x101010ff, +0x0b0b0bff, 0x0b0b0bff, 0x090909ff, 0x111111ff, 0x1d1d1dff, 0x1d1d1dff, 0x1d1d1dff, 0x1d1d1dff, 0x1d1d1dff, 0x1d1d1dff, 0x1d1d1dff, 0x1d1d1dff, 0x1d1d1dff, 0x1d1d1dff, 0x1d1d1dff, 0x1e1e1eff, 0x1e1e1eff, 0x1e1e1eff, 0x1e1e1eff, 0x1e1e1eff, 0x1e1e1eff, 0x1e1e1eff, 0x1e1e1eff, 0x1e1e1eff, 0x1e1e1eff, 0x1f1f1fff, 0x1f1f1fff, 0x202020ff, 0x202020ff, 0x202020ff, 0x202020ff, 0x202020ff, +0x202020ff, 0x202020ff, 0x202020ff, 0x202020ff, 0x202020ff, 0x202020ff, 0x202020ff, 0x202020ff, 0x202020ff, 0x202020ff, 0x202020ff, 0x202020ff, 0x202020ff, 0x202020ff, 0x212121ff, 0x212121ff, 0x212121ff, 0x222222ff, 0x222222ff, 0x222222ff, 0x222222ff, 0x222222ff, 0x222222ff, 0x222222ff, 0x222222ff, 0x222222ff, 0x222222ff, 0x222222ff, 0x222222ff, 0x222222ff, 0x222222ff, 0x222222ff, +0x222222ff, 0x222222ff, 0x222222ff, 0x222222ff, 0x222222ff, 0x222222ff, 0x222222ff, 0x222222ff, 0x222222ff, 0x222222ff, 0x222222ff, 0x222222ff, 0x222222ff, 0x222222ff, 0x222222ff, 0x222222ff, 0x222222ff, 0x222222ff, 0x222222ff, 0x222222ff, 0x222222ff, 0x222222ff, 0x222222ff, 0x222222ff, 0x222222ff, 0x222222ff, 0x222222ff, 0x222222ff, 0x222222ff, 0x222222ff, 0x222222ff, 0x222222ff, +0x222222ff, 0x212122ff, 0x212122ff, 0x212122ff, 0x212122ff, 0x212122ff, 0x212122ff, 0x212122ff, 0x212122ff, 0x222222ff, 0x222222ff, 0x222222ff, 0x222222ff, 0x222222ff, 0x222222ff, 0x222222ff, 0x222222ff, 0x222222ff, 0x222222ff, 0x222222ff, 0x222222ff, 0x222222ff, 0x222222ff, 0x212122ff, 0x212122ff, 0x212122ff, 0x212122ff, 0x242426ff, 0x22220cff, 0x0d0d38ff, 0x00009eff, 0x00009aff, +0x000099ff, 0x000098ff, 0x000098ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x00009bff, 0x00009fff, 0x00009dff, 0x00009bff, 0x00009aff, 0x00009aff, 0x00009dff, 0x00008dff, 0x161666ff, 0x17175cff, 0x17175eff, 0x17175fff, 0x15155dff, 0x15155dff, 0x15155dff, 0x15155dff, 0x15155dff, 0x15155dff, 0x15155dff, 0x13135bff, +0x1b1b61ff, 0x2e2e7eff, 0x4d4d72ff, 0x7f7f65ff, 0x9a9a85ff, 0x959580ff, 0x969681ff, 0x969681ff, 0x959580ff, 0x969684ff, 0xa2a29eff, 0xb3b3b3ff, 0xb9b9baff, 0xabababff, 0x8f8f8fff, 0x636363ff, 0x3d3d3dff, 0x444444ff, 0x444344ff, 0x434442ff, 0x484839ff, 0x494a35ff, 0x474838ff, 0x47473dff, 0x4a4b39ff, 0x4d4c37ff, 0x4c4c37ff, 0x4c4c37ff, 0x4c4c37ff, 0x4c4c37ff, 0x4c4c37ff, 0x4c4c37ff, +0x4c4c37ff, 0x4c4c37ff, 0x4c4c37ff, 0x4c4c37ff, 0x4c4c37ff, 0x4c4c37ff, 0x4c4c37ff, 0x4c4c37ff, 0x4c4c37ff, 0x4c4c37ff, 0x4c4c37ff, 0x4c4c37ff, 0x4c4c37ff, 0x4e4e35ff, 0x474740ff, 0x2b2b62ff, 0x21216dff, 0x24246aff, 0x24246aff, 0x24246aff, 0x24246aff, 0x24246aff, 0x252567ff, 0x07078bff, 0x0000a3ff, 0x0000a0ff, 0x0000a4ff, 0x0000a3ff, 0x00009cff, 0x00009cff, 0x0000a1ff, 0x0000a4ff, +0x000070ff, 0x141453ff, 0x363684ff, 0x777785ff, 0xb8b89dff, 0xcacac3ff, 0xd7d7d8ff, 0xe4e4e4ff, 0xe2e2e2ff, 0xd5d5d5ff, 0xc6c6c6ff, 0xc6c6c6ff, 0xc9c9c9ff, 0xccccccff, 0xccccccff, 0xd1d1d1ff, 0xd4d4d4ff, 0xd6d6d6ff, 0xe3e3e3ff, 0xeaeaeaff, 0xe1e1e1ff, 0xcececeff, 0xccccccff, 0xc4c4c4ff, 0xaeaeaeff, 0x959595ff, 0x525252ff, 0x282828ff, 0x121212ff, 0x040404ff, 0x070707ff, 0x090909ff, +0x0a0a0aff, 0x0a0a0aff, 0x080808ff, 0x121212ff, 0x212121ff, 0x212121ff, 0x212121ff, 0x212121ff, 0x212121ff, 0x212121ff, 0x212121ff, 0x212121ff, 0x212121ff, 0x212121ff, 0x212121ff, 0x212121ff, 0x212121ff, 0x212121ff, 0x212121ff, 0x212121ff, 0x212121ff, 0x212121ff, 0x212121ff, 0x212121ff, 0x212121ff, 0x212121ff, 0x222222ff, 0x222222ff, 0x222222ff, 0x222222ff, 0x222222ff, 0x222222ff, +0x222222ff, 0x222222ff, 0x222222ff, 0x222222ff, 0x222222ff, 0x222222ff, 0x222222ff, 0x222222ff, 0x222222ff, 0x222222ff, 0x222222ff, 0x222222ff, 0x222222ff, 0x222222ff, 0x222222ff, 0x222222ff, 0x222222ff, 0x222222ff, 0x222222ff, 0x222222ff, 0x222222ff, 0x222222ff, 0x222222ff, 0x222222ff, 0x222222ff, 0x222222ff, 0x222222ff, 0x222222ff, 0x222222ff, 0x222222ff, 0x222222ff, 0x222222ff, +0x222222ff, 0x222222ff, 0x222222ff, 0x222222ff, 0x222222ff, 0x222222ff, 0x222222ff, 0x222222ff, 0x222222ff, 0x222222ff, 0x222222ff, 0x212122ff, 0x212122ff, 0x212122ff, 0x212122ff, 0x212122ff, 0x212122ff, 0x212122ff, 0x212122ff, 0x222222ff, 0x222222ff, 0x222222ff, 0x222222ff, 0x222222ff, 0x222222ff, 0x222222ff, 0x222222ff, 0x222222ff, 0x222222ff, 0x222222ff, 0x222222ff, 0x222222ff, +0x222222ff, 0x212122ff, 0x212122ff, 0x212122ff, 0x212122ff, 0x212122ff, 0x212122ff, 0x212122ff, 0x222222ff, 0x1e1e1eff, 0x1c1c1cff, 0x1c1c1cff, 0x1c1c1cff, 0x1c1c1cff, 0x1c1c1cff, 0x1c1c1cff, 0x1c1c1cff, 0x1c1c1cff, 0x1c1c1cff, 0x1c1c1cff, 0x1c1c1cff, 0x1c1c1cff, 0x1d1d1cff, 0x242415ff, 0x262611ff, 0x262611ff, 0x282813ff, 0x222206ff, 0x0b0b0bff, 0x00005eff, 0x00009dff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x00009bff, 0x0000a2ff, 0x0000a4ff, 0x0000a4ff, 0x0000a4ff, 0x0000a4ff, 0x0000a4ff, 0x0000a4ff, 0x0000a4ff, 0x0000a4ff, 0x0000a4ff, 0x0000a4ff, 0x0000a5ff, +0x0000a2ff, 0x0000a2ff, 0x000089ff, 0x121262ff, 0x0a0a60ff, 0x0a0a61ff, 0x0a0a61ff, 0x0a0a61ff, 0x080861ff, 0x12125aff, 0x414147ff, 0x5f5f4bff, 0x5e5e50ff, 0x636354ff, 0x616153ff, 0x4f4f42ff, 0x474739ff, 0x49493bff, 0x49493bff, 0x49493bff, 0x49493bff, 0x49493cff, 0x4c4c38ff, 0x3f3f47ff, 0x21216dff, 0x1b1b75ff, 0x1e1e73ff, 0x1d1d73ff, 0x1d1d73ff, 0x1d1d73ff, 0x1d1d73ff, 0x1d1d73ff, +0x1d1d73ff, 0x1d1d73ff, 0x1d1d73ff, 0x1d1d73ff, 0x1d1d73ff, 0x1d1d73ff, 0x1d1d73ff, 0x1d1d73ff, 0x1d1d73ff, 0x1d1d73ff, 0x1d1d73ff, 0x1d1d73ff, 0x1d1d73ff, 0x202070ff, 0x16167aff, 0x01019cff, 0x0000a6ff, 0x0000a4ff, 0x0000a4ff, 0x0000a4ff, 0x0000a4ff, 0x0000a4ff, 0x0000a4ff, 0x00009dff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, +0x0000a0ff, 0x0000a5ff, 0x00009fff, 0x000077ff, 0x292974ff, 0x656573ff, 0x999983ff, 0xc4c4b9ff, 0xecece8ff, 0xf6f6f5ff, 0xe9e9e8ff, 0xd7d7d7ff, 0xc7c7c7ff, 0xc8c8c8ff, 0xc7c7c7ff, 0xc7c7c7ff, 0xc8c8c8ff, 0xcacacaff, 0xc7c7c7ff, 0xc5c5c5ff, 0xc7c7c7ff, 0xcacacaff, 0xc9c9c9ff, 0xd5d5d5ff, 0xf1f1f1ff, 0xdededeff, 0x8d8d8dff, 0x525252ff, 0x2f2f2fff, 0x242424ff, 0x272727ff, 0x262626ff, +0x262626ff, 0x262626ff, 0x272727ff, 0x242424ff, 0x222222ff, 0x222222ff, 0x222222ff, 0x222222ff, 0x222222ff, 0x222222ff, 0x222222ff, 0x222222ff, 0x222222ff, 0x222222ff, 0x222222ff, 0x222222ff, 0x222222ff, 0x222222ff, 0x222222ff, 0x222222ff, 0x222222ff, 0x222222ff, 0x222222ff, 0x222222ff, 0x222222ff, 0x222222ff, 0x222222ff, 0x222222ff, 0x222222ff, 0x222222ff, 0x222222ff, 0x222222ff, +0x222222ff, 0x222222ff, 0x222222ff, 0x222222ff, 0x222222ff, 0x222222ff, 0x222222ff, 0x222222ff, 0x222222ff, 0x222222ff, 0x222222ff, 0x222222ff, 0x222222ff, 0x222222ff, 0x222222ff, 0x222222ff, 0x222222ff, 0x222222ff, 0x222222ff, 0x222222ff, 0x222222ff, 0x222222ff, 0x212122ff, 0x212122ff, 0x212122ff, 0x212122ff, 0x212122ff, 0x212122ff, 0x212122ff, 0x212122ff, 0x212122ff, 0x222222ff, +0x212122ff, 0x212121ff, 0x212121ff, 0x212121ff, 0x212121ff, 0x212121ff, 0x212121ff, 0x212121ff, 0x212121ff, 0x212121ff, 0x212121ff, 0x222220ff, 0x222220ff, 0x222220ff, 0x222220ff, 0x222220ff, 0x222220ff, 0x222220ff, 0x222220ff, 0x21211fff, 0x1f1f1eff, 0x1e1e1cff, 0x1e1e1dff, 0x1e1e1dff, 0x1e1e1dff, 0x1e1e1dff, 0x1e1e1dff, 0x1e1e1dff, 0x1e1e1dff, 0x1e1e1dff, 0x1e1e1dff, 0x1e1e1dff, +0x1f1f1bff, 0x232319ff, 0x242416ff, 0x242416ff, 0x242416ff, 0x242416ff, 0x242416ff, 0x242416ff, 0x232315ff, 0x313125ff, 0x3d3d2eff, 0x3a3a2cff, 0x3a3a2cff, 0x3a3a2cff, 0x3a3a2cff, 0x3a3a2cff, 0x3a3a2cff, 0x3a3a2cff, 0x3a3a2cff, 0x3a3a2cff, 0x3a3a2cff, 0x3b3b2cff, 0x39392eff, 0x1b1b54ff, 0x0a0a68ff, 0x0f0f63ff, 0x101066ff, 0x080858ff, 0x00006eff, 0x0000a4ff, 0x00009aff, 0x000098ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, +0x000098ff, 0x000098ff, 0x00009dff, 0x0000a4ff, 0x0000a4ff, 0x0000a4ff, 0x0000a4ff, 0x0000a3ff, 0x0000a6ff, 0x00009dff, 0x0f0f7cff, 0x14146dff, 0x12126fff, 0x12126fff, 0x131371ff, 0x171775ff, 0x1b1b77ff, 0x1b1b77ff, 0x1b1b77ff, 0x1b1b77ff, 0x1b1b77ff, 0x1a1a77ff, 0x1d1d75ff, 0x121280ff, 0x00009dff, 0x0000a5ff, 0x0000a2ff, 0x0000a3ff, 0x0000a3ff, 0x0000a3ff, 0x0000a3ff, 0x0000a3ff, +0x0000a3ff, 0x0000a3ff, 0x0000a3ff, 0x0000a3ff, 0x0000a3ff, 0x0000a3ff, 0x0000a3ff, 0x0000a3ff, 0x0000a3ff, 0x0000a3ff, 0x0000a3ff, 0x0000a3ff, 0x0000a3ff, 0x0000a3ff, 0x0000a1ff, 0x00009aff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000098ff, 0x000098ff, 0x000098ff, 0x0000a0ff, 0x00009bff, 0x050578ff, 0x181873ff, 0x353582ff, 0x87878fff, 0xb9b9aeff, 0xddddd9ff, 0xf4f4f0ff, 0xe7e7e3ff, 0xe5e5e4ff, 0xe4e4e5ff, 0xe4e4e4ff, 0xd4d4d5ff, 0xc9c9c9ff, 0xcacacaff, 0xc9c9c9ff, 0xcacacaff, 0xcbcbcbff, 0xcbcbcbff, 0xc7c7c7ff, 0xcececeff, 0xacacacff, 0x5d5d5dff, 0x444444ff, 0x2b2b2bff, 0x1d1d1dff, 0x222222ff, 0x212121ff, +0x212121ff, 0x212121ff, 0x212121ff, 0x212121ff, 0x212121ff, 0x212121ff, 0x212121ff, 0x222222ff, 0x222222ff, 0x222222ff, 0x212121ff, 0x212121ff, 0x222222ff, 0x222222ff, 0x222222ff, 0x222222ff, 0x222222ff, 0x222222ff, 0x222222ff, 0x222222ff, 0x222222ff, 0x222222ff, 0x222222ff, 0x222222ff, 0x222222ff, 0x222222ff, 0x222222ff, 0x222222ff, 0x222222ff, 0x222222ff, 0x222222ff, 0x222222ff, +0x212122ff, 0x212122ff, 0x212122ff, 0x212122ff, 0x212122ff, 0x212122ff, 0x212122ff, 0x212122ff, 0x222222ff, 0x212121ff, 0x212121ff, 0x212121ff, 0x212121ff, 0x212121ff, 0x212121ff, 0x212121ff, 0x212121ff, 0x212121ff, 0x212121ff, 0x212121ff, 0x202021ff, 0x212120ff, 0x22221fff, 0x22221fff, 0x22221fff, 0x22221fff, 0x22221fff, 0x22221fff, 0x22221fff, 0x22221fff, 0x22221fff, 0x22221fff, +0x21211dff, 0x21211dff, 0x21211dff, 0x21211dff, 0x21211dff, 0x21211dff, 0x21211dff, 0x21211dff, 0x21211dff, 0x21211dff, 0x22221dff, 0x22221dff, 0x23231cff, 0x23231cff, 0x23231cff, 0x23231cff, 0x23231cff, 0x23231cff, 0x22221bff, 0x25251eff, 0x34342dff, 0x393933ff, 0x393932ff, 0x393932ff, 0x393932ff, 0x393932ff, 0x393932ff, 0x393932ff, 0x393932ff, 0x393932ff, 0x393932ff, 0x3b3b2fff, +0x33333aff, 0x15155fff, 0x0b0b6cff, 0x0d0d69ff, 0x0d0d6aff, 0x0d0d6aff, 0x0d0d6aff, 0x0d0d6aff, 0x0b0b68ff, 0x171775ff, 0x20207dff, 0x1e1e7bff, 0x1f1f7bff, 0x1f1f7bff, 0x1f1f7bff, 0x1f1f7bff, 0x1f1f7bff, 0x1f1f7bff, 0x1f1f7bff, 0x1f1f7bff, 0x1f1f7bff, 0x1f1f7aff, 0x1e1e7cff, 0x08089aff, 0x0000aaff, 0x0000a6ff, 0x0000a6ff, 0x0000a9ff, 0x0000a3ff, 0x000099ff, 0x000098ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x00009aff, 0x00009fff, 0x0000a2ff, 0x0000a2ff, 0x0000a2ff, 0x0000a2ff, 0x0000a2ff, 0x0000a2ff, 0x0000a2ff, 0x0000a2ff, 0x0000a2ff, 0x0000a2ff, 0x0000a2ff, 0x0000a2ff, 0x00009fff, 0x00009aff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, +0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000098ff, 0x00009aff, 0x00009fff, 0x0000a1ff, 0x000094ff, 0x151581ff, 0x24248bff, 0x45458aff, 0x8c8c8eff, 0xb3b3b4ff, 0xdbdbdbff, 0xf8f8f1ff, 0xf1f1ecff, 0xe7e7e5ff, 0xe2e2e2ff, 0xe8e8e9ff, 0xe3e3e4ff, 0xd4d4d4ff, 0xcececeff, 0xcececeff, 0xcbcbcbff, 0xd3d3d3ff, 0xb6b6b6ff, 0x555555ff, 0x3c3c3cff, 0x2e2e2eff, 0x1d1d1dff, 0x222222ff, 0x212121ff, +0x212121ff, 0x222222ff, 0x232323ff, 0x232323ff, 0x232323ff, 0x232323ff, 0x222222ff, 0x222222ff, 0x222222ff, 0x222222ff, 0x222222ff, 0x222222ff, 0x212122ff, 0x212122ff, 0x212122ff, 0x212122ff, 0x212122ff, 0x212122ff, 0x212122ff, 0x212122ff, 0x212122ff, 0x202021ff, 0x202020ff, 0x202020ff, 0x202020ff, 0x202020ff, 0x202020ff, 0x202020ff, 0x202020ff, 0x202020ff, 0x202021ff, 0x22221fff, +0x23231dff, 0x23231dff, 0x23231dff, 0x23231dff, 0x23231dff, 0x23231dff, 0x23231dff, 0x23231eff, 0x22221dff, 0x22221dff, 0x23231eff, 0x23231eff, 0x23231eff, 0x23231eff, 0x23231eff, 0x23231eff, 0x23231eff, 0x23231eff, 0x23231eff, 0x23231eff, 0x24241dff, 0x23231fff, 0x202022ff, 0x212122ff, 0x212122ff, 0x212122ff, 0x212122ff, 0x212122ff, 0x212122ff, 0x212122ff, 0x212122ff, 0x1f1f1fff, +0x292929ff, 0x373738ff, 0x373738ff, 0x373738ff, 0x373738ff, 0x373738ff, 0x373738ff, 0x373738ff, 0x373738ff, 0x3a3a34ff, 0x2c2c46ff, 0x0e0e6bff, 0x0a0a72ff, 0x0c0c6fff, 0x0c0c6fff, 0x0c0c6fff, 0x0c0c6fff, 0x0c0c6fff, 0x0a0a6fff, 0x0c0c71ff, 0x18187bff, 0x1c1c7fff, 0x1b1b7fff, 0x1b1b7fff, 0x1b1b7fff, 0x1b1b7fff, 0x1b1b7fff, 0x1b1b7fff, 0x1b1b7fff, 0x1b1b7fff, 0x1b1b7fff, 0x1d1d7dff, +0x171783ff, 0x04049eff, 0x0000a7ff, 0x0000a5ff, 0x0000a5ff, 0x0000a5ff, 0x0000a5ff, 0x0000a5ff, 0x0000a5ff, 0x0000a3ff, 0x0000a1ff, 0x0000a1ff, 0x0000a1ff, 0x0000a1ff, 0x0000a1ff, 0x0000a1ff, 0x0000a1ff, 0x0000a1ff, 0x0000a1ff, 0x0000a1ff, 0x0000a1ff, 0x0000a2ff, 0x0000a0ff, 0x00009aff, 0x000097ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000099ff, 0x00009dff, 0x00009dff, 0x000088ff, 0x0d0d77ff, 0x212191ff, 0x4d4d8aff, 0x7a7a76ff, 0x6e6e79ff, 0x797977ff, 0xacaca3ff, 0xd7d7d1ff, 0xe5e5deff, 0xe0e0dbff, 0xdcdcdbff, 0xe5e5e6ff, 0xdfdfe0ff, 0xd8d8d9ff, 0xbababbff, 0x595959ff, 0x3a3a3aff, 0x2c2c2dff, 0x202021ff, 0x232324ff, 0x232323ff, +0x242424ff, 0x222223ff, 0x1e1e1fff, 0x1d1d1dff, 0x1c1c1dff, 0x1b1b1cff, 0x1e1e1fff, 0x202021ff, 0x212121ff, 0x22221dff, 0x202019ff, 0x22221bff, 0x23231cff, 0x23231cff, 0x23231cff, 0x23231cff, 0x23231cff, 0x23231cff, 0x23231cff, 0x23231cff, 0x23231cff, 0x25251eff, 0x26261fff, 0x26261fff, 0x26261fff, 0x26261fff, 0x26261fff, 0x26261fff, 0x26261fff, 0x26261fff, 0x27271eff, 0x222225ff, +0x1e1e29ff, 0x202027ff, 0x1f1f27ff, 0x1f1f27ff, 0x1f1f27ff, 0x1f1f27ff, 0x1f1f27ff, 0x202028ff, 0x1d1d25ff, 0x292932ff, 0x37373fff, 0x35353eff, 0x35353eff, 0x35353eff, 0x35353eff, 0x35353eff, 0x35353eff, 0x35353eff, 0x35353eff, 0x35353eff, 0x3a3a38ff, 0x232354ff, 0x06067aff, 0x0a0a75ff, 0x0a0a75ff, 0x0a0a75ff, 0x0a0a75ff, 0x0a0a75ff, 0x0a0a75ff, 0x0a0a75ff, 0x0a0a75ff, 0x090974ff, +0x0e0e7aff, 0x181883ff, 0x181883ff, 0x181882ff, 0x181882ff, 0x181882ff, 0x181882ff, 0x181882ff, 0x181883ff, 0x1a1a7fff, 0x11118aff, 0x0000a2ff, 0x0000a5ff, 0x0000a4ff, 0x0000a4ff, 0x0000a4ff, 0x0000a4ff, 0x0000a4ff, 0x0000a4ff, 0x0000a4ff, 0x0000a2ff, 0x0000a0ff, 0x0000a1ff, 0x0000a1ff, 0x0000a1ff, 0x0000a1ff, 0x0000a1ff, 0x0000a1ff, 0x0000a1ff, 0x0000a1ff, 0x0000a1ff, 0x0000a1ff, +0x00009fff, 0x00009aff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000098ff, 0x000098ff, 0x00009bff, 0x00009eff, 0x00009dff, 0x000087ff, 0x050571ff, 0x010174ff, 0x1d1d51ff, 0x494951ff, 0x5a5a6cff, 0x626273ff, 0x6e6e79ff, 0x898982ff, 0xafafa5ff, 0xc8c8bfff, 0xc7c7bfff, 0xacaca3ff, 0x616159ff, 0x222219ff, 0x12120dff, 0x1f1f16ff, 0x1e1e15ff, 0x1e1e15ff, +0x1f1f17ff, 0x1a1a11ff, 0x0d0d05ff, 0x0e0e05ff, 0x12120aff, 0x0f0f07ff, 0x1f1f17ff, 0x2a2a22ff, 0x25251cff, 0x1d1d25ff, 0x0f0f21ff, 0x171726ff, 0x1f1f2eff, 0x1e1e2dff, 0x1e1e2dff, 0x1e1e2dff, 0x1e1e2dff, 0x1e1e2dff, 0x1e1e2dff, 0x1e1e2dff, 0x1d1d2dff, 0x2c2c3dff, 0x363645ff, 0x343443ff, 0x343443ff, 0x343443ff, 0x343443ff, 0x343443ff, 0x343443ff, 0x343443ff, 0x38383eff, 0x1a1a63ff, +0x050580ff, 0x09097bff, 0x09097bff, 0x09097bff, 0x09097bff, 0x09097bff, 0x09097bff, 0x09097bff, 0x06067aff, 0x0e0e80ff, 0x161687ff, 0x151586ff, 0x151586ff, 0x151586ff, 0x151586ff, 0x151586ff, 0x151586ff, 0x151586ff, 0x151586ff, 0x151586ff, 0x181883ff, 0x0b0b91ff, 0x0000a6ff, 0x0000a3ff, 0x0000a3ff, 0x0000a3ff, 0x0000a3ff, 0x0000a3ff, 0x0000a3ff, 0x0000a3ff, 0x0000a3ff, 0x0000a3ff, +0x0000a1ff, 0x0000a0ff, 0x0000a0ff, 0x0000a0ff, 0x0000a0ff, 0x0000a0ff, 0x0000a0ff, 0x0000a0ff, 0x0000a0ff, 0x0000a0ff, 0x00009dff, 0x000099ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, +0x000098ff, 0x000098ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x00009cff, 0x0000a0ff, 0x0000a0ff, 0x070790ff, 0x0b0b80ff, 0x04047dff, 0x00007dff, 0x0b0b70ff, 0x2f2f52ff, 0x444459ff, 0x515169ff, 0x56566dff, 0x4c4c64ff, 0x4f4f67ff, 0x1c1c33ff, 0x000015ff, 0x09091eff, 0x07071dff, 0x07071dff, +0x07071cff, 0x0a0a20ff, 0x101027ff, 0x1a1a32ff, 0x292940ff, 0x28283fff, 0x2e2e46ff, 0x34344aff, 0x23233cff, 0x0a0a67ff, 0x000081ff, 0x04047eff, 0x080881ff, 0x070781ff, 0x070781ff, 0x070781ff, 0x070781ff, 0x070781ff, 0x070781ff, 0x070781ff, 0x060681ff, 0x0e0e88ff, 0x13138bff, 0x12128aff, 0x12128aff, 0x12128aff, 0x12128aff, 0x12128aff, 0x12128aff, 0x12128aff, 0x141487ff, 0x060697ff, +0x0000a4ff, 0x0000a1ff, 0x0000a1ff, 0x0000a1ff, 0x0000a1ff, 0x0000a1ff, 0x0000a1ff, 0x0000a1ff, 0x0000a2ff, 0x0000a0ff, 0x00009fff, 0x00009fff, 0x00009fff, 0x00009fff, 0x00009fff, 0x00009fff, 0x00009fff, 0x00009fff, 0x00009fff, 0x00009fff, 0x00009fff, 0x00009bff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, +0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x00009cff, 0x00009eff, 0x00009eff, 0x0000a0ff, 0x00009aff, 0x08088bff, 0x070786ff, 0x030383ff, 0x030383ff, 0x040484ff, 0x111190ff, 0x090989ff, 0x00007dff, 0x00007fff, 0x00007fff, 0x00007fff, +0x00007eff, 0x010181ff, 0x070787ff, 0x0b0b8cff, 0x111190ff, 0x111190ff, 0x0f0f8fff, 0x0f0f8dff, 0x080889ff, 0x000098ff, 0x0000a4ff, 0x0000a1ff, 0x0000a0ff, 0x0000a0ff, 0x0000a0ff, 0x0000a0ff, 0x0000a0ff, 0x0000a0ff, 0x0000a0ff, 0x0000a0ff, 0x0000a0ff, 0x00009fff, 0x00009eff, 0x00009eff, 0x00009eff, 0x00009eff, 0x00009eff, 0x00009eff, 0x00009eff, 0x00009eff, 0x00009eff, 0x00009aff, +0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000099ff, 0x00009cff, 0x00009dff, 0x00009dff, 0x00009dff, 0x00009dff, 0x00009cff, 0x00009eff, 0x0000a1ff, 0x0000a1ff, 0x0000a1ff, 0x0000a1ff, +0x0000a1ff, 0x0000a0ff, 0x00009fff, 0x00009eff, 0x00009dff, 0x00009dff, 0x00009dff, 0x00009dff, 0x00009dff, 0x00009aff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, +0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000098ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, +0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff, 0x000099ff +}; diff --git a/src/joystick_driver.c b/src/joystick_driver.c index 754760b..5b90a46 100644 --- a/src/joystick_driver.c +++ b/src/joystick_driver.c @@ -1,6 +1,7 @@ /* GSport - an Apple //gs Emulator - Copyright (C) 2010 - 2013 by GSport contributors + Copyright (C) 2010 - 2019 by GSport contributors + Copyright (C) 2016 - 2018 Dagen Brock Based on the KEGS emulator written by and Copyright (C) 2003 Kent Dickey @@ -20,6 +21,7 @@ */ #include "defc.h" +#include "glog.h" #ifdef __linux__ # include @@ -32,251 +34,331 @@ # include #endif -extern int g_joystick_native_type1; /* in paddles.c */ -extern int g_joystick_native_type2; /* in paddles.c */ -extern int g_joystick_native_type; /* in paddles.c */ +#ifdef HAVE_SDL +# include "SDL.h" +//@todo: multiple joysticks/more buttons/button config +//static SDL_Joystick *joy0, *joy1; +SDL_Joystick *gGameController = NULL; +#endif + + + +extern int g_joystick_native_type1; /* in paddles.c */ +extern int g_joystick_native_type2; /* in paddles.c */ +extern int g_joystick_native_type; /* in paddles.c */ +extern int g_joystick_type; extern int g_paddle_buttons; extern int g_paddle_val[]; -const char *g_joystick_dev = "/dev/input/js0"; /* default joystick dev file */ -#define MAX_JOY_NAME 128 +const char *g_joystick_dev = "/dev/input/js0"; /* default joystick dev file */ +#define MAX_JOY_NAME 128 -int g_joystick_native_fd = -1; -int g_joystick_num_axes = 0; -int g_joystick_num_buttons = 0; +int g_joystick_native_fd = -1; +int g_joystick_num_axes = 0; +int g_joystick_num_buttons = 0; +int g_joystick_number = 0; // SDL2 +int g_joystick_x_axis = 0; // SDL2 +int g_joystick_y_axis = 1; // SDL2 +int g_joystick_button_0 = 0; // SDL2 +int g_joystick_button_1 = 1; // SDL2 + +int g_joystick_x2_axis = 2; // SDL2 +int g_joystick_y2_axis = 3; // SDL2 +int g_joystick_button_2 = 2; // SDL2 +int g_joystick_button_3 = 3; // SDL2 +#define JOY2SUPPORT -#ifdef __linux__ +#if defined(HAVE_SDL) && !defined(JOYSTICK_DEFINED) # define JOYSTICK_DEFINED -void -joystick_init() -{ - char joy_name[MAX_JOY_NAME]; - int version; - int fd; - int i; +void joystick_init() { + int i; + if( SDL_Init( SDL_INIT_JOYSTICK ) < 0 ) { + glogf( "SDL could not initialize joystick! SDL Error: %s", SDL_GetError() ); + } else { + glog("SDL2 joystick initialized"); + } + if (SDL_NumJoysticks()<1) { + glog("No joysticks detected"); + SDL_QuitSubSystem(SDL_INIT_JOYSTICK); + } else { + // @todo: make controller configurable + // @todo: add multiple controller support + gGameController = SDL_JoystickOpen( g_joystick_number ); + if( gGameController == NULL ) { + glogf( "Warning: Unable to open game controller! SDL Error: %s", SDL_GetError() ); + } + } + g_joystick_native_type = 2; + g_joystick_native_type1 = 2; + g_joystick_native_type2 = -1; + for(i = 0; i < 4; i++) { + g_paddle_val[i] = 180; + } + g_joystick_type = JOYSTICK_TYPE_NATIVE_1; + SDL_JoystickUpdate(); + joystick_update(0.0); +} - fd = open(g_joystick_dev, O_RDONLY | O_NONBLOCK); - if(fd < 0) { - printf("Unable to open joystick dev file: %s, errno: %d\n", - g_joystick_dev, errno); - printf("Defaulting to mouse joystick\n"); - return; - } +void joystick_update(double dcycs) { + if (gGameController) { + SDL_JoystickUpdate(); + g_paddle_val[0] = (int)SDL_JoystickGetAxis(gGameController, g_joystick_x_axis); // default is 0 + g_paddle_val[1] = (int)SDL_JoystickGetAxis(gGameController, g_joystick_y_axis); // default is 1 + g_paddle_val[2] = (int)SDL_JoystickGetAxis(gGameController, g_joystick_x2_axis); // default is 2 + g_paddle_val[3] = (int)SDL_JoystickGetAxis(gGameController, g_joystick_y2_axis); // default is 3 - strcpy(&joy_name[0], "Unknown Joystick"); - version = 0x800; + if (SDL_JoystickGetButton(gGameController, g_joystick_button_0)) { + g_paddle_buttons = g_paddle_buttons | 1; + } else { + g_paddle_buttons = g_paddle_buttons & (~1); + } + if (SDL_JoystickGetButton(gGameController, g_joystick_button_1)) { + g_paddle_buttons = g_paddle_buttons | 2; + } else { + g_paddle_buttons = g_paddle_buttons & (~2); + } + if (SDL_JoystickGetButton(gGameController, g_joystick_button_2)) { + g_paddle_buttons = g_paddle_buttons | 4; + } else { + g_paddle_buttons = g_paddle_buttons & (~4); + } + if (SDL_JoystickGetButton(gGameController, g_joystick_button_3)) { + g_paddle_buttons = g_paddle_buttons | 8; + } else { + g_paddle_buttons = g_paddle_buttons & (~8); + } + paddle_update_trigger_dcycs(dcycs); + } +} - ioctl(fd, JSIOCGNAME(MAX_JOY_NAME), &joy_name[0]); - ioctl(fd, JSIOCGAXES, &g_joystick_num_axes); - ioctl(fd, JSIOCGBUTTONS, &g_joystick_num_buttons); - ioctl(fd, JSIOCGVERSION, &version); +void joystick_update_buttons() { +} - printf("Detected joystick: %s [%d axes, %d buttons vers: %08x]\n", - joy_name, g_joystick_num_axes, g_joystick_num_buttons, - version); +void joystick_shut() { + SDL_JoystickClose( gGameController ); + gGameController = NULL; +} +#endif - g_joystick_native_type1 = 1; - g_joystick_native_type2 = -1; - g_joystick_native_fd = fd; - for(i = 0; i < 4; i++) { - g_paddle_val[i] = 32767; - } - g_paddle_buttons = 0xc; - joystick_update(0.0); + + + +#if defined(__linux__) && !defined(JOYSTICK_DEFINED) +# define JOYSTICK_DEFINED +void joystick_init() { + char joy_name[MAX_JOY_NAME]; + int version; + int fd; + int i; + + fd = open(g_joystick_dev, O_RDONLY | O_NONBLOCK); + if(fd < 0) { + printf("Unable to open joystick dev file: %s, errno: %d\n", + g_joystick_dev, errno); + printf("Defaulting to mouse joystick\n"); + return; + } + + strcpy(&joy_name[0], "Unknown Joystick"); + version = 0x800; + + ioctl(fd, JSIOCGNAME(MAX_JOY_NAME), &joy_name[0]); + ioctl(fd, JSIOCGAXES, &g_joystick_num_axes); + ioctl(fd, JSIOCGBUTTONS, &g_joystick_num_buttons); + ioctl(fd, JSIOCGVERSION, &version); + + printf("Detected joystick: %s [%d axes, %d buttons vers: %08x]\n", + joy_name, g_joystick_num_axes, g_joystick_num_buttons, + version); + + g_joystick_native_type1 = 1; + g_joystick_native_type2 = -1; + g_joystick_native_fd = fd; + for(i = 0; i < 4; i++) { + g_paddle_val[i] = 32767; + } + g_paddle_buttons = 0xc; + + joystick_update(0.0); } /* joystick_update_linux() called from paddles.c. Update g_paddle_val[] */ /* and g_paddle_buttons with current information */ -void -joystick_update(double dcycs) -{ - struct js_event js; /* the linux joystick event record */ - int mask; - int val; - int num; - int type; - int ret; - int len; - int i; +void joystick_update(double dcycs) { + struct js_event js; /* the linux joystick event record */ + int mask; + int val; + int num; + int type; + int ret; + int len; + int i; - /* suck up to 20 events, then give up */ - len = sizeof(struct js_event); - for(i = 0; i < 20; i++) { - ret = read(g_joystick_native_fd, &js, len); - if(ret != len) { - /* just get out */ - break; - } - type = js.type & ~JS_EVENT_INIT; - val = js.value; - num = js.number & 3; /* clamp to 0-3 */ - switch(type) { - case JS_EVENT_BUTTON: - mask = 1 << num; - if(val) { - val = mask; - } - g_paddle_buttons = (g_paddle_buttons & ~mask) | val; - break; - case JS_EVENT_AXIS: - /* val is -32767 to +32767 */ - g_paddle_val[num] = val; - break; - } - } + /* suck up to 20 events, then give up */ + len = sizeof(struct js_event); + for(i = 0; i < 20; i++) { + ret = read(g_joystick_native_fd, &js, len); + if(ret != len) { + /* just get out */ + break; + } + type = js.type & ~JS_EVENT_INIT; + val = js.value; + num = js.number & 3; /* clamp to 0-3 */ + switch(type) { + case JS_EVENT_BUTTON: + mask = 1 << num; + if(val) { + val = mask; + } + g_paddle_buttons = (g_paddle_buttons & ~mask) | val; + break; + case JS_EVENT_AXIS: + /* val is -32767 to +32767 */ + g_paddle_val[num] = val; + break; + } + } // if(i > 0) { // Note from Dave Schmenk: paddle_update_trigger_dcycles(dcycs) always has to be called to keep the triggers current. - paddle_update_trigger_dcycs(dcycs); + paddle_update_trigger_dcycs(dcycs); // } } -void -joystick_update_buttons() -{ +void joystick_update_buttons() { } #endif /* LINUX */ -#ifdef _WIN32 +#if defined(_WIN32) && !defined(JOYSTICK_DEFINED) # define JOYSTICK_DEFINED -void -joystick_init() -{ - JOYINFO info; - JOYCAPS joycap; - MMRESULT ret1, ret2; - int i; +void joystick_init() { + JOYINFO info; + JOYCAPS joycap; + MMRESULT ret1, ret2; + int i; - // Check that there is a joystick device - if(joyGetNumDevs() <= 0) { - printf("No joystick hardware detected\n"); - g_joystick_native_type1 = -1; - g_joystick_native_type2 = -1; - return; - } + // Check that there is a joystick device + if(joyGetNumDevs() <= 0) { + glog("No joystick hardware detected"); + g_joystick_native_type1 = -1; + g_joystick_native_type2 = -1; + return; + } - g_joystick_native_type1 = -1; - g_joystick_native_type2 = -1; + g_joystick_native_type1 = -1; + g_joystick_native_type2 = -1; - // Check that at least joystick 1 or joystick 2 is available - ret1 = joyGetPos(JOYSTICKID1, &info); - ret2 = joyGetDevCaps(JOYSTICKID1, &joycap, sizeof(joycap)); - if(ret1 == JOYERR_NOERROR && ret2 == JOYERR_NOERROR) { - g_joystick_native_type1 = JOYSTICKID1; - printf("Joystick #1 = %s\n", joycap.szPname); - g_joystick_native_type = JOYSTICKID1; - } - ret1 = joyGetPos(JOYSTICKID2, &info); - ret2 = joyGetDevCaps(JOYSTICKID2, &joycap, sizeof(joycap)); - if(ret1 == JOYERR_NOERROR && ret2 == JOYERR_NOERROR) { - g_joystick_native_type2 = JOYSTICKID2; - printf("Joystick #2 = %s\n", joycap.szPname); - if(g_joystick_native_type < 0) { - g_joystick_native_type = JOYSTICKID2; - } - } + // Check that at least joystick 1 or joystick 2 is available + ret1 = joyGetPos(JOYSTICKID1, &info); + ret2 = joyGetDevCaps(JOYSTICKID1, &joycap, sizeof(joycap)); + if(ret1 == JOYERR_NOERROR && ret2 == JOYERR_NOERROR) { + g_joystick_native_type1 = JOYSTICKID1; + printf("Joystick #1 = %s\n", joycap.szPname); + g_joystick_native_type = JOYSTICKID1; + } + ret1 = joyGetPos(JOYSTICKID2, &info); + ret2 = joyGetDevCaps(JOYSTICKID2, &joycap, sizeof(joycap)); + if(ret1 == JOYERR_NOERROR && ret2 == JOYERR_NOERROR) { + g_joystick_native_type2 = JOYSTICKID2; + printf("Joystick #2 = %s\n", joycap.szPname); + if(g_joystick_native_type < 0) { + g_joystick_native_type = JOYSTICKID2; + } + } - if (g_joystick_native_type1<0 && g_joystick_native_type2 <0) { - printf ("No joystick is attached\n"); - return; - } + if (g_joystick_native_type1<0 && g_joystick_native_type2 <0) { + glog("No joystick is attached"); + return; + } - for(i = 0; i < 4; i++) { - g_paddle_val[i] = 32767; - } - g_paddle_buttons = 0xc; + for(i = 0; i < 4; i++) { + g_paddle_val[i] = 32767; + } + g_paddle_buttons = 0xc; - joystick_update(0.0); + joystick_update(0.0); } -void -joystick_update(double dcycs) -{ - JOYCAPS joycap; - JOYINFO info; - UINT id; - MMRESULT ret1, ret2; +void joystick_update(double dcycs) { + JOYCAPS joycap; + JOYINFO info; + UINT id; + MMRESULT ret1, ret2; - id = g_joystick_native_type; + id = g_joystick_native_type; - ret1 = joyGetDevCaps(id, &joycap, sizeof(joycap)); - ret2 = joyGetPos(id, &info); - if(ret1 == JOYERR_NOERROR && ret2 == JOYERR_NOERROR) { - /* val should be -32767 to +32767 */ - g_paddle_val[0] = -32767 + (info.wXpos - joycap.wXmin) * 65535 / - (joycap.wXmax - joycap.wXmin); - g_paddle_val[1] = -32767 + (info.wYpos - joycap.wYmin) * 65535 / - (joycap.wYmax - joycap.wYmin); - if(info.wButtons & JOY_BUTTON1) { - g_paddle_buttons = g_paddle_buttons | 1; - } else { - g_paddle_buttons = g_paddle_buttons & (~1); - } - if(info.wButtons & JOY_BUTTON2) { - g_paddle_buttons = g_paddle_buttons | 2; - } else { - g_paddle_buttons = g_paddle_buttons & (~2); - } - paddle_update_trigger_dcycs(dcycs); - } + ret1 = joyGetDevCaps(id, &joycap, sizeof(joycap)); + ret2 = joyGetPos(id, &info); + if(ret1 == JOYERR_NOERROR && ret2 == JOYERR_NOERROR) { + g_paddle_val[0] = (info.wXpos - joycap.wXmin) * 32768 / + (joycap.wXmax - joycap.wXmin); + g_paddle_val[1] = (info.wYpos - joycap.wYmin) * 32768 / + (joycap.wYmax - joycap.wYmin); + if(info.wButtons & JOY_BUTTON1) { + g_paddle_buttons = g_paddle_buttons | 1; + } else { + g_paddle_buttons = g_paddle_buttons & (~1); + } + if(info.wButtons & JOY_BUTTON2) { + g_paddle_buttons = g_paddle_buttons | 2; + } else { + g_paddle_buttons = g_paddle_buttons & (~2); + } + paddle_update_trigger_dcycs(dcycs); + } } -void -joystick_update_buttons() -{ - JOYINFOEX info; - UINT id; +void joystick_update_buttons() { + JOYINFOEX info; + UINT id; - id = g_joystick_native_type; + id = g_joystick_native_type; - info.dwSize = sizeof(JOYINFOEX); - info.dwFlags = JOY_RETURNBUTTONS; - if(joyGetPosEx(id, &info) == JOYERR_NOERROR) { - if(info.dwButtons & JOY_BUTTON1) { - g_paddle_buttons = g_paddle_buttons | 1; - } else { - g_paddle_buttons = g_paddle_buttons & (~1); - } - if(info.dwButtons & JOY_BUTTON2) { - g_paddle_buttons = g_paddle_buttons | 2; - } else { - g_paddle_buttons = g_paddle_buttons & (~2); - } - } + info.dwSize = sizeof(JOYINFOEX); + info.dwFlags = JOY_RETURNBUTTONS; + if(joyGetPosEx(id, &info) == JOYERR_NOERROR) { + if(info.dwButtons & JOY_BUTTON1) { + g_paddle_buttons = g_paddle_buttons | 1; + } else { + g_paddle_buttons = g_paddle_buttons & (~1); + } + if(info.dwButtons & JOY_BUTTON2) { + g_paddle_buttons = g_paddle_buttons | 2; + } else { + g_paddle_buttons = g_paddle_buttons & (~2); + } + } } #endif + + + + #ifndef JOYSTICK_DEFINED /* stubs for the routines */ -void -joystick_init() -{ - g_joystick_native_type1 = -1; - g_joystick_native_type2 = -1; - g_joystick_native_type = -1; +void joystick_init() { + g_joystick_native_type1 = -1; + g_joystick_native_type2 = -1; + g_joystick_native_type = -1; } -void -joystick_update(double dcycs) -{ - int i; +void joystick_update(double dcycs) { + int i; - for(i = 0; i < 4; i++) { - g_paddle_val[i] = 32767; - } - g_paddle_buttons = 0xc; + for(i = 0; i < 4; i++) { + g_paddle_val[i] = 32767; + } + g_paddle_buttons = 0xc; } -void -joystick_update_buttons() -{ +void joystick_update_buttons() { } -// OG -void joystick_shut() -{ +void joystick_shut() { } #endif diff --git a/src/macdriver_console.c b/src/macdriver_console.c deleted file mode 100755 index 0de0d63..0000000 --- a/src/macdriver_console.c +++ /dev/null @@ -1,860 +0,0 @@ -/* - GSport - an Apple //gs Emulator - Copyright (C) 2010 - 2012 by GSport contributors - - Based on the KEGS emulator written by and Copyright (C) 2003 Kent Dickey - - This program is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by the - Free Software Foundation; either version 2 of the License, or (at your - option) any later version. - - This program is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - for more details. - - You should have received a copy of the GNU General Public License along - with this program; if not, write to the Free Software Foundation, Inc., - 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ - -#ifdef ACTIVEIPHONE -#include -#include -#include -#else -#include -#include -#include -#define ENABLEQD -#endif - -#include "defc.h" -#include "protos_macdriver.h" - -pascal OSStatus quit_event_handler(EventHandlerCallRef call_ref, EventRef event, void *ignore); -pascal OSStatus my_cmd_handler(EventHandlerCallRef handlerRef, EventRef event, void *userdata); -pascal OSStatus my_win_handler(EventHandlerCallRef handlerRef, EventRef event, void *userdata); -pascal OSStatus dummy_event_handler(EventHandlerCallRef call_ref, EventRef in_event, void *ignore); - - -int g_quit_seen = 0; - -#define MAX_STATUS_LINES 7 -#define X_LINE_LENGTH 88 -#define MAX_MAC_ARGS 128 - -int g_mac_argc = 0; -char *g_mac_argv[MAX_MAC_ARGS]; - -extern char g_argv0_path[]; -extern char *g_status_ptrs[MAX_STATUS_LINES]; -extern const char g_gsport_version_str[]; - -extern int g_warp_pointer; - -extern WindowRef g_main_window; -WindowRef g_main_window_saved; -EventHandlerUPP g_quit_handler_UPP; -EventHandlerUPP g_dummy_event_handler_UPP; -RgnHandle g_event_rgnhandle = 0; -FMFontFamily g_status_font_family; - - -extern word32 g_red_mask; -extern word32 g_green_mask; -extern word32 g_blue_mask; -extern int g_red_left_shift; -extern int g_green_left_shift; -extern int g_blue_left_shift; -extern int g_red_right_shift; -extern int g_green_right_shift; -extern int g_blue_right_shift; - - -int g_ignore_next_click = 0; - -int g_mainwin_active = 0; -int g_mac_mouse_x = 0; -int g_mac_mouse_y = 0; - -extern int g_video_act_width; -extern int g_video_act_height; -extern int g_video_act_margin_left; -extern int g_video_act_margin_right; -extern int g_video_act_margin_top; -extern int g_video_act_margin_bottom; -extern int g_screen_depth; -extern int g_force_depth; - -extern int g_screen_mdepth; - -Ptr g_mac_fullscreen_state = 0; -Rect g_main_window_saved_rect; - -extern char *g_fatal_log_strs[]; -extern int g_fatal_log; - -int -x_show_alert(int is_fatal, const char *str) -{ - DialogRef alert; - DialogItemIndex out_item_hit; - CFStringRef cfstrref, cfstrref2; - CFStringRef okstrref; - AlertStdCFStringAlertParamRec alert_param; - OSStatus osstat; - char *bufptr, *buf2ptr; - int sum, len; - int i; - - /* The dialog eats all events--including key-up events */ - /* Call adb_all_keys_up() to prevent annoying key-repeat problems */ - /* for instance, a key-down causes a dialog to appear--and the */ - /* eats the key-up event...then as soon as the dialog goes, adb.c */ - /* auto-repeat will repeat the key, and the dialog re-appears...*/ - adb_all_keys_up(); - - sum = 20; - for(i = 0; i < g_fatal_log; i++) { - sum += strlen(g_fatal_log_strs[i]); - } - bufptr = (char*)malloc(sum); - buf2ptr = bufptr; - for(i = 0; i < g_fatal_log; i++) { - len = strlen(g_fatal_log_strs[i]); - len = MIN(len, sum); - len = MAX(len, 0); - memcpy(bufptr, g_fatal_log_strs[i], MIN(len, sum)); - bufptr += len; - bufptr[0] = 0; - sum = sum - len; - } - - cfstrref = CFStringCreateWithCString(NULL, buf2ptr, - kCFStringEncodingMacRoman); - - printf("buf2ptr: :%s:\n", buf2ptr); - - osstat = GetStandardAlertDefaultParams(&alert_param, - kStdCFStringAlertVersionOne); - - if(str) { - // Provide an extra option--create a file - cfstrref2 = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, - CFSTR("Create ./%s"), str); - alert_param.otherText = cfstrref2; - } - okstrref = CFSTR("Click OK to continue"); - if(is_fatal) { - okstrref = CFSTR("Click OK to exit GSport"); - } - CreateStandardAlert(kAlertStopAlert, cfstrref, okstrref, - &alert_param, &alert); - out_item_hit = -1; - RunStandardAlert(alert, NULL, &out_item_hit); - printf("out_item_hit: %d\n", out_item_hit); - free(buf2ptr); - - clear_fatal_logs(); /* free the fatal_log string memory */ - return (out_item_hit >= 3); - -} - - - -pascal OSStatus -quit_event_handler(EventHandlerCallRef call_ref, EventRef event, void *ignore) -{ - OSStatus err; - - err = CallNextEventHandler(call_ref, event); - if(err == noErr) { - g_quit_seen = 1; - } - return err; -} - -void -show_simple_alert(char *str1, char *str2, char *str3, int num) -{ - char buf[256]; - - g_fatal_log_strs[0] = gsport_malloc_str(str1); - g_fatal_log_strs[1] = gsport_malloc_str(str2); - g_fatal_log_strs[2] = gsport_malloc_str(str3); - g_fatal_log = 3; - if(num != 0) { - snprintf(buf, 250, ": %d", num); - g_fatal_log_strs[g_fatal_log++] = gsport_malloc_str(buf); - } - x_show_alert(0, 0); -} - -void -x_dialog_create_gsport_conf(const char *str) -{ - char *path; - char tmp_buf[512]; - int ret; - - ret = x_show_alert(1, str); - if(ret) { - config_write_config_gsport_file(); - } -} - - -pascal OSStatus -my_cmd_handler( EventHandlerCallRef handlerRef, EventRef event, void *userdata) -{ - OSStatus osresult; - HICommand command; - word32 command_id; - - osresult = eventNotHandledErr; - - GetEventParameter(event, kEventParamDirectObject, typeHICommand, NULL, - sizeof(HICommand), NULL, &command); - - command_id = (word32)command.commandID; - switch(command_id) { - case 'Kbep': - SysBeep(10); - osresult = noErr; - break; - case 'abou': - show_simple_alert("GSport v", (char *)g_gsport_version_str, - "\nCopyright 2010 - 2011 GSport Contributors\n" - "Latest version at http://gsport.sourceforge.net/\n", 0); - osresult = noErr; - break; - case 'KCFG': -#ifdef ACTIVEGS -#else - cfg_toggle_config_panel(); -#endif - osresult = noErr; - break; - case 'quit': - break; - case 'swin': - /* not sure what this is, but Panther sends it */ - break; - default: - printf("commandID %08x unknown\n", command_id); - SysBeep(90); - break; - } - return osresult; -} - - - -pascal OSStatus -my_win_handler(EventHandlerCallRef handlerRef, EventRef event, void *userdata) -{ - OSStatus os_result; - UInt32 event_kind; - - os_result = eventNotHandledErr; - - // SysBeep(1); - - event_kind = GetEventKind(event); - // show_alert("win handler", event_kind); - if(event_kind == kEventWindowDrawContent) - { - update_window(); - } if(event_kind == kEventWindowClose) { - - // OG Use HALT_WANTTOQUIT pardigme - //g_quit_sim_now = 1; - set_halt_act(HALT_WANTTOQUIT); - -#ifndef ACTIVEGS - g_quit_seen = 1; - my_exit(0); -#endif - } else { - //show_event(GetEventClass(event), event_kind, 0); - update_window(); - } - - return os_result; -} - - -pascal OSStatus -dummy_event_handler(EventHandlerCallRef call_ref, EventRef in_event, - void *ignore) -{ - OSStatus err; - EventHandlerRef installed_handler; - EventTypeSpec event_spec = { kEventClassApplication, kEventAppQuit }; - - // From http://developer.apple.com/qa/qa2001/qa1061.html - // Trick to move main event queue to use ReceiveNextEvent in an event - // handler called by RunApplicationEventLoop - - err = InstallApplicationEventHandler(g_quit_handler_UPP, 1, &event_spec, - NULL, &installed_handler); - - gsportmain(g_mac_argc, g_mac_argv); - - return noErr; -} - - - -void -check_input_events() -{ - OSStatus err; - EventTargetRef target; - EventRef event; - UInt32 event_class, event_kind; - byte mac_keycode; - UInt32 keycode; - UInt32 modifiers; - Point mouse_point, mouse_delta_point; - WindowRef window_ref; - int button, button_state; - EventMouseButton mouse_button; - int handled; - int mouse_events; - int is_up; - int in_win; - int ignore; - - if(g_quit_seen) { - exit(0); - } - - SetPortWindowPort(g_main_window); - - mouse_events = 0; - target = GetEventDispatcherTarget(); - while(1) { - err = ReceiveNextEvent(0, NULL, kEventDurationNoWait, - true, &event); - - if(err == eventLoopTimedOutErr) { - break; - } - if(err != noErr) { - printf("ReceiveNextEvent err: %d\n", (int)err); - break; - } - - event_class = GetEventClass(event); - event_kind = GetEventKind(event); - handled = 0; - switch(event_class) { - case kEventClassKeyboard: - handled = 1; - keycode = 0; - modifiers = 0; - GetEventParameter(event, kEventParamKeyMacCharCodes, - typeChar, NULL, sizeof(byte), NULL, - &mac_keycode); - GetEventParameter(event, kEventParamKeyCode, - typeUInt32, NULL, sizeof(UInt32), NULL, - &keycode); - GetEventParameter(event, kEventParamKeyModifiers, - typeUInt32, NULL, sizeof(UInt32), NULL, - &modifiers); - - mac_update_modifiers((word32)modifiers); - - // Key up/down event - is_up = -1; - switch(event_kind) { - case kEventRawKeyDown: - is_up = 0; - //printf("key down: %02x, %08x\n", - // (int)mac_keycode, (int)keycode); - break; - case kEventRawKeyUp: - is_up = 1; - //printf("key up: %02x, %08x\n", - // (int)mac_keycode, (int)keycode); - break; - case kEventRawKeyModifiersChanged: - is_up = -1; - //printf("key xxx: %08x\n", (int)modifiers); - break; - } - if(is_up >= 0) { - adb_physical_key_update((int)keycode, is_up); - } - break; - case kEventClassMouse: - handled = 2; - mouse_events++; - GetEventParameter(event, kEventParamMouseLocation, - typeQDPoint, NULL, sizeof(Point), NULL, - &mouse_point); - GetWindowRegion(g_main_window, kWindowContentRgn, - g_event_rgnhandle); - in_win = PtInRgn(mouse_point, g_event_rgnhandle); - // in_win = 1 if it was in the contect region of window - err = GetEventParameter(event, kEventParamMouseDelta, - typeQDPoint, NULL, sizeof(Point), NULL, - &mouse_delta_point); - button = 0; - button_state = -1; - switch(event_kind) { - case kEventMouseDown: - button_state = 7; - handled = 3; - break; - case kEventMouseUp: - button_state = 0; - handled = 3; - break; - } - if(button_state >= 0) { - GetEventParameter(event, kEventParamMouseButton, - typeMouseButton, NULL, - sizeof(EventMouseButton), NULL, - &mouse_button); - button = mouse_button; - if(button > 1) { - button = 4 - button; - button = 1 << button; - } - ignore = (button_state != 0) && - (!in_win || g_ignore_next_click); - ignore = ignore || !g_mainwin_active; - if(ignore) { - // Outside of A2 window, ignore clicks - button = 0; - } - if(button_state == 0) { - g_ignore_next_click = 0; - } - } - - GlobalToLocal(&mouse_point); - - if(g_warp_pointer) { - if(err == 0) { - g_mac_mouse_x += mouse_delta_point.h; - g_mac_mouse_y += mouse_delta_point.v; - } - mac_warp_mouse(); - } else { - g_mac_mouse_x = mouse_point.h - - g_video_act_margin_left; - g_mac_mouse_y = mouse_point.v - - g_video_act_margin_top; - } - -#if 0 - printf("Mouse %d at: %d,%d button:%d, button_st:%d\n", - mouse_events, g_mac_mouse_x, g_mac_mouse_y, - button, button_state); - printf("Mouse deltas: err:%d, %d,%d\n", (int)err, - mouse_delta_point.h, mouse_delta_point.v); -#endif - - update_mouse(g_mac_mouse_x, g_mac_mouse_y, - button_state, button & 7); - if(g_warp_pointer) { - g_mac_mouse_x = A2_WINDOW_WIDTH/2; - g_mac_mouse_y = A2_WINDOW_HEIGHT/2; - update_mouse(g_mac_mouse_x, g_mac_mouse_y,0,-1); - } - break; - case kEventClassApplication: - switch(event_kind) { - case kEventAppActivated: - handled = 1; - g_mainwin_active = 1; - window_ref = 0; - GetEventParameter(event, kEventParamWindowRef, - typeWindowRef, NULL, sizeof(WindowRef), - NULL, &window_ref); - if(window_ref == g_main_window) { - g_ignore_next_click = 1; - } - break; - case kEventAppDeactivated: - handled = 1; - g_mainwin_active = 0; - g_ignore_next_click = 1; - break; - } - break; - } - // show_event(event_class, event_kind, handled); - if(handled != 1) { - (void)SendEventToEventTarget(event, target); - } - ReleaseEvent(event); - } - - return; -} - -void -temp_run_application_event_loop(void) -{ - OSStatus err; - EventRef dummy_event; - EventHandlerRef install_handler; - EventTypeSpec event_spec = { 'KWIN', 'KWIN' }; - - // Create UPP for dummy_event_handler and for quit_event_handler - err = noErr; - dummy_event = 0; - - g_dummy_event_handler_UPP = NewEventHandlerUPP(dummy_event_handler); - g_quit_handler_UPP = NewEventHandlerUPP(quit_event_handler); - if((g_dummy_event_handler_UPP == 0) || (g_quit_handler_UPP == 0)) { - err = memFullErr; - } - - if(err == noErr) { - err = InstallApplicationEventHandler(g_dummy_event_handler_UPP, - 1, &event_spec, 0, &install_handler); - if(err == noErr) { - err = MacCreateEvent(NULL, 'KWIN', 'KWIN', - GetCurrentEventTime(), kEventAttributeNone, - &dummy_event); - if(err == noErr) { - err = PostEventToQueue(GetMainEventQueue(), - dummy_event, kEventPriorityHigh); - } - if(err == noErr) { - RunApplicationEventLoop(); - } - - (void)RemoveEventHandler(install_handler); - } - } - - if(dummy_event != NULL) { - ReleaseEvent(dummy_event); - } -} - - - -int -#ifdef ACTIVEGS -macmain -#else -main -#endif -(int argc, char* argv[]) -{ - ProcessSerialNumber my_psn; - - IBNibRef nibRef; - EventHandlerUPP handlerUPP; - EventTypeSpec cmd_event[3]; - GDHandle g_gdhandle ; - Rect win_rect; - OSStatus err; - char *argptr; - int slash_cnt; - int i; - -#ifndef ACTIVEGS - /* Prepare argv0 */ - slash_cnt = 0; - argptr = argv[0]; - for(i = strlen(argptr); i >= 0; i--) { - if(argptr[i] == '/') { - slash_cnt++; - if(slash_cnt == 3) { - strncpy(&(g_argv0_path[0]), argptr, i); - g_argv0_path[i] = 0; - } - } - } - - printf("g_argv0_path is %s\n", g_argv0_path); - - g_mac_argv[0] = argv[0]; - g_mac_argc = 1; - i = 1; - while((i < argc) && (g_mac_argc < MAX_MAC_ARGS)) { - if(!strncmp(argv[i], "-psn", 4)) { - /* skip this argument */ - } else { - g_mac_argv[g_mac_argc++] = argv[i]; - } - i++; - } -#endif - - InitCursor(); - g_event_rgnhandle = NewRgn(); - g_status_font_family = FMGetFontFamilyFromName("\pCourier"); - - SetRect(&win_rect, 0, 0, X_A2_WINDOW_WIDTH, X_A2_WINDOW_HEIGHT - // OG Remove status line from ActiveGS window -#ifndef ACTIVEGS - + MAX_STATUS_LINES*16 + 8 -#endif - ); - OffsetRect(&win_rect, 64, 50); - - - // Create a Nib reference passing the name of the nib file - // CreateNibReference only searches into the application bundle. - err = CreateNibReference(CFSTR("main"), &nibRef); - require_noerr( err, CantGetNibRef ); - // Once the nib reference is created, set the menu bar. - err = SetMenuBarFromNib(nibRef, CFSTR("MenuBar")); - require_noerr( err, CantSetMenuBar ); - - -#ifndef ACTIVEGS - err = CreateNewWindow(kDocumentWindowClass, - kWindowStandardDocumentAttributes | - kWindowStandardHandlerAttribute, - &win_rect, &g_main_window); - - err = SetWindowTitleWithCFString(g_main_window, CFSTR("GSport")); -#else - err = CreateNewWindow(kDocumentWindowClass, - (kWindowCloseBoxAttribute /*| kWindowFullZoomAttribute */| kWindowCollapseBoxAttribute /*| kWindowResizableAttribute*/) /*kWindowStandardDocumentAttributes*/ | - kWindowStandardHandlerAttribute, - &win_rect, &g_main_window); - extern CFStringRef activeGSversionSTR; - err = SetWindowTitleWithCFString(g_main_window, activeGSversionSTR); -#endif - - //printf("CreateNewWindow ret: %d, g_main_window: %p\n", (int)err, g_main_window); - - - // We don't need the nib reference anymore. - DisposeNibReference(nibRef); - - SysBeep(120); - - handlerUPP = NewEventHandlerUPP( my_cmd_handler ); - - cmd_event[0].eventClass = kEventClassCommand; - cmd_event[0].eventKind = kEventProcessCommand; - InstallWindowEventHandler(g_main_window, handlerUPP, 1, &cmd_event[0], - (void *)g_main_window, NULL); - - handlerUPP = NewEventHandlerUPP(my_win_handler); - cmd_event[0].eventClass = kEventClassWindow; - cmd_event[0].eventKind = kEventWindowDrawContent; - cmd_event[1].eventClass = kEventClassWindow; - cmd_event[1].eventKind = kEventWindowUpdate; - cmd_event[2].eventClass = kEventClassWindow; - cmd_event[2].eventKind = kEventWindowClose; - err = InstallWindowEventHandler(g_main_window, handlerUPP, 3, - &cmd_event[0], (void *)g_main_window, NULL); - require_noerr(err, CantCreateWindow); - - // Get screen depth - g_gdhandle = GetGDevice(); - g_screen_mdepth = (**((**g_gdhandle).gdPMap)).pixelSize; - - g_screen_depth = g_screen_mdepth; - - if(g_screen_depth > 16) { - /* 32-bit display */ - g_red_mask = 0xff; - g_green_mask = 0xff; - g_blue_mask = 0xff; - - /* - if (macUsingCoreGraphics) - { - g_red_left_shift = 0; - g_green_left_shift = 8; - g_blue_left_shift = 16; - } - else - */ - { - g_red_left_shift = 16; - g_green_left_shift = 8; - g_blue_left_shift = 0; - - } - - g_red_right_shift = 0; - g_green_right_shift = 0; - g_blue_right_shift = 0; - } else if(g_screen_depth > 8) { - /* 16-bit display */ - g_red_mask = 0x1f; - g_green_mask = 0x1f; - g_blue_mask = 0x1f; - g_red_left_shift = 10; - g_green_left_shift = 5; - g_blue_left_shift = 0; - g_red_right_shift = 3; - g_green_right_shift = 3; - g_blue_right_shift = 3; - } - - // show_alert("About to show window", (int)g_main_window); - update_main_window_size(); - - update_window(); - - - // The window was created hidden so show it. - ShowWindow( g_main_window ); - BringToFront( g_main_window ); - - update_window(); - - // Make us pop to the front a different way - err = GetCurrentProcess(&my_psn); - if(err == noErr) { - (void)SetFrontProcess(&my_psn); - } - - // Call the event loop - temp_run_application_event_loop(); - - -CantCreateWindow: -CantSetMenuBar: -CantGetNibRef: - show_simple_alert("ending", "", "error code", err); - return err; -} - -void -xdriver_end() -{ - - printf("xdriver_end\n"); - - if(g_fatal_log >= 0) { - x_show_alert(1, 0); - } -} - - -void -x_redraw_status_lines() -{ - // OG Disable status line -#ifndef ACTIVEGS - Rect rect; - Pattern white_pattern; - char tmp_buf[256]; - char *buf; - int len; - int line; - int height; - int margin; - - SetPortWindowPort(g_main_window); - PenNormal(); - height = 16; - margin = 0; - TextFont(g_status_font_family); - TextFace(normal); - TextSize(12); - - SetRect(&rect, 0, X_A2_WINDOW_HEIGHT + margin, X_A2_WINDOW_WIDTH, - X_A2_WINDOW_HEIGHT + margin + MAX_STATUS_LINES*height); - GetQDGlobalsWhite(&white_pattern); - FillRect(&rect, &white_pattern); - - for(line = 0; line < MAX_STATUS_LINES; line++) { - buf = g_status_ptrs[line]; - if(buf == 0) { - /* skip it */ - continue; - } - MoveTo(10, X_A2_WINDOW_HEIGHT + height*line + margin + height); - len = MIN(250, strlen(buf)); - strncpy(&tmp_buf[1], buf, len); - tmp_buf[0] = len; - DrawString((const unsigned char*)&tmp_buf[0]); - } -#endif -} - -void -x_full_screen(int do_full) -{ - -#if 0 - WindowRef new_window; - short width, height; - OSErr ret; - - width = 640; - height = 480; - if(do_full && (g_mac_fullscreen_state == 0)) { - g_main_window_saved = g_main_window; - - GetWindowBounds(g_main_window, kWindowContentRgn, - &g_main_window_saved_rect); - ret = BeginFullScreen(&g_mac_fullscreen_state, 0, - &width, &height, &new_window, 0, 0); - printf("Ret beginfullscreen: %d\n", (int)ret); - printf("New width: %d, new height: %d\n", width, height); - if(ret == noErr) { - g_main_window = new_window; - } else { - g_mac_fullscreen_state = 0; - } - } else if(!do_full && (g_mac_fullscreen_state != 0)) { - ret = EndFullScreen(g_mac_fullscreen_state, 0); - printf("ret endfullscreen: %d\n", (int)ret); - g_main_window = g_main_window_saved; - g_mac_fullscreen_state = 0; - //InitCursor(); - SetWindowBounds(g_main_window, kWindowContentRgn, - &g_main_window_saved_rect); - } - - update_main_window_size(); - - ShowWindow(g_main_window); - BringToFront(g_main_window); - update_window(); -#endif -} - - -void -x_push_done() -{ - - CGrafPtr window_port; - - SetPortWindowPort(g_main_window); - window_port = GetWindowPort(g_main_window); - - QDFlushPortBuffer(window_port, 0); - -} - -void -mac_warp_mouse() -{ -#ifndef ACTIVEGS - Rect port_rect; - Point win_origin_pt; - CGPoint cgpoint; - CGDisplayErr cg_err; - - GetPortBounds(GetWindowPort(g_main_window), &port_rect); - SetPt(&win_origin_pt, port_rect.left, port_rect.top); - LocalToGlobal(&win_origin_pt); - - cgpoint = CGPointMake( (float)(win_origin_pt.h + X_A2_WINDOW_WIDTH/2), - (float)(win_origin_pt.v + X_A2_WINDOW_HEIGHT/2)); - cg_err = CGDisplayMoveCursorToPoint(kCGDirectMainDisplay, cgpoint); -#endif -} diff --git a/src/moremem.c b/src/moremem.c index 7e49f7d..14492d8 100644 --- a/src/moremem.c +++ b/src/moremem.c @@ -1,6 +1,7 @@ /* GSport - an Apple //gs Emulator - Copyright (C) 2010 - 2014 by GSport contributors + Copyright (C) 2010 - 2019 by GSport contributors + Copyright (C) 2016 - 2018 Dagen Brock Based on the KEGS emulator written by and Copyright (C) 2003 Kent Dickey @@ -22,7 +23,7 @@ #include "defc.h" #ifdef HAVE_TFE -#include "tfe/protos_tfe.h" +#include "tfe/protos_tfe.h" #endif extern char const g_gsport_version_str[]; @@ -50,2463 +51,2433 @@ extern int g_parallel; char c; /* from iwm.c */ -int g_num_shadow_all_banks = 0; +int g_num_shadow_all_banks = 0; #define IOR(val) ( (val) ? 0x80 : 0x00 ) extern int g_cur_a2_stat; -int g_em_emubyte_cnt = 0; -int g_paddle_buttons = 0; -int g_irq_pending = 0; +int g_em_emubyte_cnt = 0; +int g_paddle_buttons = 0; +int g_irq_pending = 0; -int g_c023_val = 0; -int g_c029_val_some = 0x41; -int g_c02b_val = 0x08; -int g_c02d_int_crom = 0; -int g_c031_disk35 = 0; -int g_c033_data = 0; -int g_c034_val = 0; -int g_c035_shadow_reg = 0x08; -int g_c036_val_speed = 0x80; -int g_c03ef_doc_ptr = 0; -int g_c041_val = 0; /* C041_EN_25SEC_INTS, C041_EN_MOVE_INTS */ -int g_c046_val = 0; -int g_c05x_annuncs = 0; -int g_c068_statereg = 0; -int g_c08x_wrdefram = 0; -int g_zipgs_unlock = 0; -int g_zipgs_reg_c059 = 0x5f; - // 7=LC cache dis, 6==5ms paddle del en, 5==5ms ext del en, - // 4==5ms c02e enab, 3==CPS follow enab, 2-0: 111 -int g_zipgs_reg_c05a = 0x0f; - // 7:4 = current ZIP speed, 0=100%, 1=93.75%, F=6.25% - // 3:0: always 1111 -int g_zipgs_reg_c05b = 0x40; - // 7==1ms clock, 6==cshupd: tag data at c05f updated - // 5==LC cache disable, 4==bd is disabled, 3==delay in effect, - // 2==rombank, 1-0==ram size (00:8K, 01=16K, 10=32K, 11=64K) -int g_zipgs_reg_c05c = 0x00; - // 7:1==slot delay enable (for 52-54ms), 0==speaker 5ms delay +int g_c023_val = 0; +int g_c029_val_some = 0x41; +int g_c02b_val = 0x08; +int g_c02d_int_crom = 0; +int g_c031_disk35 = 0; +int g_c033_data = 0; +int g_c034_val = 0; +int g_c035_shadow_reg = 0x08; +int g_c036_val_speed = 0x80; +int g_c03ef_doc_ptr = 0; +int g_c041_val = 0; /* C041_EN_25SEC_INTS, C041_EN_MOVE_INTS */ +int g_c046_val = 0; +int g_c05x_annuncs = 0; +int g_c068_statereg = 0; +int g_c08x_wrdefram = 0; +int g_zipgs_unlock = 0; +int g_zipgs_reg_c059 = 0x5f; +// 7=LC cache dis, 6==5ms paddle del en, 5==5ms ext del en, +// 4==5ms c02e enab, 3==CPS follow enab, 2-0: 111 +int g_zipgs_reg_c05a = 0x0f; +// 7:4 = current ZIP speed, 0=100%, 1=93.75%, F=6.25% +// 3:0: always 1111 +int g_zipgs_reg_c05b = 0x40; +// 7==1ms clock, 6==cshupd: tag data at c05f updated +// 5==LC cache disable, 4==bd is disabled, 3==delay in effect, +// 2==rombank, 1-0==ram size (00:8K, 01=16K, 10=32K, 11=64K) +int g_zipgs_reg_c05c = 0x00; +// 7:1==slot delay enable (for 52-54ms), 0==speaker 5ms delay -#define EMUSTATE(a) { #a, &a } +#define EMUSTATE(a) { #a, &a } Emustate_intlist g_emustate_intlist[] = { - EMUSTATE(g_cur_a2_stat), - EMUSTATE(g_paddle_buttons), + EMUSTATE(g_cur_a2_stat), + EMUSTATE(g_paddle_buttons), - EMUSTATE(g_em_emubyte_cnt), - EMUSTATE(g_irq_pending), - EMUSTATE(g_c023_val), - EMUSTATE(g_c029_val_some), - EMUSTATE(g_c02b_val), - EMUSTATE(g_c02d_int_crom), - EMUSTATE(g_c031_disk35), - EMUSTATE(g_c033_data), - EMUSTATE(g_c034_val), - EMUSTATE(g_c035_shadow_reg), - EMUSTATE(g_c036_val_speed), - EMUSTATE(g_c03ef_doc_ptr), - EMUSTATE(g_c041_val), - EMUSTATE(g_c046_val), - EMUSTATE(g_c05x_annuncs), - EMUSTATE(g_c068_statereg), - EMUSTATE(g_c08x_wrdefram), - EMUSTATE(g_zipgs_unlock), - EMUSTATE(g_zipgs_reg_c059), - EMUSTATE(g_zipgs_reg_c05a), - EMUSTATE(g_zipgs_reg_c05b), - EMUSTATE(g_zipgs_reg_c05c), - { 0, 0, } + EMUSTATE(g_em_emubyte_cnt), + EMUSTATE(g_irq_pending), + EMUSTATE(g_c023_val), + EMUSTATE(g_c029_val_some), + EMUSTATE(g_c02b_val), + EMUSTATE(g_c02d_int_crom), + EMUSTATE(g_c031_disk35), + EMUSTATE(g_c033_data), + EMUSTATE(g_c034_val), + EMUSTATE(g_c035_shadow_reg), + EMUSTATE(g_c036_val_speed), + EMUSTATE(g_c03ef_doc_ptr), + EMUSTATE(g_c041_val), + EMUSTATE(g_c046_val), + EMUSTATE(g_c05x_annuncs), + EMUSTATE(g_c068_statereg), + EMUSTATE(g_c08x_wrdefram), + EMUSTATE(g_zipgs_unlock), + EMUSTATE(g_zipgs_reg_c059), + EMUSTATE(g_zipgs_reg_c05a), + EMUSTATE(g_zipgs_reg_c05b), + EMUSTATE(g_zipgs_reg_c05c), + { 0, 0, } }; extern double g_paddle_trig_dcycs; extern double g_last_vbl_dcycs; Emustate_dbllist g_emustate_dbllist[] = { - EMUSTATE(g_paddle_trig_dcycs), - EMUSTATE(g_last_vbl_dcycs), - { 0, 0, } + EMUSTATE(g_paddle_trig_dcycs), + EMUSTATE(g_last_vbl_dcycs), + { 0, 0, } }; extern word32 g_mem_size_total; Emustate_word32list g_emustate_word32list[] = { - EMUSTATE(g_mem_size_total), - { 0, 0, } + EMUSTATE(g_mem_size_total), + { 0, 0, } }; -#define UNIMPL_READ \ - halt_printf("UNIMP READ to addr %08x\n", loc); \ - return 0; +#define UNIMPL_READ \ + halt_printf("UNIMP READ to addr %08x\n", loc); \ + return 0; -#define UNIMPL_WRITE \ - halt_printf("UNIMP WRITE to addr %08x, val: %04x\n", loc, val); \ - return; +#define UNIMPL_WRITE \ + halt_printf("UNIMP WRITE to addr %08x, val: %04x\n", loc, val); \ + return; //#ifdef _WINDOWS -// OG Added Transwarp ROM +// OG Added Transwarp ROM #define TRANSWARP int transwarp_low_val = 0; -#ifdef _WIN32 +#ifdef _WIN32 __declspec(align(256)) #endif unsigned char transwarpcode[][32] -#if !defined(_WIN32) && !defined(__OS2__) +#if !defined(_WIN32) __attribute__ ((aligned(256))) #endif -={ -{ + ={ + { /*0xBCFF00*/ 'T','W','G','S',0,0,0,0,0,0,0,0,0,0,0,0, -/*0xBCFF10*/ 0x5C,0x40,0xFF,0xBC, // JMP GetMaxSpeed -/*0xBCFF14*/ 0x5C,0x60,0xFF,0xBC, // JMP GetNumISpeed -/*0xBCFF18*/ 0x6B,0x00,0x00,0x00, // ??? -/*0xBCFF1C*/ 0x6B,0x00,0x00,0x00 // ??? -}, -{ -/*0xBCFF20*/ 0x5C,0x80,0xFF,0xBC, // JMP GetCurSpeed -/*0xBCFF24*/ 0x5C,0xA0,0xFF,0xBC, // JMP SetCurSpeed -/*0xBCFF28*/ 0x5C,0xC0,0xFF,0xBC, // JMP GetCurISpeed -/*0xBCFF2C*/ 0x5C,0xE0,0xFF,0xBC, // JMP SetCurISpeed -/*0xBCFF30*/ 0x6B,0x00,0x00,0x00, // ??? -/*0xBCFF34*/ 0x6B,0x00,0x00,0x00, // ??? -/*0xBCFF38*/ 0x6B,0x00,0x00,0x00, // ??? -/*0xBCFF3C*/ 0x6B,0x00,0x00,0x00 // GetTWConfig -}, -{ -/* 0xBCFF40*/ // GetMaxSpeed +/*0xBCFF10*/ 0x5C,0x40,0xFF,0xBC, // JMP GetMaxSpeed +/*0xBCFF14*/ 0x5C,0x60,0xFF,0xBC, // JMP GetNumISpeed +/*0xBCFF18*/ 0x6B,0x00,0x00,0x00, // ??? +/*0xBCFF1C*/ 0x6B,0x00,0x00,0x00 // ??? + }, + { +/*0xBCFF20*/ 0x5C,0x80,0xFF,0xBC, // JMP GetCurSpeed +/*0xBCFF24*/ 0x5C,0xA0,0xFF,0xBC, // JMP SetCurSpeed +/*0xBCFF28*/ 0x5C,0xC0,0xFF,0xBC, // JMP GetCurISpeed +/*0xBCFF2C*/ 0x5C,0xE0,0xFF,0xBC, // JMP SetCurISpeed +/*0xBCFF30*/ 0x6B,0x00,0x00,0x00, // ??? +/*0xBCFF34*/ 0x6B,0x00,0x00,0x00, // ??? +/*0xBCFF38*/ 0x6B,0x00,0x00,0x00, // ??? +/*0xBCFF3C*/ 0x6B,0x00,0x00,0x00 // GetTWConfig + }, + { +/* 0xBCFF40*/ // GetMaxSpeed #define ZIP_SPEED 8000 -0xA9, ZIP_SPEED & 0xFF, (ZIP_SPEED >> 8) &0xFF, // LDA 0x1F40 // Max Speed = 8.0Mhz -0x6B, // RTL -0x00,0x00,0x00,0x00, //4 -0x00,0x00,0x00,0x00, //8 -0x6B,0x00,0x00,0x00, //C Space Shark calls this address ??? -}, -{ -/* 0xBCFF60*/ //GetNumISpeed -0xA9,0x02,0x00, // LDA 0x0002 // 0=slow, 1=normal, 2=warp -0x6B, // RTL -}, -{ + 0xA9, ZIP_SPEED & 0xFF, (ZIP_SPEED >> 8) &0xFF, // LDA 0x1F40 // Max Speed = 8.0Mhz + 0x6B, // RTL + 0x00,0x00,0x00,0x00, //4 + 0x00,0x00,0x00,0x00, //8 + 0x6B,0x00,0x00,0x00, //C Space Shark calls this address ??? + }, + { +/* 0xBCFF60*/ //GetNumISpeed + 0xA9,0x02,0x00, // LDA 0x0002 // 0=slow, 1=normal, 2=warp + 0x6B, // RTL + }, + { /* 0xBCFF80*/ //GetCurSpeed -0xAF, 0x6A, 0xC0, 0x00, // LDA 0xC06A (/6B) -0x6B, // RTL -}, -{ + 0xAF, 0x6A, 0xC0, 0x00, // LDA 0xC06A (/6B) + 0x6B, // RTL + }, + { /* 0xBCFFA0*/ //SetCurSpeed -0x8F, 0x6A, 0xC0, 0x00, // STA 0xC06A (/6B) -0x6B, // RTL -}, -{ + 0x8F, 0x6A, 0xC0, 0x00, // STA 0xC06A (/6B) + 0x6B, // RTL + }, + { /* 0xBCFFC0*/ //GetCurISpeed -0x48, // PHA -0xAF, 0x6C, 0xC0, 0x00, // LDA 0xC06C (/6D) -0xAA, // TAX -0x68, // PLA -0x6B, // RTL -}, -{ + 0x48, // PHA + 0xAF, 0x6C, 0xC0, 0x00, // LDA 0xC06C (/6D) + 0xAA, // TAX + 0x68, // PLA + 0x6B, // RTL + }, + { /* 0xBCFFE0*/ //SetCurISpeed -0x48, // PHA -0x8A, // TXA -0x8F, 0x6C, 0xC0, 0x00, // STA 0xC06C (/6D) -0x68, // PLA -0x6B, // RTL -} -} + 0x48, // PHA + 0x8A, // TXA + 0x8F, 0x6C, 0xC0, 0x00, // STA 0xC06C (/6D) + 0x68, // PLA + 0x6B, // RTL + } + } ; +/* SLOT 7 DEVSEL RAM (used by HOST.MLI) */ +static byte slot7_devsel[15] = { 0 }; + + // OG Added moremem_init() -void moremem_init() -{ - g_em_emubyte_cnt = 0; - g_paddle_buttons = 0; - g_irq_pending = 0; +void moremem_init() { + g_em_emubyte_cnt = 0; + g_paddle_buttons = 0; + g_irq_pending = 0; - g_c023_val = 0; - g_c029_val_some = 0x41; - g_c02b_val = 0x08; - g_c02d_int_crom = 0; - g_c031_disk35 = 0; - g_c034_val = 0; - g_c035_shadow_reg = 0x08; - g_c036_val_speed = 0x80; - g_c03ef_doc_ptr = 0; - g_c041_val = 0; /* C041_EN_25SEC_INTS, C041_EN_MOVE_INTS */ - g_c046_val = 0; - g_c05x_annuncs = 0; - g_c068_statereg = 0; - g_c08x_wrdefram = 0; - g_zipgs_unlock = 0; - g_zipgs_reg_c059 = 0x5f; - g_zipgs_reg_c05a = 0x0f; - g_zipgs_reg_c05b = 0x40; - g_zipgs_reg_c05c = 0x00; + g_c023_val = 0; + g_c029_val_some = 0x41; + g_c02b_val = 0x08; + g_c02d_int_crom = 0; + g_c031_disk35 = 0; + g_c034_val = 0; + g_c035_shadow_reg = 0x08; + g_c036_val_speed = 0x80; + g_c03ef_doc_ptr = 0; + g_c041_val = 0; /* C041_EN_25SEC_INTS, C041_EN_MOVE_INTS */ + g_c046_val = 0; + g_c05x_annuncs = 0; + g_c068_statereg = 0; + g_c08x_wrdefram = 0; + g_zipgs_unlock = 0; + g_zipgs_reg_c059 = 0x5f; + g_zipgs_reg_c05a = 0x0f; + g_zipgs_reg_c05b = 0x40; + g_zipgs_reg_c05c = 0x00; } -void -fixup_brks() -{ - word32 page; - word32 tmp, tmp2; - Pg_info val; - int is_wr_only; - int i, num; +void fixup_brks() { + word32 page; + word32 tmp, tmp2; + Pg_info val; + int is_wr_only; + int i, num; - num = g_num_breakpoints; - for(i = 0; i < num; i++) { - page = (g_breakpts[i] >> 8) & 0xffff; - is_wr_only = (g_breakpts[i] >> 24) & 1; - if(!is_wr_only) { - val = GET_PAGE_INFO_RD(page); - tmp = PTR2WORD(val) & 0xff; - tmp2 = tmp | BANK_IO_TMP | BANK_BREAK; - SET_PAGE_INFO_RD(page, val - tmp + tmp2); - } - val = GET_PAGE_INFO_WR(page); - tmp = PTR2WORD(val) & 0xff; - tmp2 = tmp | BANK_IO_TMP | BANK_BREAK; - SET_PAGE_INFO_WR(page, val - tmp + tmp2); - } + num = g_num_breakpoints; + for(i = 0; i < num; i++) { + page = (g_breakpts[i] >> 8) & 0xffff; + is_wr_only = (g_breakpts[i] >> 24) & 1; + if(!is_wr_only) { + val = GET_PAGE_INFO_RD(page); + tmp = PTR2WORD(val) & 0xff; + tmp2 = tmp | BANK_IO_TMP | BANK_BREAK; + SET_PAGE_INFO_RD(page, val - tmp + tmp2); + } + val = GET_PAGE_INFO_WR(page); + tmp = PTR2WORD(val) & 0xff; + tmp2 = tmp | BANK_IO_TMP | BANK_BREAK; + SET_PAGE_INFO_WR(page, val - tmp + tmp2); + } } -void -fixup_hires_on() -{ - if((g_cur_a2_stat & ALL_STAT_ST80) == 0) { - return; - } +void fixup_hires_on() { + if((g_cur_a2_stat & ALL_STAT_ST80) == 0) { + return; + } - fixup_bank0_2000_4000(); - fixup_brks(); + fixup_bank0_2000_4000(); + fixup_brks(); } -void -fixup_bank0_2000_4000() -{ - byte *mem0rd; - byte *mem0wr; +void fixup_bank0_2000_4000() { + byte *mem0rd; + byte *mem0wr; - mem0rd = &(g_memory_ptr[0x2000]); - mem0wr = mem0rd; - if((g_cur_a2_stat & ALL_STAT_ST80) && (g_cur_a2_stat & ALL_STAT_HIRES)){ - if(g_cur_a2_stat & ALL_STAT_PAGE2) { - mem0rd += 0x10000; - mem0wr += 0x10000; - if((g_c035_shadow_reg & 0x12) == 0 || - (g_c035_shadow_reg & 0x8) == 0) { - mem0wr += BANK_SHADOW2; - } - } else if((g_c035_shadow_reg & 0x02) == 0) { - mem0wr += BANK_SHADOW; - } - - } else { - if(RAMRD) { - mem0rd += 0x10000; - } - if(RAMWRT) { - mem0wr += 0x10000; - if((g_c035_shadow_reg & 0x12) == 0 || - (g_c035_shadow_reg & 0x8) == 0) { - mem0wr += BANK_SHADOW2; - } - } else if((g_c035_shadow_reg & 0x02) == 0) { - mem0wr += BANK_SHADOW; - } - } + mem0rd = &(g_memory_ptr[0x2000]); + mem0wr = mem0rd; + if((g_cur_a2_stat & ALL_STAT_ST80) && (g_cur_a2_stat & ALL_STAT_HIRES)) { + if(g_cur_a2_stat & ALL_STAT_PAGE2) { + mem0rd += 0x10000; + mem0wr += 0x10000; + if((g_c035_shadow_reg & 0x12) == 0 || + (g_c035_shadow_reg & 0x8) == 0) { + mem0wr += BANK_SHADOW2; + } + } else if((g_c035_shadow_reg & 0x02) == 0) { + mem0wr += BANK_SHADOW; + } - fixup_any_bank_any_page(0x20, 0x20, mem0rd, mem0wr); + } else { + if(RAMRD) { + mem0rd += 0x10000; + } + if(RAMWRT) { + mem0wr += 0x10000; + if((g_c035_shadow_reg & 0x12) == 0 || + (g_c035_shadow_reg & 0x8) == 0) { + mem0wr += BANK_SHADOW2; + } + } else if((g_c035_shadow_reg & 0x02) == 0) { + mem0wr += BANK_SHADOW; + } + } + + fixup_any_bank_any_page(0x20, 0x20, mem0rd, mem0wr); } -void -fixup_bank0_0400_0800() -{ - byte *mem0rd; - byte *mem0wr; - int shadow; +void fixup_bank0_0400_0800() { + byte *mem0rd; + byte *mem0wr; + int shadow; - mem0rd = &(g_memory_ptr[0x400]); - mem0wr = mem0rd; - shadow = BANK_SHADOW; - if(g_cur_a2_stat & ALL_STAT_ST80) { - if(g_cur_a2_stat & ALL_STAT_PAGE2) { - shadow = BANK_SHADOW2; - mem0rd += 0x10000; - mem0wr += 0x10000; - } - } else { - if(RAMWRT) { - shadow = BANK_SHADOW2; - mem0wr += 0x10000; - } - if(RAMRD) { - mem0rd += 0x10000; - } - } - if((g_c035_shadow_reg & 0x01) == 0) { - mem0wr += shadow; - } + mem0rd = &(g_memory_ptr[0x400]); + mem0wr = mem0rd; + shadow = BANK_SHADOW; + if(g_cur_a2_stat & ALL_STAT_ST80) { + if(g_cur_a2_stat & ALL_STAT_PAGE2) { + shadow = BANK_SHADOW2; + mem0rd += 0x10000; + mem0wr += 0x10000; + } + } else { + if(RAMWRT) { + shadow = BANK_SHADOW2; + mem0wr += 0x10000; + } + if(RAMRD) { + mem0rd += 0x10000; + } + } + if((g_c035_shadow_reg & 0x01) == 0) { + mem0wr += shadow; + } - fixup_any_bank_any_page(0x4, 4, mem0rd, mem0wr); + fixup_any_bank_any_page(0x4, 4, mem0rd, mem0wr); } -void -fixup_any_bank_any_page(int start_page, int num_pages, byte *mem0rd, - byte *mem0wr) -{ - int i; +void fixup_any_bank_any_page(int start_page, int num_pages, byte *mem0rd, + byte *mem0wr) { + int i; - for(i = 0; i < num_pages; i++) { - SET_PAGE_INFO_RD(i + start_page, mem0rd); - mem0rd += 0x100; - } + for(i = 0; i < num_pages; i++) { + SET_PAGE_INFO_RD(i + start_page, mem0rd); + mem0rd += 0x100; + } - for(i = 0; i < num_pages; i++) { - SET_PAGE_INFO_WR(i + start_page, mem0wr); - mem0wr += 0x100; - } + for(i = 0; i < num_pages; i++) { + SET_PAGE_INFO_WR(i + start_page, mem0wr); + mem0wr += 0x100; + } } -void -fixup_intcx() -{ - byte *rom10000; - byte *rom_inc; - int no_io_shadow; - int off; - int start_k; - word32 mask; - int j, k; +void fixup_intcx() { + byte *rom10000; + byte *rom_inc; + int no_io_shadow; + int off; + int start_k; + word32 mask; + int j, k; - rom10000 = &(g_rom_fc_ff_ptr[0x30000]); + rom10000 = &(g_rom_fc_ff_ptr[0x30000]); - no_io_shadow = (g_c035_shadow_reg & 0x40); + no_io_shadow = (g_c035_shadow_reg & 0x40); - start_k = 0; - if(no_io_shadow) { - /* if not shadowing, banks 0 and 1 are not affected by intcx */ - start_k = 2; - } + start_k = 0; + if(no_io_shadow) { + /* if not shadowing, banks 0 and 1 are not affected by intcx */ + start_k = 2; + } - for(k = start_k; k < 4; k++) { - off = k; - if(k >= 2) { - off += (0xe0 - 2); - } - /* step off through 0x00, 0x01, 0xe0, 0xe1 */ + for(k = start_k; k < 4; k++) { + off = k; + if(k >= 2) { + off += (0xe0 - 2); + } + /* step off through 0x00, 0x01, 0xe0, 0xe1 */ - off = off << 8; - SET_PAGE_INFO_RD(0xc0 + off, SET_BANK_IO); + off = off << 8; + SET_PAGE_INFO_RD(0xc0 + off, SET_BANK_IO); - for(j = 0xc1; j < 0xc8; j++) { - mask = 1 << (j & 0xf); - if(j < 0xc8) { - rom_inc = SET_BANK_IO; - if(((g_c02d_int_crom & mask) == 0) || INTCX) { - rom_inc = rom10000 + (j << 8); - } else { - // User-slot rom - rom_inc = &(g_rom_cards_ptr[0]) + - ((j - 0xc0) << 8); - } - SET_PAGE_INFO_RD(j + off, rom_inc); - } - } - for(j = 0xc8; j < 0xd0; j++) { - - /*c800 - cfff */ - if(((g_c02d_int_crom & (1 << 3)) == 0) || INTCX) - { - rom_inc = rom10000 + (j << 8); - } - else - { - rom_inc = rom10000 + (j << 8); + for(j = 0xc1; j < 0xc8; j++) { + mask = 1 << (j & 0xf); + if(j < 0xc8) { + rom_inc = SET_BANK_IO; + if(((g_c02d_int_crom & mask) == 0) || INTCX) { + rom_inc = rom10000 + (j << 8); + } else { + // User-slot rom + rom_inc = &(g_rom_cards_ptr[0]) + + ((j - 0xc0) << 8); + } + SET_PAGE_INFO_RD(j + off, rom_inc); + } + } + for(j = 0xc8; j < 0xd0; j++) { - } - SET_PAGE_INFO_RD(j + off, rom_inc); - } - iostrobe = 0; - for(j = 0xc0; j < 0xd0; j++) { - SET_PAGE_INFO_WR(j + off, SET_BANK_IO); - } - } - if(!no_io_shadow) { - SET_PAGE_INFO_RD(0xc7, SET_BANK_IO); /* smartport */ - } - fixup_brks(); + /*c800 - cfff */ + if(((g_c02d_int_crom & (1 << 3)) == 0) || INTCX) + { + rom_inc = rom10000 + (j << 8); + } + else + { + rom_inc = rom10000 + (j << 8); + + } + SET_PAGE_INFO_RD(j + off, rom_inc); + } + iostrobe = 0; + for(j = 0xc0; j < 0xd0; j++) { + SET_PAGE_INFO_WR(j + off, SET_BANK_IO); + } + } + if(!no_io_shadow) { + SET_PAGE_INFO_RD(0xc7, SET_BANK_IO); /* smartport */ + } + fixup_brks(); } -void -fixup_wrdefram(int new_wrdefram) -{ - byte *mem0wr; - byte *wrptr; - int j; - - g_c08x_wrdefram = new_wrdefram; +void fixup_wrdefram(int new_wrdefram) { + byte *mem0wr; + byte *wrptr; + int j; - if(g_c035_shadow_reg & 0x40) { - /* do nothing */ - return; - } + g_c08x_wrdefram = new_wrdefram; - /* if shadowing, banks 0 and 1 are affected by wrdefram */ - mem0wr = &(g_memory_ptr[0]); - if(!new_wrdefram) { - mem0wr += (BANK_IO_TMP | BANK_IO2_TMP); - } + if(g_c035_shadow_reg & 0x40) { + /* do nothing */ + return; + } - wrptr = mem0wr + 0x1e000; - for(j = 0x1e0; j < 0x200; j++) { - SET_PAGE_INFO_WR(j, wrptr); - wrptr += 0x100; - } + /* if shadowing, banks 0 and 1 are affected by wrdefram */ + mem0wr = &(g_memory_ptr[0]); + if(!new_wrdefram) { + mem0wr += (BANK_IO_TMP | BANK_IO2_TMP); + } - wrptr = mem0wr + 0x0e000; - if(ALTZP) { - wrptr += 0x10000; - } - for(j = 0xe0; j < 0x100; j++) { - SET_PAGE_INFO_WR(j, wrptr); - wrptr += 0x100; - } + wrptr = mem0wr + 0x1e000; + for(j = 0x1e0; j < 0x200; j++) { + SET_PAGE_INFO_WR(j, wrptr); + wrptr += 0x100; + } - wrptr = mem0wr + 0x1d000; - if(! LCBANK2) { - wrptr -= 0x1000; - } - for(j = 0x1d0; j < 0x1e0; j++) { - SET_PAGE_INFO_WR(j, wrptr); - wrptr += 0x100; - } + wrptr = mem0wr + 0x0e000; + if(ALTZP) { + wrptr += 0x10000; + } + for(j = 0xe0; j < 0x100; j++) { + SET_PAGE_INFO_WR(j, wrptr); + wrptr += 0x100; + } - wrptr = mem0wr + 0xd000; - if(! LCBANK2) { - wrptr -= 0x1000; - } - if(ALTZP) { - wrptr += 0x10000; - } - for(j = 0xd0; j < 0xe0; j++) { - SET_PAGE_INFO_WR(j, wrptr); - wrptr += 0x100; - } + wrptr = mem0wr + 0x1d000; + if(!LCBANK2) { + wrptr -= 0x1000; + } + for(j = 0x1d0; j < 0x1e0; j++) { + SET_PAGE_INFO_WR(j, wrptr); + wrptr += 0x100; + } - fixup_brks(); + wrptr = mem0wr + 0xd000; + if(!LCBANK2) { + wrptr -= 0x1000; + } + if(ALTZP) { + wrptr += 0x10000; + } + for(j = 0xd0; j < 0xe0; j++) { + SET_PAGE_INFO_WR(j, wrptr); + wrptr += 0x100; + } + + fixup_brks(); } -void -fixup_st80col(double dcycs) -{ - int cur_a2_stat; +void fixup_st80col(double dcycs) { + int cur_a2_stat; - cur_a2_stat = g_cur_a2_stat; + cur_a2_stat = g_cur_a2_stat; - fixup_bank0_0400_0800(); + fixup_bank0_0400_0800(); - if(cur_a2_stat & ALL_STAT_HIRES) { - /* fixup no matter what PAGE2 since PAGE2 and RAMRD/WR */ - /* can work against each other */ - fixup_bank0_2000_4000(); - } + if(cur_a2_stat & ALL_STAT_HIRES) { + /* fixup no matter what PAGE2 since PAGE2 and RAMRD/WR */ + /* can work against each other */ + fixup_bank0_2000_4000(); + } - if(cur_a2_stat & ALL_STAT_PAGE2) { - change_display_mode(dcycs); - } + if(cur_a2_stat & ALL_STAT_PAGE2) { + change_display_mode(dcycs); + } - fixup_brks(); + fixup_brks(); } -void -fixup_altzp() -{ - byte *mem0rd, *mem0wr; - int rdrom, c08x_wrdefram; - int altzp; +void fixup_altzp() { + byte *mem0rd, *mem0wr; + int rdrom, c08x_wrdefram; + int altzp; - altzp = ALTZP; - mem0rd = &(g_memory_ptr[0]); - if(altzp) { - mem0rd += 0x10000; - } - SET_PAGE_INFO_RD(0, mem0rd); - SET_PAGE_INFO_RD(1, mem0rd + 0x100); - SET_PAGE_INFO_WR(0, mem0rd); - SET_PAGE_INFO_WR(1, mem0rd + 0x100); + altzp = ALTZP; + mem0rd = &(g_memory_ptr[0]); + if(altzp) { + mem0rd += 0x10000; + } + SET_PAGE_INFO_RD(0, mem0rd); + SET_PAGE_INFO_RD(1, mem0rd + 0x100); + SET_PAGE_INFO_WR(0, mem0rd); + SET_PAGE_INFO_WR(1, mem0rd + 0x100); - mem0rd = &(g_memory_ptr[0xd000]); - mem0wr = mem0rd; - c08x_wrdefram = g_c08x_wrdefram; - rdrom = RDROM; + mem0rd = &(g_memory_ptr[0xd000]); + mem0wr = mem0rd; + c08x_wrdefram = g_c08x_wrdefram; + rdrom = RDROM; - if(g_c035_shadow_reg & 0x40) { - if(ALTZP) { - mem0rd += 0x10000; - } - fixup_any_bank_any_page(0xd0, 0x10, mem0rd - 0x1000, - mem0rd - 0x1000); - c08x_wrdefram = 1; - rdrom = 0; - } else { - if(!c08x_wrdefram) { - mem0wr += (BANK_IO_TMP | BANK_IO2_TMP); - } - if(ALTZP) { - mem0rd += 0x10000; - mem0wr += 0x10000; - } - if(! LCBANK2) { - mem0rd -= 0x1000; - mem0wr -= 0x1000; - } - if(rdrom) { - mem0rd = &(g_rom_fc_ff_ptr[0x3d000]); - } - fixup_any_bank_any_page(0xd0, 0x10, mem0rd, mem0wr); - } + if(g_c035_shadow_reg & 0x40) { + if(ALTZP) { + mem0rd += 0x10000; + } + fixup_any_bank_any_page(0xd0, 0x10, mem0rd - 0x1000, + mem0rd - 0x1000); + c08x_wrdefram = 1; + rdrom = 0; + } else { + if(!c08x_wrdefram) { + mem0wr += (BANK_IO_TMP | BANK_IO2_TMP); + } + if(ALTZP) { + mem0rd += 0x10000; + mem0wr += 0x10000; + } + if(!LCBANK2) { + mem0rd -= 0x1000; + mem0wr -= 0x1000; + } + if(rdrom) { + mem0rd = &(g_rom_fc_ff_ptr[0x3d000]); + } + fixup_any_bank_any_page(0xd0, 0x10, mem0rd, mem0wr); + } - mem0rd = &(g_memory_ptr[0xe000]); - mem0wr = mem0rd; - if(!c08x_wrdefram) { - mem0wr += (BANK_IO_TMP | BANK_IO2_TMP); - } - if(ALTZP) { - mem0rd += 0x10000; - mem0wr += 0x10000; - } - if(rdrom) { - mem0rd = &(g_rom_fc_ff_ptr[0x3e000]); - } - fixup_any_bank_any_page(0xe0, 0x20, mem0rd, mem0wr); + mem0rd = &(g_memory_ptr[0xe000]); + mem0wr = mem0rd; + if(!c08x_wrdefram) { + mem0wr += (BANK_IO_TMP | BANK_IO2_TMP); + } + if(ALTZP) { + mem0rd += 0x10000; + mem0wr += 0x10000; + } + if(rdrom) { + mem0rd = &(g_rom_fc_ff_ptr[0x3e000]); + } + fixup_any_bank_any_page(0xe0, 0x20, mem0rd, mem0wr); - /* No need for fixup_brks since called from set_statereg() */ + /* No need for fixup_brks since called from set_statereg() */ } -void -fixup_page2(double dcycs) -{ - if((g_cur_a2_stat & ALL_STAT_ST80)) { - fixup_bank0_0400_0800(); - if((g_cur_a2_stat & ALL_STAT_HIRES)) { - fixup_bank0_2000_4000(); - } - } else { - change_display_mode(dcycs); - } +void fixup_page2(double dcycs) { + if((g_cur_a2_stat & ALL_STAT_ST80)) { + fixup_bank0_0400_0800(); + if((g_cur_a2_stat & ALL_STAT_HIRES)) { + fixup_bank0_2000_4000(); + } + } else { + change_display_mode(dcycs); + } } -void -fixup_ramrd() -{ - byte *mem0rd; - int cur_a2_stat; - int j; +void fixup_ramrd() { + byte *mem0rd; + int cur_a2_stat; + int j; - cur_a2_stat = g_cur_a2_stat; + cur_a2_stat = g_cur_a2_stat; - if((cur_a2_stat & ALL_STAT_ST80) == 0) { - fixup_bank0_0400_0800(); - } - if( ((cur_a2_stat & ALL_STAT_ST80) == 0) || - ((cur_a2_stat & ALL_STAT_HIRES) == 0) ) { - fixup_bank0_2000_4000(); - } + if((cur_a2_stat & ALL_STAT_ST80) == 0) { + fixup_bank0_0400_0800(); + } + if( ((cur_a2_stat & ALL_STAT_ST80) == 0) || + ((cur_a2_stat & ALL_STAT_HIRES) == 0) ) { + fixup_bank0_2000_4000(); + } - mem0rd = &(g_memory_ptr[0x0000]); - if(RAMRD) { - mem0rd += 0x10000; - } + mem0rd = &(g_memory_ptr[0x0000]); + if(RAMRD) { + mem0rd += 0x10000; + } - SET_PAGE_INFO_RD(2, mem0rd + 0x200); - SET_PAGE_INFO_RD(3, mem0rd + 0x300); + SET_PAGE_INFO_RD(2, mem0rd + 0x200); + SET_PAGE_INFO_RD(3, mem0rd + 0x300); - for(j = 8; j < 0x20; j++) { - SET_PAGE_INFO_RD(j, mem0rd + j*0x100); - } + for(j = 8; j < 0x20; j++) { + SET_PAGE_INFO_RD(j, mem0rd + j*0x100); + } - for(j = 0x40; j < 0xc0; j++) { - SET_PAGE_INFO_RD(j, mem0rd + j*0x100); - } + for(j = 0x40; j < 0xc0; j++) { + SET_PAGE_INFO_RD(j, mem0rd + j*0x100); + } - /* No need for fixup_brks since only called from set_statereg() */ + /* No need for fixup_brks since only called from set_statereg() */ } -void -fixup_ramwrt() -{ - byte *mem0wr; - int cur_a2_stat; - int shadow; - int ramwrt; - int j; +void fixup_ramwrt() { + byte *mem0wr; + int cur_a2_stat; + int shadow; + int ramwrt; + int j; - cur_a2_stat = g_cur_a2_stat; + cur_a2_stat = g_cur_a2_stat; - if((cur_a2_stat & ALL_STAT_ST80) == 0) { - fixup_bank0_0400_0800(); - } - if( ((cur_a2_stat & ALL_STAT_ST80) == 0) || - ((cur_a2_stat & ALL_STAT_HIRES) == 0) ) { - fixup_bank0_2000_4000(); - } + if((cur_a2_stat & ALL_STAT_ST80) == 0) { + fixup_bank0_0400_0800(); + } + if( ((cur_a2_stat & ALL_STAT_ST80) == 0) || + ((cur_a2_stat & ALL_STAT_HIRES) == 0) ) { + fixup_bank0_2000_4000(); + } - mem0wr = &(g_memory_ptr[0x0000]); - ramwrt = RAMWRT; - if(ramwrt) { - mem0wr += 0x10000; - } + mem0wr = &(g_memory_ptr[0x0000]); + ramwrt = RAMWRT; + if(ramwrt) { + mem0wr += 0x10000; + } - SET_PAGE_INFO_WR(2, mem0wr + 0x200); - SET_PAGE_INFO_WR(3, mem0wr + 0x300); + SET_PAGE_INFO_WR(2, mem0wr + 0x200); + SET_PAGE_INFO_WR(3, mem0wr + 0x300); - shadow = BANK_SHADOW; - if(ramwrt) { - shadow = BANK_SHADOW2; - } - if( ((g_c035_shadow_reg & 0x20) != 0) || - ((g_rom_version < 3) && !g_user_page2_shadow)) { - shadow = 0; - } - for(j = 8; j < 0x0c; j++) { - SET_PAGE_INFO_WR(j, mem0wr + j*0x100 + shadow); - } + shadow = BANK_SHADOW; + if(ramwrt) { + shadow = BANK_SHADOW2; + } + if( ((g_c035_shadow_reg & 0x20) != 0) || + ((g_rom_version < 3) && !g_user_page2_shadow)) { + shadow = 0; + } + for(j = 8; j < 0x0c; j++) { + SET_PAGE_INFO_WR(j, mem0wr + j*0x100 + shadow); + } - for(j = 0xc; j < 0x20; j++) { - SET_PAGE_INFO_WR(j, mem0wr + j*0x100); - } + for(j = 0xc; j < 0x20; j++) { + SET_PAGE_INFO_WR(j, mem0wr + j*0x100); + } - shadow = 0; - if(ramwrt) { - if((g_c035_shadow_reg & 0x14) == 0 || - (g_c035_shadow_reg & 0x08) == 0) { - shadow = BANK_SHADOW2; - } - } else if((g_c035_shadow_reg & 0x04) == 0) { - shadow = BANK_SHADOW; - } - for(j = 0x40; j < 0x60; j++) { - SET_PAGE_INFO_WR(j, mem0wr + j*0x100 + shadow); - } + shadow = 0; + if(ramwrt) { + if((g_c035_shadow_reg & 0x14) == 0 || + (g_c035_shadow_reg & 0x08) == 0) { + shadow = BANK_SHADOW2; + } + } else if((g_c035_shadow_reg & 0x04) == 0) { + shadow = BANK_SHADOW; + } + for(j = 0x40; j < 0x60; j++) { + SET_PAGE_INFO_WR(j, mem0wr + j*0x100 + shadow); + } - shadow = 0; - if(ramwrt && (g_c035_shadow_reg & 0x08) == 0) { - /* shr shadowing */ - shadow = BANK_SHADOW2; - } - for(j = 0x60; j < 0xa0; j++) { - SET_PAGE_INFO_WR(j, mem0wr + j*0x100 + shadow); - } + shadow = 0; + if(ramwrt && (g_c035_shadow_reg & 0x08) == 0) { + /* shr shadowing */ + shadow = BANK_SHADOW2; + } + for(j = 0x60; j < 0xa0; j++) { + SET_PAGE_INFO_WR(j, mem0wr + j*0x100 + shadow); + } - for(j = 0xa0; j < 0xc0; j++) { - SET_PAGE_INFO_WR(j, mem0wr + j*0x100); - } + for(j = 0xa0; j < 0xc0; j++) { + SET_PAGE_INFO_WR(j, mem0wr + j*0x100); + } - /* No need for fixup_brks() since only called from set_statereg() */ + /* No need for fixup_brks() since only called from set_statereg() */ } -void -fixup_lcbank2() -{ - byte *mem0rd, *mem0wr; - int lcbank2, c08x_wrdefram, rdrom; - int off; - int k; +void fixup_lcbank2() { + byte *mem0rd, *mem0wr; + int lcbank2, c08x_wrdefram, rdrom; + int off; + int k; - for(k = 0; k < 4; k++) { - off = k; - if(k >= 2) { - off += (0xe0 - 2); - } - /* step off through 0x00, 0x01, 0xe0, 0xe1 */ + for(k = 0; k < 4; k++) { + off = k; + if(k >= 2) { + off += (0xe0 - 2); + } + /* step off through 0x00, 0x01, 0xe0, 0xe1 */ - if(k < 2) { - mem0rd = &(g_memory_ptr[k << 16]); - } else { - mem0rd = &(g_slow_memory_ptr[(k & 1) << 16]); - } - if((k == 0) && ALTZP) { - mem0rd += 0x10000; - } - lcbank2 = LCBANK2; - c08x_wrdefram = g_c08x_wrdefram; - rdrom = RDROM; - if((k < 2) && (g_c035_shadow_reg & 0x40)) { - lcbank2 = 0; - c08x_wrdefram = 1; - rdrom = 0; - } - if(! lcbank2) { - mem0rd -= 0x1000; /* lcbank1, use 0xc000-cfff */ - } - mem0wr = mem0rd; - if((k < 2) && !c08x_wrdefram) { - mem0wr += (BANK_IO_TMP | BANK_IO2_TMP); - } - if((k < 2) && rdrom) { - mem0rd = &(g_rom_fc_ff_ptr[0x30000]); - } - fixup_any_bank_any_page(off*0x100 + 0xd0, 0x10, - mem0rd + 0xd000, mem0wr + 0xd000); - } + if(k < 2) { + mem0rd = &(g_memory_ptr[k << 16]); + } else { + mem0rd = &(g_slow_memory_ptr[(k & 1) << 16]); + } + if((k == 0) && ALTZP) { + mem0rd += 0x10000; + } + lcbank2 = LCBANK2; + c08x_wrdefram = g_c08x_wrdefram; + rdrom = RDROM; + if((k < 2) && (g_c035_shadow_reg & 0x40)) { + lcbank2 = 0; + c08x_wrdefram = 1; + rdrom = 0; + } + if(!lcbank2) { + mem0rd -= 0x1000; /* lcbank1, use 0xc000-cfff */ + } + mem0wr = mem0rd; + if((k < 2) && !c08x_wrdefram) { + mem0wr += (BANK_IO_TMP | BANK_IO2_TMP); + } + if((k < 2) && rdrom) { + mem0rd = &(g_rom_fc_ff_ptr[0x30000]); + } + fixup_any_bank_any_page(off*0x100 + 0xd0, 0x10, + mem0rd + 0xd000, mem0wr + 0xd000); + } - /* No need for fixup_brks() since only called from set_statereg(), */ - /* or from other routines which will handle it */ + /* No need for fixup_brks() since only called from set_statereg(), */ + /* or from other routines which will handle it */ } -void -fixup_rdrom() -{ - byte *mem0rd; - int j, k; +void fixup_rdrom() { + byte *mem0rd; + int j, k; - /* fixup_lcbank2 handles 0xd000-dfff for rd & wr*/ - fixup_lcbank2(); + /* fixup_lcbank2 handles 0xd000-dfff for rd & wr*/ + fixup_lcbank2(); - for(k = 0; k < 2; k++) { - /* k is the bank */ - mem0rd = &(g_memory_ptr[k << 16]); - if((k == 0) && ALTZP) { - mem0rd += 0x10000; - } - if((g_c035_shadow_reg & 0x40) == 0) { - if(RDROM) { - mem0rd = &(g_rom_fc_ff_ptr[0x30000]); - } - } - for(j = 0xe0; j < 0x100; j++) { - SET_PAGE_INFO_RD(j + k*0x100, mem0rd + j*0x100); - } - } + for(k = 0; k < 2; k++) { + /* k is the bank */ + mem0rd = &(g_memory_ptr[k << 16]); + if((k == 0) && ALTZP) { + mem0rd += 0x10000; + } + if((g_c035_shadow_reg & 0x40) == 0) { + if(RDROM) { + mem0rd = &(g_rom_fc_ff_ptr[0x30000]); + } + } + for(j = 0xe0; j < 0x100; j++) { + SET_PAGE_INFO_RD(j + k*0x100, mem0rd + j*0x100); + } + } - /* No need for fixup_brks() since only called from set_statereg() */ + /* No need for fixup_brks() since only called from set_statereg() */ } -void -set_statereg(double dcycs, int val) -{ - int _xor; // OG renamed xor to _xor +void set_statereg(double dcycs, int val) { + int _xor; // OG renamed xor to _xor - _xor = val ^ g_c068_statereg; - g_c068_statereg = val; - if(_xor == 0) { - return; - } + _xor = val ^ g_c068_statereg; + g_c068_statereg = val; + if(_xor == 0) { + return; + } - if(_xor & 0x80) { - /* altzp */ - fixup_altzp(); - } - if(_xor & 0x40) { - /* page2 */ - g_cur_a2_stat = (g_cur_a2_stat & ~ALL_STAT_PAGE2) | - (val & ALL_STAT_PAGE2); - fixup_page2(dcycs); - } + if(_xor & 0x80) { + /* altzp */ + fixup_altzp(); + } + if(_xor & 0x40) { + /* page2 */ + g_cur_a2_stat = (g_cur_a2_stat & ~ALL_STAT_PAGE2) | + (val & ALL_STAT_PAGE2); + fixup_page2(dcycs); + } - if(_xor & 0x20) { - /* RAMRD */ - fixup_ramrd(); - } + if(_xor & 0x20) { + /* RAMRD */ + fixup_ramrd(); + } - if(_xor & 0x10) { - /* RAMWRT */ - fixup_ramwrt(); - } + if(_xor & 0x10) { + /* RAMWRT */ + fixup_ramwrt(); + } - if(_xor & 0x08) { - /* RDROM */ - fixup_rdrom(); - } + if(_xor & 0x08) { + /* RDROM */ + fixup_rdrom(); + } - if(_xor & 0x04) { - /* LCBANK2 */ - fixup_lcbank2(); - } + if(_xor & 0x04) { + /* LCBANK2 */ + fixup_lcbank2(); + } - if(_xor & 0x02) { - /* ROMBANK */ - halt_printf("Just set rombank = %d\n", ROMB); - } + if(_xor & 0x02) { + /* ROMBANK */ + halt_printf("Just set rombank = %d\n", ROMB); + } - if(_xor & 0x01) { - fixup_intcx(); - } + if(_xor & 0x01) { + fixup_intcx(); + } - if(_xor) { - fixup_brks(); - } + if(_xor) { + fixup_brks(); + } } -void -fixup_shadow_txt1() -{ - byte *mem0wr; - int j; +void fixup_shadow_txt1() { + byte *mem0wr; + int j; - fixup_bank0_0400_0800(); + fixup_bank0_0400_0800(); - mem0wr = &(g_memory_ptr[0x10000]); - if((g_c035_shadow_reg & 0x01) == 0) { - mem0wr += BANK_SHADOW2; - } - for(j = 4; j < 8; j++) { - SET_PAGE_INFO_WR(0x100 + j, mem0wr + j*0x100); - } + mem0wr = &(g_memory_ptr[0x10000]); + if((g_c035_shadow_reg & 0x01) == 0) { + mem0wr += BANK_SHADOW2; + } + for(j = 4; j < 8; j++) { + SET_PAGE_INFO_WR(0x100 + j, mem0wr + j*0x100); + } } -void -fixup_shadow_txt2() -{ - byte *mem0wr; - int shadow; - int j; +void fixup_shadow_txt2() { + byte *mem0wr; + int shadow; + int j; - /* bank 0 */ - mem0wr = &(g_memory_ptr[0x00000]); - shadow = BANK_SHADOW; - if(RAMWRT) { - mem0wr += 0x10000; - shadow = BANK_SHADOW2; - } - if(((g_c035_shadow_reg & 0x20) == 0) && - ((g_rom_version >= 3) || g_user_page2_shadow)) { - mem0wr += shadow; - } - for(j = 8; j < 0xc; j++) { - SET_PAGE_INFO_WR(j, mem0wr + j*0x100); - } + /* bank 0 */ + mem0wr = &(g_memory_ptr[0x00000]); + shadow = BANK_SHADOW; + if(RAMWRT) { + mem0wr += 0x10000; + shadow = BANK_SHADOW2; + } + if(((g_c035_shadow_reg & 0x20) == 0) && + ((g_rom_version >= 3) || g_user_page2_shadow)) { + mem0wr += shadow; + } + for(j = 8; j < 0xc; j++) { + SET_PAGE_INFO_WR(j, mem0wr + j*0x100); + } - /* and bank 1 */ - mem0wr = &(g_memory_ptr[0x10000]); - if(((g_c035_shadow_reg & 0x20) == 0) && - ((g_rom_version >= 3) || g_user_page2_shadow)) { - mem0wr += BANK_SHADOW2; - } - for(j = 8; j < 0xc; j++) { - SET_PAGE_INFO_WR(0x100 + j, mem0wr + j*0x100); - } + /* and bank 1 */ + mem0wr = &(g_memory_ptr[0x10000]); + if(((g_c035_shadow_reg & 0x20) == 0) && + ((g_rom_version >= 3) || g_user_page2_shadow)) { + mem0wr += BANK_SHADOW2; + } + for(j = 8; j < 0xc; j++) { + SET_PAGE_INFO_WR(0x100 + j, mem0wr + j*0x100); + } } -void -fixup_shadow_hires1() -{ - byte *mem0wr; - int j; +void fixup_shadow_hires1() { + byte *mem0wr; + int j; - fixup_bank0_2000_4000(); + fixup_bank0_2000_4000(); - /* and bank 1 */ - mem0wr = &(g_memory_ptr[0x10000]); - if((g_c035_shadow_reg & 0x12) == 0 || (g_c035_shadow_reg & 0x8) == 0) { - mem0wr += BANK_SHADOW2; - } - for(j = 0x20; j < 0x40; j++) { - SET_PAGE_INFO_WR(0x100 + j, mem0wr + j*0x100); - } + /* and bank 1 */ + mem0wr = &(g_memory_ptr[0x10000]); + if((g_c035_shadow_reg & 0x12) == 0 || (g_c035_shadow_reg & 0x8) == 0) { + mem0wr += BANK_SHADOW2; + } + for(j = 0x20; j < 0x40; j++) { + SET_PAGE_INFO_WR(0x100 + j, mem0wr + j*0x100); + } } -void -fixup_shadow_hires2() -{ - byte *mem0wr; - int j; +void fixup_shadow_hires2() { + byte *mem0wr; + int j; - /* bank 0 */ - mem0wr = &(g_memory_ptr[0x00000]); - if(RAMWRT) { - mem0wr += 0x10000; - if((g_c035_shadow_reg & 0x14) == 0 || - (g_c035_shadow_reg & 0x8) == 0) { - mem0wr += BANK_SHADOW2; - } - } else if((g_c035_shadow_reg & 0x04) == 0) { - mem0wr += BANK_SHADOW; - } - for(j = 0x40; j < 0x60; j++) { - SET_PAGE_INFO_WR(j, mem0wr + j*0x100); - } + /* bank 0 */ + mem0wr = &(g_memory_ptr[0x00000]); + if(RAMWRT) { + mem0wr += 0x10000; + if((g_c035_shadow_reg & 0x14) == 0 || + (g_c035_shadow_reg & 0x8) == 0) { + mem0wr += BANK_SHADOW2; + } + } else if((g_c035_shadow_reg & 0x04) == 0) { + mem0wr += BANK_SHADOW; + } + for(j = 0x40; j < 0x60; j++) { + SET_PAGE_INFO_WR(j, mem0wr + j*0x100); + } - /* and bank 1 */ - mem0wr = &(g_memory_ptr[0x10000]); - if((g_c035_shadow_reg & 0x14) == 0 || (g_c035_shadow_reg & 0x8) == 0) { - mem0wr += BANK_SHADOW2; - } - for(j = 0x40; j < 0x60; j++) { - SET_PAGE_INFO_WR(0x100 + j, mem0wr + j*0x100); - } + /* and bank 1 */ + mem0wr = &(g_memory_ptr[0x10000]); + if((g_c035_shadow_reg & 0x14) == 0 || (g_c035_shadow_reg & 0x8) == 0) { + mem0wr += BANK_SHADOW2; + } + for(j = 0x40; j < 0x60; j++) { + SET_PAGE_INFO_WR(0x100 + j, mem0wr + j*0x100); + } } -void -fixup_shadow_shr() -{ - byte *mem0wr; - int j; +void fixup_shadow_shr() { + byte *mem0wr; + int j; - /* bank 0, only pages 0x60 - 0xa0 */ - mem0wr = &(g_memory_ptr[0x00000]); - if(RAMWRT) { - mem0wr += 0x10000; - if((g_c035_shadow_reg & 0x8) == 0) { - mem0wr += BANK_SHADOW2; - } - } - for(j = 0x60; j < 0xa0; j++) { - SET_PAGE_INFO_WR(j, mem0wr + j*0x100); - } + /* bank 0, only pages 0x60 - 0xa0 */ + mem0wr = &(g_memory_ptr[0x00000]); + if(RAMWRT) { + mem0wr += 0x10000; + if((g_c035_shadow_reg & 0x8) == 0) { + mem0wr += BANK_SHADOW2; + } + } + for(j = 0x60; j < 0xa0; j++) { + SET_PAGE_INFO_WR(j, mem0wr + j*0x100); + } - /* and bank 1, only pages 0x60 - 0xa0 */ - mem0wr = &(g_memory_ptr[0x10000]); - if((g_c035_shadow_reg & 0x8) == 0) { - mem0wr += BANK_SHADOW2; - } - for(j = 0x60; j < 0xa0; j++) { - SET_PAGE_INFO_WR(0x100 + j, mem0wr + j*0x100); - } + /* and bank 1, only pages 0x60 - 0xa0 */ + mem0wr = &(g_memory_ptr[0x10000]); + if((g_c035_shadow_reg & 0x8) == 0) { + mem0wr += BANK_SHADOW2; + } + for(j = 0x60; j < 0xa0; j++) { + SET_PAGE_INFO_WR(0x100 + j, mem0wr + j*0x100); + } } -void -fixup_shadow_iolc() -{ - byte *mem0rd; - int k; +void fixup_shadow_iolc() { + byte *mem0rd; + int k; - if(g_c035_shadow_reg & 0x40) { - /* Disable language card area */ - for(k = 0; k < 2; k++) { - mem0rd = &(g_memory_ptr[k << 16]); - fixup_any_bank_any_page((k << 8) + 0xc0, 0x10, - mem0rd + 0xd000, mem0rd + 0xd000); - if(k == 0 && ALTZP) { - mem0rd += 0x10000; - } - fixup_any_bank_any_page((k << 8) + 0xd0, 0x10, - mem0rd + 0xc000, mem0rd + 0xc000); - fixup_any_bank_any_page((k << 8) + 0xe0, 0x20, - mem0rd + 0xe000, mem0rd + 0xe000); - } - } else { - /* 0xc000 area */ - fixup_intcx(); + if(g_c035_shadow_reg & 0x40) { + /* Disable language card area */ + for(k = 0; k < 2; k++) { + mem0rd = &(g_memory_ptr[k << 16]); + fixup_any_bank_any_page((k << 8) + 0xc0, 0x10, + mem0rd + 0xd000, mem0rd + 0xd000); + if(k == 0 && ALTZP) { + mem0rd += 0x10000; + } + fixup_any_bank_any_page((k << 8) + 0xd0, 0x10, + mem0rd + 0xc000, mem0rd + 0xc000); + fixup_any_bank_any_page((k << 8) + 0xe0, 0x20, + mem0rd + 0xe000, mem0rd + 0xe000); + } + } else { + /* 0xc000 area */ + fixup_intcx(); - /* 0xd000 area */ - /* fixup_lcbank2(); -- not needed since fixup_rdrom does it */ + /* 0xd000 area */ + /* fixup_lcbank2(); -- not needed since fixup_rdrom does it */ - /* Fix 0xd000-0xffff for reads, banks 0 and 1 */ - fixup_rdrom(); /* which calls fixup_lcbank2 */ + /* Fix 0xd000-0xffff for reads, banks 0 and 1 */ + fixup_rdrom(); /* which calls fixup_lcbank2 */ - /* Fix 0xd000-0xffff for writes, banks 0 and 1 */ - fixup_wrdefram(g_c08x_wrdefram); - } + /* Fix 0xd000-0xffff for writes, banks 0 and 1 */ + fixup_wrdefram(g_c08x_wrdefram); + } } -void -update_shadow_reg(int val) -{ - int _xor; +void update_shadow_reg(int val) { + int _xor; - if(g_c035_shadow_reg == val) { - return; - } + if(g_c035_shadow_reg == val) { + return; + } - _xor = g_c035_shadow_reg ^ val; - g_c035_shadow_reg = val; + _xor = g_c035_shadow_reg ^ val; + g_c035_shadow_reg = val; - if(_xor & 8) { - fixup_shadow_hires1(); - fixup_shadow_hires2(); - fixup_shadow_shr(); - _xor = _xor & (~0x16); - } - if(_xor & 0x10) { - fixup_shadow_hires1(); - fixup_shadow_hires2(); - _xor = _xor & (~0x6); - } - if(_xor & 2) { - fixup_shadow_hires1(); - } - if(_xor & 4) { - fixup_shadow_hires2(); - } - if(_xor & 1) { - fixup_shadow_txt1(); - } - if((_xor & 0x20) && ((g_rom_version >= 3) || g_user_page2_shadow)) { - fixup_shadow_txt2(); - } - if(_xor & 0x40) { - fixup_shadow_iolc(); - } - if(_xor) { - fixup_brks(); - } + if(_xor & 8) { + fixup_shadow_hires1(); + fixup_shadow_hires2(); + fixup_shadow_shr(); + _xor = _xor & (~0x16); + } + if(_xor & 0x10) { + fixup_shadow_hires1(); + fixup_shadow_hires2(); + _xor = _xor & (~0x6); + } + if(_xor & 2) { + fixup_shadow_hires1(); + } + if(_xor & 4) { + fixup_shadow_hires2(); + } + if(_xor & 1) { + fixup_shadow_txt1(); + } + if((_xor & 0x20) && ((g_rom_version >= 3) || g_user_page2_shadow)) { + fixup_shadow_txt2(); + } + if(_xor & 0x40) { + fixup_shadow_iolc(); + } + if(_xor) { + fixup_brks(); + } } -void -fixup_shadow_all_banks() -{ - byte *mem0rd; - int shadow; - int num_banks; - int j, k; +void fixup_shadow_all_banks() { + byte *mem0rd; + int shadow; + int num_banks; + int j, k; - /* Assume Ninja Force Megademo */ - /* only do banks 3 - num_banks by 2, shadowing into e1 */ + /* Assume Ninja Force Megademo */ + /* only do banks 3 - num_banks by 2, shadowing into e1 */ - shadow = 0; - if((g_c036_val_speed & 0x10) && ((g_c035_shadow_reg & 0x08) == 0)) { - shadow = BANK_SHADOW2; - } - num_banks = g_mem_size_total >> 16; - for(k = 3; k < num_banks; k += 2) { - mem0rd = &(g_memory_ptr[k*0x10000 + 0x2000]) + shadow; - for(j = 0x20; j < 0xa0; j++) { - SET_PAGE_INFO_WR(k*0x100 + j, mem0rd); - mem0rd += 0x100; - } - } + shadow = 0; + if((g_c036_val_speed & 0x10) && ((g_c035_shadow_reg & 0x08) == 0)) { + shadow = BANK_SHADOW2; + } + num_banks = g_mem_size_total >> 16; + for(k = 3; k < num_banks; k += 2) { + mem0rd = &(g_memory_ptr[k*0x10000 + 0x2000]) + shadow; + for(j = 0x20; j < 0xa0; j++) { + SET_PAGE_INFO_WR(k*0x100 + j, mem0rd); + mem0rd += 0x100; + } + } - fixup_brks(); + fixup_brks(); } -void -setup_pageinfo() -{ - byte *mem0rd; - word32 mem_size_pages; +void setup_pageinfo() { + byte *mem0rd; + word32 mem_size_pages; - /* first, set all of memory to point to itself */ - - mem_size_pages = g_mem_size_total >> 8; - mem0rd = &(g_memory_ptr[0]); - fixup_any_bank_any_page(0, mem_size_pages, mem0rd, mem0rd); + /* first, set all of memory to point to itself */ - /* mark unused memory as BAD_MEM */ - fixup_any_bank_any_page(mem_size_pages, 0xfc00-mem_size_pages, - BANK_BAD_MEM, BANK_BAD_MEM); + mem_size_pages = g_mem_size_total >> 8; + mem0rd = &(g_memory_ptr[0]); + fixup_any_bank_any_page(0, mem_size_pages, mem0rd, mem0rd); - fixup_shadow_all_banks(); + /* mark unused memory as BAD_MEM */ + fixup_any_bank_any_page(mem_size_pages, 0xfc00-mem_size_pages, + BANK_BAD_MEM, BANK_BAD_MEM); - /* ROM */ - mem0rd = &(g_rom_fc_ff_ptr[0]); - fixup_any_bank_any_page(0xfc00, 0x400, mem0rd, - mem0rd + (BANK_IO_TMP | BANK_IO2_TMP)); + fixup_shadow_all_banks(); - /* banks e0, e1 */ - mem0rd = &(g_slow_memory_ptr[0]); - fixup_any_bank_any_page(0xe000, 0x04, mem0rd + 0x0000, mem0rd + 0x0000); - fixup_any_bank_any_page(0xe004, 0x08, mem0rd + 0x0400, - mem0rd + 0x0400 + BANK_SHADOW); - fixup_any_bank_any_page(0xe00c, 0x14, mem0rd + 0x0c00, mem0rd + 0x0c00); - fixup_any_bank_any_page(0xe020, 0x40, mem0rd + 0x2000, - mem0rd + 0x2000 + BANK_SHADOW); - fixup_any_bank_any_page(0xe060, 0xa0, mem0rd + 0x6000, mem0rd + 0x6000); + /* ROM */ + mem0rd = &(g_rom_fc_ff_ptr[0]); + fixup_any_bank_any_page(0xfc00, 0x400, mem0rd, + mem0rd + (BANK_IO_TMP | BANK_IO2_TMP)); - mem0rd = &(g_slow_memory_ptr[0x10000]); - fixup_any_bank_any_page(0xe100, 0x04, mem0rd + 0x0000, mem0rd + 0x0000); - fixup_any_bank_any_page(0xe104, 0x08, mem0rd + 0x0400, - mem0rd + 0x0400 + BANK_SHADOW2); - fixup_any_bank_any_page(0xe10c, 0x14, mem0rd + 0x0c00, mem0rd + 0x0c00); - fixup_any_bank_any_page(0xe120, 0x80, mem0rd + 0x2000, - mem0rd + 0x2000 + BANK_SHADOW2); - fixup_any_bank_any_page(0xe1a0, 0x60, mem0rd + 0xa000, mem0rd + 0xa000); + /* banks e0, e1 */ + mem0rd = &(g_slow_memory_ptr[0]); + fixup_any_bank_any_page(0xe000, 0x04, mem0rd + 0x0000, mem0rd + 0x0000); + fixup_any_bank_any_page(0xe004, 0x08, mem0rd + 0x0400, + mem0rd + 0x0400 + BANK_SHADOW); + fixup_any_bank_any_page(0xe00c, 0x14, mem0rd + 0x0c00, mem0rd + 0x0c00); + fixup_any_bank_any_page(0xe020, 0x40, mem0rd + 0x2000, + mem0rd + 0x2000 + BANK_SHADOW); + fixup_any_bank_any_page(0xe060, 0xa0, mem0rd + 0x6000, mem0rd + 0x6000); - fixup_intcx(); /* correct banks 0xe0,0xe1, 0xc000-0xcfff area */ - fixup_lcbank2(); /* correct 0xd000-0xdfff area */ + mem0rd = &(g_slow_memory_ptr[0x10000]); + fixup_any_bank_any_page(0xe100, 0x04, mem0rd + 0x0000, mem0rd + 0x0000); + fixup_any_bank_any_page(0xe104, 0x08, mem0rd + 0x0400, + mem0rd + 0x0400 + BANK_SHADOW2); + fixup_any_bank_any_page(0xe10c, 0x14, mem0rd + 0x0c00, mem0rd + 0x0c00); + fixup_any_bank_any_page(0xe120, 0x80, mem0rd + 0x2000, + mem0rd + 0x2000 + BANK_SHADOW2); + fixup_any_bank_any_page(0xe1a0, 0x60, mem0rd + 0xa000, mem0rd + 0xa000); - fixup_bank0_2000_4000(); - fixup_bank0_0400_0800(); - fixup_wrdefram(g_c08x_wrdefram); - fixup_altzp(); - fixup_ramrd(); - fixup_ramwrt(); - fixup_rdrom(); - fixup_shadow_txt1(); - fixup_shadow_txt2(); - fixup_shadow_hires1(); - fixup_shadow_hires2(); - fixup_shadow_shr(); - fixup_shadow_iolc(); - fixup_brks(); + fixup_intcx(); /* correct banks 0xe0,0xe1, 0xc000-0xcfff area */ + fixup_lcbank2(); /* correct 0xd000-0xdfff area */ -#ifdef TRANSWARP // OG adding Transwarp code - SET_PAGE_INFO_RD(0xBCFF,transwarpcode); + fixup_bank0_2000_4000(); + fixup_bank0_0400_0800(); + fixup_wrdefram(g_c08x_wrdefram); + fixup_altzp(); + fixup_ramrd(); + fixup_ramwrt(); + fixup_rdrom(); + fixup_shadow_txt1(); + fixup_shadow_txt2(); + fixup_shadow_hires1(); + fixup_shadow_hires2(); + fixup_shadow_shr(); + fixup_shadow_iolc(); + fixup_brks(); + +#ifdef TRANSWARP // OG adding Transwarp code + SET_PAGE_INFO_RD(0xBCFF,transwarpcode); #endif } -void -show_bankptrs_bank0rdwr() -{ - show_bankptrs(0); - show_bankptrs(1); - show_bankptrs(0xe0); - show_bankptrs(0xe1); - printf("statereg: %02x\n", g_c068_statereg); +void show_bankptrs_bank0rdwr() { + show_bankptrs(0); + show_bankptrs(1); + show_bankptrs(0xe0); + show_bankptrs(0xe1); + printf("statereg: %02x\n", g_c068_statereg); } -void -show_bankptrs(int bnk) -{ - int i; - Pg_info rd, wr; - byte *ptr_rd, *ptr_wr; +void show_bankptrs(int bnk) { + int i; + Pg_info rd, wr; + byte *ptr_rd, *ptr_wr; - printf("g_memory_ptr: %p, dummy_mem: %p, slow_mem_ptr: %p\n", - g_memory_ptr, g_dummy_memory1_ptr, g_slow_memory_ptr); - printf("g_rom_fc_ff_ptr: %p\n", g_rom_fc_ff_ptr); + printf("g_memory_ptr: %p, dummy_mem: %p, slow_mem_ptr: %p\n", + g_memory_ptr, g_dummy_memory1_ptr, g_slow_memory_ptr); + printf("g_rom_fc_ff_ptr: %p\n", g_rom_fc_ff_ptr); - printf("Showing bank_info array for %02x\n", bnk); - for(i = 0; i < 256; i++) { - rd = GET_PAGE_INFO_RD(bnk*0x100 + i); - wr = GET_PAGE_INFO_WR(bnk*0x100 + i); - ptr_rd = (byte *)rd; - ptr_wr = (byte *)wr; - printf("%04x rd: ", bnk*256 + i); - show_addr(ptr_rd); - printf(" wr: "); - show_addr(ptr_wr); - printf("\n"); - } -} - -void -show_addr(byte *ptr) -{ - word32 mem_size; - - mem_size = g_mem_size_total; - if(ptr >= g_memory_ptr && ptr < &g_memory_ptr[mem_size]) { - printf("%p--memory[%06x]", ptr, - (word32)(ptr - g_memory_ptr)); - } else if(ptr >= g_rom_fc_ff_ptr && ptr < &g_rom_fc_ff_ptr[256*1024]) { - printf("%p--rom_fc_ff[%06x]", ptr, - (word32)(ptr - g_rom_fc_ff_ptr)); - } else if(ptr >= g_slow_memory_ptr && ptr<&g_slow_memory_ptr[128*1024]){ - printf("%p--slow_memory[%06x]", ptr, - (word32)(ptr - g_slow_memory_ptr)); - } else if(ptr >=g_dummy_memory1_ptr && ptr < &g_dummy_memory1_ptr[256]){ - printf("%p--dummy_memory[%06x]", ptr, - (word32)(ptr - g_dummy_memory1_ptr)); - } else { - printf("%p--unknown", ptr); - } + printf("Showing bank_info array for %02x\n", bnk); + for(i = 0; i < 256; i++) { + rd = GET_PAGE_INFO_RD(bnk*0x100 + i); + wr = GET_PAGE_INFO_WR(bnk*0x100 + i); + ptr_rd = (byte *)rd; + ptr_wr = (byte *)wr; + printf("%04x rd: ", bnk*256 + i); + show_addr(ptr_rd); + printf(" wr: "); + show_addr(ptr_wr); + printf("\n"); + } } -#define CALC_DCYCS_FROM_CYC_PTR(dcycs, cyc_ptr, fcyc, new_fcyc) \ - dcycs = g_last_vbl_dcycs + *cyc_ptr; +// function to get the pointer to memory where a gs page is located - db +unsigned char * get_page_ptr_rd(int addr) { + Pg_info rd; + byte *ptr_rd; + + int bank = ( addr & 0xFF0000 ) >> 16; // unnecessary conversion that we throw away below w/ "*0x100" + int page = ( addr & 0x00FF00 ) >> 8; + rd = GET_PAGE_INFO_RD(bank*0x100 + page); + ptr_rd = (byte *)rd; + //printf("ADDR %06x at pageptr %p\n",addr, ptr_rd); // seems to be correct. + /* code */ + return rd; +} + +// function to get a byte from a 24bit address - db +int get_byte_at_address(int addr) { + unsigned char *page_ptr_rd = get_page_ptr_rd(addr); + int offset = addr & 0xff; + int mem_byte = page_ptr_rd[offset] & 0xff; + //printf("0x%06X = $%02X \t(dec) %d\n", addr, (int) mem_byte, (int) mem_byte); + return (int) mem_byte; +} + +// function to set a byte from a 24bit address - db +void set_byte_at_address(int addr, int value) { + unsigned char *page_ptr_rd = get_page_ptr_rd(addr); + int offset = addr & 0xff; + page_ptr_rd[offset] = value; + +} -int -io_read(word32 loc, double *cyc_ptr) -{ - double dcycs; - word64 word64_tmp; -#if 0 - double fcyc, new_fcyc; -#endif - word32 mask; - int new_lcbank2; - int new_wrdefram; - int tmp; - int i; +void show_addr(byte *ptr) { + word32 mem_size; - CALC_DCYCS_FROM_CYC_PTR(dcycs, cyc_ptr, fcyc, new_fcyc); + mem_size = g_mem_size_total; + if(ptr >= g_memory_ptr && ptr < &g_memory_ptr[mem_size]) { + printf("%p--memory[%06x]", ptr, + (word32)(ptr - g_memory_ptr)); + } else if(ptr >= g_rom_fc_ff_ptr && ptr < &g_rom_fc_ff_ptr[256*1024]) { + printf("%p--rom_fc_ff[%06x]", ptr, + (word32)(ptr - g_rom_fc_ff_ptr)); + } else if(ptr >= g_slow_memory_ptr && ptr<&g_slow_memory_ptr[128*1024]) { + printf("%p--slow_memory[%06x]", ptr, + (word32)(ptr - g_slow_memory_ptr)); + } else if(ptr >=g_dummy_memory1_ptr && ptr < &g_dummy_memory1_ptr[256]) { + printf("%p--dummy_memory[%06x]", ptr, + (word32)(ptr - g_dummy_memory1_ptr)); + } else { + printf("%p--unknown", ptr); + } +} + + +#define CALC_DCYCS_FROM_CYC_PTR(dcycs, cyc_ptr, fcyc, new_fcyc) \ + dcycs = g_last_vbl_dcycs + *cyc_ptr; + + +int io_read(word32 loc, double *cyc_ptr) { + double dcycs; + word64 word64_tmp; + word32 mask; + int new_lcbank2; + int new_wrdefram; + int tmp; + int i; + + CALC_DCYCS_FROM_CYC_PTR(dcycs, cyc_ptr, fcyc, new_fcyc); /* IO space */ - switch((loc >> 8) & 0xf) { - case 0: /* 0xc000 - 0xc0ff */ - switch(loc & 0xff) { - /* 0xc000 - 0xc00f */ - case 0x00: case 0x01: case 0x02: case 0x03: - case 0x04: case 0x05: case 0x06: case 0x07: - case 0x08: case 0x09: case 0x0a: case 0x0b: - case 0x0c: case 0x0d: case 0x0e: case 0x0f: - return(adb_read_c000()); + switch((loc >> 8) & 0xf) { + case 0: /* 0xc000 - 0xc0ff */ + switch(loc & 0xff) { + /* 0xc000 - 0xc00f */ + case 0x00: case 0x01: case 0x02: case 0x03: + case 0x04: case 0x05: case 0x06: case 0x07: + case 0x08: case 0x09: case 0x0a: case 0x0b: + case 0x0c: case 0x0d: case 0x0e: case 0x0f: + return(adb_read_c000()); - /* 0xc010 - 0xc01f */ - case 0x10: /* c010 */ - return(adb_access_c010()); - case 0x11: /* c011 = RDLCBANK2 */ - return IOR(LCBANK2); - case 0x12: /* c012= RDLCRAM */ - return IOR(!RDROM); - case 0x13: /* c013=rdramd */ - return IOR(RAMRD); - case 0x14: /* c014=rdramwrt */ - return IOR(RAMWRT); - case 0x15: /* c015 = INTCX */ - return IOR(INTCX); - case 0x16: /* c016: ALTZP */ - return IOR(ALTZP); - case 0x17: /* c017: rdc3rom */ - return IOR(g_c02d_int_crom & (1 << 3)); - case 0x18: /* c018: rd80c0l */ - return IOR((g_cur_a2_stat & ALL_STAT_ST80)); - case 0x19: /* c019: rdvblbar */ - tmp = in_vblank(dcycs); - return IOR(tmp); - case 0x1a: /* c01a: rdtext */ - return IOR(g_cur_a2_stat & ALL_STAT_TEXT); - case 0x1b: /* c01b: rdmix */ - return IOR(g_cur_a2_stat & ALL_STAT_MIX_T_GR); - case 0x1c: /* c01c: rdpage2 */ - return IOR(g_cur_a2_stat & ALL_STAT_PAGE2); - case 0x1d: /* c01d: rdhires */ - return IOR(g_cur_a2_stat & ALL_STAT_HIRES); - case 0x1e: /* c01e: altcharset on? */ - return IOR(g_cur_a2_stat & ALL_STAT_ALTCHARSET); - case 0x1f: /* c01f: rd80vid */ - return IOR(g_cur_a2_stat & ALL_STAT_VID80); + /* 0xc010 - 0xc01f */ + case 0x10: /* c010 */ + return(adb_access_c010()); + case 0x11: /* c011 = RDLCBANK2 */ + return IOR(LCBANK2); + case 0x12: /* c012= RDLCRAM */ + return IOR(!RDROM); + case 0x13: /* c013=rdramd */ + return IOR(RAMRD); + case 0x14: /* c014=rdramwrt */ + return IOR(RAMWRT); + case 0x15: /* c015 = INTCX */ + return IOR(INTCX); + case 0x16: /* c016: ALTZP */ + return IOR(ALTZP); + case 0x17: /* c017: rdc3rom */ + return IOR(g_c02d_int_crom & (1 << 3)); + case 0x18: /* c018: rd80c0l */ + return IOR((g_cur_a2_stat & ALL_STAT_ST80)); + case 0x19: /* c019: rdvblbar */ + tmp = in_vblank(dcycs); + return IOR(tmp); + case 0x1a: /* c01a: rdtext */ + return IOR(g_cur_a2_stat & ALL_STAT_TEXT); + case 0x1b: /* c01b: rdmix */ + return IOR(g_cur_a2_stat & ALL_STAT_MIX_T_GR); + case 0x1c: /* c01c: rdpage2 */ + return IOR(g_cur_a2_stat & ALL_STAT_PAGE2); + case 0x1d: /* c01d: rdhires */ + return IOR(g_cur_a2_stat & ALL_STAT_HIRES); + case 0x1e: /* c01e: altcharset on? */ + return IOR(g_cur_a2_stat & ALL_STAT_ALTCHARSET); + case 0x1f: /* c01f: rd80vid */ + return IOR(g_cur_a2_stat & ALL_STAT_VID80); - /* 0xc020 - 0xc02f */ - case 0x20: /* 0xc020 */ - /* Click cassette port */ - return float_bus(dcycs); - case 0x21: /* 0xc021 */ - /* Not documented, but let's return COLOR_C021 */ - return IOR(g_cur_a2_stat & ALL_STAT_COLOR_C021); - case 0x22: /* 0xc022 */ - return (g_cur_a2_stat >> BIT_ALL_STAT_BG_COLOR) & 0xff; - case 0x23: /* 0xc023 */ - return g_c023_val; - case 0x24: /* 0xc024 */ - return mouse_read_c024(dcycs); - case 0x25: /* 0xc025 */ - return adb_read_c025(); - case 0x26: /* 0xc026 */ - return adb_read_c026(); - case 0x27: /* 0xc027 */ - return adb_read_c027(); - case 0x28: /* 0xc028 */ - UNIMPL_READ; - case 0x29: /* 0xc029 */ - return((g_cur_a2_stat & 0xa0) | g_c029_val_some); - case 0x2a: /* 0xc02a */ + /* 0xc020 - 0xc02f */ + case 0x20: /* 0xc020 */ + /* Click cassette port */ + return float_bus(dcycs); + case 0x21: /* 0xc021 */ + /* Not documented, but let's return COLOR_C021 */ + return IOR(g_cur_a2_stat & ALL_STAT_COLOR_C021); + case 0x22: /* 0xc022 */ + return (g_cur_a2_stat >> BIT_ALL_STAT_BG_COLOR) & 0xff; + case 0x23: /* 0xc023 */ + return g_c023_val; + case 0x24: /* 0xc024 */ + return mouse_read_c024(dcycs); + case 0x25: /* 0xc025 */ + return adb_read_c025(); + case 0x26: /* 0xc026 */ + return adb_read_c026(); + case 0x27: /* 0xc027 */ + return adb_read_c027(); + case 0x28: /* 0xc028 */ + UNIMPL_READ; + case 0x29: /* 0xc029 */ + return((g_cur_a2_stat & 0xa0) | g_c029_val_some); + case 0x2a: /* 0xc02a */ #if 0 - printf("Reading c02a...returning 0\n"); + printf("Reading c02a...returning 0\n"); #endif - return 0; - case 0x2b: /* 0xc02b */ - return g_c02b_val; - case 0x2c: /* 0xc02c */ - /* printf("reading c02c, returning 0\n"); */ - return 0; - case 0x2d: /* 0xc02d */ - tmp = g_c02d_int_crom; - return tmp; - case 0x2e: /* 0xc02e */ - case 0x2f: /* 0xc02f */ - return read_vid_counters(loc, dcycs); + return 0; + case 0x2b: /* 0xc02b */ + return g_c02b_val; + case 0x2c: /* 0xc02c */ + /* printf("reading c02c, returning 0\n"); */ + return 0; + case 0x2d: /* 0xc02d */ + tmp = g_c02d_int_crom; + return tmp; + case 0x2e: /* 0xc02e */ + case 0x2f: /* 0xc02f */ + return read_vid_counters(loc, dcycs); - /* 0xc030 - 0xc03f */ - case 0x30: /* 0xc030 */ - /* click speaker */ - doc_read_c030(dcycs); - return float_bus(dcycs); - case 0x31: /* 0xc031 */ - /* 3.5" control */ - return g_c031_disk35; - case 0x32: /* 0xc032 */ - /* scan int */ - return 0; - case 0x33: /* 0xc033 = CLOCKDATA*/ - return g_c033_data; - case 0x34: /* 0xc034 = CLOCKCTL */ - return g_c034_val; - case 0x35: /* 0xc035 */ - return g_c035_shadow_reg; - case 0x36: /* 0xc036 = CYAREG */ - return g_c036_val_speed; - case 0x37: /* 0xc037 */ - return 0; - case 0x38: /* 0xc038 */ - return scc_read_reg(1, dcycs); - case 0x39: /* 0xc039 */ - return scc_read_reg(0, dcycs); - case 0x3a: /* 0xc03a */ - return scc_read_data(1, dcycs); - case 0x3b: /* 0xc03b */ - return scc_read_data(0, dcycs); - case 0x3c: /* 0xc03c */ - /* doc control */ - return doc_read_c03c(dcycs); - case 0x3d: /* 0xc03d */ - return doc_read_c03d(dcycs); - case 0x3e: /* 0xc03e */ - return (g_c03ef_doc_ptr & 0xff); - case 0x3f: /* 0xc03f */ - return (g_c03ef_doc_ptr >> 8); + /* 0xc030 - 0xc03f */ + case 0x30: /* 0xc030 */ + /* click speaker */ + doc_read_c030(dcycs); + return float_bus(dcycs); + case 0x31: /* 0xc031 */ + /* 3.5" control */ + return g_c031_disk35; + case 0x32: /* 0xc032 */ + /* scan int */ + return 0; + case 0x33: /* 0xc033 = CLOCKDATA*/ + return g_c033_data; + case 0x34: /* 0xc034 = CLOCKCTL */ + return g_c034_val; + case 0x35: /* 0xc035 */ + return g_c035_shadow_reg; + case 0x36: /* 0xc036 = CYAREG */ + return g_c036_val_speed; + case 0x37: /* 0xc037 */ + return 0; + case 0x38: /* 0xc038 */ + return scc_read_reg(1, dcycs); + case 0x39: /* 0xc039 */ + return scc_read_reg(0, dcycs); + case 0x3a: /* 0xc03a */ + return scc_read_data(1, dcycs); + case 0x3b: /* 0xc03b */ + return scc_read_data(0, dcycs); + case 0x3c: /* 0xc03c */ + /* doc control */ + return doc_read_c03c(dcycs); + case 0x3d: /* 0xc03d */ + return doc_read_c03d(dcycs); + case 0x3e: /* 0xc03e */ + return (g_c03ef_doc_ptr & 0xff); + case 0x3f: /* 0xc03f */ + return (g_c03ef_doc_ptr >> 8); - /* 0xc040 - 0xc04f */ - case 0x40: /* 0xc040 */ - /* cassette */ - return 0; - case 0x41: /* 0xc041 */ - return g_c041_val; - case 0x44: /* 0xc044 */ - // SCC LAD A - return scc_read_lad(0); - case 0x45: /* 0xc045 */ - // SCC LAD B - return scc_read_lad(1); - case 0x46: /* 0xc046 */ - tmp = g_c046_val; - g_c046_val = (tmp & 0xbf) + ((tmp & 0x80) >> 1); - return tmp; - case 0x47: /* 0xc047 */ - remove_irq(IRQ_PENDING_C046_25SEC | - IRQ_PENDING_C046_VBL); - g_c046_val &= 0xe7; /* clear vbl_int, 1/4sec int*/ - return 0; - case 0x42: /* 0xc042 */ - case 0x43: /* 0xc043 */ - return 0; - case 0x4f: /* 0xc04f */ - /* for information on c04f, see: */ - /* www.sheppyware.net/tech/hardware/softswitches.html */ - /* write to $c04f to start. Then read $c04f to get */ - /* emulator ($16=sweet16, $fe=bernie II). */ - /* Then read again to get version: $21 == 2.1 */ - switch(g_em_emubyte_cnt) { - case 1: - g_em_emubyte_cnt = 2; - return 'G'; - case 2: - g_em_emubyte_cnt = 0; - tmp = g_gsport_version_str[0] - '0'; - i = g_gsport_version_str[2] - '0'; - return ((tmp & 0xf) << 4) + (i & 0xf); - default: - g_em_emubyte_cnt = 0; - return 0; - } - case 0x48: /* 0xc048 */ - case 0x49: /* 0xc049 */ - case 0x4a: /* 0xc04a */ - case 0x4b: /* 0xc04b */ - case 0x4c: /* 0xc04c */ - case 0x4d: /* 0xc04d */ - case 0x4e: /* 0xc04e */ - UNIMPL_READ; + /* 0xc040 - 0xc04f */ + case 0x40: /* 0xc040 */ + /* cassette */ + return 0; + case 0x41: /* 0xc041 */ + return g_c041_val; + case 0x44: /* 0xc044 */ + // SCC LAD A + return scc_read_lad(0); + case 0x45: /* 0xc045 */ + // SCC LAD B + return scc_read_lad(1); + case 0x46: /* 0xc046 */ + tmp = g_c046_val; + g_c046_val = (tmp & 0xbf) + ((tmp & 0x80) >> 1); + return tmp; + case 0x47: /* 0xc047 */ + remove_irq(IRQ_PENDING_C046_25SEC | + IRQ_PENDING_C046_VBL); + g_c046_val &= 0xe7; /* clear vbl_int, 1/4sec int*/ + return 0; + case 0x42: /* 0xc042 */ + case 0x43: /* 0xc043 */ + return 0; + case 0x4f: /* 0xc04f */ + /* for information on c04f, see: */ + /* www.sheppyware.net/tech/hardware/softswitches.html */ + /* write to $c04f to start. Then read $c04f to get */ + /* emulator ($16=sweet16, $fe=bernie II). */ + /* Then read again to get version: $21 == 2.1 */ + switch(g_em_emubyte_cnt) { + case 1: + g_em_emubyte_cnt = 2; + return 'G'; + case 2: + g_em_emubyte_cnt = 0; + tmp = g_gsport_version_str[0] - '0'; + i = g_gsport_version_str[2] - '0'; + return ((tmp & 0xf) << 4) + (i & 0xf); + default: + g_em_emubyte_cnt = 0; + return 0; + } + case 0x48: /* 0xc048 */ + case 0x49: /* 0xc049 */ + case 0x4a: /* 0xc04a */ + case 0x4b: /* 0xc04b */ + case 0x4c: /* 0xc04c */ + case 0x4d: /* 0xc04d */ + case 0x4e: /* 0xc04e */ + UNIMPL_READ; - /* 0xc050 - 0xc05f */ - case 0x50: /* 0xc050 */ - if(g_cur_a2_stat & ALL_STAT_TEXT) { - g_cur_a2_stat &= (~ALL_STAT_TEXT); - change_display_mode(dcycs); - } - return float_bus(dcycs); - case 0x51: /* 0xc051 */ - if((g_cur_a2_stat & ALL_STAT_TEXT) == 0) { - g_cur_a2_stat |= (ALL_STAT_TEXT); - change_display_mode(dcycs); - } - return float_bus(dcycs); - case 0x52: /* 0xc052 */ - if(g_cur_a2_stat & ALL_STAT_MIX_T_GR) { - g_cur_a2_stat &= (~ALL_STAT_MIX_T_GR); - change_display_mode(dcycs); - } - return float_bus(dcycs); - case 0x53: /* 0xc053 */ - if((g_cur_a2_stat & ALL_STAT_MIX_T_GR) == 0) { - g_cur_a2_stat |= (ALL_STAT_MIX_T_GR); - change_display_mode(dcycs); - } - return float_bus(dcycs); - case 0x54: /* 0xc054 */ - set_statereg(dcycs, g_c068_statereg & (~0x40)); - return float_bus(dcycs); - case 0x55: /* 0xc055 */ - set_statereg(dcycs, g_c068_statereg | 0x40); - return float_bus(dcycs); - case 0x56: /* 0xc056 */ - if(g_cur_a2_stat & ALL_STAT_HIRES) { - g_cur_a2_stat &= (~ALL_STAT_HIRES); - fixup_hires_on(); - change_display_mode(dcycs); - } - return float_bus(dcycs); - case 0x57: /* 0xc057 */ - if((g_cur_a2_stat & ALL_STAT_HIRES) == 0) { - g_cur_a2_stat |= (ALL_STAT_HIRES); - fixup_hires_on(); - change_display_mode(dcycs); - } - return float_bus(dcycs); - case 0x58: /* 0xc058 */ - if(g_zipgs_unlock < 4) { - g_c05x_annuncs &= (~1); - } - return 0; - case 0x59: /* 0xc059 */ - if(g_zipgs_unlock >= 4) { - return g_zipgs_reg_c059; - } else { - g_c05x_annuncs |= 1; - } - return 0; - case 0x5a: /* 0xc05a */ - if(g_zipgs_unlock >= 4) { - return g_zipgs_reg_c05a; - } else { - g_c05x_annuncs &= (~2); - } - return 0; - case 0x5b: /* 0xc05b */ - if(g_zipgs_unlock >= 4) { - word64_tmp = (word64)dcycs; - tmp = (word64_tmp >> 9) & 1; - return (tmp << 7) + (g_zipgs_reg_c05b & 0x7f); - } else { - g_c05x_annuncs |= 2; - } - return 0; - case 0x5c: /* 0xc05c */ - if(g_zipgs_unlock >= 4) { - return g_zipgs_reg_c05c; - } else { - g_c05x_annuncs &= (~4); - } - return 0; - case 0x5d: /* 0xc05d */ - if(g_zipgs_unlock >= 4) { - halt_printf("Reading ZipGS $c05d!\n"); - } else { - g_c05x_annuncs |= 4; - } - return 0; - case 0x5e: /* 0xc05e */ - if(g_zipgs_unlock >= 4) { - halt_printf("Reading ZipGS $c05e!\n"); - } else if(g_cur_a2_stat & ALL_STAT_ANNUNC3) { - g_cur_a2_stat &= (~ALL_STAT_ANNUNC3); - change_display_mode(dcycs); - } - return 0; - case 0x5f: /* 0xc05f */ - if(g_zipgs_unlock >= 4) { - halt_printf("Reading ZipGS $c05f!\n"); - } else if((g_cur_a2_stat & ALL_STAT_ANNUNC3) == 0) { - g_cur_a2_stat |= (ALL_STAT_ANNUNC3); - change_display_mode(dcycs); - } - return 0; + /* 0xc050 - 0xc05f */ + case 0x50: /* 0xc050 */ + if(g_cur_a2_stat & ALL_STAT_TEXT) { + g_cur_a2_stat &= (~ALL_STAT_TEXT); + change_display_mode(dcycs); + } + return float_bus(dcycs); + case 0x51: /* 0xc051 */ + if((g_cur_a2_stat & ALL_STAT_TEXT) == 0) { + g_cur_a2_stat |= (ALL_STAT_TEXT); + change_display_mode(dcycs); + } + return float_bus(dcycs); + case 0x52: /* 0xc052 */ + if(g_cur_a2_stat & ALL_STAT_MIX_T_GR) { + g_cur_a2_stat &= (~ALL_STAT_MIX_T_GR); + change_display_mode(dcycs); + } + return float_bus(dcycs); + case 0x53: /* 0xc053 */ + if((g_cur_a2_stat & ALL_STAT_MIX_T_GR) == 0) { + g_cur_a2_stat |= (ALL_STAT_MIX_T_GR); + change_display_mode(dcycs); + } + return float_bus(dcycs); + case 0x54: /* 0xc054 */ + set_statereg(dcycs, g_c068_statereg & (~0x40)); + return float_bus(dcycs); + case 0x55: /* 0xc055 */ + set_statereg(dcycs, g_c068_statereg | 0x40); + return float_bus(dcycs); + case 0x56: /* 0xc056 */ + if(g_cur_a2_stat & ALL_STAT_HIRES) { + g_cur_a2_stat &= (~ALL_STAT_HIRES); + fixup_hires_on(); + change_display_mode(dcycs); + } + return float_bus(dcycs); + case 0x57: /* 0xc057 */ + if((g_cur_a2_stat & ALL_STAT_HIRES) == 0) { + g_cur_a2_stat |= (ALL_STAT_HIRES); + fixup_hires_on(); + change_display_mode(dcycs); + } + return float_bus(dcycs); + case 0x58: /* 0xc058 */ + if(g_zipgs_unlock < 4) { + g_c05x_annuncs &= (~1); + } + return 0; + case 0x59: /* 0xc059 */ + if(g_zipgs_unlock >= 4) { + return g_zipgs_reg_c059; + } else { + g_c05x_annuncs |= 1; + } + return 0; + case 0x5a: /* 0xc05a */ + if(g_zipgs_unlock >= 4) { + return g_zipgs_reg_c05a; + } else { + g_c05x_annuncs &= (~2); + } + return 0; + case 0x5b: /* 0xc05b */ + if(g_zipgs_unlock >= 4) { + word64_tmp = (word64)dcycs; + tmp = (word64_tmp >> 9) & 1; + return (tmp << 7) + (g_zipgs_reg_c05b & 0x7f); + } else { + g_c05x_annuncs |= 2; + } + return 0; + case 0x5c: /* 0xc05c */ + if(g_zipgs_unlock >= 4) { + return g_zipgs_reg_c05c; + } else { + g_c05x_annuncs &= (~4); + } + return 0; + case 0x5d: /* 0xc05d */ + if(g_zipgs_unlock >= 4) { + halt_printf("Reading ZipGS $c05d!\n"); + } else { + g_c05x_annuncs |= 4; + } + return 0; + case 0x5e: /* 0xc05e */ + if(g_zipgs_unlock >= 4) { + halt_printf("Reading ZipGS $c05e!\n"); + } else if(g_cur_a2_stat & ALL_STAT_ANNUNC3) { + g_cur_a2_stat &= (~ALL_STAT_ANNUNC3); + change_display_mode(dcycs); + } + return 0; + case 0x5f: /* 0xc05f */ + if(g_zipgs_unlock >= 4) { + halt_printf("Reading ZipGS $c05f!\n"); + } else if((g_cur_a2_stat & ALL_STAT_ANNUNC3) == 0) { + g_cur_a2_stat |= (ALL_STAT_ANNUNC3); + change_display_mode(dcycs); + } + return 0; - /* 0xc060 - 0xc06f */ - case 0x60: /* 0xc060 */ - return IOR(g_paddle_buttons & 8); - case 0x61: /* 0xc061 */ - return IOR(adb_is_cmd_key_down() || - g_paddle_buttons & 1); - case 0x62: /* 0xc062 */ - return IOR(adb_is_option_key_down() || - g_paddle_buttons & 2); - case 0x63: /* 0xc063 */ - return IOR(g_paddle_buttons & 4); - case 0x64: /* 0xc064 */ - return read_paddles(dcycs, 0); - case 0x65: /* 0xc065 */ - return read_paddles(dcycs, 1); - case 0x66: /* 0xc066 */ - return read_paddles(dcycs, 2); - case 0x67: /* 0xc067 */ - return read_paddles(dcycs, 3); - case 0x68: /* 0xc068 = STATEREG */ - return g_c068_statereg; - case 0x69: /* 0xc069 */ - /* Reserved reg, return 0 */ - return 0; - // OG Transwarp Read Interface - #ifdef TRANSWARP - case 0x6a: /* 0xc06a */ - { - extern double g_zip_pmhz; - return (int)(g_zip_pmhz*1000)&0xFF; - } - case 0x6b: /* 0xc06b */ - { - extern double g_zip_pmhz; - return (((int)(g_zip_pmhz*1000))>>8)&0xFF; - } - case 0x6c: /* 0xc06c */ - { - extern double g_zip_pmhz; - if (g_zip_pmhz==1.0) return 0; // slow - else if (g_zip_pmhz>=2.6) return 2; // warp - else return 1; // zip - } - #else - case 0x6a: /* 0xc06a */ - case 0x6b: /* 0xc06b */ - case 0x6c: /* 0xc06c */ - #endif - case 0x6d: /* 0xc06d */ - case 0x6e: /* 0xc06e */ - case 0x6f: /* 0xc06f */ - UNIMPL_READ; + /* 0xc060 - 0xc06f */ + case 0x60: /* 0xc060 */ + return IOR(g_paddle_buttons & 8); + case 0x61: /* 0xc061 */ + return IOR(adb_is_cmd_key_down() || + g_paddle_buttons & 1); + case 0x62: /* 0xc062 */ + return IOR(adb_is_option_key_down() || + g_paddle_buttons & 2); + case 0x63: /* 0xc063 */ + return IOR(g_paddle_buttons & 4); + case 0x64: /* 0xc064 */ + return read_paddles(dcycs, 0); + case 0x65: /* 0xc065 */ + return read_paddles(dcycs, 1); + case 0x66: /* 0xc066 */ + return read_paddles(dcycs, 2); + case 0x67: /* 0xc067 */ + return read_paddles(dcycs, 3); + case 0x68: /* 0xc068 = STATEREG */ + return g_c068_statereg; + case 0x69: /* 0xc069 */ + /* Reserved reg, return 0 */ + return 0; + // OG Transwarp Read Interface + #ifdef TRANSWARP + case 0x6a: /* 0xc06a */ + { + extern double g_zip_pmhz; + return (int)(g_zip_pmhz*1000)&0xFF; + } + case 0x6b: /* 0xc06b */ + { + extern double g_zip_pmhz; + return (((int)(g_zip_pmhz*1000))>>8)&0xFF; + } + case 0x6c: /* 0xc06c */ + { + extern double g_zip_pmhz; + if (g_zip_pmhz==1.0) return 0; // slow + else if (g_zip_pmhz>=2.6) return 2; // warp + else return 1; // zip + } + #else + case 0x6a: /* 0xc06a */ + case 0x6b: /* 0xc06b */ + case 0x6c: /* 0xc06c */ + #endif + case 0x6d: /* 0xc06d */ + case 0x6e: /* 0xc06e */ + case 0x6f: /* 0xc06f */ + UNIMPL_READ; - /* 0xc070 - 0xc07f */ - case 0x70: /* c070 */ - paddle_trigger(dcycs); - return 0; - case 0x71: /* 0xc071 */ - case 0x72: case 0x73: - case 0x74: case 0x75: case 0x76: case 0x77: - case 0x78: case 0x79: case 0x7a: case 0x7b: - case 0x7c: case 0x7d: case 0x7e: case 0x7f: - return g_rom_fc_ff_ptr[3*65536 + 0xc000 + (loc & 0xff)]; + /* 0xc070 - 0xc07f */ + case 0x70: /* c070 */ + paddle_trigger(dcycs); + return 0; + case 0x71: /* 0xc071 */ + case 0x72: case 0x73: + case 0x74: case 0x75: case 0x76: case 0x77: + case 0x78: case 0x79: case 0x7a: case 0x7b: + case 0x7c: case 0x7d: case 0x7e: case 0x7f: + return g_rom_fc_ff_ptr[3*65536 + 0xc000 + (loc & 0xff)]; - /* 0xc080 - 0xc08f */ - case 0x80: case 0x81: case 0x82: case 0x83: - case 0x84: case 0x85: case 0x86: case 0x87: - case 0x88: case 0x89: case 0x8a: case 0x8b: - case 0x8c: case 0x8d: case 0x8e: case 0x8f: - new_lcbank2 = ((loc & 0x8) >> 1) ^ 0x4; - new_wrdefram = (loc & 1); - if(new_wrdefram != g_c08x_wrdefram) { - fixup_wrdefram(new_wrdefram); - } - switch(loc & 0x3) { - case 0x1: /* 0xc081 */ - case 0x2: /* 0xc082 */ - /* Read rom, set lcbank2 */ - set_statereg(dcycs, (g_c068_statereg & ~(0x04))| - (new_lcbank2 | 0x08)); - break; - case 0x0: /* 0xc080 */ - case 0x3: /* 0xc083 */ - /* Read ram (clear RDROM), set lcbank2 */ - set_statereg(dcycs, (g_c068_statereg & ~(0x0c))| - (new_lcbank2)); - break; - } - return float_bus(dcycs); - /* 0xc090 - 0xc09f */ - case 0x90: case 0x91: case 0x92: case 0x93: - case 0x94: case 0x95: case 0x96: case 0x97: - case 0x98: case 0x99: case 0x9a: case 0x9b: - case 0x9c: case 0x9d: case 0x9e: case 0x9f: - if (g_parallel) - { - return parallel_read((word16)loc & 0xf); - } - else - { - UNIMPL_READ; - } + /* 0xc080 - 0xc08f */ + case 0x80: case 0x81: case 0x82: case 0x83: + case 0x84: case 0x85: case 0x86: case 0x87: + case 0x88: case 0x89: case 0x8a: case 0x8b: + case 0x8c: case 0x8d: case 0x8e: case 0x8f: + new_lcbank2 = ((loc & 0x8) >> 1) ^ 0x4; + new_wrdefram = (loc & 1); + if(new_wrdefram != g_c08x_wrdefram) { + fixup_wrdefram(new_wrdefram); + } + switch(loc & 0x3) { + case 0x1: /* 0xc081 */ + case 0x2: /* 0xc082 */ + /* Read rom, set lcbank2 */ + set_statereg(dcycs, (g_c068_statereg & ~(0x04))| + (new_lcbank2 | 0x08)); + break; + case 0x0: /* 0xc080 */ + case 0x3: /* 0xc083 */ + /* Read ram (clear RDROM), set lcbank2 */ + set_statereg(dcycs, (g_c068_statereg & ~(0x0c))| + (new_lcbank2)); + break; + } + return float_bus(dcycs); + /* 0xc090 - 0xc09f */ + case 0x90: case 0x91: case 0x92: case 0x93: + case 0x94: case 0x95: case 0x96: case 0x97: + case 0x98: case 0x99: case 0x9a: case 0x9b: + case 0x9c: case 0x9d: case 0x9e: case 0x9f: + if (g_parallel) + { + return parallel_read((word16)loc & 0xf); + } + else + { + UNIMPL_READ; + } - /* 0xc0a0 - 0xc0af */ - case 0xa0: case 0xa1: case 0xa2: case 0xa3: - case 0xa4: case 0xa5: case 0xa6: case 0xa7: - case 0xa8: case 0xa9: case 0xaa: case 0xab: - case 0xac: case 0xad: case 0xae: case 0xaf: - return 0; - /* UNIMPL_READ; */ + /* 0xc0a0 - 0xc0af */ + case 0xa0: case 0xa1: case 0xa2: case 0xa3: + case 0xa4: case 0xa5: case 0xa6: case 0xa7: + case 0xa8: case 0xa9: case 0xaa: case 0xab: + case 0xac: case 0xad: case 0xae: case 0xaf: + return 0; + /* UNIMPL_READ; */ - /* 0xc0b0 - 0xc0bf */ - //case 0xb0: - /* c0b0: female voice tool033 look at this */ - // return 0; - //case 0xb1: case 0xb2: case 0xb3: - //case 0xb4: case 0xb5: case 0xb6: case 0xb7: - //case 0xb9: case 0xba: case 0xbb: - //case 0xbc: case 0xbd: case 0xbe: case 0xbf: - /* UNIMPL_READ; */ - // return 0; - /* c0b8: Second Sight card stuff: return 0 */ - //case 0xb8: - // return 0; - // break; + /* 0xc0b0 - 0xc0bf */ + //case 0xb0: + /* c0b0: female voice tool033 look at this */ + // return 0; + //case 0xb1: case 0xb2: case 0xb3: + //case 0xb4: case 0xb5: case 0xb6: case 0xb7: + //case 0xb9: case 0xba: case 0xbb: + //case 0xbc: case 0xbd: case 0xbe: case 0xbf: + /* UNIMPL_READ; */ + // return 0; + /* c0b8: Second Sight card stuff: return 0 */ + //case 0xb8: + // return 0; + // break; #ifdef HAVE_TFE - /*Uthernet read access on slot 3*/ - case 0xb0: - case 0xb1: - case 0xb2: - case 0xb3: - case 0xb4: - case 0xb5: - case 0xb6: - case 0xb7: - case 0xb8: - case 0xb9: - case 0xba: - case 0xbb: - case 0xbc: - case 0xbd: - case 0xbe: - case 0xbf: - if (tfe_enabled){ - return tfe_read((word16)loc & 0xf); - } - else - {return 0;} + /*Uthernet read access on slot 3*/ + case 0xb0: + case 0xb1: + case 0xb2: + case 0xb3: + case 0xb4: + case 0xb5: + case 0xb6: + case 0xb7: + case 0xb8: + case 0xb9: + case 0xba: + case 0xbb: + case 0xbc: + case 0xbd: + case 0xbe: + case 0xbf: + if (tfe_enabled) { + return tfe_read((word16)loc & 0xf); + } + else + {return 0;} #endif - /* 0xc0c0 - 0xc0cf */ - case 0xc0: case 0xc1: case 0xc2: case 0xc3: - case 0xc4: case 0xc5: case 0xc6: case 0xc7: - case 0xc8: case 0xc9: case 0xca: case 0xcb: - case 0xcc: case 0xcd: case 0xce: case 0xcf: - return 0; - /* 0xc0d0 - 0xc0df */ - case 0xd0: case 0xd1: case 0xd2: case 0xd3: - case 0xd4: case 0xd5: case 0xd6: case 0xd7: - case 0xd8: case 0xd9: case 0xda: case 0xdb: - case 0xdc: case 0xdd: case 0xde: case 0xdf: - return 0; - /* 0xc0e0 - 0xc0ef */ - case 0xe0: case 0xe1: case 0xe2: case 0xe3: - case 0xe4: case 0xe5: case 0xe6: case 0xe7: - case 0xe8: case 0xe9: case 0xea: case 0xeb: - case 0xed: case 0xee: case 0xef: - return read_iwm(loc, dcycs); - case 0xec: - return iwm_read_c0ec(dcycs); - /* 0xc0f0 - 0xc0ff */ - case 0xf0: case 0xf1: case 0xf2: case 0xf3: - case 0xf4: case 0xf5: case 0xf6: case 0xf7: - case 0xf8: case 0xf9: case 0xfa: case 0xfb: - case 0xfc: case 0xfd: case 0xfe: case 0xff: - return 0; + /* 0xc0c0 - 0xc0cf */ + case 0xc0: case 0xc1: case 0xc2: case 0xc3: + case 0xc4: case 0xc5: case 0xc6: case 0xc7: + case 0xc8: case 0xc9: case 0xca: case 0xcb: + case 0xcc: case 0xcd: case 0xce: case 0xcf: + return 0; + /* 0xc0d0 - 0xc0df */ + case 0xd0: case 0xd1: case 0xd2: case 0xd3: + case 0xd4: case 0xd5: case 0xd6: case 0xd7: + case 0xd8: case 0xd9: case 0xda: case 0xdb: + case 0xdc: case 0xdd: case 0xde: case 0xdf: + return 0; + /* 0xc0e0 - 0xc0ef */ + case 0xe0: case 0xe1: case 0xe2: case 0xe3: + case 0xe4: case 0xe5: case 0xe6: case 0xe7: + case 0xe8: case 0xe9: case 0xea: case 0xeb: + case 0xed: case 0xee: case 0xef: + return read_iwm(loc, dcycs); + case 0xec: + return iwm_read_c0ec(dcycs); + /* 0xc0f0 - 0xc0ff */ + case 0xf0: case 0xf1: case 0xf2: case 0xf3: + case 0xf4: case 0xf5: case 0xf6: case 0xf7: + case 0xf8: case 0xf9: case 0xfa: case 0xfb: + case 0xfc: case 0xfd: case 0xfe: case 0xff: + return slot7_devsel[loc & 0x0f] /* 0 */; - default: - printf("loc: %04x bad\n", loc); - UNIMPL_READ; - } - case 1: case 2: case 3: case 4: case 5: case 6: - /* c100 - c6ff */ - mask = (1 << ((loc >> 8) & 7)); - if(INTCX || ((g_c02d_int_crom & mask) == 0)) { - return(g_rom_fc_ff_ptr[0x3c000 + (loc & 0xfff)]); - } - return float_bus(dcycs); - case 7: - /* c700 */ - if(INTCX || ((g_c02d_int_crom & (1 << 7)) == 0)) { - return(g_rom_fc_ff_ptr[0x3c000 + (loc & 0xfff)]); - } - tmp = g_rom_fc_ff_ptr[0x3c500 + (loc & 0xff)]; - if((loc & 0xff) == 0xfb) { - tmp = tmp & 0xbf; /* clear bit 6 for ROM 03 */ - } - return tmp; - case 8: case 9: case 0xa: case 0xb: case 0xc: case 0xd: case 0xe: - if(INTCX || ((g_c02d_int_crom & (1 << 3)) == 0)) { - return(g_rom_fc_ff_ptr[0x3c000 + (loc & 0xfff)]); - } - UNIMPL_READ; - case 0xf: - if(INTCX || ((g_c02d_int_crom & (1 << 3)) == 0)) { - return(g_rom_fc_ff_ptr[0x3c000 + (loc & 0xfff)]); - } - if((loc & 0xfff) == 0xfff) { - return g_rom_fc_ff_ptr[0x3cfff]; - } - UNIMPL_READ; - } + default: + printf("loc: %04x bad\n", loc); + UNIMPL_READ; + } + case 1: case 2: case 3: case 4: case 5: case 6: + /* c100 - c6ff */ + mask = (1 << ((loc >> 8) & 7)); + if(INTCX || ((g_c02d_int_crom & mask) == 0)) { + return(g_rom_fc_ff_ptr[0x3c000 + (loc & 0xfff)]); + } + return float_bus(dcycs); + case 7: + /* c700 */ + if(INTCX || ((g_c02d_int_crom & (1 << 7)) == 0)) { + return(g_rom_fc_ff_ptr[0x3c000 + (loc & 0xfff)]); + } + tmp = g_rom_fc_ff_ptr[0x3c500 + (loc & 0xff)]; + if((loc & 0xff) == 0xfb) { + tmp = tmp & 0xbf; /* clear bit 6 for ROM 03 */ + } + return tmp; + case 8: case 9: case 0xa: case 0xb: case 0xc: case 0xd: case 0xe: + if(INTCX || ((g_c02d_int_crom & (1 << 3)) == 0)) { + return(g_rom_fc_ff_ptr[0x3c000 + (loc & 0xfff)]); + } + UNIMPL_READ; + case 0xf: + if(INTCX || ((g_c02d_int_crom & (1 << 3)) == 0)) { + return(g_rom_fc_ff_ptr[0x3c000 + (loc & 0xfff)]); + } + if((loc & 0xfff) == 0xfff) { + return g_rom_fc_ff_ptr[0x3cfff]; + } + UNIMPL_READ; + } - halt_printf("io_read: hit end, loc: %06x\n", loc); + halt_printf("io_read: hit end, loc: %06x\n", loc); - return 0xff; + return 0xff; } -void -io_write(word32 loc, int val, double *cyc_ptr) -{ - double dcycs; +void io_write(word32 loc, int val, double *cyc_ptr) { + double dcycs; + int new_tmp; + int new_lcbank2; + int new_wrdefram; + int tmp; + int fixup; + + CALC_DCYCS_FROM_CYC_PTR(dcycs, cyc_ptr, fcyc, new_fcyc); + + val = val & 0xff; + switch((loc >> 8) & 0xf) { + case 0: /* 0xc000 - 0xc0ff */ + //printf ("ioaddress: %x", (loc & 0xf)); + switch(loc & 0xff) { + /* 0xc000 - 0xc00f */ + case 0x00: /* 0xc000 */ + if(g_cur_a2_stat & ALL_STAT_ST80) { + g_cur_a2_stat &= (~ALL_STAT_ST80); + fixup_st80col(dcycs); + } + return; + case 0x01: /* 0xc001 */ + if((g_cur_a2_stat & ALL_STAT_ST80) == 0) { + g_cur_a2_stat |= (ALL_STAT_ST80); + fixup_st80col(dcycs); + } + return; + case 0x02: /* 0xc002 */ + set_statereg(dcycs, g_c068_statereg & ~0x20); + return; + case 0x03: /* 0xc003 */ + set_statereg(dcycs, g_c068_statereg | 0x20); + return; + case 0x04: /* 0xc004 */ + set_statereg(dcycs, g_c068_statereg & ~0x10); + return; + case 0x05: /* 0xc005 */ + set_statereg(dcycs, g_c068_statereg | 0x10); + return; + case 0x06: /* 0xc006 */ + set_statereg(dcycs, g_c068_statereg & ~0x01); + return; + case 0x07: /* 0xc007 */ + set_statereg(dcycs, g_c068_statereg | 0x01); + return; + case 0x08: /* 0xc008 */ + set_statereg(dcycs, g_c068_statereg & ~0x80); + return; + case 0x09: /* 0xc009 */ + set_statereg(dcycs, g_c068_statereg | 0x80); + return; + case 0x0a: /* 0xc00a */ + tmp = 1 << 3; + if((g_c02d_int_crom & tmp) != 0) { + g_c02d_int_crom &= ~tmp; + fixup_intcx(); + } + return; + case 0x0b: /* 0xc00b */ + tmp = 1 << 3; + if((g_c02d_int_crom & tmp) == 0) { + g_c02d_int_crom |= tmp; + fixup_intcx(); + } + return; + case 0x0c: /* 0xc00c */ + if(g_cur_a2_stat & ALL_STAT_VID80) { + g_cur_a2_stat &= (~ALL_STAT_VID80); + change_display_mode(dcycs); + } + return; + case 0x0d: /* 0xc00d */ + if((g_cur_a2_stat & ALL_STAT_VID80) == 0) { + g_cur_a2_stat |= (ALL_STAT_VID80); + change_display_mode(dcycs); + } + return; + case 0x0e: /* 0xc00e */ + if(g_cur_a2_stat & ALL_STAT_ALTCHARSET) { + g_cur_a2_stat &= (~ALL_STAT_ALTCHARSET); + change_display_mode(dcycs); + } + return; + case 0x0f: /* 0xc00f */ + if((g_cur_a2_stat & ALL_STAT_ALTCHARSET) == 0) { + g_cur_a2_stat |= (ALL_STAT_ALTCHARSET); + change_display_mode(dcycs); + } + return; + /* 0xc010 - 0xc01f */ + case 0x10: case 0x11: case 0x12: case 0x13: + case 0x14: case 0x15: case 0x16: case 0x17: + case 0x18: case 0x19: case 0x1a: case 0x1b: + case 0x1c: case 0x1d: case 0x1e: case 0x1f: + adb_access_c010(); + return; + /* 0xc020 - 0xc02f */ + case 0x20: /* 0xc020 */ + /* WRITE CASSETTE?? */ + return; + case 0x21: /* 0xc021 */ + new_tmp = ((val >> 7) & 1) << + (31 - BIT_ALL_STAT_COLOR_C021); + if((g_cur_a2_stat & ALL_STAT_COLOR_C021) != new_tmp) { + g_cur_a2_stat ^= new_tmp; + change_display_mode(dcycs); + } + return; + case 0x22: /* 0xc022 */ + /* change text color */ + tmp = (g_cur_a2_stat >> BIT_ALL_STAT_BG_COLOR) & 0xff; + if(val != tmp) { + /* change text/bg color! */ + g_cur_a2_stat &= ~(ALL_STAT_TEXT_COLOR | + ALL_STAT_BG_COLOR); + g_cur_a2_stat += (val << BIT_ALL_STAT_BG_COLOR); + change_display_mode(dcycs); + } + return; + case 0x23: /* 0xc023 */ + if((val & 0x19) != 0) { + halt_printf("c023 write of %02x!!!\n", val); + } + tmp = (g_c023_val & 0x70) | (val & 0x0f); + if((tmp & 0x22) == 0x22) { + add_irq(IRQ_PENDING_C023_SCAN); + } + if(!(tmp & 2)) { + remove_irq(IRQ_PENDING_C023_SCAN); + } + if((tmp & 0x44) == 0x44) { + add_irq(IRQ_PENDING_C023_1SEC); + } + if(!(tmp & 0x4)) { + remove_irq(IRQ_PENDING_C023_1SEC); + } + + if(g_irq_pending & (IRQ_PENDING_C023_SCAN | + IRQ_PENDING_C023_1SEC)) { + tmp |= 0x80; + } + g_c023_val = tmp; + return; + case 0x24: /* 0xc024 */ + /* Write to mouse reg: Throw it away */ + return; + case 0x26: /* 0xc026 */ + adb_write_c026(val); + return; + case 0x27: /* 0xc027 */ + adb_write_c027(val); + return; + case 0x29: /* 0xc029 */ + g_c029_val_some = val & 0x41; + if((val & 1) == 0) { + halt_printf("c029: %02x\n", val); + } + new_tmp = val & 0xa0; + if(new_tmp != (g_cur_a2_stat & 0xa0)) { + g_cur_a2_stat = (g_cur_a2_stat & (~0xa0)) + + new_tmp; + change_display_mode(dcycs); + } + return; + case 0x2a: /* 0xc02a */ #if 0 - double fcyc, new_fcyc; + printf("Writing c02a with %02x\n", val); #endif - int new_tmp; - int new_lcbank2; - int new_wrdefram; - int tmp; - int fixup; + return; + case 0x2b: /* 0xc02b */ + g_c02b_val = val; + if(val != 0x08 && val != 0x00) { + printf("Writing c02b with %02x\n", val); + } + return; + case 0x2d: /* 0xc02d */ + if((val & 0x9) != 0) { + halt_printf("Illegal c02d write: %02x!\n", val); + } + fixup = (val != g_c02d_int_crom); + g_c02d_int_crom = val; + if(fixup) { + vid_printf("Write c02d of %02x\n", val); + fixup_intcx(); + } + return; + case 0x28: /* 0xc028 */ + case 0x2c: /* 0xc02c */ + UNIMPL_WRITE; + case 0x25: /* 0xc025 */ + /* Space Shark writes to c025--ignore */ + case 0x2e: /* 0xc02e */ + case 0x2f: /* 0xc02f */ + /* Modulae writes to this--just ignore them */ + return; + break; - CALC_DCYCS_FROM_CYC_PTR(dcycs, cyc_ptr, fcyc, new_fcyc); - - val = val & 0xff; - switch((loc >> 8) & 0xf) { - case 0: /* 0xc000 - 0xc0ff */ - //printf ("ioaddress: %x", (loc & 0xf)); - switch(loc & 0xff) { - /* 0xc000 - 0xc00f */ - case 0x00: /* 0xc000 */ - if(g_cur_a2_stat & ALL_STAT_ST80) { - g_cur_a2_stat &= (~ALL_STAT_ST80); - fixup_st80col(dcycs); - } - return; - case 0x01: /* 0xc001 */ - if((g_cur_a2_stat & ALL_STAT_ST80) == 0) { - g_cur_a2_stat |= (ALL_STAT_ST80); - fixup_st80col(dcycs); - } - return; - case 0x02: /* 0xc002 */ - set_statereg(dcycs, g_c068_statereg & ~0x20); - return; - case 0x03: /* 0xc003 */ - set_statereg(dcycs, g_c068_statereg | 0x20); - return; - case 0x04: /* 0xc004 */ - set_statereg(dcycs, g_c068_statereg & ~0x10); - return; - case 0x05: /* 0xc005 */ - set_statereg(dcycs, g_c068_statereg | 0x10); - return; - case 0x06: /* 0xc006 */ - set_statereg(dcycs, g_c068_statereg & ~0x01); - return; - case 0x07: /* 0xc007 */ - set_statereg(dcycs, g_c068_statereg | 0x01); - return; - case 0x08: /* 0xc008 */ - set_statereg(dcycs, g_c068_statereg & ~0x80); - return; - case 0x09: /* 0xc009 */ - set_statereg(dcycs, g_c068_statereg | 0x80); - return; - case 0x0a: /* 0xc00a */ - tmp = 1 << 3; - if((g_c02d_int_crom & tmp) != 0) { - g_c02d_int_crom &= ~tmp; - fixup_intcx(); - } - return; - case 0x0b: /* 0xc00b */ - tmp = 1 << 3; - if((g_c02d_int_crom & tmp) == 0) { - g_c02d_int_crom |= tmp; - fixup_intcx(); - } - return; - case 0x0c: /* 0xc00c */ - if(g_cur_a2_stat & ALL_STAT_VID80) { - g_cur_a2_stat &= (~ALL_STAT_VID80); - change_display_mode(dcycs); - } - return; - case 0x0d: /* 0xc00d */ - if((g_cur_a2_stat & ALL_STAT_VID80) == 0) { - g_cur_a2_stat |= (ALL_STAT_VID80); - change_display_mode(dcycs); - } - return; - case 0x0e: /* 0xc00e */ - if(g_cur_a2_stat & ALL_STAT_ALTCHARSET) { - g_cur_a2_stat &= (~ALL_STAT_ALTCHARSET); - change_display_mode(dcycs); - } - return; - case 0x0f: /* 0xc00f */ - if((g_cur_a2_stat & ALL_STAT_ALTCHARSET) == 0) { - g_cur_a2_stat |= (ALL_STAT_ALTCHARSET); - change_display_mode(dcycs); - } - return; - /* 0xc010 - 0xc01f */ - case 0x10: case 0x11: case 0x12: case 0x13: - case 0x14: case 0x15: case 0x16: case 0x17: - case 0x18: case 0x19: case 0x1a: case 0x1b: - case 0x1c: case 0x1d: case 0x1e: case 0x1f: - adb_access_c010(); - return; - /* 0xc020 - 0xc02f */ - case 0x20: /* 0xc020 */ - /* WRITE CASSETTE?? */ - return; - case 0x21: /* 0xc021 */ - new_tmp = ((val >> 7) & 1) << - (31 - BIT_ALL_STAT_COLOR_C021); - if((g_cur_a2_stat & ALL_STAT_COLOR_C021) != new_tmp) { - g_cur_a2_stat ^= new_tmp; - change_display_mode(dcycs); - } - return; - case 0x22: /* 0xc022 */ - /* change text color */ - tmp = (g_cur_a2_stat >> BIT_ALL_STAT_BG_COLOR) & 0xff; - if(val != tmp) { - /* change text/bg color! */ - g_cur_a2_stat &= ~(ALL_STAT_TEXT_COLOR | - ALL_STAT_BG_COLOR); - g_cur_a2_stat += (val << BIT_ALL_STAT_BG_COLOR); - change_display_mode(dcycs); - } - return; - case 0x23: /* 0xc023 */ - if((val & 0x19) != 0) { - halt_printf("c023 write of %02x!!!\n", val); - } - tmp = (g_c023_val & 0x70) | (val & 0x0f); - if((tmp & 0x22) == 0x22) { - add_irq(IRQ_PENDING_C023_SCAN); - } - if(!(tmp & 2)) { - remove_irq(IRQ_PENDING_C023_SCAN); - } - if((tmp & 0x44) == 0x44) { - add_irq(IRQ_PENDING_C023_1SEC); - } - if(!(tmp & 0x4)) { - remove_irq(IRQ_PENDING_C023_1SEC); - } - - if(g_irq_pending & (IRQ_PENDING_C023_SCAN | - IRQ_PENDING_C023_1SEC)) { - tmp |= 0x80; - } - g_c023_val = tmp; - return; - case 0x24: /* 0xc024 */ - /* Write to mouse reg: Throw it away */ - return; - case 0x26: /* 0xc026 */ - adb_write_c026(val); - return; - case 0x27: /* 0xc027 */ - adb_write_c027(val); - return; - case 0x29: /* 0xc029 */ - g_c029_val_some = val & 0x41; - if((val & 1) == 0) { - halt_printf("c029: %02x\n", val); - } - new_tmp = val & 0xa0; - if(new_tmp != (g_cur_a2_stat & 0xa0)) { - g_cur_a2_stat = (g_cur_a2_stat & (~0xa0)) + - new_tmp; - change_display_mode(dcycs); - } - return; - case 0x2a: /* 0xc02a */ + /* 0xc030 - 0xc03f */ + case 0x30: /* 0xc030 */ #if 0 - printf("Writing c02a with %02x\n", val); + printf("Write speaker?\n"); #endif - return; - case 0x2b: /* 0xc02b */ - g_c02b_val = val; - if(val != 0x08 && val != 0x00) { - printf("Writing c02b with %02x\n", val); - } - return; - case 0x2d: /* 0xc02d */ - if((val & 0x9) != 0) { - halt_printf("Illegal c02d write: %02x!\n", val); - } - fixup = (val != g_c02d_int_crom); - g_c02d_int_crom = val; - if(fixup) { - vid_printf("Write c02d of %02x\n", val); - fixup_intcx(); - } - return; - case 0x28: /* 0xc028 */ - case 0x2c: /* 0xc02c */ - UNIMPL_WRITE; - case 0x25: /* 0xc025 */ - /* Space Shark writes to c025--ignore */ - case 0x2e: /* 0xc02e */ - case 0x2f: /* 0xc02f */ - /* Modulae writes to this--just ignore them */ - return; - break; + (void)doc_read_c030(dcycs); + return; + case 0x31: /* 0xc031 */ + tmp = val ^ g_c031_disk35; + if(tmp & 0x40) { + /* apple35_sel changed, maybe speed change */ + set_halt(HALT_EVENT); + } + g_c031_disk35 = val & 0xc0; + return; + case 0x32: /* 0xc032 */ + tmp = g_c023_val & 0x7f; + if(((val & 0x40) == 0) && (tmp & 0x40)) { + /* clear 1 sec int */ + remove_irq(IRQ_PENDING_C023_1SEC); + tmp &= 0xbf; + g_c023_val = tmp; + } + if(((val & 0x20) == 0) && (tmp & 0x20)) { + /* clear scan line int */ + remove_irq(IRQ_PENDING_C023_SCAN); + g_c023_val = tmp & 0xdf; + check_for_new_scan_int(dcycs); + } + if(g_irq_pending & (IRQ_PENDING_C023_1SEC | + IRQ_PENDING_C023_SCAN)) { + g_c023_val |= 0x80; + } + if((val & 0x9f) != 0x9f) { + irq_printf("c032: wrote %02x!\n", val); + } + return; + case 0x33: /* 0xc033 = CLOCKDATA*/ + g_c033_data = val; + return; + case 0x34: /* 0xc034 = CLOCKCTL */ + tmp = val ^ g_c034_val; + clock_write_c034(val); + if(tmp & 0xf) { + change_border_color(dcycs, val & 0xf); + } + return; + case 0x35: /* 0xc035 */ + update_shadow_reg(val); + return; + case 0x36: /* 0xc036 = CYAREG */ + tmp = val ^ g_c036_val_speed; + g_c036_val_speed = (val & ~0x20); /* clr bit 5 */ + if(tmp & 0x80) { + /* to recalculate times since speed changing */ + set_halt(HALT_EVENT); + } + if(tmp & 0xf) { + /* slot_motor_detect changed */ + set_halt(HALT_EVENT); + } - /* 0xc030 - 0xc03f */ - case 0x30: /* 0xc030 */ -#if 0 - printf("Write speaker?\n"); -#endif - (void)doc_read_c030(dcycs); - return; - case 0x31: /* 0xc031 */ - tmp = val ^ g_c031_disk35; - if(tmp & 0x40) { - /* apple35_sel changed, maybe speed change */ - set_halt(HALT_EVENT); - } - g_c031_disk35 = val & 0xc0; - return; - case 0x32: /* 0xc032 */ - tmp = g_c023_val & 0x7f; - if(((val & 0x40) == 0) && (tmp & 0x40)) { - /* clear 1 sec int */ - remove_irq(IRQ_PENDING_C023_1SEC); - tmp &= 0xbf; - g_c023_val = tmp; - } - if(((val & 0x20) == 0) && (tmp & 0x20)) { - /* clear scan line int */ - remove_irq(IRQ_PENDING_C023_SCAN); - g_c023_val = tmp & 0xdf; - check_for_new_scan_int(dcycs); - } - if(g_irq_pending & (IRQ_PENDING_C023_1SEC | - IRQ_PENDING_C023_SCAN)) { - g_c023_val |= 0x80; - } - if((val & 0x9f) != 0x9f) { - irq_printf("c032: wrote %02x!\n", val); - } - return; - case 0x33: /* 0xc033 = CLOCKDATA*/ - g_c033_data = val; - return; - case 0x34: /* 0xc034 = CLOCKCTL */ - tmp = val ^ g_c034_val; - clock_write_c034(val); - if(tmp & 0xf) { - change_border_color(dcycs, val & 0xf); - } - return; - case 0x35: /* 0xc035 */ - update_shadow_reg(val); - return; - case 0x36: /* 0xc036 = CYAREG */ - tmp = val ^ g_c036_val_speed; - g_c036_val_speed = (val & ~0x20); /* clr bit 5 */ - if(tmp & 0x80) { - /* to recalculate times since speed changing */ - set_halt(HALT_EVENT); - } - if(tmp & 0xf) { - /* slot_motor_detect changed */ - set_halt(HALT_EVENT); - } + if((val & 0x60) != 0) { + /* for ROM 03, 0x40 is the power-on status */ + /* and can be read/write */ + if(((val & 0x60) != 0x40) || + (g_rom_version < 3)) { + g_c036_val_speed &= (~0x60); + halt_printf("c036: %2x\n", val); + } + } + if(tmp & 0x10) { /* shadow in all banks! */ + if(g_num_shadow_all_banks++ == 0) { + printf("Shadowing all banks...This " + "must be the NFC Megademo\n"); + } + fixup_shadow_all_banks(); + } + return; + case 0x37: /* 0xc037 */ + /* just ignore, probably someone writing c036 m=0 */ + return; + case 0x38: /* 0xc038 */ + scc_write_reg(1, val, dcycs); + return; + case 0x39: /* 0xc039 */ + scc_write_reg(0, val, dcycs); + return; + case 0x3a: /* 0xc03a */ + scc_write_data(1, val, dcycs); + return; + case 0x3b: /* 0xc03b */ + scc_write_data(0, val, dcycs); + return; + case 0x3c: /* 0xc03c */ + /* doc ctl */ + doc_write_c03c(val, dcycs); + return; + case 0x3d: /* 0xc03d */ + /* doc data reg */ + doc_write_c03d(val, dcycs); + return; + case 0x3e: /* 0xc03e */ + g_c03ef_doc_ptr = (g_c03ef_doc_ptr & 0xff00) + val; + return; + case 0x3f: /* 0xc03f */ + g_c03ef_doc_ptr = (g_c03ef_doc_ptr & 0xff) + (val << 8); + return; - if((val & 0x60) != 0) { - /* for ROM 03, 0x40 is the power-on status */ - /* and can be read/write */ - if(((val & 0x60) != 0x40) || - (g_rom_version < 3)) { - g_c036_val_speed &= (~0x60); - halt_printf("c036: %2x\n", val); - } - } - if(tmp & 0x10) { /* shadow in all banks! */ - if(g_num_shadow_all_banks++ == 0) { - printf("Shadowing all banks...This " - "must be the NFC Megademo\n"); - } - fixup_shadow_all_banks(); - } - return; - case 0x37: /* 0xc037 */ - /* just ignore, probably someone writing c036 m=0 */ - return; - case 0x38: /* 0xc038 */ - scc_write_reg(1, val, dcycs); - return; - case 0x39: /* 0xc039 */ - scc_write_reg(0, val, dcycs); - return; - case 0x3a: /* 0xc03a */ - scc_write_data(1, val, dcycs); - return; - case 0x3b: /* 0xc03b */ - scc_write_data(0, val, dcycs); - return; - case 0x3c: /* 0xc03c */ - /* doc ctl */ - doc_write_c03c(val, dcycs); - return; - case 0x3d: /* 0xc03d */ - /* doc data reg */ - doc_write_c03d(val, dcycs); - return; - case 0x3e: /* 0xc03e */ - g_c03ef_doc_ptr = (g_c03ef_doc_ptr & 0xff00) + val; - return; - case 0x3f: /* 0xc03f */ - g_c03ef_doc_ptr = (g_c03ef_doc_ptr & 0xff) + (val << 8); - return; + /* 0xc040 - 0xc04f */ + case 0x41: /* c041 */ + g_c041_val = val & 0x1f; + if((val & 0xe6) != 0) { + halt_printf("write c041: %02x\n", val); + } - /* 0xc040 - 0xc04f */ - case 0x41: /* c041 */ - g_c041_val = val & 0x1f; - if((val & 0xe6) != 0) { - halt_printf("write c041: %02x\n", val); - } - - if (val & C041_EN_MOUSE) - { - // Enable Mega II mouse - } + if (val & C041_EN_MOUSE) + { + // Enable Mega II mouse + } - if(!(val & C041_EN_VBL_INTS)) { - /* no more vbl interrupt */ - remove_irq(IRQ_PENDING_C046_VBL); - } - if(!(val & C041_EN_25SEC_INTS)) { - remove_irq(IRQ_PENDING_C046_25SEC); - } - return; - case 0x46: /* c046 */ - /* ignore writes to c046 */ - return; - case 0x47: /* c047 */ - remove_irq(IRQ_PENDING_C046_VBL | - IRQ_PENDING_C046_25SEC); - g_c046_val &= 0xe7; /* clear vblint, 1/4sec int*/ - return; - case 0x48: /* c048 */ - /* diversitune writes this--ignore it */ - return; - case 0x42: /* c042 */ - case 0x43: /* c043 */ - return; - case 0x4f: /* c04f */ - g_em_emubyte_cnt = 1; - return; - case 0x40: /* c040 */ - case 0x44: /* c044 */ - case 0x45: /* c045 */ - case 0x49: /* c049 */ - case 0x4a: /* c04a */ - case 0x4b: /* c04b */ - case 0x4c: /* c04c */ - case 0x4d: /* c04d */ - case 0x4e: /* c04e */ - UNIMPL_WRITE; + if(!(val & C041_EN_VBL_INTS)) { + /* no more vbl interrupt */ + remove_irq(IRQ_PENDING_C046_VBL); + } + if(!(val & C041_EN_25SEC_INTS)) { + remove_irq(IRQ_PENDING_C046_25SEC); + } + return; + case 0x46: /* c046 */ + /* ignore writes to c046 */ + return; + case 0x47: /* c047 */ + remove_irq(IRQ_PENDING_C046_VBL | + IRQ_PENDING_C046_25SEC); + g_c046_val &= 0xe7; /* clear vblint, 1/4sec int*/ + return; + case 0x48: /* c048 */ + /* diversitune writes this--ignore it */ + return; + case 0x42: /* c042 */ + case 0x43: /* c043 */ + return; + case 0x4f: /* c04f */ + g_em_emubyte_cnt = 1; + return; + case 0x40: /* c040 */ + case 0x44: /* c044 */ + case 0x45: /* c045 */ + case 0x49: /* c049 */ + case 0x4a: /* c04a */ + case 0x4b: /* c04b */ + case 0x4c: /* c04c */ + case 0x4d: /* c04d */ + case 0x4e: /* c04e */ + UNIMPL_WRITE; - /* 0xc050 - 0xc05f */ - case 0x50: /* 0xc050 */ - if(g_cur_a2_stat & ALL_STAT_TEXT) { - g_cur_a2_stat &= (~ALL_STAT_TEXT); - change_display_mode(dcycs); - } - return; - case 0x51: /* 0xc051 */ - if((g_cur_a2_stat & ALL_STAT_TEXT) == 0) { - g_cur_a2_stat |= (ALL_STAT_TEXT); - change_display_mode(dcycs); - } - return; - case 0x52: /* 0xc052 */ - if(g_cur_a2_stat & ALL_STAT_MIX_T_GR) { - g_cur_a2_stat &= (~ALL_STAT_MIX_T_GR); - change_display_mode(dcycs); - } - return; - case 0x53: /* 0xc053 */ - if((g_cur_a2_stat & ALL_STAT_MIX_T_GR) == 0) { - g_cur_a2_stat |= (ALL_STAT_MIX_T_GR); - change_display_mode(dcycs); - } - return; - case 0x54: /* 0xc054 */ - set_statereg(dcycs, g_c068_statereg & (~0x40)); - return; - case 0x55: /* 0xc055 */ - set_statereg(dcycs, g_c068_statereg | 0x40); - return; - case 0x56: /* 0xc056 */ - if(g_cur_a2_stat & ALL_STAT_HIRES) { - g_cur_a2_stat &= (~ALL_STAT_HIRES); - fixup_hires_on(); - change_display_mode(dcycs); - } - return; - case 0x57: /* 0xc057 */ - if((g_cur_a2_stat & ALL_STAT_HIRES) == 0) { - g_cur_a2_stat |= (ALL_STAT_HIRES); - fixup_hires_on(); - change_display_mode(dcycs); - } - return; - case 0x58: /* 0xc058 */ - if(g_zipgs_unlock >= 4) { - g_zipgs_reg_c059 &= 0x4; /* last reset cold */ - } else { - g_c05x_annuncs &= (~1); - } - return; - case 0x59: /* 0xc059 */ - if(g_zipgs_unlock >= 4) { - g_zipgs_reg_c059 = (val & 0xf8) | - (g_zipgs_reg_c059 & 0x7); - } else { - g_c05x_annuncs |= 1; - } - return; - case 0x5a: /* 0xc05a */ - g_c05x_annuncs &= (~2); - if((val & 0xf0) == 0x50) { - g_zipgs_unlock++; - } else if((val & 0xf0) == 0xa0) { - g_zipgs_unlock = 0; - } else if(g_zipgs_unlock >= 4) { - if((g_zipgs_reg_c05b & 0x10) == 0) { - /* to recalculate times */ - set_halt(HALT_EVENT); - } - g_zipgs_reg_c05b |= 0x10; // disable - } - return; - case 0x5b: /* 0xc05b */ - if(g_zipgs_unlock >= 4) { - if((g_zipgs_reg_c05b & 0x10) != 0) { - /* to recalculate times */ - set_halt(HALT_EVENT); - } - g_zipgs_reg_c05b &= (~0x10); // enable - } else { - g_c05x_annuncs |= 2; - } - return; - case 0x5c: /* 0xc05c */ - if(g_zipgs_unlock >= 4) { - g_zipgs_reg_c05c = val; - } else { - g_c05x_annuncs &= (~4); - } - return; - case 0x5d: /* 0xc05d */ - if(g_zipgs_unlock >= 4) { - if(((g_zipgs_reg_c05a ^ val) >= 0x10) && - ((g_zipgs_reg_c05b & 0x10) == 0)) { - set_halt(HALT_EVENT); - } - g_zipgs_reg_c05a = val | 0xf; - } else { - g_c05x_annuncs |= 4; - } - return; - case 0x5e: /* 0xc05e */ - if(g_zipgs_unlock >= 4) { - /* Zippy writes 0x80 and 0x00 here... */ - } else if(g_cur_a2_stat & ALL_STAT_ANNUNC3) { - g_cur_a2_stat &= (~ALL_STAT_ANNUNC3); - change_display_mode(dcycs); - } - return; - case 0x5f: /* 0xc05f */ - if(g_zipgs_unlock >= 4) { - halt_printf("Wrote ZipGS $c05f: %02x\n", val); - } else if((g_cur_a2_stat & ALL_STAT_ANNUNC3) == 0) { - g_cur_a2_stat |= (ALL_STAT_ANNUNC3); - change_display_mode(dcycs); - } - return; + /* 0xc050 - 0xc05f */ + case 0x50: /* 0xc050 */ + if(g_cur_a2_stat & ALL_STAT_TEXT) { + g_cur_a2_stat &= (~ALL_STAT_TEXT); + change_display_mode(dcycs); + } + return; + case 0x51: /* 0xc051 */ + if((g_cur_a2_stat & ALL_STAT_TEXT) == 0) { + g_cur_a2_stat |= (ALL_STAT_TEXT); + change_display_mode(dcycs); + } + return; + case 0x52: /* 0xc052 */ + if(g_cur_a2_stat & ALL_STAT_MIX_T_GR) { + g_cur_a2_stat &= (~ALL_STAT_MIX_T_GR); + change_display_mode(dcycs); + } + return; + case 0x53: /* 0xc053 */ + if((g_cur_a2_stat & ALL_STAT_MIX_T_GR) == 0) { + g_cur_a2_stat |= (ALL_STAT_MIX_T_GR); + change_display_mode(dcycs); + } + return; + case 0x54: /* 0xc054 */ + set_statereg(dcycs, g_c068_statereg & (~0x40)); + return; + case 0x55: /* 0xc055 */ + set_statereg(dcycs, g_c068_statereg | 0x40); + return; + case 0x56: /* 0xc056 */ + if(g_cur_a2_stat & ALL_STAT_HIRES) { + g_cur_a2_stat &= (~ALL_STAT_HIRES); + fixup_hires_on(); + change_display_mode(dcycs); + } + return; + case 0x57: /* 0xc057 */ + if((g_cur_a2_stat & ALL_STAT_HIRES) == 0) { + g_cur_a2_stat |= (ALL_STAT_HIRES); + fixup_hires_on(); + change_display_mode(dcycs); + } + return; + case 0x58: /* 0xc058 */ + if(g_zipgs_unlock >= 4) { + g_zipgs_reg_c059 &= 0x4; /* last reset cold */ + } else { + g_c05x_annuncs &= (~1); + } + return; + case 0x59: /* 0xc059 */ + if(g_zipgs_unlock >= 4) { + g_zipgs_reg_c059 = (val & 0xf8) | + (g_zipgs_reg_c059 & 0x7); + } else { + g_c05x_annuncs |= 1; + } + return; + case 0x5a: /* 0xc05a */ + g_c05x_annuncs &= (~2); + if((val & 0xf0) == 0x50) { + g_zipgs_unlock++; + } else if((val & 0xf0) == 0xa0) { + g_zipgs_unlock = 0; + } else if(g_zipgs_unlock >= 4) { + if((g_zipgs_reg_c05b & 0x10) == 0) { + /* to recalculate times */ + set_halt(HALT_EVENT); + } + g_zipgs_reg_c05b |= 0x10; // disable + } + return; + case 0x5b: /* 0xc05b */ + if(g_zipgs_unlock >= 4) { + if((g_zipgs_reg_c05b & 0x10) != 0) { + /* to recalculate times */ + set_halt(HALT_EVENT); + } + g_zipgs_reg_c05b &= (~0x10); // enable + } else { + g_c05x_annuncs |= 2; + } + return; + case 0x5c: /* 0xc05c */ + if(g_zipgs_unlock >= 4) { + g_zipgs_reg_c05c = val; + } else { + g_c05x_annuncs &= (~4); + } + return; + case 0x5d: /* 0xc05d */ + if(g_zipgs_unlock >= 4) { + if(((g_zipgs_reg_c05a ^ val) >= 0x10) && + ((g_zipgs_reg_c05b & 0x10) == 0)) { + set_halt(HALT_EVENT); + } + g_zipgs_reg_c05a = val | 0xf; + } else { + g_c05x_annuncs |= 4; + } + return; + case 0x5e: /* 0xc05e */ + if(g_zipgs_unlock >= 4) { + /* Zippy writes 0x80 and 0x00 here... */ + } else if(g_cur_a2_stat & ALL_STAT_ANNUNC3) { + g_cur_a2_stat &= (~ALL_STAT_ANNUNC3); + change_display_mode(dcycs); + } + return; + case 0x5f: /* 0xc05f */ + if(g_zipgs_unlock >= 4) { + halt_printf("Wrote ZipGS $c05f: %02x\n", val); + } else if((g_cur_a2_stat & ALL_STAT_ANNUNC3) == 0) { + g_cur_a2_stat |= (ALL_STAT_ANNUNC3); + change_display_mode(dcycs); + } + return; - /* 0xc060 - 0xc06f */ - case 0x60: /* 0xc060 */ - case 0x61: /* 0xc061 */ - case 0x62: /* 0xc062 */ - case 0x63: /* 0xc063 */ - case 0x64: /* 0xc064 */ - case 0x65: /* 0xc065 */ - case 0x66: /* 0xc066 */ - case 0x67: /* 0xc067 */ - /* all the above do nothing--return */ - return; - case 0x68: /* 0xc068 = STATEREG */ - set_statereg(dcycs, val); - return; - case 0x69: /* 0xc069 */ - /* just ignore, someone writing c068 with m=0 */ - return; + /* 0xc060 - 0xc06f */ + case 0x60: /* 0xc060 */ + case 0x61: /* 0xc061 */ + case 0x62: /* 0xc062 */ + case 0x63: /* 0xc063 */ + case 0x64: /* 0xc064 */ + case 0x65: /* 0xc065 */ + case 0x66: /* 0xc066 */ + case 0x67: /* 0xc067 */ + /* all the above do nothing--return */ + return; + case 0x68: /* 0xc068 = STATEREG */ + set_statereg(dcycs, val); + return; + case 0x69: /* 0xc069 */ + /* just ignore, someone writing c068 with m=0 */ + return; #ifdef TRANSWARP - // OG writeTranswarp pseudo-register - case 0x6a: /* 0xc06a */ - transwarp_low_val = val; - return ; - case 0x6b: /* 0xc06b */ - val = (val<<8) + transwarp_low_val; - if ((val==2600) || (val==0x0028)) // Bug for demo ... - { - printf("Disabling Transwarp!\n"); - g_zipgs_reg_c05b |= 0x10; // disable - set_halt(HALT_EVENT); - } - else if (val==8000) - { - printf("Enabling Transwarp!\n"); - g_zipgs_reg_c05b &= ~0x10; // enable - set_halt(HALT_EVENT); - } - else - printf("unknown twgs speed:%d\n",val); - return; - case 0x6c: /* 0xc06c */ - if (val==0) - ; // set slow ? - else if (val==1) - { - // disable zip - g_zipgs_reg_c05b |= 0x10; // disable - set_halt(HALT_EVENT); - } - else if (val==2) - { - // enable zip - g_zipgs_reg_c05b &= ~0x10; // enable - set_halt(HALT_EVENT); - } - else - printf("unknown twgs index:%d\n",val); - return ; + // OG writeTranswarp pseudo-register + case 0x6a: /* 0xc06a */ + transwarp_low_val = val; + return; + case 0x6b: /* 0xc06b */ + val = (val<<8) + transwarp_low_val; + if ((val==2600) || (val==0x0028)) // Bug for demo ... + { + printf("Disabling Transwarp!\n"); + g_zipgs_reg_c05b |= 0x10; // disable + set_halt(HALT_EVENT); + } + else if (val==8000) + { + printf("Enabling Transwarp!\n"); + g_zipgs_reg_c05b &= ~0x10; // enable + set_halt(HALT_EVENT); + } + else + printf("unknown twgs speed:%d\n",val); + return; + case 0x6c: /* 0xc06c */ + if (val==0) + ; // set slow ? + else if (val==1) + { + // disable zip + g_zipgs_reg_c05b |= 0x10; // disable + set_halt(HALT_EVENT); + } + else if (val==2) + { + // enable zip + g_zipgs_reg_c05b &= ~0x10; // enable + set_halt(HALT_EVENT); + } + else + printf("unknown twgs index:%d\n",val); + return; #else - case 0x6a: /* 0xc06a */ - case 0x6b: /* 0xc06b */ - case 0x6c: /* 0xc06c */ + case 0x6a: /* 0xc06a */ + case 0x6b: /* 0xc06b */ + case 0x6c: /* 0xc06c */ #endif - case 0x6d: /* 0xc06d */ - case 0x6e: /* 0xc06e */ - case 0x6f: /* 0xc06f */ - UNIMPL_WRITE; + case 0x6d: /* 0xc06d */ + case 0x6e: /* 0xc06e */ + case 0x6f: /* 0xc06f */ + UNIMPL_WRITE; - /* 0xc070 - 0xc07f */ - case 0x70: /* 0xc070 = Trigger paddles */ - paddle_trigger(dcycs); - return; - case 0x73: /* 0xc073 = multibank ram card bank addr? */ - return; - case 0x71: /* 0xc071 = another multibank ram card enable? */ - case 0x7e: /* 0xc07e */ - case 0x7f: /* 0xc07f */ - return; - case 0x72: /* 0xc072 */ - case 0x74: /* 0xc074 */ - case 0x75: /* 0xc075 */ - case 0x76: /* 0xc076 */ - case 0x77: /* 0xc077 */ - case 0x78: /* 0xc078 */ - case 0x79: /* 0xc079 */ - case 0x7a: /* 0xc07a */ - case 0x7b: /* 0xc07b */ - case 0x7c: /* 0xc07c */ - case 0x7d: /* 0xc07d */ - UNIMPL_WRITE; + /* 0xc070 - 0xc07f */ + case 0x70: /* 0xc070 = Trigger paddles */ + paddle_trigger(dcycs); + return; + case 0x73: /* 0xc073 = multibank ram card bank addr? */ + return; + case 0x71: /* 0xc071 = another multibank ram card enable? */ + case 0x7e: /* 0xc07e */ + case 0x7f: /* 0xc07f */ + return; + case 0x72: /* 0xc072 */ + case 0x74: /* 0xc074 */ + case 0x75: /* 0xc075 */ + case 0x76: /* 0xc076 */ + case 0x77: /* 0xc077 */ + case 0x78: /* 0xc078 */ + case 0x79: /* 0xc079 */ + case 0x7a: /* 0xc07a */ + case 0x7b: /* 0xc07b */ + case 0x7c: /* 0xc07c */ + case 0x7d: /* 0xc07d */ + UNIMPL_WRITE; - /* 0xc080 - 0xc08f */ - case 0x80: case 0x81: case 0x82: case 0x83: - case 0x84: case 0x85: case 0x86: case 0x87: - case 0x88: case 0x89: case 0x8a: case 0x8b: - case 0x8c: case 0x8d: case 0x8e: case 0x8f: - new_lcbank2 = ((loc >> 1) & 0x4) ^ 0x4; - new_wrdefram = (loc & 1); - if(new_wrdefram != g_c08x_wrdefram) { - fixup_wrdefram(new_wrdefram); - } - switch(loc & 0xf) { - case 0x1: /* 0xc081 */ - case 0x2: /* 0xc082 */ - case 0x5: /* 0xc085 */ - case 0x6: /* 0xc086 */ - case 0x9: /* 0xc089 */ - case 0xa: /* 0xc08a */ - case 0xd: /* 0xc08d */ - case 0xe: /* 0xc08e */ - /* Read rom, set lcbank2 */ - set_statereg(dcycs, (g_c068_statereg & ~(0x04))| - (new_lcbank2 | 0x08)); - break; - case 0x0: /* 0xc080 */ - case 0x3: /* 0xc083 */ - case 0x4: /* 0xc084 */ - case 0x7: /* 0xc087 */ - case 0x8: /* 0xc088 */ - case 0xb: /* 0xc08b */ - case 0xc: /* 0xc08c */ - case 0xf: /* 0xc08f */ - /* Read ram (clear RDROM), set lcbank2 */ - set_statereg(dcycs, (g_c068_statereg & ~(0x0c))| - (new_lcbank2)); - break; - } - return; + /* 0xc080 - 0xc08f */ + case 0x80: case 0x81: case 0x82: case 0x83: + case 0x84: case 0x85: case 0x86: case 0x87: + case 0x88: case 0x89: case 0x8a: case 0x8b: + case 0x8c: case 0x8d: case 0x8e: case 0x8f: + new_lcbank2 = ((loc >> 1) & 0x4) ^ 0x4; + new_wrdefram = (loc & 1); + if(new_wrdefram != g_c08x_wrdefram) { + fixup_wrdefram(new_wrdefram); + } + switch(loc & 0xf) { + case 0x1: /* 0xc081 */ + case 0x2: /* 0xc082 */ + case 0x5: /* 0xc085 */ + case 0x6: /* 0xc086 */ + case 0x9: /* 0xc089 */ + case 0xa: /* 0xc08a */ + case 0xd: /* 0xc08d */ + case 0xe: /* 0xc08e */ + /* Read rom, set lcbank2 */ + set_statereg(dcycs, (g_c068_statereg & ~(0x04))| + (new_lcbank2 | 0x08)); + break; + case 0x0: /* 0xc080 */ + case 0x3: /* 0xc083 */ + case 0x4: /* 0xc084 */ + case 0x7: /* 0xc087 */ + case 0x8: /* 0xc088 */ + case 0xb: /* 0xc08b */ + case 0xc: /* 0xc08c */ + case 0xf: /* 0xc08f */ + /* Read ram (clear RDROM), set lcbank2 */ + set_statereg(dcycs, (g_c068_statereg & ~(0x0c))| + (new_lcbank2)); + break; + } + return; - /* 0xc090 - 0xc09f */ - case 0x90: case 0x91: case 0x92: case 0x93: - case 0x94: case 0x95: case 0x96: case 0x97: - case 0x98: case 0x99: case 0x9a: case 0x9b: - case 0x9c: case 0x9d: case 0x9e: case 0x9f: - if (g_parallel) - { - parallel_write((word16)loc & 0xf, (byte)val); - return; - } - else - { - UNIMPL_WRITE; - } + /* 0xc090 - 0xc09f */ + case 0x90: case 0x91: case 0x92: case 0x93: + case 0x94: case 0x95: case 0x96: case 0x97: + case 0x98: case 0x99: case 0x9a: case 0x9b: + case 0x9c: case 0x9d: case 0x9e: case 0x9f: + if (g_parallel) + { + parallel_write((word16)loc & 0xf, (byte)val); + return; + } + else + { + UNIMPL_WRITE; + } - /* 0xc0a0 - 0xc0af */ - case 0xa0: case 0xa1: case 0xa3: - case 0xa4: case 0xa5: case 0xa6: case 0xa7: - case 0xa9: case 0xaa: case 0xab: - case 0xac: case 0xad: case 0xae: case 0xaf: - UNIMPL_WRITE; - case 0xa2: /* Burger Times writes here on error */ - case 0xa8: - /* Kurzweil SMP writes to 0xc0a8, ignore it */ - UNIMPL_WRITE; - return; + /* 0xc0a0 - 0xc0af */ + case 0xa0: case 0xa1: case 0xa3: + case 0xa4: case 0xa5: case 0xa6: case 0xa7: + case 0xa9: case 0xaa: case 0xab: + case 0xac: case 0xad: case 0xae: case 0xaf: + UNIMPL_WRITE; + case 0xa2: /* Burger Times writes here on error */ + case 0xa8: + /* Kurzweil SMP writes to 0xc0a8, ignore it */ + UNIMPL_WRITE; + return; - /* 0xc0b0 - 0xc0bf */ - //case 0xb0: - /* Second sight stuff--ignore it */ - return; - //case 0xb1: case 0xb2: case 0xb3: - //case 0xb4: case 0xb5: case 0xb6: case 0xb7: - //case 0xb8: case 0xb9: case 0xba: case 0xbb: - //case 0xbc: case 0xbd: case 0xbe: case 0xbf: - // UNIMPL_WRITE; + /* 0xc0b0 - 0xc0bf */ + //case 0xb0: + /* Second sight stuff--ignore it */ + return; + //case 0xb1: case 0xb2: case 0xb3: + //case 0xb4: case 0xb5: case 0xb6: case 0xb7: + //case 0xb8: case 0xb9: case 0xba: case 0xbb: + //case 0xbc: case 0xbd: case 0xbe: case 0xbf: + // UNIMPL_WRITE; #ifdef HAVE_TFE - /*Uthernet write access on slot 3*/ - case 0xb0: - case 0xb1: - case 0xb2: - case 0xb3: - case 0xb4: - case 0xb5: - case 0xb6: - case 0xb7: - case 0xb8: - case 0xb9: - case 0xba: - case 0xbb: - case 0xbc: - case 0xbd: - case 0xbe: - case 0xbf: - if (tfe_enabled) - { - tfe_store((word16)loc & 0xf, (byte)val); - return; - } - else - { - UNIMPL_WRITE; - } + /*Uthernet write access on slot 3*/ + case 0xb0: + case 0xb1: + case 0xb2: + case 0xb3: + case 0xb4: + case 0xb5: + case 0xb6: + case 0xb7: + case 0xb8: + case 0xb9: + case 0xba: + case 0xbb: + case 0xbc: + case 0xbd: + case 0xbe: + case 0xbf: + if (tfe_enabled) + { + tfe_store((word16)loc & 0xf, (byte)val); + return; + } + else + { + UNIMPL_WRITE; + } #endif - /* 0xc0c0 - 0xc0cf */ - case 0xc0: case 0xc1: case 0xc2: case 0xc3: - case 0xc4: case 0xc5: case 0xc6: case 0xc7: - case 0xc8: case 0xc9: case 0xca: case 0xcb: - case 0xcc: case 0xcd: case 0xce: case 0xcf: - UNIMPL_WRITE; + /* 0xc0c0 - 0xc0cf */ + case 0xc0: case 0xc1: case 0xc2: case 0xc3: + case 0xc4: case 0xc5: case 0xc6: case 0xc7: + case 0xc8: case 0xc9: case 0xca: case 0xcb: + case 0xcc: case 0xcd: case 0xce: case 0xcf: + UNIMPL_WRITE; - /* 0xc0d0 - 0xc0df */ - case 0xd0: case 0xd1: case 0xd2: case 0xd3: - case 0xd4: case 0xd5: case 0xd6: case 0xd7: - case 0xd8: case 0xd9: case 0xda: case 0xdb: - case 0xdc: case 0xdd: case 0xde: case 0xdf: - UNIMPL_WRITE; + /* 0xc0d0 - 0xc0df */ + case 0xd0: case 0xd1: case 0xd2: case 0xd3: + case 0xd4: case 0xd5: case 0xd6: case 0xd7: + case 0xd8: case 0xd9: case 0xda: case 0xdb: + case 0xdc: case 0xdd: case 0xde: case 0xdf: + UNIMPL_WRITE; - /* 0xc0e0 - 0xc0ef */ - case 0xe0: case 0xe1: case 0xe2: case 0xe3: - case 0xe4: case 0xe5: case 0xe6: case 0xe7: - case 0xe8: case 0xe9: case 0xea: case 0xeb: - case 0xec: case 0xed: case 0xee: case 0xef: - write_iwm(loc, val, dcycs); - return; + /* 0xc0e0 - 0xc0ef */ + case 0xe0: case 0xe1: case 0xe2: case 0xe3: + case 0xe4: case 0xe5: case 0xe6: case 0xe7: + case 0xe8: case 0xe9: case 0xea: case 0xeb: + case 0xec: case 0xed: case 0xee: case 0xef: + write_iwm(loc, val, dcycs); + return; - /* 0xc0f0 - 0xc0ff */ - case 0xf0: case 0xf1: case 0xf2: case 0xf3: - case 0xf4: case 0xf5: case 0xf6: case 0xf7: - case 0xf8: case 0xf9: case 0xfa: case 0xfb: - case 0xfc: case 0xfd: case 0xfe: case 0xff: - UNIMPL_WRITE; - default: - printf("WRite loc: %x\n",loc); - exit(-300); - } - break; - case 1: case 2: case 3: case 4: case 5: case 6: case 7: - /* c1000 - c7ff */ - UNIMPL_WRITE; - case 8: case 9: case 0xa: case 0xb: case 0xc: case 0xd: case 0xe: - UNIMPL_WRITE; - case 0xf: - if((loc & 0xfff) == 0xfff) { - /* cfff */ - return; - } - UNIMPL_WRITE; - } - printf("Huh2? Write loc: %x\n", loc); - exit(-290); + /* 0xc0f0 - 0xc0ff */ + case 0xf0: case 0xf1: case 0xf2: case 0xf3: + case 0xf4: case 0xf5: case 0xf6: case 0xf7: + case 0xf8: case 0xf9: case 0xfa: case 0xfb: + case 0xfc: case 0xfd: case 0xfe: case 0xff: + slot7_devsel[loc & 0x0f] = val; /* UNIMPL_WRITE; */ + return; + + default: + printf("WRite loc: %x\n",loc); + exit(-300); + } + break; + case 1: case 2: case 3: case 4: case 5: case 6: case 7: + /* c1000 - c7ff */ + UNIMPL_WRITE; + case 8: case 9: case 0xa: case 0xb: case 0xc: case 0xd: case 0xe: + UNIMPL_WRITE; + case 0xf: + if((loc & 0xfff) == 0xfff) { + /* cfff */ + return; + } + UNIMPL_WRITE; + } + printf("Huh2? Write loc: %x\n", loc); + exit(-290); } #if 0 -int -get_slow_mem(word32 loc, int duff_cycles) -{ - int val; +int get_slow_mem(word32 loc, int duff_cycles) { + int val; - loc = loc & 0x1ffff; - - if((loc &0xf000) == 0xc000) { - return(io_read(loc &0xfff, duff_cycles)); - } - if((loc & 0xf000) >= 0xd000) { - if((loc & 0xf000) == 0xd000) { - if(!LCBANK2) { - /* Not LCBANK2 == be 0xc000 - 0xd000 */ - loc = loc - 0x1000; - } - } - } + loc = loc & 0x1ffff; - val = g_slow_memory_ptr[loc]; + if((loc &0xf000) == 0xc000) { + return(io_read(loc &0xfff, duff_cycles)); + } + if((loc & 0xf000) >= 0xd000) { + if((loc & 0xf000) == 0xd000) { + if(!LCBANK2) { + /* Not LCBANK2 == be 0xc000 - 0xd000 */ + loc = loc - 0x1000; + } + } + } - halt_printf("get_slow_mem: %06x = %02x\n", loc, val); + val = g_slow_memory_ptr[loc]; - return val; + halt_printf("get_slow_mem: %06x = %02x\n", loc, val); + + return val; } -int -set_slow_mem(word32 loc, int val, int duff_cycles) -{ - int or_pos; - word32 or_val; +int set_slow_mem(word32 loc, int val, int duff_cycles) { + int or_pos; + word32 or_val; - loc = loc & 0x1ffff; - if((loc & 0xf000) == 0xc000) { - return(io_write(loc & 0xfff, val, duff_cycles)); - } + loc = loc & 0x1ffff; + if((loc & 0xf000) == 0xc000) { + return(io_write(loc & 0xfff, val, duff_cycles)); + } - if((loc & 0xf000) == 0xd000) { - if(!LCBANK2) { - /* Not LCBANK2 == be 0xc000 - 0xd000 */ - loc = loc - 0x1000; - } - } + if((loc & 0xf000) == 0xd000) { + if(!LCBANK2) { + /* Not LCBANK2 == be 0xc000 - 0xd000 */ + loc = loc - 0x1000; + } + } - if(g_slow_memory_ptr[loc] != val) { - or_pos = (loc >> SHIFT_PER_CHANGE) & 0x1f; - or_val = DEP1(1, or_pos, 0); - if((loc >> CHANGE_SHIFT) >= SLOW_MEM_CH_SIZE || loc < 0) { - printf("loc: %08x!!\n", loc); - exit(11); - } - slow_mem_changed[(loc & 0xffff) >> CHANGE_SHIFT] |= or_val; - } + if(g_slow_memory_ptr[loc] != val) { + or_pos = (loc >> SHIFT_PER_CHANGE) & 0x1f; + or_val = DEP1(1, or_pos, 0); + if((loc >> CHANGE_SHIFT) >= SLOW_MEM_CH_SIZE || loc < 0) { + printf("loc: %08x!!\n", loc); + exit(11); + } + slow_mem_changed[(loc & 0xffff) >> CHANGE_SHIFT] |= or_val; + } /* doesn't shadow text/hires graphics properly! */ - g_slow_memory_ptr[loc] = val; + g_slow_memory_ptr[loc] = val; - return val; + return val; } #endif @@ -2519,87 +2490,81 @@ set_slow_mem(word32 loc, int val, int duff_cycles) /* vertical blanking engages on line 192, even if in super hires mode */ /* (Last 8 lines in SHR are drawn with vbl_active set */ -word32 -get_lines_since_vbl(double dcycs) -{ - double dcycs_since_last_vbl; - double dlines_since_vbl; - double dcyc_line_start; - word32 lines_since_vbl; - int offset; +word32 get_lines_since_vbl(double dcycs) { + double dcycs_since_last_vbl; + double dlines_since_vbl; + double dcyc_line_start; + word32 lines_since_vbl; + int offset; - dcycs_since_last_vbl = dcycs - g_last_vbl_dcycs; + dcycs_since_last_vbl = dcycs - g_last_vbl_dcycs; - dlines_since_vbl = dcycs_since_last_vbl * (1.0 / 65.0); - lines_since_vbl = (int)dlines_since_vbl; - dcyc_line_start = (double)lines_since_vbl * 65.0; + dlines_since_vbl = dcycs_since_last_vbl * (1.0 / 65.0); + lines_since_vbl = (int)dlines_since_vbl; + dcyc_line_start = (double)lines_since_vbl * 65.0; - offset = ((int)(dcycs_since_last_vbl - dcyc_line_start)) & 0xff; + offset = ((int)(dcycs_since_last_vbl - dcyc_line_start)) & 0xff; - lines_since_vbl = (lines_since_vbl << 8) + offset; + lines_since_vbl = (lines_since_vbl << 8) + offset; - if(lines_since_vbl < 0x10680) { - return lines_since_vbl; - } else { - halt_printf("lines_since_vbl: %08x!\n", lines_since_vbl); - printf("dc_s_l_v: %f, dcycs: %f, last_vbl_cycs: %f\n", - dcycs_since_last_vbl, dcycs, g_last_vbl_dcycs); - show_dtime_array(); - show_all_events(); - /* U_STACK_TRACE(); */ - } + if(lines_since_vbl < 0x10680) { + return lines_since_vbl; + } else { + halt_printf("lines_since_vbl: %08x!\n", lines_since_vbl); + printf("dc_s_l_v: %f, dcycs: %f, last_vbl_cycs: %f\n", + dcycs_since_last_vbl, dcycs, g_last_vbl_dcycs); + show_dtime_array(); + show_all_events(); + /* U_STACK_TRACE(); */ + } - return lines_since_vbl; + return lines_since_vbl; } -int -in_vblank(double dcycs) -{ - int lines_since_vbl; +int in_vblank(double dcycs) { + int lines_since_vbl; - lines_since_vbl = get_lines_since_vbl(dcycs); + lines_since_vbl = get_lines_since_vbl(dcycs); - if(lines_since_vbl >= 0xc000) { - return 1; - } + if(lines_since_vbl >= 0xc000) { + return 1; + } - return 0; + return 0; } /* horizontal video counter goes from 0x00,0x40 - 0x7f, then 0x80,0xc0-0xff */ /* over 2*65 cycles. The last visible screen pos is 0x7f and 0xff */ /* This matches GSport starting line 0 at the border for line -1 */ -int -read_vid_counters(int loc, double dcycs) -{ - word32 mask; - int lines_since_vbl; +int read_vid_counters(int loc, double dcycs) { + word32 mask; + int lines_since_vbl; - loc = loc & 0xf; + loc = loc & 0xf; - lines_since_vbl = get_lines_since_vbl(dcycs); + lines_since_vbl = get_lines_since_vbl(dcycs); - lines_since_vbl += 0x10000; - if(lines_since_vbl >= 0x20000) { - lines_since_vbl = lines_since_vbl - 0x20000 + 0xfa00; - } + lines_since_vbl += 0x10000; + if(lines_since_vbl >= 0x20000) { + lines_since_vbl = lines_since_vbl - 0x20000 + 0xfa00; + } - if(lines_since_vbl > 0x1ffff) { - halt_printf("lines_since_vbl: %04x, dcycs: %f, last_vbl: %f\n", - lines_since_vbl, dcycs, g_last_vbl_dcycs); - } + if(lines_since_vbl > 0x1ffff) { + halt_printf("lines_since_vbl: %04x, dcycs: %f, last_vbl: %f\n", + lines_since_vbl, dcycs, g_last_vbl_dcycs); + } - if(loc == 0xe) { - /* Vertical count */ - return (lines_since_vbl >> 9) & 0xff; - } + if(loc == 0xe) { + /* Vertical count */ + return (lines_since_vbl >> 9) & 0xff; + } - mask = (lines_since_vbl >> 1) & 0x80; + mask = (lines_since_vbl >> 1) & 0x80; - lines_since_vbl = (lines_since_vbl & 0xff); - if(lines_since_vbl >= 0x01) { - lines_since_vbl = (lines_since_vbl + 0x3f) & 0x7f; - } - return (mask | (lines_since_vbl & 0xff)); + lines_since_vbl = (lines_since_vbl & 0xff); + if(lines_since_vbl >= 0x01) { + lines_since_vbl = (lines_since_vbl + 0x3f) & 0x7f; + } + return (mask | (lines_since_vbl & 0xff)); } diff --git a/src/options.c b/src/options.c new file mode 100644 index 0000000..87289bd --- /dev/null +++ b/src/options.c @@ -0,0 +1,453 @@ +/* + GSport - an Apple //gs Emulator + Copyright (C) 2010 - 2019 by GSport contributors + Copyright (C) 2016 - 2018 Dagen Brock + + Based on the KEGS emulator written by and Copyright (C) 2003 Kent Dickey + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 2 of the License, or (at your + option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include +#include +#include +#include "options.h" +#include "glog.h" +#include "defc.h" + +// config is parsed in config.c :: config_parse_config_gsport_file() +// cli is parsed here. would be nice to reuse some code + +// Halts on bad reads. Sets flags via engine_s.s:set_halt_act() function +extern int g_halt_on_bad_read; // defined in sim65816.c +// Ignore bad memory accesses. +extern int g_ignore_bad_acc; // defined in sim65816.c +// Ignore red alert halts. +extern int g_ignore_halts; // defined in sim65816.c +// Size of RAM memory expansion card in bytes (default = 8*1024*1024 = 8MB) +extern int g_mem_size_exp; // defined in sim65816.c +// Implemented in display drivers (not SDL2 though) ? +extern int g_screen_redraw_skip_amt; // defined in video.c, implemented in various driver files + +// Using simple dhires color map +extern int g_use_dhr140; // defined in video.c +// Force B/W hires modes +extern int g_use_bw_hires; // defined in video.c +// Set starting X/Y positions +extern int g_startx; // defined in video.c +extern int g_starty; // defined in video.c +extern int g_startw; // defined in video.c +extern int g_starth; // defined in video.c +// Use High DPI (Retina) display - SDL2 +extern int g_highdpi; // defined in video.c +// Create borderless window - SDL2 +extern int g_borderless; // defined in video.c +// Allow window resizing, dragging to scale - SDL2 +extern int g_resizeable; // defined in video.c +// Allow the window scaling to be free from aspect contraints - SDL2 +extern int g_noaspect; +// Don't explicitly set vsync present flag on renderer - SDL2 +extern int g_novsync; // defined in video.c +// Don't explicitly set HW accelerator flag on renderer - SDL2 +extern int g_nohwaccel; // defined in video.c +// Use SDL_WINDOW_FULLSCREEN_DESKTOP for fullscreen instead of switching modes +extern int g_fullscreen_desktop; +// Enable Dagen's scanline simulator (SDL2) +extern int g_scanline_simulator; // defined in sim65816.c +// Ethernet (interface?) +extern int g_ethernet; // defined in sim65816.c +// Enable and set port for Dagen's debugger +extern int g_dbg_enable_port; // defined in debug.c +// Set preferred audio frequency +extern int g_preferred_rate; // defined in sound_driver.c, implemented in various driver files +// Enable/disable audio +extern int g_audio_enable; // defined in sound.c +// Start in fullscreen mode +extern int g_fullscreen; // defined in adb.c, because weird driver writing for x + +// Specify the joystick - SDL2 +extern int g_joystick_number; // defined in joystick_driver.c +extern int g_joystick_x_axis; // defined in joystick_driver.c +extern int g_joystick_y_axis; // defined in joystick_driver.c +extern int g_joystick_x2_axis; // defined in joystick_driver.c +extern int g_joystick_y2_axis; // defined in joystick_driver.c +extern int g_joystick_button_0; // defined in joystick_driver.c +extern int g_joystick_button_1; // defined in joystick_driver.c +extern int g_joystick_button_2; // defined in joystick_driver.c +extern int g_joystick_button_3; // defined in joystick_driver.c + + +// DEPRECATED: force bit depth (15/16/24) for X-Windows, might still work. +extern int g_force_depth; // defined in sim65816.c +// DEPRECATED: Use X shared memory (MIT-SHM) +extern int g_use_shmem; // defined in all the various drivers +// DEPRECATED: Set DISPLAY environment variable for X-Windows +extern char g_display_env[512]; // defined in sim65816.c +// DEPRECATED: Set VERBOSE flags for one or more subsystems as defined below +extern int Verbose; // defined in sim65816.c +// #define VERBOSE_DISK 0x001 +// #define VERBOSE_IRQ 0x002 +// #define VERBOSE_CLK 0x004 +// #define VERBOSE_SHADOW 0x008 +// #define VERBOSE_IWM 0x010 +// #define VERBOSE_DOC 0x020 +// #define VERBOSE_ADB 0x040 +// #define VERBOSE_SCC 0x080 +// #define VERBOSE_TEST 0x100 +// #define VERBOSE_VIDEO 0x200 +// #define VERBOSE_MAC +// This is deprecated because it is not well-defined or supported +// It should still work and some sort of system should be put in place +// to extend and fix this, or take it out. + + +extern const char *g_config_gsport_name_list[]; +extern char g_config_gsport_screenshot_dir[]; +extern char *final_arg; + +static const char parse_log_prefix[] = "Option set [CLI]:"; + +// this is here because we need to flip a bit to force B/W modes +extern int g_cur_a2_stat; + +void help_exit(); // displays the cli help text and exits with 1 + +int parse_int(const char *str1, int min, int max) +{ + int tmp; + tmp = strtol(str1, 0, 0); + if (tmp > max) { tmp = max; } + if (tmp < min) { tmp = min; } + return tmp; +} +void parse_cli_options(int argc, char **argv) { + int i; + int tmp1; + int skip_amt; + char *final_arg = 0; + + + for(i = 1; i < argc; i++) { + if( (!strcmp("-?", argv[i])) || (!strcmp("-h", argv[i])) || (!strcmp("-help", argv[i]))) { + help_exit(); + } else if(!strcmp("-badrd", argv[i])) { + glogf("%s Halting on bad reads", parse_log_prefix); + g_halt_on_bad_read = 2; + } else if(!strcmp("-fullscreen", argv[i])) { + glogf("%s Starting emulator in fullscreen", parse_log_prefix); + g_fullscreen = 1; + } else if(!strcmp("-highdpi", argv[i])) { + glogf("%s Creating window in High DPI mode", parse_log_prefix); + g_highdpi = 1; + } else if(!strcmp("-borderless", argv[i])) { + glogf("%s Creating borderless window", parse_log_prefix); + g_borderless = 1; + } else if(!strcmp("-resizeable", argv[i])) { + glogf("%s Window will be resizeable", parse_log_prefix); + g_resizeable = 1; + } else if(!strcmp("-noaspect", argv[i])) { + glogf("%s Window will scale freely, without locking the aspect ratio", parse_log_prefix); + g_noaspect = 1; + } else if(!strcmp("-novsync", argv[i])) { + glogf("%s Renderer skipping vsync flag", parse_log_prefix); + g_novsync = 1; + } else if(!strcmp("-nohwaccel", argv[i])) { + glogf("%s Renderer skipping HW accel flag", parse_log_prefix); + g_nohwaccel = 1; + } else if(!strcmp("-fulldesk", argv[i])) { + glogf("%s Using desktop fullscreen mode", parse_log_prefix); + g_fullscreen_desktop = 1; + } else if(!strcmp("-noignbadacc", argv[i])) { + glogf("%s Not ignoring bad memory accesses", parse_log_prefix); + g_ignore_bad_acc = 0; + } else if(!strcmp("-noignhalt", argv[i])) { + glogf("%s Not ignoring code red halts", parse_log_prefix); + g_ignore_halts = 0; + } else if(!strcmp("-mem", argv[i])) { + if((i+1) >= argc) { + glogf("%s Error, option '-mem' missing argument", parse_log_prefix); + exit(1); + } + g_mem_size_exp = strtol(argv[i+1], 0, 0) & 0x00ff0000; + glogf("%s Using %d as memory size", parse_log_prefix, g_mem_size_exp); + i++; + } else if(!strcmp("-skip", argv[i])) { + if((i+1) >= argc) { + glogf("%s Error, option '-skip' missing argument", parse_log_prefix); + exit(1); + } + skip_amt = strtol(argv[i+1], 0, 0); + glogf("%s Using %d as skip_amt", parse_log_prefix, skip_amt); + g_screen_redraw_skip_amt = skip_amt; + i++; + } else if(!strcmp("-audio", argv[i])) { + if((i+1) >= argc) { + glogf("%s Error, option '-audio' missing argument", parse_log_prefix); + exit(1); + } + tmp1 = strtol(argv[i+1], 0, 0); + glogf("%s Using %d as audio enable val", parse_log_prefix, tmp1); + g_audio_enable = tmp1; + i++; + } else if(!strcmp("-arate", argv[i])) { + if((i+1) >= argc) { + glogf("%s Error, option '-arate' missing argument", parse_log_prefix); + exit(1); + } + tmp1 = strtol(argv[i+1], 0, 0); + glogf("%s Using %d as preferred audio rate", parse_log_prefix, tmp1); + g_preferred_rate = tmp1; + i++; + } else if(!strcmp("-v", argv[i])) { + if((i+1) >= argc) { + glogf("%s Error, option '-v' missing argument", parse_log_prefix); + exit(1); + } + tmp1 = strtol(argv[i+1], 0, 0); + glogf("%s Setting Verbose = 0x%03x", parse_log_prefix, tmp1); + Verbose = tmp1; + i++; + } else if(!strcmp("-display", argv[i])) { + if((i+1) >= argc) { + glogf("%s Error, option '-display' missing argument", parse_log_prefix); + exit(1); + } + glogf("%s Using %s as display", parse_log_prefix, argv[i+1]); + sprintf(g_display_env, "DISPLAY=%s", argv[i+1]); + putenv(&g_display_env[0]); + i++; + } else if(!strcmp("-noshm", argv[i])) { + glogf("%s Not using X shared memory", parse_log_prefix); + g_use_shmem = 0; + } else if(!strcmp("-joy", argv[i])) { + if((i+1) >= argc) { + glogf("%s Error, option '-joy' missing argument", parse_log_prefix); + exit(1); + } + tmp1 = strtol(argv[i+1], 0, 0); // no bounds check, not sure what ids we get + glogf("%s Setting joystick number %d", parse_log_prefix, tmp1); + g_joystick_number = tmp1; + i++; + } else if(!strcmp("-joy-x", argv[i])) { + if((i+1) >= argc) { + glogf("%s Error, option '-joy-x' missing argument", parse_log_prefix); + exit(1); + } + tmp1 = strtol(argv[i+1], 0, 0); // no bounds check, not sure what ids we get + glogf("%s Setting joystick X axis %d", parse_log_prefix, tmp1); + g_joystick_x_axis = tmp1; + i++; + } else if(!strcmp("-joy-y", argv[i])) { + if((i+1) >= argc) { + glogf("%s Error, option '-joy-y' missing argument", parse_log_prefix); + exit(1); + } + tmp1 = strtol(argv[i+1], 0, 0); // no bounds check, not sure what ids we get + glogf("%s Setting joystick Y axis %d", parse_log_prefix, tmp1); + g_joystick_y_axis = tmp1; + i++; + } else if(!strcmp("-joy-x2", argv[i])) { + if((i+1) >= argc) { + glogf("%s Error, option '-joy-x2' missing argument", parse_log_prefix); + exit(1); + } + tmp1 = strtol(argv[i+1], 0, 0); // no bounds check, not sure what ids we get + glogf("%s Setting joystick X2 axis %d", parse_log_prefix, tmp1); + g_joystick_x2_axis = tmp1; + i++; + } else if(!strcmp("-joy-y2", argv[i])) { + if((i+1) >= argc) { + glogf("%s Error, option '-joy-y2' missing argument", parse_log_prefix); + exit(1); + } + tmp1 = strtol(argv[i+1], 0, 0); // no bounds check, not sure what ids we get + glogf("%s Setting joystick Y2 axis %d", parse_log_prefix, tmp1); + g_joystick_y2_axis = tmp1; + i++; + } else if(!strcmp("-joy-b0", argv[i])) { + if((i+1) >= argc) { + glogf("%s Error, option '-joy-b0' missing argument", parse_log_prefix); + exit(1); + } + tmp1 = strtol(argv[i+1], 0, 0); // no bounds check, not sure what ids we get + glogf("%s Setting joystick Button 0 to Gamepad %d", parse_log_prefix, tmp1); + g_joystick_button_0 = tmp1; + i++; + } else if(!strcmp("-joy-b1", argv[i])) { + if((i+1) >= argc) { + glogf("%s Error, option '-joy-b1' missing argument", parse_log_prefix); + exit(1); + } + tmp1 = strtol(argv[i+1], 0, 0); // no bounds check, not sure what ids we get + glogf("%s Setting joystick Button 1 to Gamepad %d", parse_log_prefix, tmp1); + g_joystick_button_1 = tmp1; + i++; + } else if(!strcmp("-joy-b2", argv[i])) { + if((i+1) >= argc) { + glogf("%s Error, option '-joy-b2' missing argument", parse_log_prefix); + exit(1); + } + tmp1 = strtol(argv[i+1], 0, 0); // no bounds check, not sure what ids we get + glogf("%s Setting joystick Button 2 to Gamepad %d", parse_log_prefix, tmp1); + g_joystick_button_2 = tmp1; + i++; + } else if(!strcmp("-joy-b3", argv[i])) { + if((i+1) >= argc) { + glogf("%s Error, option '-joy-b3' missing argument", parse_log_prefix); + exit(1); + } + tmp1 = strtol(argv[i+1], 0, 0); // no bounds check, not sure what ids we get + glogf("%s Setting joystick Button 3 to Gamepad %d", parse_log_prefix, tmp1); + g_joystick_button_3 = tmp1; + i++; + } else if(!strcmp("-dhr140", argv[i])) { + glogf("%s Using simple dhires color map", parse_log_prefix); + g_use_dhr140 = 1; + } else if(!strcmp("-bw", argv[i])) { + glogf("%s Forcing black-and-white hires modes", parse_log_prefix); + g_cur_a2_stat |= ALL_STAT_COLOR_C021; + g_use_bw_hires = 1; + } else if(!strcmp("-scanline", argv[i])) { + glogf("%s Enable scanline simulation", parse_log_prefix); + if((i+1) >= argc) { + glogf("%s Error, option '-scanline' missing argument", parse_log_prefix); + exit(1); + } + tmp1 = parse_int(argv[i+1], 0, 100); + glogf("%s Setting scanline simulator darkness to %d%%", parse_log_prefix, tmp1); + g_scanline_simulator = tmp1; + i++; + } else if(!strcmp("-enet", argv[i])) { + if((i+1) >= argc) { + glogf("%s Error, option '-enet' missing argument", parse_log_prefix); + exit(1); + } + tmp1 = strtol(argv[i+1], 0, 0); + glogf("%s Using %d as ethernet enable val", parse_log_prefix, tmp1); + g_ethernet = tmp1; + i++; + } else if(!strcmp("-x", argv[i])) { + if((i+1) >= argc) { + glogf("%s Error, option '-x' missing argument", parse_log_prefix); + exit(1); + } + tmp1 = strtol(argv[i+1], 0, 0); + glogf("%s Using %d as x val", parse_log_prefix, tmp1); + g_startx = tmp1; + i++; + } else if(!strcmp("-y", argv[i])) { + if((i+1) >= argc) { + glogf("%s Error, option '-y' missing argument", parse_log_prefix); + exit(1); + } + tmp1 = strtol(argv[i+1], 0, 0); + glogf("%s Using %d as y val", parse_log_prefix, tmp1); + g_starty = tmp1; + i++; + } else if(!strcmp("-sw", argv[i])) { + if((i+1) >= argc) { + glogf("%s Error, option '-sw' missing argument", parse_log_prefix); + exit(1); + } + tmp1 = strtol(argv[i+1], 0, 0); + glogf("%s Using %d as width val", parse_log_prefix, tmp1); + g_startw = tmp1; + i++; + } else if(!strcmp("-sh", argv[i])) { + if((i+1) >= argc) { + glogf("%s Error, option '-sh' missing argument", parse_log_prefix); + exit(1); + } + tmp1 = strtol(argv[i+1], 0, 0); + glogf("%s Using %d as height val", parse_log_prefix, tmp1); + g_starth = tmp1; + i++; + } else if(!strcmp("-config", argv[i])) { // Config file passed + if((i+1) >= argc) { + glogf("%s Error, option '-config' missing argument", parse_log_prefix); + exit(1); + } + glogf("%s Using %s as configuration file", parse_log_prefix, argv[i+1]); + + g_config_gsport_name_list[0] = argv[i+1]; // overwrite default list with passed item as sole option + g_config_gsport_name_list[1] = 0; // terminate string array + i++; + } else if (!strcmp("-ssdir", argv[i])) { // screenshot directory passed + strcpy(g_config_gsport_screenshot_dir, argv[i+1]); + struct stat path_stat; + stat(g_config_gsport_screenshot_dir, &path_stat); // (weakly) validate path + if (!S_ISDIR(path_stat.st_mode)) { + strcpy(g_config_gsport_screenshot_dir, "./"); + } + glogf("%s Using %s for screenshot path", parse_log_prefix, g_config_gsport_screenshot_dir); + i++; + } else if(!strcmp("-debugport", argv[i])) { // Debug port passed + if((i+1) >= argc) { + glogf("%s Error, option '-debugport' missing argument", parse_log_prefix); + exit(1); + } + g_dbg_enable_port = strtol(argv[i+1], 0, 0); + glogf("%s Using %d for debug port", parse_log_prefix, g_dbg_enable_port); + i++; + } else { + if ((i == (argc - 1)) && (strncmp("-", argv[i], 1) != 0)) { + final_arg = argv[i]; + } else { + glogf("%s Error, bad option: %s for debug port", parse_log_prefix, argv[i]); + exit(3); + } + } + } +} + +void help_exit() { + printf(" USAGE: \n\n"); + printf(" ./gsport # simple - uses default config.txt\n"); + printf(" ./gsport -config games_hds.gsp # set custom config file\n\n"); + printf(" You need to supply your own Apple IIgs Firmware ROM image.\n"); + printf(" Press F4 when running gsport to enter config menu and select ROM image location.\n"); + printf(" Or copy the ROM image to the gsport directory.\n"); + printf(" It will search for: \"ROM\", \"ROM.01\", \"ROM.03\" \n\n\n"); + printf(" Other command line options: \n\n"); + printf(" -badrd Halt on bad reads\n"); + printf(" -noignbadacc Don’t ignore bad memory accesses\n"); + printf(" -noignhalt Don’t ignore code red halts\n"); + printf(" -test Allow testing\n"); + printf(" -joy Set joystick number\n"); + printf(" -bw Force B/W modes\n"); + printf(" -dhr140 Use simple double-hires color map\n"); + printf(" -fullscreen Attempt to start emulator in fullscreen\n"); + printf(" -highdpi Attempt to open window in high DPI\n"); + printf(" -borderless Attempt to create borderless window\n"); + printf(" -resizeable Allow you to resize window (non-integral scaling to pixel)\n"); + printf(" -mem value Set memory size to value\n"); + printf(" -skip value Set skip_amt to value\n"); + printf(" -audio value Set audio enable to value\n"); + printf(" -arate value Set preferred audio rate to value\n"); + printf(" -enet value Set ethernet to value\n"); + printf(" -config value Set config file to value\n"); + printf(" -debugport value Set debugport to value\n"); + printf(" -ssdir value Set screenshot save directory to value\n"); + printf(" -scanline value Enable scanline simulator at value %%\n"); + printf(" -x value Open emulator window at x value\n"); + printf(" -y value Open emulator window at y value\n"); + printf(" -sw value Scale window to sw pixels wide\n"); + printf(" -sh value Scale window to sh pixels high\n"); + printf(" -novsync Don't force emulator to sync each frame\n"); + printf(" -fulldesk Use desktop 'fake' fullscreen mode\n"); + //printf(" -v value Set verbose flags to value\n\n"); + printf(" Note: The final argument, if not a flag, will be tried as a mountable device.\n\n"); + exit(1); +} diff --git a/src/options.h b/src/options.h new file mode 100644 index 0000000..1868704 --- /dev/null +++ b/src/options.h @@ -0,0 +1,29 @@ +/* + GSport - an Apple //gs Emulator + Copyright (C) 2010 - 2019 by GSport contributors + Copyright (C) 2016 - 2018 Dagen Brock + + Based on the KEGS emulator written by and Copyright (C) 2003 Kent Dickey + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 2 of the License, or (at your + option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#ifdef __cplusplus +extern "C" { +#endif + void parse_cli_options(int argc, char **argv); +#ifdef __cplusplus +} +#endif diff --git a/src/protos.h b/src/protos.h index 8f9a82a..445c355 100644 --- a/src/protos.h +++ b/src/protos.h @@ -1,6 +1,7 @@ /* GSport - an Apple //gs Emulator - Copyright (C) 2010 - 2012 by GSport contributors + Copyright (C) 2010 - 2019 by GSport contributors + Copyright (C) 2016 - 2018 Dagen Brock Based on the KEGS emulator written by and Copyright (C) 2003 Kent Dickey @@ -45,9 +46,6 @@ void x_full_screen(int do_full); void clipboard_paste(void); int clipboard_get_char(void); -/* test65.c */ -void do_gen_test(int got_num, int base_seed); - /* engine.s and engine_c.c */ void fixed_memory_ptrs_init(); @@ -57,6 +55,7 @@ word32 get_itimer(void); word32 get_memory_c(word32 addr, int cycs); word32 get_memory16_c(word32 addr, int cycs); word32 get_memory24_c(word32 addr, int cycs); +word32 get_memory32_c(word32 addr, int cycs); int get_memory_asm(word32 addr, int cycs); int get_memory16_asm(word32 addr, int cycs); @@ -67,6 +66,7 @@ int get_memory16_act_stub_asm(word32 addr, int cycs); void set_memory_c(word32 addr, word32 val, int cycs); void set_memory16_c(word32 addr, word32 val, int cycs); void set_memory24_c(word32 addr, word32 val, int cycs); +void set_memory32_c(word32 addr, word32 val, int cycs); int enter_engine(Engine_reg *ptr); void clr_halt_act(void); @@ -121,6 +121,7 @@ int read_adb_ram(word32 addr); void write_adb_ram(word32 addr, int val); int adb_get_keypad_xy(int get_y); int update_mouse(int x, int y, int button_states, int buttons_valid); +int update_mouse_w_delta(int x, int y, int button_states, int buttons_valid, int delta_x, int delta_y); int mouse_read_c024(double dcycs); void mouse_compress_fifo(double dcycs); void adb_key_event(int a2code, int is_up); @@ -176,34 +177,6 @@ void insert_disk(int slot, int drive, const char *name, int ejected, int force_s void eject_named_disk(Disk *dsk, const char *name, const char *partition_name); void eject_disk_by_num(int slot, int drive); void eject_disk(Disk *dsk); -int cfg_get_fd_size(char *filename); -int cfg_partition_read_block(FILE *file, void *buf, int blk, int blk_size); -int cfg_partition_find_by_name_or_num(FILE *file, const char *partnamestr, int part_num, Disk *dsk); -int cfg_maybe_insert_disk(int slot, int drive, const char *namestr); -int cfg_stat(char *path, struct stat *sb); -int cfg_partition_make_list(char *filename, FILE *file); -void cfg_htab_vtab(int x, int y); -void cfg_home(void); -void cfg_cleol(void); -void cfg_putchar(int c); -void cfg_printf(const char *fmt, ...); -void cfg_print_num(int num, int max_len); -void cfg_get_disk_name(char *outstr, int maxlen, int type_ext, int with_extras); -void cfg_parse_menu(Cfg_menu *menuptr, int menu_pos, int highlight_pos, int change); -void cfg_get_base_path(char *pathptr, const char *inptr, int go_up); -void cfg_file_init(void); -void cfg_free_alldirents(Cfg_listhdr *listhdrptr); -void cfg_file_add_dirent(Cfg_listhdr *listhdrptr, const char *nameptr, int is_dir, int size, int image_start, int part_num); -int cfg_dirent_sortfn(const void *obj1, const void *obj2); -int cfg_str_match(const char *str1, const char *str2, int len); -void cfg_file_readdir(const char *pathptr); -char *cfg_shorten_filename(const char *in_ptr, int maxlen); -void cfg_fix_topent(Cfg_listhdr *listhdrptr); -void cfg_file_draw(void); -void cfg_partition_selected(void); -void cfg_file_update_ptr(char *str); -void cfg_file_selected(void); -void cfg_file_handle_key(int key); void config_control_panel(void); @@ -219,6 +192,7 @@ void show_bp(void); void delete_bp(word32 addr); void do_blank(void); void do_go(void); +void do_go_debug(void); // socket debug ver void do_step(void); void xam_mem(int count); void show_hex_mem(int startbank, word32 start, int endbank, word32 end, int count); diff --git a/src/sdl2_driver.c b/src/sdl2_driver.c new file mode 100644 index 0000000..c592a0c --- /dev/null +++ b/src/sdl2_driver.c @@ -0,0 +1,887 @@ +/* + GSport - an Apple //gs Emulator + Copyright (C) 2010 - 2019 by GSport contributors + Copyright (C) 2016 - 2018 Dagen Brock + + Based on the KEGS emulator written by and Copyright (C) 2003 Kent Dickey + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 2 of the License, or (at your + option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +// fps shiz +unsigned int lastTime = 0, currentTime, frames; + +// @todo: mouse clip bugs.. great western shootout. Paint 8/16. still in win32 +#include "SDL.h" +#include "SDL_image.h" +#include "glog.h" + +#include +#include +#include +#include +#include // just for basename :P +#include +#include "defc.h" +#ifdef HAVE_ICON // Currently a flag because not supported outside of SDL builds. Looking at full solution. + #include "icongs.h" +#endif +#ifdef _WIN32 + #include +#endif +// BITMASKS +#define ShiftMask 1 +#define ControlMask 4 +#define LockMask 2 + +int g_use_shmem = 0; + +int g_num_check_input_calls = 0; +int g_check_input_flush_rate = 2; +int g_win_status_debug = 0; // Current visibility of status lines. +int g_win_status_debug_request = 0; // Desired visibility of status lines. +int g_screen_mdepth = 0; +int kb_shift_control_state = 0; + +void debuginfo_renderer(SDL_Renderer *r); +void x_take_screenshot(); // screenshot stuff +void x_grabmouse(); +int g_screenshot_requested = 0; // DB to know if we want to save a screenshot +extern char g_config_gsport_name[]; +extern char g_config_gsport_screenshot_dir[]; +int screenshot_index = 0; // allows us to save time by not scanning from 0 each time +char screenshot_filename[256]; + +extern int g_fullscreen; // only checked at start if set via CLI, otherwise it's set via function call x_full_screen() +extern int g_grabmouse; +extern int g_highdpi; +extern int g_borderless; +extern int g_resizeable; +extern int g_noaspect; +extern int g_novsync; +extern int g_nohwaccel; +extern int g_fullscreen_desktop; +extern int g_scanline_simulator; +extern int g_startx; +extern int g_starty; +extern int g_startw; +extern int g_starth; +extern int g_screen_depth; +extern int g_quit_sim_now; +extern int g_border_sides_refresh_needed; +extern int g_border_special_refresh_needed; +extern int g_status_refresh_needed; +extern int g_lores_colors[]; +extern int g_a2vid_palette; +extern int g_installed_full_superhires_colormap; +extern char *g_status_ptrs[MAX_STATUS_LINES]; +extern word32 g_a2_screen_buffer_changed; +extern word32 g_full_refresh_needed; +extern word32 g_palette_8to1624[256]; +extern word32 g_a2palette_8to1624[256]; +extern Kimage g_mainwin_kimage; +extern const char g_gsport_version_str[]; // version string for title bar + +SDL_Window *window; // Declare a pointer +SDL_Renderer *renderer; +SDL_Texture *texture; +SDL_Texture *overlay_texture; // This is used for scanline simulation. Could be more in future (HUD). +Uint32 *overlay_pixels; + +static char *g_clipboard = NULL; // clipboard variables +static size_t g_clipboard_pos = 0; + +void dev_video_init_sdl(); +void handle_sdl_key_event(SDL_Event event); +void check_input_events_sdl(); +void handle_sdl_mouse_event(SDL_Event event); + +int g_num_a2_keycodes = 0; +int a2_key_to_sdlkeycode[][3] = { + { 0x35, SDLK_ESCAPE, 0 }, + { 0x7a, SDLK_F1, 0 }, + { 0x78, SDLK_F2, 0 }, + { 0x63, SDLK_F3, 0 }, + { 0x76, SDLK_F4, 0 }, + { 0x60, SDLK_F5, 0 }, + { 0x61, SDLK_F6, 0 }, + { 0x62, SDLK_F7, 0 }, + { 0x64, SDLK_F8, 0 }, + { 0x65, SDLK_F9, 0 }, + { 0x6d, SDLK_F10, 0 }, + { 0x67, SDLK_F11, 0 }, + { 0x6f, SDLK_F12, 0 }, + { 0x69, SDLK_F13, 0 }, + { 0x6b, SDLK_F14, 0 }, + { 0x71, SDLK_F15, 0 }, + { 0x7f, SDLK_PAUSE, 0 }, + { 0x32, SDLK_BACKQUOTE, '~' }, /* Key number 18? */ + { 0x12, SDLK_1, '!' }, + { 0x13, SDLK_2, '@' }, + { 0x14, SDLK_3, '#' }, + { 0x15, SDLK_4, '$' }, + { 0x17, SDLK_5, '%' }, + { 0x16, SDLK_6, '^' }, + { 0x1a, SDLK_7, '&' }, + { 0x1c, SDLK_8, '*' }, + { 0x19, SDLK_9, '(' }, + { 0x1d, SDLK_0, ')' }, + { 0x1b, SDLK_MINUS, SDLK_UNDERSCORE }, + { 0x18, SDLK_EQUALS, SDLK_PLUS }, + { 0x33, SDLK_BACKSPACE, 0 }, + { 0x72, SDLK_INSERT, 0 }, /* Help? XK_Help */ + /* { 0x73, XK_Home, 0 }, alias XK_Home to be XK_KP_Equal! */ + { 0x74, SDLK_PAGEUP, 0 }, + { 0x47, SDLK_NUMLOCKCLEAR, 0 }, /* Clear, XK_Clear */ + { 0x51, SDLK_KP_EQUALS, 0 }, /* Note XK_Home alias! XK_Home */ + { 0x4b, SDLK_KP_DIVIDE, 0 }, + { 0x43, SDLK_KP_MULTIPLY, 0 }, + { 0x30, SDLK_TAB, 0 }, + { 0x0c, SDLK_q, 'Q' }, + { 0x0d, SDLK_w, 'W' }, + { 0x0e, SDLK_e, 'E' }, + { 0x0f, SDLK_r, 'R' }, + { 0x11, SDLK_t, 'T' }, + { 0x10, SDLK_y, 'Y' }, + { 0x20, SDLK_u, 'U' }, + { 0x22, SDLK_i, 'I' }, + { 0x1f, SDLK_o, 'O' }, + { 0x23, SDLK_p, 'P' }, + { 0x21, SDLK_RIGHTBRACKET, '{' }, + { 0x1e, SDLK_LEFTBRACKET, '}' }, + { 0x2a, SDLK_BACKSLASH, '|' }, /* backslash, bar */ + { 0x75, SDLK_DELETE, 0 }, + { 0x77, SDLK_END, 0 }, + { 0x79, SDLK_PAGEDOWN, 0 }, + { 0x59, SDLK_KP_7, SDLK_HOME }, + { 0x5b, SDLK_KP_8, SDLK_UP }, + { 0x5c, SDLK_KP_9, SDLK_PAGEUP }, + { 0x4e, SDLK_KP_MINUS, 0 }, + { 0x39, SDLK_CAPSLOCK, 0 }, + { 0x00, SDLK_a, 'A' }, + { 0x01, SDLK_s, 'S' }, + { 0x02, SDLK_d, 'D' }, + { 0x03, SDLK_f, 'F' }, + { 0x05, SDLK_g, 'G' }, + { 0x04, SDLK_h, 'H' }, + { 0x26, SDLK_j, 'J' }, + { 0x28, SDLK_k, 'K' }, + { 0x25, SDLK_l, 'L' }, + { 0x29, SDLK_SEMICOLON, SDLK_COLON }, + { 0x27, SDLK_QUOTE, SDLK_QUOTEDBL }, + { 0x24, SDLK_RETURN, 0 }, + { 0x56, SDLK_KP_4, SDLK_LEFT}, + { 0x57, SDLK_KP_5, 0 }, + { 0x58, SDLK_KP_6, SDLK_RIGHT }, + { 0x45, SDLK_KP_PLUS, 0 }, + { 0x38, SDLK_LSHIFT, SDLK_RSHIFT }, + { 0x06, SDLK_z, 'Z' }, + { 0x07, SDLK_x, 'X' }, + { 0x08, SDLK_c, 'C' }, + { 0x09, SDLK_v, 'V' }, + { 0x0b, SDLK_b, 'B' }, + { 0x2d, SDLK_n, 'N' }, + { 0x2e, SDLK_m, 'M' }, + { 0x2b, SDLK_COMMA, SDLK_LESS }, + { 0x2f, SDLK_PERIOD, SDLK_GREATER }, + { 0x2c, SDLK_SLASH, SDLK_QUESTION }, + { 0x3e, SDLK_UP, 0 }, + { 0x53, SDLK_KP_1, 0 }, + { 0x54, SDLK_KP_2, SDLK_DOWN }, + { 0x55, SDLK_KP_3, SDLK_PAGEDOWN }, + { 0x36, SDLK_RCTRL, SDLK_LCTRL }, + #if defined(__APPLE__) + { 0x3a, SDLK_LALT, SDLK_RALT }, /* Option */ + { 0x37, SDLK_LGUI, SDLK_RGUI }, /* Command */ + #else + { 0x3a, SDLK_LGUI, SDLK_RGUI }, /* Command */ + { 0x37, SDLK_LALT, SDLK_RALT }, /* Option */ + #endif + { 0x31, SDLK_SPACE, 0 }, + { 0x3b, SDLK_LEFT, 0 }, + { 0x3d, SDLK_DOWN, 0 }, + { 0x3c, SDLK_RIGHT, 0 }, + { 0x52, SDLK_KP_0, 0 }, + { 0x41, SDLK_KP_PERIOD, 0 }, + { 0x4c, SDLK_KP_ENTER, 0 }, + { -1, -1, -1 } +}; + + + +int main(int argc, char **argv) { + return gsportmain(argc, argv); +} + + +const char *byte_to_binary(int x) { + static char b[9]; + b[0] = '\0'; + + int z; + for (z = 128; z > 0; z >>= 1) + { + strcat(b, ((x & z) == z) ? "1" : "0"); + } + + return b; +} + + +// Queries the Screen to see if set to Fullscreen or Not +// @return SDL_FALSE when windowed, SDL_TRUE when fullscreen +SDL_bool IsFullScreen(SDL_Window *win) { + Uint32 flags = SDL_GetWindowFlags(win); + if (flags & SDL_WINDOW_FULLSCREEN) { + return SDL_TRUE; // return SDL_TRUE if fullscreen + } + return SDL_FALSE; // Return SDL_FALSE if windowed +} + + + +void dev_video_init() { + word32 lores_col; + + // build keycode map ?? + g_num_a2_keycodes = 0; + int i; + int keycode; + + for(i = 0; i < 0x7f; i++) { + keycode = a2_key_to_sdlkeycode[i][0]; + if(keycode < 0) { + g_num_a2_keycodes = i; + break; + } else if(keycode > 0x7f) { + glogf("a2_key_to_xsym[%d] = %02x!\n", i, keycode); + exit(2); + } + } + + // This actually creates our window + dev_video_init_sdl(); + + // @todo DANGER DANGER. HARD CODING THESE.. there was logic for stepping values in xdriver + g_screen_depth = 24; + g_screen_mdepth =32; + video_get_kimages(); + video_get_kimage(&g_mainwin_kimage, 0, g_screen_depth,g_screen_mdepth); + + for(i = 0; i < 256; i++) { + //g_xcolor_a2vid_array[i].pixel = i; + lores_col = g_lores_colors[i & 0xf]; + video_update_color_raw(i, lores_col); + g_a2palette_8to1624[i] = g_palette_8to1624[i]; + } + +} + + +void do_icon() { + #ifdef HAVE_ICON + //surface = SDL_CreateRGBSurfaceFrom(pixels,w,h,depth,pitch,rmask,gmask,bmask,amask); + int size = 256; // icon size + SDL_Surface *surface; // declare an SDL_Surface to be filled in with pixel data from an image file + surface = SDL_CreateRGBSurfaceFrom(icon_pixels,size,size,32,size*4,0xff000000,0x00ff0000,0x0000ff00,0x000000ff); + + // The icon is attached to the window pointer + SDL_SetWindowIcon(window, surface); + // ...and the surface containing the icon pixel data is no longer required. + SDL_FreeSurface(surface); + #endif +} + + +// Initialize our SDL window and texture +void dev_video_init_sdl() { + SDL_Init(SDL_INIT_VIDEO); // Initialize SDL2 + + #if defined __APPLE__ + extern void fix_mac_menu(); + fix_mac_menu(); + #endif + + // Create an application window with the following settings: + char window_title[32]; + sprintf(window_title, "GSport v%-6s", g_gsport_version_str); + int startx = SDL_WINDOWPOS_UNDEFINED; + int starty = SDL_WINDOWPOS_UNDEFINED; + if (g_startx != WINDOWPOS_UNDEFINED) { startx = g_startx; } + if (g_starty != WINDOWPOS_UNDEFINED) { starty = g_starty; } + int more_flags = 0; + // check for CLI fullscreen + if (g_fullscreen) { + more_flags |= SDL_WINDOW_FULLSCREEN_DESKTOP; + } + if (g_highdpi) { + more_flags |= SDL_WINDOW_ALLOW_HIGHDPI; + } + if (g_borderless) { + more_flags |= SDL_WINDOW_BORDERLESS; + } + if (g_resizeable) { + more_flags |= SDL_WINDOW_RESIZABLE; + } + + window = SDL_CreateWindow( + window_title, // window title (GSport vX.X) + startx, + starty, + g_startw, // width, in pixels + g_starth, // height, in pixels + SDL_WINDOW_OPENGL // flags - see below + | more_flags + ); + + + // Check that the window was successfully created + if (window == NULL) { + // In the case that the window could not be made... + glogf("Could not create window: %s", SDL_GetError()); + //@todo die, i guess + } else { + glog("SDL2 graphics initialized"); + } + + // SET WINDOW ICON + do_icon(); + + int renderer_hints = 0; + if (!g_novsync) { + renderer_hints |= SDL_RENDERER_PRESENTVSYNC; + } + if (!g_nohwaccel) { + renderer_hints |= SDL_RENDERER_ACCELERATED; + } + renderer = SDL_CreateRenderer(window, -1, renderer_hints); + debuginfo_renderer(renderer); + + SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "linear"); // make the scaled rendering look smoother. + // SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "best"); // make the scaled rendering look smoother. + if (!g_noaspect) { + SDL_RenderSetLogicalSize(renderer, BASE_WINDOW_WIDTH, X_A2_WINDOW_HEIGHT); + } + + texture = SDL_CreateTexture(renderer, + SDL_PIXELFORMAT_ARGB8888, + SDL_TEXTUREACCESS_STREAMING, + BASE_WINDOW_WIDTH, X_A2_WINDOW_HEIGHT); + // The window is open: could enter program loop here (see SDL_PollEvent()) + //overlay test + overlay_texture = SDL_CreateTexture(renderer, + SDL_PIXELFORMAT_ARGB8888, + SDL_TEXTUREACCESS_STREAMING, + BASE_WINDOW_WIDTH, + X_A2_WINDOW_HEIGHT); + + SDL_SetTextureBlendMode(overlay_texture, SDL_BLENDMODE_BLEND); + overlay_pixels = malloc(BASE_WINDOW_WIDTH*X_A2_WINDOW_HEIGHT*sizeof(Uint32)); + Uint32 pixelARGB = 0x33000000; // default "low grey" + if (overlay_pixels) { + if (g_scanline_simulator > 0) { + pixelARGB = (int)(g_scanline_simulator*2.56) << 24; + } + for (int y=0; ydata_ptr + (srcy * kimage_ptr->width_act + srcx) * pixel_size; + + SDL_Rect dstrect; + dstrect.x = destx; + dstrect.y = desty; + dstrect.w = width; + dstrect.h = height; + int pitch = 640; + if (width < 560) { + pitch = EFF_BORDER_WIDTH; + // seems to be the correct value, but would like clarification + pitch = BORDER_WIDTH+72; + } + SDL_UpdateTexture(texture, &dstrect, src_ptr, pitch*4 ); + + // We now call the render step seperately in sdl_present_buffer once per frame + // SDL picks up the buffer and waits for VBLANK to send it +} + + +void set_refresh_needed() { + g_a2_screen_buffer_changed = -1; + g_full_refresh_needed = -1; + + g_border_sides_refresh_needed = 1; + g_border_special_refresh_needed = 1; + g_status_refresh_needed = 1; +} + + +void x_get_kimage(Kimage *kimage_ptr) { + byte *data; + int width; + int height; + int depth; + + width = kimage_ptr->width_req; + height = kimage_ptr->height; + depth = kimage_ptr->depth; + // this might be too big!!! I had it at depth/3 but it segfaults + data = malloc(width*height*(depth/4)); + kimage_ptr->data_ptr = data; +} + + +void check_input_events() { + check_input_events_sdl(); +} + + +void check_input_events_sdl() { + SDL_Event event; + + while (SDL_PollEvent(&event)) { + /* Check all window events (mostly for Fullscreen) */ + if (event.type == SDL_WINDOWEVENT) { + set_refresh_needed(); + } + switch( event.type ) { + case SDL_KEYDOWN: + case SDL_KEYUP: + handle_sdl_key_event(event); + break; + case SDL_MOUSEMOTION: + case SDL_MOUSEBUTTONUP: + case SDL_MOUSEBUTTONDOWN: + handle_sdl_mouse_event(event); + break; + case SDL_QUIT: + xdriver_end(); + my_exit(1); + break; + case SDL_DROPFILE: + { + char *file = event.drop.file; + cfg_inspect_maybe_insert_file(file, 0); + SDL_free(file); + } + break; + default: + break; + } + } +} + + +int sdl_keysym_to_a2code(int keysym, int is_up) { + int i; + + if(keysym == 0) { + return -1; + } + + if((keysym == SDLK_LSHIFT) || (keysym == SDLK_RSHIFT)) { + if(is_up) { + kb_shift_control_state &= ~ShiftMask; + } else { + kb_shift_control_state |= ShiftMask; + } + } + if(keysym == SDLK_CAPSLOCK) { + if(is_up) { + kb_shift_control_state &= ~LockMask; + } else { + kb_shift_control_state |= LockMask; + } + } + if((keysym == SDLK_LCTRL) || (keysym == SDLK_RCTRL)) { + if(is_up) { + kb_shift_control_state &= ~ControlMask; + } else { + kb_shift_control_state |= ControlMask; + } + } + + /* Look up Apple 2 keycode */ + for(i = g_num_a2_keycodes - 1; i >= 0; i--) { + if((keysym == a2_key_to_sdlkeycode[i][1]) || + (keysym == a2_key_to_sdlkeycode[i][2])) { + return a2_key_to_sdlkeycode[i][0]; + } + } + + return -1; +} + + +void handle_sdl_key_event(SDL_Event event) { + int state_xor; + int state = 0; + int is_up; + + int mod = event.key.keysym.mod; + + // simulate xmask style here + // @todo: this can probably all be refactored now that X is gone + //state = state & (ControlMask | LockMask | ShiftMask); + + // when mod key is first press, comes as event, otherwise just a modifier + if( mod & KMOD_LCTRL || mod & KMOD_RCTRL || + event.type == (SDL_KEYDOWN && (event.key.keysym.sym == SDLK_LCTRL || event.key.keysym.sym == SDLK_RCTRL))) { + state = state | ControlMask; + } + if( (mod & KMOD_LSHIFT) || (mod & KMOD_RSHIFT) || + event.type == (SDL_KEYDOWN && (event.key.keysym.sym == SDLK_LSHIFT || event.key.keysym.sym == SDLK_RSHIFT))) { + state = state | ShiftMask; + } + if( mod & KMOD_CAPS) { + state = state | LockMask; + } + + state_xor = kb_shift_control_state ^ state; + is_up = 0; + if(state_xor & ControlMask) { + is_up = ((state & ControlMask) == 0); + adb_physical_key_update(0x36, is_up); + } + if(state_xor & LockMask) { + is_up = ((state & LockMask) == 0); + adb_physical_key_update(0x39, is_up); + } + if(state_xor & ShiftMask) { + is_up = ((state & ShiftMask) == 0); + adb_physical_key_update(0x38, is_up); + } + + kb_shift_control_state = state; + + is_up = 0; + int a2code; + if (event.type == SDL_KEYUP) { + is_up = 1; + } + switch( event.key.keysym.sym ) { + case SDLK_F11: + if (kb_shift_control_state & ShiftMask) { // SHIFT+F11 + if (!is_up) { + if (g_scanline_simulator) { + glog("Enable scanline simulator"); + g_scanline_simulator = 0; + } else { + glog("Disable scanline simulator"); + g_scanline_simulator = 1; + } + set_refresh_needed(); // make sure user sees it right away + } + } else { + if (!is_up) { + if (!IsFullScreen(window)) { + glog("Enable fullscreen"); + SDL_SetWindowGrab(window, true); + SDL_SetRelativeMouseMode(true); + + Uint32 fullmode = g_fullscreen_desktop ? SDL_WINDOW_FULLSCREEN_DESKTOP : SDL_WINDOW_FULLSCREEN; + SDL_SetWindowFullscreen(window, fullmode); + } else { + glog("Disable fullscreen"); + SDL_SetWindowFullscreen(window, 0); + SDL_SetWindowGrab(window, false); + SDL_SetWindowSize(window, g_startw, g_starth); + SDL_SetRelativeMouseMode(false); + + } + } + } + break; + default: + a2code = sdl_keysym_to_a2code(event.key.keysym.sym, is_up); + if(a2code >= 0) { + adb_physical_key_update(a2code, is_up); + } + break; + } +} + + +void handle_sdl_mouse_event(SDL_Event event) { + int x, y; + + int scaledmotion = 0; + if (scaledmotion) { + x = event.motion.x * A2_WINDOW_WIDTH / g_startw; + y = event.motion.y * A2_WINDOW_HEIGHT / g_starth; + } else { + x = event.motion.x - BASE_MARGIN_LEFT; + y = event.motion.y - BASE_MARGIN_TOP; + } + + switch (event.type) { + case SDL_MOUSEMOTION: + update_mouse_w_delta(x, y, 0, 0, event.motion.xrel, event.motion.yrel); + break; + case SDL_MOUSEBUTTONUP: + update_mouse_w_delta(x, y, 0, event.motion.state &7, 0, 0); + break; + case SDL_MOUSEBUTTONDOWN: + update_mouse_w_delta(x, y, event.motion.state &7, event.motion.state &7 , 0, 0); + break; + } +} + + +void x_push_kimage(Kimage *kimage_ptr, int destx, int desty, int srcx, int srcy, int width, int height) { + sdl_push_kimage(kimage_ptr, destx, desty, srcx, srcy, width, height); +} + + +// called by src/sim65816.c +void x_dialog_create_gsport_conf(const char *str) { + // Just write the config file already... + config_write_config_gsport_file(); +} + + +void x_full_screen(int do_full) { + if (do_full) { + SDL_SetWindowFullscreen(window, SDL_WINDOW_FULLSCREEN_DESKTOP); + } else { + SDL_SetWindowFullscreen(window, 0); + SDL_SetWindowSize(window, BASE_WINDOW_WIDTH, X_A2_WINDOW_HEIGHT); + } +} + + +int file_exists(char *fname) { + if( access( fname, F_OK ) != -1 ) { + return 1; // file exists + } else { + return 0; // file does not exist + } +} + + +// This tries to determine the next screenshot name. +// It uses the config name as the basename. +void make_next_screenshot_filename() { + char filepart[256]; + char filename[256]; + + int available_filename = 0; + while (!available_filename) { + char *bn = basename(g_config_gsport_name); + // get location of '.' + char *dotptr = strchr(bn, '.'); + int index = dotptr - bn; + strncpy(filepart, bn, index); + filepart[index] = '\0'; //terminator + // handle trailing "/" vs no "/" + char tchar = g_config_gsport_screenshot_dir[strlen(g_config_gsport_screenshot_dir) - 1]; + if (tchar == '/') { + sprintf(filename, "%s%s%04d.png",g_config_gsport_screenshot_dir,filepart,screenshot_index); + } else { + sprintf(filename, "%s/%s%04d.png",g_config_gsport_screenshot_dir,filepart,screenshot_index); + } + screenshot_index++; + if (!file_exists(filename)) { + available_filename = 1; + } + } + strcpy(screenshot_filename, filename); +} + + + +// @todo: some error with writing data direct to png. output is empty/transparent? +// workaround is this horrible hack of saving the bmp -> load bmp -> save png +void x_take_screenshot() { + make_next_screenshot_filename(); + glogf("Taking screenshot - %s", screenshot_filename); + SDL_Surface *sshot = SDL_CreateRGBSurface(0, BASE_WINDOW_WIDTH, X_A2_WINDOW_HEIGHT, 32, 0x00ff0000, 0x0000ff00, 0x000000ff, 0xff000000); + SDL_LockSurface(sshot); + int read = SDL_RenderReadPixels(renderer, NULL, SDL_PIXELFORMAT_ARGB8888, sshot->pixels, sshot->pitch); + if (read != 0) { + printf("READPXL FAIL!\n%s\n", SDL_GetError()); + } + SDL_SaveBMP(sshot, "screenshot.bmp"); + SDL_UnlockSurface(sshot); + SDL_FreeSurface(sshot); + + SDL_Surface *s = SDL_CreateRGBSurface(0, BASE_WINDOW_WIDTH, X_A2_WINDOW_HEIGHT, 32, 0x00ff0000, 0x0000ff00, 0x000000ff, 0xff000000); + if (s) { + SDL_Surface * image = SDL_LoadBMP("screenshot.bmp"); + IMG_SavePNG(image, screenshot_filename); + SDL_FreeSurface(image); + } + SDL_FreeSurface(s); +} + + +void clipboard_paste(void) { + + char *cp; + + if (g_clipboard) { + free(g_clipboard); + g_clipboard = NULL; + g_clipboard_pos = 0; + } + + cp = SDL_GetClipboardText(); + if (!cp) return; + + g_clipboard = strdup(cp); + g_clipboard_pos = 0; + + SDL_free(cp); +} + + +int clipboard_get_char(void) { + char c; + + if (!g_clipboard) + return 0; + + /* skip utf-8 characters. */ + do { + c = g_clipboard[g_clipboard_pos++]; + } while (c & 0x80); + + /* windows -- skip the \n in \r\n. */ + if (c == '\r' && g_clipboard[g_clipboard_pos] == '\n') + g_clipboard_pos++; + + /* everybody else -- convert \n to \r */ + if (c == '\n') c = '\r'; + + if (c == 0) { + free(g_clipboard); + g_clipboard = NULL; + g_clipboard_pos = 0; + return 0; + } + + return c | 0x80; +} + +int x_show_alert(int is_fatal, const char *str) { + if (str) { + SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "GSport Alert", str, NULL); + } + return 0; +} + +void xdriver_end() { + SDL_DestroyWindow(window); + iwm_shut(); + // Clean up + SDL_Quit(); +} + +// This will help us determine how well and which drivers are supported on +// different SDL platforms +void debuginfo_renderer(SDL_Renderer *r) { + int n = SDL_GetNumRenderDrivers(); + glogf("**--- SDL DEBUG ------ (%i) drivers", n); + for(int i = 0; i < n; i++) { + SDL_RendererInfo info; + SDL_GetRenderDriverInfo(i, &info); + glogf("* '%s'", info.name); + } + + + SDL_RendererInfo info = {0}; + if (SDL_GetRendererInfo(r,&info) == 0) { + glogf("* SDL_RENDERER_SOFTWARE: %d", (info.flags & SDL_RENDERER_SOFTWARE) > 0 ); + glogf("* SDL_RENDERER_ACCELERATED: %d", (info.flags & SDL_RENDERER_ACCELERATED) > 0 ); + glogf("* SDL_RENDERER_PRESENTVSYNC: %d", (info.flags & SDL_RENDERER_PRESENTVSYNC) > 0 ); + glogf("* SDL_RENDERER_TARGETTEXTURE: %d", (info.flags & SDL_RENDERER_TARGETTEXTURE) > 0 ); + glogf("* active renderer -> '%s'", info.name); + } else { + glog("NO Renderinfo"); + } +} + +// as this is triggered when new images were pushed to backing buffer, +// this is when we want to update frames. +// putting it in x_push_done means we can skip frames that weren't changed. +// the emulator will still run at whatever specified speed. but this way, +// when running in faster 8mhz/unlimited modes, it won't be slowed down by +// forcing every draw at 60FPS sync. +void x_push_done() { + void sdl_present_buffer(); + sdl_present_buffer(); +} + +void sdl_present_buffer() { + SDL_RenderClear(renderer); + SDL_RenderCopy(renderer, texture, NULL, NULL); + if (g_scanline_simulator) { + SDL_RenderCopy(renderer, overlay_texture, NULL, NULL); + } + + SDL_RenderPresent(renderer); + if (g_screenshot_requested) { + x_take_screenshot(); + g_screenshot_requested = 0; + } +} + +void x_grabmouse() { + SDL_SetWindowGrab(window, g_grabmouse); + SDL_SetRelativeMouseMode(g_grabmouse); +} + +// BELOW ARE FUNCTIONS THAT ARE EITHER UNIMPLEMENTED, OR AR NOT RELEVANT TO +// THIS DRIVER. + +// called by src/sim65816.c +void get_ximage(Kimage *kimage_ptr) { } +void x_toggle_status_lines() { } +void x_redraw_status_lines() { } +void x_hide_pointer(int do_hide) { } +void x_auto_repeat_on(int must) { } +void x_auto_repeat_off(int must) { } +void x_release_kimage(Kimage* kimage_ptr) { } +int x_calc_ratio(float x,float y) { return 1; } +void x_set_mask_and_shift(word32 x_mask, word32 *mask_ptr, int *shift_left_ptr, int *shift_right_ptr) { return; } +void x_update_color(int col_num, int red, int green, int blue, word32 rgb) { } +void x_update_physical_colormap() { } +void show_xcolor_array() { } diff --git a/src/sdl2snd_driver.c b/src/sdl2snd_driver.c new file mode 100644 index 0000000..918cca1 --- /dev/null +++ b/src/sdl2snd_driver.c @@ -0,0 +1,222 @@ +/* + GSport - an Apple //gs Emulator + Copyright (C) 2010 - 2019 by GSport contributors + Copyright (C) 2016 - 2018 Dagen Brock + + Based on the KEGS emulator written by and Copyright (C) 2003 Kent Dickey + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 2 of the License, or (at your + option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include "SDL.h" +#include "defc.h" +#include "glog.h" +#include "sound.h" +#include +extern word32 *g_sound_shm_addr; +extern int g_sound_shm_pos; +extern int g_audio_enable; +extern int g_preferred_rate; + +static byte *playbuf = 0; +static int g_playbuf_buffered = 0; +static SDL_AudioSpec spec; +static int snd_buf; +static int snd_write; /* write position into playbuf */ +static /* volatile */ int snd_read = 0; +static int g_sound_paused; +static int g_zeroes_buffered; +static int g_zeroes_seen; +// newer SDL allows you to specify devices. for now, we use what it gives us, +// but this can be made configurable in the future +SDL_AudioDeviceID dev = 0; + + +void sdlsnd_init(word32 *shmaddr) { + if (SDL_Init(SDL_INIT_AUDIO) < 0) { + glog("Could not initialize SDL2 audio"); + g_audio_enable = 0; + } else { + glog("SDL2 audio initialized"); + } + + child_sound_loop(-1, -1, shmaddr); + return; +} + + +void sound_write_sdl(int real_samps, int size) { + +#ifdef HAVE_SDL + int shm_read; + + if (real_samps) { + shm_read = (g_sound_shm_pos - size + SOUND_SHM_SAMP_SIZE)%SOUND_SHM_SAMP_SIZE; + SDL_LockAudioDevice(dev); + while(size > 0) { + if(g_playbuf_buffered >= snd_buf) { + printf("sound_write_sdl failed @%d, %d buffered, %d samples skipped\n",snd_write,g_playbuf_buffered, size); + shm_read += size; + shm_read %= SOUND_SHM_SAMP_SIZE; + size = 0; + } else { + ((word32*)playbuf)[snd_write/SAMPLE_CHAN_SIZE] = g_sound_shm_addr[shm_read]; + shm_read++; + if (shm_read >= SOUND_SHM_SAMP_SIZE) + shm_read = 0; + snd_write += SAMPLE_CHAN_SIZE; + if (snd_write >= snd_buf) + snd_write = 0; + size--; + g_playbuf_buffered += SAMPLE_CHAN_SIZE; + } + } + + assert((snd_buf+snd_write - snd_read)%snd_buf == g_playbuf_buffered%snd_buf); + assert(g_sound_shm_pos == shm_read); + SDL_UnlockAudioDevice(dev); + } + if(g_sound_paused && (g_playbuf_buffered > 0)) { + glogf("Unpausing sound, %d buffered",g_playbuf_buffered); + g_sound_paused = 0; + SDL_PauseAudioDevice(dev, 0); + } + if(!g_sound_paused && (g_playbuf_buffered <= 0)) { + glog("Pausing sound"); + g_sound_paused = 1; + SDL_PauseAudioDevice(dev, 1); + } +#endif +} + +#ifdef HAVE_SDL +/* Callback for sound */ +static void _snd_callback(void* userdata, Uint8 *stream, int len) { + int i; + /* Slurp off the play buffer */ + assert((snd_buf+snd_write - snd_read)%snd_buf == g_playbuf_buffered%snd_buf); + /*printf("slurp %d, %d buffered\n",len, g_playbuf_buffered);*/ + for(i = 0; i < len; ++i) { + if(g_playbuf_buffered <= 0) { + stream[i] = 0; + } else { + stream[i] = playbuf[snd_read++]; + if(snd_read == snd_buf) + snd_read = 0; + g_playbuf_buffered--; + } + } +#if 0 + if (g_playbuf_buffered <= 0) { + printf("snd_callback: buffer empty, Pausing sound\n"); + g_sound_paused = 1; + SDL_PauseAudio(1); + } +#endif + //printf("end slurp %d, %d buffered\n",len, g_playbuf_buffered); +} +#endif + + + + +long sound_init_device_sdl() { +#ifdef HAVE_SDL + long rate; + SDL_AudioSpec wanted; + + if (SDL_Init(SDL_INIT_AUDIO) < 0) { + glogf("SDL2 Couldn't init SDL_INIT_AUDIO: %s!", SDL_GetError()); + return 0; + } + + /* Set the desired format */ + wanted.freq = g_preferred_rate; + wanted.format = AUDIO_S16SYS; + wanted.channels = NUM_CHANNELS; + wanted.samples = 512; + wanted.callback = _snd_callback; + wanted.userdata = NULL; + + /* Open audio, and get the real spec */ + dev = SDL_OpenAudioDevice(NULL, 0, &wanted, &spec, 0); + if (dev == 0) { + glogf("SDL2 Couldn't open audio: %s!", SDL_GetError()); + SDL_QuitSubSystem(SDL_INIT_AUDIO); + return 0; + + } else { + glogf("SDL2 opened audio device: %d", dev); + } + + /* Check everything */ + if(spec.channels != wanted.channels) { + glogf("SDL2 Warning, couldn't get stereo audio format!"); + //goto snd_error; + } + if(spec.format != wanted.format) { + glog("SDL2 Warning, couldn't get a supported audio format!"); + glogf("SDL2 wanted %X, got %X",wanted.format,spec.format); + //goto snd_error; + } + if(spec.freq != wanted.freq) { + glogf("SDL2 wanted rate = %d, got rate = %d", wanted.freq, spec.freq); + } + /* Set things as they really are */ + rate = spec.freq; + + snd_buf = SOUND_SHM_SAMP_SIZE*SAMPLE_CHAN_SIZE; + playbuf = (byte*) malloc(snd_buf); + if (!playbuf) + goto snd_error; + g_playbuf_buffered = 0; + + glogf("SDL2 sound shared memory size=%d", SOUND_SHM_SAMP_SIZE * SAMPLE_CHAN_SIZE); + + g_sound_shm_addr = malloc(SOUND_SHM_SAMP_SIZE * SAMPLE_CHAN_SIZE); + memset(g_sound_shm_addr,0,SOUND_SHM_SAMP_SIZE * SAMPLE_CHAN_SIZE); + + /* It's all good! */ + g_zeroes_buffered = 0; + g_zeroes_seen = 0; + /* Let's start playing sound */ + g_sound_paused = 0; + SDL_PauseAudioDevice(dev, 0); + + set_audio_rate(rate); + return rate; + +snd_error: + /* Oops! Something bad happened, cleanup. */ + SDL_CloseAudioDevice(dev); + SDL_QuitSubSystem(SDL_INIT_AUDIO); + if(playbuf) + free((void*)playbuf); + playbuf = 0; + snd_buf = 0; + return 0; +#else + return 0; +#endif +} + +void sound_shutdown_sdl() { +#ifdef HAVE_SDL + SDL_CloseAudioDevice(dev); + if(playbuf) + free((void*)playbuf); + playbuf = 0; +#endif +} diff --git a/src/sim65816.c b/src/sim65816.c index 8c09aa9..b2a9695 100644 --- a/src/sim65816.c +++ b/src/sim65816.c @@ -1,6 +1,7 @@ /* GSport - an Apple //gs Emulator - Copyright (C) 2010 - 2014 by GSport contributors + Copyright (C) 2010 - 2019 by GSport contributors + Copyright (C) 2016 - 2018 Dagen Brock Based on the KEGS emulator written by and Copyright (C) 2003 Kent Dickey @@ -20,57 +21,71 @@ */ #include +#include #include "defc.h" -#ifdef HAVE_TFE - #include "tfe/tfesupp.h" - #include "tfe/protos_tfe.h" -#endif - #include "printer.h" - #include "imagewriter.h" +#include "printer.h" +#include "imagewriter.h" +#include "debug.h" +#include "glog.h" +#include "options.h" +extern const char *g_config_gsport_name_list[]; +extern char g_config_gsport_screenshot_dir[]; #ifdef UNDER_CE -#define vsnprintf _vsnprintf + #define vsnprintf _vsnprintf #endif -#if defined (_WIN32) || defined(__CYGWIN__) -#define WIN32_LEAN_AND_MEAN /* Tell windows we want less header gunk */ -#define STRICT /* Tell Windows we want compile type checks */ -#include /* Need a definition for LPTSTR in CYGWIN */ +#ifdef HAVE_TFE + #include "tfe/tfesupp.h" + #include "tfe/protos_tfe.h" +#endif +#if defined (_WIN32) && !defined(WIN_SDL)|| defined(__CYGWIN__) && !defined(WIN_SDL) + #define WIN32_LEAN_AND_MEAN /* Tell windows we want less header gunk */ + #define STRICT /* Tell Windows we want compile type checks */ + #include /* Need a definition for LPTSTR in CYGWIN */ extern void get_cwd(LPTSTR buffer, int size); #endif -#define PC_LOG_LEN (8*1024) - -int g_speed_fast ; // OG Expose fast parameter -int g_initialized = 0; // OG To know if the emulator has finalized its initialization -int g_accept_events = 0; // OG To know if the emulator is ready to accept external events +#define PC_LOG_LEN (8*1024) +int g_speed_fast; // OG Expose fast parameter +int g_initialized = 0; // OG To know if the emulator has finalized its initialization +int g_accept_events = 0; // OG To know if the emulator is ready to accept external events char g_argv0_path[256] = "./"; -const char *g_gsport_default_paths[] = { "", "./", "${HOME}/","${PWD}/", -#ifdef MAC - "${0}/../", -#endif - "${HOME}/Library/GSport/", - "${0}/Contents/Resources/", "/usr/local/lib/", - "/usr/local/gsport/", "/usr/local/lib/gsport/", "/usr/share/gsport/", - "/var/lib/", "/usr/lib/gsport/", "${0}/", 0 }; +const char *g_gsport_default_paths[] = { // probably overkill on the paths + "", + "./", + "${HOME}/", + "${PWD}/", + "${HOME}/Library/GSport/", + "/usr/local/lib/", + "/usr/lib/gsport/", + "/usr/local/gsport/", + "/usr/local/lib/gsport/", + "/usr/share/gsport/", + "/var/lib/", + "${0}/", + 0 +}; -#define MAX_EVENTS 64 +#define MAX_EVENTS 64 /* All EV_* must be less than 256, since upper bits reserved for other use */ /* e.g., DOC_INT uses upper bits to encode oscillator */ -#define EV_60HZ 1 -#define EV_STOP 2 -#define EV_SCAN_INT 3 -#define EV_DOC_INT 4 -#define EV_VBL_INT 5 -#define EV_SCC 6 -#define EV_VID_UPD 7 +#define EV_60HZ 1 +#define EV_STOP 2 +#define EV_SCAN_INT 3 +#define EV_DOC_INT 4 +#define EV_VBL_INT 5 +#define EV_SCC 6 +#define EV_VID_UPD 7 extern int g_stepping; +extern int g_dbg_step; + extern int g_c068_statereg; extern int g_cur_a2_stat; @@ -111,24 +126,36 @@ extern int g_config_control_panel; extern int g_audio_enable; extern int g_preferred_rate; +extern int g_dbg_enable_port; + +/* display parameters */ +char g_display_env[512]; +int g_force_depth = -1; +int g_screen_depth = 8; +int g_scanline_simulator = 0; + +extern int g_screen_redraw_skip_amt; +extern int g_use_dhr140; +extern int g_use_bw_hires; void U_STACK_TRACE(); -double g_fcycles_stop = 0.0; -int halt_sim = 0; -int enter_debug = 0; -int g_rom_version = -1; -int g_user_halt_bad = 0; -int g_halt_on_bad_read = 0; -int g_ignore_bad_acc = 1; -int g_ignore_halts = 1; -int g_code_red = 0; -int g_code_yellow = 0; -int g_use_alib = 0; -int g_serial_type[2]; -int g_iw2_emul = 0; -int g_serial_out_masking = 0; -int g_serial_modem[2] = { 0, 1 }; +double g_fcycles_stop = 0.0; +int halt_sim = 0; +int enter_debug = 0; +int g_rom_version = -1; + +int g_user_halt_bad = 0; +int g_halt_on_bad_read = 0; +int g_ignore_bad_acc = 1; +int g_ignore_halts = 1; + +int g_code_red = 0; +int g_code_yellow = 0; +int g_serial_type[2]; +int g_iw2_emul = 0; +int g_serial_out_masking = 0; +int g_serial_modem[2] = { 0, 1 }; int g_ethernet = 0; int g_ethernet_interface = 0; int g_parallel = 0; @@ -151,44 +178,43 @@ char* g_imagewriter_output = "bmp"; int g_imagewriter_multipage = 0; int g_imagewriter_timeout = 2; char* g_imagewriter_fixed_font = "lib/letgothl.ttf"; -char* g_imagewriter_prop_font = "lib/letgothl.ttf"; +char* g_imagewriter_prop_font = "lib/letgothl.ttf"; int g_imagewriter_paper = 0; -int g_imagewriter_banner = 0; - -int g_config_iwm_vbl_count = 0; -extern const char g_gsport_version_str[] = "0.31"; -int g_pause=0; // OG Added pause +int g_imagewriter_banner = 0; -#define START_DCYCS (0.0) +int g_config_iwm_vbl_count = 0; +const char g_gsport_version_str[] = "0.4"; +int g_pause=0; // OG Added pause -double g_last_vbl_dcycs = START_DCYCS; -double g_cur_dcycs = START_DCYCS; +#define START_DCYCS (0.0) -double g_last_vbl_dadjcycs = 0.0; -double g_dadjcycs = 0.0; +double g_last_vbl_dcycs = START_DCYCS; +double g_cur_dcycs = START_DCYCS; + +double g_last_vbl_dadjcycs = 0.0; +double g_dadjcycs = 0.0; -int g_wait_pending = 0; -int g_stp_pending = 0; +int g_wait_pending = 0; +int g_stp_pending = 0; extern int g_irq_pending; -int g_num_irq = 0; -int g_num_brk = 0; -int g_num_cop = 0; -int g_num_enter_engine = 0; -int g_io_amt = 0; -int g_engine_action = 0; -int g_engine_halt_event = 0; -int g_engine_scan_int = 0; -int g_engine_doc_int = 0; +int g_num_irq = 0; +int g_num_brk = 0; +int g_num_cop = 0; +int g_num_enter_engine = 0; +int g_io_amt = 0; +int g_engine_action = 0; +int g_engine_halt_event = 0; +int g_engine_scan_int = 0; +int g_engine_doc_int = 0; -int g_testing = 0; -int g_testing_enabled = 0; +int g_testing = 0; -#define MAX_FATAL_LOGS 20 +#define MAX_FATAL_LOGS 20 -int g_debug_file_fd = -1; -int g_fatal_log = -1; +int g_debug_file_fd = -1; +int g_fatal_log = -1; char *g_fatal_log_strs[MAX_FATAL_LOGS]; word32 stop_run_at; @@ -202,9 +228,9 @@ word32 g_natcycs_lastvbl = 0; int Verbose = 0; int Halt_on = 0; -word32 g_mem_size_base = 256*1024; /* size of motherboard memory */ -word32 g_mem_size_exp = 8*1024*1024; /* size of expansion RAM card */ -word32 g_mem_size_total = 256*1024; /* Total contiguous RAM from 0 */ +word32 g_mem_size_base = 256*1024; /* size of motherboard memory */ +word32 g_mem_size_exp = 8*1024*1024; /* size of expansion RAM card */ +word32 g_mem_size_total = 256*1024; /* Total contiguous RAM from 0 */ extern word32 slow_mem_changed[]; @@ -214,1791 +240,1605 @@ byte *g_dummy_memory1_ptr = 0; byte *g_rom_fc_ff_ptr = 0; byte *g_rom_cards_ptr = 0; -// OG Added allocated pointers -byte *g_slow_memory_ptr_allocated = 0; -byte *g_memory_ptr_allocated = 0; -byte *g_dummy_memory1_ptr_allocated = 0; -byte *g_rom_fc_ff_ptr_allocated = 0; -byte *g_rom_cards_ptr_allocated = 0; - -void *g_memory_alloc_ptr = 0; /* for freeing memory area */ +// OG Added allocated pointers +byte *g_slow_memory_ptr_allocated = 0; +byte *g_memory_ptr_allocated = 0; +byte *g_dummy_memory1_ptr_allocated = 0; +byte *g_rom_fc_ff_ptr_allocated = 0; +byte *g_rom_cards_ptr_allocated = 0; + +void *g_memory_alloc_ptr = 0; /* for freeing memory area */ Page_info page_info_rd_wr[2*65536 + PAGE_INFO_PAD_SIZE]; Pc_log g_pc_log_array[PC_LOG_LEN + 2]; Data_log g_data_log_array[PC_LOG_LEN + 2]; -Pc_log *g_log_pc_ptr = &(g_pc_log_array[0]); -Pc_log *g_log_pc_start_ptr = &(g_pc_log_array[0]); -Pc_log *g_log_pc_end_ptr = &(g_pc_log_array[PC_LOG_LEN]); +Pc_log *g_log_pc_ptr = &(g_pc_log_array[0]); +Pc_log *g_log_pc_start_ptr = &(g_pc_log_array[0]); +Pc_log *g_log_pc_end_ptr = &(g_pc_log_array[PC_LOG_LEN]); Data_log *g_log_data_ptr = &(g_data_log_array[0]); Data_log *g_log_data_start_ptr = &(g_data_log_array[0]); Data_log *g_log_data_end_ptr = &(g_data_log_array[PC_LOG_LEN]); -// OG Added sim65816_initglobals() -void sim65816_initglobals() -{ +// OG Added sim65816_initglobals() +void sim65816_initglobals() { + g_fcycles_stop = 0.0; + halt_sim = 0; + enter_debug = 0; + g_rom_version = -1; + g_user_halt_bad = 0; + g_halt_on_bad_read = 0; + g_ignore_bad_acc = 1; + g_ignore_halts = 1; + g_code_red = 0; + g_code_yellow = 0; + g_iw2_emul = 0; + g_serial_out_masking = 0; + //g_serial_modem[2] = { 0, 1 }; - g_fcycles_stop = 0.0; - halt_sim = 0; - enter_debug = 0; - g_rom_version = -1; - g_user_halt_bad = 0; - g_halt_on_bad_read = 0; - g_ignore_bad_acc = 1; - g_ignore_halts = 1; - g_code_red = 0; - g_code_yellow = 0; - g_use_alib = 0; - g_iw2_emul = 0; - g_serial_out_masking = 0; - //g_serial_modem[2] = { 0, 1 }; - - g_config_iwm_vbl_count = 0; - - g_pause=0; - - g_last_vbl_dcycs = START_DCYCS; - g_cur_dcycs = START_DCYCS; - - g_last_vbl_dadjcycs = 0.0; - g_dadjcycs = 0.0; - - - g_wait_pending = 0; - g_stp_pending = 0; - - g_num_irq = 0; - g_num_brk = 0; - g_num_cop = 0; - g_num_enter_engine = 0; - g_io_amt = 0; - g_engine_action = 0; - g_engine_halt_event = 0; - g_engine_scan_int = 0; - g_engine_doc_int = 0; - - g_testing = 0; - g_testing_enabled = 0; - - g_debug_file_fd = -1; - g_fatal_log = -1; - - g_25sec_cntr = 0; - g_1sec_cntr = 0; - - g_dnatcycs_1sec = 0.0; - g_natcycs_lastvbl = 0; - - Verbose = 0; - Halt_on = 0; - - g_mem_size_base = 256*1024; /* size of motherboard memory */ - g_mem_size_exp = 8*1024*1024; /* size of expansion RAM card */ - g_mem_size_total = 256*1024; /* Total contiguous RAM from 0 */ -} - -void -show_pc_log() -{ - FILE *pcfile; - Pc_log *log_pc_ptr; - Data_log *log_data_ptr; - double dcycs; - double start_dcycs; - word32 instr; - word32 psr; - word32 acc, xreg, yreg; - word32 stack, direct; - word32 dbank; - word32 kpc; - int data_wrap; - int accsize, xsize; - int num; - int i; + g_config_iwm_vbl_count = 0; - pcfile = fopen("pc_log_out", "w"); - if(pcfile == 0) { - fprintf(stderr,"fopen failed...errno: %d\n", errno); - exit(2); - } + g_pause=0; - log_pc_ptr = g_log_pc_ptr; - log_data_ptr = g_log_data_ptr; + g_last_vbl_dcycs = START_DCYCS; + g_cur_dcycs = START_DCYCS; + + g_last_vbl_dadjcycs = 0.0; + g_dadjcycs = 0.0; + + + g_wait_pending = 0; + g_stp_pending = 0; + + g_num_irq = 0; + g_num_brk = 0; + g_num_cop = 0; + g_num_enter_engine = 0; + g_io_amt = 0; + g_engine_action = 0; + g_engine_halt_event = 0; + g_engine_scan_int = 0; + g_engine_doc_int = 0; + + g_testing = 0; + + g_debug_file_fd = -1; + g_fatal_log = -1; + + g_25sec_cntr = 0; + g_1sec_cntr = 0; + + g_dnatcycs_1sec = 0.0; + g_natcycs_lastvbl = 0; + + Verbose = 0; + Halt_on = 0; + + g_mem_size_base = 256*1024; /* size of motherboard memory */ + g_mem_size_exp = 8*1024*1024; /* size of expansion RAM card */ + g_mem_size_total = 256*1024; /* Total contiguous RAM from 0 */ +} + +void show_pc_log() { + FILE *pcfile; + Pc_log *log_pc_ptr; + Data_log *log_data_ptr; + double dcycs; + double start_dcycs; + word32 instr; + word32 psr; + word32 acc, xreg, yreg; + word32 stack, direct; + word32 dbank; + word32 kpc; + int data_wrap; + int accsize, xsize; + int num; + int i; + + pcfile = fopen("pc_log_out", "w"); + if(pcfile == 0) { + fprintf(stderr,"fopen failed...errno: %d\n", errno); + exit(2); + } + + log_pc_ptr = g_log_pc_ptr; + log_data_ptr = g_log_data_ptr; #if 0 - fprintf(pcfile, "current pc_log_ptr: %p, start: %p, end: %p\n", - log_pc_ptr, log_pc_start_ptr, log_pc_end_ptr); + fprintf(pcfile, "current pc_log_ptr: %p, start: %p, end: %p\n", + log_pc_ptr, log_pc_start_ptr, log_pc_end_ptr); #endif - start_dcycs = log_pc_ptr->dcycs; - dcycs = start_dcycs; + start_dcycs = log_pc_ptr->dcycs; + dcycs = start_dcycs; - data_wrap = 0; - /* find first data entry */ - while(data_wrap < 2 && (log_data_ptr->dcycs < dcycs)) { - log_data_ptr++; - if(log_data_ptr >= g_log_data_end_ptr) { - log_data_ptr = g_log_data_start_ptr; - data_wrap++; - } - } - fprintf(pcfile, "start_dcycs: %9.2f\n", start_dcycs); + data_wrap = 0; + /* find first data entry */ + while(data_wrap < 2 && (log_data_ptr->dcycs < dcycs)) { + log_data_ptr++; + if(log_data_ptr >= g_log_data_end_ptr) { + log_data_ptr = g_log_data_start_ptr; + data_wrap++; + } + } + fprintf(pcfile, "start_dcycs: %9.2f\n", start_dcycs); - for(i = 0; i < PC_LOG_LEN; i++) { - dcycs = log_pc_ptr->dcycs; - while((data_wrap < 2) && (log_data_ptr->dcycs <= dcycs) && - (log_data_ptr->dcycs >= start_dcycs)) { - fprintf(pcfile, "DATA set %06x = %06x (%d) %9.2f\n", - log_data_ptr->addr, log_data_ptr->val, - log_data_ptr->size, - log_data_ptr->dcycs - start_dcycs); - log_data_ptr++; - if(log_data_ptr >= g_log_data_end_ptr) { - log_data_ptr = g_log_data_start_ptr; - data_wrap++; - } - } - dbank = (log_pc_ptr->dbank_kpc >> 24) & 0xff; - kpc = log_pc_ptr->dbank_kpc & 0xffffff; - instr = log_pc_ptr->instr; - psr = (log_pc_ptr->psr_acc >> 16) & 0xffff;; - acc = log_pc_ptr->psr_acc & 0xffff;; - xreg = (log_pc_ptr->xreg_yreg >> 16) & 0xffff;; - yreg = log_pc_ptr->xreg_yreg & 0xffff;; - stack = (log_pc_ptr->stack_direct >> 16) & 0xffff;; - direct = log_pc_ptr->stack_direct & 0xffff;; + for(i = 0; i < PC_LOG_LEN; i++) { + dcycs = log_pc_ptr->dcycs; + while((data_wrap < 2) && (log_data_ptr->dcycs <= dcycs) && + (log_data_ptr->dcycs >= start_dcycs)) { + fprintf(pcfile, "DATA set %06x = %06x (%d) %9.2f\n", + log_data_ptr->addr, log_data_ptr->val, + log_data_ptr->size, + log_data_ptr->dcycs - start_dcycs); + log_data_ptr++; + if(log_data_ptr >= g_log_data_end_ptr) { + log_data_ptr = g_log_data_start_ptr; + data_wrap++; + } + } + dbank = (log_pc_ptr->dbank_kpc >> 24) & 0xff; + kpc = log_pc_ptr->dbank_kpc & 0xffffff; + instr = log_pc_ptr->instr; + psr = (log_pc_ptr->psr_acc >> 16) & 0xffff;; + acc = log_pc_ptr->psr_acc & 0xffff;; + xreg = (log_pc_ptr->xreg_yreg >> 16) & 0xffff;; + yreg = log_pc_ptr->xreg_yreg & 0xffff;; + stack = (log_pc_ptr->stack_direct >> 16) & 0xffff;; + direct = log_pc_ptr->stack_direct & 0xffff;; - num = log_pc_ptr - g_log_pc_start_ptr; + num = log_pc_ptr - g_log_pc_start_ptr; - accsize = 2; - xsize = 2; - if(psr & 0x20) { - accsize = 1; - } - if(psr & 0x10) { - xsize = 1; - } + accsize = 2; + xsize = 2; + if(psr & 0x20) { + accsize = 1; + } + if(psr & 0x10) { + xsize = 1; + } - fprintf(pcfile, "%04x: A:%04x X:%04x Y:%04x P:%03x " - "S:%04x D:%04x B:%02x %9.2f ", i, - acc, xreg, yreg, psr, stack, direct, dbank, - (dcycs-start_dcycs)); + fprintf(pcfile, "%04x: A:%04x X:%04x Y:%04x P:%03x " + "S:%04x D:%04x B:%02x %9.2f ", i, + acc, xreg, yreg, psr, stack, direct, dbank, + (dcycs-start_dcycs)); - do_dis(pcfile, kpc, accsize, xsize, 1, instr); - log_pc_ptr++; - if(log_pc_ptr >= g_log_pc_end_ptr) { - log_pc_ptr = g_log_pc_start_ptr; - } - } + do_dis(pcfile, kpc, accsize, xsize, 1, instr); + log_pc_ptr++; + if(log_pc_ptr >= g_log_pc_end_ptr) { + log_pc_ptr = g_log_pc_start_ptr; + } + } - fclose(pcfile); + fclose(pcfile); } -#define TOOLBOX_LOG_LEN 64 +#define TOOLBOX_LOG_LEN 64 int g_toolbox_log_pos = 0; word32 g_toolbox_log_array[TOOLBOX_LOG_LEN][8]; -word32 -toolbox_debug_4byte(word32 addr) -{ - word32 part1, part2; +word32 toolbox_debug_4byte(word32 addr) { + word32 part1, part2; - /* If addr looks safe, use it */ - if(addr > 0xbffc) { - return (word32)-1; - } + /* If addr looks safe, use it */ + if(addr > 0xbffc) { + return (word32)-1; + } - part1 = get_memory16_c(addr, 0); - part1 = (part1 >> 8) + ((part1 & 0xff) << 8); - part2 = get_memory16_c(addr+2, 0); - part2 = (part2 >> 8) + ((part2 & 0xff) << 8); + part1 = get_memory16_c(addr, 0); + part1 = (part1 >> 8) + ((part1 & 0xff) << 8); + part2 = get_memory16_c(addr+2, 0); + part2 = (part2 >> 8) + ((part2 & 0xff) << 8); - return (part1 << 16) + part2; + return (part1 << 16) + part2; } -void -toolbox_debug_c(word32 xreg, word32 stack, double *cyc_ptr) -{ - int pos; +void toolbox_debug_c(word32 xreg, word32 stack, double *cyc_ptr) { + int pos; - pos = g_toolbox_log_pos; + pos = g_toolbox_log_pos; - stack += 9; - g_toolbox_log_array[pos][0] = (word32)(g_last_vbl_dcycs + *cyc_ptr); - g_toolbox_log_array[pos][1] = stack+1; - g_toolbox_log_array[pos][2] = xreg; - g_toolbox_log_array[pos][3] = toolbox_debug_4byte(stack+1); - g_toolbox_log_array[pos][4] = toolbox_debug_4byte(stack+5); - g_toolbox_log_array[pos][5] = toolbox_debug_4byte(stack+9); - g_toolbox_log_array[pos][6] = toolbox_debug_4byte(stack+13); - g_toolbox_log_array[pos][7] = toolbox_debug_4byte(stack+17); + stack += 9; + g_toolbox_log_array[pos][0] = (word32)(g_last_vbl_dcycs + *cyc_ptr); + g_toolbox_log_array[pos][1] = stack+1; + g_toolbox_log_array[pos][2] = xreg; + g_toolbox_log_array[pos][3] = toolbox_debug_4byte(stack+1); + g_toolbox_log_array[pos][4] = toolbox_debug_4byte(stack+5); + g_toolbox_log_array[pos][5] = toolbox_debug_4byte(stack+9); + g_toolbox_log_array[pos][6] = toolbox_debug_4byte(stack+13); + g_toolbox_log_array[pos][7] = toolbox_debug_4byte(stack+17); - pos++; - if(pos >= TOOLBOX_LOG_LEN) { - pos = 0; - } + pos++; + if(pos >= TOOLBOX_LOG_LEN) { + pos = 0; + } - g_toolbox_log_pos = pos; + g_toolbox_log_pos = pos; } -void -show_toolbox_log() -{ - int pos; - int i; +void show_toolbox_log() { + int pos; + int i; - pos = g_toolbox_log_pos; + pos = g_toolbox_log_pos; - for(i = TOOLBOX_LOG_LEN - 1; i >= 0; i--) { - printf("%2d:%2d: %08x %06x %04x: %08x %08x %08x %08x %08x\n", - i, pos, - g_toolbox_log_array[pos][0], - g_toolbox_log_array[pos][1], - g_toolbox_log_array[pos][2], - g_toolbox_log_array[pos][3], - g_toolbox_log_array[pos][4], - g_toolbox_log_array[pos][5], - g_toolbox_log_array[pos][6], - g_toolbox_log_array[pos][7]); - pos++; - if(pos >= TOOLBOX_LOG_LEN) { - pos = 0; - } - } + for(i = TOOLBOX_LOG_LEN - 1; i >= 0; i--) { + printf("%2d:%2d: %08x %06x %04x: %08x %08x %08x %08x %08x\n", + i, pos, + g_toolbox_log_array[pos][0], + g_toolbox_log_array[pos][1], + g_toolbox_log_array[pos][2], + g_toolbox_log_array[pos][3], + g_toolbox_log_array[pos][4], + g_toolbox_log_array[pos][5], + g_toolbox_log_array[pos][6], + g_toolbox_log_array[pos][7]); + pos++; + if(pos >= TOOLBOX_LOG_LEN) { + pos = 0; + } + } } #if 0 /* get_memory_c is not used, get_memory_asm is, but this does what the */ /* assembly language would do */ -word32 -get_memory_c(word32 loc, int diff_cycles) -{ - byte *addr; - word32 result; - int index; +word32 get_memory_c(word32 loc, int diff_cycles) { + byte *addr; + word32 result; + int index; #ifdef CHECK_BREAKPOINTS - check_breakpoints_c(loc); + check_breakpoints_c(loc); #endif - index = loc >> 8; - result = page_info[index].rd; - if(result & BANK_IO_BIT) { - return get_memory_io(loc, diff_cycles); - } + index = loc >> 8; + result = page_info[index].rd; + if(result & BANK_IO_BIT) { + return get_memory_io(loc, diff_cycles); + } - addr = (byte *)((result & 0xffffff00) + (loc & 0xff)); + addr = (byte *)((result & 0xffffff00) + (loc & 0xff)); - return *addr; + return *addr; } #endif -word32 -get_memory_io(word32 loc, double *cyc_ptr) -{ - int tmp; +word32 get_memory_io(word32 loc, double *cyc_ptr) { + int tmp; - if(loc > 0xffffff) { - halt_printf("get_memory_io:%08x out of range==halt!\n", loc); - return 0; - } - tmp = loc & 0xfef000; - if(tmp == 0xc000 || tmp == 0xe0c000) { - return(io_read(loc & 0xfff, cyc_ptr)); - } + if(loc > 0xffffff) { + halt_printf("get_memory_io:%08x out of range==halt!\n", loc); + return 0; + } + tmp = loc & 0xfef000; + if(tmp == 0xc000 || tmp == 0xe0c000) { + return(io_read(loc & 0xfff, cyc_ptr)); + } - /* Else it's an illegal addr...skip if memory sizing */ - if(loc >= g_mem_size_total) { - if((loc & 0xfffe) == 0) { + /* Else it's an illegal addr...skip if memory sizing */ + if(loc >= g_mem_size_total) { + if((loc & 0xfffe) == 0) { #if 0 - printf("get_io assuming mem sizing, not halting\n"); + printf("get_io assuming mem sizing, not halting\n"); #endif - return 0; - } - } + return 0; + } + } - /* Skip reads to f80000 and f00000, just return 0 */ - if((loc & 0xf70000) == 0xf00000) { - return 0; - } + /* Skip reads to f80000 and f00000, just return 0 */ + if((loc & 0xf70000) == 0xf00000) { + return 0; + } - if((loc & 0xff0000) == 0xef0000) { - /* DOC RAM */ - return (doc_ram[loc & 0xffff]); - } + if((loc & 0xff0000) == 0xef0000) { + /* DOC RAM */ + return (doc_ram[loc & 0xffff]); + } - g_code_yellow++; - if(g_ignore_bad_acc && !g_user_halt_bad) { - /* print no message, just get out. User doesn't want */ - /* to be bothered by buggy programs */ - return 0; - } + g_code_yellow++; + if(g_ignore_bad_acc && !g_user_halt_bad) { + /* print no message, just get out. User doesn't want */ + /* to be bothered by buggy programs */ + return 0; + } - printf("get_memory_io for addr: %06x\n", loc); - printf("stat for addr: %06x = %p\n", loc, - GET_PAGE_INFO_RD((loc >> 8) & 0xffff)); - set_halt(g_halt_on_bad_read | g_user_halt_bad); + printf("get_memory_io for addr: %06x\n", loc); + printf("stat for addr: %06x = %p\n", loc, + GET_PAGE_INFO_RD((loc >> 8) & 0xffff)); + set_halt(g_halt_on_bad_read | g_user_halt_bad); - return 0; + return 0; } #if 0 -word32 -get_memory16_pieces(word32 loc, int diff_cycles) -{ - return(get_memory_c(loc, diff_cycles) + - (get_memory_c(loc+1, diff_cycles) << 8)); +word32 get_memory16_pieces(word32 loc, int diff_cycles) { + return(get_memory_c(loc, diff_cycles) + + (get_memory_c(loc+1, diff_cycles) << 8)); } -word32 -get_memory24(word32 loc, int diff_cycles) -{ - return(get_memory_c(loc, diff_cycles) + - (get_memory_c(loc+1, diff_cycles) << 8) + - (get_memory_c(loc+2, diff_cycles) << 16)); +word32 get_memory24(word32 loc, int diff_cycles) { + return(get_memory_c(loc, diff_cycles) + + (get_memory_c(loc+1, diff_cycles) << 8) + + (get_memory_c(loc+2, diff_cycles) << 16)); } #endif #if 0 -void -set_memory(word32 loc, int val, int diff_cycles) -{ - byte *ptr; - word32 new_addr; - word32 tmp; - word32 or_val; - int or_pos; - int old_slow_val; +void set_memory(word32 loc, int val, int diff_cycles) { + byte *ptr; + word32 new_addr; + word32 tmp; + word32 or_val; + int or_pos; + int old_slow_val; #ifdef CHECK_BREAKPOINTS - check_breakpoints_c(loc); + check_breakpoints_c(loc); #endif - tmp = GET_PAGE_INFO_WR((loc>>8) & 0xffff); - if(tmp & BANK_IO) { - set_memory_io(loc, val, diff_cycles); - return; - } + tmp = GET_PAGE_INFO_WR((loc>>8) & 0xffff); + if(tmp & BANK_IO) { + set_memory_io(loc, val, diff_cycles); + return; + } - if((loc & 0xfef000) == 0xe0c000) { - printf("set_memory_special: non-io for addr %08x, %02x, %d\n", - loc, val, diff_cycles); - halt_printf("tmp: %08x\n", tmp); - } + if((loc & 0xfef000) == 0xe0c000) { + printf("set_memory_special: non-io for addr %08x, %02x, %d\n", + loc, val, diff_cycles); + halt_printf("tmp: %08x\n", tmp); + } - ptr = (byte *)(tmp & (~0xff)); + ptr = (byte *)(tmp & (~0xff)); - new_addr = loc & 0xffff; - old_slow_val = val; + new_addr = loc & 0xffff; + old_slow_val = val; - if(tmp & BANK_SHADOW) { - old_slow_val = g_slow_memory_ptr[new_addr]; - } else if(tmp & BANK_SHADOW2) { - new_addr += 0x10000; - old_slow_val = g_slow_memory_ptr[new_addr]; - } + if(tmp & BANK_SHADOW) { + old_slow_val = g_slow_memory_ptr[new_addr]; + } else if(tmp & BANK_SHADOW2) { + new_addr += 0x10000; + old_slow_val = g_slow_memory_ptr[new_addr]; + } - if(old_slow_val != val) { - g_slow_memory_ptr[new_addr] = val; - or_pos = (new_addr >> SHIFT_PER_CHANGE) & 0x1f; - or_val = DEP1(1, or_pos, 0); - if((new_addr >> CHANGE_SHIFT) >= SLOW_MEM_CH_SIZE) { - printf("new_addr: %08x\n", new_addr); - exit(12); - } - slow_mem_changed[(new_addr & 0xffff) >> CHANGE_SHIFT] |= or_val; - } + if(old_slow_val != val) { + g_slow_memory_ptr[new_addr] = val; + or_pos = (new_addr >> SHIFT_PER_CHANGE) & 0x1f; + or_val = DEP1(1, or_pos, 0); + if((new_addr >> CHANGE_SHIFT) >= SLOW_MEM_CH_SIZE) { + printf("new_addr: %08x\n", new_addr); + exit(12); + } + slow_mem_changed[(new_addr & 0xffff) >> CHANGE_SHIFT] |= or_val; + } - ptr[loc & 0xff] = val; + ptr[loc & 0xff] = val; } #endif -void -set_memory_io(word32 loc, int val, double *cyc_ptr) -{ - word32 tmp; - tmp = loc & 0xfef000; - if(tmp == 0xc000 || tmp == 0xe0c000) { - io_write(loc, val, cyc_ptr); - return; - } +void set_memory_io(word32 loc, int val, double *cyc_ptr) { + word32 tmp; + tmp = loc & 0xfef000; + if(tmp == 0xc000 || tmp == 0xe0c000) { + io_write(loc, val, cyc_ptr); + return; + } - /* Else it's an illegal addr */ - if(loc >= g_mem_size_total) { - if((loc & 0xfffe) == 0) { + /* Else it's an illegal addr */ + if(loc >= g_mem_size_total) { + if((loc & 0xfffe) == 0) { #if 0 - printf("set_io assuming mem sizing, not halting\n"); + printf("set_io assuming mem sizing, not halting\n"); #endif - return; - } - } + return; + } + } - /* ignore writes to ROM */ - if((loc & 0xfc0000) == 0xfc0000) { - return; - } + /* ignore writes to ROM */ + if((loc & 0xfc0000) == 0xfc0000) { + return; + } - if((loc & 0xff0000) == 0xef0000) { - /* DOC RAM */ - doc_ram[loc & 0xffff] = val; - return; - } + if((loc & 0xff0000) == 0xef0000) { + /* DOC RAM */ + doc_ram[loc & 0xffff] = val; + return; + } - if(g_ignore_bad_acc && !g_user_halt_bad) { - /* print no message, just get out. User doesn't want */ - /* to be bothered by buggy programs */ - return; - } + if(g_ignore_bad_acc && !g_user_halt_bad) { + /* print no message, just get out. User doesn't want */ + /* to be bothered by buggy programs */ + return; + } - if((loc & 0xffc000) == 0x00c000) { - printf("set_memory %06x = %02x, warning\n", loc, val); - return; - } + if((loc & 0xffc000) == 0x00c000) { + printf("set_memory %06x = %02x, warning\n", loc, val); + return; + } - halt_printf("set_memory %06x = %02x, stopping\n", loc, val); + halt_printf("set_memory %06x = %02x, stopping\n", loc, val); - return; + return; } #if 0 -void -check_breakpoints_c(word32 loc) -{ - int index; - int count; - int i; +void check_breakpoints_c(word32 loc) { + int index; + int count; + int i; - index = (loc & (MAX_BP_INDEX-1)); - count = breakpoints[index].count; - if(count) { - for(i = 0; i < count; i++) { - if(loc == breakpoints[index].addrs[i]) { - halt_printf("Write hit breakpoint %d!\n", i); - } - } - } + index = (loc & (MAX_BP_INDEX-1)); + count = breakpoints[index].count; + if(count) { + for(i = 0; i < count; i++) { + if(loc == breakpoints[index].addrs[i]) { + halt_printf("Write hit breakpoint %d!\n", i); + } + } + } } #endif -void -show_regs_act(Engine_reg *eptr) -{ - int tmp_acc, tmp_x, tmp_y, tmp_psw; - int kpc; - int direct_page, dbank; - int stack; - - kpc = eptr->kpc; - tmp_acc = eptr->acc; - direct_page = eptr->direct; - dbank = eptr->dbank; - stack = eptr->stack; +void show_regs_act(Engine_reg *eptr) { + int tmp_acc, tmp_x, tmp_y, tmp_psw; + int kpc; + int direct_page, dbank; + int stack; - tmp_x = eptr->xreg; - tmp_y = eptr->yreg; + kpc = eptr->kpc; + tmp_acc = eptr->acc; + direct_page = eptr->direct; + dbank = eptr->dbank; + stack = eptr->stack; - tmp_psw = eptr->psr; + tmp_x = eptr->xreg; + tmp_y = eptr->yreg; - printf(" PC=%02x.%04x A=%04x X=%04x Y=%04x P=%03x", - kpc>>16, kpc & 0xffff ,tmp_acc,tmp_x,tmp_y,tmp_psw); - printf(" S=%04x D=%04x B=%02x,cyc:%.3f\n", stack, direct_page, - dbank, g_cur_dcycs); + tmp_psw = eptr->psr; + + printf(" PC=%02x.%04x A=%04x X=%04x Y=%04x P=%03x", + kpc>>16, kpc & 0xffff,tmp_acc,tmp_x,tmp_y,tmp_psw); + printf(" S=%04x D=%04x B=%02x,cyc:%.3f\n", stack, direct_page, + dbank, g_cur_dcycs); } -void -show_regs() -{ - show_regs_act(&engine); +void show_regs() { + show_regs_act(&engine); } -//OG for regular exit, use quitEmulator() - -void quitEmulator() -{ - printf("set_halt(HALT_WANTTOQUIT)\n"); - set_halt(HALT_WANTTOQUIT); -} - -//OG change exit to fatal_exit() - -#ifndef ACTIVEGS - // use standard exit function - #define fatalExit exit -#else - extern void fatalExit(int); -#endif - -void my_exit(int ret) -{ - end_screen(); - imagewriter_close(); - printer_close(); - printf("exiting (ret=%d)\n",ret); - fatalExit(ret); +//OG for regular exit, use quitEmulator() +void quitEmulator() { + printf("set_halt(HALT_WANTTOQUIT)\n"); + set_halt(HALT_WANTTOQUIT); } - -void -do_reset() -{ - - // OG Cleared remaining IRQS on RESET - extern int g_irq_pending; - extern int g_scan_int_events ; - extern int g_c023_val; - - g_c068_statereg = 0x08 + 0x04 + 0x01; /* rdrom, lcbank2, intcx */ - g_c035_shadow_reg = 0; - - g_c08x_wrdefram = 1; - g_c02d_int_crom = 0; - g_c023_val = 0; - g_c041_val = 0; - - engine.psr = (engine.psr | 0x134) & ~(0x08); - engine.stack = 0x100 + (engine.stack & 0xff); - engine.dbank = 0; - engine.direct = 0; - engine.xreg &= 0xff; - engine.yreg &= 0xff; - g_wait_pending = 0; - g_stp_pending = 0; - - - video_reset(); - adb_reset(); - iwm_reset(); - scc_reset(); - sound_reset(g_cur_dcycs); - setup_pageinfo(); - change_display_mode(g_cur_dcycs); - - g_irq_pending = 0; - - engine.kpc = get_memory16_c(0x00fffc, 0); - - g_stepping = 0; - - if (g_irq_pending) - halt_printf("*** irq remainings...\n"); - -} - -#define CHECK(start, var, value, var1, var2) \ - var2 = PTR2WORD(&(var)); \ - var1 = PTR2WORD((start)); \ - if((var2 - var1) != value) { \ - printf("CHECK: " #var " is 0x%x, but " #value " is 0x%x\n", \ - (var2 - var1), value); \ - exit(5); \ - } - -void -check_engine_asm_defines() -{ - Fplus fplus; - Fplus *fplusptr; - Pc_log pclog; - Pc_log *pcptr; - Engine_reg ereg; - Engine_reg *eptr; - word32 val1; - word32 val2; - - eptr = &ereg; - CHECK(eptr, eptr->fcycles, ENGINE_FCYCLES, val1, val2); - CHECK(eptr, eptr->fplus_ptr, ENGINE_FPLUS_PTR, val1, val2); - CHECK(eptr, eptr->acc, ENGINE_REG_ACC, val1, val2); - CHECK(eptr, eptr->xreg, ENGINE_REG_XREG, val1, val2); - CHECK(eptr, eptr->yreg, ENGINE_REG_YREG, val1, val2); - CHECK(eptr, eptr->stack, ENGINE_REG_STACK, val1, val2); - CHECK(eptr, eptr->dbank, ENGINE_REG_DBANK, val1, val2); - CHECK(eptr, eptr->direct, ENGINE_REG_DIRECT, val1, val2); - CHECK(eptr, eptr->psr, ENGINE_REG_PSR, val1, val2); - CHECK(eptr, eptr->kpc, ENGINE_REG_KPC, val1, val2); - - pcptr = &pclog; - CHECK(pcptr, pcptr->dbank_kpc, LOG_PC_DBANK_KPC, val1, val2); - CHECK(pcptr, pcptr->instr, LOG_PC_INSTR, val1, val2); - CHECK(pcptr, pcptr->psr_acc, LOG_PC_PSR_ACC, val1, val2); - CHECK(pcptr, pcptr->xreg_yreg, LOG_PC_XREG_YREG, val1, val2); - CHECK(pcptr, pcptr->stack_direct, LOG_PC_STACK_DIRECT, val1, val2); - if(LOG_PC_SIZE != sizeof(pclog)) { - printf("LOG_PC_SIZE: %d != sizeof=%d\n", LOG_PC_SIZE, - (int)sizeof(pclog)); - exit(2); - } - - fplusptr = &fplus; - CHECK(fplusptr, fplusptr->plus_1, FPLUS_PLUS_1, val1, val2); - CHECK(fplusptr, fplusptr->plus_2, FPLUS_PLUS_2, val1, val2); - CHECK(fplusptr, fplusptr->plus_3, FPLUS_PLUS_3, val1, val2); - CHECK(fplusptr, fplusptr->plus_x_minus_1, FPLUS_PLUS_X_M1, val1, val2); -} - -byte * -memalloc_align(int size, int skip_amt, void **alloc_ptr) -{ - byte *bptr; - word32 addr; - word32 offset; - - skip_amt = MAX(256, skip_amt); - bptr = (byte*)calloc(size + skip_amt + 256, 1); // OG Added cast - if(alloc_ptr) { - /* Save allocation address */ - *alloc_ptr = bptr; - } - - addr = PTR2WORD(bptr) & 0xff; - - /* must align bptr to be 256-byte aligned */ - /* this code should work even if ptrs are > 32 bits */ - - offset = ((addr + skip_amt - 1) & (~0xff)) - addr; - - return (bptr + offset); -} - -void -memory_ptr_init() -{ - word32 mem_size; - - /* This routine may be called several times--each time the ROM file */ - /* changes this will be called */ - mem_size = MIN(0xdf0000, g_mem_size_base + g_mem_size_exp); - g_mem_size_total = mem_size; - - // OG using memory_ptr_shut() instead - memory_ptr_shut(); - /* - if(g_memory_alloc_ptr) { - free(g_memory_alloc_ptr); - g_memory_alloc_ptr = 0; - } - */ - g_memory_ptr = memalloc_align(mem_size, 256, &g_memory_alloc_ptr); - - printf("RAM size is 0 - %06x (%.2fMB)\n", mem_size, - (double)mem_size/(1024.0*1024.0)); -} - -// OG Added memory_ptr_shut -void -memory_ptr_shut() -{ - if(g_memory_alloc_ptr) - { - free(g_memory_alloc_ptr); - g_memory_alloc_ptr = 0; - } - g_memory_ptr = 0; -} - - -extern int g_screen_redraw_skip_amt; -extern int g_use_shmem; -extern int g_use_dhr140; -extern int g_use_bw_hires; - -char g_display_env[512]; -int g_force_depth = -1; -int g_screen_depth = 8; - - -int -gsportmain(int argc, char **argv) -{ - int diff; - int skip_amt; - int tmp1; - int i; - char *final_arg = 0; - - // OG Restoring globals - sim65816_initglobals(); - moremem_init(); - -//OG Disabling argument parsing -#ifndef ACTIVEGS - - /* parse args */ - for(i = 1; i < argc; i++) { - if(!strcmp("-badrd", argv[i])) { - printf("Halting on bad reads\n"); - g_halt_on_bad_read = 2; - } else if(!strcmp("-noignbadacc", argv[i])) { - printf("Not ignoring bad memory accesses\n"); - g_ignore_bad_acc = 0; - } else if(!strcmp("-noignhalt", argv[i])) { - printf("Not ignoring code red halts\n"); - g_ignore_halts = 0; - } else if(!strcmp("-test", argv[i])) { - printf("Allowing testing\n"); - g_testing_enabled = 1; - } else if(!strcmp("-hpdev", argv[i])) { - printf("Using /dev/audio\n"); - g_use_alib = 0; - } else if(!strcmp("-alib", argv[i])) { - printf("Using Aserver audio server\n"); - g_use_alib = 1; - } else if(!strcmp("-24", argv[i])) { - printf("Using 24-bit visual\n"); - g_force_depth = 24; - } else if(!strcmp("-16", argv[i])) { - printf("Using 16-bit visual\n"); - g_force_depth = 16; - } else if(!strcmp("-15", argv[i])) { - printf("Using 15-bit visual\n"); - g_force_depth = 15; - } else if(!strcmp("-mem", argv[i])) { - if((i+1) >= argc) { - printf("Missing argument\n"); - exit(1); - } - g_mem_size_exp = strtol(argv[i+1], 0, 0) & 0x00ff0000; - printf("Using %d as memory size\n", g_mem_size_exp); - i++; - } else if(!strcmp("-skip", argv[i])) { - if((i+1) >= argc) { - printf("Missing argument\n"); - exit(1); - } - skip_amt = strtol(argv[i+1], 0, 0); - printf("Using %d as skip_amt\n", skip_amt); - g_screen_redraw_skip_amt = skip_amt; - i++; - } else if(!strcmp("-audio", argv[i])) { - if((i+1) >= argc) { - printf("Missing argument\n"); - exit(1); - } - tmp1 = strtol(argv[i+1], 0, 0); - printf("Using %d as audio enable val\n", tmp1); - g_audio_enable = tmp1; - i++; - } else if(!strcmp("-arate", argv[i])) { - if((i+1) >= argc) { - printf("Missing argument\n"); - exit(1); - } - tmp1 = strtol(argv[i+1], 0, 0); - printf("Using %d as preferred audio rate\n", tmp1); - g_preferred_rate = tmp1; - i++; - } else if(!strcmp("-v", argv[i])) { - if((i+1) >= argc) { - printf("Missing argument\n"); - exit(1); - } - tmp1 = strtol(argv[i+1], 0, 0); - printf("Setting Verbose = 0x%03x\n", tmp1); - Verbose = tmp1; - i++; -#ifndef __NeXT__ - } else if(!strcmp("-display", argv[i])) { - if((i+1) >= argc) { - printf("Missing argument\n"); - exit(1); - } - printf("Using %s as display\n", argv[i+1]); - sprintf(g_display_env, "DISPLAY=%s", argv[i+1]); - putenv(&g_display_env[0]); - i++; -#endif - } else if(!strcmp("-noshm", argv[i])) { - printf("Not using X shared memory\n"); - g_use_shmem = 0; - } else if(!strcmp("-joystick", argv[i])) { - printf("Ignoring -joystick option\n"); - } else if(!strcmp("-dhr140", argv[i])) { - printf("Using simple dhires color map\n"); - g_use_dhr140 = 1; - } else if(!strcmp("-bw", argv[i])) { - printf("Forcing black-and-white hires modes\n"); - g_cur_a2_stat |= ALL_STAT_COLOR_C021; - g_use_bw_hires = 1; - } else if(!strcmp("-enet", argv[i])) { - if((i+1) >= argc) { - printf("Missing argument\n"); - exit(1); - } - tmp1 = strtol(argv[i+1], 0, 0); - printf("Using %d as ethernet enable val\n", tmp1); - g_ethernet = tmp1; - i++; - } else { - if ((i == (argc - 1)) && (strncmp("-", argv[i], 1) != 0)) { - final_arg = argv[i]; - } else { - printf("Bad option: %s\n", argv[i]); - exit(3); - } - } - } -#endif - check_engine_asm_defines(); - fixed_memory_ptrs_init(); - - if(sizeof(word32) != 4) { - printf("sizeof(word32) = %d, must be 4!\n", - (int)sizeof(word32)); - exit(1); - } - - if(!g_engine_c_mode) { - diff = &defs_instr_end_8 - &defs_instr_start_8; - if(diff != 1) { - printf("defs_instr_end_8 - start is %d\n",diff); - exit(1); - } - - diff = &defs_instr_end_16 - &defs_instr_start_16; - if(diff != 1) { - printf("defs_instr_end_16 - start is %d\n", diff); - exit(1); - } - - diff = &op_routs_end - &op_routs_start; - if(diff != 1) { - printf("op_routs_end - start is %d\n", diff); - exit(1); - } - } - - iwm_init(); - config_init(); - // If the final argument was not a switch, then treat it like a disk image filename to insert - if (final_arg) { - // ...and flag it to boot - cfg_inspect_maybe_insert_file(final_arg, 1); - } - printer_init(g_printer_dpi,85,110,g_printer_output,g_printer_multipage != 0); - //If ethernet is enabled in config.gsport, let's initialize it -#ifdef HAVE_TFE - if (g_ethernet == 1) - { - int i = 0; - char *ppname = NULL; - char *ppdes = NULL; - if (tfe_enumadapter_open()) - { - //Loop through the available adapters until we reach the interface number specified in config.gsport - while(tfe_enumadapter(&ppname,&ppdes)) - { - if (i == g_ethernet_interface) break; - i++; - } - tfe_enumadapter_close(); - printf("Using host ethernet interface: %s\nUthernet support is ON.\n",ppdes); - } - else - { - printf("No ethernet host adapters found. Do you have PCap installed/enabled?\nUthernet support is OFF.\n"); - } - set_tfe_interface(ppname); //Connect the emulated ethernet device with the selected host adapter - lib_free(ppname); - lib_free(ppdes); - tfe_init(); - } -#endif - - load_roms_init_memory(); - - init_reg(); - clear_halt(); - - initialize_events(); - - video_init(); - -#ifndef _WIN32 - //sleep(1); -#endif - sound_init(); - scc_init(); - adb_init(); - joystick_init(); - if(g_rom_version >= 3) { - g_c036_val_speed |= 0x40; /* set power-on bit */ - } - - do_reset(); - g_stepping = 0; - - // OG Notify emulator has been initialized and ready to accept external events - g_initialized = 1; - g_accept_events = 1; - - do_go(); - - /* If we get here, we hit a breakpoint, call debug intfc */ - do_debug_intfc(); - - // OG Notify emulator is being closed, and cannot accept events anymore - g_accept_events = 0; - - sound_shutdown(); - - - // OG Cleaning up - adb_shut(); - iwm_shut(); - fixed_memory_ptrs_shut(); - load_roms_shut_memory(); - clear_fatal_logs(); - - // OG Not needed anymore : the emulator will quit gently - //my_exit(0); - end_screen(); - - return 0; -} - -void -load_roms_init_memory() -{ - config_load_roms(); - memory_ptr_init(); - clk_setup_bram_version(); /* Must be after config_load_roms */ - if(g_rom_version >= 3) { - g_c036_val_speed |= 0x40; /* set power-on bit */ - } else { - g_c036_val_speed &= (~0x40); /* clear the bit */ - } - do_reset(); - - /* if user booted ROM 01, switches to ROM 03, then switches back */ - /* to ROM 01, then the reset routines call to Tool $0102 looks */ - /* at uninitialized $e1/15fe and if it is negative it will JMP */ - /* through $e1/1688 which ROM 03 left pointing to fc/0199 */ - /* So set e1/15fe = 0 */ - set_memory16_c(0xe115fe, 0, 0); -} - -// OG Added load_roms_shut_memory -void load_roms_shut_memory() -{ - memory_ptr_shut(); -} - -#ifndef ACTIVEGS - -void -gsport_expand_path(char *out_ptr, const char *in_ptr, int maxlen) -{ - char name_buf[256]; - char *tmp_ptr; - int name_len; - int in_char; - int state; - - out_ptr[0] = 0; - - name_len = 0; - state = 0; - - /* See if in_ptr has ${} notation, replace with getenv or argv0 */ - while(maxlen > 0) { - in_char = *in_ptr++; - *out_ptr++ = in_char; - maxlen--; - if(state == 0) { - /* No $ seen yet, look for it */ - if(in_char == '$') { - state = 1; - } - } else if(state == 1) { - /* See if next char is '{' (dummy }) */ - if(in_char == '{') { /* add dummy } */ - state = 2; - name_len = 0; - out_ptr -= 2; - } else { - state = 0; - } - } else if(state == 2) { - /* fill name_buf ... dummy '{' */ - out_ptr--; - if(in_char == '}') { - name_buf[name_len] = 0; - - /* got token, now look it up */ - tmp_ptr = ""; - if(!strncmp("0", name_buf, 128)) { - /* Replace ${0} with g_argv0_path */ - tmp_ptr = &(g_argv0_path[0]); -#if defined (_WIN32) || defined(__CYGWIN__) - } else if(!strncmp("PWD", name_buf, 128)) { - /* Replace ${PWD} with cwd in Windows */ - get_cwd(out_ptr,128); - tmp_ptr = out_ptr; -#endif - } else { - tmp_ptr = getenv(name_buf); - if(tmp_ptr == 0) { - tmp_ptr = ""; - } - } - strncpy(out_ptr, tmp_ptr, maxlen); - out_ptr += strlen(tmp_ptr); - maxlen -= strlen(tmp_ptr); - state = 0; - } else { - name_buf[name_len++] = in_char; - } - } - if(in_char == 0) { - /* make sure its null terminated */ - *out_ptr++ = 0; - break; - } - } -} - -void -setup_gsport_file(char *outname, int maxlen, int ok_if_missing, - int can_create_file, const char **name_ptr) -{ - char local_path[256]; - struct stat stat_buf; - const char **path_ptr; - const char **cur_name_ptr, **save_path_ptr; - int ret; - - outname[0] = 0; - - path_ptr = &g_gsport_default_paths[0]; - - save_path_ptr = path_ptr; - while(*path_ptr) { - gsport_expand_path(&(local_path[0]), *path_ptr, 250); - cur_name_ptr = name_ptr; - while(*cur_name_ptr) { - strcpy(outname, &(local_path[0])); - strncat(outname, *cur_name_ptr, 255-strlen(outname)); - if(!ok_if_missing) { - printf("Trying '%s'\n", outname); - } - ret = stat(outname, &stat_buf); - if(ret == 0) { - /* got it! */ - return; - } - cur_name_ptr++; - } - path_ptr++; - } - - outname[0] = 0; - if(ok_if_missing > 0) { - return; - } - - /* couldn't find it, print out all the attempts */ - path_ptr = save_path_ptr; - fatal_printf("Could not find required file \"%s\" in any of these " - "directories:\n", *name_ptr); - while(*path_ptr) { - fatal_printf(" %s\n", *path_ptr++); - } - - if(can_create_file) { - // If we didn't find a file, pick a place to put it. - // Default is the current working directory. -#ifdef MAC - gsport_expand_path(&(local_path[0]), "${0}/../config.txt", 250); +//OG change exit to fatal_exit() +#ifndef ACTIVEGS +// use standard exit function + #define fatalExit exit #else - gsport_expand_path(&(local_path[0]), "${PWD}/config.txt", 250); +extern void fatalExit(int); #endif - strcpy(outname, &(local_path[0])); - // Ask user if it's OK to create the file (or just create it) - x_dialog_create_gsport_conf(*name_ptr); - can_create_file = 0; - // But clear out the fatal_printfs first - clear_fatal_logs(); - setup_gsport_file(outname, maxlen, ok_if_missing, - can_create_file, name_ptr); - // It's one-level of recursion--it cannot loop since we - // clear can_create_file. - // If it returns, then there was succes and we should get out - return; - } else if(ok_if_missing) { - /* Just show an alert and return if ok_if_missing < 0 */ - x_show_alert(0, 0); - return; - } - - my_exit(2); +void my_exit(int ret) { + end_screen(); + imagewriter_close(); + printer_close(); + glogf("Exiting (ret=%d)",ret); + fatalExit(ret); } -#endif - + +void do_reset() { + + // OG Cleared remaining IRQS on RESET + extern int g_irq_pending; + extern int g_scan_int_events; + extern int g_c023_val; + + g_c068_statereg = 0x08 + 0x04 + 0x01; /* rdrom, lcbank2, intcx */ + g_c035_shadow_reg = 0; + + g_c08x_wrdefram = 1; + g_c02d_int_crom = 0; + g_c023_val = 0; + g_c041_val = 0; + + engine.psr = (engine.psr | 0x134) & ~(0x08); + engine.stack = 0x100 + (engine.stack & 0xff); + engine.dbank = 0; + engine.direct = 0; + engine.xreg &= 0xff; + engine.yreg &= 0xff; + g_wait_pending = 0; + g_stp_pending = 0; + + + video_reset(); + adb_reset(); + iwm_reset(); + scc_reset(); + sound_reset(g_cur_dcycs); + setup_pageinfo(); + change_display_mode(g_cur_dcycs); + + g_irq_pending = 0; + + engine.kpc = get_memory16_c(0x00fffc, 0); + + g_stepping = 0; + g_dbg_step = 0; + + if (g_irq_pending) + halt_printf("*** irq remainings...\n"); + +} + +#define CHECK(start, var, value, var1, var2) \ + var2 = PTR2WORD(&(var)); \ + var1 = PTR2WORD((start)); \ + if((var2 - var1) != value) { \ + printf("CHECK: " #var " is 0x%x, but " #value " is 0x%x\n", \ + (var2 - var1), value); \ + exit(5); \ + } + +void check_engine_asm_defines() { + Fplus fplus; + Fplus *fplusptr; + Pc_log pclog; + Pc_log *pcptr; + Engine_reg ereg; + Engine_reg *eptr; + word32 val1; + word32 val2; + + eptr = &ereg; + CHECK(eptr, eptr->fcycles, ENGINE_FCYCLES, val1, val2); + CHECK(eptr, eptr->fplus_ptr, ENGINE_FPLUS_PTR, val1, val2); + CHECK(eptr, eptr->acc, ENGINE_REG_ACC, val1, val2); + CHECK(eptr, eptr->xreg, ENGINE_REG_XREG, val1, val2); + CHECK(eptr, eptr->yreg, ENGINE_REG_YREG, val1, val2); + CHECK(eptr, eptr->stack, ENGINE_REG_STACK, val1, val2); + CHECK(eptr, eptr->dbank, ENGINE_REG_DBANK, val1, val2); + CHECK(eptr, eptr->direct, ENGINE_REG_DIRECT, val1, val2); + CHECK(eptr, eptr->psr, ENGINE_REG_PSR, val1, val2); + CHECK(eptr, eptr->kpc, ENGINE_REG_KPC, val1, val2); + + pcptr = &pclog; + CHECK(pcptr, pcptr->dbank_kpc, LOG_PC_DBANK_KPC, val1, val2); + CHECK(pcptr, pcptr->instr, LOG_PC_INSTR, val1, val2); + CHECK(pcptr, pcptr->psr_acc, LOG_PC_PSR_ACC, val1, val2); + CHECK(pcptr, pcptr->xreg_yreg, LOG_PC_XREG_YREG, val1, val2); + CHECK(pcptr, pcptr->stack_direct, LOG_PC_STACK_DIRECT, val1, val2); + if(LOG_PC_SIZE != sizeof(pclog)) { + printf("LOG_PC_SIZE: %d != sizeof=%d\n", LOG_PC_SIZE, + (int)sizeof(pclog)); + exit(2); + } + + fplusptr = &fplus; + CHECK(fplusptr, fplusptr->plus_1, FPLUS_PLUS_1, val1, val2); + CHECK(fplusptr, fplusptr->plus_2, FPLUS_PLUS_2, val1, val2); + CHECK(fplusptr, fplusptr->plus_3, FPLUS_PLUS_3, val1, val2); + CHECK(fplusptr, fplusptr->plus_x_minus_1, FPLUS_PLUS_X_M1, val1, val2); +} + +byte * memalloc_align(int size, int skip_amt, void **alloc_ptr) { + byte *bptr; + word32 addr; + word32 offset; + + skip_amt = MAX(256, skip_amt); + bptr = (byte*)calloc(size + skip_amt + 256, 1); // OG Added cast + if(alloc_ptr) { + /* Save allocation address */ + *alloc_ptr = bptr; + } + + addr = PTR2WORD(bptr) & 0xff; + + /* must align bptr to be 256-byte aligned */ + /* this code should work even if ptrs are > 32 bits */ + + offset = ((addr + skip_amt - 1) & (~0xff)) - addr; + + return (bptr + offset); +} + +void memory_ptr_init() { + word32 mem_size; + + /* This routine may be called several times--each time the ROM file */ + /* changes this will be called */ + mem_size = MIN(0xdf0000, g_mem_size_base + g_mem_size_exp); + g_mem_size_total = mem_size; + + // OG using memory_ptr_shut() instead + memory_ptr_shut(); + /* + if(g_memory_alloc_ptr) { + free(g_memory_alloc_ptr); + g_memory_alloc_ptr = 0; + } + */ + g_memory_ptr = memalloc_align(mem_size, 256, &g_memory_alloc_ptr); + + glogf("RAM size is %d bytes (%.2fMB)", mem_size, (double)mem_size/(1024.0*1024.0)); +} + +// OG Added memory_ptr_shut +void memory_ptr_shut() { + if(g_memory_alloc_ptr) + { + free(g_memory_alloc_ptr); + g_memory_alloc_ptr = 0; + } + g_memory_ptr = 0; +} + + + +int gsportmain(int argc, char **argv) { + int diff; + int skip_amt; + int i; + char *final_arg = 0; + + printf("\n\x1b[37m GSport v%s \x1b[0m \n\n", g_gsport_version_str); + + // OG Restoring globals + sim65816_initglobals(); + moremem_init(); + parse_cli_options(argc, argv); + + + + // initialize ss dir to default value (current path) + strcpy(g_config_gsport_screenshot_dir, "./"); + + + + + check_engine_asm_defines(); + fixed_memory_ptrs_init(); + + if(sizeof(word32) != 4) { + printf("sizeof(word32) = %d, must be 4!\n", + (int)sizeof(word32)); + exit(1); + } + + if(!g_engine_c_mode) { + diff = &defs_instr_end_8 - &defs_instr_start_8; + if(diff != 1) { + printf("defs_instr_end_8 - start is %d\n",diff); + exit(1); + } + + diff = &defs_instr_end_16 - &defs_instr_start_16; + if(diff != 1) { + printf("defs_instr_end_16 - start is %d\n", diff); + exit(1); + } + + diff = &op_routs_end - &op_routs_start; + if(diff != 1) { + printf("op_routs_end - start is %d\n", diff); + exit(1); + } + } + + iwm_init(); + debug_init(); // enable socket debugger if configured + config_init(); + // If the final argument was not a switch, then treat it like a disk image filename to insert + if (final_arg) { + // ...and flag it to boot + cfg_inspect_maybe_insert_file(final_arg, 1); + } + printer_init(g_printer_dpi,85,110,g_printer_output,g_printer_multipage != 0); + //If ethernet is enabled in config.gsport, let's initialize it +#ifdef HAVE_TFE + if (g_ethernet == 1) + { + int i = 0; + char *ppname = NULL; + char *ppdes = NULL; + if (tfe_enumadapter_open()) + { + //Loop through the available adapters until we reach the interface number specified in config.gsport + while(tfe_enumadapter(&ppname,&ppdes)) + { + if (i == g_ethernet_interface) break; + i++; + } + tfe_enumadapter_close(); + printf("Using host ethernet interface: %s\nUthernet support is ON.\n",ppdes); + } + else + { + printf("No ethernet host adapters found. Do you have PCap installed/enabled?\nUthernet support is OFF.\n"); + } + set_tfe_interface(ppname); //Connect the emulated ethernet device with the selected host adapter + lib_free(ppname); + lib_free(ppdes); + tfe_init(); + } +#endif + + load_roms_init_memory(); + + init_reg(); + clear_halt(); + + + initialize_events(); + + video_init(); + + sound_init(); + scc_init(); + adb_init(); + joystick_init(); + if(g_rom_version >= 3) { + g_c036_val_speed |= 0x40; /* set power-on bit */ + } + + do_reset(); + g_stepping = 0; + g_dbg_step = 0; + + // OG Notify emulator has been initialized and ready to accept external events + g_initialized = 1; + g_accept_events = 1; + + // Call one of two main run_prog() routines + if (g_dbg_enable_port) { + do_go_debug(); + } else { + do_go(); + /* If we get here, we hit a breakpoint, call debug intfc */ + do_debug_intfc(); + } + + // OG Notify emulator is being closed, and cannot accept events anymore + g_accept_events = 0; + + sound_shutdown(); + + + // OG Cleaning up + adb_shut(); + iwm_shut(); + fixed_memory_ptrs_shut(); + load_roms_shut_memory(); + clear_fatal_logs(); + + // OG Not needed anymore : the emulator will quit gently + //my_exit(0); + end_screen(); + + return 0; +} + +void load_roms_init_memory() { + config_load_roms(); + memory_ptr_init(); + clk_setup_bram_version(); /* Must be after config_load_roms */ + if(g_rom_version >= 3) { + g_c036_val_speed |= 0x40; /* set power-on bit */ + } else { + g_c036_val_speed &= (~0x40); /* clear the bit */ + } + do_reset(); + + /* if user booted ROM 01, switches to ROM 03, then switches back */ + /* to ROM 01, then the reset routines call to Tool $0102 looks */ + /* at uninitialized $e1/15fe and if it is negative it will JMP */ + /* through $e1/1688 which ROM 03 left pointing to fc/0199 */ + /* So set e1/15fe = 0 */ + set_memory16_c(0xe115fe, 0, 0); +} + +// OG Added load_roms_shut_memory +void load_roms_shut_memory() { + memory_ptr_shut(); +} + +#ifndef ACTIVEGS + +void gsport_expand_path(char *out_ptr, const char *in_ptr, int maxlen) { + char name_buf[256]; + char *tmp_ptr; + int name_len; + int in_char; + int state; + + out_ptr[0] = 0; + + name_len = 0; + state = 0; + + /* See if in_ptr has ${} notation, replace with getenv or argv0 */ + while(maxlen > 0) { + in_char = *in_ptr++; + *out_ptr++ = in_char; + maxlen--; + if(state == 0) { + /* No $ seen yet, look for it */ + if(in_char == '$') { + state = 1; + } + } else if(state == 1) { + /* See if next char is '{' (dummy }) */ + if(in_char == '{') { /* add dummy } */ + state = 2; + name_len = 0; + out_ptr -= 2; + } else { + state = 0; + } + } else if(state == 2) { + /* fill name_buf ... dummy '{' */ + out_ptr--; + if(in_char == '}') { + name_buf[name_len] = 0; + + /* got token, now look it up */ + tmp_ptr = ""; + if(!strncmp("0", name_buf, 128)) { + /* Replace ${0} with g_argv0_path */ + tmp_ptr = &(g_argv0_path[0]); +#if defined (_WIN32) && !defined(WIN_SDL)|| defined(__CYGWIN__) && !defined(WIN_SDL) + } else if(!strncmp("PWD", name_buf, 128)) { + /* Replace ${PWD} with cwd in Windows */ + get_cwd(out_ptr,128); + tmp_ptr = out_ptr; +#endif + } else { + tmp_ptr = getenv(name_buf); + if(tmp_ptr == 0) { + tmp_ptr = ""; + } + } + strncpy(out_ptr, tmp_ptr, maxlen); + out_ptr += strlen(tmp_ptr); + maxlen -= strlen(tmp_ptr); + state = 0; + } else { + name_buf[name_len++] = in_char; + } + } + if(in_char == 0) { + /* make sure its null terminated */ + *out_ptr++ = 0; + break; + } + } +} + +void setup_gsport_file(char *outname, int maxlen, int ok_if_missing, int can_create_file, const char **name_ptr) { + char local_path[256]; + struct stat stat_buf; + const char **path_ptr; + const char **cur_name_ptr, **save_path_ptr; + int ret; + + outname[0] = 0; + + path_ptr = &g_gsport_default_paths[0]; + + save_path_ptr = path_ptr; + while(*path_ptr) { + gsport_expand_path(&(local_path[0]), *path_ptr, 250); + cur_name_ptr = name_ptr; + while(*cur_name_ptr) { + strcpy(outname, &(local_path[0])); + strncat(outname, *cur_name_ptr, 255-strlen(outname)); + if(!ok_if_missing) { // ?? + glogf("Trying config file '%s'", outname); + } + ret = stat(outname, &stat_buf); + if(ret == 0) { + return; + } + cur_name_ptr++; + } + path_ptr++; + } + + outname[0] = 0; + if(ok_if_missing > 0) { + return; + } + + glogf("Could not find required file \"%s\" !!!", *name_ptr); + // this check is crap + if (strcmp(*name_ptr, "ROM") == 0) { + glog(" IIgs will likely hang now!"); + glog(" Get an Apple IIgs firmware ROM image from somewhere like:"); + glog(" ftp://ftp.apple.asimov.net/pub/apple_II/emulators/rom_images/"); + glog(" ... and rename the file to \"ROM\" and restart"); + glog(" ... or hit and browse for a valid ROM image."); + x_show_alert(0, "Missing Apple IIgs ROM file.\nHit F4 to configure ROM location or refer to documentation."); + } + + if(can_create_file) { + // If we didn't find a file, pick a place to put it. + // Default is the current working directory. + // This is often wrong in OS X. /Applications/GSport.app is + // probably not writable by the default user, and PWD is set + // there when launched from an .app structure. + // Normally the HOME directory under a *NIX system is probably + // a better place for the config file. Ideally a "dotfile" + // like most applications, or something under "~/Library". + // However, GSport is promoting a notion of Config-as-a-VM + // where we want to encourage many configs. (See DGB video + // on YT regarding the GSVision UI experiment.) + + + glogf("Trying to create config (%s)", "${HOME}/.config.gsp"); + gsport_expand_path(&(local_path[0]), "${HOME}/.config.gsp", 250); + + strcpy(outname, &(local_path[0])); + // Ask user if it's OK to create the file (or just create it) + x_dialog_create_gsport_conf(*name_ptr); + can_create_file = 0; + + // But clear out the fatal_printfs first + clear_fatal_logs(); + setup_gsport_file(outname, maxlen, ok_if_missing, can_create_file, name_ptr); + // It's one-level of recursion--it cannot loop since we + // clear can_create_file. + // If it returns, then there was succes and we should get out + return; + } else if(ok_if_missing) { + return; + } + + my_exit(2); +} + +#endif + Event g_event_list[MAX_EVENTS]; Event g_event_free; Event g_event_start; -void -initialize_events() -{ - int i; +void initialize_events() { + int i; - for(i = 1; i < MAX_EVENTS; i++) { - g_event_list[i-1].next = &g_event_list[i]; - } - g_event_free.next = &g_event_list[0]; - g_event_list[MAX_EVENTS-1].next = 0; + for(i = 1; i < MAX_EVENTS; i++) { + g_event_list[i-1].next = &g_event_list[i]; + } + g_event_free.next = &g_event_list[0]; + g_event_list[MAX_EVENTS-1].next = 0; - g_event_start.next = 0; - g_event_start.dcycs = 0.0; + g_event_start.next = 0; + g_event_start.dcycs = 0.0; - add_event_entry(DCYCS_IN_16MS, EV_60HZ); + add_event_entry(DCYCS_IN_16MS, EV_60HZ); } -void -check_for_one_event_type(int type) -{ - Event *ptr; - int count; - int depth; +void check_for_one_event_type(int type) { + Event *ptr; + int count; + int depth; - count = 0; - depth = 0; - ptr = g_event_start.next; - while(ptr != 0) { - depth++; - if(ptr->type == type) { - count++; - if(count != 1) { - halt_printf("in check_for_1, type %d found at " - "depth: %d, count: %d, at %f\n", - type, depth, count, ptr->dcycs); - } - } - ptr = ptr->next; - } + count = 0; + depth = 0; + ptr = g_event_start.next; + while(ptr != 0) { + depth++; + if(ptr->type == type) { + count++; + if(count != 1) { + halt_printf("in check_for_1, type %d found at " + "depth: %d, count: %d, at %f\n", + type, depth, count, ptr->dcycs); + } + } + ptr = ptr->next; + } } -void -add_event_entry(double dcycs, int type) -{ - Event *this_event; - Event *ptr, *prev_ptr; - int tmp_type; - int done; +void add_event_entry(double dcycs, int type) { + Event *this_event; + Event *ptr, *prev_ptr; + int tmp_type; + int done; - this_event = g_event_free.next; - if(this_event == 0) { - halt_printf("Out of queue entries!\n"); - show_all_events(); - return; - } - g_event_free.next = this_event->next; + this_event = g_event_free.next; + if(this_event == 0) { + halt_printf("Out of queue entries!\n"); + show_all_events(); + return; + } + g_event_free.next = this_event->next; - this_event->type = type; + this_event->type = type; - tmp_type = type & 0xff; - if((dcycs < 0.0) || (dcycs > (g_cur_dcycs + 50*1000*1000.0)) || - ((dcycs < g_cur_dcycs) && (tmp_type != EV_SCAN_INT))) { - halt_printf("add_event: dcycs: %f, type:%05x, cur_dcycs: %f!\n", - dcycs, type, g_cur_dcycs); - dcycs = g_cur_dcycs + 1000.0; - } + tmp_type = type & 0xff; + if((dcycs < 0.0) || (dcycs > (g_cur_dcycs + 50*1000*1000.0)) || + ((dcycs < g_cur_dcycs) && (tmp_type != EV_SCAN_INT))) { + halt_printf("add_event: dcycs: %f, type:%05x, cur_dcycs: %f!\n", + dcycs, type, g_cur_dcycs); + dcycs = g_cur_dcycs + 1000.0; + } - ptr = g_event_start.next; - if(ptr && (dcycs < ptr->dcycs)) { - /* create event before next expected event */ - /* do this by setting HALT_EVENT */ - set_halt(HALT_EVENT); - } + ptr = g_event_start.next; + if(ptr && (dcycs < ptr->dcycs)) { + /* create event before next expected event */ + /* do this by setting HALT_EVENT */ + set_halt(HALT_EVENT); + } - prev_ptr = &g_event_start; - ptr = g_event_start.next; + prev_ptr = &g_event_start; + ptr = g_event_start.next; - done = 0; - while(!done) { - if(ptr == 0) { - this_event->next = ptr; - this_event->dcycs = dcycs; - prev_ptr->next = this_event; - return; - } else { - if(ptr->dcycs < dcycs) { - /* step across this guy */ - prev_ptr = ptr; - ptr = ptr->next; - } else { - /* go in front of this guy */ - this_event->dcycs = dcycs; - this_event->next = ptr; - prev_ptr->next = this_event; - return; - } - } - } + done = 0; + while(!done) { + if(ptr == 0) { + this_event->next = ptr; + this_event->dcycs = dcycs; + prev_ptr->next = this_event; + return; + } else { + if(ptr->dcycs < dcycs) { + /* step across this guy */ + prev_ptr = ptr; + ptr = ptr->next; + } else { + /* go in front of this guy */ + this_event->dcycs = dcycs; + this_event->next = ptr; + prev_ptr->next = this_event; + return; + } + } + } } extern int g_doc_saved_ctl; -double -remove_event_entry(int type) -{ - Event *ptr, *prev_ptr; - Event *next_ptr; +double remove_event_entry(int type) { + Event *ptr, *prev_ptr; + Event *next_ptr; - ptr = g_event_start.next; - prev_ptr = &g_event_start; + ptr = g_event_start.next; + prev_ptr = &g_event_start; - while(ptr != 0) { - if((ptr->type & 0xffff) == type) { - /* got it, remove it */ - next_ptr = ptr->next; - prev_ptr->next = next_ptr; + while(ptr != 0) { + if((ptr->type & 0xffff) == type) { + /* got it, remove it */ + next_ptr = ptr->next; + prev_ptr->next = next_ptr; - /* Add ptr to free list */ - ptr->next = g_event_free.next; - g_event_free.next = ptr; + /* Add ptr to free list */ + ptr->next = g_event_free.next; + g_event_free.next = ptr; - return ptr->dcycs; - } - prev_ptr = ptr; - ptr = ptr->next; - } + return ptr->dcycs; + } + prev_ptr = ptr; + ptr = ptr->next; + } - halt_printf("remove event_entry: %08x, but not found!\n", type); - if((type & 0xff) == EV_DOC_INT) { - printf("DOC, g_doc_saved_ctl = %02x\n", g_doc_saved_ctl); - } + halt_printf("remove event_entry: %08x, but not found!\n", type); + if((type & 0xff) == EV_DOC_INT) { + printf("DOC, g_doc_saved_ctl = %02x\n", g_doc_saved_ctl); + } #ifdef HPUX - U_STACK_TRACE(); + U_STACK_TRACE(); #endif - show_all_events(); + show_all_events(); - return 0.0; + return 0.0; } -void -add_event_stop(double dcycs) -{ - add_event_entry(dcycs, EV_STOP); +void add_event_stop(double dcycs) { + add_event_entry(dcycs, EV_STOP); } -void -add_event_doc(double dcycs, int osc) -{ - if(dcycs < g_cur_dcycs) { - dcycs = g_cur_dcycs; +void add_event_doc(double dcycs, int osc) { + if(dcycs < g_cur_dcycs) { + dcycs = g_cur_dcycs; #if 0 - halt_printf("add_event_doc: dcycs: %f, cur_dcycs: %f\n", - dcycs, g_cur_dcycs); + halt_printf("add_event_doc: dcycs: %f, cur_dcycs: %f\n", + dcycs, g_cur_dcycs); #endif - } + } - add_event_entry(dcycs, EV_DOC_INT + (osc << 8)); + add_event_entry(dcycs, EV_DOC_INT + (osc << 8)); } -void -add_event_scc(double dcycs, int type) -{ - if(dcycs < g_cur_dcycs) { - dcycs = g_cur_dcycs; - } +void add_event_scc(double dcycs, int type) { + if(dcycs < g_cur_dcycs) { + dcycs = g_cur_dcycs; + } - add_event_entry(dcycs, EV_SCC + (type << 8)); + add_event_entry(dcycs, EV_SCC + (type << 8)); } -void -add_event_vbl() -{ - double dcycs; +void add_event_vbl() { + double dcycs; - dcycs = g_last_vbl_dcycs + (DCYCS_IN_16MS * (192.0/262.0)); - add_event_entry(dcycs, EV_VBL_INT); + dcycs = g_last_vbl_dcycs + (DCYCS_IN_16MS * (192.0/262.0)); + add_event_entry(dcycs, EV_VBL_INT); } -void -add_event_vid_upd(int line) -{ - double dcycs; +void add_event_vid_upd(int line) { + double dcycs; - dcycs = g_last_vbl_dcycs + ((DCYCS_IN_16MS * line) / 262.0); - add_event_entry(dcycs, EV_VID_UPD + (line << 8)); + dcycs = g_last_vbl_dcycs + ((DCYCS_IN_16MS * line) / 262.0); + add_event_entry(dcycs, EV_VID_UPD + (line << 8)); } -double -remove_event_doc(int osc) -{ - return remove_event_entry(EV_DOC_INT + (osc << 8)); +double remove_event_doc(int osc) { + return remove_event_entry(EV_DOC_INT + (osc << 8)); } -double -remove_event_scc(int type) -{ - return remove_event_entry(EV_SCC + (type << 8)); +double remove_event_scc(int type) { + return remove_event_entry(EV_SCC + (type << 8)); } -void -show_all_events() -{ - Event *ptr; - int count; - double dcycs; +void show_all_events() { + Event *ptr; + int count; + double dcycs; - count = 0; - ptr = g_event_start.next; - while(ptr != 0) { - dcycs = ptr->dcycs; - printf("Event: %02x: type: %05x, dcycs: %f (%f)\n", - count, ptr->type, dcycs, dcycs - g_cur_dcycs); - ptr = ptr->next; - count++; - } + count = 0; + ptr = g_event_start.next; + while(ptr != 0) { + dcycs = ptr->dcycs; + printf("Event: %02x: type: %05x, dcycs: %f (%f)\n", + count, ptr->type, dcycs, dcycs - g_cur_dcycs); + ptr = ptr->next; + count++; + } } -word32 g_vbl_count = 0; -int g_vbl_index_count = 0; -double dtime_array[60]; -double g_dadjcycs_array[60]; -double g_dtime_diff3_array[60]; -double g_dtime_this_vbl_array[60]; -double g_dtime_exp_array[60]; -double g_dtime_pmhz_array[60]; -double g_dtime_eff_pmhz_array[60]; -int g_limit_speed = 2; -double sim_time[60]; -double g_sim_sum = 0.0; +word32 g_vbl_count = 0; +int g_vbl_index_count = 0; +double dtime_array[60]; +double g_dadjcycs_array[60]; +double g_dtime_diff3_array[60]; +double g_dtime_this_vbl_array[60]; +double g_dtime_exp_array[60]; +double g_dtime_pmhz_array[60]; +double g_dtime_eff_pmhz_array[60]; +int g_limit_speed = 2; +double sim_time[60]; +double g_sim_sum = 0.0; -double g_cur_sim_dtime = 0.0; -double g_projected_pmhz = 1.0; -double g_zip_pmhz = 8.0; -double g_sim_mhz = 100.0; -int g_line_ref_amt = 1; -int g_video_line_update_interval = 0; +double g_cur_sim_dtime = 0.0; +double g_projected_pmhz = 1.0; +double g_zip_pmhz = 8.0; +double g_sim_mhz = 100.0; +int g_line_ref_amt = 1; +int g_video_line_update_interval = 0; -Fplus g_recip_projected_pmhz_slow; -Fplus g_recip_projected_pmhz_fast; -Fplus g_recip_projected_pmhz_zip; -Fplus g_recip_projected_pmhz_unl; +Fplus g_recip_projected_pmhz_slow; +Fplus g_recip_projected_pmhz_fast; +Fplus g_recip_projected_pmhz_zip; +Fplus g_recip_projected_pmhz_unl; -void -show_pmhz() -{ - printf("Pmhz: %f, c036:%02x, limit: %d\n", - g_projected_pmhz, g_c036_val_speed, g_limit_speed); +void show_pmhz() { + printf("Pmhz: %f, c036:%02x, limit: %d\n", + g_projected_pmhz, g_c036_val_speed, g_limit_speed); } -void -setup_zip_speeds() -{ - double frecip; - double fmhz; - int mult; +void setup_zip_speeds() { + double frecip; + double fmhz; + int mult; - mult = 16 - ((g_zipgs_reg_c05a >> 4) & 0xf); - // 16 = full speed, 1 = 1/16th speed - fmhz = (8.0 * mult) / 16.0; + mult = 16 - ((g_zipgs_reg_c05a >> 4) & 0xf); + // 16 = full speed, 1 = 1/16th speed + fmhz = (8.0 * mult) / 16.0; #if 0 - if(mult == 16) { - /* increase full speed by 19% to make zipgs freq measuring */ - /* programs work correctly */ - fmhz = fmhz * 1.19; - } + if(mult == 16) { + /* increase full speed by 19% to make zipgs freq measuring */ + /* programs work correctly */ + fmhz = fmhz * 1.19; + } #endif - frecip = 1.0 / fmhz; - g_zip_pmhz = fmhz; - g_recip_projected_pmhz_zip.plus_1 = frecip; - g_recip_projected_pmhz_zip.plus_2 = 2.0 * frecip; - g_recip_projected_pmhz_zip.plus_3 = 3.0 * frecip; - if(frecip >= 0.5) { - g_recip_projected_pmhz_zip.plus_x_minus_1 = 1.01; - } else { - g_recip_projected_pmhz_zip.plus_x_minus_1 = 1.01 - frecip; - } + frecip = 1.0 / fmhz; + g_zip_pmhz = fmhz; + g_recip_projected_pmhz_zip.plus_1 = frecip; + g_recip_projected_pmhz_zip.plus_2 = 2.0 * frecip; + g_recip_projected_pmhz_zip.plus_3 = 3.0 * frecip; + if(frecip >= 0.5) { + g_recip_projected_pmhz_zip.plus_x_minus_1 = 1.01; + } else { + g_recip_projected_pmhz_zip.plus_x_minus_1 = 1.01 - frecip; + } } -void -run_prog() -{ - Fplus *fplus_ptr; - Event *this_event; - Event *db1; - double dcycs; - double now_dtime; - double prev_dtime; - double prerun_fcycles; - double fspeed_mult; - double fcycles_stop; - word32 ret; - word32 zip_speed_0tof, zip_speed_0tof_new; - int zip_en, zip_follow_cps; - int type; - int motor_on; - int iwm_1; - int iwm_25; - int limit_speed; - int apple35_sel; - int fast, zip_speed, faster_than_28, unl_speed; - int this_type; +void run_prog() { + Fplus *fplus_ptr; + Event *this_event; + Event *db1; + double dcycs; + double now_dtime; + double prev_dtime; + double prerun_fcycles; + double fspeed_mult; + double fcycles_stop; + word32 ret; + word32 zip_speed_0tof, zip_speed_0tof_new; + int zip_en, zip_follow_cps; + int type; + int motor_on; + int iwm_1; + int iwm_25; + int limit_speed; + int apple35_sel; + int fast, zip_speed, faster_than_28, unl_speed; + int this_type; - fflush(stdout); + fflush(stdout); - g_cur_sim_dtime = 0.0; + g_cur_sim_dtime = 0.0; - g_recip_projected_pmhz_slow.plus_1 = 1.0; - g_recip_projected_pmhz_slow.plus_2 = 2.0; - g_recip_projected_pmhz_slow.plus_3 = 3.0; - g_recip_projected_pmhz_slow.plus_x_minus_1 = 0.9; + g_recip_projected_pmhz_slow.plus_1 = 1.0; + g_recip_projected_pmhz_slow.plus_2 = 2.0; + g_recip_projected_pmhz_slow.plus_3 = 3.0; + g_recip_projected_pmhz_slow.plus_x_minus_1 = 0.9; - g_recip_projected_pmhz_fast.plus_1 = (1.0 / 2.5); - g_recip_projected_pmhz_fast.plus_2 = (2.0 / 2.5); - g_recip_projected_pmhz_fast.plus_3 = (3.0 / 2.5); - g_recip_projected_pmhz_fast.plus_x_minus_1 = (1.98 - (1.0/2.5)); + g_recip_projected_pmhz_fast.plus_1 = (1.0 / 2.5); + g_recip_projected_pmhz_fast.plus_2 = (2.0 / 2.5); + g_recip_projected_pmhz_fast.plus_3 = (3.0 / 2.5); + g_recip_projected_pmhz_fast.plus_x_minus_1 = (1.98 - (1.0/2.5)); - zip_speed_0tof = g_zipgs_reg_c05a & 0xf0; - setup_zip_speeds(); + zip_speed_0tof = g_zipgs_reg_c05a & 0xf0; + setup_zip_speeds(); - if(engine.fplus_ptr == 0) { - g_recip_projected_pmhz_unl = g_recip_projected_pmhz_slow; - } + if(engine.fplus_ptr == 0) { + g_recip_projected_pmhz_unl = g_recip_projected_pmhz_slow; + } - while(1) { - fflush(stdout); - -// OG Disabling control panel -#ifndef ACTIVEGS - if(g_config_control_panel) { - config_control_panel(); - } -#endif - if(g_irq_pending && !(engine.psr & 0x4)) { - irq_printf("taking an irq!\n"); - take_irq(0); - /* Interrupt! */ - } + while(1) { + fflush(stdout); - motor_on = g_iwm_motor_on; - limit_speed = g_limit_speed; - apple35_sel = g_c031_disk35 & 0x40; - zip_en = ((g_zipgs_reg_c05b & 0x10) == 0); - zip_follow_cps = ((g_zipgs_reg_c059 & 0x8) != 0); - zip_speed_0tof_new = g_zipgs_reg_c05a & 0xf0; - fast = (g_c036_val_speed & 0x80) || (zip_en && !zip_follow_cps); - // OG Make fast parameter public - g_speed_fast = fast; - if(zip_speed_0tof_new != zip_speed_0tof) { - zip_speed_0tof = zip_speed_0tof_new; - setup_zip_speeds(); - } +// OG Disabling control panel +#ifndef ACTIVEGS + if(g_config_control_panel) { + config_control_panel(); + } +#endif + if(g_irq_pending && !(engine.psr & 0x4)) { + irq_printf("taking an irq!\n"); + take_irq(0); + /* Interrupt! */ + } - iwm_1 = motor_on && !apple35_sel && - (g_c036_val_speed & 0x4) && - (g_slow_525_emul_wr || !g_fast_disk_emul); - iwm_25 = (motor_on && apple35_sel) && !g_fast_disk_emul; - faster_than_28 = fast && (!iwm_1 && !iwm_25) && zip_en && - ((limit_speed == 0) || (limit_speed == 3)); - zip_speed = faster_than_28 && - ((zip_speed_0tof != 0) || (limit_speed == 3) || - (g_zipgs_unlock >= 4) ); - - // OG unlimited speed should not be affected by zip. - // unl_speed = faster_than_28 && !zip_speed; - unl_speed = (limit_speed == 0) && faster_than_28; - - if(unl_speed) { - /* use unlimited speed */ - fspeed_mult = g_projected_pmhz; - fplus_ptr = &g_recip_projected_pmhz_unl; - } else if(zip_speed) { - fspeed_mult = g_zip_pmhz; - fplus_ptr = &g_recip_projected_pmhz_zip; - } else if(fast && !iwm_1 && !(limit_speed == 1)) { - fspeed_mult = 2.5; - fplus_ptr = &g_recip_projected_pmhz_fast; - } else { - /* else run slow */ - fspeed_mult = 1.0; - fplus_ptr = &g_recip_projected_pmhz_slow; - } + motor_on = g_iwm_motor_on; + limit_speed = g_limit_speed; + apple35_sel = g_c031_disk35 & 0x40; + zip_en = ((g_zipgs_reg_c05b & 0x10) == 0); + zip_follow_cps = ((g_zipgs_reg_c059 & 0x8) != 0); + zip_speed_0tof_new = g_zipgs_reg_c05a & 0xf0; + fast = (g_c036_val_speed & 0x80) || (zip_en && !zip_follow_cps); + // OG Make fast parameter public + g_speed_fast = fast; + if(zip_speed_0tof_new != zip_speed_0tof) { + zip_speed_0tof = zip_speed_0tof_new; + setup_zip_speeds(); + } - engine.fplus_ptr = fplus_ptr; + iwm_1 = motor_on && !apple35_sel && + (g_c036_val_speed & 0x4) && + (g_slow_525_emul_wr || !g_fast_disk_emul); + iwm_25 = (motor_on && apple35_sel) && !g_fast_disk_emul; + faster_than_28 = fast && (!iwm_1 && !iwm_25) && zip_en && + ((limit_speed == 0) || (limit_speed == 3)); + zip_speed = faster_than_28 && + ((zip_speed_0tof != 0) || (limit_speed == 3) || + (g_zipgs_unlock >= 4) ); - this_type = g_event_start.next->type; + // OG unlimited speed should not be affected by zip. + // unl_speed = faster_than_28 && !zip_speed; + unl_speed = (limit_speed == 0) && faster_than_28; - prerun_fcycles = g_cur_dcycs - g_last_vbl_dcycs; - engine.fcycles = prerun_fcycles; - fcycles_stop = (g_event_start.next->dcycs - g_last_vbl_dcycs) + - 0.001; - if(g_stepping) { - fcycles_stop = prerun_fcycles; - } - g_fcycles_stop = fcycles_stop; + if(unl_speed) { + /* use unlimited speed */ + fspeed_mult = g_projected_pmhz; + fplus_ptr = &g_recip_projected_pmhz_unl; + } else if(zip_speed) { + fspeed_mult = g_zip_pmhz; + fplus_ptr = &g_recip_projected_pmhz_zip; + } else if(fast && !iwm_1 && !(limit_speed == 1)) { + fspeed_mult = 2.5; + fplus_ptr = &g_recip_projected_pmhz_fast; + } else { + /* else run slow */ + fspeed_mult = 1.0; + fplus_ptr = &g_recip_projected_pmhz_slow; + } + + engine.fplus_ptr = fplus_ptr; + + this_type = g_event_start.next->type; + + prerun_fcycles = g_cur_dcycs - g_last_vbl_dcycs; + engine.fcycles = prerun_fcycles; + fcycles_stop = (g_event_start.next->dcycs - g_last_vbl_dcycs) + + 0.001; + if(g_stepping || g_dbg_step < 0) { + fcycles_stop = prerun_fcycles; + } + g_fcycles_stop = fcycles_stop; #if 0 - printf("Enter engine, fcycs: %f, stop: %f\n", - prerun_fcycles, fcycles_stop); - printf("g_cur_dcycs: %f, last_vbl_dcyc: %f\n", g_cur_dcycs, - g_last_vbl_dcycs); + printf("Enter engine, fcycs: %f, stop: %f\n", + prerun_fcycles, fcycles_stop); + printf("g_cur_dcycs: %f, last_vbl_dcyc: %f\n", g_cur_dcycs, + g_last_vbl_dcycs); #endif - g_num_enter_engine++; - prev_dtime = get_dtime(); + g_num_enter_engine++; + prev_dtime = get_dtime(); - ret = enter_engine(&engine); + ret = enter_engine(&engine); - now_dtime = get_dtime(); + now_dtime = get_dtime(); - g_cur_sim_dtime += (now_dtime - prev_dtime); + g_cur_sim_dtime += (now_dtime - prev_dtime); - dcycs = g_last_vbl_dcycs + (double)(engine.fcycles); + dcycs = g_last_vbl_dcycs + (double)(engine.fcycles); - g_dadjcycs += (engine.fcycles - prerun_fcycles) * - fspeed_mult; + g_dadjcycs += (engine.fcycles - prerun_fcycles) * + fspeed_mult; #if 0 - printf("...back, engine.fcycles: %f, dcycs: %f\n", - (double)engine.fcycles, dcycs); + printf("...back, engine.fcycles: %f, dcycs: %f\n", + (double)engine.fcycles, dcycs); #endif - g_cur_dcycs = dcycs; + g_cur_dcycs = dcycs; - if(ret != 0) { - g_engine_action++; - handle_action(ret); - } + if(ret != 0) { + g_engine_action++; + handle_action(ret); + } - if(halt_sim == HALT_EVENT) { - g_engine_halt_event++; - /* if we needed to stop to check for interrupts, */ - /* clear halt */ - halt_sim = 0; - } + if(halt_sim == HALT_EVENT) { + g_engine_halt_event++; + /* if we needed to stop to check for interrupts, */ + /* clear halt */ + halt_sim = 0; + } #if 0 - if(!g_testing && run_cycles < -2000000) { - halt_printf("run_cycles: %d, cycles: %d\n", run_cycles, - cycles); - printf("this_type: %05x\n", this_type); - printf("duff_cycles: %d\n", duff_cycles); - printf("start.next->rel_time: %d, type: %05x\n", - g_event_start.next->rel_time, - g_event_start.next->type); - } + if(!g_testing && run_cycles < -2000000) { + halt_printf("run_cycles: %d, cycles: %d\n", run_cycles, + cycles); + printf("this_type: %05x\n", this_type); + printf("duff_cycles: %d\n", duff_cycles); + printf("start.next->rel_time: %d, type: %05x\n", + g_event_start.next->rel_time, + g_event_start.next->type); + } #endif - this_event = g_event_start.next; - while(dcycs >= this_event->dcycs) { - /* Pop this guy off of the queue */ - g_event_start.next = this_event->next; + this_event = g_event_start.next; + while(dcycs >= this_event->dcycs) { + if(halt_sim != 0 && halt_sim != HALT_EVENT) { + break; + } + if(g_stepping || g_dbg_step != 0) { + printf("HIT STEPPING BREAK!\n"); + break; + } + /* Pop this guy off of the queue */ + g_event_start.next = this_event->next; - type = this_event->type; - this_event->next = g_event_free.next; - g_event_free.next = this_event; - switch(type & 0xff) { - case EV_60HZ: - update_60hz(dcycs, now_dtime); - break; - case EV_STOP: - printf("type: EV_STOP\n"); - printf("next: %p, dcycs: %f\n", - g_event_start.next, dcycs); - db1 = g_event_start.next; - halt_printf("next.dcycs: %f\n", db1->dcycs); - break; - case EV_SCAN_INT: - g_engine_scan_int++; - irq_printf("type: scan int\n"); - do_scan_int(dcycs, type >> 8); - break; - case EV_DOC_INT: - g_engine_doc_int++; - doc_handle_event(type >> 8, dcycs); - break; - case EV_VBL_INT: - do_vbl_int(); - break; - case EV_SCC: - do_scc_event(type >> 8, dcycs); - break; - case EV_VID_UPD: - video_update_event_line(type >> 8); - break; - default: - printf("Unknown event: %d!\n", type); - exit(3); - } + type = this_event->type; + this_event->next = g_event_free.next; + g_event_free.next = this_event; + switch(type & 0xff) { + case EV_60HZ: + update_60hz(dcycs, now_dtime); + debug_server_poll(); + if (debug_events_waiting() > 0) { + debug_handle_event(); + } + break; + case EV_STOP: + printf("type: EV_STOP\n"); + printf("next: %p, dcycs: %f\n", + g_event_start.next, dcycs); + db1 = g_event_start.next; + halt_printf("next.dcycs: %f\n", db1->dcycs); + break; + case EV_SCAN_INT: + g_engine_scan_int++; + irq_printf("type: scan int\n"); + do_scan_int(dcycs, type >> 8); + break; + case EV_DOC_INT: + g_engine_doc_int++; + doc_handle_event(type >> 8, dcycs); + break; + case EV_VBL_INT: + do_vbl_int(); + break; + case EV_SCC: + do_scc_event(type >> 8, dcycs); + break; + case EV_VID_UPD: + video_update_event_line(type >> 8); + break; + default: + printf("Unknown event: %d!\n", type); + exit(3); + } - this_event = g_event_start.next; + this_event = g_event_start.next; - } + } - if(g_event_start.next == 0) { - halt_printf("ERROR...run_prog, event_start.n=0!\n"); - } + if(g_event_start.next == 0) { + halt_printf("ERROR...run_prog, event_start.n=0!\n"); + } #if 0 - if(!g_testing && g_event_start.next->rel_time > 2000000) { - printf("Z:start.next->rel_time: %d, duff_cycles: %d\n", - g_event_start.next->rel_time, duff_cycles); - halt_printf("Zrun_cycles:%d, cycles:%d\n", run_cycles, - cycles); + if(!g_testing && g_event_start.next->rel_time > 2000000) { + printf("Z:start.next->rel_time: %d, duff_cycles: %d\n", + g_event_start.next->rel_time, duff_cycles); + halt_printf("Zrun_cycles:%d, cycles:%d\n", run_cycles, + cycles); - show_all_events(); - } + show_all_events(); + } #endif - if(halt_sim != 0 && halt_sim != HALT_EVENT) { - break; - } - if(g_stepping) { - break; - } - } + if(halt_sim != 0 && halt_sim != HALT_EVENT) { + break; + } + if(g_stepping || g_dbg_step != 0) { + break; + } + } - if(!g_testing) { - printf("leaving run_prog, halt_sim:%d\n", halt_sim); - } + if(!g_testing) { + printf("leaving run_prog, halt_sim:%d\n", halt_sim); + } - x_auto_repeat_on(0); + x_auto_repeat_on(0); } -void -add_irq(word32 irq_mask) -{ - if(g_irq_pending & irq_mask) { - /* Already requested, just get out */ - return; - } - g_irq_pending |= irq_mask; - set_halt(HALT_EVENT); +void add_irq(word32 irq_mask) { + if(g_irq_pending & irq_mask) { + /* Already requested, just get out */ + return; + } + g_irq_pending |= irq_mask; + set_halt(HALT_EVENT); } -void -remove_irq(word32 irq_mask) -{ - g_irq_pending = g_irq_pending & (~irq_mask); +void remove_irq(word32 irq_mask) { + g_irq_pending = g_irq_pending & (~irq_mask); } -void -take_irq(int is_it_brk) -{ - word32 new_kpc; - word32 va; +void take_irq(int is_it_brk) { + word32 new_kpc; + word32 va; - irq_printf("Taking irq, at: %02x/%04x, psw: %02x, dcycs: %f\n", - engine.kpc>>16, engine.kpc & 0xffff, engine.psr, - g_cur_dcycs); + irq_printf("Taking irq, at: %02x/%04x, psw: %02x, dcycs: %f\n", + engine.kpc>>16, engine.kpc & 0xffff, engine.psr, + g_cur_dcycs); - g_num_irq++; - if(g_wait_pending) { - /* step over WAI instruction */ - engine.kpc++; - g_wait_pending = 0; - } + g_num_irq++; + if(g_wait_pending) { + /* step over WAI instruction */ + engine.kpc++; + g_wait_pending = 0; + } - if(engine.psr & 0x100) { - /* Emulation */ - set_memory_c(engine.stack, (engine.kpc >> 8) & 0xff, 0); - engine.stack = ((engine.stack -1) & 0xff) + 0x100; + if(engine.psr & 0x100) { + /* Emulation */ + set_memory_c(engine.stack, (engine.kpc >> 8) & 0xff, 0); + engine.stack = ((engine.stack -1) & 0xff) + 0x100; - set_memory_c(engine.stack, engine.kpc & 0xff, 0); - engine.stack = ((engine.stack -1) & 0xff) + 0x100; + set_memory_c(engine.stack, engine.kpc & 0xff, 0); + engine.stack = ((engine.stack -1) & 0xff) + 0x100; - set_memory_c(engine.stack, - (engine.psr & 0xef)|(is_it_brk<<4),0); - /* Clear B bit in psr on stack */ - engine.stack = ((engine.stack -1) & 0xff) + 0x100; + set_memory_c(engine.stack, + (engine.psr & 0xef)|(is_it_brk<<4),0); + /* Clear B bit in psr on stack */ + engine.stack = ((engine.stack -1) & 0xff) + 0x100; - va = 0xfffffe; - if(g_c035_shadow_reg & 0x40) { - /* I/O shadowing off...use ram locs */ - va = 0x00fffe; - } + va = 0xfffffe; + if(g_c035_shadow_reg & 0x40) { + /* I/O shadowing off...use ram locs */ + va = 0x00fffe; + } - } else { - /* native */ - set_memory_c(engine.stack, (engine.kpc >> 16) & 0xff, 0); - engine.stack = ((engine.stack -1) & 0xffff); + } else { + /* native */ + set_memory_c(engine.stack, (engine.kpc >> 16) & 0xff, 0); + engine.stack = ((engine.stack -1) & 0xffff); - set_memory_c(engine.stack, (engine.kpc >> 8) & 0xff, 0); - engine.stack = ((engine.stack -1) & 0xffff); + set_memory_c(engine.stack, (engine.kpc >> 8) & 0xff, 0); + engine.stack = ((engine.stack -1) & 0xffff); - set_memory_c(engine.stack, engine.kpc & 0xff, 0); - engine.stack = ((engine.stack -1) & 0xffff); + set_memory_c(engine.stack, engine.kpc & 0xff, 0); + engine.stack = ((engine.stack -1) & 0xffff); - set_memory_c(engine.stack, engine.psr & 0xff, 0); - engine.stack = ((engine.stack -1) & 0xffff); + set_memory_c(engine.stack, engine.psr & 0xff, 0); + engine.stack = ((engine.stack -1) & 0xffff); - if(is_it_brk) { - /* break */ - va = 0xffffe6; - if(g_c035_shadow_reg & 0x40) { - va = 0xffe6; - } - } else { - /* irq */ - va = 0xffffee; - if(g_c035_shadow_reg & 0x40) { - va = 0xffee; - } - } + if(is_it_brk) { + /* break */ + va = 0xffffe6; + if(g_c035_shadow_reg & 0x40) { + va = 0xffe6; + } + } else { + /* irq */ + va = 0xffffee; + if(g_c035_shadow_reg & 0x40) { + va = 0xffee; + } + } - } + } - new_kpc = get_memory_c(va, 0); - new_kpc = new_kpc + (get_memory_c(va+1, 0) << 8); + new_kpc = get_memory_c(va, 0); + new_kpc = new_kpc + (get_memory_c(va+1, 0) << 8); - engine.psr = ((engine.psr & 0x1f3) | 0x4); + engine.psr = ((engine.psr & 0x1f3) | 0x4); - engine.kpc = new_kpc; - HALT_ON(HALT_ON_IRQ, "Halting on IRQ\n"); + engine.kpc = new_kpc; + HALT_ON(HALT_ON_IRQ, "Halting on IRQ\n"); } -double g_dtime_last_vbl = 0.0; -double g_dtime_expected = (1.0/60.0); +double g_dtime_last_vbl = 0.0; +double g_dtime_expected = (1.0/60.0); int g_scan_int_events = 0; -void -show_dtime_array() -{ - double dfirst_time; - double first_total_cycs; - int i; - int pos; +void show_dtime_array() { + double dfirst_time; + double first_total_cycs; + int i; + int pos; - dfirst_time = 0.0; - first_total_cycs = 0.0; + dfirst_time = 0.0; + first_total_cycs = 0.0; - for(i = 0; i < 60; i++) { - pos = (g_vbl_index_count + i) % 60; - printf("%2d:%2d dt:%.5f adjc:%9.1f this_vbl:%.6f " - "exp:%.5f p:%2.2f ep:%2.2f\n", - i, pos, - dtime_array[pos] - dfirst_time, - g_dadjcycs_array[pos] - first_total_cycs, - g_dtime_this_vbl_array[pos], - g_dtime_exp_array[pos] - dfirst_time, - g_dtime_pmhz_array[pos], - g_dtime_eff_pmhz_array[pos]); - dfirst_time = dtime_array[pos]; - first_total_cycs = g_dadjcycs_array[pos]; - } + for(i = 0; i < 60; i++) { + pos = (g_vbl_index_count + i) % 60; + printf("%2d:%2d dt:%.5f adjc:%9.1f this_vbl:%.6f " + "exp:%.5f p:%2.2f ep:%2.2f\n", + i, pos, + dtime_array[pos] - dfirst_time, + g_dadjcycs_array[pos] - first_total_cycs, + g_dtime_this_vbl_array[pos], + g_dtime_exp_array[pos] - dfirst_time, + g_dtime_pmhz_array[pos], + g_dtime_eff_pmhz_array[pos]); + dfirst_time = dtime_array[pos]; + first_total_cycs = g_dadjcycs_array[pos]; + } } extern word32 g_cycs_in_40col; @@ -2027,602 +1867,653 @@ extern int g_a2vid_palette; extern int g_status_refresh_needed; +/* our main function that runs each 60Hz update cycle */ +void update_60hz(double dcycs, double dtime_now) { + register word32 end_time; + char status_buf[1024]; + char sim_mhz_buf[128]; + char total_mhz_buf[128]; + char *sim_mhz_ptr, *total_mhz_ptr; + char *code_str1, *code_str2, *sp_str; + double eff_pmhz; + double planned_dcycs; + double predicted_pmhz; + double recip_predicted_pmhz; + double dtime_this_vbl_sim; + double dtime_diff_1sec; + double dratio; + double dtime_till_expected; + double dtime_diff; + double dtime_this_vbl; + double dadjcycs_this_vbl; + double dadj_cycles_1sec; + double dtmp1, dtmp2, dtmp3, dtmp4, dtmp5; + double dnatcycs_1sec; + int tmp; + int doit_3_persec; + int cur_vbl_index; + int prev_vbl_index; -void -update_60hz(double dcycs, double dtime_now) -{ - register word32 end_time; - char status_buf[1024]; - char sim_mhz_buf[128]; - char total_mhz_buf[128]; - char *sim_mhz_ptr, *total_mhz_ptr; - char *code_str1, *code_str2, *sp_str; - double eff_pmhz; - double planned_dcycs; - double predicted_pmhz; - double recip_predicted_pmhz; - double dtime_this_vbl_sim; - double dtime_diff_1sec; - double dratio; - double dtime_till_expected; - double dtime_diff; - double dtime_this_vbl; - double dadjcycs_this_vbl; - double dadj_cycles_1sec; - double dtmp1, dtmp2, dtmp3, dtmp4, dtmp5; - double dnatcycs_1sec; - int tmp; - int doit_3_persec; - int cur_vbl_index; - int prev_vbl_index; + g_vbl_count++; - g_vbl_count++; + /* NOTE: this event is defined to occur before line 0 */ + /* It's actually happening at the start of the border for line (-1) */ + /* All other timings should be adjusted for this */ - /* NOTE: this event is defined to occur before line 0 */ - /* It's actually happening at the start of the border for line (-1) */ - /* All other timings should be adjusted for this */ + irq_printf("vbl_60hz: vbl: %d, dcycs: %f, last_vbl_dcycs: %f\n", + g_vbl_count, dcycs, g_last_vbl_dcycs); - irq_printf("vbl_60hz: vbl: %d, dcycs: %f, last_vbl_dcycs: %f\n", - g_vbl_count, dcycs, g_last_vbl_dcycs); + planned_dcycs = DCYCS_IN_16MS; - planned_dcycs = DCYCS_IN_16MS; + g_last_vbl_dcycs = g_last_vbl_dcycs + planned_dcycs; - g_last_vbl_dcycs = g_last_vbl_dcycs + planned_dcycs; + add_event_entry(g_last_vbl_dcycs + planned_dcycs, EV_60HZ); + check_for_one_event_type(EV_60HZ); - add_event_entry(g_last_vbl_dcycs + planned_dcycs, EV_60HZ); - check_for_one_event_type(EV_60HZ); + cur_vbl_index = g_vbl_index_count; - cur_vbl_index = g_vbl_index_count; + /* figure out dtime spent running SIM, not all the overhead */ + dtime_this_vbl_sim = g_cur_sim_dtime; + g_cur_sim_dtime = 0.0; + g_sim_sum = g_sim_sum - sim_time[cur_vbl_index] + dtime_this_vbl_sim; + sim_time[cur_vbl_index] = dtime_this_vbl_sim; - /* figure out dtime spent running SIM, not all the overhead */ - dtime_this_vbl_sim = g_cur_sim_dtime; - g_cur_sim_dtime = 0.0; - g_sim_sum = g_sim_sum - sim_time[cur_vbl_index] + dtime_this_vbl_sim; - sim_time[cur_vbl_index] = dtime_this_vbl_sim; + dadj_cycles_1sec = g_dadjcycs - g_dadjcycs_array[cur_vbl_index]; - dadj_cycles_1sec = g_dadjcycs - g_dadjcycs_array[cur_vbl_index]; + /* dtime_diff_1sec is dtime total spent over the last 60 ticks */ + dtime_diff_1sec = dtime_now - dtime_array[cur_vbl_index]; - /* dtime_diff_1sec is dtime total spent over the last 60 ticks */ - dtime_diff_1sec = dtime_now - dtime_array[cur_vbl_index]; + dtime_array[cur_vbl_index] = dtime_now; + g_dadjcycs_array[cur_vbl_index] = g_dadjcycs; - dtime_array[cur_vbl_index] = dtime_now; - g_dadjcycs_array[cur_vbl_index] = g_dadjcycs; + prev_vbl_index = cur_vbl_index; + cur_vbl_index = prev_vbl_index + 1; + if(cur_vbl_index >= 60) { + cur_vbl_index = 0; + } + g_vbl_index_count = cur_vbl_index; - prev_vbl_index = cur_vbl_index; - cur_vbl_index = prev_vbl_index + 1; - if(cur_vbl_index >= 60) { - cur_vbl_index = 0; - } - g_vbl_index_count = cur_vbl_index; + GET_ITIMER(end_time); + g_dnatcycs_1sec += (double)(end_time - g_natcycs_lastvbl); + g_natcycs_lastvbl = end_time; - GET_ITIMER(end_time); - g_dnatcycs_1sec += (double)(end_time - g_natcycs_lastvbl); - g_natcycs_lastvbl = end_time; + if(prev_vbl_index == 0) { + if(g_sim_sum < (1.0/250.0)) { + sim_mhz_ptr = "???"; + g_sim_mhz = 250.0; + } else { + g_sim_mhz = (dadj_cycles_1sec / g_sim_sum) / + (1000.0*1000.0); + sprintf(sim_mhz_buf, "%6.2f", g_sim_mhz); + sim_mhz_ptr = sim_mhz_buf; + } + if(dtime_diff_1sec < (1.0/250.0)) { + total_mhz_ptr = "???"; + } else { + sprintf(total_mhz_buf, "%6.2f", + (dadj_cycles_1sec / dtime_diff_1sec) / + (1000000.0)); + total_mhz_ptr = total_mhz_buf; + } - if(prev_vbl_index == 0) { - if(g_sim_sum < (1.0/250.0)) { - sim_mhz_ptr = "???"; - g_sim_mhz = 250.0; - } else { - g_sim_mhz = (dadj_cycles_1sec / g_sim_sum) / - (1000.0*1000.0); - sprintf(sim_mhz_buf, "%6.2f", g_sim_mhz); - sim_mhz_ptr = sim_mhz_buf; - } - if(dtime_diff_1sec < (1.0/250.0)) { - total_mhz_ptr = "???"; - } else { - sprintf(total_mhz_buf, "%6.2f", - (dadj_cycles_1sec / dtime_diff_1sec) / - (1000000.0)); - total_mhz_ptr = total_mhz_buf; - } + switch(g_limit_speed) { + case 1: sp_str = "1Mhz"; break; + case 2: sp_str = "2.8Mhz"; break; + case 3: sp_str = "8.0Mhz"; break; + default: sp_str = "Unlimited"; break; + } - switch(g_limit_speed) { - case 1: sp_str = "1Mhz"; break; - case 2: sp_str = "2.8Mhz"; break; - case 3: sp_str = "8.0Mhz"; break; - default: sp_str = "Unlimited"; break; - } +// OG Pass speed info to the control (ActiveX specific) +#ifdef ACTIVEGS + { + extern void updateInfo(const char* target,const char *speed); + updateInfo(sp_str,total_mhz_ptr); + } +#endif + sprintf(status_buf, "dcycs:%9.1f sim MHz:%s " + "Eff MHz:%s, sec:%1.3f vol:%02x pal:%x, Limit:%s", + dcycs/(1000.0*1000.0), sim_mhz_ptr, total_mhz_ptr, + dtime_diff_1sec, g_doc_vol, g_a2vid_palette, + sp_str); + video_update_status_line(0, status_buf); -// OG Pass speed info to the control (ActiveX specific) -#ifdef ACTIVEGS - { - extern void updateInfo(const char* target,const char *speed); - updateInfo(sp_str,total_mhz_ptr); - } -#endif - sprintf(status_buf, "dcycs:%9.1f sim MHz:%s " - "Eff MHz:%s, sec:%1.3f vol:%02x pal:%x, Limit:%s", - dcycs/(1000.0*1000.0), sim_mhz_ptr, total_mhz_ptr, - dtime_diff_1sec, g_doc_vol, g_a2vid_palette, - sp_str); - video_update_status_line(0, status_buf); + if(g_video_line_update_interval == 0) { + if(g_sim_mhz > 12.0) { + /* just set video line_ref_amt to 1 */ + g_line_ref_amt = 1; + } else if(g_line_ref_amt == 1 && g_sim_mhz < 4.0) { + g_line_ref_amt = 8; + } + } else { + g_line_ref_amt = g_video_line_update_interval; + } - if(g_video_line_update_interval == 0) { - if(g_sim_mhz > 12.0) { - /* just set video line_ref_amt to 1 */ - g_line_ref_amt = 1; - } else if(g_line_ref_amt == 1 && g_sim_mhz < 4.0) { - g_line_ref_amt = 8; + if(g_dnatcycs_1sec < (1000.0*1000.0)) { + /* make it so large that all %'s become 0 */ + g_dnatcycs_1sec = 800.0*1000.0*1000.0*1000.0; + } + dnatcycs_1sec = g_dnatcycs_1sec / 100.0; /* eff mult by 100 */ + + dtmp2 = (double)(g_cycs_in_check_input) / dnatcycs_1sec; + dtmp3 = (double)(g_cycs_in_refresh_line) / dnatcycs_1sec; + dtmp4 = (double)(g_cycs_in_refresh_ximage) / dnatcycs_1sec; + sprintf(status_buf, "xfer:%08x, %5.1f ref_amt:%d " + "ch_in:%4.1f%% ref_l:%4.1f%% ref_x:%4.1f%%", + g_refresh_bytes_xfer, g_dnatcycs_1sec/(1000.0*1000.0), + g_line_ref_amt, dtmp2, dtmp3, dtmp4); + video_update_status_line(1, status_buf); + + sprintf(status_buf, "Ints:%3d I/O:%4dK BRK:%3d COP:%2d " + "Eng:%3d act:%3d hev:%3d esi:%3d edi:%3d", + g_num_irq, g_io_amt>>10, g_num_brk, g_num_cop, + g_num_enter_engine, g_engine_action, + g_engine_halt_event, g_engine_scan_int, + g_engine_doc_int); + video_update_status_line(2, status_buf); + + dtmp1 = (double)(g_cycs_in_sound1) / dnatcycs_1sec; + dtmp2 = (double)(g_cycs_in_sound2) / dnatcycs_1sec; + dtmp3 = (double)(g_cycs_in_sound3) / dnatcycs_1sec; + dtmp4 = (double)(g_cycs_in_start_sound) / dnatcycs_1sec; + dtmp5 = (double)(g_cycs_in_est_sound) / dnatcycs_1sec; + sprintf(status_buf, "snd1:%4.1f%%, 2:%4.1f%%, " + "3:%4.1f%%, st:%4.1f%% est:%4.1f%% %4.2f", + dtmp1, dtmp2, dtmp3, dtmp4, dtmp5, g_fvoices); + video_update_status_line(3, status_buf); + + code_str1 = ""; + code_str2 = ""; + if(g_code_yellow) { + code_str1 = "Code: Yellow"; + code_str2 = "Emulated system state suspect, save work"; + } + if(g_code_red) { + code_str1 = "Code: RED"; + code_str2 = "Emulated system state probably corrupt"; + } + sprintf(status_buf, "snd_plays:%4d, doc_ev:%4d, st_snd:%4d " + "snd_parms: %4d %s", + g_num_snd_plays, g_num_doc_events, g_num_start_sounds, + g_num_recalc_snd_parms, code_str1); + video_update_status_line(4, status_buf); + + draw_iwm_status(5, status_buf); + + sprintf(status_buf, "GSport v%-6s " + "Press F4 for Config Menu %s", + g_gsport_version_str, code_str2); + video_update_status_line(6, status_buf); + + g_status_refresh_needed = 1; + + g_num_irq = 0; + g_num_brk = 0; + g_num_cop = 0; + g_num_enter_engine = 0; + g_io_amt = 0; + g_engine_action = 0; + g_engine_halt_event = 0; + g_engine_scan_int = 0; + g_engine_doc_int = 0; + + g_cycs_in_40col = 0; + g_cycs_in_xredraw = 0; + g_cycs_in_check_input = 0; + g_cycs_in_refresh_line = 0; + g_cycs_in_refresh_ximage = 0; + g_cycs_in_io_read = 0; + g_cycs_in_sound1 = 0; + g_cycs_in_sound2 = 0; + g_cycs_in_sound3 = 0; + g_cycs_in_sound4 = 0; + g_cycs_in_start_sound = 0; + g_cycs_in_est_sound = 0; + g_dnatcycs_1sec = 0.0; + g_refresh_bytes_xfer = 0; + + g_num_snd_plays = 0; + g_num_doc_events = 0; + g_num_start_sounds = 0; + g_num_scan_osc = 0; + g_num_recalc_snd_parms = 0; + + g_fvoices = (float)0.0; + } + + dtime_this_vbl = dtime_now - g_dtime_last_vbl; + if(dtime_this_vbl < 0.001) { + dtime_this_vbl = 0.001; + } + + g_dtime_last_vbl = dtime_now; + + dadjcycs_this_vbl = g_dadjcycs - g_last_vbl_dadjcycs; + g_last_vbl_dadjcycs = g_dadjcycs; + + g_dtime_expected += (1.0/60.0); + + eff_pmhz = ((dadjcycs_this_vbl) / (dtime_this_vbl)) / + DCYCS_1_MHZ; + + /* using eff_pmhz, predict how many cycles can be run by */ + /* g_dtime_expected */ + + dtime_till_expected = g_dtime_expected - dtime_now; + + dratio = 60.0 * dtime_till_expected; + + predicted_pmhz = eff_pmhz * dratio; + + if(!(predicted_pmhz < (1.4 * g_projected_pmhz))) { + predicted_pmhz = 1.4 * g_projected_pmhz; + } + + if(!(predicted_pmhz > (0.7 * g_projected_pmhz))) { + predicted_pmhz = 0.7 * g_projected_pmhz; + } + + if(!(predicted_pmhz >= 1.0)) { + irq_printf("predicted: %f, setting to 1.0\n", predicted_pmhz); + predicted_pmhz = 1.0; + } + + if(!(predicted_pmhz < 250.0)) { + irq_printf("predicted: %f, setting to 250.0\n", predicted_pmhz); + predicted_pmhz = 250.0; + } + + recip_predicted_pmhz = 1.0/predicted_pmhz; + g_projected_pmhz = predicted_pmhz; + + g_recip_projected_pmhz_unl.plus_1 = 1.0*recip_predicted_pmhz; + g_recip_projected_pmhz_unl.plus_2 = 2.0*recip_predicted_pmhz; + g_recip_projected_pmhz_unl.plus_3 = 3.0*recip_predicted_pmhz; + g_recip_projected_pmhz_unl.plus_x_minus_1 = 1.01 - recip_predicted_pmhz; + + if(dtime_till_expected < -0.125) { + /* If we were way off, get back on track */ + /* this happens because our sim took much longer than */ + /* expected, so we're going to skip some VBL */ + irq_printf("adj1: dtexp:%f, dt_new:%f\n", + g_dtime_expected, dtime_now); + + dtime_diff = -dtime_till_expected; + + irq_printf("dtime_till_exp: %f, dtime_diff: %f, dcycs: %f\n", + dtime_till_expected, dtime_diff, dcycs); + + g_dtime_expected += dtime_diff; + } + + if(dtime_till_expected > (3/60.0)) { + /* we're running fast, usleep */ + micro_sleep(dtime_till_expected - (1/60.0)); + } + + g_dtime_this_vbl_array[prev_vbl_index] = dtime_this_vbl; + g_dtime_exp_array[prev_vbl_index] = g_dtime_expected; + g_dtime_pmhz_array[prev_vbl_index] = predicted_pmhz; + g_dtime_eff_pmhz_array[prev_vbl_index] = eff_pmhz; + + if(g_c041_val & C041_EN_VBL_INTS) { + add_event_vbl(); + } + + g_25sec_cntr++; + if(g_25sec_cntr >= 16) { + g_25sec_cntr = 0; + if(g_c041_val & C041_EN_25SEC_INTS) { + add_irq(IRQ_PENDING_C046_25SEC); + g_c046_val |= 0x10; + irq_printf("Setting c046 .25 sec int, g_irq_pend:%d\n", + g_irq_pending); + } + } + + g_1sec_cntr++; + if(g_1sec_cntr >= 60) { + g_1sec_cntr = 0; + tmp = g_c023_val; + tmp |= 0x40; /* set 1sec int */ + if(tmp & 0x04) { + tmp |= 0x80; + add_irq(IRQ_PENDING_C023_1SEC); + irq_printf("Setting c023 to %02x irq_pend: %d\n", + tmp, g_irq_pending); + } + g_c023_val = tmp; + } + + if(!g_scan_int_events) { + check_scan_line_int(dcycs, 0); + } + + doit_3_persec = 0; + if(g_config_iwm_vbl_count > 0) { + g_config_iwm_vbl_count--; + } else { + g_config_iwm_vbl_count = 20; + doit_3_persec = 1; + } + + iwm_vbl_update(doit_3_persec); + +// OG Disabling config update +#ifndef ACTIVEGS + config_vbl_update(doit_3_persec); +#else +// OG Added disk update + { + extern void checkImages(); + checkImages(); + } +#endif + + video_update(); + sound_update(dcycs); + clock_update(); + scc_update(dcycs); + //Check and see if virtual printer timeout has been reached. + if (g_printer_timeout) + { + printer_update(); + } + if (g_imagewriter_timeout) + { + imagewriter_update(); + } + paddle_update_buttons(); +} + +void do_vbl_int() { + if(g_c041_val & C041_EN_VBL_INTS) { + g_c046_val |= 0x08; + add_irq(IRQ_PENDING_C046_VBL); + irq_printf("Setting c046 vbl_int_status to 1, irq_pend: %d\n", + g_irq_pending); + } +} + + +void do_scan_int(double dcycs, int line) { + int c023_val; + g_scan_int_events = 0; + + c023_val = g_c023_val; + if(c023_val & 0x20) { + halt_printf("c023 scan_int and another on line %03x\n", line); + } + + /* make sure scan int is still enabled for this line */ + if((g_slow_memory_ptr[0x19d00 + line] & 0x40) && + (g_cur_a2_stat & ALL_STAT_SUPER_HIRES)) { + /* valid interrupt, do it */ + c023_val |= 0xa0; /* vgc_int and scan_int */ + if(c023_val & 0x02) { + add_irq(IRQ_PENDING_C023_SCAN); + irq_printf("Setting c023 to %02x, irq_pend: %d\n", + c023_val, g_irq_pending); + } + g_c023_val = c023_val; + HALT_ON(HALT_ON_SCAN_INT, "In do_scan_int\n"); + } else { + /* scan int bit cleared on scan line control byte */ + /* look for next line, if any */ + check_scan_line_int(dcycs, line+1); + } +} + +void check_scan_line_int(double dcycs, int cur_video_line) { + int delay; + int start; + int line; + int i; + /* Called during VBL interrupt phase */ + + if(!(g_cur_a2_stat & ALL_STAT_SUPER_HIRES)) { + return; + } + + if(g_c023_val & 0x20) { + /* don't check for any more */ + return; + } + + start = cur_video_line; + if(start < 0) { + halt_printf("check_scan_line_int: cur_video_line: %d\n", + cur_video_line); + start = 0; + } + + for(line = start; line < 200; line++) { + i = line; + + if(i < 0 || i >= 200) { + halt_printf("check_new_scan_int:i:%d, line:%d, st:%d\n", + i, line, start); + i = 0; + } + if(g_slow_memory_ptr[0x19d00+i] & 0x40) { + irq_printf("Adding scan_int for line %d\n", i); + delay = (int)( (DCYCS_IN_16MS/262.0) * ((double)line) ); + add_event_entry(g_last_vbl_dcycs + delay, EV_SCAN_INT + + (line << 8)); + g_scan_int_events = 1; + check_for_one_event_type(EV_SCAN_INT); + break; + } + } +} + +void check_for_new_scan_int(double dcycs) { + int cur_video_line; + + cur_video_line = get_lines_since_vbl(dcycs) >> 8; + + check_scan_line_int(dcycs, cur_video_line); +} + +void init_reg() { + engine.acc = 0; + engine.xreg = 0; + engine.yreg = 0; + engine.stack = 0x1ff; + engine.direct = 0; + engine.psr = 0x134; + engine.fplus_ptr = 0; + +} + + +void handle_action(word32 ret) { + int type; + + type = EXTRU(ret,3,4); + switch(type) { + case RET_BREAK: + do_break(ret & 0xff); + break; + case RET_COP: + do_cop(ret & 0xff); + break; +#if 0 + case RET_MVN: + do_mvn(ret & 0xffff); + break; +#endif + case RET_C700: + do_c700(ret); + break; + case RET_C70A: + do_c70a(ret); + break; + case RET_C70D: + do_c70d(ret); + break; +#if 0 + case RET_ADD_DEC_8: + do_add_dec_8(ret); + break; + case RET_ADD_DEC_16: + do_add_dec_16(ret); + break; +#endif + case RET_IRQ: + irq_printf("Special fast IRQ response. irq_pending: %x\n", + g_irq_pending); + break; + case RET_WDM: + do_wdm(ret & 0xff); + break; + case RET_STP: + do_stp(); + break; + default: + halt_printf("Unknown special action: %08x!\n", ret); + } + +} + +#if 0 +void do_add_dec_8(word32 ret) { + halt_printf("do_add_dec_8 called, ret: %08x\n", ret); +} + +void do_add_dec_16(word32 ret) { + halt_printf("do_add_dec_16 called, ret: %08x\n", ret); +} +#endif + +void do_break(word32 ret) { + if(!g_testing) { + printf("I think I got a break, second byte: %02x!\n", ret); + printf("kpc: %06x\n", engine.kpc); + } + + halt_printf("do_break, kpc: %06x\n", engine.kpc); + enter_debug = 1; +} + +void do_cop(word32 ret) { + halt_printf("COP instr %02x!\n", ret); + fflush(stdout); +} + +#if 0 +void do_mvn(word32 banks) { + int src_bank, dest_bank; + int dest, src; + int num; + int i; + int val; + + halt_printf("In MVN...just quitting\n"); + return; + printf("MVN instr with %04x, cycles: %08x\n", banks, engine.cycles); + src_bank = banks >> 8; + dest_bank = banks & 0xff; + printf("psr: %03x\n", engine.psr); + if((engine.psr & 0x30) != 0) { + halt_printf("MVN in non-native mode unimplemented!\n"); + } + + dest = dest_bank << 16 | engine.yreg; + src = src_bank << 16 | engine.xreg; + num = engine.acc; + printf("Moving %08x+1 bytes from %08x to %08x\n", num, src, dest); + + for(i = 0; i <= num; i++) { + val = get_memory_c(src, 0); + set_memory_c(dest, val, 0); + src = (src_bank << 16) | ((src + 1) & 0xffff); + dest = (dest_bank << 16) | ((dest + 1) & 0xffff); + } + engine.dbank = dest_bank; + engine.acc = 0xffff; + engine.yreg = dest & 0xffff; + engine.xreg = src & 0xffff; + engine.kpc = (engine.kpc + 3); + printf("move done. db: %02x, acc: %04x, y: %04x, x: %04x, num: %08x\n", + engine.dbank, engine.acc, engine.yreg, engine.xreg, num); +} +#endif + +extern void host_fst(void); + +static void wdm_print() { + /* x:y is ptr to cstring to print, a is type of string */ + /* 0 = cstring, 1 = pstring, 2 = gsosstring, $8000 is add \n */ + + word32 address = engine.xreg + (engine.yreg << 16); + word16 type = engine.acc; + char c; + int length; + + if (address) switch (type & 0xff){ + case 0: + while ((c = get_memory_c(address++, 0))) { + fputc(c, stdout); } - } else { - g_line_ref_amt = g_video_line_update_interval; - } - - if(g_dnatcycs_1sec < (1000.0*1000.0)) { - /* make it so large that all %'s become 0 */ - g_dnatcycs_1sec = 800.0*1000.0*1000.0*1000.0; - } - dnatcycs_1sec = g_dnatcycs_1sec / 100.0; /* eff mult by 100 */ - - dtmp2 = (double)(g_cycs_in_check_input) / dnatcycs_1sec; - dtmp3 = (double)(g_cycs_in_refresh_line) / dnatcycs_1sec; - dtmp4 = (double)(g_cycs_in_refresh_ximage) / dnatcycs_1sec; - sprintf(status_buf, "xfer:%08x, %5.1f ref_amt:%d " - "ch_in:%4.1f%% ref_l:%4.1f%% ref_x:%4.1f%%", - g_refresh_bytes_xfer, g_dnatcycs_1sec/(1000.0*1000.0), - g_line_ref_amt, dtmp2, dtmp3, dtmp4); - video_update_status_line(1, status_buf); - - sprintf(status_buf, "Ints:%3d I/O:%4dK BRK:%3d COP:%2d " - "Eng:%3d act:%3d hev:%3d esi:%3d edi:%3d", - g_num_irq, g_io_amt>>10, g_num_brk, g_num_cop, - g_num_enter_engine, g_engine_action, - g_engine_halt_event, g_engine_scan_int, - g_engine_doc_int); - video_update_status_line(2, status_buf); - - dtmp1 = (double)(g_cycs_in_sound1) / dnatcycs_1sec; - dtmp2 = (double)(g_cycs_in_sound2) / dnatcycs_1sec; - dtmp3 = (double)(g_cycs_in_sound3) / dnatcycs_1sec; - dtmp4 = (double)(g_cycs_in_start_sound) / dnatcycs_1sec; - dtmp5 = (double)(g_cycs_in_est_sound) / dnatcycs_1sec; - sprintf(status_buf, "snd1:%4.1f%%, 2:%4.1f%%, " - "3:%4.1f%%, st:%4.1f%% est:%4.1f%% %4.2f", - dtmp1, dtmp2, dtmp3, dtmp4, dtmp5, g_fvoices); - video_update_status_line(3, status_buf); - - code_str1 = ""; - code_str2 = ""; - if(g_code_yellow) { - code_str1 = "Code: Yellow"; - code_str2 = "Emulated system state suspect, save work"; - } - if(g_code_red) { - code_str1 = "Code: RED"; - code_str2 = "Emulated system state probably corrupt"; - } - sprintf(status_buf, "snd_plays:%4d, doc_ev:%4d, st_snd:%4d " - "snd_parms: %4d %s", - g_num_snd_plays, g_num_doc_events, g_num_start_sounds, - g_num_recalc_snd_parms, code_str1); - video_update_status_line(4, status_buf); - - draw_iwm_status(5, status_buf); - - sprintf(status_buf, "GSport v%-6s " - "Press F4 for Config Menu %s", - g_gsport_version_str, code_str2); - video_update_status_line(6, status_buf); - - g_status_refresh_needed = 1; - - g_num_irq = 0; - g_num_brk = 0; - g_num_cop = 0; - g_num_enter_engine = 0; - g_io_amt = 0; - g_engine_action = 0; - g_engine_halt_event = 0; - g_engine_scan_int = 0; - g_engine_doc_int = 0; - - g_cycs_in_40col = 0; - g_cycs_in_xredraw = 0; - g_cycs_in_check_input = 0; - g_cycs_in_refresh_line = 0; - g_cycs_in_refresh_ximage = 0; - g_cycs_in_io_read = 0; - g_cycs_in_sound1 = 0; - g_cycs_in_sound2 = 0; - g_cycs_in_sound3 = 0; - g_cycs_in_sound4 = 0; - g_cycs_in_start_sound = 0; - g_cycs_in_est_sound = 0; - g_dnatcycs_1sec = 0.0; - g_refresh_bytes_xfer = 0; - - g_num_snd_plays = 0; - g_num_doc_events = 0; - g_num_start_sounds = 0; - g_num_scan_osc = 0; - g_num_recalc_snd_parms = 0; - - g_fvoices = (float)0.0; - } - - dtime_this_vbl = dtime_now - g_dtime_last_vbl; - if(dtime_this_vbl < 0.001) { - dtime_this_vbl = 0.001; - } - - g_dtime_last_vbl = dtime_now; - - dadjcycs_this_vbl = g_dadjcycs - g_last_vbl_dadjcycs; - g_last_vbl_dadjcycs = g_dadjcycs; - - g_dtime_expected += (1.0/60.0); - - eff_pmhz = ((dadjcycs_this_vbl) / (dtime_this_vbl)) / - DCYCS_1_MHZ; - - /* using eff_pmhz, predict how many cycles can be run by */ - /* g_dtime_expected */ - - dtime_till_expected = g_dtime_expected - dtime_now; - - dratio = 60.0 * dtime_till_expected; - - predicted_pmhz = eff_pmhz * dratio; - - if(! (predicted_pmhz < (1.4 * g_projected_pmhz))) { - predicted_pmhz = 1.4 * g_projected_pmhz; - } - - if(! (predicted_pmhz > (0.7 * g_projected_pmhz))) { - predicted_pmhz = 0.7 * g_projected_pmhz; - } - - if(!(predicted_pmhz >= 1.0)) { - irq_printf("predicted: %f, setting to 1.0\n", predicted_pmhz); - predicted_pmhz = 1.0; - } - - if(!(predicted_pmhz < 250.0)) { - irq_printf("predicted: %f, setting to 250.0\n", predicted_pmhz); - predicted_pmhz = 250.0; - } - - recip_predicted_pmhz = 1.0/predicted_pmhz; - g_projected_pmhz = predicted_pmhz; - - g_recip_projected_pmhz_unl.plus_1 = 1.0*recip_predicted_pmhz; - g_recip_projected_pmhz_unl.plus_2 = 2.0*recip_predicted_pmhz; - g_recip_projected_pmhz_unl.plus_3 = 3.0*recip_predicted_pmhz; - g_recip_projected_pmhz_unl.plus_x_minus_1 = 1.01 - recip_predicted_pmhz; - - if(dtime_till_expected < -0.125) { - /* If we were way off, get back on track */ - /* this happens because our sim took much longer than */ - /* expected, so we're going to skip some VBL */ - irq_printf("adj1: dtexp:%f, dt_new:%f\n", - g_dtime_expected, dtime_now); - - dtime_diff = -dtime_till_expected; - - irq_printf("dtime_till_exp: %f, dtime_diff: %f, dcycs: %f\n", - dtime_till_expected, dtime_diff, dcycs); - - g_dtime_expected += dtime_diff; - } - - if(dtime_till_expected > (3/60.0)) { - /* we're running fast, usleep */ - micro_sleep(dtime_till_expected - (1/60.0)); - } - - g_dtime_this_vbl_array[prev_vbl_index] = dtime_this_vbl; - g_dtime_exp_array[prev_vbl_index] = g_dtime_expected; - g_dtime_pmhz_array[prev_vbl_index] = predicted_pmhz; - g_dtime_eff_pmhz_array[prev_vbl_index] = eff_pmhz; - - - if(g_c041_val & C041_EN_VBL_INTS) { - add_event_vbl(); - } - - g_25sec_cntr++; - if(g_25sec_cntr >= 16) { - g_25sec_cntr = 0; - if(g_c041_val & C041_EN_25SEC_INTS) { - add_irq(IRQ_PENDING_C046_25SEC); - g_c046_val |= 0x10; - irq_printf("Setting c046 .25 sec int, g_irq_pend:%d\n", - g_irq_pending); - } - } - - g_1sec_cntr++; - if(g_1sec_cntr >= 60) { - g_1sec_cntr = 0; - tmp = g_c023_val; - tmp |= 0x40; /* set 1sec int */ - if(tmp & 0x04) { - tmp |= 0x80; - add_irq(IRQ_PENDING_C023_1SEC); - irq_printf("Setting c023 to %02x irq_pend: %d\n", - tmp, g_irq_pending); - } - g_c023_val = tmp; - } - - if(!g_scan_int_events) { - check_scan_line_int(dcycs, 0); - } - - doit_3_persec = 0; - if(g_config_iwm_vbl_count > 0) { - g_config_iwm_vbl_count--; - } else { - g_config_iwm_vbl_count = 20; - doit_3_persec = 1; - } - - iwm_vbl_update(doit_3_persec); - -// OG Disabling config update -#ifndef ACTIVEGS - config_vbl_update(doit_3_persec); -#else -// OG Added disk update - { - extern void checkImages(); - checkImages(); - } -#endif - - video_update(); - sound_update(dcycs); - clock_update(); - scc_update(dcycs); - //Check and see if virtual printer timeout has been reached. - if (g_printer_timeout) - { - printer_update(); - } - if (g_imagewriter_timeout) - { - imagewriter_update(); - } - paddle_update_buttons(); -} - -void -do_vbl_int() -{ - if(g_c041_val & C041_EN_VBL_INTS) { - g_c046_val |= 0x08; - add_irq(IRQ_PENDING_C046_VBL); - irq_printf("Setting c046 vbl_int_status to 1, irq_pend: %d\n", - g_irq_pending); - } -} - - -void -do_scan_int(double dcycs, int line) -{ - int c023_val; - g_scan_int_events = 0; - - c023_val = g_c023_val; - if(c023_val & 0x20) { - halt_printf("c023 scan_int and another on line %03x\n", line); - } - - /* make sure scan int is still enabled for this line */ - if((g_slow_memory_ptr[0x19d00 + line] & 0x40) && - (g_cur_a2_stat & ALL_STAT_SUPER_HIRES)) { - /* valid interrupt, do it */ - c023_val |= 0xa0; /* vgc_int and scan_int */ - if(c023_val & 0x02) { - add_irq(IRQ_PENDING_C023_SCAN); - irq_printf("Setting c023 to %02x, irq_pend: %d\n", - c023_val, g_irq_pending); - } - g_c023_val = c023_val; - HALT_ON(HALT_ON_SCAN_INT, "In do_scan_int\n"); - } else { - /* scan int bit cleared on scan line control byte */ - /* look for next line, if any */ - check_scan_line_int(dcycs, line+1); - } -} - -void -check_scan_line_int(double dcycs, int cur_video_line) -{ - int delay; - int start; - int line; - int i; - /* Called during VBL interrupt phase */ - - if(!(g_cur_a2_stat & ALL_STAT_SUPER_HIRES)) { - return; - } - - if(g_c023_val & 0x20) { - /* don't check for any more */ - return; - } - - start = cur_video_line; - if(start < 0) { - halt_printf("check_scan_line_int: cur_video_line: %d\n", - cur_video_line); - start = 0; - } - - for(line = start; line < 200; line++) { - i = line; - - if(i < 0 || i >= 200) { - halt_printf("check_new_scan_int:i:%d, line:%d, st:%d\n", - i, line, start); - i = 0; - } - if(g_slow_memory_ptr[0x19d00+i] & 0x40) { - irq_printf("Adding scan_int for line %d\n", i); - delay = (int)( (DCYCS_IN_16MS/262.0) * ((double)line) ); - add_event_entry(g_last_vbl_dcycs + delay, EV_SCAN_INT + - (line << 8)); - g_scan_int_events = 1; - check_for_one_event_type(EV_SCAN_INT); break; + + case 1: + length = get_memory_c(address++, 0); + while (length--) { + c = get_memory_c(address++, 0); + fputc(c, stdout); + } + break; + + case 2: + length = get_memory16_c(address, 0); + address += 2; + while (length--) { + c = get_memory_c(address++, 0); + fputc(c, stdout); + } + break; + } + if (type & 0x8000) fputc('\n', stdout); +} + +static void wdm_hexdump() { + /* x:y is ptr to memory, a is length */ + word32 count = engine.acc; + word32 address = engine.xreg + (engine.yreg << 16); + if (address && count) { + + static char hex[] = "0123456789abcdef"; + char buffer1[16*3+1]; + char buffer2[16+1]; + byte b; + int i, j; + while (count) { + + memset(buffer1, ' ', sizeof(buffer1)-1); + memset(buffer2, ' ', sizeof(buffer2)-1); + buffer1[48] = 0; + buffer2[16] = 0; + + int xx = 16; + if (count < 16) xx = count; + for (i = 0, j = 0; i < xx; ++i) { + b = get_memory_c(address + i, 0); + buffer1[j++] = hex[b >> 4]; + buffer1[j++] = hex[b & 0x0f]; + buffer1[j++] = ' '; + b &= 0x7f; /* support high ascii */ + buffer2[i] = isprint(b) ? b : '.'; + + } + printf("%06x %s%s\n", address, buffer1, buffer2); + count -= xx; + address += xx; } } } - -void -check_for_new_scan_int(double dcycs) -{ - int cur_video_line; - - cur_video_line = get_lines_since_vbl(dcycs) >> 8; - - check_scan_line_int(dcycs, cur_video_line); -} - -void -init_reg() -{ - engine.acc = 0; - engine.xreg = 0; - engine.yreg = 0; - engine.stack = 0x1ff; - engine.direct = 0; - engine.psr = 0x134; - engine.fplus_ptr = 0; - -} - - -void -handle_action(word32 ret) -{ - int type; - - type = EXTRU(ret,3,4); - switch(type) { - case RET_BREAK: - do_break(ret & 0xff); - break; - case RET_COP: - do_cop(ret & 0xff); - break; -#if 0 - case RET_MVN: - do_mvn(ret & 0xffff); - break; -#endif - case RET_C700: - do_c700(ret); - break; - case RET_C70A: - do_c70a(ret); - break; - case RET_C70D: - do_c70d(ret); - break; -#if 0 - case RET_ADD_DEC_8: - do_add_dec_8(ret); - break; - case RET_ADD_DEC_16: - do_add_dec_16(ret); - break; -#endif - case RET_IRQ: - irq_printf("Special fast IRQ response. irq_pending: %x\n", - g_irq_pending); - break; - case RET_WDM: - do_wdm(ret & 0xff); - break; - case RET_STP: - do_stp(); - break; - default: - halt_printf("Unknown special action: %08x!\n", ret); - } - -} - -#if 0 -void -do_add_dec_8(word32 ret) -{ - halt_printf("do_add_dec_8 called, ret: %08x\n", ret); -} - -void -do_add_dec_16(word32 ret) -{ - halt_printf("do_add_dec_16 called, ret: %08x\n", ret); -} -#endif - -void -do_break(word32 ret) -{ - if(!g_testing) { - printf("I think I got a break, second byte: %02x!\n", ret); - printf("kpc: %06x\n", engine.kpc); - } - - halt_printf("do_break, kpc: %06x\n", engine.kpc); - enter_debug = 1; -} - -void -do_cop(word32 ret) -{ - halt_printf("COP instr %02x!\n", ret); - fflush(stdout); -} - -#if 0 -void -do_mvn(word32 banks) -{ - int src_bank, dest_bank; - int dest, src; - int num; - int i; - int val; - - halt_printf("In MVN...just quitting\n"); - return; - printf("MVN instr with %04x, cycles: %08x\n", banks, engine.cycles); - src_bank = banks >> 8; - dest_bank = banks & 0xff; - printf("psr: %03x\n", engine.psr); - if((engine.psr & 0x30) != 0) { - halt_printf("MVN in non-native mode unimplemented!\n"); - } - - dest = dest_bank << 16 | engine.yreg; - src = src_bank << 16 | engine.xreg; - num = engine.acc; - printf("Moving %08x+1 bytes from %08x to %08x\n", num, src, dest); - - for(i = 0; i <= num; i++) { - val = get_memory_c(src, 0); - set_memory_c(dest, val, 0); - src = (src_bank << 16) | ((src + 1) & 0xffff); - dest = (dest_bank << 16) | ((dest + 1) & 0xffff); - } - engine.dbank = dest_bank; - engine.acc = 0xffff; - engine.yreg = dest & 0xffff; - engine.xreg = src & 0xffff; - engine.kpc = (engine.kpc + 3); - printf("move done. db: %02x, acc: %04x, y: %04x, x: %04x, num: %08x\n", - engine.dbank, engine.acc, engine.yreg, engine.xreg, num); -} -#endif +extern void host_mli_head(void); +extern void host_mli_tail(void); void do_wdm(word32 arg) @@ -2630,118 +2521,129 @@ do_wdm(word32 arg) switch(arg) { case 0x8d: /* Bouncin Ferno does WDM 8d */ break; - default: - halt_printf("do_wdm: %02x!\n", arg); - } + + + /* 0xAx range can be used for debugging, etc */ + + case 0xa0: /* print */ + wdm_print(); + break; + + case 0xa1: /* hexdump */ + wdm_hexdump(); + break; + + + /* 0xFx shouldn't be called unless you know what you're doing */ + + case 0xfc: /* mli head patch */ + host_mli_head(); + break; + + case 0xfd: /* mli tail patch */ + host_mli_tail(); + break; + + case 0xfe: /* used for ModemWorks branch */ + break; + + case 0xff: /* fst */ + host_fst(); + break; + + default: + halt_printf("do_wdm: %02x! pc = $%06x\n", arg, engine.kpc - 2); + } } -void -do_wai() -{ - halt_printf("do_wai!\n"); +void do_wai() { + halt_printf("do_wai!\n"); } -void -do_stp() -{ - if(!g_stp_pending) { - g_stp_pending = 1; - halt_printf("Hit STP instruction at: %06x, press RESET to " - "continue\n", engine.kpc); - } +void do_stp() { + if(!g_stp_pending) { + g_stp_pending = 1; + halt_printf("Hit STP instruction at: %06x, press RESET to " + "continue\n", engine.kpc); + } } -void -size_fail(int val, word32 v1, word32 v2) -{ - halt_printf("Size failure, val: %08x, %08x %08x\n", val, v1, v2); +void size_fail(int val, word32 v1, word32 v2) { + halt_printf("Size failure, val: %08x, %08x %08x\n", val, v1, v2); } -int -fatal_printf(const char *fmt, ...) -{ - va_list ap; - int ret; +int gsport_vprintf(const char *fmt, va_list ap) { + char *bufptr, *buf2ptr; + int len; + int ret; - va_start(ap, fmt); + bufptr = (char*)malloc(4096); // OG Added Cast + ret = vsnprintf(bufptr, 4090, fmt, ap); - if(g_fatal_log < 0) { - g_fatal_log = 0; - } - ret = gsport_vprintf(fmt, ap); - va_end(ap); + // OG Display warning + printf("Warning:%s",bufptr); - return ret; + len = strlen(bufptr); + if(g_fatal_log >= 0 && g_fatal_log < MAX_FATAL_LOGS) { + buf2ptr = (char*)malloc(len+1); // OG Added Cast + memcpy(buf2ptr, bufptr, len+1); + g_fatal_log_strs[g_fatal_log++] = buf2ptr; + } + must_write(1, bufptr, len); + if(g_debug_file_fd >= 0) { + must_write(g_debug_file_fd, bufptr, len); + } + free(bufptr); + + return ret; } -int -gsport_vprintf(const char *fmt, va_list ap) -{ - char *bufptr, *buf2ptr; - int len; - int ret; - bufptr = (char*)malloc(4096); // OG Added Cast - ret = vsnprintf(bufptr, 4090, fmt, ap); +int fatal_printf(const char *fmt, ...) { + va_list ap; + int ret; - // OG Display warning - printf("Warning:%s",bufptr); - - len = strlen(bufptr); - if(g_fatal_log >= 0 && g_fatal_log < MAX_FATAL_LOGS) { - buf2ptr = (char*)malloc(len+1); // OG Added Cast - memcpy(buf2ptr, bufptr, len+1); - g_fatal_log_strs[g_fatal_log++] = buf2ptr; - } - must_write(1, bufptr, len); - if(g_debug_file_fd >= 0) { - must_write(g_debug_file_fd, bufptr, len); - } - free(bufptr); + va_start(ap, fmt); - return ret; + if(g_fatal_log < 0) { + g_fatal_log = 0; + } + ret = gsport_vprintf(fmt, ap); + va_end(ap); + + return ret; } -void -must_write(int fd, char *bufptr, int len) -{ - int ret; -#ifndef __OS2__ - while(len > 0) { - ret = write(fd, bufptr, len); - if(ret >= 0) { - len -= ret; - bufptr += ret; - } else if(errno != EAGAIN && errno != EINTR) { - return; // just get out - } - } -#else - printf("%s\n",bufptr); -#endif +void must_write(int fd, char *bufptr, int len) { + int ret; + while(len > 0) { + ret = write(fd, bufptr, len); + if(ret >= 0) { + len -= ret; + bufptr += ret; + } else if(errno != EAGAIN && errno != EINTR) { + return; // just get out + } + } } -void -clear_fatal_logs() -{ - int i; +void clear_fatal_logs() { + int i; - for(i = 0; i < g_fatal_log; i++) { - free(g_fatal_log_strs[i]); - g_fatal_log_strs[i] = 0; - } - g_fatal_log = -1; + for(i = 0; i < g_fatal_log; i++) { + free(g_fatal_log_strs[i]); + g_fatal_log_strs[i] = 0; + } + g_fatal_log = -1; } -char * -gsport_malloc_str(char *in_str) -{ - char *str; - int len; +char *gsport_malloc_str(char *in_str) { + char *str; + int len; - len = strlen(in_str) + 1; - str = (char*)malloc(len); // OG Added cast - memcpy(str, in_str, len); + len = strlen(in_str) + 1; + str = (char*)malloc(len); // OG Added cast + memcpy(str, in_str, len); - return str; + return str; } diff --git a/src/sound_driver.c b/src/sound_driver.c index cd55dd0..3618ce3 100644 --- a/src/sound_driver.c +++ b/src/sound_driver.c @@ -1,440 +1,425 @@ -/* - GSport - an Apple //gs Emulator - Copyright (C) 2010 - 2012 by GSport contributors - - Based on the KEGS emulator written by and Copyright (C) 2003 Kent Dickey - - This program is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by the - Free Software Foundation; either version 2 of the License, or (at your - option) any later version. - - This program is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - for more details. - - You should have received a copy of the GNU General Public License along - with this program; if not, write to the Free Software Foundation, Inc., - 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ - -#include "defc.h" -#include "sound.h" - -#ifdef HPUX -# include -#endif - -#if defined(__linux__) || defined(OSS) -# include -#endif - -#ifndef WIN_SOUND /* Workaround - gcc in cygwin wasn't defining _WIN32 */ -# include -# include -#endif -#ifndef UNDER_CE -#include -#endif - - -extern int Verbose; - -extern int g_audio_rate; - -int g_preferred_rate = 48000; -int g_audio_socket = -1; -int g_bytes_written = 0; - -#define ZERO_BUF_SIZE 2048 - -word32 g_snd_zero_buf[ZERO_BUF_SIZE]; - -#define ZERO_PAUSE_SAFETY_SAMPS (g_audio_rate >> 5) -#define ZERO_PAUSE_NUM_SAMPS (4*g_audio_rate) - -int g_zeroes_buffered = 0; -int g_zeroes_seen = 0; -int g_sound_paused = 0; -int g_childsnd_vbl = 0; -int g_childsnd_pos = 0; -word32 *g_childsnd_shm_addr = 0; - -void child_sound_init_linux(); -void child_sound_init_hpdev(); -void child_sound_initWIN_SOUND(); -void child_sound_init_mac(); - -void -reliable_buf_write(word32 *shm_addr, int pos, int size) -{ - byte *ptr; - int ret; - - if(size < 1 || pos < 0 || pos > SOUND_SHM_SAMP_SIZE || - size > SOUND_SHM_SAMP_SIZE || - (pos + size) > SOUND_SHM_SAMP_SIZE) { - printf("reliable_buf_write: pos: %04x, size: %04x\n", - pos, size); - exit(1); - } - - ptr = (byte *)&(shm_addr[pos]); - size = size * 4; - - while(size > 0) { -#ifdef WIN_SOUND - ret = win32_send_audio(ptr, size); -#else -# ifdef MAC - ret = mac_send_audio(ptr, size); -# else - ret = write(g_audio_socket, ptr, size); -# endif -#endif - - if(ret < 0) { - printf("audio write, errno: %d\n", errno); - exit(1); - } - size = size - ret; - ptr += ret; - g_bytes_written += ret; - } - -} - -void -reliable_zero_write(int amt) -{ - int len; - - while(amt > 0) { - len = MIN(amt, ZERO_BUF_SIZE); - reliable_buf_write(g_snd_zero_buf, 0, len); - amt -= len; - } -} - - -void -child_sound_loop(int read_fd, int write_fd, word32 *shm_addr) -{ -#ifdef HPUX - long status_return; -#endif - word32 tmp; - int ret; - - doc_printf("Child pipe fd: %d\n", read_fd); - - g_audio_rate = g_preferred_rate; - - g_zeroes_buffered = 0; - g_zeroes_seen = 0; - g_sound_paused = 0; - - g_childsnd_pos = 0; - g_childsnd_vbl = 0; - g_childsnd_shm_addr = shm_addr; - -#ifdef HPUX - child_sound_init_hpdev(); -#endif -#if defined(__linux__) || defined(OSS) - child_sound_init_linux(); -#endif -#ifdef WIN_SOUND - child_sound_init_win32(); - return; -#endif -#ifdef MAC - child_sound_init_mac(); - return; -#endif - - tmp = g_audio_rate; - ret = write(write_fd, &tmp, 4); - if(ret != 4) { - printf("Unable to send back audio rate to parent\n"); - printf("ret: %d fd: %d, errno: %d\n", ret, write_fd, errno); - exit(1); - } - printf("Wrote to fd %d the audio rate\n", write_fd); - - close(write_fd); - - while(1) { - errno = 0; - ret = read(read_fd, (char*)&tmp, 4); - if(ret <= 0) { - printf("child dying from ret: %d, errno: %d\n", - ret, errno); - break; - } - - child_sound_playit(tmp); - } - -#ifdef HPUX - ioctl(g_audio_socket, AUDIO_DRAIN, 0); -#endif - close(g_audio_socket); - - exit(0); -} - -void -child_sound_playit(word32 tmp) -{ - int size; - - size = tmp & 0xffffff; - - //printf("child_sound_playit: %08x\n", tmp); - - if((tmp >> 24) == 0xa2) { - /* play sound here */ - - -#if 0 - g_childsnd_pos += g_zeroes_buffered; - while(g_childsnd_pos >= SOUND_SHM_SAMP_SIZE) { - g_childsnd_pos -= SOUND_SHM_SAMP_SIZE; - } -#endif - - if(g_zeroes_buffered) { - reliable_zero_write(g_zeroes_buffered); - } - - g_zeroes_buffered = 0; - g_zeroes_seen = 0; - - if((size + g_childsnd_pos) > SOUND_SHM_SAMP_SIZE) { - reliable_buf_write(g_childsnd_shm_addr, g_childsnd_pos, - SOUND_SHM_SAMP_SIZE - g_childsnd_pos); - size = (g_childsnd_pos + size) - SOUND_SHM_SAMP_SIZE; - g_childsnd_pos = 0; - } - - reliable_buf_write(g_childsnd_shm_addr, g_childsnd_pos, size); - - if(g_sound_paused) { - printf("Unpausing sound, zb: %d\n", g_zeroes_buffered); - g_sound_paused = 0; - } - - } else if((tmp >> 24) == 0xa1) { - if(g_sound_paused) { - if(g_zeroes_buffered < ZERO_PAUSE_SAFETY_SAMPS) { - g_zeroes_buffered += size; - } - } else { - /* not paused, send it through */ - g_zeroes_seen += size; - - reliable_zero_write(size); - - if(g_zeroes_seen >= ZERO_PAUSE_NUM_SAMPS) { - printf("Pausing sound\n"); - g_sound_paused = 1; - } - } - } else { - printf("tmp received bad: %08x\n", tmp); - exit(3); - } - - g_childsnd_pos += size; - while(g_childsnd_pos >= SOUND_SHM_SAMP_SIZE) { - g_childsnd_pos -= SOUND_SHM_SAMP_SIZE; - } - - g_childsnd_vbl++; - if(g_childsnd_vbl >= 60) { - g_childsnd_vbl = 0; -#if 0 - printf("sound bytes written: %06x\n", g_bytes_written); - printf("Sample samples[0]: %08x %08x %08x %08x\n", - g_childsnd_shm_addr[0], g_childsnd_shm_addr[1], - g_childsnd_shm_addr[2], g_childsnd_shm_addr[3]); - printf("Sample samples[100]: %08x %08x %08x %08x\n", - g_childsnd_shm_addr[100], g_childsnd_shm_addr[101], - g_childsnd_shm_addr[102], g_childsnd_shm_addr[103]); -#endif - g_bytes_written = 0; - } -} - - -#ifdef HPUX -void -child_sound_init_hpdev() -{ - struct audio_describe audio_descr; - int output_channel; - char *str; - int speaker; - int ret; - int i; - - g_audio_socket = open("/dev/audio", O_WRONLY, 0); - if(g_audio_socket < 0) { - printf("open /dev/audio failed, ret: %d, errno:%d\n", - g_audio_socket, errno); - exit(1); - } - - ret = ioctl(g_audio_socket, AUDIO_DESCRIBE, &audio_descr); - if(ret < 0) { - printf("ioctl AUDIO_DESCRIBE failed, ret:%d, errno:%d\n", - ret, errno); - exit(1); - } - - for(i = 0; i < audio_descr.nrates; i++) { - printf("Audio rate[%d] = %d\n", i, - audio_descr.sample_rate[i]); - } - - ret = ioctl(g_audio_socket, AUDIO_SET_DATA_FORMAT, - AUDIO_FORMAT_LINEAR16BIT); - if(ret < 0) { - printf("ioctl AUDIO_SET_DATA_FORMAT failed, ret:%d, errno:%d\n", - ret, errno); - exit(1); - } - - ret = ioctl(g_audio_socket, AUDIO_SET_CHANNELS, NUM_CHANNELS); - if(ret < 0) { - printf("ioctl AUDIO_SET_CHANNELS failed, ret:%d, errno:%d\n", - ret, errno); - exit(1); - } - - ret = ioctl(g_audio_socket, AUDIO_SET_TXBUFSIZE, 16*1024); - if(ret < 0) { - printf("ioctl AUDIO_SET_TXBUFSIZE failed, ret:%d, errno:%d\n", - ret, errno); - exit(1); - } - - ret = ioctl(g_audio_socket, AUDIO_SET_SAMPLE_RATE, g_audio_rate); - if(ret < 0) { - printf("ioctl AUDIO_SET_SAMPLE_RATE failed, ret:%d, errno:%d\n", - ret, errno); - exit(1); - } - - ret = ioctl(g_audio_socket, AUDIO_GET_OUTPUT, &output_channel); - if(ret < 0) { - printf("ioctl AUDIO_GET_OUTPUT failed, ret:%d, errno:%d\n", - ret, errno); - exit(1); - } - - - speaker = 1; - str = getenv("SPEAKER"); - if(str) { - if(str[0] != 'i' && str[0] != 'I') { - speaker = 0; - } - } - - if(speaker) { - printf("Sending sound to internal speaker\n"); - output_channel |= AUDIO_OUT_SPEAKER; - } else { - printf("Sending sound to external jack\n"); - output_channel &= (~AUDIO_OUT_SPEAKER); - output_channel |= AUDIO_OUT_HEADPHONE; - } - - ret = ioctl(g_audio_socket, AUDIO_SET_OUTPUT, output_channel); - if(ret < 0) { - printf("ioctl AUDIO_SET_OUTPUT failed, ret:%d, errno:%d\n", - ret, errno); - exit(1); - } -} -#endif /* HPUX */ - -#if defined(__linux__) || defined(OSS) -void -child_sound_init_linux() -{ - int stereo; - int sample_size; - int rate; - int fragment; - int fmt; - int ret; - - g_audio_socket = open("/dev/dsp", O_WRONLY, 0); - if(g_audio_socket < 0) { - printf("open /dev/dsp failed, ret: %d, errno:%d\n", - g_audio_socket, errno); - exit(1); - } - - fragment = 0x00200009; -#if 0 - ret = ioctl(g_audio_socket, SNDCTL_DSP_SETFRAGMENT, &fragment); - if(ret < 0) { - printf("ioctl SETFRAGEMNT failed, ret:%d, errno:%d\n", - ret, errno); - exit(1); - } -#endif - - sample_size = 16; - ret = ioctl(g_audio_socket, SNDCTL_DSP_SAMPLESIZE, &sample_size); - if(ret < 0) { - printf("ioctl SNDCTL_DSP_SAMPLESIZE failed, ret:%d, errno:%d\n", - ret, errno); - exit(1); - } - -#if defined(GSPORT_LITTLE_ENDIAN) || defined (__LITTLE_ENDIAN__) // OSX needs to calculate endianness mid-compilation, can't be passed on compile command - fmt = AFMT_S16_LE; -#else - fmt = AFMT_S16_BE; -#endif - ret = ioctl(g_audio_socket, SNDCTL_DSP_SETFMT, &fmt); - if(ret < 0) { - printf("ioctl SNDCTL_DSP_SETFMT failed, ret:%d, errno:%d\n", - ret, errno); - exit(1); - } - - stereo = 1; - ret = ioctl(g_audio_socket, SNDCTL_DSP_STEREO, &stereo); - if(ret < 0) { - printf("ioctl SNDCTL_DSP_STEREO failed, ret:%d, errno:%d\n", - ret, errno); - exit(1); - } - - rate = g_audio_rate; - ret = ioctl(g_audio_socket, SNDCTL_DSP_SPEED, &rate); - if(ret < 0) { - printf("ioctl SNDCTL_DSP_SPEED failed, ret:%d, errno:%d\n", - ret, errno); - exit(1); - } - if(ret > 0) { - rate = ret; /* rate is returned value */ - } - if(rate < 8000) { - printf("Audio rate of %d which is < 8000!\n", rate); - exit(1); - } - - g_audio_rate = rate; - - printf("Sound initialized\n"); -} -#endif +/* + GSport - an Apple //gs Emulator + Copyright (C) 2010 - 2019 by GSport contributors + Copyright (C) 2016 - 2018 Dagen Brock + + Based on the KEGS emulator written by and Copyright (C) 2003 Kent Dickey + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 2 of the License, or (at your + option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include "defc.h" +#include "sound.h" +#include "glog.h" + +#ifdef HPUX +# include +#endif +#ifdef HAVE_SDL +# include "SDL.h" +long sound_init_device_sdl(); +#endif + +#if defined(__linux__) || defined(OSS) +# include +#endif + +#ifndef WIN_SOUND /* Workaround - gcc in cygwin wasn't defining _WIN32 */ +# include +# include +#endif +#ifndef UNDER_CE +#include +#endif + + +extern int Verbose; + +extern int g_audio_rate; + +int g_preferred_rate = 48000; +int g_audio_socket = -1; +int g_bytes_written = 0; + +#define ZERO_BUF_SIZE 2048 + +word32 g_snd_zero_buf[ZERO_BUF_SIZE]; + +#define ZERO_PAUSE_SAFETY_SAMPS (g_audio_rate >> 5) +#define ZERO_PAUSE_NUM_SAMPS (4*g_audio_rate) + +int g_zeroes_buffered = 0; +int g_zeroes_seen = 0; +int g_sound_paused = 0; +int g_childsnd_vbl = 0; +int g_childsnd_pos = 0; +word32 *g_childsnd_shm_addr = 0; + +void child_sound_init_linux(); +void child_sound_init_hpdev(); +void child_sound_initWIN_SOUND(); +void child_sound_init_mac(); +void child_sound_init_sdl(); +long sound_init_device_sdl(); + +void reliable_buf_write(word32 *shm_addr, int pos, int size) { + byte *ptr; + int ret = 0; + + if(size < 1 || pos < 0 || pos > SOUND_SHM_SAMP_SIZE || + size > SOUND_SHM_SAMP_SIZE || + (pos + size) > SOUND_SHM_SAMP_SIZE) { + printf("reliable_buf_write: pos: %04x, size: %04x\n", pos, size); + exit(1); + } + + ptr = (byte *)&(shm_addr[pos]); + size = size * 4; + + while(size > 0) { +#if defined(HAVE_SDL) + //ret = sdl_send_audio(ptr, size); + +#elif defined(WIN_SOUND) + ret = win32_send_audio(ptr, size); +#elif defined(MAC) && !defined(HAVE_SDL) + ret = mac_send_audio(ptr, size); +#else + ret = write(g_audio_socket, ptr, size); +#endif + + if(ret < 0) { + printf("audio write, errno: %d\n", errno); + exit(1); + } + size = size - ret; + ptr += ret; + g_bytes_written += ret; + } + +} + +void reliable_zero_write(int amt) { + int len; + + while(amt > 0) { + len = MIN(amt, ZERO_BUF_SIZE); + reliable_buf_write(g_snd_zero_buf, 0, len); + amt -= len; + } +} + + +void child_sound_loop(int read_fd, int write_fd, word32 *shm_addr) { + word32 tmp; + int ret; + + g_audio_rate = g_preferred_rate; + + g_zeroes_buffered = 0; + g_zeroes_seen = 0; + g_sound_paused = 0; + + g_childsnd_pos = 0; + g_childsnd_vbl = 0; + g_childsnd_shm_addr = shm_addr; + +#if defined(HAVE_SDL) + //child_sound_init_sdl(); + sound_init_device_sdl(); // ignores long return value of sample rate + return; +#elif defined(__linux__) || defined(OSS) + child_sound_init_linux(); +#elif HPUX + child_sound_init_hpdev(); +#elif WIN_SOUND + child_sound_init_win32(); + return; +#elif defined(MAC) && !defined(HAVE_SDL) + child_sound_init_mac(); + return; +#endif + + doc_printf("Child pipe fd: %d\n", read_fd); + + tmp = g_audio_rate; + ret = write(write_fd, &tmp, 4); + if(ret != 4) { + printf("Unable to send back audio rate to parent\n"); + printf("ret: %d fd: %d, errno: %d\n", ret, write_fd, errno); + exit(1); + } + printf("Wrote to fd %d the audio rate\n", write_fd); + + close(write_fd); + + while(1) { + errno = 0; + ret = read(read_fd, (char*)&tmp, 4); + if(ret <= 0) { + printf("child dying from ret: %d, errno: %d\n", + ret, errno); + break; + } + + child_sound_playit(tmp); + } + +#ifdef HPUX + ioctl(g_audio_socket, AUDIO_DRAIN, 0); +#endif + close(g_audio_socket); + + exit(0); +} + +// called by sound.c:send_sound() +void child_sound_playit(word32 tmp) { + int size; + + size = tmp & 0xffffff; + + if((tmp >> 24) == 0xa2) { + /* play sound here */ + + +#if 0 + g_childsnd_pos += g_zeroes_buffered; + while(g_childsnd_pos >= SOUND_SHM_SAMP_SIZE) { + g_childsnd_pos -= SOUND_SHM_SAMP_SIZE; + } +#endif + + if(g_zeroes_buffered) { + reliable_zero_write(g_zeroes_buffered); + } + + g_zeroes_buffered = 0; + g_zeroes_seen = 0; + + // only write up to end of buffer + if((size + g_childsnd_pos) > SOUND_SHM_SAMP_SIZE) { + reliable_buf_write(g_childsnd_shm_addr, g_childsnd_pos, + SOUND_SHM_SAMP_SIZE - g_childsnd_pos); + size = (g_childsnd_pos + size) - SOUND_SHM_SAMP_SIZE; + g_childsnd_pos = 0; + } + + reliable_buf_write(g_childsnd_shm_addr, g_childsnd_pos, size); + + if(g_sound_paused) { + glogf("Unpausing sound, zb: %d\n", g_zeroes_buffered); + g_sound_paused = 0; + } + + } else if((tmp >> 24) == 0xa1) { + if(g_sound_paused) { + if(g_zeroes_buffered < ZERO_PAUSE_SAFETY_SAMPS) { + g_zeroes_buffered += size; + } + } else { + /* not paused, send it through */ + g_zeroes_seen += size; + + reliable_zero_write(size); + + if(g_zeroes_seen >= ZERO_PAUSE_NUM_SAMPS) { + glog("Pausing sound"); + g_sound_paused = 1; + } + } + } else { + printf("tmp received bad: %08x\n", tmp); + exit(3); + } + + g_childsnd_pos += size; + while(g_childsnd_pos >= SOUND_SHM_SAMP_SIZE) { + g_childsnd_pos -= SOUND_SHM_SAMP_SIZE; + } + + g_childsnd_vbl++; + if(g_childsnd_vbl >= 60) { + g_childsnd_vbl = 0; + g_bytes_written = 0; + } +} + + +#ifdef HPUX +void child_sound_init_hpdev() { + struct audio_describe audio_descr; + int output_channel; + char *str; + int speaker; + int ret; + int i; + + g_audio_socket = open("/dev/audio", O_WRONLY, 0); + if(g_audio_socket < 0) { + printf("open /dev/audio failed, ret: %d, errno:%d\n", + g_audio_socket, errno); + exit(1); + } + + ret = ioctl(g_audio_socket, AUDIO_DESCRIBE, &audio_descr); + if(ret < 0) { + printf("ioctl AUDIO_DESCRIBE failed, ret:%d, errno:%d\n", + ret, errno); + exit(1); + } + + for(i = 0; i < audio_descr.nrates; i++) { + printf("Audio rate[%d] = %d\n", i, + audio_descr.sample_rate[i]); + } + + ret = ioctl(g_audio_socket, AUDIO_SET_DATA_FORMAT, + AUDIO_FORMAT_LINEAR16BIT); + if(ret < 0) { + printf("ioctl AUDIO_SET_DATA_FORMAT failed, ret:%d, errno:%d\n", + ret, errno); + exit(1); + } + + ret = ioctl(g_audio_socket, AUDIO_SET_CHANNELS, NUM_CHANNELS); + if(ret < 0) { + printf("ioctl AUDIO_SET_CHANNELS failed, ret:%d, errno:%d\n", + ret, errno); + exit(1); + } + + ret = ioctl(g_audio_socket, AUDIO_SET_TXBUFSIZE, 16*1024); + if(ret < 0) { + printf("ioctl AUDIO_SET_TXBUFSIZE failed, ret:%d, errno:%d\n", + ret, errno); + exit(1); + } + + ret = ioctl(g_audio_socket, AUDIO_SET_SAMPLE_RATE, g_audio_rate); + if(ret < 0) { + printf("ioctl AUDIO_SET_SAMPLE_RATE failed, ret:%d, errno:%d\n", + ret, errno); + exit(1); + } + + ret = ioctl(g_audio_socket, AUDIO_GET_OUTPUT, &output_channel); + if(ret < 0) { + printf("ioctl AUDIO_GET_OUTPUT failed, ret:%d, errno:%d\n", + ret, errno); + exit(1); + } + + + speaker = 1; + str = getenv("SPEAKER"); + if(str) { + if(str[0] != 'i' && str[0] != 'I') { + speaker = 0; + } + } + + if(speaker) { + printf("Sending sound to internal speaker\n"); + output_channel |= AUDIO_OUT_SPEAKER; + } else { + printf("Sending sound to external jack\n"); + output_channel &= (~AUDIO_OUT_SPEAKER); + output_channel |= AUDIO_OUT_HEADPHONE; + } + + ret = ioctl(g_audio_socket, AUDIO_SET_OUTPUT, output_channel); + if(ret < 0) { + printf("ioctl AUDIO_SET_OUTPUT failed, ret:%d, errno:%d\n", + ret, errno); + exit(1); + } +} +#endif /* HPUX */ + +#if defined(__linux__) || defined(OSS) +void child_sound_init_linux() { + int stereo; + int sample_size; + int rate; + int fragment; + int fmt; + int ret; + + g_audio_socket = open("/dev/dsp", O_WRONLY, 0); + if(g_audio_socket < 0) { + printf("open /dev/dsp failed, ret: %d, errno:%d\n", + g_audio_socket, errno); + exit(1); + } + + fragment = 0x00200009; +#if 0 + ret = ioctl(g_audio_socket, SNDCTL_DSP_SETFRAGMENT, &fragment); + if(ret < 0) { + printf("ioctl SETFRAGEMNT failed, ret:%d, errno:%d\n", + ret, errno); + exit(1); + } +#endif + + sample_size = 16; + ret = ioctl(g_audio_socket, SNDCTL_DSP_SAMPLESIZE, &sample_size); + if(ret < 0) { + printf("ioctl SNDCTL_DSP_SAMPLESIZE failed, ret:%d, errno:%d\n", + ret, errno); + exit(1); + } + +#if defined(GSPORT_LITTLE_ENDIAN) || defined (__LITTLE_ENDIAN__) // OSX needs to calculate endianness mid-compilation, can't be passed on compile command + fmt = AFMT_S16_LE; +#else + fmt = AFMT_S16_BE; +#endif + ret = ioctl(g_audio_socket, SNDCTL_DSP_SETFMT, &fmt); + if(ret < 0) { + printf("ioctl SNDCTL_DSP_SETFMT failed, ret:%d, errno:%d\n", + ret, errno); + exit(1); + } + + stereo = 1; + ret = ioctl(g_audio_socket, SNDCTL_DSP_STEREO, &stereo); + if(ret < 0) { + printf("ioctl SNDCTL_DSP_STEREO failed, ret:%d, errno:%d\n", + ret, errno); + exit(1); + } + + rate = g_audio_rate; + ret = ioctl(g_audio_socket, SNDCTL_DSP_SPEED, &rate); + if(ret < 0) { + printf("ioctl SNDCTL_DSP_SPEED failed, ret:%d, errno:%d\n", + ret, errno); + exit(1); + } + if(ret > 0) { + rate = ret; /* rate is returned value */ + } + if(rate < 8000) { + printf("Audio rate of %d which is < 8000!\n", rate); + exit(1); + } + + g_audio_rate = rate; + + printf("Sound initialized\n"); +} +#endif diff --git a/src/tfe/CMakeLists.txt b/src/tfe/CMakeLists.txt new file mode 100644 index 0000000..80df2c3 --- /dev/null +++ b/src/tfe/CMakeLists.txt @@ -0,0 +1,6 @@ +set(CMAKE_INCLUDE_CURRENT_DIR ON) + +add_library(tfe tfe.c tfearch.c tfesupp.c) + +target_compile_definitions(tfe PUBLIC HAVE_TFE) + diff --git a/src/tfe/protos_tfe.h b/src/tfe/protos_tfe.h index eef041f..07e6dcf 100644 --- a/src/tfe/protos_tfe.h +++ b/src/tfe/protos_tfe.h @@ -1,6 +1,7 @@ /* GSport - an Apple //gs Emulator - Copyright (C) 2010 by GSport contributors + Copyright (C) 2010 - 2019 by GSport contributors + Copyright (C) 2016 - 2018 Dagen Brock Based on the KEGS emulator written by and Copyright (C) 2003 Kent Dickey @@ -101,4 +102,4 @@ int tfe_arch_enumadapter_open(void); int tfe_arch_enumadapter(char **ppname, char **ppdescription); int tfe_arch_enumadapter_close(void); -#endif \ No newline at end of file +#endif diff --git a/src/tfe/tfe.c b/src/tfe/tfe.c index f0f9698..43c5b3a 100644 --- a/src/tfe/tfe.c +++ b/src/tfe/tfe.c @@ -4,7 +4,7 @@ * Written by * Spiro Trikaliotis * Christian Vogelgsang - * + * * This file is part of VICE, the Versatile Commodore Emulator. * See README for copyright notice. * @@ -26,8 +26,6 @@ */ - - #include #include #include @@ -61,9 +59,9 @@ /* variables needed */ /* - This variable is used when we need to postpone the initialization - because tfe_init() is not yet called -*/ + This variable is used when we need to postpone the initialization + because tfe_init() is not yet called + */ static int should_activate = 0; static int init_tfe_flag = 0; typedef signed int log_t; @@ -73,22 +71,22 @@ typedef signed int log_t; static log_t tfe_log = LOG_ERR; -/* status which received packages to accept +/* status which received packages to accept This is used in tfe_should_accept(). -*/ -static byte tfe_ia_mac[6] = { 0,0,0,0,0,0 }; + */ +static byte tfe_ia_mac[6] = { 0,0,0,0,0,0 }; /* remember the value of the hash mask */ static DWORD tfe_hash_mask[2]; /* reveiver setup */ static word16 tfe_recv_control = 0; /* copy of CC_RXCTL (contains all bits below) */ -static int tfe_recv_broadcast = 0; /* broadcast */ -static int tfe_recv_mac = 0; /* individual address (IA) */ -static int tfe_recv_multicast = 0; /* multicast if address passes the hash filter */ -static int tfe_recv_correct = 0; /* accept correct frames */ -static int tfe_recv_promiscuous = 0; /* promiscuous mode */ -static int tfe_recv_hashfilter = 0; /* accept if IA passes the hash filter */ +static int tfe_recv_broadcast = 0; /* broadcast */ +static int tfe_recv_mac = 0; /* individual address (IA) */ +static int tfe_recv_multicast = 0; /* multicast if address passes the hash filter */ +static int tfe_recv_correct = 0; /* accept correct frames */ +static int tfe_recv_promiscuous = 0; /* promiscuous mode */ +static int tfe_recv_hashfilter = 0; /* accept if IA passes the hash filter */ /* Flag: Can we even use TFE, or is the hardware not available? */ static int tfe_cannot_use = 0; @@ -107,7 +105,7 @@ static char *tfe_interface = NULL; REMARK: The TFE operatoes the cs8900a in IO space configuration, as it generates I/OW and I/OR signals. -*/ + */ #define TFE_COUNT_IO_REGISTER 0x10 /* we have 16 I/O register */ static byte *tfe = NULL; @@ -115,12 +113,12 @@ static byte *tfe = NULL; RW: RXTXDATA = DE00/DE01 RW: RXTXDATA2 = DE02/DE03 (for 32-bit-operation) -W: TXCMD = DE04/DE05 (TxCMD, Transmit Command) mapped to PP + 0144 (Reg. 9, Sec. 4.4, page 46) - -W: TXLENGTH = DE06/DE07 (TxLenght, Transmit Length) mapped to PP + 0146 + -W: TXLENGTH = DE06/DE07 (TxLenght, Transmit Length) mapped to PP + 0146 R-: INTSTQUEUE = DE08/DE09 (Interrupt Status Queue) mapped to PP + 0120 (ISQ, Sec. 5.1, page 78) RW: PP_PTR = DE0A/DE0B (PacketPage Pointer) (see. page 75p: Read -011.---- ----.----) - RW: PP_DATA0 = DE0C/DE0D (PacketPage Data (Port 0)) + RW: PP_DATA0 = DE0C/DE0D (PacketPage Data (Port 0)) RW: PP_DATA1 = DE0E/DE0F (PacketPage Data (Port 1)) (for 32 bit only) -*/ + */ #define TFE_ADDR_RXTXDATA 0x00 /* RW */ #define TFE_ADDR_RXTXDATA2 0x02 /* RW 32 bit only! */ @@ -129,31 +127,31 @@ static byte *tfe = NULL; #define TFE_ADDR_INTSTQUEUE 0x08 /* R- Interrupt status queue, maps to PP + 0120 */ #define TFE_ADDR_PP_PTR 0x0a /* RW PacketPage Pointer */ #define TFE_ADDR_PP_DATA 0x0c /* RW PacketPage Data, Port 0 */ -#define TFE_ADDR_PP_DATA2 0x0e /* RW PacketPage Data, Port 1 - 32 bit only */ +#define TFE_ADDR_PP_DATA2 0x0e /* RW PacketPage Data, Port 1 - 32 bit only */ /* Makros for reading and writing the visible TFE register: */ #define GET_TFE_8( _xxx_ ) \ - ( assert(_xxx_> 8) & 0xff; \ - } while (0) + do { \ + assert(_xxx_> 8) & 0xff; \ + } while (0) /* The PacketPage register */ /* note: The locations 0 to MAX_PACKETPAGE_ARRAY-1 are handled in this array. */ @@ -167,49 +165,49 @@ static word16 tfe_packetpage_ptr = 0; /* Makros for reading and writing the PacketPage register: */ #define GET_PP_8( _xxx_ ) \ - (assert(_xxx_> 8) & 0xFF; \ - } while (0) + do { \ + assert(_xxx_> 8) & 0xFF; \ + } while (0) #define SET_PP_32( _xxx_, _val_ ) \ - do { \ - assert(_xxx_> 8) & 0xFF; \ - tfe_packetpage[_xxx_+2] = (_val_>>16) & 0xFF; \ - tfe_packetpage[_xxx_+3] = (_val_>>24) & 0xFF; \ - } while (0) + do { \ + assert(_xxx_> 8) & 0xFF; \ + tfe_packetpage[_xxx_+2] = (_val_>>16) & 0xFF; \ + tfe_packetpage[_xxx_+3] = (_val_>>24) & 0xFF; \ + } while (0) /* The packetpage register: see p. 39f */ @@ -316,27 +314,26 @@ static int rxevent_read_mask = 3; /* set if L and/or H byte was read in RXEVENT? static int TfeDebugMaxFrameLengthToDump = 150; -static char *debug_outbuffer(const int length, const unsigned char * const buffer) -{ +static char *debug_outbuffer(const int length, const unsigned char * const buffer) { #define MAXLEN_DEBUG 1600 - int i; - static char outbuffer[MAXLEN_DEBUG*4+1]; - char *p = outbuffer; + int i; + static char outbuffer[MAXLEN_DEBUG*4+1]; + char *p = outbuffer; - assert( TfeDebugMaxFrameLengthToDump <= MAXLEN_DEBUG ); - - *p = 0; + assert( TfeDebugMaxFrameLengthToDump <= MAXLEN_DEBUG ); - for (i=0; i=length) - break; - - sprintf( p, "%02X%c", buffer[i], ((i+1)%16==0)?'*':(((i+1)%8==0)?'-':' ')); - p+=3; - } + *p = 0; - return outbuffer; + for (i=0; i=length) + break; + + sprintf( p, "%02X%c", buffer[i], ((i+1)%16==0) ? '*' : (((i+1)%8==0) ? '-' : ' ')); + p+=3; + } + + return outbuffer; } #endif @@ -344,266 +341,257 @@ static char *debug_outbuffer(const int length, const unsigned char * const buffe /* ------------------------------------------------------------------------- */ /* initialization and deinitialization functions */ -static void tfe_set_tx_status(int ready,int error) -{ - word16 old_status = GET_PP_16(TFE_PP_ADDR_SE_BUSST); - - /* mask out TxBidErr and Rdy4TxNOW */ - word16 new_status = old_status & ~0x180; - if(ready) - new_status |= 0x100; /* set Rdy4TxNOW */ - if(error) - new_status |= 0x080; /* set TxBidErr */ - - if(new_status!=old_status) { - SET_PP_16(TFE_PP_ADDR_SE_BUSST,new_status); +static void tfe_set_tx_status(int ready,int error) { + word16 old_status = GET_PP_16(TFE_PP_ADDR_SE_BUSST); + + /* mask out TxBidErr and Rdy4TxNOW */ + word16 new_status = old_status & ~0x180; + if(ready) + new_status |= 0x100; /* set Rdy4TxNOW */ + if(error) + new_status |= 0x080; /* set TxBidErr */ + + if(new_status!=old_status) { + SET_PP_16(TFE_PP_ADDR_SE_BUSST,new_status); #ifdef TFE_DEBUG_RXTX_STATE - log_message(tfe_log,"TX: set status Rdy4TxNOW=%d TxBidErr=%d", - ready,error); + log_message(tfe_log,"TX: set status Rdy4TxNOW=%d TxBidErr=%d", + ready,error); #endif - } + } } -static void tfe_set_receiver(int enabled) -{ - rx_enabled = enabled; - rx_state = TFE_RX_IDLE; +static void tfe_set_receiver(int enabled) { + rx_enabled = enabled; + rx_state = TFE_RX_IDLE; - rxevent_read_mask = 3; /* was L or H byte read in RXEVENT? */ + rxevent_read_mask = 3; /* was L or H byte read in RXEVENT? */ } -static void tfe_set_transmitter(int enabled) -{ - tx_enabled = enabled; - tx_state = TFE_TX_IDLE; - - tfe_set_tx_status(0,0); +static void tfe_set_transmitter(int enabled) { + tx_enabled = enabled; + tx_state = TFE_TX_IDLE; + + tfe_set_tx_status(0,0); } -void tfe_reset(void) -{ - if (tfe_enabled && !should_activate) - { - int i; - - assert( tfe ); - assert( tfe_packetpage ); +void tfe_reset(void) { + if (tfe_enabled && !should_activate) + { + int i; - tfe_arch_pre_reset(); + assert( tfe ); + assert( tfe_packetpage ); - /* initialize visible IO register and PacketPage registers */ - memset( tfe, 0, TFE_COUNT_IO_REGISTER ); - memset( tfe_packetpage, 0, MAX_PACKETPAGE_ARRAY ); + tfe_arch_pre_reset(); - /* according to page 19 unless stated otherwise */ - SET_PP_32(TFE_PP_ADDR_PRODUCTID, 0x0900630E ); /* p.41: 0E630009 for Rev. D; reversed order! */ - SET_PP_16(TFE_PP_ADDR_IOBASE, 0x0300); - SET_PP_16(TFE_PP_ADDR_INTNO, 0x0004); /* xxxx xxxx xxxx x100b */ - SET_PP_16(TFE_PP_ADDR_DMA_CHAN, 0x0003); /* xxxx xxxx xxxx xx11b */ + /* initialize visible IO register and PacketPage registers */ + memset( tfe, 0, TFE_COUNT_IO_REGISTER ); + memset( tfe_packetpage, 0, MAX_PACKETPAGE_ARRAY ); + + /* according to page 19 unless stated otherwise */ + SET_PP_32(TFE_PP_ADDR_PRODUCTID, 0x0900630E ); /* p.41: 0E630009 for Rev. D; reversed order! */ + SET_PP_16(TFE_PP_ADDR_IOBASE, 0x0300); + SET_PP_16(TFE_PP_ADDR_INTNO, 0x0004); /* xxxx xxxx xxxx x100b */ + SET_PP_16(TFE_PP_ADDR_DMA_CHAN, 0x0003); /* xxxx xxxx xxxx xx11b */ #if 0 /* not needed since all memory is initialized with 0 */ - SET_PP_16(TFE_PP_ADDR_DMA_SOF, 0x0000); - SET_PP_16(TFE_PP_ADDR_DMA_FC, 0x0000); /* x000h */ - SET_PP_16(TFE_PP_ADDR_RXDMA_BC, 0x0000); - SET_PP_32(TFE_PP_ADDR_MEMBASE, 0x0000); /* xxx0 0000h */ - SET_PP_32(TFE_PP_ADDR_BPROM_BASE, 0x00000000); /* xxx0 0000h */ - SET_PP_32(TFE_PP_ADDR_BPROM_MASK, 0x00000000); /* xxx0 0000h */ + SET_PP_16(TFE_PP_ADDR_DMA_SOF, 0x0000); + SET_PP_16(TFE_PP_ADDR_DMA_FC, 0x0000); /* x000h */ + SET_PP_16(TFE_PP_ADDR_RXDMA_BC, 0x0000); + SET_PP_32(TFE_PP_ADDR_MEMBASE, 0x0000); /* xxx0 0000h */ + SET_PP_32(TFE_PP_ADDR_BPROM_BASE, 0x00000000); /* xxx0 0000h */ + SET_PP_32(TFE_PP_ADDR_BPROM_MASK, 0x00000000); /* xxx0 0000h */ - SET_PP_16(TFE_PP_ADDR_SE_ISQ, 0x0000); /* p. 51 */ + SET_PP_16(TFE_PP_ADDR_SE_ISQ, 0x0000); /* p. 51 */ #endif - /* according to descriptions of the registers, see definitions of - TFE_PP_ADDR_CC_... and TFE_PP_ADDR_SE_... above! */ + /* according to descriptions of the registers, see definitions of + TFE_PP_ADDR_CC_... and TFE_PP_ADDR_SE_... above! */ - SET_PP_16(TFE_PP_ADDR_CC_RXCFG, 0x0003); - SET_PP_16(TFE_PP_ADDR_CC_RXCTL, 0x0005); - SET_PP_16(TFE_PP_ADDR_CC_TXCFG, 0x0007); - SET_PP_16(TFE_PP_ADDR_CC_TXCMD, 0x0009); - SET_PP_16(TFE_PP_ADDR_CC_BUFCFG, 0x000B); - SET_PP_16(TFE_PP_ADDR_CC_LINECTL, 0x0013); - SET_PP_16(TFE_PP_ADDR_CC_SELFCTL, 0x0015); - SET_PP_16(TFE_PP_ADDR_CC_BUSCTL, 0x0017); - SET_PP_16(TFE_PP_ADDR_CC_TESTCTL, 0x0019); + SET_PP_16(TFE_PP_ADDR_CC_RXCFG, 0x0003); + SET_PP_16(TFE_PP_ADDR_CC_RXCTL, 0x0005); + SET_PP_16(TFE_PP_ADDR_CC_TXCFG, 0x0007); + SET_PP_16(TFE_PP_ADDR_CC_TXCMD, 0x0009); + SET_PP_16(TFE_PP_ADDR_CC_BUFCFG, 0x000B); + SET_PP_16(TFE_PP_ADDR_CC_LINECTL, 0x0013); + SET_PP_16(TFE_PP_ADDR_CC_SELFCTL, 0x0015); + SET_PP_16(TFE_PP_ADDR_CC_BUSCTL, 0x0017); + SET_PP_16(TFE_PP_ADDR_CC_TESTCTL, 0x0019); - SET_PP_16(TFE_PP_ADDR_SE_ISQ, 0x0000); - SET_PP_16(TFE_PP_ADDR_SE_RXEVENT, 0x0004); - SET_PP_16(TFE_PP_ADDR_SE_TXEVENT, 0x0008); - SET_PP_16(TFE_PP_ADDR_SE_BUFEVENT, 0x000C); - SET_PP_16(TFE_PP_ADDR_SE_RXMISS, 0x0010); - SET_PP_16(TFE_PP_ADDR_SE_TXCOL, 0x0012); - SET_PP_16(TFE_PP_ADDR_SE_LINEST, 0x0014); - SET_PP_16(TFE_PP_ADDR_SE_SELFST, 0x0016); - SET_PP_16(TFE_PP_ADDR_SE_BUSST, 0x0018); - SET_PP_16(TFE_PP_ADDR_SE_TDR, 0x001C); - - SET_PP_16(TFE_PP_ADDR_TXCMD, 0x0009); + SET_PP_16(TFE_PP_ADDR_SE_ISQ, 0x0000); + SET_PP_16(TFE_PP_ADDR_SE_RXEVENT, 0x0004); + SET_PP_16(TFE_PP_ADDR_SE_TXEVENT, 0x0008); + SET_PP_16(TFE_PP_ADDR_SE_BUFEVENT, 0x000C); + SET_PP_16(TFE_PP_ADDR_SE_RXMISS, 0x0010); + SET_PP_16(TFE_PP_ADDR_SE_TXCOL, 0x0012); + SET_PP_16(TFE_PP_ADDR_SE_LINEST, 0x0014); + SET_PP_16(TFE_PP_ADDR_SE_SELFST, 0x0016); + SET_PP_16(TFE_PP_ADDR_SE_BUSST, 0x0018); + SET_PP_16(TFE_PP_ADDR_SE_TDR, 0x001C); - /* 4.4.19 Self Status Register, p. 65 - Important: set INITD (Bit 7) to signal device is ready */ - SET_PP_16(TFE_PP_ADDR_SE_SELFST, 0x0896); + SET_PP_16(TFE_PP_ADDR_TXCMD, 0x0009); - tfe_recv_control = GET_PP_16(TFE_PP_ADDR_CC_RXCTL); - - /* spec: mac address is undefined after reset. - real HW: keeps the last set address. */ - for(i=0;i<6;i++) - SET_PP_8(TFE_PP_ADDR_MAC_ADDR+i,tfe_ia_mac[i]); - - /* reset state */ - tfe_set_transmitter(0); - tfe_set_receiver(0); + /* 4.4.19 Self Status Register, p. 65 + Important: set INITD (Bit 7) to signal device is ready */ + SET_PP_16(TFE_PP_ADDR_SE_SELFST, 0x0896); - tfe_arch_post_reset(); + tfe_recv_control = GET_PP_16(TFE_PP_ADDR_CC_RXCTL); - printf("CS8900a rev.D reset\n"); - } + /* spec: mac address is undefined after reset. + real HW: keeps the last set address. */ + for(i=0; i<6; i++) + SET_PP_8(TFE_PP_ADDR_MAC_ADDR+i,tfe_ia_mac[i]); + + /* reset state */ + tfe_set_transmitter(0); + tfe_set_receiver(0); + + tfe_arch_post_reset(); + + printf("CS8900a rev.D reset\n"); + } } #ifdef DOS_TFE -static void set_standard_tfe_interface(void) -{ - char *dev, errbuf[PCAP_ERRBUF_SIZE]; - dev = pcap_lookupdev(errbuf); - util_string_set(&tfe_interface, dev); +static void set_standard_tfe_interface(void) { + char *dev, errbuf[PCAP_ERRBUF_SIZE]; + dev = pcap_lookupdev(errbuf); + util_string_set(&tfe_interface, dev); } #endif static -int tfe_activate_i(void) -{ - assert( tfe == NULL ); - assert( tfe_packetpage == NULL ); +int tfe_activate_i(void) { + assert( tfe == NULL ); + assert( tfe_packetpage == NULL ); #ifdef TFE_DEBUG - log_message( tfe_log, "tfe_activate_i()." ); + log_message( tfe_log, "tfe_activate_i()." ); #endif - /* allocate memory for visible IO register */ - tfe = (byte *)lib_malloc( TFE_COUNT_IO_REGISTER ); - if (tfe==NULL) - { + /* allocate memory for visible IO register */ + tfe = (byte *)lib_malloc( TFE_COUNT_IO_REGISTER ); + if (tfe==NULL) + { #ifdef TFE_DEBUG_INIT - log_message(tfe_log, "tfe_activate_i: Allocating tfe failed."); + log_message(tfe_log, "tfe_activate_i: Allocating tfe failed."); #endif - tfe_enabled = 0; - return 0; - } - - /* allocate memory for PacketPage register */ - tfe_packetpage = (byte *)lib_malloc( MAX_PACKETPAGE_ARRAY ); - if (tfe_packetpage==NULL) - { -#ifdef TFE_DEBUG_INIT - log_message(tfe_log, "tfe_activate: Allocating tfe_packetpage failed."); -#endif - lib_free(tfe); - tfe=NULL; - tfe_enabled = 0; - return 0; - } - -#ifdef TFE_DEBUG_INIT - log_message(tfe_log, "tfe_activate: Allocated memory successfully."); - log_message(tfe_log, "\ttfe at $%08X, tfe_packetpage at $%08X", tfe, tfe_packetpage ); -#endif - -#ifdef DOS_TFE - set_standard_tfe_interface(); -#endif - - if (!tfe_arch_activate(tfe_interface)) { - lib_free(tfe_packetpage); - lib_free(tfe); - tfe=NULL; - tfe_packetpage=NULL; - tfe_enabled = 0; - tfe_cannot_use = 1; - return 0; - } - - /* virtually reset the LAN chip */ - tfe_reset(); - + tfe_enabled = 0; return 0; -} + } -static -int tfe_deactivate_i(void) -{ -#ifdef TFE_DEBUG - log_message( tfe_log, "tfe_deactivate_i()." ); + /* allocate memory for PacketPage register */ + tfe_packetpage = (byte *)lib_malloc( MAX_PACKETPAGE_ARRAY ); + if (tfe_packetpage==NULL) + { +#ifdef TFE_DEBUG_INIT + log_message(tfe_log, "tfe_activate: Allocating tfe_packetpage failed."); #endif - - assert(tfe && tfe_packetpage); - - tfe_arch_deactivate(); - lib_free(tfe); - tfe = NULL; - lib_free(tfe_packetpage); - tfe_packetpage = NULL; + tfe=NULL; + tfe_enabled = 0; return 0; + } + +#ifdef TFE_DEBUG_INIT + log_message(tfe_log, "tfe_activate: Allocated memory successfully."); + log_message(tfe_log, "\ttfe at $%08X, tfe_packetpage at $%08X", tfe, tfe_packetpage ); +#endif + +#ifdef DOS_TFE + set_standard_tfe_interface(); +#endif + + if (!tfe_arch_activate(tfe_interface)) { + lib_free(tfe_packetpage); + lib_free(tfe); + tfe=NULL; + tfe_packetpage=NULL; + tfe_enabled = 0; + tfe_cannot_use = 1; + return 0; + } + + /* virtually reset the LAN chip */ + tfe_reset(); + + return 0; +} + +static +int tfe_deactivate_i(void) { +#ifdef TFE_DEBUG + log_message( tfe_log, "tfe_deactivate_i()." ); +#endif + + assert(tfe && tfe_packetpage); + + tfe_arch_deactivate(); + + lib_free(tfe); + tfe = NULL; + lib_free(tfe_packetpage); + tfe_packetpage = NULL; + return 0; } static int tfe_activate(void) { #ifdef TFE_DEBUG - log_message( tfe_log, "tfe_activate()." ); + log_message( tfe_log, "tfe_activate()." ); #endif - if (init_tfe_flag) { - return tfe_activate_i(); - } - else { - should_activate = 1; - } - return 0; + if (init_tfe_flag) { + return tfe_activate_i(); + } + else { + should_activate = 1; + } + return 0; } static int tfe_deactivate(void) { #ifdef TFE_DEBUG - log_message( tfe_log, "tfe_deactivate()." ); + log_message( tfe_log, "tfe_deactivate()." ); #endif - if (should_activate) - should_activate = 0; - else { - if (tfe_log != LOG_ERR) - return tfe_deactivate_i(); - } + if (should_activate) + should_activate = 0; + else { + if (tfe_log != LOG_ERR) + return tfe_deactivate_i(); + } - return 0; + return 0; } -void tfe_init(void) -{ - tfe_enabled = 1; - init_tfe_flag = 1; - should_activate = 1; - if (!tfe_arch_init()) { - tfe_enabled = 0; - tfe_cannot_use = 1; - } +void tfe_init(void) { + tfe_enabled = 1; + init_tfe_flag = 1; + should_activate = 1; + if (!tfe_arch_init()) { + tfe_enabled = 0; + tfe_cannot_use = 1; + } - if (should_activate) { - should_activate = 0; - if (tfe_activate() < 0) { - tfe_enabled = 0; - tfe_cannot_use = 1; - } + if (should_activate) { + should_activate = 0; + if (tfe_activate() < 0) { + tfe_enabled = 0; + tfe_cannot_use = 1; } + } } -void tfe_shutdown(void) -{ - assert( (tfe && tfe_packetpage) || (!tfe && !tfe_packetpage)); +void tfe_shutdown(void) { + assert( (tfe && tfe_packetpage) || (!tfe && !tfe_packetpage)); - if (tfe) - tfe_deactivate(); + if (tfe) + tfe_deactivate(); - if (tfe_interface != NULL) - lib_free(tfe_interface); + if (tfe_interface != NULL) + lib_free(tfe_interface); } @@ -611,665 +599,658 @@ void tfe_shutdown(void) /* reading and writing TFE register functions */ /* -These registers are currently fully or partially supported: + These registers are currently fully or partially supported: -TFE_PP_ADDR_CC_RXCFG 0x0102 * # RW - 4.4.6., p. 52 - 0003 * -TFE_PP_ADDR_CC_RXCTL 0x0104 * # RW - 4.4.8., p. 54 - 0005 * -TFE_PP_ADDR_CC_LINECTL 0x0112 * # RW - 4.4.16., p. 62 - 0013 * -TFE_PP_ADDR_SE_RXEVENT 0x0124 * # R- - 4.4.7., p. 53 - 0004 * -TFE_PP_ADDR_SE_BUSST 0x0138 * # R- - 4.4.21., p. 67 - 0018 * -TFE_PP_ADDR_TXCMD 0x0144 * # -W - 4.5., p. 70 - 5.7., p. 98 * -TFE_PP_ADDR_TXLENGTH 0x0146 * # -W - 4.5., p. 70 - 5.7., p. 98 * -TFE_PP_ADDR_MAC_ADDR 0x0158 * # RW - 4.6., p. 71 - 5.3., p. 86 * + TFE_PP_ADDR_CC_RXCFG 0x0102 * # RW - 4.4.6., p. 52 - 0003 * + TFE_PP_ADDR_CC_RXCTL 0x0104 * # RW - 4.4.8., p. 54 - 0005 * + TFE_PP_ADDR_CC_LINECTL 0x0112 * # RW - 4.4.16., p. 62 - 0013 * + TFE_PP_ADDR_SE_RXEVENT 0x0124 * # R- - 4.4.7., p. 53 - 0004 * + TFE_PP_ADDR_SE_BUSST 0x0138 * # R- - 4.4.21., p. 67 - 0018 * + TFE_PP_ADDR_TXCMD 0x0144 * # -W - 4.5., p. 70 - 5.7., p. 98 * + TFE_PP_ADDR_TXLENGTH 0x0146 * # -W - 4.5., p. 70 - 5.7., p. 98 * + TFE_PP_ADDR_MAC_ADDR 0x0158 * # RW - 4.6., p. 71 - 5.3., p. 86 * 0x015a 0x015c -*/ + */ #ifdef TFE_DEBUG_FRAMES #define return( _x_ ) \ - { \ - int retval = _x_; \ + { \ + int retval = _x_; \ \ - log_message(tfe_log, "%s correct_mac=%u, broadcast=%u, multicast=%u, hashed=%u, hash_index=%u", (retval? "+++ ACCEPTED":"--- rejected"), *pcorrect_mac, *pbroadcast, *pmulticast, *phashed, *phash_index); \ + log_message(tfe_log, "%s correct_mac=%u, broadcast=%u, multicast=%u, hashed=%u, hash_index=%u", (retval ? "+++ ACCEPTED" : "--- rejected"), *pcorrect_mac, *pbroadcast, *pmulticast, *phashed, *phash_index); \ \ - return retval; \ - } + return retval; \ + } #endif /* - This is a helper for tfe_receive() to determine if the received frame should be accepted - according to the settings. + This is a helper for tfe_receive() to determine if the received frame should be accepted + according to the settings. - This function is even allowed to be called in tfearch.c from tfe_arch_receive() if - necessary, which is the reason why its prototype is included here in tfearch.h. -*/ -int tfe_should_accept(unsigned char *buffer, int length, int *phashed, int *phash_index, - int *pcorrect_mac, int *pbroadcast, int *pmulticast) -{ - int hashreg; /* Hash Register (for hash computation) */ + This function is even allowed to be called in tfearch.c from tfe_arch_receive() if + necessary, which is the reason why its prototype is included here in tfearch.h. + */ +int tfe_should_accept(unsigned char *buffer, int length, int *phashed, int *phash_index, + int *pcorrect_mac, int *pbroadcast, int *pmulticast) { + int hashreg; /* Hash Register (for hash computation) */ - assert(length>=6); /* we need at least 6 octets since the DA has this length */ + assert(length>=6); /* we need at least 6 octets since the DA has this length */ - /* first of all, delete any status */ - *phashed = 0; - *phash_index = 0; - *pcorrect_mac = 0; - *pbroadcast = 0; - *pmulticast = 0; + /* first of all, delete any status */ + *phashed = 0; + *phash_index = 0; + *pcorrect_mac = 0; + *pbroadcast = 0; + *pmulticast = 0; #ifdef TFE_DEBUG_FRAMES - log_message(tfe_log, "tfe_should_accept called with %02X:%02X:%02X:%02X:%02X:%02X, length=%4u and buffer %s", - tfe_ia_mac[0], tfe_ia_mac[1], tfe_ia_mac[2], - tfe_ia_mac[3], tfe_ia_mac[4], tfe_ia_mac[5], - length, - debug_outbuffer(length, buffer) - ); + log_message(tfe_log, "tfe_should_accept called with %02X:%02X:%02X:%02X:%02X:%02X, length=%4u and buffer %s", + tfe_ia_mac[0], tfe_ia_mac[1], tfe_ia_mac[2], + tfe_ia_mac[3], tfe_ia_mac[4], tfe_ia_mac[5], + length, + debug_outbuffer(length, buffer) + ); #endif - if ( buffer[0]==tfe_ia_mac[0] - && buffer[1]==tfe_ia_mac[1] - && buffer[2]==tfe_ia_mac[2] - && buffer[3]==tfe_ia_mac[3] - && buffer[4]==tfe_ia_mac[4] - && buffer[5]==tfe_ia_mac[5] - ) { - /* this is our individual address (IA) */ + if ( buffer[0]==tfe_ia_mac[0] + && buffer[1]==tfe_ia_mac[1] + && buffer[2]==tfe_ia_mac[2] + && buffer[3]==tfe_ia_mac[3] + && buffer[4]==tfe_ia_mac[4] + && buffer[5]==tfe_ia_mac[5] + ) { + /* this is our individual address (IA) */ - *pcorrect_mac = 1; + *pcorrect_mac = 1; - /* if we don't want "correct MAC", we might have the chance - * that this address fits the hash index - */ - if (tfe_recv_mac || tfe_recv_promiscuous) - return(1); + /* if we don't want "correct MAC", we might have the chance + * that this address fits the hash index + */ + if (tfe_recv_mac || tfe_recv_promiscuous) + return(1); + } + + if ( buffer[0]==0xFF + && buffer[1]==0xFF + && buffer[2]==0xFF + && buffer[3]==0xFF + && buffer[4]==0xFF + && buffer[5]==0xFF + ) { + /* this is a broadcast address */ + *pbroadcast = 1; + + /* broadcasts cannot be accepted by the hash filter */ + return((tfe_recv_broadcast || tfe_recv_promiscuous) ? 1 : 0); + } + + /* now check if DA passes the hash filter */ + hashreg = (~crc32_buf((char *)buffer,6) >> 26) & 0x3F; + + *phashed = (tfe_hash_mask[(hashreg>=32) ? 1 : 0] & (1 << (hashreg&0x1F))) ? 1 : 0; + if (*phashed) { + *phash_index = hashreg; + + if (buffer[0] & 0x80) { + /* we have a multicast address */ + *pmulticast = 1; + + /* if the multicast address fits into the hash filter, + * the hashed bit has to be clear + */ + *phashed = 0; + + return((tfe_recv_multicast || tfe_recv_promiscuous) ? 1 : 0); } + return((tfe_recv_hashfilter || tfe_recv_promiscuous) ? 1 : 0); + } - if ( buffer[0]==0xFF - && buffer[1]==0xFF - && buffer[2]==0xFF - && buffer[3]==0xFF - && buffer[4]==0xFF - && buffer[5]==0xFF - ) { - /* this is a broadcast address */ - *pbroadcast = 1; - - /* broadcasts cannot be accepted by the hash filter */ - return((tfe_recv_broadcast || tfe_recv_promiscuous) ? 1 : 0); - } - - /* now check if DA passes the hash filter */ - hashreg = (~crc32_buf((char *)buffer,6) >> 26) & 0x3F; - - *phashed = (tfe_hash_mask[(hashreg>=32)?1:0] & (1 << (hashreg&0x1F))) ? 1 : 0; - if (*phashed) { - *phash_index = hashreg; - - if (buffer[0] & 0x80) { - /* we have a multicast address */ - *pmulticast = 1; - - /* if the multicast address fits into the hash filter, - * the hashed bit has to be clear - */ - *phashed = 0; - - return((tfe_recv_multicast || tfe_recv_promiscuous) ? 1 : 0); - } - return((tfe_recv_hashfilter || tfe_recv_promiscuous) ? 1 : 0); - } - - return(tfe_recv_promiscuous ? 1 : 0); + return(tfe_recv_promiscuous ? 1 : 0); } #ifdef TFE_DEBUG_FRAMES #undef return #endif -static -word16 tfe_receive(void) -{ - word16 ret_val = 0x0004; +static +word16 tfe_receive(void) { + word16 ret_val = 0x0004; - byte buffer[MAX_RXLENGTH]; + byte buffer[MAX_RXLENGTH]; - int len; - int hashed; - int hash_index; - int rx_ok; - int correct_mac; - int broadcast; - int multicast; - int crc_error; + int len; + int hashed; + int hash_index; + int rx_ok; + int correct_mac; + int broadcast; + int multicast; + int crc_error; - int newframe; + int newframe; - int ready; + int ready; - do { - len = MAX_RXLENGTH; + do { + len = MAX_RXLENGTH; - ready = 1 ; /* assume we will find a good frame */ + ready = 1; /* assume we will find a good frame */ - newframe = tfe_arch_receive( - buffer, /* where to store a frame */ - &len, /* length of received frame */ - &hashed, /* set if the dest. address is accepted by the hash filter */ - &hash_index, /* hash table index if hashed == TRUE */ - &rx_ok, /* set if good CRC and valid length */ - &correct_mac, /* set if dest. address is exactly our IA */ - &broadcast, /* set if dest. address is a broadcast address */ - &crc_error /* set if received frame had a CRC error */ - ); + newframe = tfe_arch_receive( + buffer, /* where to store a frame */ + &len, /* length of received frame */ + &hashed, /* set if the dest. address is accepted by the hash filter */ + &hash_index, /* hash table index if hashed == TRUE */ + &rx_ok, /* set if good CRC and valid length */ + &correct_mac, /* set if dest. address is exactly our IA */ + &broadcast, /* set if dest. address is a broadcast address */ + &crc_error /* set if received frame had a CRC error */ + ); - assert((len&1) == 0); /* length has to be even! */ + assert((len&1) == 0); /* length has to be even! */ - if (newframe) { - if (hashed || correct_mac || broadcast) { - /* we already know the type of frame: Trust it! */ + if (newframe) { + if (hashed || correct_mac || broadcast) { + /* we already know the type of frame: Trust it! */ #ifdef TFE_DEBUG_FRAMES - log_message( tfe_log, "+++ tfe_receive(): *** hashed=%u, correct_mac=%u, " - "broadcast=%u", hashed, correct_mac, broadcast); + log_message( tfe_log, "+++ tfe_receive(): *** hashed=%u, correct_mac=%u, " + "broadcast=%u", hashed, correct_mac, broadcast); #endif - } - else { - /* determine ourself the type of frame */ - if (!tfe_should_accept(buffer, - len, &hashed, &hash_index, &correct_mac, &broadcast, &multicast)) { + } + else { + /* determine ourself the type of frame */ + if (!tfe_should_accept(buffer, + len, &hashed, &hash_index, &correct_mac, &broadcast, &multicast)) { - /* if we should not accept this frame, just do nothing - * now, look for another one */ - ready = 0; /* try another frame */ - continue; - } - } - - - /* we did receive a frame, return that status */ - ret_val |= rx_ok ? 0x0100 : 0; - ret_val |= multicast ? 0x0200 : 0; - - if (!multicast) { - ret_val |= hashed ? 0x0040 : 0; - } - - if (hashed && rx_ok) { - /* we have the 2nd, special format with hash index: */ - assert(hash_index < 64); - ret_val |= hash_index << 9; - } - else { - /* we have the regular format */ - ret_val |= correct_mac ? 0x0400 : 0; - ret_val |= broadcast ? 0x0800 : 0; - ret_val |= crc_error ? 0x1000 : 0; - ret_val |= (lenMAX_RXLENGTH) ? 0x4000 : 0; - } - - /* discard any octets that are beyond the MAX_RXLEN */ - if (len>MAX_RXLENGTH) { - len = MAX_RXLENGTH; - } - - if (rx_ok) { - int i; - - /* set relevant parts of the PP area to correct values */ - SET_PP_16(TFE_PP_ADDR_RXLENGTH, len); - - for (i=0;iMAX_RXLENGTH) ? 0x4000 : 0; + } + + /* discard any octets that are beyond the MAX_RXLEN */ + if (len>MAX_RXLENGTH) { + len = MAX_RXLENGTH; + } + + if (rx_ok) { + int i; + + /* set relevant parts of the PP area to correct values */ + SET_PP_16(TFE_PP_ADDR_RXLENGTH, len); + + for (i=0; i=6) && (!odd_address)) - rx_buffer += 2; - - addr += rx_buffer; - value = GET_PP_8(addr); - rx_count++; - } - -#ifdef TFE_DEBUG_RXTX_DATA - log_message(tfe_log,"RX: %04x/%04x: %02x (buffer=%04x,odd=%d)", - rx_count,rx_length+4,value,addr,odd_address); -#endif - - /* check frame end */ - if(rx_count>=rx_length+4) { - /* reset receiver state to idle */ - rx_state = TFE_RX_IDLE; -#ifdef TFE_DEBUG_RXTX_STATE - log_message(tfe_log,"RX: read frame (length=%04x)",rx_length); -#endif - } - return value; + /* incr after RXSTATUS or RX_LENGTH even (L) read */ + if(!odd_address) + rx_buffer += 2; } + /* read frame data */ + else { + /* incr before frame read (but not in first word) */ + if((rx_count>=6) && (!odd_address)) + rx_buffer += 2; + + addr += rx_buffer; + value = GET_PP_8(addr); + rx_count++; + } + +#ifdef TFE_DEBUG_RXTX_DATA + log_message(tfe_log,"RX: %04x/%04x: %02x (buffer=%04x,odd=%d)", + rx_count,rx_length+4,value,addr,odd_address); +#endif + + /* check frame end */ + if(rx_count>=rx_length+4) { + /* reset receiver state to idle */ + rx_state = TFE_RX_IDLE; +#ifdef TFE_DEBUG_RXTX_STATE + log_message(tfe_log,"RX: read frame (length=%04x)",rx_length); +#endif + } + return value; + } } /* ------------------------------------------------------------------------- */ /* handle side-effects of read and write operations */ /* - This is called *after* the relevant octets are written -*/ + This is called *after* the relevant octets are written + */ static -void tfe_sideeffects_write_pp(word16 ppaddress, int odd_address) -{ +void tfe_sideeffects_write_pp(word16 ppaddress, int odd_address) { // const char *on_off[2] = { "on","off" }; //#define on_off_str(x) ((x) ? on_off[0] : on_off[1]) - word16 content = GET_PP_16( ppaddress ); + word16 content = GET_PP_16( ppaddress ); - assert((ppaddress & 1) == 0); + assert((ppaddress & 1) == 0); - switch (ppaddress) - { + switch (ppaddress) + { case TFE_PP_ADDR_CC_RXCFG: - /* Skip_1 Flag: remove current (partial) tx frame and restore state */ - if (content & 0x40) { - -/* tfe_arch_receive_remove_committed_frame(); */ - - /* restore tx state */ - if(tx_state!=TFE_TX_IDLE) { - tx_state = TFE_TX_IDLE; -#ifdef TFE_DEBUG_RXTX_STATE - log_message(tfe_log,"TX: skipping current frame"); -#endif - } + /* Skip_1 Flag: remove current (partial) tx frame and restore state */ + if (content & 0x40) { - /* reset transmitter */ - tfe_set_transmitter(tx_enabled); - - /* this is an "act once" bit, thus restore it to zero. */ - content &= ~0x40; - SET_PP_16( ppaddress, content ); +/* tfe_arch_receive_remove_committed_frame(); */ + + /* restore tx state */ + if(tx_state!=TFE_TX_IDLE) { + tx_state = TFE_TX_IDLE; +#ifdef TFE_DEBUG_RXTX_STATE + log_message(tfe_log,"TX: skipping current frame"); +#endif } - break; + + /* reset transmitter */ + tfe_set_transmitter(tx_enabled); + + /* this is an "act once" bit, thus restore it to zero. */ + content &= ~0x40; + SET_PP_16( ppaddress, content ); + } + break; case TFE_PP_ADDR_CC_RXCTL: - if(tfe_recv_control!=content) { - tfe_recv_broadcast = content & 0x0800; /* broadcast */ - tfe_recv_mac = content & 0x0400; /* individual address (IA) */ - tfe_recv_multicast = content & 0x0200; /* multicast if address passes the hash filter */ - tfe_recv_correct = content & 0x0100; /* accept correct frames */ - tfe_recv_promiscuous = content & 0x0080; /* promiscuous mode */ - tfe_recv_hashfilter = content & 0x0040; /* accept if IA passes the hash filter */ - tfe_recv_control = content; - - /*log_message(tfe_log,"setup receiver: broadcast=%s mac=%s multicast=%s correct=%s promiscuous=%s hashfilter=%s", - on_off_str(tfe_recv_broadcast), - on_off_str(tfe_recv_mac), - on_off_str(tfe_recv_multicast), - on_off_str(tfe_recv_correct), - on_off_str(tfe_recv_promiscuous), - on_off_str(tfe_recv_hashfilter));*/ + if(tfe_recv_control!=content) { + tfe_recv_broadcast = content & 0x0800; /* broadcast */ + tfe_recv_mac = content & 0x0400; /* individual address (IA) */ + tfe_recv_multicast = content & 0x0200; /* multicast if address passes the hash filter */ + tfe_recv_correct = content & 0x0100; /* accept correct frames */ + tfe_recv_promiscuous = content & 0x0080; /* promiscuous mode */ + tfe_recv_hashfilter = content & 0x0040; /* accept if IA passes the hash filter */ + tfe_recv_control = content; - tfe_arch_recv_ctl( tfe_recv_broadcast, - tfe_recv_mac, - tfe_recv_multicast, - tfe_recv_correct, - tfe_recv_promiscuous, - tfe_recv_hashfilter - ); - } - break; + /*log_message(tfe_log,"setup receiver: broadcast=%s mac=%s multicast=%s correct=%s promiscuous=%s hashfilter=%s", + on_off_str(tfe_recv_broadcast), + on_off_str(tfe_recv_mac), + on_off_str(tfe_recv_multicast), + on_off_str(tfe_recv_correct), + on_off_str(tfe_recv_promiscuous), + on_off_str(tfe_recv_hashfilter));*/ + + tfe_arch_recv_ctl( tfe_recv_broadcast, + tfe_recv_mac, + tfe_recv_multicast, + tfe_recv_correct, + tfe_recv_promiscuous, + tfe_recv_hashfilter + ); + } + break; case TFE_PP_ADDR_CC_LINECTL: - { - int enable_tx = (content & 0x0080) == 0x0080; - int enable_rx = (content & 0x0040) == 0x0040; - - if((enable_tx!=tx_enabled)||(enable_rx!=rx_enabled)) { - tfe_arch_line_ctl(enable_tx,enable_rx); - tfe_set_transmitter(enable_tx); - tfe_set_receiver(enable_rx); - - /*log_message(tfe_log,"line control: transmitter=%s receiver=%s", - on_off_str(enable_tx), - on_off_str(enable_rx));*/ - } - } - break; + { + int enable_tx = (content & 0x0080) == 0x0080; + int enable_rx = (content & 0x0040) == 0x0040; + + if((enable_tx!=tx_enabled)||(enable_rx!=rx_enabled)) { + tfe_arch_line_ctl(enable_tx,enable_rx); + tfe_set_transmitter(enable_tx); + tfe_set_receiver(enable_rx); + + /*log_message(tfe_log,"line control: transmitter=%s receiver=%s", + on_off_str(enable_tx), + on_off_str(enable_rx));*/ + } + } + break; case TFE_PP_ADDR_CC_SELFCTL: - { - /* reset chip? */ - if((content & 0x40)==0x40) { - tfe_reset(); - } - } - break; - + { + /* reset chip? */ + if((content & 0x40)==0x40) { + tfe_reset(); + } + } + break; + case TFE_PP_ADDR_TXCMD: - { - if(odd_address) { - word16 txcommand = GET_PP_16(TFE_PP_ADDR_TXCMD); - - /* already transmitting? */ - if(tx_state == TFE_TX_READ_BUSST) { + { + if(odd_address) { + word16 txcommand = GET_PP_16(TFE_PP_ADDR_TXCMD); + + /* already transmitting? */ + if(tx_state == TFE_TX_READ_BUSST) { #ifdef TFE_DEBUG_WARN_RXTX - log_message(tfe_log, "WARNING! Early abort of transmitted frame"); + log_message(tfe_log, "WARNING! Early abort of transmitted frame"); #endif - } - - /* The transmit status command gets the last transmit command */ - SET_PP_16(TFE_PP_ADDR_CC_TXCMD, txcommand); - - /* set transmit state */ - tx_state = TFE_TX_GOT_CMD; - tfe_set_tx_status(0,0); - -#ifdef TFE_DEBUG_RXTX_STATE - log_message(tfe_log, "TX: COMMAND accepted (%04x)",txcommand); -#endif - } } - break; + + /* The transmit status command gets the last transmit command */ + SET_PP_16(TFE_PP_ADDR_CC_TXCMD, txcommand); + + /* set transmit state */ + tx_state = TFE_TX_GOT_CMD; + tfe_set_tx_status(0,0); + +#ifdef TFE_DEBUG_RXTX_STATE + log_message(tfe_log, "TX: COMMAND accepted (%04x)",txcommand); +#endif + } + } + break; case TFE_PP_ADDR_TXLENGTH: - { - if(odd_address && (tx_state == TFE_TX_GOT_CMD)) { - word16 txlength = GET_PP_16(TFE_PP_ADDR_TXLENGTH); - word16 txcommand = GET_PP_16(TFE_PP_ADDR_CC_TXCMD); - - if(txlength<4) { - /* frame to short */ + { + if(odd_address && (tx_state == TFE_TX_GOT_CMD)) { + word16 txlength = GET_PP_16(TFE_PP_ADDR_TXLENGTH); + word16 txcommand = GET_PP_16(TFE_PP_ADDR_CC_TXCMD); + + if(txlength<4) { + /* frame to short */ #ifdef TFE_DEBUG_RXTX_STATE - log_message(tfe_log, "TX: LENGTH rejected - too short! (%04x)",txlength); + log_message(tfe_log, "TX: LENGTH rejected - too short! (%04x)",txlength); #endif - /* mask space available but do not commit */ - tx_state = TFE_TX_IDLE; - tfe_set_tx_status(1,0); - } - else if ( (txlength>MAX_TXLENGTH) - || ((txlength>MAX_TXLENGTH-4) && (!(txcommand&0x1000))) - ) { - tx_state = TFE_TX_IDLE; + /* mask space available but do not commit */ + tx_state = TFE_TX_IDLE; + tfe_set_tx_status(1,0); + } + else if ( (txlength>MAX_TXLENGTH) + || ((txlength>MAX_TXLENGTH-4) && (!(txcommand&0x1000))) + ) { + tx_state = TFE_TX_IDLE; #ifdef TFE_DEBUG_RXTX_STATE - log_message(tfe_log, "TX: LENGTH rejected - too long! (%04x)",txlength); + log_message(tfe_log, "TX: LENGTH rejected - too long! (%04x)",txlength); #endif - /* txlength too big, mark an error */ - tfe_set_tx_status(0,1); - } - else { - /* make sure we put the octets to transmit at the right place */ - tx_buffer = TFE_PP_ADDR_TX_FRAMELOC; - tx_count = 0; - tx_length = txlength; - tx_state = TFE_TX_GOT_LEN; + /* txlength too big, mark an error */ + tfe_set_tx_status(0,1); + } + else { + /* make sure we put the octets to transmit at the right place */ + tx_buffer = TFE_PP_ADDR_TX_FRAMELOC; + tx_count = 0; + tx_length = txlength; + tx_state = TFE_TX_GOT_LEN; #ifdef TFE_DEBUG_RXTX_STATE - log_message(tfe_log, "TX: LENGTH accepted (%04x)",txlength); + log_message(tfe_log, "TX: LENGTH accepted (%04x)",txlength); #endif - /* all right, signal that we're ready for the next frame */ - tfe_set_tx_status(1,0); - } - } + /* all right, signal that we're ready for the next frame */ + tfe_set_tx_status(1,0); } - break; + } + } + break; case TFE_PP_ADDR_LOG_ADDR_FILTER: case TFE_PP_ADDR_LOG_ADDR_FILTER+2: case TFE_PP_ADDR_LOG_ADDR_FILTER+4: case TFE_PP_ADDR_LOG_ADDR_FILTER+6: - { - unsigned int pos = 8 * (ppaddress - TFE_PP_ADDR_LOG_ADDR_FILTER + odd_address); - DWORD *p = (pos < 32) ? &tfe_hash_mask[0] : &tfe_hash_mask[1]; + { + unsigned int pos = 8 * (ppaddress - TFE_PP_ADDR_LOG_ADDR_FILTER + odd_address); + DWORD *p = (pos < 32) ? &tfe_hash_mask[0] : &tfe_hash_mask[1]; - *p &= ~(0xFF << pos); /* clear out relevant bits */ - *p |= GET_PP_8(ppaddress+odd_address) << pos; + *p &= ~(0xFF << pos); /* clear out relevant bits */ + *p |= GET_PP_8(ppaddress+odd_address) << pos; - // tfe_arch_set_hashfilter(tfe_hash_mask); + // tfe_arch_set_hashfilter(tfe_hash_mask); #if 0 - if(odd_address && (ppaddress == TFE_PP_ADDR_LOG_ADDR_FILTER+6)) - log_message(tfe_log,"set hash filter: %02x:%02x:%02x:%02x:%02x:%02x", - tfe_hash_mask[0], - tfe_hash_mask[1], - tfe_hash_mask[2], - tfe_hash_mask[3], - tfe_hash_mask[4], - tfe_hash_mask[5]); + if(odd_address && (ppaddress == TFE_PP_ADDR_LOG_ADDR_FILTER+6)) + log_message(tfe_log,"set hash filter: %02x:%02x:%02x:%02x:%02x:%02x", + tfe_hash_mask[0], + tfe_hash_mask[1], + tfe_hash_mask[2], + tfe_hash_mask[3], + tfe_hash_mask[4], + tfe_hash_mask[5]); #endif - } - break; + } + break; case TFE_PP_ADDR_MAC_ADDR: case TFE_PP_ADDR_MAC_ADDR+2: case TFE_PP_ADDR_MAC_ADDR+4: - /* the MAC address has been changed */ - tfe_ia_mac[ppaddress-TFE_PP_ADDR_MAC_ADDR+odd_address] = - GET_PP_8(ppaddress+odd_address); - tfe_arch_set_mac(tfe_ia_mac); - - if(odd_address && (ppaddress == TFE_PP_ADDR_MAC_ADDR+4)) - /*log_message(tfe_log,"set MAC address: %02x:%02x:%02x:%02x:%02x:%02x", - tfe_ia_mac[0],tfe_ia_mac[1],tfe_ia_mac[2], - tfe_ia_mac[3],tfe_ia_mac[4],tfe_ia_mac[5]);*/ + /* the MAC address has been changed */ + tfe_ia_mac[ppaddress-TFE_PP_ADDR_MAC_ADDR+odd_address] = + GET_PP_8(ppaddress+odd_address); + tfe_arch_set_mac(tfe_ia_mac); + + if(odd_address && (ppaddress == TFE_PP_ADDR_MAC_ADDR+4)) + /*log_message(tfe_log,"set MAC address: %02x:%02x:%02x:%02x:%02x:%02x", + tfe_ia_mac[0],tfe_ia_mac[1],tfe_ia_mac[2], + tfe_ia_mac[3],tfe_ia_mac[4],tfe_ia_mac[5]);*/ break; - } + } #undef on_off_str } /* - This is called *before* the relevant octets are read -*/ + This is called *before* the relevant octets are read + */ static -void tfe_sideeffects_read_pp(word16 ppaddress,int odd_address) -{ - switch (ppaddress) - { +void tfe_sideeffects_read_pp(word16 ppaddress,int odd_address) { + switch (ppaddress) + { case TFE_PP_ADDR_SE_RXEVENT: - /* reading this before all octets of the frame are read - performs an "implied skip" */ - { - int access_mask = (odd_address) ? 1 : 2; - - /* update the status register only if the full word of the last - status was read! unfortunately different access patterns are - possible: either the status is read LH, LH, LH... - or HL, HL, HL, or even L, L, L or H, H, H */ - if((access_mask & rxevent_read_mask)!=0) { - /* receiver is not enabled */ - if(!rx_enabled) { -#ifdef TFE_DEBUG_WARN_RXTX - log_message(tfe_log,"WARNING! Can't receive any frame (Receiver is not enabled)!"); -#endif - } else { - /* perform frame reception */ - word16 ret_val = tfe_receive(); + /* reading this before all octets of the frame are read + performs an "implied skip" */ + { + int access_mask = (odd_address) ? 1 : 2; - /* RXSTATUS and RXEVENT are the same, except that RXSTATUS buffers - the old value while RXEVENT sets a new value whenever it is called - */ - SET_PP_16(TFE_PP_ADDR_RXSTATUS, ret_val); - SET_PP_16(TFE_PP_ADDR_SE_RXEVENT, ret_val); - } - - /* reset read mask of (possible) other access */ - rxevent_read_mask = access_mask; - } else { - /* add access bit to mask */ - rxevent_read_mask |= access_mask; - } + /* update the status register only if the full word of the last + status was read! unfortunately different access patterns are + possible: either the status is read LH, LH, LH... + or HL, HL, HL, or even L, L, L or H, H, H */ + if((access_mask & rxevent_read_mask)!=0) { + /* receiver is not enabled */ + if(!rx_enabled) { +#ifdef TFE_DEBUG_WARN_RXTX + log_message(tfe_log,"WARNING! Can't receive any frame (Receiver is not enabled)!"); +#endif + } else { + /* perform frame reception */ + word16 ret_val = tfe_receive(); + + /* RXSTATUS and RXEVENT are the same, except that RXSTATUS buffers + the old value while RXEVENT sets a new value whenever it is called + */ + SET_PP_16(TFE_PP_ADDR_RXSTATUS, ret_val); + SET_PP_16(TFE_PP_ADDR_SE_RXEVENT, ret_val); } - break; + /* reset read mask of (possible) other access */ + rxevent_read_mask = access_mask; + } else { + /* add access bit to mask */ + rxevent_read_mask |= access_mask; + } + } + + break; case TFE_PP_ADDR_SE_BUSST: - if(odd_address) { - /* read busst before transmit condition is fullfilled */ - if(tx_state == TFE_TX_GOT_LEN) { - word16 bus_status = GET_PP_16(TFE_PP_ADDR_SE_BUSST); - /* check Rdy4TXNow flag */ - if((bus_status & 0x100) == 0x100) { - tx_state = TFE_TX_READ_BUSST; + if(odd_address) { + /* read busst before transmit condition is fullfilled */ + if(tx_state == TFE_TX_GOT_LEN) { + word16 bus_status = GET_PP_16(TFE_PP_ADDR_SE_BUSST); + /* check Rdy4TXNow flag */ + if((bus_status & 0x100) == 0x100) { + tx_state = TFE_TX_READ_BUSST; #ifdef TFE_DEBUG_RXTX_STATE - log_message(tfe_log, "TX: Ready4TXNow set! (%04x)", - bus_status); + log_message(tfe_log, "TX: Ready4TXNow set! (%04x)", + bus_status); #endif - } else { + } else { #ifdef TFE_DEBUG_RXTX_STATE - log_message(tfe_log, "TX: waiting for Ready4TXNow! (%04x)", - bus_status); -#endif - } - } + log_message(tfe_log, "TX: waiting for Ready4TXNow! (%04x)", + bus_status); +#endif + } } - break; - } + } + break; + } } /* ------------------------------------------------------------------------- */ /* read/write from packet page register */ /* read a register from packet page */ -static word16 tfe_read_register(word16 ppaddress) -{ +static word16 tfe_read_register(word16 ppaddress) { word16 value = GET_PP_16(ppaddress); - + /* --- check the register address --- */ if(ppaddress<0x100) { /* reserved range reads 0x0300 on real HW */ @@ -1277,18 +1258,18 @@ static word16 tfe_read_register(word16 ppaddress) return 0x0300; } } - + /* --- read control register range --- */ else if(ppaddress<0x120) { word16 regNum = ppaddress - 0x100; regNum &= ~1; - regNum ++; + regNum++; #ifdef TFE_DEBUG_REGISTERS log_message(tfe_log, "Read Control Register %04x: %04x (reg=%02x)", ppaddress,value,regNum); #endif - + /* reserved register? */ if((regNum==0x01)||(regNum==0x11)||(regNum>0x19)) { #ifdef TFE_DEBUG_WARN_REG @@ -1301,9 +1282,9 @@ static word16 tfe_read_register(word16 ppaddress) } /* make sure interal address is always valid */ - assert((value&0x3f) == regNum); + assert((value&0x3f) == regNum); } - + /* --- read status register range --- */ else if(ppaddress<0x140) { word16 regNum = ppaddress - 0x120; @@ -1332,7 +1313,7 @@ static word16 tfe_read_register(word16 ppaddress) /* make sure interal address is always valid */ assert((value&0x3f) == regNum); } - + /* --- read transmit register range --- */ else if(ppaddress<0x150) { if(ppaddress==0x144) { @@ -1362,7 +1343,7 @@ static word16 tfe_read_register(word16 ppaddress) return 0x0300; } } - + /* --- read address filter register range --- */ else if(ppaddress<0x160) { /* reserved range */ @@ -1376,10 +1357,10 @@ static word16 tfe_read_register(word16 ppaddress) return 0x0300; } } - + /* --- reserved range below 0x400 --- - returns 0x300 on real HW - */ + returns 0x300 on real HW + */ else if(ppaddress<0x400) { #ifdef TFE_DEBUG_WARN_REG log_message(tfe_log, @@ -1388,7 +1369,7 @@ static word16 tfe_read_register(word16 ppaddress) #endif return 0x0300; } - + /* --- range from 0x400 .. 0x9ff --- RX Frame */ else if(ppaddress<0xa00) { #ifdef TFE_DEBUG_WARN_REG @@ -1398,7 +1379,7 @@ static word16 tfe_read_register(word16 ppaddress) #endif return 0x0000; } - + /* --- range from 0xa00 .. 0xfff --- TX Frame */ else { #ifdef TFE_DEBUG_WARN_REG @@ -1408,13 +1389,12 @@ static word16 tfe_read_register(word16 ppaddress) #endif return 0x0000; } - + /* actually read from pp memory */ return value; } -void tfe_write_register(word16 ppaddress,word16 value) -{ +void tfe_write_register(word16 ppaddress,word16 value) { /* --- write bus interface register range --- */ if(ppaddress<0x100) { int ignore = 0; @@ -1436,7 +1416,7 @@ void tfe_write_register(word16 ppaddress,word16 value) return; } } - + /* --- write to control register range --- */ else if(ppaddress<0x120) { word16 regNum = ppaddress - 0x100; @@ -1464,7 +1444,7 @@ void tfe_write_register(word16 ppaddress,word16 value) return; } } - + /* --- write to status register range --- */ else if(ppaddress<0x140) { #ifdef TFE_DEBUG_WARN_REG @@ -1536,7 +1516,7 @@ void tfe_write_register(word16 ppaddress,word16 value) #endif return; } - else if(ppaddress<0xa00){ + else if(ppaddress<0xa00) { #ifdef TFE_DEBUG_WARN_REG log_message(tfe_log, "WARNING! Ignoring write to RX Buffer Range %04x", @@ -1554,15 +1534,14 @@ void tfe_write_register(word16 ppaddress,word16 value) } /* actually set value */ - SET_PP_16(ppaddress, value); + SET_PP_16(ppaddress, value); } #define PP_PTR_AUTO_INCR_FLAG 0x8000 /* auto increment flag in package pointer */ #define PP_PTR_FLAG_MASK 0xf000 /* is always : x y 1 1 (with x=auto incr) */ #define PP_PTR_ADDR_MASK 0x0fff /* address portion of packet page pointer */ -static void tfe_auto_incr_pp_ptr(void) -{ +static void tfe_auto_incr_pp_ptr(void) { /* perform auto increment of packet page pointer */ if((tfe_packetpage_ptr & PP_PTR_AUTO_INCR_FLAG)==PP_PTR_AUTO_INCR_FLAG) { /* pointer is always increment by one on real HW */ @@ -1581,235 +1560,232 @@ static void tfe_auto_incr_pp_ptr(void) #define LOHI_WORD(x,y) ( (word16)(x) | ( ((word16)(y)) <<8 ) ) /* ----- read byte from I/O range in VICE ----- */ -byte tfe_read(word16 io_address) -{ - byte retval,lo,hi; - word16 word_value; - word16 reg_base; +byte tfe_read(word16 io_address) { + byte retval,lo,hi; + word16 word_value; + word16 reg_base; - assert( tfe ); - assert( tfe_packetpage ); - assert( io_address < 0x10); + assert( tfe ); + assert( tfe_packetpage ); + assert( io_address < 0x10); - /*if (tfe_as_rr_net) { - // rr status register is handled by rr cartidge - if (io_address < 0x02) { - return 0; - } - io_address ^= 0x08; - }*/ - /* register base addr */ - reg_base = io_address & ~1; + /*if (tfe_as_rr_net) { + // rr status register is handled by rr cartidge + if (io_address < 0x02) { + return 0; + } + io_address ^= 0x08; + }*/ + /* register base addr */ + reg_base = io_address & ~1; - /* RX register is special as it reads from RX buffer directly */ - if((reg_base==TFE_ADDR_RXTXDATA)||(reg_base==TFE_ADDR_RXTXDATA2)) { - //io_source=IO_SOURCE_TFE_RR_NET; - return tfe_read_rx_buffer(io_address & 0x01); - } - - /* read packet page pointer */ - if(reg_base==TFE_ADDR_PP_PTR) { - word_value = tfe_packetpage_ptr; - } - /* read a register from packet page */ - else { - word16 ppaddress; - - /* determine read addr in packet page */ - switch (reg_base) { - /* PP_DATA2 behaves like PP_DATA on real HW - both show the contents at the page pointer */ - case TFE_ADDR_PP_DATA: - case TFE_ADDR_PP_DATA2: - /* mask and align address of packet pointer */ - ppaddress = tfe_packetpage_ptr & PP_PTR_ADDR_MASK; - ppaddress &= ~1; - /* if flags match then auto incr pointer */ - tfe_auto_incr_pp_ptr(); - break; - case TFE_ADDR_INTSTQUEUE: - ppaddress = TFE_PP_ADDR_SE_ISQ; - break; - case TFE_ADDR_TXCMD: - ppaddress = TFE_PP_ADDR_TXCMD; - break; - case TFE_ADDR_TXLENGTH: - ppaddress = TFE_PP_ADDR_TXLENGTH; - break; - default: - /* invalid! */ - assert(0); - break; - } - - /* do side effects before access */ - tfe_sideeffects_read_pp(ppaddress,io_address&1); - - /* read register value */ - word_value = tfe_read_register(ppaddress); - -#ifdef TFE_DEBUG_LOAD - log_message(tfe_log, "reading PP Ptr: $%04X => $%04X.",ppaddress,word_value); -#endif - } - - /* extract return value from word_value */ - lo = LO_BYTE(word_value); - hi = HI_BYTE(word_value); - if((io_address & 1) == 0) { - /* low byte on even address */ - retval = lo; - } else { - /* high byte on odd address */ - retval = hi; - } - -#ifdef TFE_DEBUG_LOAD - log_message(tfe_log, "read [$%02X] => $%02X.", io_address, retval); -#endif - - /* update _word_ value in register bank */ - tfe[reg_base] = lo; - tfe[reg_base+1] = hi; - + /* RX register is special as it reads from RX buffer directly */ + if((reg_base==TFE_ADDR_RXTXDATA)||(reg_base==TFE_ADDR_RXTXDATA2)) { //io_source=IO_SOURCE_TFE_RR_NET; - return retval; + return tfe_read_rx_buffer(io_address & 0x01); + } + + /* read packet page pointer */ + if(reg_base==TFE_ADDR_PP_PTR) { + word_value = tfe_packetpage_ptr; + } + /* read a register from packet page */ + else { + word16 ppaddress; + + /* determine read addr in packet page */ + switch (reg_base) { + /* PP_DATA2 behaves like PP_DATA on real HW + both show the contents at the page pointer */ + case TFE_ADDR_PP_DATA: + case TFE_ADDR_PP_DATA2: + /* mask and align address of packet pointer */ + ppaddress = tfe_packetpage_ptr & PP_PTR_ADDR_MASK; + ppaddress &= ~1; + /* if flags match then auto incr pointer */ + tfe_auto_incr_pp_ptr(); + break; + case TFE_ADDR_INTSTQUEUE: + ppaddress = TFE_PP_ADDR_SE_ISQ; + break; + case TFE_ADDR_TXCMD: + ppaddress = TFE_PP_ADDR_TXCMD; + break; + case TFE_ADDR_TXLENGTH: + ppaddress = TFE_PP_ADDR_TXLENGTH; + break; + default: + /* invalid! */ + assert(0); + break; + } + + /* do side effects before access */ + tfe_sideeffects_read_pp(ppaddress,io_address&1); + + /* read register value */ + word_value = tfe_read_register(ppaddress); + +#ifdef TFE_DEBUG_LOAD + log_message(tfe_log, "reading PP Ptr: $%04X => $%04X.",ppaddress,word_value); +#endif + } + + /* extract return value from word_value */ + lo = LO_BYTE(word_value); + hi = HI_BYTE(word_value); + if((io_address & 1) == 0) { + /* low byte on even address */ + retval = lo; + } else { + /* high byte on odd address */ + retval = hi; + } + +#ifdef TFE_DEBUG_LOAD + log_message(tfe_log, "read [$%02X] => $%02X.", io_address, retval); +#endif + + /* update _word_ value in register bank */ + tfe[reg_base] = lo; + tfe[reg_base+1] = hi; + + //io_source=IO_SOURCE_TFE_RR_NET; + return retval; } /* ----- write byte to I/O range of VICE ----- */ -void tfe_store(word16 io_address, byte var) -{ - word16 reg_base; - word16 word_value; - assert( tfe ); - assert( tfe_packetpage ); - assert( io_address < 0x10); +void tfe_store(word16 io_address, byte var) { + word16 reg_base; + word16 word_value; + assert( tfe ); + assert( tfe_packetpage ); + assert( io_address < 0x10); - /*if (tfe_as_rr_net) { - // rr control register is handled by rr cartidge - if (io_address < 0x02) { - return; - } - io_address ^= 0x08; - }*/ + /*if (tfe_as_rr_net) { + // rr control register is handled by rr cartidge + if (io_address < 0x02) { + return; + } + io_address ^= 0x08; + }*/ #ifdef TFE_DEBUG_STORE - log_message(tfe_log, "store [$%02X] <= $%02X.", io_address, (int)byte); + log_message(tfe_log, "store [$%02X] <= $%02X.", io_address, (int)byte); #endif - /* register base addr */ - reg_base = io_address & ~1; + /* register base addr */ + reg_base = io_address & ~1; - /* TX Register is special as it writes to TX buffer directly */ - if((reg_base==TFE_ADDR_RXTXDATA)||(reg_base==TFE_ADDR_RXTXDATA2)) { - tfe_write_tx_buffer(var,io_address & 1); - return; + /* TX Register is special as it writes to TX buffer directly */ + if((reg_base==TFE_ADDR_RXTXDATA)||(reg_base==TFE_ADDR_RXTXDATA2)) { + tfe_write_tx_buffer(var,io_address & 1); + return; + } + + /* combine stored value with new written byte */ + if((io_address & 1) == 0) { + /* overwrite low byte */ + word_value = LOHI_WORD(var,tfe[reg_base+1]); + } else { + /* overwrite high byte */ + word_value = LOHI_WORD(tfe[reg_base],var); + } + + if(reg_base==TFE_ADDR_PP_PTR) { + /* cv: we store the full package pointer in tfe_packetpage_ptr variable. + this includes the mask area (0xf000) and the addr range (0x0fff). + we ensure that the bits 0x3000 are always set (as in real HW). + odd values of the pointer are valid and supported. + only register read and write have to be mapped to word boundary. */ + word_value |= 0x3000; + tfe_packetpage_ptr = word_value; +#ifdef TFE_DEBUG_STORE + log_message(tfe_log, "set PP Ptr to $%04X.", tfe_packetpage_ptr); +#endif + } else { + /* write a register */ + + /*! \TODO: Find a reasonable default */ + word16 ppaddress = TFE_PP_ADDR_PRODUCTID; + + /* now determine address of write in packet page */ + switch(reg_base) { + case TFE_ADDR_PP_DATA: + case TFE_ADDR_PP_DATA2: + /* mask and align ppaddress from page pointer */ + ppaddress = tfe_packetpage_ptr & (MAX_PACKETPAGE_ARRAY-1); + ppaddress &= ~1; + /* auto increment pp ptr */ + tfe_auto_incr_pp_ptr(); + break; + case TFE_ADDR_TXCMD: + ppaddress = TFE_PP_ADDR_TXCMD; + break; + case TFE_ADDR_TXLENGTH: + ppaddress = TFE_PP_ADDR_TXLENGTH; + break; + case TFE_ADDR_INTSTQUEUE: + ppaddress = TFE_PP_ADDR_SE_ISQ; + break; + case TFE_ADDR_PP_PTR: + break; + default: + /* invalid */ + assert(0); + break; } - /* combine stored value with new written byte */ - if((io_address & 1) == 0) { - /* overwrite low byte */ - word_value = LOHI_WORD(var,tfe[reg_base+1]); - } else { - /* overwrite high byte */ - word_value = LOHI_WORD(tfe[reg_base],var); - } - - if(reg_base==TFE_ADDR_PP_PTR) { - /* cv: we store the full package pointer in tfe_packetpage_ptr variable. - this includes the mask area (0xf000) and the addr range (0x0fff). - we ensure that the bits 0x3000 are always set (as in real HW). - odd values of the pointer are valid and supported. - only register read and write have to be mapped to word boundary. */ - word_value |= 0x3000; - tfe_packetpage_ptr = word_value; #ifdef TFE_DEBUG_STORE - log_message(tfe_log, "set PP Ptr to $%04X.", tfe_packetpage_ptr); -#endif - } else { - /* write a register */ - - /*! \TODO: Find a reasonable default */ - word16 ppaddress = TFE_PP_ADDR_PRODUCTID; - - /* now determine address of write in packet page */ - switch(reg_base) { - case TFE_ADDR_PP_DATA: - case TFE_ADDR_PP_DATA2: - /* mask and align ppaddress from page pointer */ - ppaddress = tfe_packetpage_ptr & (MAX_PACKETPAGE_ARRAY-1); - ppaddress &= ~1; - /* auto increment pp ptr */ - tfe_auto_incr_pp_ptr(); - break; - case TFE_ADDR_TXCMD: - ppaddress = TFE_PP_ADDR_TXCMD; - break; - case TFE_ADDR_TXLENGTH: - ppaddress = TFE_PP_ADDR_TXLENGTH; - break; - case TFE_ADDR_INTSTQUEUE: - ppaddress = TFE_PP_ADDR_SE_ISQ; - break; - case TFE_ADDR_PP_PTR: - break; - default: - /* invalid */ - assert(0); - break; - } - -#ifdef TFE_DEBUG_STORE - log_message(tfe_log, "before writing to PP Ptr: $%04X <= $%04X.", - ppaddress,word_value); + log_message(tfe_log, "before writing to PP Ptr: $%04X <= $%04X.", + ppaddress,word_value); #endif - /* perform the write */ - tfe_write_register(ppaddress,word_value); + /* perform the write */ + tfe_write_register(ppaddress,word_value); - /* handle sideeffects */ - tfe_sideeffects_write_pp(ppaddress, io_address&1); + /* handle sideeffects */ + tfe_sideeffects_write_pp(ppaddress, io_address&1); - /* update word value if it was changed in write register or by side effect */ - word_value = GET_PP_16(ppaddress); + /* update word value if it was changed in write register or by side effect */ + word_value = GET_PP_16(ppaddress); #ifdef TFE_DEBUG_STORE - log_message(tfe_log, "after writing to PP Ptr: $%04X <= $%04X.", - ppaddress,word_value); + log_message(tfe_log, "after writing to PP Ptr: $%04X <= $%04X.", + ppaddress,word_value); #endif - } + } - /* update tfe registers */ - tfe[reg_base] = LO_BYTE(word_value); - tfe[reg_base+1] = HI_BYTE(word_value); + /* update tfe registers */ + tfe[reg_base] = LO_BYTE(word_value); + tfe[reg_base+1] = HI_BYTE(word_value); } /* ------------------------------------------------------------------------- */ /* resources support functions */ #if 0 -static int set_tfe_disabled(int val, void *param) -{ - /* dummy function since we don't want "disabled" to be stored on disk */ - return 0; +static int set_tfe_disabled(int val, void *param) { + /* dummy function since we don't want "disabled" to be stored on disk */ + return 0; } /*static int set_tfe_rr_net(int val, void *param) -{ + { if (!tfe_cannot_use) { if (!val) { - // TFE should not be used as rr net + // TFE should not be used as rr net if (tfe_as_rr_net) { tfe_as_rr_net = 0; - // if adapter is already enabled then reset the LAN chip + // if adapter is already enabled then reset the LAN chip if (tfe) { tfe_reset(); } } return 0; - } else { + } else { if (!tfe_as_rr_net) { tfe_as_rr_net = 1; - + // if adapter is already enabled then reset the LAN chip if (tfe) { tfe_reset(); @@ -1820,72 +1796,70 @@ static int set_tfe_disabled(int val, void *param) } return 0; -}*/ + }*/ -static int set_tfe_enabled(int val, void *param) -{ - if (!tfe_cannot_use) { - if (!val) { - /* TFE should be deactived */ - if (tfe_enabled) { - tfe_enabled = 0; - if (tfe_deactivate() < 0) { - return -1; - } - } - return 0; - } else { - if (!tfe_enabled) { - tfe_enabled = 1; - if (tfe_activate() < 0) { - return -1; - } - } - - return 0; +static int set_tfe_enabled(int val, void *param) { + if (!tfe_cannot_use) { + if (!val) { + /* TFE should be deactived */ + if (tfe_enabled) { + tfe_enabled = 0; + if (tfe_deactivate() < 0) { + return -1; } + } + return 0; + } else { + if (!tfe_enabled) { + tfe_enabled = 1; + if (tfe_activate() < 0) { + return -1; + } + } + return 0; } - return 0; + + } + return 0; } #endif /* 0 */ -int set_tfe_interface(const char *name) -{ - if (tfe_interface != NULL && name != NULL - && strcmp(name, tfe_interface) == 0) - return 0; - - util_string_set(&tfe_interface, name); - - if (tfe_enabled) { - /* ethernet is enabled, make sure that the new name is - taken account of - */ - if (tfe_deactivate() < 0) { - return -1; - } - if (tfe_activate() < 0) { - return -1; - } - - /* virtually reset the LAN chip */ - if (tfe) { - tfe_reset(); - } - } +int set_tfe_interface(const char *name) { + if (tfe_interface != NULL && name != NULL + && strcmp(name, tfe_interface) == 0) return 0; + + util_string_set(&tfe_interface, name); + + if (tfe_enabled) { + /* ethernet is enabled, make sure that the new name is + taken account of + */ + if (tfe_deactivate() < 0) { + return -1; + } + if (tfe_activate() < 0) { + return -1; + } + + /* virtually reset the LAN chip */ + if (tfe) { + tfe_reset(); + } + } + return 0; } /*static const resource_string_t resources_string[] = { - { "ETHERNET_INTERFACE", + { "ETHERNET_INTERFACE", ARCHDEP_ETHERNET_DEFAULT_DEVICE, RES_EVENT_NO, NULL, &tfe_interface, set_tfe_interface, NULL }, { NULL } -}; + }; -static const resource_int_t resources_int[] = { + static const resource_int_t resources_int[] = { { "ETHERNET_DISABLED", 0, RES_EVENT_NO, NULL, &tfe_cannot_use, set_tfe_disabled, NULL }, { "ETHERNET_ACTIVE", 0, RES_EVENT_STRICT, (resource_value_t)0, @@ -1893,21 +1867,21 @@ static const resource_int_t resources_int[] = { { "ETHERNET_AS_RR", 0, RES_EVENT_NO, NULL, &tfe_as_rr_net, set_tfe_rr_net, NULL }, { NULL } -};*/ + };*/ /*int tfe_resources_init(void) -{ + { if (resources_register_string(resources_string) < 0) return -1; return resources_register_int(resources_int); -}*/ + }*/ /* ------------------------------------------------------------------------- */ /* commandline support functions */ /*static const cmdline_option_t cmdline_options[] = -{ + { { "-tfe", SET_RESOURCE, 0, NULL, NULL, "ETHERNET_ACTIVE", (resource_value_t)1, USE_PARAM_STRING, USE_DESCRIPTION_ID, @@ -1934,12 +1908,12 @@ static const resource_int_t resources_int[] = { IDCLS_UNUSED, IDCLS_DISABLE_TFE_AS_RRNET, NULL, NULL }, { NULL } -}; + }; -int tfe_cmdline_options_init(void) -{ + int tfe_cmdline_options_init(void) + { return cmdline_register_options(cmdline_options); -}*/ + }*/ /* ------------------------------------------------------------------------- */ @@ -1951,16 +1925,14 @@ static char snap_module_name[] = "TFE1764"; #define SNAP_MAJOR 0 #define SNAP_MINOR 0 -int tfe_read_snapshot_module(struct snapshot_s *s) -{ - /* @SRT TODO: not yet implemented */ - return -1; +int tfe_read_snapshot_module(struct snapshot_s *s) { + /* @SRT TODO: not yet implemented */ + return -1; } -int tfe_write_snapshot_module(struct snapshot_s *s) -{ - /* @SRT TODO: not yet implemented */ - return -1; +int tfe_write_snapshot_module(struct snapshot_s *s) { + /* @SRT TODO: not yet implemented */ + return -1; } #endif /* #if 0 */ @@ -1968,23 +1940,20 @@ int tfe_write_snapshot_module(struct snapshot_s *s) /* ------------------------------------------------------------------------- */ /* functions for selecting and querying available NICs */ -int tfe_enumadapter_open(void) -{ - if (!tfe_arch_enumadapter_open()) { - tfe_cannot_use = 1; - return 0; - } - return 1; +int tfe_enumadapter_open(void) { + if (!tfe_arch_enumadapter_open()) { + tfe_cannot_use = 1; + return 0; + } + return 1; } -int tfe_enumadapter(char **ppname, char **ppdescription) -{ - return tfe_arch_enumadapter(ppname, ppdescription); +int tfe_enumadapter(char **ppname, char **ppdescription) { + return tfe_arch_enumadapter(ppname, ppdescription); } -int tfe_enumadapter_close(void) -{ - return tfe_arch_enumadapter_close(); +int tfe_enumadapter_close(void) { + return tfe_arch_enumadapter_close(); } //#endif /* #ifdef HAVE_TFE */ diff --git a/src/tfe/tfe.vcxproj b/src/tfe/tfe.vcxproj index f0ea25a..55aa273 100644 --- a/src/tfe/tfe.vcxproj +++ b/src/tfe/tfe.vcxproj @@ -1,108 +1,108 @@ - - - - - Debug - Win32 - - - Release - Win32 - - - - {E810477A-E004-4308-A58A-21393213EF89} - Win32Proj - tfe - - - - StaticLibrary - true - MultiByte - v140 - - - StaticLibrary - false - true - MultiByte - v140 - - - - - - - - - - - - - true - - - false - - - - NotUsing - Level3 - Disabled - WIN32;_DEBUG;_WINDOWS;_CRT_NONSTDC_NO_WARNINGS;_CRT_SECURE_NO_WARNINGS;TFE_EXPORTS;%(PreprocessorDefinitions) - Speed - false - ProgramDatabase - Default - CompileAsC - true - true - false - - - Windows - true - - - - - Level3 - NotUsing - Full - true - true - WIN32;NDEBUG;_WINDOWS;_CRT_NONSTDC_NO_WARNINGS;_CRT_SECURE_NO_WARNINGS;TFE_EXPORTS;%(PreprocessorDefinitions) - Speed - CompileAsC - false - StreamingSIMDExtensions - AnySuitable - true - - - Windows - true - true - true - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file + + + + + Debug + Win32 + + + Release + Win32 + + + + {E810477A-E004-4308-A58A-21393213EF89} + Win32Proj + tfe + + + + StaticLibrary + true + MultiByte + v120 + + + StaticLibrary + false + true + MultiByte + v120 + + + + + + + + + + + + + true + + + false + + + + NotUsing + Level3 + Disabled + WIN32;_DEBUG;_WINDOWS;_CRT_NONSTDC_NO_WARNINGS;_CRT_SECURE_NO_WARNINGS;TFE_EXPORTS;%(PreprocessorDefinitions) + Speed + false + ProgramDatabase + Default + CompileAsC + true + true + false + + + Windows + true + + + + + Level3 + NotUsing + Full + true + true + WIN32;NDEBUG;_WINDOWS;_CRT_NONSTDC_NO_WARNINGS;_CRT_SECURE_NO_WARNINGS;TFE_EXPORTS;%(PreprocessorDefinitions) + Speed + CompileAsC + false + StreamingSIMDExtensions + AnySuitable + true + + + Windows + true + true + true + + + + + + + + + + + + + + + + + + + + + diff --git a/src/tfe/tfe.vcxproj.filters b/src/tfe/tfe.vcxproj.filters index 1157911..78f75f4 100644 --- a/src/tfe/tfe.vcxproj.filters +++ b/src/tfe/tfe.vcxproj.filters @@ -1,54 +1,54 @@ - - - - - {4FC737F1-C7A5-4376-A066-2A32D752A2FF} - cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx - - - {93995380-89BD-4b04-88EB-625FBE52EBFB} - h;hpp;hxx;hm;inl;inc;xsd - - - {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} - rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms - - - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - - - Source Files - - - Source Files - - - Source Files - - - \ No newline at end of file + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + + + Source Files + + + Source Files + + + Source Files + + + diff --git a/src/tfe/tfearch.c b/src/tfe/tfearch.c index 8a5dc8a..3149fbc 100644 --- a/src/tfe/tfearch.c +++ b/src/tfe/tfearch.c @@ -1,10 +1,10 @@ /* - * tfearch.c - TFE ("The final ethernet") emulation, + * tfearch.c - TFE ("The final ethernet") emulation, * architecture-dependant stuff * * Written by * Spiro Trikaliotis - * + * * This file is part of VICE, the Versatile Commodore Emulator. * See README for copyright notice. * @@ -24,7 +24,7 @@ * 02111-1307 USA. * */ - + #include #include @@ -33,7 +33,7 @@ #include #include "../atbridge/pcap_delay.h" -#include "tfesupp.h" +#include "tfesupp.h" #include "../defc.h" #include "protos_tfe.h" @@ -60,36 +60,35 @@ static char TfePcapErrbuf[PCAP_ERRBUF_SIZE]; #ifdef TFE_DEBUG_PKTDUMP static -void debug_output( const char *text, unsigned char *what, int count ) -{ - char buffer[256]; - char *p = buffer; - char *pbuffer1 = what; - int len1 = count; - int i; +void debug_output( const char *text, unsigned char *what, int count ) { + char buffer[256]; + char *p = buffer; + char *pbuffer1 = what; + int len1 = count; + int i; - sprintf(buffer, "\n%s: length = %u\n", text, len1); + sprintf(buffer, "\n%s: length = %u\n", text, len1); + OutputDebugString(buffer); + do { + p = buffer; + for (i=0; (i<8) && len1>0; len1--, i++) { + sprintf( p, "%02x ", (unsigned int)(unsigned char)*pbuffer1++); + p += 3; + } + *(p-1) = '\n'; *p = 0; OutputDebugString(buffer); - do { - p = buffer; - for (i=0; (i<8) && len1>0; len1--, i++) { - sprintf( p, "%02x ", (unsigned int)(unsigned char)*pbuffer1++); - p += 3; - } - *(p-1) = '\n'; *p = 0; - OutputDebugString(buffer); - } while (len1>0); + } while (len1>0); } #endif // #ifdef TFE_DEBUG_PKTDUMP /* - These functions let the UI enumerate the available interfaces. + These functions let the UI enumerate the available interfaces. - First, TfeEnumAdapterOpen() is used to start enumeration. + First, TfeEnumAdapterOpen() is used to start enumeration. - TfeEnumAdapter is then used to gather information for each adapter present - on the system, where: + TfeEnumAdapter is then used to gather information for each adapter present + on the system, where: ppname points to a pointer which will hold the name of the interface ppdescription points to a pointer which will hold the description of the interface @@ -97,123 +96,119 @@ void debug_output( const char *text, unsigned char *what, int count ) For each of these parameters, new memory is allocated, so it has to be freed with lib_free(). - TfeEnumAdapterClose() must be used to stop processing. + TfeEnumAdapterClose() must be used to stop processing. - Each function returns 1 on success, and 0 on failure. - TfeEnumAdapter() only fails if there is no more adpater; in this case, - *ppname and *ppdescription are not altered. -*/ -int tfe_arch_enumadapter_open(void) -{ - if (pcapdelay_findalldevs(&TfePcapAlldevs, TfePcapErrbuf) == -1) - { + Each function returns 1 on success, and 0 on failure. + TfeEnumAdapter() only fails if there is no more adpater; in this case, + * ppname and *ppdescription are not altered. + */ +int tfe_arch_enumadapter_open(void) { + if (pcapdelay_findalldevs(&TfePcapAlldevs, TfePcapErrbuf) == -1) + { #ifdef TFE_DEBUG_ARCH - log_message(tfe_arch_log, "ERROR in TfeEnumAdapterOpen: pcap_findalldevs: '%s'", TfePcapErrbuf); + log_message(tfe_arch_log, "ERROR in TfeEnumAdapterOpen: pcap_findalldevs: '%s'", TfePcapErrbuf); #endif - return 0; - } + return 0; + } - if (!TfePcapAlldevs) { + if (!TfePcapAlldevs) { #ifdef TFE_DEBUG_ARCH - log_message(tfe_arch_log, "ERROR in TfeEnumAdapterOpen, finding all pcap devices - " - "Do we have the necessary privilege rights?"); + log_message(tfe_arch_log, "ERROR in TfeEnumAdapterOpen, finding all pcap devices - " + "Do we have the necessary privilege rights?"); #endif - return 0; - } + return 0; + } - TfePcapNextDev = TfePcapAlldevs; + TfePcapNextDev = TfePcapAlldevs; - return 1; + return 1; } -int tfe_arch_enumadapter(char **ppname, char **ppdescription) -{ - if (!TfePcapNextDev || (TfePcapNextDev->name == NULL)) - return 0; +int tfe_arch_enumadapter(char **ppname, char **ppdescription) { + if (!TfePcapNextDev || (TfePcapNextDev->name == NULL)) + return 0; - *ppname = lib_stralloc(TfePcapNextDev->name); - if (TfePcapNextDev->description) - *ppdescription = lib_stralloc(TfePcapNextDev->description); - else - *ppdescription = lib_stralloc(TfePcapNextDev->name); - TfePcapNextDev = TfePcapNextDev->next; + *ppname = lib_stralloc(TfePcapNextDev->name); + if (TfePcapNextDev->description) + *ppdescription = lib_stralloc(TfePcapNextDev->description); + else + *ppdescription = lib_stralloc(TfePcapNextDev->name); + TfePcapNextDev = TfePcapNextDev->next; - return 1; + return 1; } -int tfe_arch_enumadapter_close(void) -{ - if (TfePcapAlldevs) { - pcapdelay_freealldevs(TfePcapAlldevs); - TfePcapAlldevs = NULL; - } - return 1; +int tfe_arch_enumadapter_close(void) { + if (TfePcapAlldevs) { + pcapdelay_freealldevs(TfePcapAlldevs); + TfePcapAlldevs = NULL; + } + return 1; } static -int TfePcapOpenAdapter(const char *interface_name) -{ - pcap_if_t *TfePcapDevice = NULL; +int TfePcapOpenAdapter(const char *interface_name) { + pcap_if_t *TfePcapDevice = NULL; - if (!tfe_enumadapter_open()) { - return FALSE; - } - else { - /* look if we can find the specified adapter */ - char *pname; - char *pdescription; - int found = FALSE; + if (!tfe_enumadapter_open()) { + return FALSE; + } + else { + /* look if we can find the specified adapter */ + char *pname; + char *pdescription; + int found = FALSE; - if (interface_name) { - /* we have an interface name, try it */ - TfePcapDevice = TfePcapAlldevs; + if (interface_name) { + /* we have an interface name, try it */ + TfePcapDevice = TfePcapAlldevs; - while (tfe_enumadapter(&pname, &pdescription)) { - if (strcmp(pname, interface_name)==0) { - found = TRUE; - } - lib_free(pname); - lib_free(pdescription); - if (found) break; - TfePcapDevice = TfePcapNextDev; - } - } - - if (!found) { - /* just take the first adapter */ - TfePcapDevice = TfePcapAlldevs; + while (tfe_enumadapter(&pname, &pdescription)) { + if (strcmp(pname, interface_name)==0) { + found = TRUE; } + lib_free(pname); + lib_free(pdescription); + if (found) break; + TfePcapDevice = TfePcapNextDev; + } } - TfePcapFP = pcapdelay_open_live(TfePcapDevice->name, 1700, 1, 20, TfePcapErrbuf); - if ( TfePcapFP == NULL) - { -#ifdef TFE_DEBUG_ARCH - log_message(tfe_arch_log, "ERROR opening adapter: '%s'", TfePcapErrbuf); -#endif - tfe_enumadapter_close(); - return FALSE; + if (!found) { + /* just take the first adapter */ + TfePcapDevice = TfePcapAlldevs; } + } - if (pcapdelay_setnonblock(TfePcapFP, 1, TfePcapErrbuf)<0) - { + TfePcapFP = pcapdelay_open_live(TfePcapDevice->name, 1700, 1, 20, TfePcapErrbuf); + if ( TfePcapFP == NULL) + { #ifdef TFE_DEBUG_ARCH - log_message(tfe_arch_log, "WARNING: Setting PCAP to non-blocking failed: '%s'", TfePcapErrbuf); + log_message(tfe_arch_log, "ERROR opening adapter: '%s'", TfePcapErrbuf); #endif - } - - /* Check the link layer. We support only Ethernet for simplicity. */ - if(pcapdelay_datalink(TfePcapFP) != DLT_EN10MB) - { -#ifdef TFE_DEBUG_ARCH - log_message(tfe_arch_log, "ERROR: TFE works only on Ethernet networks."); -#endif - tfe_enumadapter_close(); - return FALSE; - } - tfe_enumadapter_close(); - return TRUE; + return FALSE; + } + + if (pcapdelay_setnonblock(TfePcapFP, 1, TfePcapErrbuf)<0) + { +#ifdef TFE_DEBUG_ARCH + log_message(tfe_arch_log, "WARNING: Setting PCAP to non-blocking failed: '%s'", TfePcapErrbuf); +#endif + } + + /* Check the link layer. We support only Ethernet for simplicity. */ + if(pcapdelay_datalink(TfePcapFP) != DLT_EN10MB) + { +#ifdef TFE_DEBUG_ARCH + log_message(tfe_arch_log, "ERROR: TFE works only on Ethernet networks."); +#endif + tfe_enumadapter_close(); + return FALSE; + } + + tfe_enumadapter_close(); + return TRUE; } @@ -221,50 +216,44 @@ int TfePcapOpenAdapter(const char *interface_name) /* the architecture-dependend functions */ -int tfe_arch_init(void) -{ - //tfe_arch_log = log_open("TFEARCH"); +int tfe_arch_init(void) { + //tfe_arch_log = log_open("TFEARCH"); - return 1; + return 1; } -void tfe_arch_pre_reset( void ) -{ +void tfe_arch_pre_reset( void ) { #ifdef TFE_DEBUG_ARCH - log_message( tfe_arch_log, "tfe_arch_pre_reset()." ); + log_message( tfe_arch_log, "tfe_arch_pre_reset()." ); #endif } -void tfe_arch_post_reset( void ) -{ +void tfe_arch_post_reset( void ) { #ifdef TFE_DEBUG_ARCH - log_message( tfe_arch_log, "tfe_arch_post_reset()." ); + log_message( tfe_arch_log, "tfe_arch_post_reset()." ); #endif } -int tfe_arch_activate(const char *interface_name) -{ +int tfe_arch_activate(const char *interface_name) { #ifdef TFE_DEBUG_ARCH - log_message( tfe_arch_log, "tfe_arch_activate()." ); + log_message( tfe_arch_log, "tfe_arch_activate()." ); #endif - if (!TfePcapOpenAdapter(interface_name)) { - return 0; - } - return 1; + if (!TfePcapOpenAdapter(interface_name)) { + return 0; + } + return 1; } -void tfe_arch_deactivate( void ) -{ +void tfe_arch_deactivate( void ) { #ifdef TFE_DEBUG_ARCH - log_message( tfe_arch_log, "tfe_arch_deactivate()." ); + log_message( tfe_arch_log, "tfe_arch_deactivate()." ); #endif } -void tfe_arch_set_mac( const unsigned char mac[6] ) -{ +void tfe_arch_set_mac( const unsigned char mac[6] ) { #if defined(TFE_DEBUG_ARCH) || defined(TFE_DEBUG_FRAMES) - log_message( tfe_arch_log, "New MAC address set: %02X:%02X:%02X:%02X:%02X:%02X.", - mac[0], mac[1], mac[2], mac[3], mac[4], mac[5] ); + log_message( tfe_arch_log, "New MAC address set: %02X:%02X:%02X:%02X:%02X:%02X.", + mac[0], mac[1], mac[2], mac[3], mac[4], mac[5] ); #endif } @@ -275,49 +264,46 @@ void tfe_arch_recv_ctl( int bBroadcast, /* broadcast */ int bCorrect, /* accept correct frames */ int bPromiscuous, /* promiscuous mode */ int bIAHash /* accept if IA passes the hash filter */ - ) -{ + ) { #if defined(TFE_DEBUG_ARCH) || defined(TFE_DEBUG_FRAMES) - log_message( tfe_arch_log, "tfe_arch_recv_ctl() called with the following parameters:" ); - log_message( tfe_arch_log, "\tbBroadcast = %s", bBroadcast ? "TRUE" : "FALSE" ); - log_message( tfe_arch_log, "\tbIA = %s", bIA ? "TRUE" : "FALSE" ); - log_message( tfe_arch_log, "\tbMulticast = %s", bMulticast ? "TRUE" : "FALSE" ); - log_message( tfe_arch_log, "\tbCorrect = %s", bCorrect ? "TRUE" : "FALSE" ); - log_message( tfe_arch_log, "\tbPromiscuous = %s", bPromiscuous ? "TRUE" : "FALSE" ); - log_message( tfe_arch_log, "\tbIAHash = %s", bIAHash ? "TRUE" : "FALSE" ); + log_message( tfe_arch_log, "tfe_arch_recv_ctl() called with the following parameters:" ); + log_message( tfe_arch_log, "\tbBroadcast = %s", bBroadcast ? "TRUE" : "FALSE" ); + log_message( tfe_arch_log, "\tbIA = %s", bIA ? "TRUE" : "FALSE" ); + log_message( tfe_arch_log, "\tbMulticast = %s", bMulticast ? "TRUE" : "FALSE" ); + log_message( tfe_arch_log, "\tbCorrect = %s", bCorrect ? "TRUE" : "FALSE" ); + log_message( tfe_arch_log, "\tbPromiscuous = %s", bPromiscuous ? "TRUE" : "FALSE" ); + log_message( tfe_arch_log, "\tbIAHash = %s", bIAHash ? "TRUE" : "FALSE" ); #endif } -void tfe_arch_line_ctl(int bEnableTransmitter, int bEnableReceiver ) -{ +void tfe_arch_line_ctl(int bEnableTransmitter, int bEnableReceiver ) { #if defined(TFE_DEBUG_ARCH) || defined(TFE_DEBUG_FRAMES) - log_message( tfe_arch_log, "tfe_arch_line_ctl() called with the following parameters:" ); - log_message( tfe_arch_log, "\tbEnableTransmitter = %s", bEnableTransmitter ? "TRUE" : "FALSE" ); - log_message( tfe_arch_log, "\tbEnableReceiver = %s", bEnableReceiver ? "TRUE" : "FALSE" ); + log_message( tfe_arch_log, "tfe_arch_line_ctl() called with the following parameters:" ); + log_message( tfe_arch_log, "\tbEnableTransmitter = %s", bEnableTransmitter ? "TRUE" : "FALSE" ); + log_message( tfe_arch_log, "\tbEnableReceiver = %s", bEnableReceiver ? "TRUE" : "FALSE" ); #endif } typedef struct TFE_PCAP_INTERNAL_tag { - unsigned int len; - unsigned char *buffer; + unsigned int len; + unsigned char *buffer; } TFE_PCAP_INTERNAL; /* Callback function invoked by libpcap for every incoming packet */ static -void TfePcapPacketHandler(unsigned char *param, const struct pcap_pkthdr *header, const unsigned char *pkt_data) -{ - TFE_PCAP_INTERNAL *pinternal = (TFE_PCAP_INTERNAL*)param; +void TfePcapPacketHandler(unsigned char *param, const struct pcap_pkthdr *header, const unsigned char *pkt_data) { + TFE_PCAP_INTERNAL *pinternal = (TFE_PCAP_INTERNAL*)param; - /* determine the count of bytes which has been returned, - * but make sure not to overrun the buffer - */ - if (header->caplen < pinternal->len) - pinternal->len = header->caplen; + /* determine the count of bytes which has been returned, + * but make sure not to overrun the buffer + */ + if (header->caplen < pinternal->len) + pinternal->len = header->caplen; - memcpy(pinternal->buffer, pkt_data, pinternal->len); + memcpy(pinternal->buffer, pkt_data, pinternal->len); } /* the following function receives a frame. @@ -325,27 +311,26 @@ void TfePcapPacketHandler(unsigned char *param, const struct pcap_pkthdr *header If there's none, it returns a -1. If there is one, it returns the length of the frame in bytes. - It copies the frame to *buffer and returns the number of copied + It copies the frame to *buffer and returns the number of copied bytes as return value. At most 'len' bytes are copied. -*/ -static -int tfe_arch_receive_frame(TFE_PCAP_INTERNAL *pinternal) -{ - int ret = -1; + */ +static +int tfe_arch_receive_frame(TFE_PCAP_INTERNAL *pinternal) { + int ret = -1; - /* check if there is something to receive */ - if (pcapdelay_dispatch(TfePcapFP, 1, (pcap_handler)TfePcapPacketHandler, (unsigned char*)pinternal)!=0) { - /* Something has been received */ - ret = pinternal->len; - } + /* check if there is something to receive */ + if (pcapdelay_dispatch(TfePcapFP, 1, (pcap_handler)TfePcapPacketHandler, (unsigned char*)pinternal)!=0) { + /* Something has been received */ + ret = pinternal->len; + } #ifdef TFE_DEBUG_ARCH - log_message( tfe_arch_log, "tfe_arch_receive_frame() called, returns %d.", ret ); + log_message( tfe_arch_log, "tfe_arch_receive_frame() called, returns %d.", ret ); #endif - return ret; + return ret; } void tfe_arch_transmit(int force, /* FORCE: Delete waiting frames in transmit buffer */ @@ -354,105 +339,103 @@ void tfe_arch_transmit(int force, /* FORCE: Delete waiting frames in trans int tx_pad_dis, /* TXPADDIS: Disable padding to 60 Bytes */ int txlength, /* Frame length */ unsigned char *txframe /* Pointer to the frame to be transmitted */ - ) -{ + ) { #ifdef TFE_DEBUG_ARCH - log_message( tfe_arch_log, "tfe_arch_transmit() called, with: " - "force = %s, onecoll = %s, inhibit_crc=%s, tx_pad_dis=%s, txlength=%u", - force ? "TRUE" : "FALSE", - onecoll ? "TRUE" : "FALSE", - inhibit_crc ? "TRUE" : "FALSE", - tx_pad_dis ? "TRUE" : "FALSE", - txlength - ); + log_message( tfe_arch_log, "tfe_arch_transmit() called, with: " + "force = %s, onecoll = %s, inhibit_crc=%s, tx_pad_dis=%s, txlength=%u", + force ? "TRUE" : "FALSE", + onecoll ? "TRUE" : "FALSE", + inhibit_crc ? "TRUE" : "FALSE", + tx_pad_dis ? "TRUE" : "FALSE", + txlength + ); #endif #ifdef TFE_DEBUG_PKTDUMP - debug_output( "Transmit frame: ", txframe, txlength); + debug_output( "Transmit frame: ", txframe, txlength); #endif // #ifdef TFE_DEBUG_PKTDUMP - if (pcapdelay_sendpacket(TfePcapFP, txframe, txlength) == -1) { - //log_message(tfe_arch_log, "WARNING! Could not send packet!"); - } + if (pcapdelay_sendpacket(TfePcapFP, txframe, txlength) == -1) { + //log_message(tfe_arch_log, "WARNING! Could not send packet!"); + } } /* - tfe_arch_receive() + tfe_arch_receive() - This function checks if there was a frame received. - If so, it returns 1, else 0. + This function checks if there was a frame received. + If so, it returns 1, else 0. - If there was no frame, none of the parameters is changed! + If there was no frame, none of the parameters is changed! - If there was a frame, the following actions are done: + If there was a frame, the following actions are done: - - at maximum *plen byte are transferred into the buffer given by pbuffer - - *plen gets the length of the received frame, EVEN if this is more + - at maximum *plen byte are transferred into the buffer given by pbuffer + - *plen gets the length of the received frame, EVEN if this is more than has been copied to pbuffer! - - if the dest. address was accepted by the hash filter, *phashed is set, else + - if the dest. address was accepted by the hash filter, *phashed is set, else cleared. - - if the dest. address was accepted by the hash filter, *phash_index is + - if the dest. address was accepted by the hash filter, *phash_index is set to the number of the rule leading to the acceptance - - if the receive was ok (good CRC and valid length), *prx_ok is set, + - if the receive was ok (good CRC and valid length), *prx_ok is set, else cleared. - - if the dest. address was accepted because it's exactly our MAC address + - if the dest. address was accepted because it's exactly our MAC address (set by tfe_arch_set_mac()), *pcorrect_mac is set, else cleared. - - if the dest. address was accepted since it was a broadcast address, - *pbroadcast is set, else cleared. - - if the received frame had a crc error, *pcrc_error is set, else cleared -*/ -int tfe_arch_receive(unsigned char *pbuffer , /* where to store a frame */ - int *plen, /* IN: maximum length of frame to copy; - OUT: length of received frame + - if the dest. address was accepted since it was a broadcast address, + * pbroadcast is set, else cleared. + - if the received frame had a crc error, *pcrc_error is set, else cleared + */ +int tfe_arch_receive(unsigned char *pbuffer, /* where to store a frame */ + int *plen, /* IN: maximum length of frame to copy; + OUT: length of received frame OUT can be bigger than IN if received frame was longer than supplied buffer */ int *phashed, /* set if the dest. address is accepted by the hash filter */ - int *phash_index, /* hash table index if hashed == TRUE */ + int *phash_index, /* hash table index if hashed == TRUE */ int *prx_ok, /* set if good CRC and valid length */ int *pcorrect_mac, /* set if dest. address is exactly our IA */ int *pbroadcast, /* set if dest. address is a broadcast address */ int *pcrc_error /* set if received frame had a CRC error */ - ) -{ - int len; + ) { + int len; - TFE_PCAP_INTERNAL internal = { *plen, pbuffer }; + TFE_PCAP_INTERNAL internal = { *plen, pbuffer }; #ifdef TFE_DEBUG_ARCH - log_message( tfe_arch_log, "tfe_arch_receive() called, with *plen=%u.", *plen ); + log_message( tfe_arch_log, "tfe_arch_receive() called, with *plen=%u.", *plen ); #endif - assert((*plen&1)==0); + assert((*plen&1)==0); - len = tfe_arch_receive_frame(&internal); + len = tfe_arch_receive_frame(&internal); - if (len!=-1) { + if (len!=-1) { #ifdef TFE_DEBUG_PKTDUMP - debug_output( "Received frame: ", internal.buffer, internal.len ); + debug_output( "Received frame: ", internal.buffer, internal.len ); #endif // #ifdef TFE_DEBUG_PKTDUMP - if (len&1) - ++len; + if (len&1) + ++len; - *plen = len; + *plen = len; - /* we don't decide if this frame fits the needs; - * by setting all zero, we let tfe.c do the work - * for us - */ - *phashed = - *phash_index = - *pbroadcast = - *pcorrect_mac = - *pcrc_error = 0; + /* we don't decide if this frame fits the needs; + * by setting all zero, we let tfe.c do the work + * for us + */ + *phashed = + *phash_index = + *pbroadcast = + *pcorrect_mac = + *pcrc_error = 0; - /* this frame has been received correctly */ - *prx_ok = 1; + /* this frame has been received correctly */ + *prx_ok = 1; - return 1; - } + return 1; + } - return 0; + return 0; } diff --git a/src/tfe/tfesupp.c b/src/tfe/tfesupp.c index b6419c3..9d647da 100644 --- a/src/tfe/tfesupp.c +++ b/src/tfe/tfesupp.c @@ -39,7 +39,7 @@ #include #include #include -#ifdef WIN32 +#ifdef WIN32 #include #include #include @@ -61,128 +61,117 @@ static unsigned long crc32_table[256]; static int crc32_is_initialized = 0; -void lib_free(void *ptr) -{ +void lib_free(void *ptr) { #ifdef LIB_DEBUG - lib_debug_free(ptr, 1, 1); + lib_debug_free(ptr, 1, 1); #endif #ifdef LIB_DEBUG - lib_debug_libc_free(ptr); + lib_debug_libc_free(ptr); #else - free(ptr); + free(ptr); #endif } -void *lib_malloc(size_t size) -{ +void *lib_malloc(size_t size) { #ifdef LIB_DEBUG - void *ptr = lib_debug_libc_malloc(size); + void *ptr = lib_debug_libc_malloc(size); #else - void *ptr = malloc(size); + void *ptr = malloc(size); #endif -#ifndef __OS2__ - if (ptr == NULL && size > 0) - exit(-1); -#endif + if (ptr == NULL && size > 0) + exit(-1); #ifdef LIB_DEBUG - lib_debug_alloc(ptr, size, 3); + lib_debug_alloc(ptr, size, 3); #endif - return ptr; + return ptr; } /*-----------------------------------------------------------------------*/ /* Malloc enough space for `str', copy `str' into it and return its address. */ -char *lib_stralloc(const char *str) -{ - size_t size; - char *ptr; +char *lib_stralloc(const char *str) { + size_t size; + char *ptr; - if (str == NULL) - exit(-1); + if (str == NULL) + exit(-1); - size = strlen(str) + 1; - ptr = (char *)lib_malloc(size); + size = strlen(str) + 1; + ptr = (char *)lib_malloc(size); - memcpy(ptr, str, size); - return ptr; + memcpy(ptr, str, size); + return ptr; } /* Like realloc, but abort if not enough memory is available. */ -void *lib_realloc(void *ptr, size_t size) -{ +void *lib_realloc(void *ptr, size_t size) { #ifdef LIB_DEBUG - void *new_ptr = lib_debug_libc_realloc(ptr, size); + void *new_ptr = lib_debug_libc_realloc(ptr, size); #else - void *new_ptr = realloc(ptr, size); + void *new_ptr = realloc(ptr, size); #endif -#ifndef __OS2__ - if (new_ptr == NULL) - exit(-1); -#endif + if (new_ptr == NULL) + exit(-1); #ifdef LIB_DEBUG - lib_debug_free(ptr, 1, 0); - lib_debug_alloc(new_ptr, size, 1); + lib_debug_free(ptr, 1, 0); + lib_debug_alloc(new_ptr, size, 1); #endif - return new_ptr; + return new_ptr; } // Util Stuff /* Set a new value to the dynamically allocated string *str. Returns `-1' if nothing has to be done. */ -int util_string_set(char **str, const char *new_value) -{ - if (*str == NULL) { - if (new_value != NULL) - *str = lib_stralloc(new_value); +int util_string_set(char **str, const char *new_value) { + if (*str == NULL) { + if (new_value != NULL) + *str = lib_stralloc(new_value); + } else { + if (new_value == NULL) { + lib_free(*str); + *str = NULL; } else { - if (new_value == NULL) { - lib_free(*str); - *str = NULL; - } else { - /* Skip copy if src and dest are already the same. */ - if (strcmp(*str, new_value) == 0) - return -1; + /* Skip copy if src and dest are already the same. */ + if (strcmp(*str, new_value) == 0) + return -1; - *str = (char *)lib_realloc(*str, strlen(new_value) + 1); - strcpy(*str, new_value); - } + *str = (char *)lib_realloc(*str, strlen(new_value) + 1); + strcpy(*str, new_value); } - return 0; + } + return 0; } // crc32 Stuff -unsigned long crc32_buf(const char *buffer, unsigned int len) -{ - int i, j; - unsigned long crc, c; - const char *p; +unsigned long crc32_buf(const char *buffer, unsigned int len) { + int i, j; + unsigned long crc, c; + const char *p; - if (!crc32_is_initialized) { - for (i = 0; i < 256; i++) { - c = (unsigned long) i; - for (j = 0; j < 8; j++) - c = c & 1 ? CRC32_POLY ^ (c >> 1) : c >> 1; - crc32_table[i] = c; - } - crc32_is_initialized = 1; + if (!crc32_is_initialized) { + for (i = 0; i < 256; i++) { + c = (unsigned long) i; + for (j = 0; j < 8; j++) + c = c & 1 ? CRC32_POLY ^ (c >> 1) : c >> 1; + crc32_table[i] = c; } + crc32_is_initialized = 1; + } - crc = 0xffffffff; - for (p = buffer; len > 0; ++p, --len) - crc = (crc >> 8) ^ crc32_table[(crc ^ *p) & 0xff]; - - return ~crc; + crc = 0xffffffff; + for (p = buffer; len > 0; ++p, --len) + crc = (crc >> 8) ^ crc32_table[(crc ^ *p) & 0xff]; + + return ~crc; } - diff --git a/src/unix_host_common.c b/src/unix_host_common.c new file mode 100644 index 0000000..d1b314d --- /dev/null +++ b/src/unix_host_common.c @@ -0,0 +1,533 @@ +/* + GSport - an Apple //gs Emulator + Copyright (C) 2010 - 2019 by GSport contributors + Copyright (C) 2016 - 2018 Dagen Brock + + Based on the KEGS emulator written by and Copyright (C) 2003 Kent Dickey + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 2 of the License, or (at your + option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#define _BSD_SOURCE + +#include +#include +#include +#include +#include +#include + +#if defined(__APPLE__) +#include +#include +#include +#endif + +#ifdef __linux__ +#include +#endif + +#if defined(__FreeBSD__) +#include +#include +#endif + +#if defined(_AIX) +#include +#endif + +#ifndef XATTR_FINDERINFO_NAME +#define XATTR_FINDERINFO_NAME "com.apple.FinderInfo" +#endif + +#ifndef XATTR_RESOURCEFORK_NAME +#define XATTR_RESOURCEFORK_NAME "com.apple.ResourceFork" +#endif + + + + +#include "defc.h" +#include "gsos.h" + +#include "host_common.h" + + +static ino_t root_ino = 0; +static dev_t root_dev = 0; + + +unsigned host_startup(void) { + + struct stat st; + + if (!g_cfg_host_path) return invalidFSTop; + if (!*g_cfg_host_path) return invalidFSTop; + if (host_root) free(host_root); + host_root = strdup(g_cfg_host_path); + + if (stat(host_root, &st) < 0) { + fprintf(stderr, "%s does not exist\n", host_root); + return invalidFSTop; + } + if (!S_ISDIR(st.st_mode)) { + fprintf(stderr, "%s is not a directory\n", host_root); + return invalidFSTop; + } + + root_ino = st.st_ino; + root_dev = st.st_dev; + + return 0; +} + +void host_shutdown(void) { + if (host_root) free(host_root); + host_root = NULL; + root_ino = 0; + root_dev = 0; +} + +int host_is_root(struct stat *st) { + return st->st_ino == root_ino && st->st_dev == root_dev; +} + + +/* + * Date/time conversion + */ + +/* + * converts time_t to a gs/os readhextime date/time record. + */ + +void host_set_date_time_rec(word32 ptr, time_t time) { + + if (time == 0) { + for (int i = 0; i < 8; ++i) set_memory_c(ptr++, 0, 0); + return; + } + + struct tm *tm = localtime(&time); + if (tm->tm_sec == 60) tm->tm_sec = 59; /* leap second */ + + set_memory_c(ptr++, tm->tm_sec, 0); + set_memory_c(ptr++, tm->tm_min, 0); + set_memory_c(ptr++, tm->tm_hour, 0); + set_memory_c(ptr++, tm->tm_year, 0); + set_memory_c(ptr++, tm->tm_mday - 1, 0); + set_memory_c(ptr++, tm->tm_mon, 0); + set_memory_c(ptr++, 0, 0); + set_memory_c(ptr++, tm->tm_wday + 1, 0); +} + +/* + * converts time_t to a prodos16 date/time record. + */ +void host_set_date_time(word32 ptr, time_t time) { + + if (time == 0) { + for (int i = 0; i < 4; ++i) set_memory_c(ptr++, 0, 0); + return; + } + + struct tm *tm = localtime(&time); + + word16 tmp = 0; + tmp |= (tm->tm_year % 100) << 9; + tmp |= tm->tm_mon << 5; + tmp |= tm->tm_mday; + + set_memory16_c(ptr, tmp, 0); + ptr += 2; + + tmp = 0; + tmp |= tm->tm_hour << 8; + tmp |= tm->tm_min; + set_memory16_c(ptr, tmp, 0); +} + +word32 host_convert_date_time(time_t time) { + + if (time == 0) return 0; + + struct tm *tm = localtime(&time); + + word16 dd = 0; + dd |= (tm->tm_year % 100) << 9; + dd |= tm->tm_mon << 5; + dd |= tm->tm_mday; + + word16 tt = 0; + tt |= tm->tm_hour << 8; + tt |= tm->tm_min; + + + return (tt << 16) | dd; +} + + +time_t host_get_date_time(word32 ptr) { + + word16 a = get_memory16_c(ptr + 0, 0); + word16 b = get_memory16_c(ptr + 2, 0); + if (!a && !b) return 0; + + struct tm tm; + memset(&tm, 0, sizeof(tm)); + + tm.tm_year = (a >> 9) & 0x7f; + tm.tm_mon = ((a >> 5) & 0x0f) - 1; + tm.tm_mday = (a >> 0) & 0x1f; + + tm.tm_hour = (b >> 8) & 0x1f; + tm.tm_min = (b >> 0) & 0x3f; + tm.tm_sec = 0; + + tm.tm_isdst = -1; + + // 00 - 39 => 2000-2039 + // 40 - 99 => 1940-1999 + if (tm.tm_year < 40) tm.tm_year += 100; + + + return mktime(&tm); +} + +time_t host_get_date_time_rec(word32 ptr) { + + byte buffer[8]; + for (int i = 0; i < 8; ++i) buffer[i] = get_memory_c(ptr++, 0); + + if (!memcmp(buffer, "\x00\x00\x00\x00\x00\x00\x00\x00", 8)) return 0; + + struct tm tm; + memset(&tm, 0, sizeof(tm)); + + tm.tm_sec = buffer[0]; + tm.tm_min = buffer[1]; + tm.tm_hour = buffer[2]; + tm.tm_year = buffer[3]; + tm.tm_mday = buffer[4] + 1; + tm.tm_mon = buffer[5]; + tm.tm_isdst = -1; + + return mktime(&tm); +} + + + +#if defined(__APPLE__) +void host_get_file_xinfo(const char *path, struct file_info *fi) { + + ssize_t tmp; + tmp = getxattr(path, XATTR_RESOURCEFORK_NAME, NULL, 0, 0, 0); + if (tmp < 0) tmp = 0; + fi->resource_eof = tmp; + fi->resource_blocks = (tmp + 511) / 512; + + tmp = getxattr(path, XATTR_FINDERINFO_NAME, fi->finder_info, 32, 0, 0); + if (tmp == 16 || tmp == 32) { + fi->has_fi = 1; + + host_finder_info_to_filetype(fi->finder_info, &fi->file_type, &fi->aux_type); + } +} +#elif defined(__sun) +void host_get_file_xinfo(const char *path, struct file_info *fi) { + + struct stat st; + + // can't stat an xattr directly? + int fd; + fd = attropen(path, XATTR_RESOURCEFORK_NAME, O_RDONLY); + if (fd >= 0) { + if (fstat(fd, &st) == 0) { + fi->resource_eof = st.st_size; + fi->resource_blocks = st.st_blocks; + } + close(fd); + } + + fd = attropen(path, XATTR_FINDERINFO_NAME, O_RDONLY); + if (fd >= 0) { + int tmp = read(fd, fi->finder_info, 32); + if (tmp == 16 || tmp == 32) { + fi->has_fi = 1; + host_finder_info_to_filetype(fi->finder_info, &fi->file_type, &fi->aux_type); + } + close(fd); + } +} +#elif defined(__linux__) +void host_get_file_xinfo(const char *path, struct file_info *fi) { + + ssize_t tmp; + tmp = getxattr(path, "user.com.apple.ResourceFork", NULL, 0); + if (tmp < 0) tmp = 0; + fi->resource_eof = tmp; + fi->resource_blocks = (tmp + 511) / 512; + + tmp = getxattr(path, "user.com.apple.FinderInfo", fi->finder_info, 32); + if (tmp == 16 || tmp == 32) { + fi->has_fi = 1; + + host_finder_info_to_filetype(fi->finder_info, &fi->file_type, &fi->aux_type); + } +} +#else +void host_get_file_xinfo(const char *path, struct file_info *fi) { +} +#endif + + + +word32 host_get_file_info(const char *path, struct file_info *fi) { + struct stat st; + memset(fi, 0, sizeof(*fi)); + + int ok = stat(path, &st); + if (ok < 0) return host_map_errno(errno); + + fi->eof = st.st_size; + fi->blocks = st.st_blocks; + + fi->create_date = st.st_ctime; + fi->modified_date = st.st_mtime; + +#if defined(__APPLE__) + fi->create_date = st.st_birthtime; +#endif + + + if (S_ISDIR(st.st_mode)) { + fi->storage_type = directoryFile; + fi->file_type = 0x0f; + if (host_is_root(&st)) + fi->storage_type = 0x0f; + } else if (S_ISREG(st.st_mode)) { + fi->file_type = 0x06; + if (st.st_size < 0x200) fi->storage_type = seedling; + else if (st.st_size < 0x20000) fi->storage_type = sapling; + else fi->storage_type = tree; + } else { + fi->storage_type = st.st_mode & S_IFMT; + fi->file_type = 0; + } + // 0x01 = read enable + // 0x02 = write enable + // 0x04 = invisible + // 0x08 = reserved + // 0x10 = reserved + // 0x20 = backup needed + // 0x40 = rename enable + // 0x80 = destroy enable + + fi->access = 0xc3; // placeholder... + + if (S_ISREG(st.st_mode)) { + host_get_file_xinfo(path, fi); + + if (!fi->has_fi) { + host_synthesize_file_xinfo(path, fi); + } + } + + // get file type/aux type + + if (fi->resource_eof) fi->storage_type = extendedFile; + + return 0; +} + + + + +#if defined(__APPLE__) +word32 host_set_file_info(const char *path, struct file_info *fi) { + + int ok; + struct attrlist list; + unsigned i = 0; + struct timespec dates[2]; + + if (fi->has_fi && fi->storage_type != 0x0d) { + ok = setxattr(path, XATTR_FINDERINFO_NAME, fi->finder_info, 32, 0, 0); + if (ok < 0) return host_map_errno(errno); + } + + + memset(&list, 0, sizeof(list)); + memset(dates, 0, sizeof(dates)); + + list.bitmapcount = ATTR_BIT_MAP_COUNT; + list.commonattr = 0; + + if (fi->create_date) + { + dates[i++].tv_sec = fi->create_date; + list.commonattr |= ATTR_CMN_CRTIME; + } + + if (fi->modified_date) + { + dates[i++].tv_sec = fi->modified_date; + list.commonattr |= ATTR_CMN_MODTIME; + } + + ok = 0; + if (i) ok = setattrlist(path, &list, dates, i * sizeof(struct timespec), 0); + return 0; +} +#elif defined(__sun) +word32 host_set_file_info(const char *path, struct file_info *fi) { + + if (fi->has_fi && fi->storage_type != 0x0d) { + int fd = attropen(path, XATTR_FINDERINFO_NAME, O_WRONLY | O_CREAT, 0666); + if (fd < 0) return host_map_errno(errno); + write(fd, fi->finder_info, 32); + close(fd); + } + + if (fi->modified_date) { + struct timeval times[2]; + + memset(times, 0, sizeof(times)); + + //times[0] = 0; // access + times[1].tv_sec = fi.modified_date; // modified + int ok = utimes(path, times); + if (ok < 0) return host_map_errno(errno); + } + return 0; +} +#elif defined(__linux__) +word32 host_set_file_info(const char *path, struct file_info *fi) { + + if (fi->has_fi && fi->storage_type != 0x0d) { + int ok = setxattr(path, "user.apple.FinderInfo", fi->finder_info, 32, 0); + if (ok < 0) return host_map_errno(errno); + } + + if (fi->modified_date) { + struct timeval times[2]; + + memset(times, 0, sizeof(times)); + + //times[0] = 0; // access + times[1].tv_sec = fi->modified_date; // modified + int ok = utimes(path, times); + if (ok < 0) return host_map_errno(errno); + } + return 0; +} + +#else + +word32 host_set_file_info(const char *path, struct file_info *fi) { + + if (fi->modified_date) { + + struct timeval times[2]; + + memset(times, 0, sizeof(times)); + + times[0] = 0; // access + times[1].tv_sec = fi->modified_date; // modified + + int ok = utimes(path, times); + if (ok < 0) return host_map_errno(errno); + } + return 0; +} + +#endif + + +static int qsort_callback(const void *a, const void *b) { + return strcasecmp(*(const char **)a, *(const char **)b); +} + +unsigned host_scan_directory(const char *path, char ***out, size_t *entries, unsigned p8) { + + DIR *dp; + char **data = NULL; + size_t capacity = 0; + size_t count = 0; + + dp = opendir(path); + if (!dp) return host_map_errno_path(errno, path); + + for(;;) { + struct dirent *d = readdir(dp); + if (!d) break; + + const char *name = d->d_name; + + if (name[0] == 0) continue; + if (name[0] == '.') continue; + if (p8) { + int ok = 1; + int n = strlen(name); + if (n > 15) continue; + /* check for invalid characters? */ + for (int i = 0; i < n; ++i) { + unsigned char c = name[i]; + if (isalpha(c) || isdigit(c) || c == '.') continue; + ok = 0; + break; + } + if (!ok) continue; + } + if (count == capacity) { + char **tmp; + tmp = realloc(data, (capacity + 100) * sizeof(char *)); + if (!tmp) { + closedir(dp); + host_free_directory(data, count); + return outOfMem; + } + data = tmp; + for (int i = count; i < capacity; ++i) data[i] = 0; + capacity += 100; + } + data[count++] = strdup(name); + } + closedir(dp); + + qsort(data, count, sizeof(char *), qsort_callback); + *entries = count; + *out = data; + + return 0; +} + +unsigned host_storage_type(const char *path, word16 *error) { + struct stat st; + if (!path) { + *error = badPathSyntax; + return 0; + } + if (stat(path, &st) < 0) { + *error = host_map_errno_path(errno, path); + return 0; + } + if (S_ISREG(st.st_mode)) { + return host_is_root(&st) ? 0x0f : directoryFile; + } + if (S_ISDIR(st.st_mode)) return standardFile; + *error = badStoreType; + return 0; +} diff --git a/src/vars_osx_sdl2 b/src/vars_osx_sdl2 new file mode 100644 index 0000000..0e0a456 --- /dev/null +++ b/src/vars_osx_sdl2 @@ -0,0 +1,21 @@ +TARGET = gsport +NAME = gsport +PERL = perl +CC = clang +LD = clang++ +AS = cc + +OBJECTS = $(OBJECTS1) $(TFEOBJ) $(ATOBJ) $(PCAPOBJ) $(FSTOBJ) sdl2_driver.o sdl2snd_driver.o fix_mac_menu.o +ARCHS = ppc, i386, ppc64, x86_64 + +# OPTIONS FOR COMPILING C SOURCE +CCOPTS = -O2 -Wall -fomit-frame-pointer -std=gnu99 -DHAVE_ICON -DHAVE_SDL `sdl2-config --cflags` +# OPTIONS FOR COMPILING C++ SOURCE +CPPOPTS = -O2 -DHAVE_TFE -DHAVE_SDL `freetype-config --cflags` `sdl2-config --cflags` + +EXTRA_LIBS = -lSDL2_image +OPTS = -DGSPORT_LITTLE_ENDIAN +SUFFIX = +LDFLAGS = `sdl2-config --static-libs` `freetype-config --libs` -framework Cocoa +LDOPTS = +EXTRA_SPECIALS = diff --git a/src/vars_osx_x11 b/src/vars_osx_x11 new file mode 100644 index 0000000..dcf94f2 --- /dev/null +++ b/src/vars_osx_x11 @@ -0,0 +1,20 @@ +TARGET = gsportx +NAME = gsportx +PERL = perl +CC = clang +LD = g++ +AS = cc + + +OBJECTS = $(OBJECTS1) $(TFEOBJ) $(ATOBJ) $(PCAPOBJ) xdriver.o +CCOPTS = -O2 -Wall -fomit-frame-pointer -std=gnu99 -DHAVE_SDL -DTOGGLE_STATUS -I/usr/local/include/SDL2 -I/usr/local/include/freetype2 -L/usr/X11/lib +CPPOPTS = -O2 -DHAVE_TFE -DHAVE_SDL -DTOGGLE_STATUS -I/usr/local/include/freetype2 -I/usr/local/include/SDL2 +OPTS = -DGSPORT_LITTLE_ENDIAN +SUFFIX = +LDFLAGS = +LDOPTS = +EXTRA_LIBS = -lX11 -lfreetype -lSDL2 -lpcap -lXext +EXTRA_SPECIALS = + + +XOPTS = -I/usr/X11/include diff --git a/src/vars_rpilinux_fb b/src/vars_rpilinux_fb new file mode 100644 index 0000000..8c8c036 --- /dev/null +++ b/src/vars_rpilinux_fb @@ -0,0 +1,18 @@ +TARGET = gsportfb +OBJECTS = $(OBJECTS1) $(TFEOBJ) $(ATOBJ) $(PCAPOBJ) fbdriver.o +CC = gcc +CCOPTS = -O2 -Wall -fomit-frame-pointer -std=gnu99 -march=armv6 +OPTS = -DGSPORT_LITTLE_ENDIAN -DHAVE_TFE -DHAVE_ATBRIDGE +SUFFIX = +NAME = gsportfb +LDFLAGS = +LDOPTS = +LD = g++ +EXTRA_LIBS = -ldl +EXTRA_SPECIALS = + +AS = cc +PERL = perl + +XOPTS = -I/usr/X11R6/include + diff --git a/src/vars_rpilinux_sdl2 b/src/vars_rpilinux_sdl2 new file mode 100644 index 0000000..d7d7f5d --- /dev/null +++ b/src/vars_rpilinux_sdl2 @@ -0,0 +1,16 @@ +TARGET = gsport +NAME = gsport +PERL = perl +CC = gcc +LD = g++ +#LD = gcc +AS = cc + +OBJECTS = $(OBJECTS1) $(TFEOBJ) $(ATOBJ) $(PCAPOBJ) $(FSTOBJ) sdl2_driver.o sdl2snd_driver.o +CCOPTS = -O2 -Wall -fomit-frame-pointer -std=gnu99 -march=armv6 +OPTS = -DGSPORT_LITTLE_ENDIAN -DHAVE_TFE -DHAVE_ATBRIDGE -DHAVE_SDL -I/usr/include/SDL2 -I/usr/include/freetype2 + +EXTRA_LIBS = -ldl -lfreetype -lSDL2 -lSDL2_image + +XOPTS = -I/usr/X11R6/include + diff --git a/src/vars_win32 b/src/vars_win32 index d784d55..d7bcb1b 100644 --- a/src/vars_win32 +++ b/src/vars_win32 @@ -1,10 +1,14 @@ -TARGET = gsport.exe -OBJECTS = $(OBJECTS1) $(TFEOBJ) $(ATOBJ) $(PCAPOBJ) scc_windriver.o win32snd_driver.o win_console.o win_generic.o gsport32.o +TARGET = gsport32.exe + +FSTOBJ = host_common.o win32_host_common.o host_mli.o win32_host_fst.o + +OBJECTS = $(OBJECTS1) $(TFEOBJ) $(ATOBJ) $(PCAPOBJ) $(FSTOBJ) scc_windriver.o win32snd_driver.o win_console.o win_generic.o gsport32.o CCOPTS = -O2 -DGSPORT_LITTLE_ENDIAN -DHAVE_TFE -DWIN_SOUND -DTOGGLE_STATUS -DWIN32 -D_WIN32 -D__USE_W32_SOCKETS -D_WINSOCK2API_ -std=gnu99 -DHAVE_ATBRIDGE CPPOPTS = -O2 -DGSPORT_LITTLE_ENDIAN -DHAVE_TFE -DTOGGLE_STATUS -DWIN32 -D_WIN32 -D__USE_W32_SOCKETS -D_WINSOCK2API_ -DHAVE_ATBRIDGE + SUFFIX = ".exe" -NAME = gsport +NAME = gsport32 EXTRA_LIBS = -Larch/win32 -lcomdlg32 -lShlwapi -lIPHlpApi XOPTS = -Wall -fomit-frame-pointer -march=i686 -XLIBS = \ No newline at end of file +XLIBS = diff --git a/src/vars_win32_sdl b/src/vars_win32_sdl index 98e353d..3c397bd 100644 --- a/src/vars_win32_sdl +++ b/src/vars_win32_sdl @@ -1,11 +1,18 @@ TARGET = gsport.exe -OBJECTS = $(OBJECTS1) $(TFEOBJ) $(ATOBJ) $(PCAPOBJ) scc_windriver.o win32snd_driver.o win_console.o win_generic.o gsport32.o -CCOPTS = -O2 -DGSPORT_LITTLE_ENDIAN -DHAVE_TFE -DWIN_SOUND -DHAVE_SDL -DTOGGLE_STATUS -DWIN32 -D_WIN32 -D__USE_W32_SOCKETS -D_WINSOCK2API_ -std=gnu99 -DHAVE_ATBRIDGE -CPPOPTS = -O2 -DGSPORT_LITTLE_ENDIAN -DHAVE_TFE -DHAVE_SDL -DTOGGLE_STATUS -DWIN32 -D_WIN32 -D__USE_W32_SOCKETS -D_WINSOCK2API_ -DHAVE_ATBRIDGE -I /usr/include/freetype2 -I/usr/include/SDL +NAME = gsport + +FSTOBJ = win32_host_fst.o + +OBJECTS = sdl2_driver.o $(OBJECTS1) $(FSTOBJ) sdl2snd_driver.o + +CCOPTS = -O2 -DGSPORT_LITTLE_ENDIAN -DHAVE_SDL -DWIN_SDL -DTOGGLE_STATUS -I/usr/include/SDL2 -L/cygdrive/c/mingw/lib -I/cygdrive/c/mingw/include/SDL2/ +CPPOPTS = -O2 -DGSPORT_LITTLE_ENDIAN -DHAVE_SDL -DWIN_SDL -DTOGGLE_STATUS -I/usr/include/freetype2 -L/cygdrive/c/mingw/lib -I/cygdrive/c/mingw/include/SDL2/ SUFFIX = ".exe" -NAME = gsport -EXTRA_LIBS = -Larch/win32 -lSDL -lfreetype -lcomdlg32 -lShlwapi -lIPHlpApi +EXTRA_LIBS = -Larch/win32 -lSDL2main -lSDL2 -lfreetype -lcomdlg32 -lShlwapi -lIPHlpApi -lcygwin +EXTRA_LIBS = -L/usr/local/lib -lcygwin -lSDL2main -lSDL2 -mwindows -lfreetype -lcomdlg32 -lShlwapi -lIPHlpApi -L/usr/lib -lpthread -lSDL2_image -L/cygdrive/c/mingw/lib -I/cygdrive/c/mingw/include/SDL2/ + + XOPTS = -Wall -fomit-frame-pointer -march=i686 -XLIBS = \ No newline at end of file +XLIBS = diff --git a/src/vars_win32_sdl2 b/src/vars_win32_sdl2 new file mode 100644 index 0000000..aca11b3 --- /dev/null +++ b/src/vars_win32_sdl2 @@ -0,0 +1,21 @@ +TARGET = gsport.exe +NAME = gsport + +MINGW_HOME = /cygdrive/c/mingw/i686-w64-mingw32 + +FSTOBJ = host_common.o win32_host_common.o host_mli.o win32_host_fst.o + +OBJECTS = sdl2_driver.o $(OBJECTS1) $(FSTOBJ) sdl2snd_driver.o scc_windriver.o + +CCOPTS = -O3 -DGSPORT_LITTLE_ENDIAN -DWIN32 -D_WIN32 -DHAVE_SDL -DWIN_SDL -DTOGGLE_STATUS -I$(MINGW_HOME)/include/SDL2 -DWINSDL_BORDERHACK -D__USE_W32_SOCKETS -D_WINSOCK2API_ +CPPOPTS = -O3 -DGSPORT_LITTLE_ENDIAN -DWIN32 -D_WIN32 -DHAVE_SDL -DWIN_SDL -DTOGGLE_STATUS -I/usr/include/freetype2 -I$(MINGW_HOME)/include/SDL2 -D__USE_W32_SOCKETS -D_WINSOCK2API_ + +SUFFIX = ".exe" +# working in cygwin +EXTRA_LIBS = -lcygwin -lSDL2main -lSDL2 -lfreetype -lcomdlg32 -lShlwapi -lIPHlpApi -lpthread -lSDL2_image -L$(MINGW_HOME)/lib/ +EXTRA_LIBS = -lcygwin -lSDL2main -lSDL2 -lfreetype -lcomdlg32 -lShlwapi -lIPHlpApi -lpthread -lSDL2_image -L$(MINGW_HOME)/lib/ -Larch/win32 -lshell32 + + + +#XOPTS = -Wall -fomit-frame-pointer -march=i686 +XLIBS = diff --git a/src/vars_x86linux_sdl b/src/vars_x86linux_sdl index b9ffa5b..a89d64a 100644 --- a/src/vars_x86linux_sdl +++ b/src/vars_x86linux_sdl @@ -1,18 +1,24 @@ -TARGET = gsportx -OBJECTS = $(OBJECTS1) $(TFEOBJ) $(ATOBJ) $(PCAPOBJ) xdriver.o -CC = gcc -CCOPTS = -O2 -Wall -fomit-frame-pointer -std=gnu99 -march=i686 -DHAVE_SDL -DHAVE_TFE -DHAVE_ATBRIDGE -DTOGGLE_STATUS -I/usr/include/SDL -I/usr/include/freetype2 -CPPOPTS = -O2 -DHAVE_TFE -DHAVE_SDL -DTOGGLE_STATUS -DHAVE_ATBRIDGE -I/usr/include/freetype2 -I/usr/include/SDL -OPTS = -DGSPORT_LITTLE_ENDIAN -SUFFIX = -NAME = gsportx -LDFLAGS = -LDOPTS = -LD = g++ -EXTRA_LIBS = -lXext -lfreetype -lSDL -EXTRA_SPECIALS = - -AS = cc -PERL = perl - -XOPTS = -I/usr/X11R6/include +TARGET = gsport +NAME = gsport +PERL = perl +CC = gcc +LD = g++ +AS = cc + +OBJECTS = $(OBJECTS1) $(TFEOBJ) $(ATOBJ) $(PCAPOBJ) $(FSTOBJ) sdl2_driver.o sdl2snd_driver.o + +# C Compiler Options +CCOPTS = -O2 -Wall -fomit-frame-pointer -std=gnu99 -DHAVE_SDL -DHAVE_TFE -DHAVE_ATBRIDGE -DTOGGLE_STATUS -I/usr/include/SDL2 -I/usr/include/freetype2 +# C++ Compiler Options +CPPOPTS = -O2 -DHAVE_TFE -DHAVE_SDL -DTOGGLE_STATUS -DHAVE_ATBRIDGE -I/usr/include/freetype2 -I/usr/include/SDL2 + +EXTRA_LIBS = -lfreetype -lSDL2 -lSDL2_image -ldl +OPTS = -DGSPORT_LITTLE_ENDIAN +SUFFIX = +LDFLAGS = +LDOPTS = + +EXTRA_SPECIALS = + + +XOPTS = -I/usr/X11R6/include diff --git a/src/vars_x86linux_sdl2 b/src/vars_x86linux_sdl2 new file mode 100644 index 0000000..2e68767 --- /dev/null +++ b/src/vars_x86linux_sdl2 @@ -0,0 +1,21 @@ +TARGET = gsport +NAME = gsport +PERL = perl +CC = gcc +LD = gcc +AS = cc + +OBJECTS = $(OBJECTS1) $(TFEOBJ) $(ATOBJ) $(PCAPOBJ) $(FSTOBJ) sdl2_driver.o sdl2snd_driver.o + +# C Compiler Options +CCOPTS = -O2 -Wall -fomit-frame-pointer -std=gnu99 -DHAVE_SDL -DHAVE_TFE -DHAVE_ATBRIDGE -DTOGGLE_STATUS -I/usr/include/SDL2 -I/usr/include/freetype2 +# C++ Compiler Options +CPPOPTS = -O2 -DHAVE_TFE -DHAVE_SDL -DTOGGLE_STATUS -DHAVE_ATBRIDGE -I/usr/include/freetype2 -I/usr/include/SDL2 + + +EXTRA_LIBS = -lfreetype -lSDL2 -lSDL2_image -ldl -lm -lstdc++ +OPTS = -DGSPORT_LITTLE_ENDIAN +SUFFIX = +LDFLAGS = +LDOPTS = -I. +EXTRA_SPECIALS = diff --git a/src/vars_x86linux_x11 b/src/vars_x86linux_x11 new file mode 100644 index 0000000..092ca73 --- /dev/null +++ b/src/vars_x86linux_x11 @@ -0,0 +1,21 @@ +TARGET = gsportx +NAME = gsportx +PERL = perl +CC = gcc +LD = g++ +AS = cc + +OBJECTS = $(OBJECTS1) $(TFEOBJ) $(ATOBJ) $(PCAPOBJ) $(FSTOBJ) xdriver.o +#-march=i686 is causing "error: CPU you selected does not support x86-64 instruction set" on ubuntu +#CCOPTS = -O2 -Wall -fomit-frame-pointer -std=gnu99 -march=i686 -DHAVE_TFE -DHAVE_ATBRIDGE -DTOGGLE_STATUS +CCOPTS = -O2 -Wall -fomit-frame-pointer -std=gnu99 -DHAVE_TFE -DHAVE_ATBRIDGE -DTOGGLE_STATUS +OPTS = -DGSPORT_LITTLE_ENDIAN +SUFFIX = +LDFLAGS = +LDOPTS = +# added -ldl for ubuntu +EXTRA_LIBS = -lXext -ldl +EXTRA_SPECIALS = + + +XOPTS = -I/usr/X11R6/include diff --git a/src/vars_x86solaris b/src/vars_x86solaris index e7a2ca8..a27f174 100644 --- a/src/vars_x86solaris +++ b/src/vars_x86solaris @@ -1,6 +1,6 @@ TARGET = gsportx -OBJECTS = $(OBJECTS1) xdriver.o +OBJECTS = $(OBJECTS1) $(FSTOBJ) xdriver.o CC = gcc CCOPTS = -O OPTS = -DNDEBUG -DSOLARIS -DGSPORT_LITTLE_ENDIAN -DSOLARISSOUND diff --git a/src/video.c b/src/video.c index 7095b3a..8318be4 100644 --- a/src/video.c +++ b/src/video.c @@ -1,6 +1,7 @@ /* GSport - an Apple //gs Emulator - Copyright (C) 2010 - 2012 by GSport contributors + Copyright (C) 2010 - 2019 by GSport contributors + Copyright (C) 2016 - 2018 Dagen Brock Based on the KEGS emulator written by and Copyright (C) 2003 Kent Dickey @@ -22,6 +23,7 @@ #include #include "defc.h" +#include "glog.h" extern int Verbose; @@ -39,8 +41,8 @@ byte g_cur_border_colors[270]; byte g_new_special_border[64][64]; byte g_cur_special_border[64][64]; -word32 g_a2_screen_buffer_changed = (word32)-1; -word32 g_full_refresh_needed = (word32)-1; +word32 g_a2_screen_buffer_changed = (word32)-1; +word32 g_full_refresh_needed = (word32)-1; word32 g_cycs_in_40col = 0; word32 g_cycs_in_xredraw = 0; @@ -80,75 +82,86 @@ Kimage g_mainwin_kimage; extern double g_last_vbl_dcycs; -double g_video_dcycs_check_input = 0.0; -int g_video_extra_check_inputs = 0; // OG Not recommended to use it (or apps might miss mouse changes) -int g_video_act_margin_left = BASE_MARGIN_LEFT; -int g_video_act_margin_right = BASE_MARGIN_RIGHT; -int g_video_act_margin_top = BASE_MARGIN_TOP; -int g_video_act_margin_bottom = BASE_MARGIN_BOTTOM; -int g_video_act_width = X_A2_WINDOW_WIDTH; -int g_video_act_height = X_A2_WINDOW_HEIGHT; +double g_video_dcycs_check_input = 0.0; +int g_video_extra_check_inputs = 0; // OG Not recommended to use it (or apps might miss mouse changes) +int g_video_act_margin_left = BASE_MARGIN_LEFT; +int g_video_act_margin_right = BASE_MARGIN_RIGHT; +int g_video_act_margin_top = BASE_MARGIN_TOP; +int g_video_act_margin_bottom = BASE_MARGIN_BOTTOM; +int g_video_act_width = X_A2_WINDOW_WIDTH; +int g_video_act_height = X_A2_WINDOW_HEIGHT; -int g_need_redraw = 1; -int g_palette_change_summary = 0; -word32 g_palette_change_cnt[16]; -int g_border_sides_refresh_needed = 1; -int g_border_special_refresh_needed = 1; -int g_border_line24_refresh_needed = 1; -int g_status_refresh_needed = 1; +int g_need_redraw = 1; +int g_palette_change_summary = 0; +word32 g_palette_change_cnt[16]; +int g_border_sides_refresh_needed = 1; +int g_border_special_refresh_needed = 1; +int g_border_line24_refresh_needed = 1; +int g_status_refresh_needed = 1; -int g_vbl_border_color = 0; -int g_border_last_vbl_changes = 0; +int g_vbl_border_color = 0; +int g_border_last_vbl_changes = 0; -int g_use_dhr140 = 0; -int g_use_bw_hires = 0; +int g_use_dhr140 = 0; +int g_use_bw_hires = 0; +int g_startx = WINDOWPOS_UNDEFINED; +int g_starty = WINDOWPOS_UNDEFINED; +int g_startw = BASE_WINDOW_WIDTH; +int g_starth = X_A2_WINDOW_HEIGHT; +int g_highdpi = 0; +int g_borderless = 0; +int g_resizeable = 0; +int g_noaspect = 0; +int g_novsync = 0; +int g_nohwaccel = 0; +int g_fullscreen_desktop = 0; -int g_a2_new_all_stat[200]; -int g_a2_cur_all_stat[200]; -int g_new_a2_stat_cur_line = 0; -int g_vid_update_last_line = 0; +int g_a2_new_all_stat[200]; +int g_a2_cur_all_stat[200]; +int g_new_a2_stat_cur_line = 0; +int g_vid_update_last_line = 0; -int g_expanded_col_0[16]; -int g_expanded_col_1[16]; -int g_expanded_col_2[16]; +int g_expanded_col_0[16]; +int g_expanded_col_1[16]; +int g_expanded_col_2[16]; int g_cur_a2_stat = ALL_STAT_TEXT | ALL_STAT_ANNUNC3 | - (0xf << BIT_ALL_STAT_TEXT_COLOR); -extern int g_save_cur_a2_stat; /* from config.c */ + (0xf << BIT_ALL_STAT_TEXT_COLOR); +extern int g_save_cur_a2_stat; /* from config.c */ -int g_a2vid_palette = 0xe; -int g_installed_full_superhires_colormap = 0; +int g_a2vid_palette = 0xe; +int g_installed_full_superhires_colormap = 0; -int Max_color_size = 256; +int Max_color_size = 256; word32 g_palette_8to1624[256]; word32 g_a2palette_8to1624[256]; -word32 g_saved_line_palettes[200][8]; -int g_saved_a2vid_palette = -1; -word32 g_a2vid_palette_remap[16]; +word32 g_saved_line_palettes[200][8]; +int g_saved_a2vid_palette = -1; +word32 g_a2vid_palette_remap[16]; word32 g_cycs_in_refresh_line = 0; word32 g_cycs_in_refresh_ximage = 0; -int g_num_lines_superhires = 0; -int g_num_lines_superhires640 = 0; -int g_num_lines_prev_superhires = 0; -int g_num_lines_prev_superhires640 = 0; +int g_num_lines_superhires = 0; +int g_num_lines_superhires640 = 0; +int g_num_lines_prev_superhires = 0; +int g_num_lines_prev_superhires640 = 0; -word32 g_red_mask = 0xff; -word32 g_green_mask = 0xff; -word32 g_blue_mask = 0xff; -int g_red_left_shift = 16; -int g_green_left_shift = 8; -int g_blue_left_shift = 0; -int g_red_right_shift = 0; -int g_green_right_shift = 0; -int g_blue_right_shift = 0; +word32 g_red_mask = 0xff; +word32 g_green_mask = 0xff; +word32 g_blue_mask = 0xff; +int g_red_left_shift = 16; +int g_green_left_shift = 8; +int g_blue_left_shift = 0; +int g_red_right_shift = 0; +int g_green_right_shift = 0; +int g_blue_right_shift = 0; -char g_status_buf[MAX_STATUS_LINES][STATUS_LINE_LENGTH + 1]; -char *g_status_ptrs[MAX_STATUS_LINES] = { 0 }; +char g_status_buf[MAX_STATUS_LINES][STATUS_LINE_LENGTH + 1]; +char *g_status_ptrs[MAX_STATUS_LINES] = { 0 }; // These LORES/DHIRES RGB values were extracted from ROM 3 IIgs video signals by Koichi Nishida #define BLACK_RGB 0x000 @@ -169,3471 +182,3372 @@ char *g_status_ptrs[MAX_STATUS_LINES] = { 0 }; #define WHITE_RGB 0xfff const int g_dbhires_colors[] = { - BLACK_RGB, // 0x0 black - DEEP_RED_RGB, // 0x1 deep red - BROWN_RGB, // 0x2 brown - ORANGE_RGB, // 0x3 orange - DARK_GREEN_RGB, // 0x4 dark green - DARK_GRAY_RGB, // 0x5 dark gray - GREEN_RGB, // 0x6 green - YELLOW_RGB, // 0x7 yellow - DARK_BLUE_RGB, // 0x8 dark blue - PURPLE_RGB, // 0x9 purple - LIGHT_GRAY_RGB, // 0xa light gray - PINK_RGB, // 0xb pink - MEDIUM_BLUE_RGB, // 0xc medium blue - LIGHT_BLUE_RGB, // 0xd light blue - AQUAMARINE_RGB, // 0xe aquamarine - WHITE_RGB // 0xf white + BLACK_RGB, // 0x0 black + DEEP_RED_RGB, // 0x1 deep red + BROWN_RGB, // 0x2 brown + ORANGE_RGB, // 0x3 orange + DARK_GREEN_RGB, // 0x4 dark green + DARK_GRAY_RGB, // 0x5 dark gray + GREEN_RGB, // 0x6 green + YELLOW_RGB, // 0x7 yellow + DARK_BLUE_RGB, // 0x8 dark blue + PURPLE_RGB, // 0x9 purple + LIGHT_GRAY_RGB, // 0xa light gray + PINK_RGB, // 0xb pink + MEDIUM_BLUE_RGB, // 0xc medium blue + LIGHT_BLUE_RGB, // 0xd light blue + AQUAMARINE_RGB, // 0xe aquamarine + WHITE_RGB // 0xf white }; -word32 g_dhires_convert[4096]; /* look up table of 7 bits (concat): */ - /* { 4 bits, |3 prev bits| } */ +word32 g_dhires_convert[4096]; /* look up table of 7 bits (concat): */ + /* { 4 bits, |3 prev bits| } */ const byte g_dhires_colors_16[] = { - 0x00, // 0x0 black - 0x02, // 0x1 dark blue - 0x04, // 0x2 dark green - 0x06, // 0x3 medium blue - 0x08, // 0x4 brown - 0x0a, // 0x5 light gray - 0x0c, // 0x6 green - 0x0e, // 0x7 aquamarine - 0x01, // 0x8 deep red - 0x03, // 0x9 purple - 0x05, // 0xa dark gray - 0x07, // 0xb light blue - 0x09, // 0xc orange - 0x0b, // 0xd pink - 0x0d, // 0xe yellow - 0x0f // 0xf white + 0x00, // 0x0 black + 0x02, // 0x1 dark blue + 0x04, // 0x2 dark green + 0x06, // 0x3 medium blue + 0x08, // 0x4 brown + 0x0a, // 0x5 light gray + 0x0c, // 0x6 green + 0x0e, // 0x7 aquamarine + 0x01, // 0x8 deep red + 0x03, // 0x9 purple + 0x05, // 0xa dark gray + 0x07, // 0xb light blue + 0x09, // 0xc orange + 0x0b, // 0xd pink + 0x0d, // 0xe yellow + 0x0f // 0xf white }; -int g_lores_colors[] = { - BLACK_RGB, // 0x0 black - DEEP_RED_RGB, // 0x1 deep red - DARK_BLUE_RGB, // 0x2 dark blue - PURPLE_RGB, // 0x3 purple - DARK_GREEN_RGB, // 0x4 dark green - DARK_GRAY_RGB, // 0x5 dark gray - MEDIUM_BLUE_RGB, // 0x6 medium blue - LIGHT_BLUE_RGB, // 0x7 light blue - BROWN_RGB, // 0x8 brown - ORANGE_RGB, // 0x9 orange - LIGHT_GRAY_RGB, // 0xa light gray - PINK_RGB, // 0xb pink - GREEN_RGB, // 0xc green - YELLOW_RGB, // 0xd yellow - AQUAMARINE_RGB, // 0xe aquamarine - WHITE_RGB // 0xf white +int g_lores_colors[] = { + BLACK_RGB, // 0x0 black + DEEP_RED_RGB, // 0x1 deep red + DARK_BLUE_RGB, // 0x2 dark blue + PURPLE_RGB, // 0x3 purple + DARK_GREEN_RGB, // 0x4 dark green + DARK_GRAY_RGB, // 0x5 dark gray + MEDIUM_BLUE_RGB, // 0x6 medium blue + LIGHT_BLUE_RGB, // 0x7 light blue + BROWN_RGB, // 0x8 brown + ORANGE_RGB, // 0x9 orange + LIGHT_GRAY_RGB, // 0xa light gray + PINK_RGB, // 0xb pink + GREEN_RGB, // 0xc green + YELLOW_RGB, // 0xd yellow + AQUAMARINE_RGB, // 0xe aquamarine + WHITE_RGB // 0xf white }; const word32 g_bw_hires_convert[4] = { - BIGEND(0x00000000), - BIGEND(0x0f0f0000), - BIGEND(0x00000f0f), - BIGEND(0x0f0f0f0f) + BIGEND(0x00000000), + BIGEND(0x0f0f0000), + BIGEND(0x00000f0f), + BIGEND(0x0f0f0f0f) }; const word32 g_bw_dhires_convert[16] = { - BIGEND(0x00000000), - BIGEND(0x0f000000), - BIGEND(0x000f0000), - BIGEND(0x0f0f0000), + BIGEND(0x00000000), + BIGEND(0x0f000000), + BIGEND(0x000f0000), + BIGEND(0x0f0f0000), - BIGEND(0x00000f00), - BIGEND(0x0f000f00), - BIGEND(0x000f0f00), - BIGEND(0x0f0f0f00), + BIGEND(0x00000f00), + BIGEND(0x0f000f00), + BIGEND(0x000f0f00), + BIGEND(0x0f0f0f00), - BIGEND(0x0000000f), - BIGEND(0x0f00000f), - BIGEND(0x000f000f), - BIGEND(0x0f0f000f), + BIGEND(0x0000000f), + BIGEND(0x0f00000f), + BIGEND(0x000f000f), + BIGEND(0x0f0f000f), - BIGEND(0x00000f0f), - BIGEND(0x0f000f0f), - BIGEND(0x000f0f0f), - BIGEND(0x0f0f0f0f), + BIGEND(0x00000f0f), + BIGEND(0x0f000f0f), + BIGEND(0x000f0f0f), + BIGEND(0x0f0f0f0f), }; const word32 g_hires_convert[64] = { - BIGEND(0x00000000), /* 00,0000 = black, black, black, black */ - BIGEND(0x00000000), /* 00,0001 = black, black, black, black */ - BIGEND(0x03030000), /* 00,0010 = purp , purp , black, black */ - BIGEND(0x0f0f0000), /* 00,0011 = white, white, black, black */ - BIGEND(0x00000c0c), /* 00,0100 = black, black, green, green */ - BIGEND(0x0c0c0c0c), /* 00,0101 = green, green, green, green */ - BIGEND(0x0f0f0f0f), /* 00,0110 = white, white, white, white */ - BIGEND(0x0f0f0f0f), /* 00,0111 = white, white, white, white */ - BIGEND(0x00000000), /* 00,1000 = black, black, black, black */ - BIGEND(0x00000000), /* 00,1001 = black, black, black, black */ - BIGEND(0x03030303), /* 00,1010 = purp , purp , purp , purp */ - BIGEND(0x0f0f0303), /* 00,1011 = white ,white, purp , purp */ - BIGEND(0x00000f0f), /* 00,1100 = black ,black, white, white */ - BIGEND(0x0c0c0f0f), /* 00,1101 = green ,green, white, white */ - BIGEND(0x0f0f0f0f), /* 00,1110 = white ,white, white, white */ - BIGEND(0x0f0f0f0f), /* 00,1111 = white ,white, white, white */ + BIGEND(0x00000000), /* 00,0000 = black, black, black, black */ + BIGEND(0x00000000), /* 00,0001 = black, black, black, black */ + BIGEND(0x03030000), /* 00,0010 = purp , purp , black, black */ + BIGEND(0x0f0f0000), /* 00,0011 = white, white, black, black */ + BIGEND(0x00000c0c), /* 00,0100 = black, black, green, green */ + BIGEND(0x0c0c0c0c), /* 00,0101 = green, green, green, green */ + BIGEND(0x0f0f0f0f), /* 00,0110 = white, white, white, white */ + BIGEND(0x0f0f0f0f), /* 00,0111 = white, white, white, white */ + BIGEND(0x00000000), /* 00,1000 = black, black, black, black */ + BIGEND(0x00000000), /* 00,1001 = black, black, black, black */ + BIGEND(0x03030303), /* 00,1010 = purp , purp , purp , purp */ + BIGEND(0x0f0f0303), /* 00,1011 = white ,white, purp , purp */ + BIGEND(0x00000f0f), /* 00,1100 = black ,black, white, white */ + BIGEND(0x0c0c0f0f), /* 00,1101 = green ,green, white, white */ + BIGEND(0x0f0f0f0f), /* 00,1110 = white ,white, white, white */ + BIGEND(0x0f0f0f0f), /* 00,1111 = white ,white, white, white */ - BIGEND(0x00000000), /* 01,0000 = black, black, black, black */ - BIGEND(0x00000000), /* 01,0001 = black, black, black, black */ - BIGEND(0x06060000), /* 01,0010 = blue , blue , black, black */ - BIGEND(0x0f0f0000), /* 01,0011 = white, white, black, black */ - BIGEND(0x00000c0c), /* 01,0100 = black, black, green, green */ - BIGEND(0x09090c0c), /* 01,0101 = orang, orang, green, green */ - BIGEND(0x0f0f0f0f), /* 01,0110 = white, white, white, white */ - BIGEND(0x0f0f0f0f), /* 01,0111 = white, white, white, white */ - BIGEND(0x00000000), /* 01,1000 = black, black, black, black */ - BIGEND(0x00000000), /* 01,1001 = black, black, black, black */ - BIGEND(0x06060303), /* 01,1010 = blue , blue , purp , purp */ - BIGEND(0x0f0f0303), /* 01,1011 = white ,white, purp , purp */ - BIGEND(0x00000f0f), /* 01,1100 = black ,black, white, white */ - BIGEND(0x09090f0f), /* 01,1101 = orang ,orang, white, white */ - BIGEND(0x0f0f0f0f), /* 01,1110 = white ,white, white, white */ - BIGEND(0x0f0f0f0f), /* 01,1111 = white ,white, white, white */ + BIGEND(0x00000000), /* 01,0000 = black, black, black, black */ + BIGEND(0x00000000), /* 01,0001 = black, black, black, black */ + BIGEND(0x06060000), /* 01,0010 = blue , blue , black, black */ + BIGEND(0x0f0f0000), /* 01,0011 = white, white, black, black */ + BIGEND(0x00000c0c), /* 01,0100 = black, black, green, green */ + BIGEND(0x09090c0c), /* 01,0101 = orang, orang, green, green */ + BIGEND(0x0f0f0f0f), /* 01,0110 = white, white, white, white */ + BIGEND(0x0f0f0f0f), /* 01,0111 = white, white, white, white */ + BIGEND(0x00000000), /* 01,1000 = black, black, black, black */ + BIGEND(0x00000000), /* 01,1001 = black, black, black, black */ + BIGEND(0x06060303), /* 01,1010 = blue , blue , purp , purp */ + BIGEND(0x0f0f0303), /* 01,1011 = white ,white, purp , purp */ + BIGEND(0x00000f0f), /* 01,1100 = black ,black, white, white */ + BIGEND(0x09090f0f), /* 01,1101 = orang ,orang, white, white */ + BIGEND(0x0f0f0f0f), /* 01,1110 = white ,white, white, white */ + BIGEND(0x0f0f0f0f), /* 01,1111 = white ,white, white, white */ - BIGEND(0x00000000), /* 10,0000 = black, black, black, black */ - BIGEND(0x00000000), /* 10,0001 = black, black, black, black */ - BIGEND(0x03030000), /* 10,0010 = purp , purp , black, black */ - BIGEND(0x0f0f0000), /* 10,0011 = white, white, black, black */ - BIGEND(0x00000909), /* 10,0100 = black, black, orang, orang */ - BIGEND(0x0c0c0909), /* 10,0101 = green, green, orang, orang */ - BIGEND(0x0f0f0f0f), /* 10,0110 = white, white, white, white */ - BIGEND(0x0f0f0f0f), /* 10,0111 = white, white, white, white */ - BIGEND(0x00000000), /* 10,1000 = black, black, black, black */ - BIGEND(0x00000000), /* 10,1001 = black, black, black, black */ - BIGEND(0x03030606), /* 10,1010 = purp , purp , blue , blue */ - BIGEND(0x0f0f0606), /* 10,1011 = white ,white, blue , blue */ - BIGEND(0x00000f0f), /* 10,1100 = black ,black, white, white */ - BIGEND(0x0c0c0f0f), /* 10,1101 = green ,green, white, white */ - BIGEND(0x0f0f0f0f), /* 10,1110 = white ,white, white, white */ - BIGEND(0x0f0f0f0f), /* 10,1111 = white ,white, white, white */ + BIGEND(0x00000000), /* 10,0000 = black, black, black, black */ + BIGEND(0x00000000), /* 10,0001 = black, black, black, black */ + BIGEND(0x03030000), /* 10,0010 = purp , purp , black, black */ + BIGEND(0x0f0f0000), /* 10,0011 = white, white, black, black */ + BIGEND(0x00000909), /* 10,0100 = black, black, orang, orang */ + BIGEND(0x0c0c0909), /* 10,0101 = green, green, orang, orang */ + BIGEND(0x0f0f0f0f), /* 10,0110 = white, white, white, white */ + BIGEND(0x0f0f0f0f), /* 10,0111 = white, white, white, white */ + BIGEND(0x00000000), /* 10,1000 = black, black, black, black */ + BIGEND(0x00000000), /* 10,1001 = black, black, black, black */ + BIGEND(0x03030606), /* 10,1010 = purp , purp , blue , blue */ + BIGEND(0x0f0f0606), /* 10,1011 = white ,white, blue , blue */ + BIGEND(0x00000f0f), /* 10,1100 = black ,black, white, white */ + BIGEND(0x0c0c0f0f), /* 10,1101 = green ,green, white, white */ + BIGEND(0x0f0f0f0f), /* 10,1110 = white ,white, white, white */ + BIGEND(0x0f0f0f0f), /* 10,1111 = white ,white, white, white */ - BIGEND(0x00000000), /* 11,0000 = black, black, black, black */ - BIGEND(0x00000000), /* 11,0001 = black, black, black, black */ - BIGEND(0x06060000), /* 11,0010 = blue , blue , black, black */ - BIGEND(0x0f0f0000), /* 11,0011 = white, white, black, black */ - BIGEND(0x00000909), /* 11,0100 = black, black, orang, orang */ - BIGEND(0x09090909), /* 11,0101 = orang, orang, orang, orang */ - BIGEND(0x0f0f0f0f), /* 11,0110 = white, white, white, white */ - BIGEND(0x0f0f0f0f), /* 11,0111 = white, white, white, white */ - BIGEND(0x00000000), /* 11,1000 = black, black, black, black */ - BIGEND(0x00000000), /* 11,1001 = black, black, black, black */ - BIGEND(0x06060606), /* 11,1010 = blue , blue , blue , blue */ - BIGEND(0x0f0f0606), /* 11,1011 = white ,white, blue , blue */ - BIGEND(0x00000f0f), /* 11,1100 = black ,black, white, white */ - BIGEND(0x09090f0f), /* 11,1101 = orang ,orang, white, white */ - BIGEND(0x0f0f0f0f), /* 11,1110 = white ,white, white, white */ - BIGEND(0x0f0f0f0f), /* 11,1111 = white ,white, white, white */ + BIGEND(0x00000000), /* 11,0000 = black, black, black, black */ + BIGEND(0x00000000), /* 11,0001 = black, black, black, black */ + BIGEND(0x06060000), /* 11,0010 = blue , blue , black, black */ + BIGEND(0x0f0f0000), /* 11,0011 = white, white, black, black */ + BIGEND(0x00000909), /* 11,0100 = black, black, orang, orang */ + BIGEND(0x09090909), /* 11,0101 = orang, orang, orang, orang */ + BIGEND(0x0f0f0f0f), /* 11,0110 = white, white, white, white */ + BIGEND(0x0f0f0f0f), /* 11,0111 = white, white, white, white */ + BIGEND(0x00000000), /* 11,1000 = black, black, black, black */ + BIGEND(0x00000000), /* 11,1001 = black, black, black, black */ + BIGEND(0x06060606), /* 11,1010 = blue , blue , blue , blue */ + BIGEND(0x0f0f0606), /* 11,1011 = white ,white, blue , blue */ + BIGEND(0x00000f0f), /* 11,1100 = black ,black, white, white */ + BIGEND(0x09090f0f), /* 11,1101 = orang ,orang, white, white */ + BIGEND(0x0f0f0f0f), /* 11,1110 = white ,white, white, white */ + BIGEND(0x0f0f0f0f), /* 11,1111 = white ,white, white, white */ }; - int g_screen_index[] = { - 0x000, 0x080, 0x100, 0x180, 0x200, 0x280, 0x300, 0x380, - 0x028, 0x0a8, 0x128, 0x1a8, 0x228, 0x2a8, 0x328, 0x3a8, - 0x050, 0x0d0, 0x150, 0x1d0, 0x250, 0x2d0, 0x350, 0x3d0 +int g_screen_index[] = { + 0x000, 0x080, 0x100, 0x180, 0x200, 0x280, 0x300, 0x380, + 0x028, 0x0a8, 0x128, 0x1a8, 0x228, 0x2a8, 0x328, 0x3a8, + 0x050, 0x0d0, 0x150, 0x1d0, 0x250, 0x2d0, 0x350, 0x3d0 }; -void -video_init() -{ - word32 col[4]; - Kimage *kimage_ptr; - word32 *ptr; - word32 val0, val1, val2, val3; - word32 match_col; - word32 next_col, next2_col, next3_col; - word32 val; - word32 cur_col; - int width, height; - int total_bytes; - int i, j; +void video_init() { + word32 col[4]; + Kimage *kimage_ptr; + word32 *ptr; + word32 val0, val1, val2, val3; + word32 match_col; + word32 next_col, next2_col, next3_col; + word32 val; + word32 cur_col; + int width, height; + int total_bytes; + int i, j; /* Initialize video system */ -// OG Reinit globals - g_a2_screen_buffer_changed = (word32)-1; - g_full_refresh_needed = (word32)-1; - g_cycs_in_40col = 0; - g_cycs_in_xredraw = 0; - g_refresh_bytes_xfer = 0; +// OG Reinit globals + g_a2_screen_buffer_changed = (word32)-1; + g_full_refresh_needed = (word32)-1; + g_cycs_in_40col = 0; + g_cycs_in_xredraw = 0; + g_refresh_bytes_xfer = 0; - g_video_dcycs_check_input = 0.0; - //g_video_extra_check_inputs = 0; - g_video_act_margin_left = BASE_MARGIN_LEFT; - g_video_act_margin_right = BASE_MARGIN_RIGHT; - g_video_act_margin_top = BASE_MARGIN_TOP; - g_video_act_margin_bottom = BASE_MARGIN_BOTTOM; - g_video_act_width = X_A2_WINDOW_WIDTH; - g_video_act_height = X_A2_WINDOW_HEIGHT; - - g_need_redraw = 1; - g_palette_change_summary = 0; - - g_border_sides_refresh_needed = 1; - g_border_special_refresh_needed = 1; - g_border_line24_refresh_needed = 1; - g_status_refresh_needed = 1; - - g_vbl_border_color = 0; - g_border_last_vbl_changes = 0; - - g_use_dhr140 = 0; - g_use_bw_hires = 0; - - g_new_a2_stat_cur_line = 0; - g_vid_update_last_line = 0; - - g_cur_a2_stat = ALL_STAT_TEXT | ALL_STAT_ANNUNC3 |(0xf << BIT_ALL_STAT_TEXT_COLOR); - - - g_a2vid_palette = 0xe; - g_installed_full_superhires_colormap = 0; - - Max_color_size = 256; - - g_saved_a2vid_palette = -1; - - g_cycs_in_refresh_line = 0; - g_cycs_in_refresh_ximage = 0; - - g_num_lines_superhires = 0; - g_num_lines_superhires640 = 0; - g_num_lines_prev_superhires = 0; - g_num_lines_prev_superhires640 = 0; - - /* - g_red_mask = 0xff; - g_green_mask = 0xff; - g_blue_mask = 0xff; - g_red_left_shift = 16; - g_green_left_shift = 8; - g_blue_left_shift = 0; - g_red_right_shift = 0; - g_green_right_shift = 0; - g_blue_right_shift = 0; -*/ - -/* Initialize video system */ - - for(i = 0; i < 200; i++) { - g_a2_line_kimage[i] = (Kimage *)0; // OG Changed from void* to kimage* - g_a2_line_stat[i] = -1; - g_a2_line_left_edge[i] = 0; - g_a2_line_right_edge[i] = 0; - } - for(i = 0; i < 200; i++) { - g_a2_new_all_stat[i] = 0; - g_a2_cur_all_stat[i] = 1; - for(j = 0; j < 8; j++) { - g_saved_line_palettes[i][j] = (word32)-1; - } - } - for(i = 0; i < 262; i++) { - g_cur_border_colors[i] = -1; - } - - g_new_a2_stat_cur_line = 0; + g_video_dcycs_check_input = 0.0; + //g_video_extra_check_inputs = 0; + g_video_act_margin_left = BASE_MARGIN_LEFT; + g_video_act_margin_right = BASE_MARGIN_RIGHT; + g_video_act_margin_top = BASE_MARGIN_TOP; + g_video_act_margin_bottom = BASE_MARGIN_BOTTOM; + g_video_act_width = X_A2_WINDOW_WIDTH; + g_video_act_height = X_A2_WINDOW_HEIGHT; - dev_video_init(); + g_need_redraw = 1; + g_palette_change_summary = 0; - read_a2_font(); + g_border_sides_refresh_needed = 1; + g_border_special_refresh_needed = 1; + g_border_line24_refresh_needed = 1; + g_status_refresh_needed = 1; - vid_printf("Zeroing out video memory\n"); + g_vbl_border_color = 0; + g_border_last_vbl_changes = 0; - for(i = 0; i < 7; i++) { - switch(i) { - case 0: - kimage_ptr = &(g_kimage_text[0]); - break; - case 1: - kimage_ptr = &(g_kimage_text[1]); - break; - case 2: - kimage_ptr = &(g_kimage_hires[0]); - break; - case 3: - kimage_ptr = &(g_kimage_hires[1]); - break; - case 4: - kimage_ptr = &g_kimage_superhires; - break; - case 5: - kimage_ptr = &g_kimage_border_sides; - break; - case 6: - kimage_ptr = &g_kimage_border_special; - break; - default: - printf("i: %d, unknown\n", i); - exit(3); - } + g_use_dhr140 = 0; + g_use_bw_hires = 0; - ptr = (word32 *)kimage_ptr->data_ptr; - width = kimage_ptr->width_act; - height = kimage_ptr->height; - total_bytes = (kimage_ptr->mdepth >> 3) * width * height; + g_new_a2_stat_cur_line = 0; + g_vid_update_last_line = 0; - for(j = 0; j < total_bytes >> 2; j++) { - *ptr++ = 0; - } - } + g_cur_a2_stat = ALL_STAT_TEXT | ALL_STAT_ANNUNC3 |(0xf << BIT_ALL_STAT_TEXT_COLOR); - for(i = 0; i < SLOW_MEM_CH_SIZE; i++) { - slow_mem_changed[i] = (word32)-1; - } - /* create g_expanded_col_* */ - for(i = 0; i < 16; i++) { - val = (g_lores_colors[i] >> 0) & 0xf; - g_expanded_col_0[i] = val; + g_a2vid_palette = 0xe; + g_installed_full_superhires_colormap = 0; - val = (g_lores_colors[i] >> 4) & 0xf; - g_expanded_col_1[i] = val; + Max_color_size = 256; - val = (g_lores_colors[i] >> 8) & 0xf; - g_expanded_col_2[i] = val; - } + g_saved_a2vid_palette = -1; - /* create g_dhires_convert[] array */ - for(i = 0; i < 4096; i++) { - /* Convert index bits 11:0 where 3:0 is the previous color */ - /* and 7:4 is the current color to translate */ - /* Bit 4 will be the first pixel displayed on the screen */ - match_col = i & 0xf; - for(j = 0; j < 4; j++) { - cur_col = (i >> (1 + j)) & 0xf; - next_col = (i >> (2 + j)) & 0xf; - next2_col = (i >> (3 + j)) & 0xf; - next3_col = (i >> (4 + j)) & 0xf; - cur_col = (((cur_col << 4) + cur_col) >> (3 - j)) & 0xf; + g_cycs_in_refresh_line = 0; + g_cycs_in_refresh_ximage = 0; - if((cur_col == 0xf) || (next_col == 0xf) || - (next2_col == 0xf) || - (next3_col == 0xf)) { - cur_col = 0xf; - col[j] = cur_col; - match_col = cur_col; - } else if((cur_col == 0) || (next_col == 0) || - (next2_col == 0) || (next3_col == 0)) { - cur_col = 0; - col[j] = cur_col; - match_col = cur_col; - } else { - col[j] = cur_col; - match_col = cur_col; - } - } - if(g_use_dhr140) { - for(j = 0; j < 4; j++) { - col[j] = (i >> 4) & 0xf; - } - } - val0 = g_dhires_colors_16[col[0] & 0xf]; - val1 = g_dhires_colors_16[col[1] & 0xf]; - val2 = g_dhires_colors_16[col[2] & 0xf]; - val3 = g_dhires_colors_16[col[3] & 0xf]; + g_num_lines_superhires = 0; + g_num_lines_superhires640 = 0; + g_num_lines_prev_superhires = 0; + g_num_lines_prev_superhires640 = 0; + + /* + g_red_mask = 0xff; + g_green_mask = 0xff; + g_blue_mask = 0xff; + g_red_left_shift = 16; + g_green_left_shift = 8; + g_blue_left_shift = 0; + g_red_right_shift = 0; + g_green_right_shift = 0; + g_blue_right_shift = 0; + */ + +/* Initialize video system */ + + for(i = 0; i < 200; i++) { + g_a2_line_kimage[i] = (Kimage *)0; // OG Changed from void* to kimage* + g_a2_line_stat[i] = -1; + g_a2_line_left_edge[i] = 0; + g_a2_line_right_edge[i] = 0; + } + for(i = 0; i < 200; i++) { + g_a2_new_all_stat[i] = 0; + g_a2_cur_all_stat[i] = 1; + for(j = 0; j < 8; j++) { + g_saved_line_palettes[i][j] = (word32)-1; + } + } + for(i = 0; i < 262; i++) { + g_cur_border_colors[i] = -1; + } + + g_new_a2_stat_cur_line = 0; + + dev_video_init(); + + read_a2_font(); + + vid_printf("Zeroing out video memory\n"); + + for(i = 0; i < 7; i++) { + switch(i) { + case 0: + kimage_ptr = &(g_kimage_text[0]); + break; + case 1: + kimage_ptr = &(g_kimage_text[1]); + break; + case 2: + kimage_ptr = &(g_kimage_hires[0]); + break; + case 3: + kimage_ptr = &(g_kimage_hires[1]); + break; + case 4: + kimage_ptr = &g_kimage_superhires; + break; + case 5: + kimage_ptr = &g_kimage_border_sides; + break; + case 6: + kimage_ptr = &g_kimage_border_special; + break; + default: + printf("i: %d, unknown\n", i); + exit(3); + } + + ptr = (word32 *)kimage_ptr->data_ptr; + width = kimage_ptr->width_act; + height = kimage_ptr->height; + total_bytes = (kimage_ptr->mdepth >> 3) * width * height; + + for(j = 0; j < total_bytes >> 2; j++) { + *ptr++ = 0; + } + } + + for(i = 0; i < SLOW_MEM_CH_SIZE; i++) { + slow_mem_changed[i] = (word32)-1; + } + + /* create g_expanded_col_* */ + for(i = 0; i < 16; i++) { + val = (g_lores_colors[i] >> 0) & 0xf; + g_expanded_col_0[i] = val; + + val = (g_lores_colors[i] >> 4) & 0xf; + g_expanded_col_1[i] = val; + + val = (g_lores_colors[i] >> 8) & 0xf; + g_expanded_col_2[i] = val; + } + + /* create g_dhires_convert[] array */ + for(i = 0; i < 4096; i++) { + /* Convert index bits 11:0 where 3:0 is the previous color */ + /* and 7:4 is the current color to translate */ + /* Bit 4 will be the first pixel displayed on the screen */ + match_col = i & 0xf; + for(j = 0; j < 4; j++) { + cur_col = (i >> (1 + j)) & 0xf; + next_col = (i >> (2 + j)) & 0xf; + next2_col = (i >> (3 + j)) & 0xf; + next3_col = (i >> (4 + j)) & 0xf; + cur_col = (((cur_col << 4) + cur_col) >> (3 - j)) & 0xf; + + if((cur_col == 0xf) || (next_col == 0xf) || + (next2_col == 0xf) || + (next3_col == 0xf)) { + cur_col = 0xf; + col[j] = cur_col; + match_col = cur_col; + } else if((cur_col == 0) || (next_col == 0) || + (next2_col == 0) || (next3_col == 0)) { + cur_col = 0; + col[j] = cur_col; + match_col = cur_col; + } else { + col[j] = cur_col; + match_col = cur_col; + } + } + if(g_use_dhr140) { + for(j = 0; j < 4; j++) { + col[j] = (i >> 4) & 0xf; + } + } + val0 = g_dhires_colors_16[col[0] & 0xf]; + val1 = g_dhires_colors_16[col[1] & 0xf]; + val2 = g_dhires_colors_16[col[2] & 0xf]; + val3 = g_dhires_colors_16[col[3] & 0xf]; #if defined(GSPORT_LITTLE_ENDIAN) || defined (__LITTLE_ENDIAN__) // OSX needs to calculate endianness mid-compilation, can't be passed on compile command - val = (val3 << 24) + (val2 << 16) + (val1 << 8) + val0; + val = (val3 << 24) + (val2 << 16) + (val1 << 8) + val0; #else - val = (val0 << 24) + (val1 << 16) + (val2 << 8) + val3; + val = (val0 << 24) + (val1 << 16) + (val2 << 8) + val3; #endif - g_dhires_convert[i] = val; - } + g_dhires_convert[i] = val; + } - change_display_mode(g_cur_dcycs); - video_reset(); - display_screen(); + change_display_mode(g_cur_dcycs); + video_reset(); + display_screen(); - fflush(stdout); + fflush(stdout); } -void -show_a2_line_stuff() -{ - int i; +void show_a2_line_stuff() { + int i; - for(i = 0; i < 200; i++) { - printf("line: %d: stat: %04x, ptr: %p, " - "left_edge:%d, right_edge:%d\n", - i, g_a2_line_stat[i], g_a2_line_kimage[i], - g_a2_line_left_edge[i], - g_a2_line_right_edge[i]); - } + for(i = 0; i < 200; i++) { + printf("line: %d: stat: %04x, ptr: %p, " + "left_edge:%d, right_edge:%d\n", + i, g_a2_line_stat[i], g_a2_line_kimage[i], + g_a2_line_left_edge[i], + g_a2_line_right_edge[i]); + } - printf("new_a2_stat_cur_line: %d, cur_a2_stat:%04x\n", - g_new_a2_stat_cur_line, g_cur_a2_stat); - for(i = 0; i < 200; i++) { - printf("cur_all[%d]: %03x new_all: %03x\n", i, - g_a2_cur_all_stat[i], g_a2_new_all_stat[i]); - } + printf("new_a2_stat_cur_line: %d, cur_a2_stat:%04x\n", + g_new_a2_stat_cur_line, g_cur_a2_stat); + for(i = 0; i < 200; i++) { + printf("cur_all[%d]: %03x new_all: %03x\n", i, + g_a2_cur_all_stat[i], g_a2_new_all_stat[i]); + } } -int g_flash_count = 0; +int g_flash_count = 0; -void -video_reset() -{ - int stat; - int i; +void video_reset() { + int stat; + int i; - g_installed_full_superhires_colormap = (g_screen_depth != 8); - stat = ALL_STAT_TEXT | ALL_STAT_ANNUNC3 | - (0xf << BIT_ALL_STAT_TEXT_COLOR); - if(g_use_bw_hires) { - stat |= ALL_STAT_COLOR_C021; - } - if(g_config_control_panel) { - /* Don't update cur_a2_stat when in configuration panel */ - g_save_cur_a2_stat = stat; - } else { - g_cur_a2_stat = stat; - } + g_installed_full_superhires_colormap = (g_screen_depth != 8); + stat = ALL_STAT_TEXT | ALL_STAT_ANNUNC3 | + (0xf << BIT_ALL_STAT_TEXT_COLOR); + if(g_use_bw_hires) { + stat |= ALL_STAT_COLOR_C021; + } + if(g_config_control_panel) { + /* Don't update cur_a2_stat when in configuration panel */ + g_save_cur_a2_stat = stat; + } else { + g_cur_a2_stat = stat; + } - g_palette_change_summary = 0; - for(i = 0; i < 16; i++) { - g_palette_change_cnt[i] = 0; - } + g_palette_change_summary = 0; + for(i = 0; i < 16; i++) { + g_palette_change_cnt[i] = 0; + } - /* install_a2vid_colormap(); */ - video_update_colormap(); + /* install_a2vid_colormap(); */ + video_update_colormap(); } -int g_screen_redraw_skip_count = 0; -int g_screen_redraw_skip_amt = -1; +int g_screen_redraw_skip_count = 0; +int g_screen_redraw_skip_amt = -1; -word32 g_cycs_in_check_input = 0; +word32 g_cycs_in_check_input = 0; -int g_needfullrefreshfornextframe = 1 ; - -void video_update() -{ - int did_video; +int g_needfullrefreshfornextframe = 1; - // OG g_needfullrefreshfornextframe - if (g_needfullrefreshfornextframe) - { - g_full_refresh_needed = -1; - g_a2_screen_buffer_changed = -1; - g_status_refresh_needed = 1; - g_border_sides_refresh_needed = 1; - g_border_special_refresh_needed = 1; - g_needfullrefreshfornextframe = 0; - } - - - update_border_info(); +void video_update() { + int did_video; - video_check_input_events(); - - g_screen_redraw_skip_count--; - did_video = 0; - if(g_screen_redraw_skip_count < 0) { - did_video = 1; - video_update_event_line(262); - g_screen_redraw_skip_count = g_screen_redraw_skip_amt; - } - - /* update flash */ - g_flash_count++; - if(g_flash_count >= 30) { - g_flash_count = 0; - g_cur_a2_stat ^= ALL_STAT_FLASH_STATE; - change_display_mode(g_cur_dcycs); - } + // OG g_needfullrefreshfornextframe + if (g_needfullrefreshfornextframe) + { + g_full_refresh_needed = -1; + g_a2_screen_buffer_changed = -1; + g_status_refresh_needed = 1; + g_border_sides_refresh_needed = 1; + g_border_special_refresh_needed = 1; + g_needfullrefreshfornextframe = 0; + } - check_a2vid_palette(); + update_border_info(); + + video_check_input_events(); + + g_screen_redraw_skip_count--; + did_video = 0; + if(g_screen_redraw_skip_count < 0) { + did_video = 1; + video_update_event_line(262); + g_screen_redraw_skip_count = g_screen_redraw_skip_amt; + } + + /* update flash */ + g_flash_count++; + if(g_flash_count >= 30) { + g_flash_count = 0; + g_cur_a2_stat ^= ALL_STAT_FLASH_STATE; + change_display_mode(g_cur_dcycs); + } - if(did_video) { - g_new_a2_stat_cur_line = 0; - g_a2_new_all_stat[0] = g_cur_a2_stat; - g_vid_update_last_line = 0; - video_update_through_line(0); - } - - -// OG Notify host that video has been uodated -#if defined(ACTIVEGSPLUGIN) && defined(MAC) - { - extern void x_need2refresh(); - x_need2refresh(); - } -#endif + check_a2vid_palette(); + + + if(did_video) { + g_new_a2_stat_cur_line = 0; + g_a2_new_all_stat[0] = g_cur_a2_stat; + g_vid_update_last_line = 0; + video_update_through_line(0); + } + } -int -video_all_stat_to_line_stat(int line, int new_all_stat) -{ - int page, color, dbl; - int st80, hires, annunc3, mix_t_gr; - int altchar, text_color, bg_color, flash_state; - int mode; +int video_all_stat_to_line_stat(int line, int new_all_stat) { + int page, color, dbl; + int st80, hires, annunc3, mix_t_gr; + int altchar, text_color, bg_color, flash_state; + int mode; - st80 = new_all_stat & ALL_STAT_ST80; - hires = new_all_stat & ALL_STAT_HIRES; - annunc3 = new_all_stat & ALL_STAT_ANNUNC3; - mix_t_gr = new_all_stat & ALL_STAT_MIX_T_GR; + st80 = new_all_stat & ALL_STAT_ST80; + hires = new_all_stat & ALL_STAT_HIRES; + annunc3 = new_all_stat & ALL_STAT_ANNUNC3; + mix_t_gr = new_all_stat & ALL_STAT_MIX_T_GR; - page = EXTRU(new_all_stat, 31 - BIT_ALL_STAT_PAGE2, 1) && !st80; - color = EXTRU(new_all_stat, 31 - BIT_ALL_STAT_COLOR_C021, 1); - dbl = EXTRU(new_all_stat, 31 - BIT_ALL_STAT_VID80, 1); + page = EXTRU(new_all_stat, 31 - BIT_ALL_STAT_PAGE2, 1) && !st80; + color = EXTRU(new_all_stat, 31 - BIT_ALL_STAT_COLOR_C021, 1); + dbl = EXTRU(new_all_stat, 31 - BIT_ALL_STAT_VID80, 1); - altchar = 0; text_color = 0; bg_color = 0; flash_state = 0; + altchar = 0; text_color = 0; bg_color = 0; flash_state = 0; - if(new_all_stat & ALL_STAT_SUPER_HIRES) { - mode = MODE_SUPER_HIRES; - page = 0; dbl = 0; color = 0; - } else { - if(line >= 192) { - mode = MODE_BORDER; - page = 0; dbl = 0; color = 0; - } else if((new_all_stat & ALL_STAT_TEXT) || - (line >= 160 && mix_t_gr)) { - mode = MODE_TEXT; - color = 0; - altchar = EXTRU(new_all_stat, - 31 - BIT_ALL_STAT_ALTCHARSET, 1); - text_color = EXTRU(new_all_stat, - 31 - BIT_ALL_STAT_TEXT_COLOR, 4); - bg_color = EXTRU(new_all_stat, - 31 - BIT_ALL_STAT_BG_COLOR, 4); - flash_state = EXTRU(new_all_stat, - 31 - BIT_ALL_STAT_FLASH_STATE, 1); - if(altchar) { - /* don't bother flashing if altchar on */ - flash_state = 0; - } - } else { - /* obey the graphics mode */ - dbl = dbl && !annunc3; - if(hires) { - color = color | EXTRU(new_all_stat, - 31 - BIT_ALL_STAT_DIS_COLOR_DHIRES, 1); - mode = MODE_HGR; - } else { - mode = MODE_GR; - } - } - } + if(new_all_stat & ALL_STAT_SUPER_HIRES) { + mode = MODE_SUPER_HIRES; + page = 0; dbl = 0; color = 0; + } else { + if(line >= 192) { + mode = MODE_BORDER; + page = 0; dbl = 0; color = 0; + } else if((new_all_stat & ALL_STAT_TEXT) || + (line >= 160 && mix_t_gr)) { + mode = MODE_TEXT; + color = 0; + altchar = EXTRU(new_all_stat, + 31 - BIT_ALL_STAT_ALTCHARSET, 1); + text_color = EXTRU(new_all_stat, + 31 - BIT_ALL_STAT_TEXT_COLOR, 4); + bg_color = EXTRU(new_all_stat, + 31 - BIT_ALL_STAT_BG_COLOR, 4); + flash_state = EXTRU(new_all_stat, + 31 - BIT_ALL_STAT_FLASH_STATE, 1); + if(altchar) { + /* don't bother flashing if altchar on */ + flash_state = 0; + } + } else { + /* obey the graphics mode */ + dbl = dbl && !annunc3; + if(hires) { + color = color | EXTRU(new_all_stat, + 31 - BIT_ALL_STAT_DIS_COLOR_DHIRES, 1); + mode = MODE_HGR; + } else { + mode = MODE_GR; + } + } + } - return((text_color << 12) + (bg_color << 8) + (altchar << 7) + - (mode << 4) + (flash_state << 3) + (page << 2) + - (color << 1) + dbl); + return((text_color << 12) + (bg_color << 8) + (altchar << 7) + + (mode << 4) + (flash_state << 3) + (page << 2) + + (color << 1) + dbl); } -int * -video_update_kimage_ptr(int line, int new_stat) -{ - Kimage *kimage_ptr; - int *mode_ptr; - int page; - int mode; +int *video_update_kimage_ptr(int line, int new_stat) { + Kimage *kimage_ptr; + int *mode_ptr; + int page; + int mode; - page = (new_stat >> 2) & 1; - mode = (new_stat >> 4) & 7; + page = (new_stat >> 2) & 1; + mode = (new_stat >> 4) & 7; - switch(mode) { - case MODE_TEXT: - case MODE_GR: - kimage_ptr = &(g_kimage_text[page]); - mode_ptr = &(g_mode_text[page][0]); - break; - case MODE_HGR: - kimage_ptr = &(g_kimage_hires[page]); - mode_ptr = &(g_mode_hires[page][0]); - /* arrange to force superhires reparse since we use the */ - /* same memory */ - g_mode_superhires[line] = -1; - break; - case MODE_SUPER_HIRES: - kimage_ptr = &g_kimage_superhires; - mode_ptr = &(g_mode_superhires[0]); - /* arrange to force hires reparse since we use the */ - /* same memory */ - g_mode_hires[0][line] = -1; - g_mode_hires[1][line] = -1; - break; - case MODE_BORDER: - /* Hack: reuse text page last line as the special border */ - kimage_ptr = &(g_kimage_text[0]); - mode_ptr = &(g_mode_border[0]); - break; - default: - halt_printf("update_a2_ptrs: mode: %d unknown!\n", mode); - return &(g_mode_superhires[0]); - } + switch(mode) { + case MODE_TEXT: + case MODE_GR: + kimage_ptr = &(g_kimage_text[page]); + mode_ptr = &(g_mode_text[page][0]); + break; + case MODE_HGR: + kimage_ptr = &(g_kimage_hires[page]); + mode_ptr = &(g_mode_hires[page][0]); + /* arrange to force superhires reparse since we use the */ + /* same memory */ + g_mode_superhires[line] = -1; + break; + case MODE_SUPER_HIRES: + kimage_ptr = &g_kimage_superhires; + mode_ptr = &(g_mode_superhires[0]); + /* arrange to force hires reparse since we use the */ + /* same memory */ + g_mode_hires[0][line] = -1; + g_mode_hires[1][line] = -1; + break; + case MODE_BORDER: + /* Hack: reuse text page last line as the special border */ + kimage_ptr = &(g_kimage_text[0]); + mode_ptr = &(g_mode_border[0]); + break; + default: + halt_printf("update_a2_ptrs: mode: %d unknown!\n", mode); + return &(g_mode_superhires[0]); + } - g_a2_line_kimage[line] = kimage_ptr; - return mode_ptr; + g_a2_line_kimage[line] = kimage_ptr; + return mode_ptr; } -void -change_a2vid_palette(int new_palette) -{ - int i; +void change_a2vid_palette(int new_palette) { + int i; - for(i = 0; i < 200; i++) { - g_mode_text[0][i] = -1; - g_mode_text[1][i] = -1; - g_mode_hires[0][i] = -1; - g_mode_hires[1][i] = -1; - g_mode_superhires[i] = -1; - g_mode_border[i] = -1; - } + for(i = 0; i < 200; i++) { + g_mode_text[0][i] = -1; + g_mode_text[1][i] = -1; + g_mode_hires[0][i] = -1; + g_mode_hires[1][i] = -1; + g_mode_superhires[i] = -1; + g_mode_border[i] = -1; + } - printf("Changed a2vid_palette to %x\n", new_palette); + printf("Changed a2vid_palette to %x\n", new_palette); - g_a2vid_palette = new_palette; - g_cur_a2_stat = (g_cur_a2_stat & (~ALL_STAT_A2VID_PALETTE)) + - (new_palette << BIT_ALL_STAT_A2VID_PALETTE); - change_display_mode(g_cur_dcycs); + g_a2vid_palette = new_palette; + g_cur_a2_stat = (g_cur_a2_stat & (~ALL_STAT_A2VID_PALETTE)) + + (new_palette << BIT_ALL_STAT_A2VID_PALETTE); + change_display_mode(g_cur_dcycs); - g_border_sides_refresh_needed = 1; - g_border_special_refresh_needed = 1; - g_status_refresh_needed = 1; - g_palette_change_cnt[new_palette]++; - g_border_last_vbl_changes = 1; - for(i = 0; i < 262; i++) { - g_cur_border_colors[i] = -1; - } + g_border_sides_refresh_needed = 1; + g_border_special_refresh_needed = 1; + g_status_refresh_needed = 1; + g_palette_change_cnt[new_palette]++; + g_border_last_vbl_changes = 1; + for(i = 0; i < 262; i++) { + g_cur_border_colors[i] = -1; + } } int g_num_a2vid_palette_checks = 1; int g_shr_palette_used[16]; -void -check_a2vid_palette() -{ - int sum; - int min; - int val; - int min_pos; - int count_cur; - int i; +void check_a2vid_palette() { + int sum; + int min; + int val; + int min_pos; + int count_cur; + int i; - /* determine if g_a2vid_palette should change */ - /* This is the palette of least use on superhires so that the */ - /* borders don't change when all 256 superhires colors are used */ + /* determine if g_a2vid_palette should change */ + /* This is the palette of least use on superhires so that the */ + /* borders don't change when all 256 superhires colors are used */ - g_num_a2vid_palette_checks--; - if(g_num_a2vid_palette_checks || g_installed_full_superhires_colormap){ - return; - } + g_num_a2vid_palette_checks--; + if(g_num_a2vid_palette_checks || g_installed_full_superhires_colormap) { + return; + } - g_num_a2vid_palette_checks = 60; + g_num_a2vid_palette_checks = 60; - sum = 0; - min = 0x100000; - min_pos = -1; - count_cur = g_shr_palette_used[g_a2vid_palette]; + sum = 0; + min = 0x100000; + min_pos = -1; + count_cur = g_shr_palette_used[g_a2vid_palette]; - for(i = 0; i < 16; i++) { - val = g_shr_palette_used[i]; - g_shr_palette_used[i] = 0; - if(val < min) { - min = val; - min_pos = i; - } - sum += val; - } + for(i = 0; i < 16; i++) { + val = g_shr_palette_used[i]; + g_shr_palette_used[i] = 0; + if(val < min) { + min = val; + min_pos = i; + } + sum += val; + } - if(g_a2vid_palette != min_pos && (count_cur > min)) { - change_a2vid_palette(min_pos); - } + if(g_a2vid_palette != min_pos && (count_cur > min)) { + change_a2vid_palette(min_pos); + } } -void -change_display_mode(double dcycs) -{ - int line, tmp_line; +void change_display_mode(double dcycs) { + int line, tmp_line; - line = ((get_lines_since_vbl(dcycs) + 0xff) >> 8); - if(line < 0) { - line = 0; - halt_printf("Line < 0!\n"); - } - tmp_line = MIN(199, line); + line = ((get_lines_since_vbl(dcycs) + 0xff) >> 8); + if(line < 0) { + line = 0; + halt_printf("Line < 0!\n"); + } + tmp_line = MIN(199, line); - video_update_all_stat_through_line(tmp_line); + video_update_all_stat_through_line(tmp_line); - if(line < 200) { - g_a2_new_all_stat[line] = g_cur_a2_stat; - } - /* otherwise, g_cur_a2_stat is covered at the end of vbl */ + if(line < 200) { + g_a2_new_all_stat[line] = g_cur_a2_stat; + } + /* otherwise, g_cur_a2_stat is covered at the end of vbl */ } -void -video_update_all_stat_through_line(int line) -{ - int start_line; - int prev_stat; - int max_line; - int i; +void video_update_all_stat_through_line(int line) { + int start_line; + int prev_stat; + int max_line; + int i; - start_line = g_new_a2_stat_cur_line; - prev_stat = g_a2_new_all_stat[start_line]; + start_line = g_new_a2_stat_cur_line; + prev_stat = g_a2_new_all_stat[start_line]; - max_line = MIN(199, line); + max_line = MIN(199, line); - for(i = start_line + 1; i <= max_line; i++) { - g_a2_new_all_stat[i] = prev_stat; - } - g_new_a2_stat_cur_line = max_line; + for(i = start_line + 1; i <= max_line; i++) { + g_a2_new_all_stat[i] = prev_stat; + } + g_new_a2_stat_cur_line = max_line; } -#define MAX_BORDER_CHANGES 16384 +#define MAX_BORDER_CHANGES 16384 STRUCT(Border_changes) { - float fcycs; - int val; + float fcycs; + int val; }; -int g_border_color = 0; // OG Expose border color - +int g_border_color = 0; // OG Expose border color + Border_changes g_border_changes[MAX_BORDER_CHANGES]; -int g_num_border_changes = 0; +int g_num_border_changes = 0; -void -change_border_color(double dcycs, int val) -{ - int pos; +void change_border_color(double dcycs, int val) { + int pos; - g_border_color = val; // OG Expose border color - - pos = g_num_border_changes; - g_border_changes[pos].fcycs = (float)(dcycs - g_last_vbl_dcycs); - g_border_changes[pos].val = val; + g_border_color = val; // OG Expose border color - pos++; - g_num_border_changes = pos; + pos = g_num_border_changes; + g_border_changes[pos].fcycs = (float)(dcycs - g_last_vbl_dcycs); + g_border_changes[pos].val = val; - if(pos >= MAX_BORDER_CHANGES) { - halt_printf("num border changes: %d\n", pos); - g_num_border_changes = 0; - } + pos++; + g_num_border_changes = pos; + + if(pos >= MAX_BORDER_CHANGES) { + halt_printf("num border changes: %d\n", pos); + g_num_border_changes = 0; + } } -extern int first; - -void -update_border_info() -{ - double dlines_per_dcyc; - double dcycs, dline, dcyc_line_start; - int offset; - int new_line_offset, last_line_offset; - int new_line; - int new_val; - int limit; - int color_now; - int i; +extern int first; - /* to get this routine to redraw the border, change */ - /* g_vbl_border_color, set g_border_last_vbl_changes = 1 */ - /* and change the cur_border_colors[] array */ +void update_border_info() { + double dlines_per_dcyc; + double dcycs, dline, dcyc_line_start; + int offset; + int new_line_offset, last_line_offset; + int new_line; + int new_val; + int limit; + int color_now; + int i; - color_now = g_vbl_border_color; + /* to get this routine to redraw the border, change */ + /* g_vbl_border_color, set g_border_last_vbl_changes = 1 */ + /* and change the cur_border_colors[] array */ - dlines_per_dcyc = (double)(1.0 / 65.0); - limit = g_num_border_changes; - if(g_border_last_vbl_changes || limit) { - /* add a dummy entry */ - g_border_changes[limit].fcycs = DCYCS_IN_16MS + 21.0; - g_border_changes[limit].val = (g_c034_val & 0xf); - limit++; - } - last_line_offset = (-1 << 8) + 44; - for(i = 0; i < limit; i++) { - dcycs = g_border_changes[i].fcycs; - dline = dcycs * dlines_per_dcyc; - new_line = (int)dline; - dcyc_line_start = (double)new_line * 65.0; - offset = ((int)(dcycs - dcyc_line_start)) & 0xff; + color_now = g_vbl_border_color; - /* here comes the tricky part */ - /* offset is from 0 to 65, where 0-3 is the right border of */ - /* the previous line, 4-20 is horiz blanking, 21-24 is the */ - /* left border and 25-64 is the main window */ - /* Convert this to a new notation which is 0-3 is the left */ - /* border, 4-43 is the main window, and 44-47 is the right */ - /* basically, add -21 to offset, and wrap < 0 to previous ln */ - /* note this makes line -1 offset 44-47 the left hand border */ - /* for true line 261 on the screen */ - offset -= 21; - if(offset < 0) { - new_line--; - offset += 64; - } - new_val = g_border_changes[i].val; - new_line_offset = (new_line << 8) + offset; + dlines_per_dcyc = (double)(1.0 / 65.0); + limit = g_num_border_changes; + if(g_border_last_vbl_changes || limit) { + /* add a dummy entry */ + g_border_changes[limit].fcycs = DCYCS_IN_16MS + 21.0; + g_border_changes[limit].val = (g_c034_val & 0xf); + limit++; + } + last_line_offset = (-1 << 8) + 44; + for(i = 0; i < limit; i++) { + dcycs = g_border_changes[i].fcycs; + dline = dcycs * dlines_per_dcyc; + new_line = (int)dline; + dcyc_line_start = (double)new_line * 65.0; + offset = ((int)(dcycs - dcyc_line_start)) & 0xff; - if(new_line_offset < -256 || new_line_offset >(262*256 + 0x80)){ - printf("new_line_offset: %05x\n", new_line_offset); - new_line_offset = last_line_offset; - } - while(last_line_offset < new_line_offset) { - /* see if this will finish it */ - if((last_line_offset & -256)==(new_line_offset & -256)){ - update_border_line(last_line_offset, - new_line_offset, color_now); - last_line_offset = new_line_offset; - } else { - update_border_line(last_line_offset, - (last_line_offset & -256) + 65, - color_now); - last_line_offset =(last_line_offset & -256)+256; - } - } + /* here comes the tricky part */ + /* offset is from 0 to 65, where 0-3 is the right border of */ + /* the previous line, 4-20 is horiz blanking, 21-24 is the */ + /* left border and 25-64 is the main window */ + /* Convert this to a new notation which is 0-3 is the left */ + /* border, 4-43 is the main window, and 44-47 is the right */ + /* basically, add -21 to offset, and wrap < 0 to previous ln */ + /* note this makes line -1 offset 44-47 the left hand border */ + /* for true line 261 on the screen */ + offset -= 21; + if(offset < 0) { + new_line--; + offset += 64; + } + new_val = g_border_changes[i].val; + new_line_offset = (new_line << 8) + offset; - color_now = new_val; - } + if(new_line_offset < -256 || new_line_offset >(262*256 + 0x80)) { + printf("new_line_offset: %05x\n", new_line_offset); + new_line_offset = last_line_offset; + } + while(last_line_offset < new_line_offset) { + /* see if this will finish it */ + if((last_line_offset & -256)==(new_line_offset & -256)) { + update_border_line(last_line_offset, + new_line_offset, color_now); + last_line_offset = new_line_offset; + } else { + update_border_line(last_line_offset, + (last_line_offset & -256) + 65, + color_now); + last_line_offset =(last_line_offset & -256)+256; + } + } + + color_now = new_val; + } #if 0 - if(g_num_border_changes) { - printf("Border changes: %d\n", g_num_border_changes); - } + if(g_num_border_changes) { + printf("Border changes: %d\n", g_num_border_changes); + } #endif - if(limit > 1) { - g_border_last_vbl_changes = 1; - } else { - g_border_last_vbl_changes = 0; - } + if(limit > 1) { + g_border_last_vbl_changes = 1; + } else { + g_border_last_vbl_changes = 0; + } - g_num_border_changes = 0; - g_vbl_border_color = (g_c034_val & 0xf); + g_num_border_changes = 0; + g_vbl_border_color = (g_c034_val & 0xf); } -void -update_border_line(int st_line_offset, int end_line_offset, int color) -{ - word32 val; - int st_offset, end_offset; - int left, right; - int line; +void update_border_line(int st_line_offset, int end_line_offset, int color) { + word32 val; + int st_offset, end_offset; + int left, right; + int line; - line = st_line_offset >> 8; - if(line != (end_line_offset >> 8)) { - halt_printf("ubl, %04x %04x %02x!\n", st_line_offset, - end_line_offset, color); - } - if(line < -1 || line >= 262) { - halt_printf("ubl-b, mod line is %d\n", line); - line = 0; - } - if(line < 0 || line >= 262) { - line = 0; - } + line = st_line_offset >> 8; + if(line != (end_line_offset >> 8)) { + halt_printf("ubl, %04x %04x %02x!\n", st_line_offset, + end_line_offset, color); + } + if(line < -1 || line >= 262) { + halt_printf("ubl-b, mod line is %d\n", line); + line = 0; + } + if(line < 0 || line >= 262) { + line = 0; + } - st_offset = st_line_offset & 0xff; - end_offset = end_line_offset & 0xff; + st_offset = st_line_offset & 0xff; + end_offset = end_line_offset & 0xff; - if((st_offset == 0) && (end_offset >= 0x41)) { - /* might be the same as last time, save some work */ - if(g_cur_border_colors[line] == color) { - return; - } - g_cur_border_colors[line] = color; - } else { - g_cur_border_colors[line] = -1; - } + if((st_offset == 0) && (end_offset >= 0x41)) { + /* might be the same as last time, save some work */ + if(g_cur_border_colors[line] == color) { + return; + } + g_cur_border_colors[line] = color; + } else { + g_cur_border_colors[line] = -1; + } - val = (color + (g_a2vid_palette << 4)); - val = (val << 24) + (val << 16) + (val << 8) + val; + val = (color + (g_a2vid_palette << 4)); + val = (val << 24) + (val << 16) + (val << 8) + val; - /* 0-3: left border, 4-43: main window, 44-47: right border */ - /* 48-65: horiz blanking */ - /* first, do the sides from line 0 to line 199 */ - if((line < 200) || (line >= 262)) { - if(line >= 262) { - line = 0; - } - if(st_offset < 4) { - /* left side */ - left = st_offset; - right = MIN(4, end_offset); - video_border_pixel_write(&g_kimage_border_sides, - 2*line, 2, val, (left * BORDER_WIDTH)/4, - (right * BORDER_WIDTH) / 4); + /* 0-3: left border, 4-43: main window, 44-47: right border */ + /* 48-65: horiz blanking */ + /* first, do the sides from line 0 to line 199 */ + if((line < 200) || (line >= 262)) { + if(line >= 262) { + line = 0; + } + if(st_offset < 4) { + /* left side */ + left = st_offset; + right = MIN(4, end_offset); + video_border_pixel_write(&g_kimage_border_sides, + 2*line, 2, val, (left * BORDER_WIDTH)/4, + (right * BORDER_WIDTH) / 4); - g_border_sides_refresh_needed = 1; - } - if((st_offset < 48) && (end_offset >= 44)) { - /* right side */ - left = MAX(0, st_offset - 44); - right = MIN(4, end_offset - 44); - video_border_pixel_write(&g_kimage_border_sides, - 2*line, 2, val, - BORDER_WIDTH + (left * EFF_BORDER_WIDTH/4), - BORDER_WIDTH + (right * EFF_BORDER_WIDTH/4)); - g_border_sides_refresh_needed = 1; - } - } + g_border_sides_refresh_needed = 1; + } + if((st_offset < 48) && (end_offset >= 44)) { + /* right side */ + left = MAX(0, st_offset - 44); + right = MIN(4, end_offset - 44); + video_border_pixel_write(&g_kimage_border_sides, + 2*line, 2, val, + BORDER_WIDTH + (left * EFF_BORDER_WIDTH/4), + BORDER_WIDTH + (right * EFF_BORDER_WIDTH/4)); + g_border_sides_refresh_needed = 1; + } + } - if((line >= 192) && (line < 200)) { - if(st_offset < 44 && end_offset > 4) { - left = MAX(0, st_offset - 4); - right = MIN(40, end_offset - 4); - video_border_pixel_write(&g_kimage_text[0], - 2*line, 2, val, left * 640 / 40, - right * 640 / 40); - g_border_line24_refresh_needed = 1; - } - } + if((line >= 192) && (line < 200)) { + if(st_offset < 44 && end_offset > 4) { + left = MAX(0, st_offset - 4); + right = MIN(40, end_offset - 4); + video_border_pixel_write(&g_kimage_text[0], + 2*line, 2, val, left * 640 / 40, + right * 640 / 40); + g_border_line24_refresh_needed = 1; + } + } - /* now do the bottom, lines 200 to 215 */ - if((line >= 200) && (line < (200 + BASE_MARGIN_BOTTOM/2)) ) { - line -= 200; - left = st_offset; - right = MIN(48, end_offset); - video_border_pixel_write(&g_kimage_border_special, 2*line, 2, - val, (left * X_A2_WINDOW_WIDTH / 48), - (right * X_A2_WINDOW_WIDTH / 48)); - g_border_special_refresh_needed = 1; - } + /* now do the bottom, lines 200 to 215 */ + if((line >= 200) && (line < (200 + BASE_MARGIN_BOTTOM/2)) ) { + line -= 200; + left = st_offset; + right = MIN(48, end_offset); + video_border_pixel_write(&g_kimage_border_special, 2*line, 2, + val, (left * X_A2_WINDOW_WIDTH / 48), + (right * X_A2_WINDOW_WIDTH / 48)); + g_border_special_refresh_needed = 1; + } - /* and top, lines 236 to 262 */ - if((line >= (262 - BASE_MARGIN_TOP/2)) && (line < 262)) { - line -= (262 - BASE_MARGIN_TOP/2); - left = st_offset; - right = MIN(48, end_offset); - video_border_pixel_write(&g_kimage_border_special, - BASE_MARGIN_BOTTOM + 2*line, 2, val, - (left * X_A2_WINDOW_WIDTH / 48), - (right * X_A2_WINDOW_WIDTH / 48)); - g_border_special_refresh_needed = 1; - } + /* and top, lines 236 to 262 */ + if((line >= (262 - BASE_MARGIN_TOP/2)) && (line < 262)) { + line -= (262 - BASE_MARGIN_TOP/2); + left = st_offset; + right = MIN(48, end_offset); + video_border_pixel_write(&g_kimage_border_special, + BASE_MARGIN_BOTTOM + 2*line, 2, val, + (left * X_A2_WINDOW_WIDTH / 48), + (right * X_A2_WINDOW_WIDTH / 48)); + g_border_special_refresh_needed = 1; + } } -void -video_border_pixel_write(Kimage *kimage_ptr, int starty, int num_lines, - word32 val, int st_off, int end_off) -{ - word32 *ptr; - int width; - int width_act; - int mdepth; - int num_words, num_bytes; - int bytes_per_pix; - int i, j; +void video_border_pixel_write(Kimage *kimage_ptr, int starty, int num_lines, + word32 val, int st_off, int end_off) { + word32 *ptr; + int width; + int width_act; + int mdepth; + int num_words, num_bytes; + int bytes_per_pix; + int i, j; - if(end_off <= st_off) { - return; - } + if(end_off <= st_off) { + return; + } - width = end_off - st_off; - width_act = kimage_ptr->width_act; - mdepth = kimage_ptr->mdepth; - bytes_per_pix = mdepth >> 3; - num_bytes = width * bytes_per_pix; - num_words = num_bytes >> 2; + width = end_off - st_off; + width_act = kimage_ptr->width_act; + mdepth = kimage_ptr->mdepth; + bytes_per_pix = mdepth >> 3; + num_bytes = width * bytes_per_pix; + num_words = num_bytes >> 2; - if(width > width_act) { - halt_printf("border write but width %d > act %d\n", width, - width_act); - } + if(width > width_act) { + halt_printf("border write but width %d > act %d\n", width, + width_act); + } - if(mdepth == 16) { - val = g_a2palette_8to1624[val & 0xff]; - val = (val << 16) + val; - } else if(mdepth == 32) { - /* 32-bit pixels */ - val = g_a2palette_8to1624[val & 0xff]; - } + if(mdepth == 16) { + val = g_a2palette_8to1624[val & 0xff]; + val = (val << 16) + val; + } else if(mdepth == 32) { + /* 32-bit pixels */ + val = g_a2palette_8to1624[val & 0xff]; + } - for(i = 0; i < num_lines; i++) { - ptr = (word32 *)&(kimage_ptr->data_ptr[ - (starty + i)*width_act*bytes_per_pix]); - ptr += ((st_off * bytes_per_pix) / 4); - /* HACK: the above isn't really right when bytes_per_pix is */ - /* less than four... */ - for(j = 0; j < num_words; j++) { - *ptr++ = val; - } - } + for(i = 0; i < num_lines; i++) { + ptr = (word32 *)&(kimage_ptr->data_ptr[ + (starty + i)*width_act*bytes_per_pix]); + ptr += ((st_off * bytes_per_pix) / 4); + /* HACK: the above isn't really right when bytes_per_pix is */ + /* less than four... */ + for(j = 0; j < num_words; j++) { + *ptr++ = val; + } + } } -#define CH_SETUP_A2_VID(mem_ptr, ch_mask, reparse, do_clear) \ - ch_ptr = &(slow_mem_changed[mem_ptr >> CHANGE_SHIFT]); \ - ch_bitpos = 0; \ - bits_per_line = 40 >> SHIFT_PER_CHANGE; \ - ch_shift_amount = (mem_ptr >> SHIFT_PER_CHANGE) & 0x1f; \ - mask_per_line = (-(1 << (32 - bits_per_line))); \ - mask_per_line = mask_per_line >> ch_shift_amount; \ - ch_mask = *ch_ptr & mask_per_line; \ - if(do_clear) { \ - *ch_ptr = *ch_ptr & (~ch_mask); \ - } \ - ch_mask = ch_mask << ch_shift_amount; \ - \ - if(reparse) { \ - ch_mask = - (1 << (32 - bits_per_line)); \ - } +#define CH_SETUP_A2_VID(mem_ptr, ch_mask, reparse, do_clear) \ + ch_ptr = &(slow_mem_changed[mem_ptr >> CHANGE_SHIFT]); \ + ch_bitpos = 0; \ + bits_per_line = 40 >> SHIFT_PER_CHANGE; \ + ch_shift_amount = (mem_ptr >> SHIFT_PER_CHANGE) & 0x1f; \ + mask_per_line = (-(1 << (32 - bits_per_line))); \ + mask_per_line = mask_per_line >> ch_shift_amount; \ + ch_mask = *ch_ptr & mask_per_line; \ + if(do_clear) { \ + *ch_ptr = *ch_ptr & (~ch_mask); \ + } \ + ch_mask = ch_mask << ch_shift_amount; \ + \ + if(reparse) { \ + ch_mask = -(1 << (32 - bits_per_line)); \ + } -#define CH_LOOP_A2_VID(ch_mask, ch_tmp) \ - ch_tmp = ch_mask & 0x80000000; \ - ch_mask = ch_mask << 1; \ - \ - if(!ch_tmp) { \ - continue; \ - } +#define CH_LOOP_A2_VID(ch_mask, ch_tmp) \ + ch_tmp = ch_mask & 0x80000000; \ + ch_mask = ch_mask << 1; \ + \ + if(!ch_tmp) { \ + continue; \ + } -void -redraw_changed_text_40(int start_offset, int start_line, int num_lines, - int reparse, byte *screen_data, int altcharset, int bg_val, int fg_val, - int pixels_per_line) -{ - register word32 start_time, end_time; - word32 *img_ptr, *img_ptr2; - word32 *save_img_ptr, *save_img_ptr2; - word32 *ch_ptr; - const word32 *font_ptr1; - const word32 *font_ptr2; - byte *slow_mem_ptr; - byte *b_ptr; - word32 ch_mask; - word32 ch_tmp; - word32 line_mask; - word32 mask_per_line; - word32 mem_ptr; - word32 tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6; - word32 palette_add; - word32 diff_val; - word32 and_val; - word32 add_val; - word32 ff_val; - word32 val0, val1; - int flash_state; - int y; - int x1, x2; - int ch_bitpos; - int bits_per_line; - int ch_shift_amount; - int shift_per; - int left, right; - int st_line_mod8, st_line; - int i; +void redraw_changed_text_40(int start_offset, int start_line, int num_lines, + int reparse, byte *screen_data, int altcharset, int bg_val, int fg_val, + int pixels_per_line) { + register word32 start_time, end_time; + word32 *img_ptr, *img_ptr2; + word32 *save_img_ptr, *save_img_ptr2; + word32 *ch_ptr; + const word32 *font_ptr1; + const word32 *font_ptr2; + byte *slow_mem_ptr; + byte *b_ptr; + word32 ch_mask; + word32 ch_tmp; + word32 line_mask; + word32 mask_per_line; + word32 mem_ptr; + word32 tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6; + word32 palette_add; + word32 diff_val; + word32 and_val; + word32 add_val; + word32 ff_val; + word32 val0, val1; + int flash_state; + int y; + int x1, x2; + int ch_bitpos; + int bits_per_line; + int ch_shift_amount; + int shift_per; + int left, right; + int st_line_mod8, st_line; + int i; - /* always redraws to the next multiple of 8 lines due to redraw */ - /* issues: char changed on one screen redraw at line 0 with */ - /* num_lines=1. We need to have drawn lines 1-7 also since line 1 */ - /* will not see any changed bytes */ - st_line_mod8 = start_line & 7; - st_line = start_line; + /* always redraws to the next multiple of 8 lines due to redraw */ + /* issues: char changed on one screen redraw at line 0 with */ + /* num_lines=1. We need to have drawn lines 1-7 also since line 1 */ + /* will not see any changed bytes */ + st_line_mod8 = start_line & 7; + st_line = start_line; - start_line = start_line >> 3; + start_line = start_line >> 3; - y = start_line; - line_mask = 1 << (y); - mem_ptr = 0x400 + g_screen_index[y] + start_offset; - if(mem_ptr < 0x400 || mem_ptr >= 0xc00) { - halt_printf("redraw_changed_text: mem_ptr: %08x\n", mem_ptr); - } + y = start_line; + line_mask = 1 << (y); + mem_ptr = 0x400 + g_screen_index[y] + start_offset; + if(mem_ptr < 0x400 || mem_ptr >= 0xc00) { + halt_printf("redraw_changed_text: mem_ptr: %08x\n", mem_ptr); + } - CH_SETUP_A2_VID(mem_ptr, ch_mask, reparse, (st_line_mod8 == 0)); - /* avoid clearing changed bits unless we are line 0 (mod 8) */ + CH_SETUP_A2_VID(mem_ptr, ch_mask, reparse, (st_line_mod8 == 0)); + /* avoid clearing changed bits unless we are line 0 (mod 8) */ - if(ch_mask == 0) { - return; - } + if(ch_mask == 0) { + return; + } - GET_ITIMER(start_time); + GET_ITIMER(start_time); - shift_per = (1 << SHIFT_PER_CHANGE); + shift_per = (1 << SHIFT_PER_CHANGE); - g_a2_screen_buffer_changed |= line_mask; + g_a2_screen_buffer_changed |= line_mask; - palette_add = (g_a2vid_palette << 4); - palette_add = palette_add + (palette_add << 8) + (palette_add << 16) + - (palette_add << 24); + palette_add = (g_a2vid_palette << 4); + palette_add = palette_add + (palette_add << 8) + (palette_add << 16) + + (palette_add << 24); - left = 40; - right = 0; + left = 40; + right = 0; - diff_val = (fg_val - bg_val) & 0xf; - and_val = diff_val + (diff_val << 8) + (diff_val << 16) +(diff_val<<24); - add_val = bg_val + (bg_val << 8) + (bg_val << 16) + (bg_val << 24); - ff_val = 0x0f0f0f0f; + diff_val = (fg_val - bg_val) & 0xf; + and_val = diff_val + (diff_val << 8) + (diff_val << 16) +(diff_val<<24); + add_val = bg_val + (bg_val << 8) + (bg_val << 16) + (bg_val << 24); + ff_val = 0x0f0f0f0f; - flash_state = (g_cur_a2_stat & ALL_STAT_FLASH_STATE); + flash_state = (g_cur_a2_stat & ALL_STAT_FLASH_STATE); - for(x1 = 0; x1 < 40; x1 += shift_per) { + for(x1 = 0; x1 < 40; x1 += shift_per) { - CH_LOOP_A2_VID(ch_mask, ch_tmp); + CH_LOOP_A2_VID(ch_mask, ch_tmp); - left = MIN(x1, left); - right = MAX(x1 + shift_per, right); - slow_mem_ptr = &(g_slow_memory_ptr[mem_ptr + x1]); - b_ptr = &screen_data[(8*y + st_line_mod8)*2*pixels_per_line + - x1*14]; - img_ptr = (word32 *)b_ptr; - img_ptr2 = (word32 *)(b_ptr + pixels_per_line); + left = MIN(x1, left); + right = MAX(x1 + shift_per, right); + slow_mem_ptr = &(g_slow_memory_ptr[mem_ptr + x1]); + b_ptr = &screen_data[(8*y + st_line_mod8)*2*pixels_per_line + + x1*14]; + img_ptr = (word32 *)b_ptr; + img_ptr2 = (word32 *)(b_ptr + pixels_per_line); - for(x2 = 0; x2 < shift_per; x2 += 2) { - val0 = *slow_mem_ptr++; - val1 = *slow_mem_ptr++; + for(x2 = 0; x2 < shift_per; x2 += 2) { + val0 = *slow_mem_ptr++; + val1 = *slow_mem_ptr++; - if(!altcharset) { - if(val0 >= 0x40 && val0 < 0x80) { - if(flash_state) { - val0 += 0x40; - } else { - val0 -= 0x40; - } - } - if(val1 >= 0x40 && val1 < 0x80) { - if(flash_state) { - val1 += 0x40; - } else { - val1 -= 0x40; - } - } - } - save_img_ptr = img_ptr; - save_img_ptr2 = img_ptr2; + if(!altcharset) { + if(val0 >= 0x40 && val0 < 0x80) { + if(flash_state) { + val0 += 0x40; + } else { + val0 -= 0x40; + } + } + if(val1 >= 0x40 && val1 < 0x80) { + if(flash_state) { + val1 += 0x40; + } else { + val1 -= 0x40; + } + } + } + save_img_ptr = img_ptr; + save_img_ptr2 = img_ptr2; - for(i = st_line_mod8; i < 8; i++) { - font_ptr1 = &(g_font40_even_bits[val0][i][0]); - tmp0 = (font_ptr1[0] & and_val) + add_val; - tmp1 = (font_ptr1[1] & and_val) + add_val; - tmp2 = (font_ptr1[2] & and_val) + add_val; + for(i = st_line_mod8; i < 8; i++) { + font_ptr1 = &(g_font40_even_bits[val0][i][0]); + tmp0 = (font_ptr1[0] & and_val) + add_val; + tmp1 = (font_ptr1[1] & and_val) + add_val; + tmp2 = (font_ptr1[2] & and_val) + add_val; - font_ptr2 = &(g_font40_odd_bits[val1][i][0]); - tmp3 = ((font_ptr1[3]+font_ptr2[0]) & and_val)+ - add_val; + font_ptr2 = &(g_font40_odd_bits[val1][i][0]); + tmp3 = ((font_ptr1[3]+font_ptr2[0]) & and_val)+ + add_val; - tmp4 = (font_ptr2[1] & and_val) + add_val; - tmp5 = (font_ptr2[2] & and_val) + add_val; - tmp6 = (font_ptr2[3] & and_val) + add_val; + tmp4 = (font_ptr2[1] & and_val) + add_val; + tmp5 = (font_ptr2[2] & and_val) + add_val; + tmp6 = (font_ptr2[3] & and_val) + add_val; - tmp0 = (tmp0 & ff_val) + palette_add; - tmp1 = (tmp1 & ff_val) + palette_add; - tmp2 = (tmp2 & ff_val) + palette_add; - tmp3 = (tmp3 & ff_val) + palette_add; - tmp4 = (tmp4 & ff_val) + palette_add; - tmp5 = (tmp5 & ff_val) + palette_add; - tmp6 = (tmp6 & ff_val) + palette_add; + tmp0 = (tmp0 & ff_val) + palette_add; + tmp1 = (tmp1 & ff_val) + palette_add; + tmp2 = (tmp2 & ff_val) + palette_add; + tmp3 = (tmp3 & ff_val) + palette_add; + tmp4 = (tmp4 & ff_val) + palette_add; + tmp5 = (tmp5 & ff_val) + palette_add; + tmp6 = (tmp6 & ff_val) + palette_add; - img_ptr[0] = tmp0; - img_ptr[1] = tmp1; - img_ptr[2] = tmp2; - img_ptr[3] = tmp3; - img_ptr[4] = tmp4; - img_ptr[5] = tmp5; - img_ptr[6] = tmp6; + img_ptr[0] = tmp0; + img_ptr[1] = tmp1; + img_ptr[2] = tmp2; + img_ptr[3] = tmp3; + img_ptr[4] = tmp4; + img_ptr[5] = tmp5; + img_ptr[6] = tmp6; - img_ptr2[0] = tmp0; - img_ptr2[1] = tmp1; - img_ptr2[2] = tmp2; - img_ptr2[3] = tmp3; - img_ptr2[4] = tmp4; - img_ptr2[5] = tmp5; - img_ptr2[6] = tmp6; + img_ptr2[0] = tmp0; + img_ptr2[1] = tmp1; + img_ptr2[2] = tmp2; + img_ptr2[3] = tmp3; + img_ptr2[4] = tmp4; + img_ptr2[5] = tmp5; + img_ptr2[6] = tmp6; - img_ptr += (2*pixels_per_line)/4; - img_ptr2 += (2*pixels_per_line)/4; - } + img_ptr += (2*pixels_per_line)/4; + img_ptr2 += (2*pixels_per_line)/4; + } - img_ptr = save_img_ptr + 7; - img_ptr2 = save_img_ptr2 + 7; - } - } - GET_ITIMER(end_time); + img_ptr = save_img_ptr + 7; + img_ptr2 = save_img_ptr2 + 7; + } + } + GET_ITIMER(end_time); - for(i = 0; i < (8 - st_line_mod8); i++) { - g_a2_line_left_edge[st_line + i] = (left*14); - g_a2_line_right_edge[st_line + i] = (right*14); - } + for(i = 0; i < (8 - st_line_mod8); i++) { + g_a2_line_left_edge[st_line + i] = (left*14); + g_a2_line_right_edge[st_line + i] = (right*14); + } - if(left >= right || left < 0 || right < 0) { - printf("line %d, 40: left >= right: %d >= %d\n", - start_line, left, right); - } + if(left >= right || left < 0 || right < 0) { + printf("line %d, 40: left >= right: %d >= %d\n", + start_line, left, right); + } - g_cycs_in_40col += (end_time - start_time); + g_cycs_in_40col += (end_time - start_time); - g_need_redraw = 0; + g_need_redraw = 0; } -void -redraw_changed_text_80(int start_offset, int start_line, int num_lines, - int reparse, byte *screen_data, int altcharset, int bg_val, int fg_val, - int pixels_per_line) -{ - const word32 *font_ptr0, *font_ptr1, *font_ptr2, *font_ptr3; - word32 *ch_ptr; - word32 *img_ptr, *img_ptr2; - word32 *save_img_ptr, *save_img_ptr2; - byte *b_ptr; - byte *slow_mem_ptr; - word32 ch_mask; - word32 ch_tmp; - word32 mask_per_line; - word32 mem_ptr; - word32 tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6; - word32 diff_val; - word32 add_val, and_val, ff_val; - word32 palette_add; - word32 line_mask; - word32 val0, val1, val2, val3; - int st_line_mod8, st_line; - int flash_state; - int y; - int x1, x2; - int i; - int ch_bitpos; - int bits_per_line; - int ch_shift_amount; - int shift_per; - int left, right; +void redraw_changed_text_80(int start_offset, int start_line, int num_lines, + int reparse, byte *screen_data, int altcharset, int bg_val, int fg_val, + int pixels_per_line) { + const word32 *font_ptr0, *font_ptr1, *font_ptr2, *font_ptr3; + word32 *ch_ptr; + word32 *img_ptr, *img_ptr2; + word32 *save_img_ptr, *save_img_ptr2; + byte *b_ptr; + byte *slow_mem_ptr; + word32 ch_mask; + word32 ch_tmp; + word32 mask_per_line; + word32 mem_ptr; + word32 tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6; + word32 diff_val; + word32 add_val, and_val, ff_val; + word32 palette_add; + word32 line_mask; + word32 val0, val1, val2, val3; + int st_line_mod8, st_line; + int flash_state; + int y; + int x1, x2; + int i; + int ch_bitpos; + int bits_per_line; + int ch_shift_amount; + int shift_per; + int left, right; - st_line_mod8 = start_line & 7; - st_line = start_line; + st_line_mod8 = start_line & 7; + st_line = start_line; - start_line = start_line >> 3; + start_line = start_line >> 3; - y = start_line; - line_mask = 1 << (y); - mem_ptr = 0x400 + g_screen_index[y] + start_offset; - if(mem_ptr < 0x400 || mem_ptr >= 0xc00) { - halt_printf("redraw_changed_text: mem_ptr: %08x\n", mem_ptr); - } + y = start_line; + line_mask = 1 << (y); + mem_ptr = 0x400 + g_screen_index[y] + start_offset; + if(mem_ptr < 0x400 || mem_ptr >= 0xc00) { + halt_printf("redraw_changed_text: mem_ptr: %08x\n", mem_ptr); + } - CH_SETUP_A2_VID(mem_ptr, ch_mask, reparse, (st_line_mod8 == 0)); + CH_SETUP_A2_VID(mem_ptr, ch_mask, reparse, (st_line_mod8 == 0)); - if(ch_mask == 0) { - return; - } + if(ch_mask == 0) { + return; + } - shift_per = (1 << SHIFT_PER_CHANGE); + shift_per = (1 << SHIFT_PER_CHANGE); - g_a2_screen_buffer_changed |= line_mask; + g_a2_screen_buffer_changed |= line_mask; - palette_add = (g_a2vid_palette << 4); - palette_add = palette_add + (palette_add << 8) + (palette_add << 16) + - (palette_add << 24); + palette_add = (g_a2vid_palette << 4); + palette_add = palette_add + (palette_add << 8) + (palette_add << 16) + + (palette_add << 24); - left = 40; - right = 0; + left = 40; + right = 0; - diff_val = (fg_val - bg_val) & 0xf; - add_val = bg_val + (bg_val << 8) + (bg_val << 16) + (bg_val << 24); - and_val = diff_val + (diff_val << 8) + (diff_val << 16) +(diff_val<<24); - ff_val = 0x0f0f0f0f; + diff_val = (fg_val - bg_val) & 0xf; + add_val = bg_val + (bg_val << 8) + (bg_val << 16) + (bg_val << 24); + and_val = diff_val + (diff_val << 8) + (diff_val << 16) +(diff_val<<24); + ff_val = 0x0f0f0f0f; - flash_state = (g_cur_a2_stat & ALL_STAT_FLASH_STATE); + flash_state = (g_cur_a2_stat & ALL_STAT_FLASH_STATE); - for(x1 = 0; x1 < 40; x1 += shift_per) { - CH_LOOP_A2_VID(ch_mask, ch_tmp); + for(x1 = 0; x1 < 40; x1 += shift_per) { + CH_LOOP_A2_VID(ch_mask, ch_tmp); - left = MIN(x1, left); - right = MAX(x1 + shift_per, right); + left = MIN(x1, left); + right = MAX(x1 + shift_per, right); - slow_mem_ptr = &(g_slow_memory_ptr[mem_ptr + x1]); - b_ptr = &screen_data[(y*8 + st_line_mod8)*2*pixels_per_line + - x1*14]; - img_ptr = (word32 *)b_ptr; - img_ptr2 = (word32 *)(b_ptr + pixels_per_line); + slow_mem_ptr = &(g_slow_memory_ptr[mem_ptr + x1]); + b_ptr = &screen_data[(y*8 + st_line_mod8)*2*pixels_per_line + + x1*14]; + img_ptr = (word32 *)b_ptr; + img_ptr2 = (word32 *)(b_ptr + pixels_per_line); - for(x2 = 0; x2 < shift_per; x2 += 2) { - /* do 4 chars at once! */ + for(x2 = 0; x2 < shift_per; x2 += 2) { + /* do 4 chars at once! */ - val1 = slow_mem_ptr[0]; - val3 = slow_mem_ptr[1]; - val0 = slow_mem_ptr[0x10000]; - val2 = slow_mem_ptr[0x10001]; - slow_mem_ptr += 2; + val1 = slow_mem_ptr[0]; + val3 = slow_mem_ptr[1]; + val0 = slow_mem_ptr[0x10000]; + val2 = slow_mem_ptr[0x10001]; + slow_mem_ptr += 2; - if(!altcharset) { - if(val0 >= 0x40 && val0 < 0x80) { - if(flash_state) { - val0 += 0x40; - } else { - val0 -= 0x40; - } - } - if(val1 >= 0x40 && val1 < 0x80) { - if(flash_state) { - val1 += 0x40; - } else { - val1 -= 0x40; - } - } - if(val2 >= 0x40 && val2 < 0x80) { - if(flash_state) { - val2 += 0x40; - } else { - val2 -= 0x40; - } - } - if(val3 >= 0x40 && val3 < 0x80) { - if(flash_state) { - val3 += 0x40; - } else { - val3 -= 0x40; - } - } - } - save_img_ptr = img_ptr; - save_img_ptr2 = img_ptr2; + if(!altcharset) { + if(val0 >= 0x40 && val0 < 0x80) { + if(flash_state) { + val0 += 0x40; + } else { + val0 -= 0x40; + } + } + if(val1 >= 0x40 && val1 < 0x80) { + if(flash_state) { + val1 += 0x40; + } else { + val1 -= 0x40; + } + } + if(val2 >= 0x40 && val2 < 0x80) { + if(flash_state) { + val2 += 0x40; + } else { + val2 -= 0x40; + } + } + if(val3 >= 0x40 && val3 < 0x80) { + if(flash_state) { + val3 += 0x40; + } else { + val3 -= 0x40; + } + } + } + save_img_ptr = img_ptr; + save_img_ptr2 = img_ptr2; - for(i = st_line_mod8; i < 8; i++) { - font_ptr0 = &(g_font80_off0_bits[val0][i][0]); - tmp0 = (font_ptr0[0] & and_val) + add_val; + for(i = st_line_mod8; i < 8; i++) { + font_ptr0 = &(g_font80_off0_bits[val0][i][0]); + tmp0 = (font_ptr0[0] & and_val) + add_val; - font_ptr3 = &(g_font80_off3_bits[val1][i][0]); - tmp1 = ((font_ptr0[1]+font_ptr3[0]) & and_val)+ - add_val; - /* 3 bytes from ptr0, 1 from ptr3 */ - tmp2 = (font_ptr3[1] & and_val) + add_val; + font_ptr3 = &(g_font80_off3_bits[val1][i][0]); + tmp1 = ((font_ptr0[1]+font_ptr3[0]) & and_val)+ + add_val; + /* 3 bytes from ptr0, 1 from ptr3 */ + tmp2 = (font_ptr3[1] & and_val) + add_val; - font_ptr2 = &(g_font80_off2_bits[val2][i][0]); - tmp3 = ((font_ptr3[2]+font_ptr2[0]) & and_val)+ - add_val; - /* 2 bytes from ptr3, 2 from ptr2*/ - tmp4 = (font_ptr2[1] & and_val) + add_val; + font_ptr2 = &(g_font80_off2_bits[val2][i][0]); + tmp3 = ((font_ptr3[2]+font_ptr2[0]) & and_val)+ + add_val; + /* 2 bytes from ptr3, 2 from ptr2*/ + tmp4 = (font_ptr2[1] & and_val) + add_val; - font_ptr1 = &(g_font80_off1_bits[val3][i][0]); - tmp5 = ((font_ptr2[2]+font_ptr1[0]) & and_val)+ - add_val; - /* 1 byte from ptr2, 3 from ptr1 */ - tmp6 = (font_ptr1[1] & and_val) + add_val; + font_ptr1 = &(g_font80_off1_bits[val3][i][0]); + tmp5 = ((font_ptr2[2]+font_ptr1[0]) & and_val)+ + add_val; + /* 1 byte from ptr2, 3 from ptr1 */ + tmp6 = (font_ptr1[1] & and_val) + add_val; - tmp0 = (tmp0 & ff_val) + palette_add; - tmp1 = (tmp1 & ff_val) + palette_add; - tmp2 = (tmp2 & ff_val) + palette_add; - tmp3 = (tmp3 & ff_val) + palette_add; - tmp4 = (tmp4 & ff_val) + palette_add; - tmp5 = (tmp5 & ff_val) + palette_add; - tmp6 = (tmp6 & ff_val) + palette_add; + tmp0 = (tmp0 & ff_val) + palette_add; + tmp1 = (tmp1 & ff_val) + palette_add; + tmp2 = (tmp2 & ff_val) + palette_add; + tmp3 = (tmp3 & ff_val) + palette_add; + tmp4 = (tmp4 & ff_val) + palette_add; + tmp5 = (tmp5 & ff_val) + palette_add; + tmp6 = (tmp6 & ff_val) + palette_add; - img_ptr[0] = tmp0; - img_ptr[1] = tmp1; - img_ptr[2] = tmp2; - img_ptr[3] = tmp3; - img_ptr[4] = tmp4; - img_ptr[5] = tmp5; - img_ptr[6] = tmp6; + img_ptr[0] = tmp0; + img_ptr[1] = tmp1; + img_ptr[2] = tmp2; + img_ptr[3] = tmp3; + img_ptr[4] = tmp4; + img_ptr[5] = tmp5; + img_ptr[6] = tmp6; - img_ptr2[0] = tmp0; - img_ptr2[1] = tmp1; - img_ptr2[2] = tmp2; - img_ptr2[3] = tmp3; - img_ptr2[4] = tmp4; - img_ptr2[5] = tmp5; - img_ptr2[6] = tmp6; + img_ptr2[0] = tmp0; + img_ptr2[1] = tmp1; + img_ptr2[2] = tmp2; + img_ptr2[3] = tmp3; + img_ptr2[4] = tmp4; + img_ptr2[5] = tmp5; + img_ptr2[6] = tmp6; - img_ptr += (2*pixels_per_line)/4; - img_ptr2 += (2*pixels_per_line)/4; - } + img_ptr += (2*pixels_per_line)/4; + img_ptr2 += (2*pixels_per_line)/4; + } - img_ptr = save_img_ptr + 7; - img_ptr2 = save_img_ptr2 + 7; + img_ptr = save_img_ptr + 7; + img_ptr2 = save_img_ptr2 + 7; - } - } + } + } - for(i = 0; i < (8 - st_line_mod8); i++) { - g_a2_line_left_edge[st_line + i] = (left*14); - g_a2_line_right_edge[st_line + i] = (right*14); - } + for(i = 0; i < (8 - st_line_mod8); i++) { + g_a2_line_left_edge[st_line + i] = (left*14); + g_a2_line_right_edge[st_line + i] = (right*14); + } - if(left >= right || left < 0 || right < 0) { - printf("line %d, 80: left >= right: %d >= %d\n", - start_line, left, right); - } + if(left >= right || left < 0 || right < 0) { + printf("line %d, 80: left >= right: %d >= %d\n", + start_line, left, right); + } - g_need_redraw = 0; + g_need_redraw = 0; } -void -redraw_changed_gr(int start_offset, int start_line, int num_lines, int reparse, - byte *screen_data, int pixels_per_line) -{ - word32 *img_ptr; - word32 *save_img_ptr; - word32 *ch_ptr; - byte *b_ptr; - byte *slow_mem_ptr; - word32 mask_per_line; - word32 ch_mask; - word32 ch_tmp; - word32 mem_ptr; - word32 line_mask; - word32 val0, val1; - word32 val0_wd, val1_wd; - word32 val01_wd; - word32 val_even, val_odd; - word32 palette_add; - int half; - int x1, x2; - int y; - int y2; - int ch_bitpos; - int bits_per_line; - int ch_shift_amount; - int shift_per; - int left, right; - int st_line_mod8, st_line, eff_line, end_line; - int i; +void redraw_changed_gr(int start_offset, int start_line, int num_lines, int reparse, + byte *screen_data, int pixels_per_line) { + word32 *img_ptr; + word32 *save_img_ptr; + word32 *ch_ptr; + byte *b_ptr; + byte *slow_mem_ptr; + word32 mask_per_line; + word32 ch_mask; + word32 ch_tmp; + word32 mem_ptr; + word32 line_mask; + word32 val0, val1; + word32 val0_wd, val1_wd; + word32 val01_wd; + word32 val_even, val_odd; + word32 palette_add; + int half; + int x1, x2; + int y; + int y2; + int ch_bitpos; + int bits_per_line; + int ch_shift_amount; + int shift_per; + int left, right; + int st_line_mod8, st_line, eff_line, end_line; + int i; - st_line_mod8 = start_line & 7; - st_line = start_line; - end_line = 8; // st_line_mod8 + num_lines; + st_line_mod8 = start_line & 7; + st_line = start_line; + end_line = 8; // st_line_mod8 + num_lines; - start_line = start_line >> 3; + start_line = start_line >> 3; - y = start_line; - line_mask = 1 << y; - mem_ptr = 0x400 + g_screen_index[y] + start_offset; - if(mem_ptr < 0x400 || mem_ptr >= 0xc00) { - printf("redraw_changed_gr: mem_ptr: %08x\n", mem_ptr); - } + y = start_line; + line_mask = 1 << y; + mem_ptr = 0x400 + g_screen_index[y] + start_offset; + if(mem_ptr < 0x400 || mem_ptr >= 0xc00) { + printf("redraw_changed_gr: mem_ptr: %08x\n", mem_ptr); + } - CH_SETUP_A2_VID(mem_ptr, ch_mask, reparse, (st_line_mod8 == 0)); + CH_SETUP_A2_VID(mem_ptr, ch_mask, reparse, (st_line_mod8 == 0)); - if(ch_mask == 0) { - return; - } + if(ch_mask == 0) { + return; + } - shift_per = (1 << SHIFT_PER_CHANGE); + shift_per = (1 << SHIFT_PER_CHANGE); - g_a2_screen_buffer_changed |= line_mask; + g_a2_screen_buffer_changed |= line_mask; - palette_add = (g_a2vid_palette << 4); - palette_add = palette_add + (palette_add << 8) + (palette_add << 16) + - (palette_add << 24); + palette_add = (g_a2vid_palette << 4); + palette_add = palette_add + (palette_add << 8) + (palette_add << 16) + + (palette_add << 24); - left = 40; - right = 0; + left = 40; + right = 0; - for(x1 = 0; x1 < 40; x1 += shift_per) { - CH_LOOP_A2_VID(ch_mask, ch_tmp); + for(x1 = 0; x1 < 40; x1 += shift_per) { + CH_LOOP_A2_VID(ch_mask, ch_tmp); - left = MIN(x1, left); - right = MAX(x1 + shift_per, right); + left = MIN(x1, left); + right = MAX(x1 + shift_per, right); - slow_mem_ptr = &(g_slow_memory_ptr[mem_ptr + x1]); - b_ptr = &screen_data[(y*8 + st_line_mod8)*2*pixels_per_line + - x1*14]; - img_ptr = (word32 *)b_ptr; + slow_mem_ptr = &(g_slow_memory_ptr[mem_ptr + x1]); + b_ptr = &screen_data[(y*8 + st_line_mod8)*2*pixels_per_line + + x1*14]; + img_ptr = (word32 *)b_ptr; - for(x2 = 0; x2 < shift_per; x2 += 2) { - val_even = *slow_mem_ptr++; - val_odd = *slow_mem_ptr++; + for(x2 = 0; x2 < shift_per; x2 += 2) { + val_even = *slow_mem_ptr++; + val_odd = *slow_mem_ptr++; - save_img_ptr = img_ptr; + save_img_ptr = img_ptr; - for(half = 0; half < 2; half++) { - val0 = val_even & 0xf; - val1 = val_odd & 0xf; - val0_wd = (val0 << 24) + (val0 << 16) + - (val0 << 8) + val0; - val1_wd = (val1 << 24) + (val1 << 16) + - (val1 << 8) + val1; + for(half = 0; half < 2; half++) { + val0 = val_even & 0xf; + val1 = val_odd & 0xf; + val0_wd = (val0 << 24) + (val0 << 16) + + (val0 << 8) + val0; + val1_wd = (val1 << 24) + (val1 << 16) + + (val1 << 8) + val1; #if defined(GSPORT_LITTLE_ENDIAN) || defined (__LITTLE_ENDIAN__) // OSX needs to calculate endianness mid-compilation, can't be passed on compile command - val01_wd = (val1_wd << 16) + (val0_wd & 0xffff); + val01_wd = (val1_wd << 16) + (val0_wd & 0xffff); #else - val01_wd = (val0_wd << 16) + (val1_wd & 0xffff); + val01_wd = (val0_wd << 16) + (val1_wd & 0xffff); #endif - for(y2 = 0; y2 < 8; y2++) { - eff_line = half*4 + (y2 >> 1); - if((eff_line < st_line_mod8) || - (eff_line > end_line)) { - continue; - } - - img_ptr[0] = val0_wd + palette_add; - img_ptr[1] = val0_wd + palette_add; - img_ptr[2] = val0_wd + palette_add; - img_ptr[3] = val01_wd + palette_add; - img_ptr[4] = val1_wd + palette_add; - img_ptr[5] = val1_wd + palette_add; - img_ptr[6] = val1_wd + palette_add; - img_ptr += (pixels_per_line)/4; - } + for(y2 = 0; y2 < 8; y2++) { + eff_line = half*4 + (y2 >> 1); + if((eff_line < st_line_mod8) || + (eff_line > end_line)) { + continue; + } + + img_ptr[0] = val0_wd + palette_add; + img_ptr[1] = val0_wd + palette_add; + img_ptr[2] = val0_wd + palette_add; + img_ptr[3] = val01_wd + palette_add; + img_ptr[4] = val1_wd + palette_add; + img_ptr[5] = val1_wd + palette_add; + img_ptr[6] = val1_wd + palette_add; + img_ptr += (pixels_per_line)/4; + } - val_even = val_even >> 4; - val_odd = val_odd >> 4; - } + val_even = val_even >> 4; + val_odd = val_odd >> 4; + } - img_ptr = save_img_ptr + 7; - } - } + img_ptr = save_img_ptr + 7; + } + } - for(i = 0; i < (8 - st_line_mod8); i++) { - g_a2_line_left_edge[st_line + i] = (left*14); - g_a2_line_right_edge[st_line + i] = (right*14); - } + for(i = 0; i < (8 - st_line_mod8); i++) { + g_a2_line_left_edge[st_line + i] = (left*14); + g_a2_line_right_edge[st_line + i] = (right*14); + } - g_need_redraw = 0; + g_need_redraw = 0; } -void -redraw_changed_dbl_gr(int start_offset, int start_line, int num_lines, - int reparse, byte *screen_data, int pixels_per_line) -{ - word32 *img_ptr; - word32 *save_img_ptr; - word32 *ch_ptr; - byte *b_ptr; - byte *slow_mem_ptr; - word32 mask_per_line; - word32 ch_mask; - word32 ch_tmp; - word32 mem_ptr; - word32 line_mask; - word32 val0, val1, val2, val3; - word32 val0_wd, val1_wd, val2_wd, val3_wd; - word32 val01_wd, val12_wd, val23_wd; - word32 val_even_main, val_odd_main; - word32 val_even_aux, val_odd_aux; - word32 palette_add; - int half; - int x1, x2; - int y; - int y2; - int ch_bitpos; - int bits_per_line; - int ch_shift_amount; - int shift_per; - int left, right; - int st_line_mod8, st_line, eff_line, end_line; - int i; +void redraw_changed_dbl_gr(int start_offset, int start_line, int num_lines, + int reparse, byte *screen_data, int pixels_per_line) { + word32 *img_ptr; + word32 *save_img_ptr; + word32 *ch_ptr; + byte *b_ptr; + byte *slow_mem_ptr; + word32 mask_per_line; + word32 ch_mask; + word32 ch_tmp; + word32 mem_ptr; + word32 line_mask; + word32 val0, val1, val2, val3; + word32 val0_wd, val1_wd, val2_wd, val3_wd; + word32 val01_wd, val12_wd, val23_wd; + word32 val_even_main, val_odd_main; + word32 val_even_aux, val_odd_aux; + word32 palette_add; + int half; + int x1, x2; + int y; + int y2; + int ch_bitpos; + int bits_per_line; + int ch_shift_amount; + int shift_per; + int left, right; + int st_line_mod8, st_line, eff_line, end_line; + int i; - st_line_mod8 = start_line & 7; - end_line = 8; // st_line_mod8 + num_lines - st_line = start_line; + st_line_mod8 = start_line & 7; + end_line = 8; // st_line_mod8 + num_lines + st_line = start_line; - start_line = start_line >> 3; + start_line = start_line >> 3; - y = start_line; - line_mask = 1 << y; - mem_ptr = 0x400 + g_screen_index[y] + start_offset; - if(mem_ptr < 0x400 || mem_ptr >= 0xc00) { - printf("redraw_changed_dbl_gr: mem_ptr: %08x\n", mem_ptr); - } + y = start_line; + line_mask = 1 << y; + mem_ptr = 0x400 + g_screen_index[y] + start_offset; + if(mem_ptr < 0x400 || mem_ptr >= 0xc00) { + printf("redraw_changed_dbl_gr: mem_ptr: %08x\n", mem_ptr); + } - CH_SETUP_A2_VID(mem_ptr, ch_mask, reparse, (st_line_mod8 == 0)); + CH_SETUP_A2_VID(mem_ptr, ch_mask, reparse, (st_line_mod8 == 0)); - if(ch_mask == 0) { - return; - } + if(ch_mask == 0) { + return; + } - shift_per = (1 << SHIFT_PER_CHANGE); + shift_per = (1 << SHIFT_PER_CHANGE); - g_a2_screen_buffer_changed |= line_mask; + g_a2_screen_buffer_changed |= line_mask; - palette_add = (g_a2vid_palette << 4); - palette_add = palette_add + (palette_add << 8) + (palette_add << 16) + - (palette_add << 24); + palette_add = (g_a2vid_palette << 4); + palette_add = palette_add + (palette_add << 8) + (palette_add << 16) + + (palette_add << 24); - left = 40; - right = 0; + left = 40; + right = 0; - for(x1 = 0; x1 < 40; x1 += shift_per) { - CH_LOOP_A2_VID(ch_mask, ch_tmp); + for(x1 = 0; x1 < 40; x1 += shift_per) { + CH_LOOP_A2_VID(ch_mask, ch_tmp); - left = MIN(x1, left); - right = MAX(x1 + shift_per, right); + left = MIN(x1, left); + right = MAX(x1 + shift_per, right); - slow_mem_ptr = &(g_slow_memory_ptr[mem_ptr + x1]); - b_ptr = &screen_data[(y*8 + st_line_mod8)*2*pixels_per_line + - x1*14]; - img_ptr = (word32 *)b_ptr; + slow_mem_ptr = &(g_slow_memory_ptr[mem_ptr + x1]); + b_ptr = &screen_data[(y*8 + st_line_mod8)*2*pixels_per_line + + x1*14]; + img_ptr = (word32 *)b_ptr; - for(x2 = 0; x2 < shift_per; x2 += 2) { - val_even_main = slow_mem_ptr[0]; - val_odd_main = slow_mem_ptr[1]; - val_even_aux = slow_mem_ptr[0x10000]; - val_odd_aux = slow_mem_ptr[0x10001]; - slow_mem_ptr += 2; + for(x2 = 0; x2 < shift_per; x2 += 2) { + val_even_main = slow_mem_ptr[0]; + val_odd_main = slow_mem_ptr[1]; + val_even_aux = slow_mem_ptr[0x10000]; + val_odd_aux = slow_mem_ptr[0x10001]; + slow_mem_ptr += 2; - save_img_ptr = img_ptr; + save_img_ptr = img_ptr; - for(half = 0; half < 2; half++) { - val0 = val_even_aux & 0xf; - val1 = val_even_main & 0xf; - val2 = val_odd_aux & 0xf; - val3 = val_odd_main & 0xf; + for(half = 0; half < 2; half++) { + val0 = val_even_aux & 0xf; + val1 = val_even_main & 0xf; + val2 = val_odd_aux & 0xf; + val3 = val_odd_main & 0xf; - /* Handle funny pattern of dbl gr aux mem */ - val0 = ((val0 << 1) & 0xf) + (val0 >> 3); - val2 = ((val2 << 1) & 0xf) + (val2 >> 3); + /* Handle funny pattern of dbl gr aux mem */ + val0 = ((val0 << 1) & 0xf) + (val0 >> 3); + val2 = ((val2 << 1) & 0xf) + (val2 >> 3); - val0_wd = (val0 << 24) + (val0 << 16) + - (val0 << 8) + val0; - val1_wd = (val1 << 24) + (val1 << 16) + - (val1 << 8) + val1; - val2_wd = (val2 << 24) + (val2 << 16) + - (val2 << 8) + val2; - val3_wd = (val3 << 24) + (val3 << 16) + - (val3 << 8) + val3; + val0_wd = (val0 << 24) + (val0 << 16) + + (val0 << 8) + val0; + val1_wd = (val1 << 24) + (val1 << 16) + + (val1 << 8) + val1; + val2_wd = (val2 << 24) + (val2 << 16) + + (val2 << 8) + val2; + val3_wd = (val3 << 24) + (val3 << 16) + + (val3 << 8) + val3; #if defined(GSPORT_LITTLE_ENDIAN) || defined (__LITTLE_ENDIAN__) // OSX needs to calculate endianness mid-compilation, can't be passed on compile command - val01_wd = (val1_wd << 24) + (val0_wd&0xffffff); - val12_wd = (val2_wd << 16) + (val1_wd & 0xffff); - val23_wd = (val3_wd << 8) + (val2_wd & 0xff); + val01_wd = (val1_wd << 24) + (val0_wd&0xffffff); + val12_wd = (val2_wd << 16) + (val1_wd & 0xffff); + val23_wd = (val3_wd << 8) + (val2_wd & 0xff); #else - val01_wd = (val0_wd << 8) + (val1_wd & 0xff); - val12_wd = (val1_wd << 16) + (val2_wd & 0xffff); - val23_wd = (val2_wd << 24) + (val3_wd&0xffffff); + val01_wd = (val0_wd << 8) + (val1_wd & 0xff); + val12_wd = (val1_wd << 16) + (val2_wd & 0xffff); + val23_wd = (val2_wd << 24) + (val3_wd&0xffffff); #endif - for(y2 = 0; y2 < 8; y2++) { - eff_line = half*4 + (y2 >> 1); - if((eff_line < st_line_mod8) || - (eff_line > end_line)) { - continue; - } - img_ptr[0] = val0_wd + palette_add; - img_ptr[1] = val01_wd + palette_add; - img_ptr[2] = val1_wd + palette_add; - img_ptr[3] = val12_wd + palette_add; - img_ptr[4] = val2_wd + palette_add; - img_ptr[5] = val23_wd + palette_add; - img_ptr[6] = val3_wd + palette_add; - img_ptr += (pixels_per_line)/4; - } + for(y2 = 0; y2 < 8; y2++) { + eff_line = half*4 + (y2 >> 1); + if((eff_line < st_line_mod8) || + (eff_line > end_line)) { + continue; + } + img_ptr[0] = val0_wd + palette_add; + img_ptr[1] = val01_wd + palette_add; + img_ptr[2] = val1_wd + palette_add; + img_ptr[3] = val12_wd + palette_add; + img_ptr[4] = val2_wd + palette_add; + img_ptr[5] = val23_wd + palette_add; + img_ptr[6] = val3_wd + palette_add; + img_ptr += (pixels_per_line)/4; + } - val_even_aux = val_even_aux >> 4; - val_even_main = val_even_main >> 4; - val_odd_aux = val_odd_aux >> 4; - val_odd_main = val_odd_main >> 4; - } + val_even_aux = val_even_aux >> 4; + val_even_main = val_even_main >> 4; + val_odd_aux = val_odd_aux >> 4; + val_odd_main = val_odd_main >> 4; + } - img_ptr = save_img_ptr + 7; - } - } + img_ptr = save_img_ptr + 7; + } + } - for(i = 0; i < (8 - st_line_mod8); i++) { - g_a2_line_left_edge[st_line + i] = (left*14); - g_a2_line_right_edge[st_line + i] = (right*14); - } + for(i = 0; i < (8 - st_line_mod8); i++) { + g_a2_line_left_edge[st_line + i] = (left*14); + g_a2_line_right_edge[st_line + i] = (right*14); + } - g_need_redraw = 0; + g_need_redraw = 0; } -void -redraw_changed_hires(int start_offset, int start_line, int num_lines, - int color, int reparse, byte *screen_data, int pixels_per_line) -{ - if(!color) { - redraw_changed_hires_color(start_offset, start_line, num_lines, - reparse, screen_data, pixels_per_line); - } else { - redraw_changed_hires_bw(start_offset, start_line, num_lines, - reparse, screen_data, pixels_per_line); - } +void redraw_changed_hires(int start_offset, int start_line, int num_lines, + int color, int reparse, byte *screen_data, int pixels_per_line) { + if(!color) { + redraw_changed_hires_color(start_offset, start_line, num_lines, + reparse, screen_data, pixels_per_line); + } else { + redraw_changed_hires_bw(start_offset, start_line, num_lines, + reparse, screen_data, pixels_per_line); + } } -void -redraw_changed_hires_bw(int start_offset, int start_line, int num_lines, - int reparse, byte *screen_data, int pixels_per_line) -{ - word32 *img_ptr, *img_ptr2; - word32 *ch_ptr; - byte *b_ptr; - byte *slow_mem_ptr; - word32 mask_per_line; - word32 ch_mask; - word32 ch_tmp; - word32 tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6; - word32 mem_ptr; - word32 val0, val1; - word32 val_whole; - word32 line_mask; - word32 palette_add; - int y; - int x1, x2; - int ch_bitpos; - int bits_per_line; - int ch_shift_amount; - int shift_per; - int left, right; - int st_line; - int i; +void redraw_changed_hires_bw(int start_offset, int start_line, int num_lines, + int reparse, byte *screen_data, int pixels_per_line) { + word32 *img_ptr, *img_ptr2; + word32 *ch_ptr; + byte *b_ptr; + byte *slow_mem_ptr; + word32 mask_per_line; + word32 ch_mask; + word32 ch_tmp; + word32 tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6; + word32 mem_ptr; + word32 val0, val1; + word32 val_whole; + word32 line_mask; + word32 palette_add; + int y; + int x1, x2; + int ch_bitpos; + int bits_per_line; + int ch_shift_amount; + int shift_per; + int left, right; + int st_line; + int i; - st_line = start_line; - start_line = start_line >> 3; + st_line = start_line; + start_line = start_line >> 3; - palette_add = (g_a2vid_palette << 4); - palette_add = palette_add + (palette_add << 8) + (palette_add << 16) + - (palette_add << 24); + palette_add = (g_a2vid_palette << 4); + palette_add = palette_add + (palette_add << 8) + (palette_add << 16) + + (palette_add << 24); - left = 40; - right = 0; + left = 40; + right = 0; - for(y = st_line; y < (st_line + num_lines); y++) { - line_mask = 1 << (y >> 3); - mem_ptr = 0x2000 + (((y & 7) * 0x400) + - g_screen_index[y >> 3]) + start_offset; + for(y = st_line; y < (st_line + num_lines); y++) { + line_mask = 1 << (y >> 3); + mem_ptr = 0x2000 + (((y & 7) * 0x400) + + g_screen_index[y >> 3]) + start_offset; - CH_SETUP_A2_VID(mem_ptr, ch_mask, reparse, 1); + CH_SETUP_A2_VID(mem_ptr, ch_mask, reparse, 1); - if(ch_mask == 0) { - continue; - } + if(ch_mask == 0) { + continue; + } - /* Hires depends on adjacent bits, so also reparse adjacent */ - /* regions so that if bits on the edge change, redrawing is */ - /* correct */ - ch_mask = ch_mask | (ch_mask >> 1) | (ch_mask << 1); + /* Hires depends on adjacent bits, so also reparse adjacent */ + /* regions so that if bits on the edge change, redrawing is */ + /* correct */ + ch_mask = ch_mask | (ch_mask >> 1) | (ch_mask << 1); - shift_per = (1 << SHIFT_PER_CHANGE); + shift_per = (1 << SHIFT_PER_CHANGE); - g_a2_screen_buffer_changed |= line_mask; + g_a2_screen_buffer_changed |= line_mask; - for(x1 = 0; x1 < 40; x1 += shift_per) { - CH_LOOP_A2_VID(ch_mask, ch_tmp); + for(x1 = 0; x1 < 40; x1 += shift_per) { + CH_LOOP_A2_VID(ch_mask, ch_tmp); - left = MIN(x1, left); - right = MAX(x1 + shift_per, right); + left = MIN(x1, left); + right = MAX(x1 + shift_per, right); - slow_mem_ptr = &(g_slow_memory_ptr[mem_ptr + x1]); - b_ptr = &screen_data[(y*2)*pixels_per_line + x1*14]; - img_ptr = (word32 *)b_ptr; - img_ptr2 = (word32 *)(b_ptr + pixels_per_line); + slow_mem_ptr = &(g_slow_memory_ptr[mem_ptr + x1]); + b_ptr = &screen_data[(y*2)*pixels_per_line + x1*14]; + img_ptr = (word32 *)b_ptr; + img_ptr2 = (word32 *)(b_ptr + pixels_per_line); - for(x2 = 0; x2 < shift_per; x2 += 2) { - val0 = *slow_mem_ptr++; - val1 = *slow_mem_ptr++; + for(x2 = 0; x2 < shift_per; x2 += 2) { + val0 = *slow_mem_ptr++; + val1 = *slow_mem_ptr++; - val_whole = ((val1 & 0x7f) << 7) +(val0 & 0x7f); + val_whole = ((val1 & 0x7f) << 7) +(val0 & 0x7f); - tmp0 = g_bw_hires_convert[val_whole & 3]; - val_whole = val_whole >> 2; - tmp1 = g_bw_hires_convert[val_whole & 3]; - val_whole = val_whole >> 2; - tmp2 = g_bw_hires_convert[val_whole & 3]; - val_whole = val_whole >> 2; - tmp3 = g_bw_hires_convert[val_whole & 3]; - val_whole = val_whole >> 2; - tmp4 = g_bw_hires_convert[val_whole & 3]; - val_whole = val_whole >> 2; - tmp5 = g_bw_hires_convert[val_whole & 3]; - val_whole = val_whole >> 2; - tmp6 = g_bw_hires_convert[val_whole & 3]; + tmp0 = g_bw_hires_convert[val_whole & 3]; + val_whole = val_whole >> 2; + tmp1 = g_bw_hires_convert[val_whole & 3]; + val_whole = val_whole >> 2; + tmp2 = g_bw_hires_convert[val_whole & 3]; + val_whole = val_whole >> 2; + tmp3 = g_bw_hires_convert[val_whole & 3]; + val_whole = val_whole >> 2; + tmp4 = g_bw_hires_convert[val_whole & 3]; + val_whole = val_whole >> 2; + tmp5 = g_bw_hires_convert[val_whole & 3]; + val_whole = val_whole >> 2; + tmp6 = g_bw_hires_convert[val_whole & 3]; - img_ptr[0] = tmp0 + palette_add; - img_ptr[1] = tmp1 + palette_add; - img_ptr[2] = tmp2 + palette_add; - img_ptr[3] = tmp3 + palette_add; - img_ptr[4] = tmp4 + palette_add; - img_ptr[5] = tmp5 + palette_add; - img_ptr[6] = tmp6 + palette_add; + img_ptr[0] = tmp0 + palette_add; + img_ptr[1] = tmp1 + palette_add; + img_ptr[2] = tmp2 + palette_add; + img_ptr[3] = tmp3 + palette_add; + img_ptr[4] = tmp4 + palette_add; + img_ptr[5] = tmp5 + palette_add; + img_ptr[6] = tmp6 + palette_add; - img_ptr2[0] = tmp0 + palette_add; - img_ptr2[1] = tmp1 + palette_add; - img_ptr2[2] = tmp2 + palette_add; - img_ptr2[3] = tmp3 + palette_add; - img_ptr2[4] = tmp4 + palette_add; - img_ptr2[5] = tmp5 + palette_add; - img_ptr2[6] = tmp6 + palette_add; + img_ptr2[0] = tmp0 + palette_add; + img_ptr2[1] = tmp1 + palette_add; + img_ptr2[2] = tmp2 + palette_add; + img_ptr2[3] = tmp3 + palette_add; + img_ptr2[4] = tmp4 + palette_add; + img_ptr2[5] = tmp5 + palette_add; + img_ptr2[6] = tmp6 + palette_add; - img_ptr += 7; - img_ptr2 += 7; - } - } - } + img_ptr += 7; + img_ptr2 += 7; + } + } + } - for(i = 0; i < num_lines; i++) { - g_a2_line_left_edge[st_line + i] = (left*14); - g_a2_line_right_edge[st_line + i] = (right*14); - } + for(i = 0; i < num_lines; i++) { + g_a2_line_left_edge[st_line + i] = (left*14); + g_a2_line_right_edge[st_line + i] = (right*14); + } - g_need_redraw = 0; + g_need_redraw = 0; } -void -redraw_changed_hires_color(int start_offset, int start_line, int num_lines, - int reparse, byte *screen_data, int pixels_per_line) -{ - word32 *img_ptr, *img_ptr2; - word32 *ch_ptr; - byte *b_ptr; - byte *slow_mem_ptr; - word32 mask_per_line; - word32 ch_mask; - word32 ch_tmp; - word32 mem_ptr; - word32 val0, val1; - word32 val_whole; - word32 pix_val; - word32 line_mask; - word32 prev_pixel; - word32 prev_hi; - word32 loc_hi; - word32 val_hi; - word32 tmp_val; - word32 palette_add; - int y; - int x1, x2; - int ch_bitpos; - int bits_per_line; - int ch_shift_amount; - int shift_per; - int left, right; - int st_line; - int i, j; +void redraw_changed_hires_color(int start_offset, int start_line, int num_lines, + int reparse, byte *screen_data, int pixels_per_line) { + word32 *img_ptr, *img_ptr2; + word32 *ch_ptr; + byte *b_ptr; + byte *slow_mem_ptr; + word32 mask_per_line; + word32 ch_mask; + word32 ch_tmp; + word32 mem_ptr; + word32 val0, val1; + word32 val_whole; + word32 pix_val; + word32 line_mask; + word32 prev_pixel; + word32 prev_hi; + word32 loc_hi; + word32 val_hi; + word32 tmp_val; + word32 palette_add; + int y; + int x1, x2; + int ch_bitpos; + int bits_per_line; + int ch_shift_amount; + int shift_per; + int left, right; + int st_line; + int i, j; - st_line = start_line; + st_line = start_line; - start_line = start_line >> 3; + start_line = start_line >> 3; - palette_add = (g_a2vid_palette << 4); - palette_add = palette_add + (palette_add << 8) + (palette_add << 16) + - (palette_add << 24); + palette_add = (g_a2vid_palette << 4); + palette_add = palette_add + (palette_add << 8) + (palette_add << 16) + + (palette_add << 24); - left = 40; - right = 0; + left = 40; + right = 0; - for(y = st_line; y < (st_line + num_lines); y++) { - line_mask = 1 << (y >> 3); - mem_ptr = 0x2000 + (((y & 7) * 0x400) + - g_screen_index[y >> 3]) + start_offset; + for(y = st_line; y < (st_line + num_lines); y++) { + line_mask = 1 << (y >> 3); + mem_ptr = 0x2000 + (((y & 7) * 0x400) + + g_screen_index[y >> 3]) + start_offset; - CH_SETUP_A2_VID(mem_ptr, ch_mask, reparse, 1); + CH_SETUP_A2_VID(mem_ptr, ch_mask, reparse, 1); - if(ch_mask == 0) { - continue; - } + if(ch_mask == 0) { + continue; + } - /* Hires depends on adjacent bits, so also reparse adjacent */ - /* regions so that if bits on the edge change, redrawing is */ - /* correct */ - ch_mask = ch_mask | (ch_mask >> 1) | (ch_mask << 1); + /* Hires depends on adjacent bits, so also reparse adjacent */ + /* regions so that if bits on the edge change, redrawing is */ + /* correct */ + ch_mask = ch_mask | (ch_mask >> 1) | (ch_mask << 1); - shift_per = (1 << SHIFT_PER_CHANGE); + shift_per = (1 << SHIFT_PER_CHANGE); - g_a2_screen_buffer_changed |= line_mask; + g_a2_screen_buffer_changed |= line_mask; - for(x1 = 0; x1 < 40; x1 += shift_per) { + for(x1 = 0; x1 < 40; x1 += shift_per) { - CH_LOOP_A2_VID(ch_mask, ch_tmp); + CH_LOOP_A2_VID(ch_mask, ch_tmp); - left = MIN(x1, left); - right = MAX(x1 + shift_per, right); + left = MIN(x1, left); + right = MAX(x1 + shift_per, right); - slow_mem_ptr = &(g_slow_memory_ptr[mem_ptr + x1]); - b_ptr = &screen_data[(y*2)*pixels_per_line + x1*14]; - img_ptr = (word32 *)b_ptr; - img_ptr2 = (word32 *)(b_ptr + pixels_per_line); + slow_mem_ptr = &(g_slow_memory_ptr[mem_ptr + x1]); + b_ptr = &screen_data[(y*2)*pixels_per_line + x1*14]; + img_ptr = (word32 *)b_ptr; + img_ptr2 = (word32 *)(b_ptr + pixels_per_line); - prev_pixel = 0; - prev_hi = 0; + prev_pixel = 0; + prev_hi = 0; - if(x1 > 0) { - tmp_val = slow_mem_ptr[-1]; - prev_pixel = (tmp_val >> 6) & 1; - prev_hi = (tmp_val >> 7) & 0x1; - } + if(x1 > 0) { + tmp_val = slow_mem_ptr[-1]; + prev_pixel = (tmp_val >> 6) & 1; + prev_hi = (tmp_val >> 7) & 0x1; + } - for(x2 = 0; x2 < shift_per; x2 += 2) { - val0 = *slow_mem_ptr++; - val1 = *slow_mem_ptr++; + for(x2 = 0; x2 < shift_per; x2 += 2) { + val0 = *slow_mem_ptr++; + val1 = *slow_mem_ptr++; - val_whole = ((val1 & 0x7f) << 8) + - ((val0 & 0x7f) << 1) + - prev_pixel; + val_whole = ((val1 & 0x7f) << 8) + + ((val0 & 0x7f) << 1) + + prev_pixel; - loc_hi = prev_hi; - if(((val1 >> 7) & 1) != 0) { - loc_hi += 0x7f00; - } - if(((val0 >> 7) & 1) != 0) { - loc_hi += 0xfe; - } + loc_hi = prev_hi; + if(((val1 >> 7) & 1) != 0) { + loc_hi += 0x7f00; + } + if(((val0 >> 7) & 1) != 0) { + loc_hi += 0xfe; + } - prev_pixel = (val1 >> 6) & 1; - prev_hi = (val1 >> 7) & 1; - if((x1 + x2 + 2) < 40) { - tmp_val = slow_mem_ptr[0]; - if(tmp_val & 1) { - val_whole |= 0x8000; - } - if(tmp_val & 0x80) { - loc_hi |= 0x8000; - } - } + prev_pixel = (val1 >> 6) & 1; + prev_hi = (val1 >> 7) & 1; + if((x1 + x2 + 2) < 40) { + tmp_val = slow_mem_ptr[0]; + if(tmp_val & 1) { + val_whole |= 0x8000; + } + if(tmp_val & 0x80) { + loc_hi |= 0x8000; + } + } - loc_hi = loc_hi >> 1; + loc_hi = loc_hi >> 1; - for(j = 0; j < 7; j++) { - tmp_val = val_whole & 0xf; - val_hi = loc_hi & 0x3; + for(j = 0; j < 7; j++) { + tmp_val = val_whole & 0xf; + val_hi = loc_hi & 0x3; - pix_val = g_hires_convert[(val_hi<<4) + - tmp_val]; - *img_ptr++ = pix_val + palette_add; - *img_ptr2++ = pix_val + palette_add; - val_whole = val_whole >> 2; - loc_hi = loc_hi >> 2; - } - } - } - } + pix_val = g_hires_convert[(val_hi<<4) + + tmp_val]; + *img_ptr++ = pix_val + palette_add; + *img_ptr2++ = pix_val + palette_add; + val_whole = val_whole >> 2; + loc_hi = loc_hi >> 2; + } + } + } + } - for(i = 0; i < num_lines; i++) { - g_a2_line_left_edge[st_line + i] = (left*14); - g_a2_line_right_edge[st_line + i] = (right*14); - } + for(i = 0; i < num_lines; i++) { + g_a2_line_left_edge[st_line + i] = (left*14); + g_a2_line_right_edge[st_line + i] = (right*14); + } - g_need_redraw = 0; + g_need_redraw = 0; } -void -redraw_changed_dbl_hires(int start_offset, int start_line, int num_lines, - int color, int reparse, byte *screen_data, int pixels_per_line) -{ - if(!color) { - redraw_changed_dbl_hires_color(start_offset, start_line, - num_lines, reparse, screen_data, pixels_per_line); - } else { - redraw_changed_dbl_hires_bw(start_offset, start_line, - num_lines, reparse, screen_data, pixels_per_line); - } +void redraw_changed_dbl_hires(int start_offset, int start_line, int num_lines, + int color, int reparse, byte *screen_data, int pixels_per_line) { + if(!color) { + redraw_changed_dbl_hires_color(start_offset, start_line, + num_lines, reparse, screen_data, pixels_per_line); + } else { + redraw_changed_dbl_hires_bw(start_offset, start_line, + num_lines, reparse, screen_data, pixels_per_line); + } } -void -redraw_changed_dbl_hires_bw(int start_offset, int start_line, int num_lines, - int reparse, byte *screen_data, int pixels_per_line) -{ - word32 *img_ptr, *img_ptr2; - word32 *ch_ptr; - byte *b_ptr; - byte *slow_mem_ptr; - word32 mask_per_line; - word32 ch_mask; - word32 ch_tmp; - word32 mem_ptr; - word32 val0, val1, val2, val3; - word32 tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6; - word32 val_whole; - word32 line_mask; - word32 palette_add; - int y; - int x1, x2; - int ch_bitpos; - int bits_per_line; - int ch_shift_amount; - int shift_per; - int left, right; - int st_line; - int i; +void redraw_changed_dbl_hires_bw(int start_offset, int start_line, int num_lines, + int reparse, byte *screen_data, int pixels_per_line) { + word32 *img_ptr, *img_ptr2; + word32 *ch_ptr; + byte *b_ptr; + byte *slow_mem_ptr; + word32 mask_per_line; + word32 ch_mask; + word32 ch_tmp; + word32 mem_ptr; + word32 val0, val1, val2, val3; + word32 tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6; + word32 val_whole; + word32 line_mask; + word32 palette_add; + int y; + int x1, x2; + int ch_bitpos; + int bits_per_line; + int ch_shift_amount; + int shift_per; + int left, right; + int st_line; + int i; - st_line = start_line; - start_line = start_line >> 3; + st_line = start_line; + start_line = start_line >> 3; - palette_add = (g_a2vid_palette << 4); - palette_add = palette_add + (palette_add << 8) + (palette_add << 16) + - (palette_add << 24); + palette_add = (g_a2vid_palette << 4); + palette_add = palette_add + (palette_add << 8) + (palette_add << 16) + + (palette_add << 24); - left = 40; - right = 0; + left = 40; + right = 0; - for(y = st_line; y < (st_line + num_lines); y++) { - line_mask = 1 << (y >> 3); - mem_ptr = 0x2000 + (((y & 7) * 0x400) + g_screen_index[y >> 3] + - start_offset); + for(y = st_line; y < (st_line + num_lines); y++) { + line_mask = 1 << (y >> 3); + mem_ptr = 0x2000 + (((y & 7) * 0x400) + g_screen_index[y >> 3] + + start_offset); - CH_SETUP_A2_VID(mem_ptr, ch_mask, reparse, 1); + CH_SETUP_A2_VID(mem_ptr, ch_mask, reparse, 1); - if(ch_mask == 0) { - continue; - } + if(ch_mask == 0) { + continue; + } - shift_per = (1 << SHIFT_PER_CHANGE); + shift_per = (1 << SHIFT_PER_CHANGE); - g_a2_screen_buffer_changed |= line_mask; + g_a2_screen_buffer_changed |= line_mask; - for(x1 = 0; x1 < 40; x1 += shift_per) { + for(x1 = 0; x1 < 40; x1 += shift_per) { - CH_LOOP_A2_VID(ch_mask, ch_tmp); + CH_LOOP_A2_VID(ch_mask, ch_tmp); - left = MIN(x1, left); - right = MAX(x1 + shift_per, right); + left = MIN(x1, left); + right = MAX(x1 + shift_per, right); - slow_mem_ptr = &(g_slow_memory_ptr[mem_ptr + x1]); - b_ptr = &screen_data[(y*2)*pixels_per_line + x1*14]; - img_ptr = (word32 *)b_ptr; - img_ptr2 = (word32 *)(b_ptr + pixels_per_line); + slow_mem_ptr = &(g_slow_memory_ptr[mem_ptr + x1]); + b_ptr = &screen_data[(y*2)*pixels_per_line + x1*14]; + img_ptr = (word32 *)b_ptr; + img_ptr2 = (word32 *)(b_ptr + pixels_per_line); - for(x2 = 0; x2 < shift_per; x2 += 2) { - val0 = slow_mem_ptr[0x10000]; - val1 = slow_mem_ptr[0]; - val2 = slow_mem_ptr[0x10001]; - val3 = slow_mem_ptr[1]; - slow_mem_ptr += 2; + for(x2 = 0; x2 < shift_per; x2 += 2) { + val0 = slow_mem_ptr[0x10000]; + val1 = slow_mem_ptr[0]; + val2 = slow_mem_ptr[0x10001]; + val3 = slow_mem_ptr[1]; + slow_mem_ptr += 2; - val_whole = ((val3 & 0x7f) << 21) + - ((val2 & 0x7f) << 14) + - ((val1 & 0x7f) << 7) + - (val0 & 0x7f); + val_whole = ((val3 & 0x7f) << 21) + + ((val2 & 0x7f) << 14) + + ((val1 & 0x7f) << 7) + + (val0 & 0x7f); - tmp0 = g_bw_dhires_convert[val_whole & 0xf]; - val_whole = val_whole >> 4; - tmp1 = g_bw_dhires_convert[val_whole & 0xf]; - val_whole = val_whole >> 4; - tmp2 = g_bw_dhires_convert[val_whole & 0xf]; - val_whole = val_whole >> 4; - tmp3 = g_bw_dhires_convert[val_whole & 0xf]; - val_whole = val_whole >> 4; - tmp4 = g_bw_dhires_convert[val_whole & 0xf]; - val_whole = val_whole >> 4; - tmp5 = g_bw_dhires_convert[val_whole & 0xf]; - val_whole = val_whole >> 4; - tmp6 = g_bw_dhires_convert[val_whole & 0xf]; + tmp0 = g_bw_dhires_convert[val_whole & 0xf]; + val_whole = val_whole >> 4; + tmp1 = g_bw_dhires_convert[val_whole & 0xf]; + val_whole = val_whole >> 4; + tmp2 = g_bw_dhires_convert[val_whole & 0xf]; + val_whole = val_whole >> 4; + tmp3 = g_bw_dhires_convert[val_whole & 0xf]; + val_whole = val_whole >> 4; + tmp4 = g_bw_dhires_convert[val_whole & 0xf]; + val_whole = val_whole >> 4; + tmp5 = g_bw_dhires_convert[val_whole & 0xf]; + val_whole = val_whole >> 4; + tmp6 = g_bw_dhires_convert[val_whole & 0xf]; - img_ptr[0] = tmp0 + palette_add; - img_ptr[1] = tmp1 + palette_add; - img_ptr[2] = tmp2 + palette_add; - img_ptr[3] = tmp3 + palette_add; - img_ptr[4] = tmp4 + palette_add; - img_ptr[5] = tmp5 + palette_add; - img_ptr[6] = tmp6 + palette_add; + img_ptr[0] = tmp0 + palette_add; + img_ptr[1] = tmp1 + palette_add; + img_ptr[2] = tmp2 + palette_add; + img_ptr[3] = tmp3 + palette_add; + img_ptr[4] = tmp4 + palette_add; + img_ptr[5] = tmp5 + palette_add; + img_ptr[6] = tmp6 + palette_add; - img_ptr2[0] = tmp0 + palette_add; - img_ptr2[1] = tmp1 + palette_add; - img_ptr2[2] = tmp2 + palette_add; - img_ptr2[3] = tmp3 + palette_add; - img_ptr2[4] = tmp4 + palette_add; - img_ptr2[5] = tmp5 + palette_add; - img_ptr2[6] = tmp6 + palette_add; + img_ptr2[0] = tmp0 + palette_add; + img_ptr2[1] = tmp1 + palette_add; + img_ptr2[2] = tmp2 + palette_add; + img_ptr2[3] = tmp3 + palette_add; + img_ptr2[4] = tmp4 + palette_add; + img_ptr2[5] = tmp5 + palette_add; + img_ptr2[6] = tmp6 + palette_add; - img_ptr += 7; - img_ptr2 += 7; - } - } - } + img_ptr += 7; + img_ptr2 += 7; + } + } + } - for(i = 0; i < num_lines; i++) { - g_a2_line_left_edge[st_line + i] = (left*14); - g_a2_line_right_edge[st_line + i] = (right*14); - } + for(i = 0; i < num_lines; i++) { + g_a2_line_left_edge[st_line + i] = (left*14); + g_a2_line_right_edge[st_line + i] = (right*14); + } - g_need_redraw = 0; + g_need_redraw = 0; } -void -redraw_changed_dbl_hires_color(int start_offset, int start_line, int num_lines, - int reparse, byte *screen_data, int pixels_per_line) -{ - word32 *ch_ptr; - word32 *img_ptr, *img_ptr2; - byte *slow_mem_ptr; - byte *b_ptr; - word32 mask_per_line; - word32 ch_mask; - word32 ch_tmp; - word32 mem_ptr; - word32 val0, val1, val2, val3; - word32 tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6; - word32 val_whole; - word32 prev_val; - word32 line_mask; - word32 palette_add; - int y; - int x1, x2; - int ch_bitpos; - int bits_per_line; - int ch_shift_amount; - int shift_per; - int left, right; - int st_line; - int i; +void redraw_changed_dbl_hires_color(int start_offset, int start_line, int num_lines, + int reparse, byte *screen_data, int pixels_per_line) { + word32 *ch_ptr; + word32 *img_ptr, *img_ptr2; + byte *slow_mem_ptr; + byte *b_ptr; + word32 mask_per_line; + word32 ch_mask; + word32 ch_tmp; + word32 mem_ptr; + word32 val0, val1, val2, val3; + word32 tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6; + word32 val_whole; + word32 prev_val; + word32 line_mask; + word32 palette_add; + int y; + int x1, x2; + int ch_bitpos; + int bits_per_line; + int ch_shift_amount; + int shift_per; + int left, right; + int st_line; + int i; - st_line = start_line; - start_line = start_line >> 3; + st_line = start_line; + start_line = start_line >> 3; - palette_add = (g_a2vid_palette << 4); - palette_add = palette_add + (palette_add << 8) + (palette_add << 16) + - (palette_add << 24); + palette_add = (g_a2vid_palette << 4); + palette_add = palette_add + (palette_add << 8) + (palette_add << 16) + + (palette_add << 24); - left = 40; - right = 0; + left = 40; + right = 0; - for(y = st_line; y < (st_line + num_lines); y++) { - line_mask = 1 << (y >> 3); - mem_ptr = 0x2000 + (((y & 7) * 0x400) + g_screen_index[y >> 3] + - start_offset); + for(y = st_line; y < (st_line + num_lines); y++) { + line_mask = 1 << (y >> 3); + mem_ptr = 0x2000 + (((y & 7) * 0x400) + g_screen_index[y >> 3] + + start_offset); - CH_SETUP_A2_VID(mem_ptr, ch_mask, reparse, 1); + CH_SETUP_A2_VID(mem_ptr, ch_mask, reparse, 1); - if(ch_mask == 0) { - continue; - } + if(ch_mask == 0) { + continue; + } - /* dbl-hires also depends on adjacent bits, so reparse */ - /* adjacent regions so that if bits on the edge change, */ - /* redrawing is correct */ - ch_mask = ch_mask | (ch_mask >> 1) | (ch_mask << 1); - ch_mask = -1; + /* dbl-hires also depends on adjacent bits, so reparse */ + /* adjacent regions so that if bits on the edge change, */ + /* redrawing is correct */ + ch_mask = ch_mask | (ch_mask >> 1) | (ch_mask << 1); + ch_mask = -1; - shift_per = (1 << SHIFT_PER_CHANGE); + shift_per = (1 << SHIFT_PER_CHANGE); - g_a2_screen_buffer_changed |= line_mask; + g_a2_screen_buffer_changed |= line_mask; - for(x1 = 0; x1 < 40; x1 += shift_per) { + for(x1 = 0; x1 < 40; x1 += shift_per) { - CH_LOOP_A2_VID(ch_mask, ch_tmp); + CH_LOOP_A2_VID(ch_mask, ch_tmp); - left = MIN(x1, left); - right = MAX(x1 + shift_per, right); + left = MIN(x1, left); + right = MAX(x1 + shift_per, right); - slow_mem_ptr = &(g_slow_memory_ptr[mem_ptr + x1]); - b_ptr = &screen_data[(y*2)*pixels_per_line + x1*14]; - img_ptr = (word32 *)b_ptr; - img_ptr2 = (word32 *)(b_ptr + pixels_per_line); + slow_mem_ptr = &(g_slow_memory_ptr[mem_ptr + x1]); + b_ptr = &screen_data[(y*2)*pixels_per_line + x1*14]; + img_ptr = (word32 *)b_ptr; + img_ptr2 = (word32 *)(b_ptr + pixels_per_line); - for(x2 = 0; x2 < shift_per; x2 += 2) { - val0 = slow_mem_ptr[0x10000]; - val1 = slow_mem_ptr[0]; - val2 = slow_mem_ptr[0x10001]; - val3 = slow_mem_ptr[1]; + for(x2 = 0; x2 < shift_per; x2 += 2) { + val0 = slow_mem_ptr[0x10000]; + val1 = slow_mem_ptr[0]; + val2 = slow_mem_ptr[0x10001]; + val3 = slow_mem_ptr[1]; - prev_val = 0; - if((x1 + x2) > 0) { - prev_val = (slow_mem_ptr[-1] >> 3) &0xf; - } - val_whole = ((val3 & 0x7f) << 25) + - ((val2 & 0x7f) << 18) + - ((val1 & 0x7f) << 11) + - ((val0 & 0x7f) << 4) + prev_val; + prev_val = 0; + if((x1 + x2) > 0) { + prev_val = (slow_mem_ptr[-1] >> 3) &0xf; + } + val_whole = ((val3 & 0x7f) << 25) + + ((val2 & 0x7f) << 18) + + ((val1 & 0x7f) << 11) + + ((val0 & 0x7f) << 4) + prev_val; - tmp0 = g_dhires_convert[val_whole & 0xfff]; - val_whole = val_whole >> 4; - tmp1 = g_dhires_convert[val_whole & 0xfff]; - val_whole = val_whole >> 4; - tmp2 = g_dhires_convert[val_whole & 0xfff]; - val_whole = val_whole >> 4; - tmp3 = g_dhires_convert[val_whole & 0xfff]; - val_whole = val_whole >> 4; - tmp4 = g_dhires_convert[val_whole & 0xfff]; - val_whole = val_whole >> 4; - tmp5 = g_dhires_convert[val_whole & 0xfff]; - val_whole = val_whole >> 4; - if((x1 + x2 + 2) < 40) { - val_whole += (slow_mem_ptr[0x10002]<<8); - } - tmp6 = g_dhires_convert[val_whole & 0xfff]; + tmp0 = g_dhires_convert[val_whole & 0xfff]; + val_whole = val_whole >> 4; + tmp1 = g_dhires_convert[val_whole & 0xfff]; + val_whole = val_whole >> 4; + tmp2 = g_dhires_convert[val_whole & 0xfff]; + val_whole = val_whole >> 4; + tmp3 = g_dhires_convert[val_whole & 0xfff]; + val_whole = val_whole >> 4; + tmp4 = g_dhires_convert[val_whole & 0xfff]; + val_whole = val_whole >> 4; + tmp5 = g_dhires_convert[val_whole & 0xfff]; + val_whole = val_whole >> 4; + if((x1 + x2 + 2) < 40) { + val_whole += (slow_mem_ptr[0x10002]<<8); + } + tmp6 = g_dhires_convert[val_whole & 0xfff]; - img_ptr[0] = tmp0 + palette_add; - img_ptr[1] = tmp1 + palette_add; - img_ptr[2] = tmp2 + palette_add; - img_ptr[3] = tmp3 + palette_add; - img_ptr[4] = tmp4 + palette_add; - img_ptr[5] = tmp5 + palette_add; - img_ptr[6] = tmp6 + palette_add; + img_ptr[0] = tmp0 + palette_add; + img_ptr[1] = tmp1 + palette_add; + img_ptr[2] = tmp2 + palette_add; + img_ptr[3] = tmp3 + palette_add; + img_ptr[4] = tmp4 + palette_add; + img_ptr[5] = tmp5 + palette_add; + img_ptr[6] = tmp6 + palette_add; - img_ptr2[0] = tmp0 + palette_add; - img_ptr2[1] = tmp1 + palette_add; - img_ptr2[2] = tmp2 + palette_add; - img_ptr2[3] = tmp3 + palette_add; - img_ptr2[4] = tmp4 + palette_add; - img_ptr2[5] = tmp5 + palette_add; - img_ptr2[6] = tmp6 + palette_add; + img_ptr2[0] = tmp0 + palette_add; + img_ptr2[1] = tmp1 + palette_add; + img_ptr2[2] = tmp2 + palette_add; + img_ptr2[3] = tmp3 + palette_add; + img_ptr2[4] = tmp4 + palette_add; + img_ptr2[5] = tmp5 + palette_add; + img_ptr2[6] = tmp6 + palette_add; - slow_mem_ptr += 2; - img_ptr += 7; - img_ptr2 += 7; - } - } - } + slow_mem_ptr += 2; + img_ptr += 7; + img_ptr2 += 7; + } + } + } - for(i = 0; i < num_lines; i++) { - g_a2_line_left_edge[st_line + i] = (left*14); - g_a2_line_right_edge[st_line + i] = (right*14); - } + for(i = 0; i < num_lines; i++) { + g_a2_line_left_edge[st_line + i] = (left*14); + g_a2_line_right_edge[st_line + i] = (right*14); + } - g_need_redraw = 0; + g_need_redraw = 0; } -int -video_rebuild_super_hires_palette(word32 scan_info, int line, int reparse) -{ - word32 *word_ptr; - word32 *ch_ptr; - byte *byte_ptr; - word32 ch_mask, mask_per_line; - word32 tmp; - word32 scan, old_scan; - int palette_changed; - int diff0, diff1, diff2; - int val0, val1, val2; - int diffs; - int low_delta, low_color; - int delta; - int full; - int ch_bit_offset, ch_word_offset; - int bits_per_line; - int palette; - int j, k; +int video_rebuild_super_hires_palette(word32 scan_info, int line, int reparse) { + word32 *word_ptr; + word32 *ch_ptr; + byte *byte_ptr; + word32 ch_mask, mask_per_line; + word32 tmp; + word32 scan, old_scan; + int palette_changed; + int diff0, diff1, diff2; + int val0, val1, val2; + int diffs; + int low_delta, low_color; + int delta; + int full; + int ch_bit_offset, ch_word_offset; + int bits_per_line; + int palette; + int j, k; - palette_changed = 0; - palette = scan_info & 0xf; + palette_changed = 0; + palette = scan_info & 0xf; - ch_ptr = &(slow_mem_changed[0x9e00 >> CHANGE_SHIFT]); - ch_bit_offset = (palette << 5) >> SHIFT_PER_CHANGE; - ch_word_offset = ch_bit_offset >> 5; - ch_bit_offset = ch_bit_offset & 0x1f; - bits_per_line = (0x20 >> SHIFT_PER_CHANGE); - mask_per_line = -(1 << (32 - bits_per_line)); - mask_per_line = mask_per_line >> ch_bit_offset; + ch_ptr = &(slow_mem_changed[0x9e00 >> CHANGE_SHIFT]); + ch_bit_offset = (palette << 5) >> SHIFT_PER_CHANGE; + ch_word_offset = ch_bit_offset >> 5; + ch_bit_offset = ch_bit_offset & 0x1f; + bits_per_line = (0x20 >> SHIFT_PER_CHANGE); + mask_per_line = -(1 << (32 - bits_per_line)); + mask_per_line = mask_per_line >> ch_bit_offset; - ch_mask = ch_ptr[ch_word_offset] & mask_per_line; - ch_ptr[ch_word_offset] &= ~mask_per_line; /* clear the bits */ + ch_mask = ch_ptr[ch_word_offset] & mask_per_line; + ch_ptr[ch_word_offset] &= ~mask_per_line; /* clear the bits */ - old_scan = g_superhires_scan_save[line]; - scan = (scan_info & 0xfaf) + (g_palette_change_cnt[palette] << 12); - g_superhires_scan_save[line] = scan; + old_scan = g_superhires_scan_save[line]; + scan = (scan_info & 0xfaf) + (g_palette_change_cnt[palette] << 12); + g_superhires_scan_save[line] = scan; #if 0 - if(line == 1) { - word_ptr = (word32 *)&(g_slow_memory_ptr[0x19e00+palette*0x20]); - printf("y1vrshp, ch:%08x, s:%08x,os:%08x %d = %08x %08x %08x %08x %08x %08x %08x %08x\n", - ch_mask, scan, old_scan, reparse, - word_ptr[0], word_ptr[1], word_ptr[2], word_ptr[3], - word_ptr[4], word_ptr[5], word_ptr[6], word_ptr[7]); - } + if(line == 1) { + word_ptr = (word32 *)&(g_slow_memory_ptr[0x19e00+palette*0x20]); + printf("y1vrshp, ch:%08x, s:%08x,os:%08x %d = %08x %08x %08x %08x %08x %08x %08x %08x\n", + ch_mask, scan, old_scan, reparse, + word_ptr[0], word_ptr[1], word_ptr[2], word_ptr[3], + word_ptr[4], word_ptr[5], word_ptr[6], word_ptr[7]); + } #endif - diffs = reparse | ((scan ^ old_scan) & 0xf0f); - /* we must do full reparse if palette changed for this line */ + diffs = reparse | ((scan ^ old_scan) & 0xf0f); + /* we must do full reparse if palette changed for this line */ - if(!diffs && (ch_mask == 0) && (((scan ^ old_scan) & (~0xf0)) == 0)) { - /* nothing changed, get out fast */ - return 0; - } + if(!diffs && (ch_mask == 0) && (((scan ^ old_scan) & (~0xf0)) == 0)) { + /* nothing changed, get out fast */ + return 0; + } - if(ch_mask) { - /* indicates the palette has changed, and other scan lines */ - /* using this palette need to do a full 32-byte compare to */ - /* decide if they need to update or not */ - g_palette_change_cnt[palette]++; - } + if(ch_mask) { + /* indicates the palette has changed, and other scan lines */ + /* using this palette need to do a full 32-byte compare to */ + /* decide if they need to update or not */ + g_palette_change_cnt[palette]++; + } - word_ptr = (word32 *)&(g_slow_memory_ptr[0x19e00 + palette*0x20]); - for(j = 0; j < 8; j++) { - if(word_ptr[j] != g_saved_line_palettes[line][j]) { - diffs = 1; - break; - } - } + word_ptr = (word32 *)&(g_slow_memory_ptr[0x19e00 + palette*0x20]); + for(j = 0; j < 8; j++) { + if(word_ptr[j] != g_saved_line_palettes[line][j]) { + diffs = 1; + break; + } + } - if(diffs == 0) { - return 0; - } + if(diffs == 0) { + return 0; + } - /* first, save this word_ptr into saved_line_palettes */ - byte_ptr = (byte *)word_ptr; - for(j = 0; j < 8; j++) { - g_saved_line_palettes[line][j] = word_ptr[j]; - } + /* first, save this word_ptr into saved_line_palettes */ + byte_ptr = (byte *)word_ptr; + for(j = 0; j < 8; j++) { + g_saved_line_palettes[line][j] = word_ptr[j]; + } - full = g_installed_full_superhires_colormap; + full = g_installed_full_superhires_colormap; - if(!full && palette == g_a2vid_palette) { - /* construct new color approximations from lores */ - for(j = 0; j < 16; j++) { - tmp = *byte_ptr++; - val2 = (*byte_ptr++) & 0xf; - val0 = tmp & 0xf; - val1 = (tmp >> 4) & 0xf; - low_delta = 0x1000; - low_color = 0x0; - for(k = 0; k < 16; k++) { - diff0 = g_expanded_col_0[k] - val0; - diff1 = g_expanded_col_1[k] - val1; - diff2 = g_expanded_col_2[k] - val2; - if(diff0 < 0) { - diff0 = -diff0; - } - if(diff1 < 0) { - diff1 = -diff1; - } - if(diff2 < 0) { - diff2 = -diff2; - } - delta = diff0 + diff1 + diff2; - if(delta < low_delta) { - low_delta = delta; - low_color = k; - } - } + if(!full && palette == g_a2vid_palette) { + /* construct new color approximations from lores */ + for(j = 0; j < 16; j++) { + tmp = *byte_ptr++; + val2 = (*byte_ptr++) & 0xf; + val0 = tmp & 0xf; + val1 = (tmp >> 4) & 0xf; + low_delta = 0x1000; + low_color = 0x0; + for(k = 0; k < 16; k++) { + diff0 = g_expanded_col_0[k] - val0; + diff1 = g_expanded_col_1[k] - val1; + diff2 = g_expanded_col_2[k] - val2; + if(diff0 < 0) { + diff0 = -diff0; + } + if(diff1 < 0) { + diff1 = -diff1; + } + if(diff2 < 0) { + diff2 = -diff2; + } + delta = diff0 + diff1 + diff2; + if(delta < low_delta) { + low_delta = delta; + low_color = k; + } + } - g_a2vid_palette_remap[j] = low_color; - } - } + g_a2vid_palette_remap[j] = low_color; + } + } - byte_ptr = (byte *)word_ptr; - /* this palette has changed */ - for(j = 0; j < 16; j++) { - val0 = *byte_ptr++; - val1 = *byte_ptr++; - video_update_color_array(palette*16 + j, (val1<<8) + val0); - } + byte_ptr = (byte *)word_ptr; + /* this palette has changed */ + for(j = 0; j < 16; j++) { + val0 = *byte_ptr++; + val1 = *byte_ptr++; + video_update_color_array(palette*16 + j, (val1<<8) + val0); + } - g_palette_change_summary = 1; + g_palette_change_summary = 1; - return 1; + return 1; } -#define SUPER_TYPE redraw_changed_super_hires_oneline_nofill_8 -#define SUPER_FILL 0 -#define SUPER_PIXEL_SIZE 8 +#define SUPER_TYPE redraw_changed_super_hires_oneline_nofill_8 +#define SUPER_FILL 0 +#define SUPER_PIXEL_SIZE 8 #include "superhires.h" -#undef SUPER_TYPE -#undef SUPER_FILL -#undef SUPER_PIXEL_SIZE +#undef SUPER_TYPE +#undef SUPER_FILL +#undef SUPER_PIXEL_SIZE -#define SUPER_TYPE redraw_changed_super_hires_oneline_nofill_16 -#define SUPER_FILL 0 -#define SUPER_PIXEL_SIZE 16 +#define SUPER_TYPE redraw_changed_super_hires_oneline_nofill_16 +#define SUPER_FILL 0 +#define SUPER_PIXEL_SIZE 16 #include "superhires.h" -#undef SUPER_TYPE -#undef SUPER_FILL -#undef SUPER_PIXEL_SIZE +#undef SUPER_TYPE +#undef SUPER_FILL +#undef SUPER_PIXEL_SIZE -#define SUPER_TYPE redraw_changed_super_hires_oneline_nofill_32 -#define SUPER_FILL 0 -#define SUPER_PIXEL_SIZE 32 +#define SUPER_TYPE redraw_changed_super_hires_oneline_nofill_32 +#define SUPER_FILL 0 +#define SUPER_PIXEL_SIZE 32 #include "superhires.h" -#undef SUPER_TYPE -#undef SUPER_FILL -#undef SUPER_PIXEL_SIZE +#undef SUPER_TYPE +#undef SUPER_FILL +#undef SUPER_PIXEL_SIZE -#define SUPER_TYPE redraw_changed_super_hires_oneline_fill_8 -#define SUPER_FILL 1 -#define SUPER_PIXEL_SIZE 8 +#define SUPER_TYPE redraw_changed_super_hires_oneline_fill_8 +#define SUPER_FILL 1 +#define SUPER_PIXEL_SIZE 8 #include "superhires.h" -#undef SUPER_TYPE -#undef SUPER_FILL -#undef SUPER_PIXEL_SIZE +#undef SUPER_TYPE +#undef SUPER_FILL +#undef SUPER_PIXEL_SIZE -#define SUPER_TYPE redraw_changed_super_hires_oneline_fill_16 -#define SUPER_FILL 1 -#define SUPER_PIXEL_SIZE 16 +#define SUPER_TYPE redraw_changed_super_hires_oneline_fill_16 +#define SUPER_FILL 1 +#define SUPER_PIXEL_SIZE 16 #include "superhires.h" -#undef SUPER_TYPE -#undef SUPER_FILL -#undef SUPER_PIXEL_SIZE +#undef SUPER_TYPE +#undef SUPER_FILL +#undef SUPER_PIXEL_SIZE -#define SUPER_TYPE redraw_changed_super_hires_oneline_fill_32 -#define SUPER_FILL 1 -#define SUPER_PIXEL_SIZE 32 +#define SUPER_TYPE redraw_changed_super_hires_oneline_fill_32 +#define SUPER_FILL 1 +#define SUPER_PIXEL_SIZE 32 #include "superhires.h" -#undef SUPER_TYPE -#undef SUPER_FILL -#undef SUPER_PIXEL_SIZE +#undef SUPER_TYPE +#undef SUPER_FILL +#undef SUPER_PIXEL_SIZE -void -redraw_changed_super_hires(int start_offset, int start_line, int num_lines, - int in_reparse, byte *screen_data) -{ - word32 *ch_ptr; - word32 mask_per_line; - word32 all_checks; - word32 check0, check1, mask0, mask1; - word32 this_check; - word32 tmp; - word32 line_mask; - word32 pal; - word32 scan, old_scan; - word32 kd_tmp_debug; - int y; - int bits_per_line; - int a2vid_palette; - int type; - int left, right; - int st_line; - int check_bit_pos, check_word_off; - int pixel_size, pixel_size_type; - int use_a2vid_palette, mode_640; - int pixels_per_line; - int ret; - int i; +void redraw_changed_super_hires(int start_offset, int start_line, int num_lines, + int in_reparse, byte *screen_data) { + word32 *ch_ptr; + word32 mask_per_line; + word32 all_checks; + word32 check0, check1, mask0, mask1; + word32 this_check; + word32 tmp; + word32 line_mask; + word32 pal; + word32 scan, old_scan; + word32 kd_tmp_debug; + int y; + int bits_per_line; + int a2vid_palette; + int type; + int left, right; + int st_line; + int check_bit_pos, check_word_off; + int pixel_size, pixel_size_type; + int use_a2vid_palette, mode_640; + int pixels_per_line; + int ret; + int i; - st_line = start_line; - start_line = start_line >> 3; + st_line = start_line; + start_line = start_line >> 3; - pixel_size = g_kimage_superhires.mdepth; - pixels_per_line = g_kimage_superhires.width_act; + pixel_size = g_kimage_superhires.mdepth; + pixels_per_line = g_kimage_superhires.width_act; - pixel_size_type = (pixel_size >> 3) - 1; - /* pixel_size_type is now: 0=8bit, 1=16bit, 3=32bit */ - if(pixel_size_type >= 3) { - pixel_size_type = 2; - } + pixel_size_type = (pixel_size >> 3) - 1; + /* pixel_size_type is now: 0=8bit, 1=16bit, 3=32bit */ + if(pixel_size_type >= 3) { + pixel_size_type = 2; + } - kd_tmp_debug = g_a2_screen_buffer_changed; + kd_tmp_debug = g_a2_screen_buffer_changed; - line_mask = 1 << (start_line); + line_mask = 1 << (start_line); - ch_ptr = &(slow_mem_changed[(0x2000) >> CHANGE_SHIFT]); - bits_per_line = 160 >> SHIFT_PER_CHANGE; - mask_per_line = -(1 << (32 - bits_per_line)); + ch_ptr = &(slow_mem_changed[(0x2000) >> CHANGE_SHIFT]); + bits_per_line = 160 >> SHIFT_PER_CHANGE; + mask_per_line = -(1 << (32 - bits_per_line)); - if(SHIFT_PER_CHANGE != 3) { - halt_printf("SHIFT_PER_CHANGE must be 3!\n"); - return; - } + if(SHIFT_PER_CHANGE != 3) { + halt_printf("SHIFT_PER_CHANGE must be 3!\n"); + return; + } - a2vid_palette = g_a2vid_palette; - if(g_installed_full_superhires_colormap) { - a2vid_palette = -1; - } else { - /* handle palette counting for finding least-used palette */ - if(pixel_size == 8) { - for(y = 8*start_line; y < 8*(start_line + 1); y++) { - scan = g_slow_memory_ptr[0x19d00 + y]; - pal = scan & 0xf; - g_shr_palette_used[pal]++; - } - } - } + a2vid_palette = g_a2vid_palette; + if(g_installed_full_superhires_colormap) { + a2vid_palette = -1; + } else { + /* handle palette counting for finding least-used palette */ + if(pixel_size == 8) { + for(y = 8*start_line; y < 8*(start_line + 1); y++) { + scan = g_slow_memory_ptr[0x19d00 + y]; + pal = scan & 0xf; + g_shr_palette_used[pal]++; + } + } + } - all_checks = 0; - check0 = 0; - check1 = 0; - for(y = st_line; y < (st_line + num_lines); y++) { - scan = g_slow_memory_ptr[0x19d00 + y]; - check_bit_pos = bits_per_line * y; - check_word_off = check_bit_pos >> 5; /* 32 bits per word */ - check_bit_pos = check_bit_pos & 0x1f; /* 5-bit bit_pos */ - check0 = ch_ptr[check_word_off]; - check1 = ch_ptr[check_word_off+1]; - mask0 = mask_per_line >> check_bit_pos; - mask1 = 0; - this_check = check0 << check_bit_pos; - /* move indicated bit to MSbit position */ - if((check_bit_pos + bits_per_line) > 32) { - this_check |= (check1 >> (32 - check_bit_pos)); - mask1 = mask_per_line << (32 - check_bit_pos); - } + all_checks = 0; + check0 = 0; + check1 = 0; + for(y = st_line; y < (st_line + num_lines); y++) { + scan = g_slow_memory_ptr[0x19d00 + y]; + check_bit_pos = bits_per_line * y; + check_word_off = check_bit_pos >> 5; /* 32 bits per word */ + check_bit_pos = check_bit_pos & 0x1f; /* 5-bit bit_pos */ + check0 = ch_ptr[check_word_off]; + check1 = ch_ptr[check_word_off+1]; + mask0 = mask_per_line >> check_bit_pos; + mask1 = 0; + this_check = check0 << check_bit_pos; + /* move indicated bit to MSbit position */ + if((check_bit_pos + bits_per_line) > 32) { + this_check |= (check1 >> (32 - check_bit_pos)); + mask1 = mask_per_line << (32 - check_bit_pos); + } - ch_ptr[check_word_off] = check0 & ~mask0; - ch_ptr[check_word_off+1] = check1 & ~mask1; + ch_ptr[check_word_off] = check0 & ~mask0; + ch_ptr[check_word_off+1] = check1 & ~mask1; - this_check = this_check & mask_per_line; - old_scan = g_superhires_scan_save[y]; - use_a2vid_palette = ((scan & 0xf) == (word32)a2vid_palette); - scan = (scan + (a2vid_palette << 8)) & 0xfff; + this_check = this_check & mask_per_line; + old_scan = g_superhires_scan_save[y]; + use_a2vid_palette = ((scan & 0xf) == (word32)a2vid_palette); + scan = (scan + (a2vid_palette << 8)) & 0xfff; - ret = video_rebuild_super_hires_palette(scan, y, in_reparse); + ret = video_rebuild_super_hires_palette(scan, y, in_reparse); #if 0 - if(y == 1) { - printf("y1, ch:%08x, ret:%d, scan:%03x, os:%03x\n", - this_check, ret, scan, old_scan); - } + if(y == 1) { + printf("y1, ch:%08x, ret:%d, scan:%03x, os:%03x\n", + this_check, ret, scan, old_scan); + } #endif - if(ret || in_reparse || ((scan ^ old_scan) & 0xa0)) { - /* 0x80 == mode640, 0x20 = fill */ - this_check = -1; - } + if(ret || in_reparse || ((scan ^ old_scan) & 0xa0)) { + /* 0x80 == mode640, 0x20 = fill */ + this_check = -1; + } - if(this_check == 0) { - continue; - } + if(this_check == 0) { + continue; + } - mode_640 = (scan & 0x80); - if(mode_640) { - g_num_lines_superhires640++; - } + mode_640 = (scan & 0x80); + if(mode_640) { + g_num_lines_superhires640++; + } - type = ((scan >> 5) & 1) + (pixel_size_type << 1); - if(type & 1) { - /* fill mode--redraw whole line */ - this_check = -1; - } + type = ((scan >> 5) & 1) + (pixel_size_type << 1); + if(type & 1) { + /* fill mode--redraw whole line */ + this_check = -1; + } - all_checks |= this_check; + all_checks |= this_check; - g_a2_screen_buffer_changed |= line_mask; + g_a2_screen_buffer_changed |= line_mask; - switch(type) { - case 0: /* nofill, 8 bit pixels */ - redraw_changed_super_hires_oneline_nofill_8( - screen_data, pixels_per_line, y, scan, - this_check, use_a2vid_palette, mode_640); - break; - case 1: /* fill, 8 bit pixels */ - redraw_changed_super_hires_oneline_fill_8( - screen_data, pixels_per_line, y, scan, - this_check, use_a2vid_palette, mode_640); - break; - case 2: /* nofill, 16 bit pixels */ - redraw_changed_super_hires_oneline_nofill_16( - screen_data, pixels_per_line, y, scan, - this_check, use_a2vid_palette, mode_640); - break; - case 3: /* fill, 16 bit pixels */ - redraw_changed_super_hires_oneline_fill_16( - screen_data, pixels_per_line, y, scan, - this_check, use_a2vid_palette, mode_640); - break; - case 4: /* nofill, 32 bit pixels */ - redraw_changed_super_hires_oneline_nofill_32( - screen_data, pixels_per_line, y, scan, - this_check, use_a2vid_palette, mode_640); - break; - case 5: /* fill, 32 byte pixels */ - redraw_changed_super_hires_oneline_fill_32( - screen_data, pixels_per_line, y, scan, - this_check, use_a2vid_palette, mode_640); - break; - default: - halt_printf("type: %d bad!\n", type); - } - } + switch(type) { + case 0: /* nofill, 8 bit pixels */ + redraw_changed_super_hires_oneline_nofill_8( + screen_data, pixels_per_line, y, scan, + this_check, use_a2vid_palette, mode_640); + break; + case 1: /* fill, 8 bit pixels */ + redraw_changed_super_hires_oneline_fill_8( + screen_data, pixels_per_line, y, scan, + this_check, use_a2vid_palette, mode_640); + break; + case 2: /* nofill, 16 bit pixels */ + redraw_changed_super_hires_oneline_nofill_16( + screen_data, pixels_per_line, y, scan, + this_check, use_a2vid_palette, mode_640); + break; + case 3: /* fill, 16 bit pixels */ + redraw_changed_super_hires_oneline_fill_16( + screen_data, pixels_per_line, y, scan, + this_check, use_a2vid_palette, mode_640); + break; + case 4: /* nofill, 32 bit pixels */ + redraw_changed_super_hires_oneline_nofill_32( + screen_data, pixels_per_line, y, scan, + this_check, use_a2vid_palette, mode_640); + break; + case 5: /* fill, 32 byte pixels */ + redraw_changed_super_hires_oneline_fill_32( + screen_data, pixels_per_line, y, scan, + this_check, use_a2vid_palette, mode_640); + break; + default: + halt_printf("type: %d bad!\n", type); + } + } - left = 4*40; - right = 0; + left = 4*40; + right = 0; - tmp = all_checks; - if(all_checks) { - for(i = 0; i < 160; i += 8) { - if(tmp & 0x80000000) { - left = MIN(i, left); - right = MAX(i + 8, right); - } - tmp = tmp << 1; - } - } + tmp = all_checks; + if(all_checks) { + for(i = 0; i < 160; i += 8) { + if(tmp & 0x80000000) { + left = MIN(i, left); + right = MAX(i + 8, right); + } + tmp = tmp << 1; + } + } - for(i = 0; i < num_lines; i++) { - g_a2_line_left_edge[st_line + i] = 4*left; - g_a2_line_right_edge[st_line + i] = 4*right; - } + for(i = 0; i < num_lines; i++) { + g_a2_line_left_edge[st_line + i] = 4*left; + g_a2_line_right_edge[st_line + i] = 4*right; + } #if 0 - if((g_a2_screen_buffer_changed & (1 << start_line)) != 0) { - if(((g_full_refresh_needed & (1 << start_line)) == 0) && - left >= right) { - halt_printf("shr: line: %d, left: %d, right:%d\n", - start_line, left, right); - printf("mask_per_line: %08x, all_checks: %08x\n", - mask_per_line, all_checks); - printf("check0,1 = %08x,%08x\n", check0, check1); - printf("a2_screen_chang: %08x\n", kd_tmp_debug); + if((g_a2_screen_buffer_changed & (1 << start_line)) != 0) { + if(((g_full_refresh_needed & (1 << start_line)) == 0) && + left >= right) { + halt_printf("shr: line: %d, left: %d, right:%d\n", + start_line, left, right); + printf("mask_per_line: %08x, all_checks: %08x\n", + mask_per_line, all_checks); + printf("check0,1 = %08x,%08x\n", check0, check1); + printf("a2_screen_chang: %08x\n", kd_tmp_debug); #ifdef HPUX - U_STACK_TRACE(); + U_STACK_TRACE(); #endif - } - } + } + } #endif - g_need_redraw = 0; + g_need_redraw = 0; } -void -display_screen() -{ - video_update_through_line(262); +void display_screen() { + video_update_through_line(262); } -void -video_update_event_line(int line) -{ - int new_line; +void video_update_event_line(int line) { + int new_line; - video_update_through_line(line); + video_update_through_line(line); - new_line = line + g_line_ref_amt; - if(new_line < 200) { - if(!g_config_control_panel) { - add_event_vid_upd(new_line); - } - } else if(line >= 262) { - video_update_through_line(0); - if(!g_config_control_panel) { - add_event_vid_upd(1); /* add event for new screen */ - } - } + new_line = line + g_line_ref_amt; + if(new_line < 200) { + if(!g_config_control_panel) { + add_event_vid_upd(new_line); + } + } else if(line >= 262) { + video_update_through_line(0); + if(!g_config_control_panel) { + add_event_vid_upd(1); /* add event for new screen */ + } + } - if(g_video_extra_check_inputs) { - if(g_video_dcycs_check_input < g_cur_dcycs) { - video_check_input_events(); - } - } + if(g_video_extra_check_inputs) { + if(g_video_dcycs_check_input < g_cur_dcycs) { + video_check_input_events(); + } + } } -void -video_check_input_events() -{ - word32 start_time, end_time; +void video_check_input_events() { + word32 start_time, end_time; - g_video_dcycs_check_input = g_cur_dcycs + 4000.0; + g_video_dcycs_check_input = g_cur_dcycs + 4000.0; - GET_ITIMER(start_time); - check_input_events(); - GET_ITIMER(end_time); + GET_ITIMER(start_time); + check_input_events(); + GET_ITIMER(end_time); - g_cycs_in_check_input += (end_time - start_time); + g_cycs_in_check_input += (end_time - start_time); } -void -video_update_through_line(int line) -{ - register word32 start_time; - register word32 end_time; - int *mode_ptr; - word32 mask; - int last_line, num_lines; - int must_reparse; - int new_all_stat, prev_all_stat; - int new_stat, prev_stat; - int i; +void video_update_through_line(int line) { + register word32 start_time; + register word32 end_time; + int *mode_ptr; + word32 mask; + int last_line, num_lines; + int must_reparse; + int new_all_stat, prev_all_stat; + int new_stat, prev_stat; + int i; #if 0 - vid_printf("\nvideo_upd for line %d, lines: %06x\n", line, - get_lines_since_vbl(g_cur_dcycs)); + vid_printf("\nvideo_upd for line %d, lines: %06x\n", line, + get_lines_since_vbl(g_cur_dcycs)); #endif - GET_ITIMER(start_time); + GET_ITIMER(start_time); - video_update_all_stat_through_line(line); + video_update_all_stat_through_line(line); - i = g_vid_update_last_line; + i = g_vid_update_last_line; - last_line = MIN(200, line+1); /* go through line, but not past 200 */ + last_line = MIN(200, line+1); /* go through line, but not past 200 */ - prev_stat = -2; - prev_all_stat = -2; - num_lines = 0; - must_reparse = 0; - for(i = g_vid_update_last_line; i < last_line; i++) { - new_all_stat = g_a2_new_all_stat[i]; - if(new_all_stat != g_a2_cur_all_stat[i]) { - /* regen line_stat for this line */ - g_a2_cur_all_stat[i] = new_all_stat; - if(new_all_stat == prev_all_stat) { - /* save a lookup */ - new_stat = prev_stat; - } else { - new_stat = video_all_stat_to_line_stat(i, - new_all_stat); - } - if(new_stat != g_a2_line_stat[i]) { - /* status changed */ - g_a2_line_stat[i] = new_stat; - mode_ptr = video_update_kimage_ptr(i, new_stat); - if(mode_ptr[i] != new_stat) { - must_reparse = 1; - mode_ptr[i] = new_stat; - } - mask = 1 << (line >> 3); - g_full_refresh_needed |= mask; - g_a2_screen_buffer_changed |= mask; - } - } + prev_stat = -2; + prev_all_stat = -2; + num_lines = 0; + must_reparse = 0; + for(i = g_vid_update_last_line; i < last_line; i++) { + new_all_stat = g_a2_new_all_stat[i]; + if(new_all_stat != g_a2_cur_all_stat[i]) { + /* regen line_stat for this line */ + g_a2_cur_all_stat[i] = new_all_stat; + if(new_all_stat == prev_all_stat) { + /* save a lookup */ + new_stat = prev_stat; + } else { + new_stat = video_all_stat_to_line_stat(i, + new_all_stat); + } + if(new_stat != g_a2_line_stat[i]) { + /* status changed */ + g_a2_line_stat[i] = new_stat; + mode_ptr = video_update_kimage_ptr(i, new_stat); + if(mode_ptr[i] != new_stat) { + must_reparse = 1; + mode_ptr[i] = new_stat; + } + mask = 1 << (line >> 3); + g_full_refresh_needed |= mask; + g_a2_screen_buffer_changed |= mask; + } + } - new_stat = g_a2_line_stat[i]; + new_stat = g_a2_line_stat[i]; - if( ((new_stat == prev_stat) && ((i & 7) != 0)) || - (num_lines == 0) ) { - /* merge prev and this together */ - prev_stat = new_stat; - num_lines++; - continue; - } + if( ((new_stat == prev_stat) && ((i & 7) != 0)) || + (num_lines == 0) ) { + /* merge prev and this together */ + prev_stat = new_stat; + num_lines++; + continue; + } - /* else, we must call refresh */ - video_refresh_lines(i - num_lines, num_lines, must_reparse); - num_lines = 1; - prev_all_stat = -1; - prev_stat = new_stat; - must_reparse = 0; - } - if(num_lines > 0) { - video_refresh_lines(i - num_lines, num_lines, must_reparse); - } + /* else, we must call refresh */ + video_refresh_lines(i - num_lines, num_lines, must_reparse); + num_lines = 1; + prev_all_stat = -1; + prev_stat = new_stat; + must_reparse = 0; + } + if(num_lines > 0) { + video_refresh_lines(i - num_lines, num_lines, must_reparse); + } - g_vid_update_last_line = last_line; + g_vid_update_last_line = last_line; - /* deal with border */ - if(line >= 262) { - if(g_num_lines_prev_superhires != g_num_lines_superhires) { - /* switched in/out from superhires--refresh borders */ - g_border_sides_refresh_needed = 1; - } - refresh_border(); + /* deal with border */ + if(line >= 262) { + if(g_num_lines_prev_superhires != g_num_lines_superhires) { + /* switched in/out from superhires--refresh borders */ + g_border_sides_refresh_needed = 1; + } + refresh_border(); - if(g_status_refresh_needed) { - g_status_refresh_needed = 0; - x_redraw_status_lines(); - } - } - GET_ITIMER(end_time); + if(g_status_refresh_needed) { + g_status_refresh_needed = 0; + x_redraw_status_lines(); + } + } + GET_ITIMER(end_time); - g_cycs_in_refresh_line += (end_time - start_time); + g_cycs_in_refresh_line += (end_time - start_time); - if(line >= 262) { - GET_ITIMER(start_time); - if(g_palette_change_summary) { - g_palette_change_summary = 0; - video_update_colormap(); - } + if(line >= 262) { + GET_ITIMER(start_time); + if(g_palette_change_summary) { + g_palette_change_summary = 0; + video_update_colormap(); + } - video_push_kimages(); - GET_ITIMER(end_time); - g_cycs_in_refresh_ximage += (end_time - start_time); + video_push_kimages(); + GET_ITIMER(end_time); + g_cycs_in_refresh_ximage += (end_time - start_time); - g_num_lines_prev_superhires = g_num_lines_superhires; - g_num_lines_prev_superhires640 = g_num_lines_superhires640; - g_num_lines_superhires = 0; - g_num_lines_superhires640 = 0; - } + g_num_lines_prev_superhires = g_num_lines_superhires; + g_num_lines_prev_superhires640 = g_num_lines_superhires640; + g_num_lines_superhires = 0; + g_num_lines_superhires640 = 0; + } } -void -video_refresh_lines(int st_line, int num_lines, int must_reparse) -{ - byte *ptr; - int line; - int stat; - int mode; - int dbl, page, color; - int altchar, bg_color, text_color; - int pixels_per_line; - int i; +void video_refresh_lines(int st_line, int num_lines, int must_reparse) { + byte *ptr; + int line; + int stat; + int mode; + int dbl, page, color; + int altchar, bg_color, text_color; + int pixels_per_line; + int i; - line = st_line; + line = st_line; - /* do some basic checking, num_lines should be 1-8, and */ - /* st_line+num_lines-1 cannot roll over 8 */ - if((num_lines < 1) || (num_lines > 8) || - (((st_line & 7) + num_lines) > 8) ) { - halt_printf("video_refresh_lines called with %d, %d\n", - st_line, num_lines); - return; - } + /* do some basic checking, num_lines should be 1-8, and */ + /* st_line+num_lines-1 cannot roll over 8 */ + if((num_lines < 1) || (num_lines > 8) || + (((st_line & 7) + num_lines) > 8) ) { + halt_printf("video_refresh_lines called with %d, %d\n", + st_line, num_lines); + return; + } - stat = g_a2_line_stat[line]; - ptr = g_a2_line_kimage[line]->data_ptr; - pixels_per_line = g_a2_line_kimage[line]->width_act; + stat = g_a2_line_stat[line]; + ptr = g_a2_line_kimage[line]->data_ptr; + pixels_per_line = g_a2_line_kimage[line]->width_act; - /* do not zero g_a2_line_left/right_edge here since text/gr routs */ - /* need to leave stale values around for drawing to work correctly */ - /* all routs force in new left/right when there are screen changes */ + /* do not zero g_a2_line_left/right_edge here since text/gr routs */ + /* need to leave stale values around for drawing to work correctly */ + /* all routs force in new left/right when there are screen changes */ - dbl = stat & 1; - color = (stat >> 1) & 1; - page = (stat >> 2) & 1; - mode = (stat >> 4) & 7; + dbl = stat & 1; + color = (stat >> 1) & 1; + page = (stat >> 2) & 1; + mode = (stat >> 4) & 7; #if 0 - printf("refresh line: %d, stat: %04x\n", line, stat); + printf("refresh line: %d, stat: %04x\n", line, stat); #endif - switch(mode) { - case MODE_TEXT: - altchar = (stat >> 7) & 1; - bg_color = (stat >> 8) & 0xf; - text_color = (stat >> 12) & 0xf; - if(dbl) { - redraw_changed_text_80(0x000 + page*0x400, st_line, - num_lines, must_reparse, ptr, altchar, bg_color, - text_color, pixels_per_line); - } else { - redraw_changed_text_40(0x000 + page*0x400, st_line, - num_lines, must_reparse, ptr, altchar, bg_color, - text_color, pixels_per_line); - } - break; - case MODE_GR: - if(dbl) { - redraw_changed_dbl_gr(0x000 + page*0x400, st_line, - num_lines, must_reparse, ptr, pixels_per_line); - } else { - redraw_changed_gr(0x000 + page*0x400, st_line, - num_lines, must_reparse, ptr, pixels_per_line); - } - break; - case MODE_HGR: - if(dbl) { - redraw_changed_dbl_hires(0x000 + page*0x2000, st_line, - num_lines, color, must_reparse, ptr, - pixels_per_line); - } else { - redraw_changed_hires(0x000 + page*0x2000, st_line, - num_lines, color, must_reparse, ptr, - pixels_per_line); - } - break; - case MODE_SUPER_HIRES: - g_num_lines_superhires++; - redraw_changed_super_hires(0, st_line, num_lines, - must_reparse, ptr); - break; - case MODE_BORDER: - if(line < 192) { - halt_printf("Border line not 192: %d\n", line); - } - for(i = 0; i < num_lines; i++) { - g_a2_line_left_edge[line + i] = 0; - g_a2_line_right_edge[line + i] = 560; - } - if(g_border_line24_refresh_needed) { - g_border_line24_refresh_needed = 0; - g_a2_screen_buffer_changed |= (1 << 24); - } - break; - default: - halt_printf("refresh screen: mode: 0x%02x unknown!\n", mode); - exit(7); - } + switch(mode) { + case MODE_TEXT: + altchar = (stat >> 7) & 1; + bg_color = (stat >> 8) & 0xf; + text_color = (stat >> 12) & 0xf; + if(dbl) { + redraw_changed_text_80(0x000 + page*0x400, st_line, + num_lines, must_reparse, ptr, altchar, bg_color, + text_color, pixels_per_line); + } else { + redraw_changed_text_40(0x000 + page*0x400, st_line, + num_lines, must_reparse, ptr, altchar, bg_color, + text_color, pixels_per_line); + } + break; + case MODE_GR: + if(dbl) { + redraw_changed_dbl_gr(0x000 + page*0x400, st_line, + num_lines, must_reparse, ptr, pixels_per_line); + } else { + redraw_changed_gr(0x000 + page*0x400, st_line, + num_lines, must_reparse, ptr, pixels_per_line); + } + break; + case MODE_HGR: + if(dbl) { + redraw_changed_dbl_hires(0x000 + page*0x2000, st_line, + num_lines, color, must_reparse, ptr, + pixels_per_line); + } else { + redraw_changed_hires(0x000 + page*0x2000, st_line, + num_lines, color, must_reparse, ptr, + pixels_per_line); + } + break; + case MODE_SUPER_HIRES: + g_num_lines_superhires++; + redraw_changed_super_hires(0, st_line, num_lines, + must_reparse, ptr); + break; + case MODE_BORDER: + if(line < 192) { + halt_printf("Border line not 192: %d\n", line); + } + for(i = 0; i < num_lines; i++) { + g_a2_line_left_edge[line + i] = 0; + g_a2_line_right_edge[line + i] = 560; + } + if(g_border_line24_refresh_needed) { + g_border_line24_refresh_needed = 0; + g_a2_screen_buffer_changed |= (1 << 24); + } + break; + default: + halt_printf("refresh screen: mode: 0x%02x unknown!\n", mode); + exit(7); + } } -void -refresh_border() -{ - /**ZZZZ***/ +void refresh_border() { + /**ZZZZ***/ } -// OG Added video_release_kimages proto -void video_release_kimages(); - -void -end_screen() -{ - printf("In end_screen\n"); - - // OG Free up allocated images - video_release_kimages(); - xdriver_end(); +// OG Added video_release_kimages proto +void video_release_kimages(); + +void end_screen() { + glog("Shutting down display"); + + // OG Free up allocated images + video_release_kimages(); + xdriver_end(); } byte g_font_array[256][8] = { #include "gsportfont.h" }; -void -read_a2_font() -{ - byte *f40_e_ptr; - byte *f40_o_ptr; - byte *f80_0_ptr, *f80_1_ptr, *f80_2_ptr, *f80_3_ptr; - int char_num; - int j, k; - int val0; - int mask; - int pix; +void read_a2_font() { + byte *f40_e_ptr; + byte *f40_o_ptr; + byte *f80_0_ptr, *f80_1_ptr, *f80_2_ptr, *f80_3_ptr; + int char_num; + int j, k; + int val0; + int mask; + int pix; - for(char_num = 0; char_num < 0x100; char_num++) { - for(j = 0; j < 8; j++) { - val0 = g_font_array[char_num][j]; + for(char_num = 0; char_num < 0x100; char_num++) { + for(j = 0; j < 8; j++) { + val0 = g_font_array[char_num][j]; - mask = 0x80; + mask = 0x80; - for(k = 0; k < 3; k++) { - g_font80_off0_bits[char_num][j][k] = 0; - g_font80_off1_bits[char_num][j][k] = 0; - g_font80_off2_bits[char_num][j][k] = 0; - g_font80_off3_bits[char_num][j][k] = 0; - g_font40_even_bits[char_num][j][k] = 0; - g_font40_odd_bits[char_num][j][k] = 0; - } - g_font40_even_bits[char_num][j][3] = 0; - g_font40_odd_bits[char_num][j][3] = 0; + for(k = 0; k < 3; k++) { + g_font80_off0_bits[char_num][j][k] = 0; + g_font80_off1_bits[char_num][j][k] = 0; + g_font80_off2_bits[char_num][j][k] = 0; + g_font80_off3_bits[char_num][j][k] = 0; + g_font40_even_bits[char_num][j][k] = 0; + g_font40_odd_bits[char_num][j][k] = 0; + } + g_font40_even_bits[char_num][j][3] = 0; + g_font40_odd_bits[char_num][j][3] = 0; - f40_e_ptr = (byte *)&g_font40_even_bits[char_num][j][0]; - f40_o_ptr = (byte *)&g_font40_odd_bits[char_num][j][0]; + f40_e_ptr = (byte *)&g_font40_even_bits[char_num][j][0]; + f40_o_ptr = (byte *)&g_font40_odd_bits[char_num][j][0]; - f80_0_ptr = (byte *)&g_font80_off0_bits[char_num][j][0]; - f80_1_ptr = (byte *)&g_font80_off1_bits[char_num][j][0]; - f80_2_ptr = (byte *)&g_font80_off2_bits[char_num][j][0]; - f80_3_ptr = (byte *)&g_font80_off3_bits[char_num][j][0]; + f80_0_ptr = (byte *)&g_font80_off0_bits[char_num][j][0]; + f80_1_ptr = (byte *)&g_font80_off1_bits[char_num][j][0]; + f80_2_ptr = (byte *)&g_font80_off2_bits[char_num][j][0]; + f80_3_ptr = (byte *)&g_font80_off3_bits[char_num][j][0]; - for(k = 0; k < 7; k++) { - pix = 0; - if(val0 & mask) { - pix = 0xf; - } + for(k = 0; k < 7; k++) { + pix = 0; + if(val0 & mask) { + pix = 0xf; + } - f40_e_ptr[2*k] = pix; - f40_e_ptr[2*k+1] = pix; + f40_e_ptr[2*k] = pix; + f40_e_ptr[2*k+1] = pix; - f40_o_ptr[2*k+2] = pix; - f40_o_ptr[2*k+3] = pix; + f40_o_ptr[2*k+2] = pix; + f40_o_ptr[2*k+3] = pix; - f80_0_ptr[k] = pix; - f80_1_ptr[k+1] = pix; - f80_2_ptr[k+2] = pix; - f80_3_ptr[k+3] = pix; + f80_0_ptr[k] = pix; + f80_1_ptr[k+1] = pix; + f80_2_ptr[k+2] = pix; + f80_3_ptr[k+3] = pix; - mask = mask >> 1; - } - } - } + mask = mask >> 1; + } + } + } } /* Helper routine for the *driver.c files */ -void -video_get_kimage(Kimage *kimage_ptr, int extend_info, int depth, int mdepth) -{ - int width; - int height; +void video_get_kimage(Kimage *kimage_ptr, int extend_info, int depth, int mdepth) { + int width; + int height; - width = A2_WINDOW_WIDTH; - height = A2_WINDOW_HEIGHT; - if(extend_info & 1) { - /* Border at top and bottom of screen */ - width = X_A2_WINDOW_WIDTH; - height = X_A2_WINDOW_HEIGHT - A2_WINDOW_HEIGHT + 2*8; - } - if(extend_info & 2) { - /* Border at sides of screen */ - width = BORDER_WIDTH + EFF_BORDER_WIDTH; - height = A2_WINDOW_HEIGHT; - } + width = A2_WINDOW_WIDTH; + height = A2_WINDOW_HEIGHT; + if(extend_info & 1) { + /* Border at top and bottom of screen */ + width = X_A2_WINDOW_WIDTH; + height = X_A2_WINDOW_HEIGHT - A2_WINDOW_HEIGHT + 2*8; + } + if(extend_info & 2) { + /* Border at sides of screen */ + width = BORDER_WIDTH + EFF_BORDER_WIDTH; + height = A2_WINDOW_HEIGHT; + } - kimage_ptr->dev_handle = 0; - kimage_ptr->dev_handle2 = 0; - kimage_ptr->data_ptr = 0; - kimage_ptr->width_req = width; - kimage_ptr->width_act = width; - kimage_ptr->height = height; - kimage_ptr->depth = depth; - kimage_ptr->mdepth = mdepth; - kimage_ptr->aux_info = 0; + kimage_ptr->dev_handle = 0; + kimage_ptr->dev_handle2 = 0; + kimage_ptr->data_ptr = 0; + kimage_ptr->width_req = width; + kimage_ptr->width_act = width; + kimage_ptr->height = height; + kimage_ptr->depth = depth; + kimage_ptr->mdepth = mdepth; + kimage_ptr->aux_info = 0; - x_get_kimage(kimage_ptr); + x_get_kimage(kimage_ptr); } -void -video_get_kimages() -{ - video_get_kimage(&g_kimage_text[0], 0, 8, 8); - video_get_kimage(&g_kimage_text[1], 0, 8, 8); - video_get_kimage(&g_kimage_hires[0], 0, 8, 8); - video_get_kimage(&g_kimage_hires[1], 0, 8, 8); - video_get_kimage(&g_kimage_superhires, 0, g_screen_depth, - g_screen_mdepth); - video_get_kimage(&g_kimage_border_special, 1, g_screen_depth, - g_screen_mdepth); - video_get_kimage(&g_kimage_border_sides, 2, g_screen_depth, - g_screen_mdepth); +void video_get_kimages() { + video_get_kimage(&g_kimage_text[0], 0, 8, 8); + video_get_kimage(&g_kimage_text[1], 0, 8, 8); + video_get_kimage(&g_kimage_hires[0], 0, 8, 8); + video_get_kimage(&g_kimage_hires[1], 0, 8, 8); + video_get_kimage(&g_kimage_superhires, 0, g_screen_depth, + g_screen_mdepth); + video_get_kimage(&g_kimage_border_special, 1, g_screen_depth, + g_screen_mdepth); + video_get_kimage(&g_kimage_border_sides, 2, g_screen_depth, + g_screen_mdepth); } -// OG Added video_release_kimages (to match video_get_kimages) -void video_release_kimages() -{ - extern void x_release_kimage(Kimage *kimage_ptr); - - x_release_kimage(&g_kimage_text[0]); - x_release_kimage(&g_kimage_text[1]); - x_release_kimage(&g_kimage_hires[0]); - x_release_kimage(&g_kimage_hires[1]); - x_release_kimage(&g_kimage_superhires); - x_release_kimage(&g_kimage_border_special); - x_release_kimage(&g_kimage_border_sides); -} - - -void -video_convert_kimage_depth(Kimage *kim_in, Kimage *kim_out, int startx, - int starty, int width, int height) -{ - byte *indata, *inptr; - word32 *outdata32, *outptr32; - word16 *outdata16, *outptr16; - word32 *palptr; - int out_width, in_width; - int x, y; +// OG Added video_release_kimages (to match video_get_kimages) +void video_release_kimages() { + extern void x_release_kimage(Kimage *kimage_ptr); - indata = (byte *)kim_in->data_ptr; - outdata32 = (word32 *)kim_out->data_ptr; - outdata16 = (word16 *)kim_out->data_ptr; - - if(kim_in == &g_kimage_superhires) { - palptr = &(g_palette_8to1624[0]); - } else { - palptr = &(g_a2palette_8to1624[0]); - } - if(kim_in->depth != 8) { - printf("x_convert_kimage_depth from non-8 bit depth: %p\n", - kim_in); - exit(1); - } - - out_width = kim_out->width_act; - in_width = kim_in->width_act; - indata += (starty * in_width + startx); - outdata32 += (starty * out_width + startx); - outdata16 += (starty * out_width + startx); - if(kim_out->mdepth == 16) { - for(y = 0; y < height; y++) { - outptr16 = outdata16; - inptr = indata; - for(x = 0; x < width; x++) { - *outptr16++ = palptr[*inptr++]; - } - outdata16 += out_width; - indata += in_width; - } - } else { - /* 32-bit depth */ - for(y = 0; y < height; y++) { - outptr32 = outdata32; - inptr = indata; - for(x = 0; x < width; x++) { - *outptr32++ = palptr[*inptr++]; - } - outdata32 += out_width; - indata += in_width; - } - } + x_release_kimage(&g_kimage_text[0]); + x_release_kimage(&g_kimage_text[1]); + x_release_kimage(&g_kimage_hires[0]); + x_release_kimage(&g_kimage_hires[1]); + x_release_kimage(&g_kimage_superhires); + x_release_kimage(&g_kimage_border_special); + x_release_kimage(&g_kimage_border_sides); } -void -video_push_lines(Kimage *kimage_ptr, int start_line, int end_line, int left_pix, - int right_pix) -{ - int mdepth_mismatch; - int srcy; - int center = 0; // OG added variable to center screen - - //OG add null pointer check when emulator is restarted - if (!kimage_ptr) - { - printf("warning : video_push_lines(kimage_ptr=null)\n"); - return ; - } - if(left_pix >= right_pix || left_pix < 0 || right_pix <= 0) { - halt_printf("video_push_lines: lines %d to %d, pix %d to %d\n", - start_line, end_line, left_pix, right_pix); - printf("a2_screen_buf_ch:%08x, g_full_refr:%08x\n", - g_a2_screen_buffer_changed, g_full_refresh_needed); - } +void video_convert_kimage_depth(Kimage *kim_in, Kimage *kim_out, int startx, + int starty, int width, int height) { + byte *indata, *inptr; + word32 *outdata32, *outptr32; + word16 *outdata16, *outptr16; + word32 *palptr; + int out_width, in_width; + int x, y; - srcy = 2*start_line; + indata = (byte *)kim_in->data_ptr; + outdata32 = (word32 *)kim_out->data_ptr; + outdata16 = (word16 *)kim_out->data_ptr; - mdepth_mismatch = (kimage_ptr->mdepth != g_screen_mdepth); - if(mdepth_mismatch) { - /* translate from 8-bit pseudo to correct visual */ - video_convert_kimage_depth(kimage_ptr, &g_mainwin_kimage, - left_pix, srcy, (right_pix - left_pix), - 2*(end_line - start_line)); - kimage_ptr = &g_mainwin_kimage; - } - g_refresh_bytes_xfer += 2*(end_line - start_line) * - (right_pix - left_pix); + if(kim_in == &g_kimage_superhires) { + palptr = &(g_palette_8to1624[0]); + } else { + palptr = &(g_a2palette_8to1624[0]); + } + if(kim_in->depth != 8) { + printf("x_convert_kimage_depth from non-8 bit depth: %p\n", + kim_in); + exit(1); + } - // OG Calculating new center - if (g_cur_a2_stat & ALL_STAT_SUPER_HIRES) - center=0; - else - center=EFF_BORDER_WIDTH - BORDER_WIDTH; - - // OG shifting image to the center - x_push_kimage(kimage_ptr, g_video_act_margin_left + left_pix + center, - g_video_act_margin_top + srcy, left_pix, srcy, - (right_pix - left_pix), 2*(end_line - start_line)); + out_width = kim_out->width_act; + in_width = kim_in->width_act; + indata += (starty * in_width + startx); + outdata32 += (starty * out_width + startx); + outdata16 += (starty * out_width + startx); + if(kim_out->mdepth == 16) { + for(y = 0; y < height; y++) { + outptr16 = outdata16; + inptr = indata; + for(x = 0; x < width; x++) { + *outptr16++ = palptr[*inptr++]; + } + outdata16 += out_width; + indata += in_width; + } + } else { + /* 32-bit depth */ + for(y = 0; y < height; y++) { + outptr32 = outdata32; + inptr = indata; + for(x = 0; x < width; x++) { + *outptr32++ = palptr[*inptr++]; + } + outdata32 += out_width; + indata += in_width; + } + } } -void -video_push_border_sides_lines(int src_x, int dest_x, int width, int start_line, - int end_line) -{ - Kimage *kimage_ptr; - int srcy; +void video_push_lines(Kimage *kimage_ptr, int start_line, int end_line, int left_pix, + int right_pix) { + int mdepth_mismatch; + int srcy; + int center = 0; // OG added variable to center screen - if(start_line < 0 || width < 0) { - return; - } + //OG add null pointer check when emulator is restarted + if (!kimage_ptr) + { + printf("warning : video_push_lines(kimage_ptr=null)\n"); + return; + } + + if(left_pix >= right_pix || left_pix < 0 || right_pix <= 0) { + halt_printf("video_push_lines: lines %d to %d, pix %d to %d\n", + start_line, end_line, left_pix, right_pix); + printf("a2_screen_buf_ch:%08x, g_full_refr:%08x\n", + g_a2_screen_buffer_changed, g_full_refresh_needed); + } + + srcy = 2*start_line; + + mdepth_mismatch = (kimage_ptr->mdepth != g_screen_mdepth); + if(mdepth_mismatch) { + /* translate from 8-bit pseudo to correct visual */ + video_convert_kimage_depth(kimage_ptr, &g_mainwin_kimage, + left_pix, srcy, (right_pix - left_pix), + 2*(end_line - start_line)); + kimage_ptr = &g_mainwin_kimage; + } + g_refresh_bytes_xfer += 2*(end_line - start_line) * + (right_pix - left_pix); + + // OG Calculating new center + if (g_cur_a2_stat & ALL_STAT_SUPER_HIRES) + center=0; + else + center=EFF_BORDER_WIDTH - BORDER_WIDTH; + + // OG shifting image to the center + x_push_kimage(kimage_ptr, g_video_act_margin_left + left_pix + center, + g_video_act_margin_top + srcy, left_pix, srcy, + (right_pix - left_pix), 2*(end_line - start_line)); +} + +void video_push_border_sides_lines(int src_x, int dest_x, int width, int start_line, + int end_line) { + Kimage *kimage_ptr; + int srcy; + + if(start_line < 0 || width < 0) { + return; + } #if 0 - printf("push_border_sides lines:%d-%d from %d to %d\n", - start_line, end_line, end_x - width, end_x); + printf("push_border_sides lines:%d-%d from %d to %d\n", + start_line, end_line, end_x - width, end_x); #endif - kimage_ptr = &g_kimage_border_sides; - g_refresh_bytes_xfer += 2 * (end_line - start_line) * width; + kimage_ptr = &g_kimage_border_sides; + g_refresh_bytes_xfer += 2 * (end_line - start_line) * width; - srcy = 2 * start_line; + srcy = 2 * start_line; - // Adjust dext_x to accound for changed margins - dest_x = dest_x + g_video_act_margin_left - BASE_MARGIN_LEFT; - if(dest_x < BASE_MARGIN_LEFT) { - src_x = src_x + g_video_act_margin_left - BASE_MARGIN_LEFT; - // Don't adjust src_x if doing right border - } - if(dest_x < 0) { - width = width + dest_x; - src_x = src_x - dest_x; - dest_x = 0; - } - if(src_x < 0) { - width = width + src_x; - dest_x = dest_x - src_x; - src_x = 0; - } - if(dest_x + width > g_video_act_width) { - width = g_video_act_width - dest_x; - } - if(width > 0) { - x_push_kimage(kimage_ptr, dest_x, g_video_act_margin_top + srcy, - src_x, srcy, width, 2*(end_line - start_line)); - } + // Adjust dext_x to accound for changed margins + dest_x = dest_x + g_video_act_margin_left - BASE_MARGIN_LEFT; + if(dest_x < BASE_MARGIN_LEFT) { + src_x = src_x + g_video_act_margin_left - BASE_MARGIN_LEFT; + // Don't adjust src_x if doing right border + } + if(dest_x < 0) { + width = width + dest_x; + src_x = src_x - dest_x; + dest_x = 0; + } + if(src_x < 0) { + width = width + src_x; + dest_x = dest_x - src_x; + src_x = 0; + } + if(dest_x + width > g_video_act_width) { + width = g_video_act_width - dest_x; + } + if(width > 0) { + x_push_kimage(kimage_ptr, dest_x, g_video_act_margin_top + srcy, + src_x, srcy, width, 2*(end_line - start_line)); + } } -void -video_push_border_sides() -{ - int old_width; - int prev_line; - int width; - int mode; - int i; +void video_push_border_sides() { + int old_width; + int prev_line; + int width; + int mode; + int i; #if 0 - printf("refresh border sides!\n"); + printf("refresh border sides!\n"); #endif - /* redraw left sides */ - // OG Left side can alos be "jagged" as a2 screen is now being centered - - //video_push_border_sides_lines(0, 0, BORDER_WIDTH, 0, 200); - - prev_line = -1; - old_width = -1; - for(i = 0; i < 200; i++) { - mode = (g_a2_line_stat[i] >> 4) & 7; - width = EFF_BORDER_WIDTH; - if(mode == MODE_SUPER_HIRES) { - width = BORDER_WIDTH; - } - if(width != old_width) { - video_push_border_sides_lines(BORDER_WIDTH, - 0, old_width, - prev_line, i); - prev_line = i; - old_width = width; - } - } - video_push_border_sides_lines(0/*BORDER_WIDTH*/, - 0, old_width, prev_line, 200); + /* redraw left sides */ + // OG Left side can alos be "jagged" as a2 screen is now being centered - /* right side--can be "jagged" */ - prev_line = -1; - old_width = -1; - for(i = 0; i < 200; i++) { - mode = (g_a2_line_stat[i] >> 4) & 7; - width = EFF_BORDER_WIDTH; - if(mode == MODE_SUPER_HIRES) { - width = BORDER_WIDTH; - } - if(width != old_width) { - video_push_border_sides_lines(BORDER_WIDTH, - X_A2_WINDOW_WIDTH - old_width, old_width, - prev_line, i); - prev_line = i; - old_width = width; - } - } + //video_push_border_sides_lines(0, 0, BORDER_WIDTH, 0, 200); - video_push_border_sides_lines(0/*BORDER_WIDTH*/, - X_A2_WINDOW_WIDTH - old_width, old_width, prev_line, 200); + prev_line = -1; + old_width = -1; + for(i = 0; i < 200; i++) { + mode = (g_a2_line_stat[i] >> 4) & 7; + width = EFF_BORDER_WIDTH; + if(mode == MODE_SUPER_HIRES) { + width = BORDER_WIDTH; + } + if(width != old_width) { + video_push_border_sides_lines(BORDER_WIDTH, + 0, old_width, + prev_line, i); + prev_line = i; + old_width = width; + } + } + video_push_border_sides_lines(0 /*BORDER_WIDTH*/, + 0, old_width, prev_line, 200); + + /* right side--can be "jagged" */ + prev_line = -1; + old_width = -1; + for(i = 0; i < 200; i++) { + mode = (g_a2_line_stat[i] >> 4) & 7; + width = EFF_BORDER_WIDTH; + if(mode == MODE_SUPER_HIRES) { + width = BORDER_WIDTH; + } + if(width != old_width) { + video_push_border_sides_lines(BORDER_WIDTH, + X_A2_WINDOW_WIDTH - old_width, old_width, + prev_line, i); + prev_line = i; + old_width = width; + } + } + + video_push_border_sides_lines(0 /*BORDER_WIDTH*/, + X_A2_WINDOW_WIDTH - old_width, old_width, prev_line, 200); } -void -video_push_border_special() -{ - Kimage *kimage_ptr; - int width, height; - int src_x, src_y; - int dest_x, dest_y; +void video_push_border_special() { + Kimage *kimage_ptr; + int width, height; + int src_x, src_y; + int dest_x, dest_y; - kimage_ptr = &g_kimage_border_special; - width = g_video_act_width; - g_refresh_bytes_xfer += width * (BASE_MARGIN_TOP + BASE_MARGIN_BOTTOM); + kimage_ptr = &g_kimage_border_special; + width = g_video_act_width; + g_refresh_bytes_xfer += width * (BASE_MARGIN_TOP + BASE_MARGIN_BOTTOM); - // First do bottom border: dest_x from 0 to 640+MARGIN_LEFT+MARGIN_RIGHT - // and dest_y of BASE_MARGIN_BOTTOM starting at TOP+A2_HEIGHT - // src_x is dest_x, and src_y is 0. - dest_y = g_video_act_margin_top + A2_WINDOW_HEIGHT; - height = g_video_act_margin_bottom; - src_y = BASE_MARGIN_BOTTOM - height; + // First do bottom border: dest_x from 0 to 640+MARGIN_LEFT+MARGIN_RIGHT + // and dest_y of BASE_MARGIN_BOTTOM starting at TOP+A2_HEIGHT + // src_x is dest_x, and src_y is 0. + dest_y = g_video_act_margin_top + A2_WINDOW_HEIGHT; + height = g_video_act_margin_bottom; + src_y = BASE_MARGIN_BOTTOM - height; - dest_x = 0; - src_x = BASE_MARGIN_LEFT - g_video_act_margin_left; + dest_x = 0; + src_x = BASE_MARGIN_LEFT - g_video_act_margin_left; +/* + glogf("width: %d", kimage_ptr->width_act); + for (int i = 600; i< 700; i++) { + kimage_ptr->data_ptr[i*4] = 0xFF; + kimage_ptr->data_ptr[i*4+1] = 0xFF; + kimage_ptr->data_ptr[i*4+2] = 0x00; + } + */ + if(width > 0 && height > 0) { + #ifdef WINSDL_BORDERHACK + x_push_kimage(kimage_ptr, dest_x+72, dest_y, src_x, src_y, width, height); + #endif + x_push_kimage(kimage_ptr, dest_x, dest_y, src_x, src_y, width, height); +// glogf("X:%d Y: %d SX:%d SY:%D W:%d H:%d\n",dest_x, dest_y, src_x, src_y, width, height); + } - if(width > 0 && height > 0) { - x_push_kimage(kimage_ptr, dest_x, dest_y, src_x, src_y, - width, height); - } - - // Then fix top border: dest_x from 0 to 640+LEFT+RIGHT and - // dest_y from 0 to TOP. src_x is dest_x, but src_y is - // BOTTOM to BOTTOM+TOP - // Just use src_x and dest_x from earlier. - height = g_video_act_margin_top; - dest_y = 0; - src_y = BASE_MARGIN_BOTTOM; - if(width > 0 && height > 0) { - x_push_kimage(kimage_ptr, dest_x, dest_y, src_x, src_y, - width, height); - } + // Then fix top border: dest_x from 0 to 640+LEFT+RIGHT and + // dest_y from 0 to TOP. src_x is dest_x, but src_y is + // BOTTOM to BOTTOM+TOP + // Just use src_x and dest_x from earlier. + height = g_video_act_margin_top; + dest_y = 0; + src_y = BASE_MARGIN_BOTTOM; + if(width > 0 && height > 0) { + #ifdef WINSDL_BORDERHACK + x_push_kimage(kimage_ptr, dest_x+72, dest_y, src_x, src_y, width, height); + #endif + x_push_kimage(kimage_ptr, dest_x, dest_y, src_x, src_y, width, height); + } } -// OG Added window ratio support -extern int x_calc_ratio(float ratiox,float ratioy); - -void -video_push_kimages() -{ - register word32 start_time; - register word32 end_time; - Kimage *last_kim, *cur_kim; - word32 mask; - int start; - int line; - int left_pix, right_pix; - int left, right; - int line_div8; - float ratiox = 0,ratioy = 0; +// OG Added window ratio support +extern int x_calc_ratio(float ratiox,float ratioy); - if(g_border_sides_refresh_needed) { - g_border_sides_refresh_needed = 0; - video_push_border_sides(); - } - if(g_border_special_refresh_needed) { - g_border_special_refresh_needed = 0; - video_push_border_special(); - } +void video_push_kimages() { + register word32 start_time; + register word32 end_time; + Kimage *last_kim, *cur_kim; + word32 mask; + int start; + int line; + int left_pix, right_pix; + int left, right; + int line_div8; + float ratiox = 0,ratioy = 0; - if(g_a2_screen_buffer_changed == 0) { - return; - } + if(g_border_sides_refresh_needed) { + g_border_sides_refresh_needed = 0; + video_push_border_sides(); + } + if(g_border_special_refresh_needed) { + g_border_special_refresh_needed = 0; + video_push_border_special(); + } - GET_ITIMER(start_time); + if(g_a2_screen_buffer_changed == 0) { + return; + } - if (x_calc_ratio(ratiox,ratioy)) - { - line = 0; - while (1) - { - start = line; - cur_kim = g_a2_line_kimage[line]; - while(line < 200 && g_a2_line_kimage[line] == cur_kim) line++; - if (cur_kim == &g_kimage_superhires) - right = 640; - else - right = 560; - - video_push_lines(cur_kim, start, line,0,right); - if (line==200) break; - } - - } - else - { - start = -1; - last_kim = (Kimage *)-1; - cur_kim = (Kimage *)0; + GET_ITIMER(start_time); - left_pix = 640; - right_pix = 0; + if (x_calc_ratio(ratiox,ratioy)) + { + line = 0; + while (1) + { + start = line; + cur_kim = g_a2_line_kimage[line]; + while(line < 200 && g_a2_line_kimage[line] == cur_kim) line++; + if (cur_kim == &g_kimage_superhires) + right = 640; + else + right = 560; - for(line = 0; line < 200; line++) { - line_div8 = line >> 3; - mask = 1 << (line_div8); - cur_kim = g_a2_line_kimage[line]; - if((g_full_refresh_needed & mask) != 0) { - left = 0; - right = 560; - if(cur_kim == &g_kimage_superhires) { - right = 640; - } - } else { - left = g_a2_line_left_edge[line]; - right = g_a2_line_right_edge[line]; - } + video_push_lines(cur_kim, start, line,0,right); + if (line==200) break; + } - if(!(g_a2_screen_buffer_changed & mask) || (left > right)) { - /* No need to update this line */ - /* Refresh previous chunks of lines, if any */ - if(start >= 0) { - video_push_lines(last_kim, start, line, - left_pix, right_pix); - start = -1; - left_pix = 640; - right_pix = 0; - } - } else { - /* Need to update this line */ - if(start < 0) { - start = line; - last_kim = cur_kim; - } - if(cur_kim != last_kim) { - /* do the refresh */ - video_push_lines(last_kim, start, line, - left_pix, right_pix); - last_kim = cur_kim; - start = line; - left_pix = left; - right_pix = right; - } - left_pix = MIN(left, left_pix); - right_pix = MAX(right, right_pix); - } - } + } + else + { + start = -1; + last_kim = (Kimage *)-1; + cur_kim = (Kimage *)0; - if(start >= 0) { - video_push_lines(last_kim, start, 200, left_pix, right_pix); - } - } + left_pix = 640; + right_pix = 0; - g_a2_screen_buffer_changed = 0; - g_full_refresh_needed = 0; + for(line = 0; line < 200; line++) { + line_div8 = line >> 3; + mask = 1 << (line_div8); + cur_kim = g_a2_line_kimage[line]; + if((g_full_refresh_needed & mask) != 0) { + left = 0; + right = 560; + if(cur_kim == &g_kimage_superhires) { + right = 640; + } + } else { + left = g_a2_line_left_edge[line]; + right = g_a2_line_right_edge[line]; + } - x_push_done(); + if(!(g_a2_screen_buffer_changed & mask) || (left > right)) { + /* No need to update this line */ + /* Refresh previous chunks of lines, if any */ + if(start >= 0) { + video_push_lines(last_kim, start, line, + left_pix, right_pix); + start = -1; + left_pix = 640; + right_pix = 0; + } + } else { + /* Need to update this line */ + if(start < 0) { + start = line; + last_kim = cur_kim; + } + if(cur_kim != last_kim) { + /* do the refresh */ + video_push_lines(last_kim, start, line, + left_pix, right_pix); + last_kim = cur_kim; + start = line; + left_pix = left; + right_pix = right; + } + left_pix = MIN(left, left_pix); + right_pix = MAX(right, right_pix); + } + } - GET_ITIMER(end_time); + if(start >= 0) { + video_push_lines(last_kim, start, 200, left_pix, right_pix); + } + } - g_cycs_in_xredraw += (end_time - start_time); + g_a2_screen_buffer_changed = 0; + g_full_refresh_needed = 0; + + x_push_done(); + + GET_ITIMER(end_time); + + g_cycs_in_xredraw += (end_time - start_time); } -void -video_update_color_raw(int col_num, int a2_color) -{ - word32 tmp; - int red, green, blue; - int newred, newgreen, newblue; +void video_update_color_raw(int col_num, int a2_color) { + word32 tmp; + int red, green, blue; + int newred, newgreen, newblue; - red = (a2_color >> 8) & 0xf; - green = (a2_color >> 4) & 0xf; - blue = (a2_color) & 0xf; - red = ((red << 4) + red); - green = ((green << 4) + green); - blue = ((blue << 4) + blue); + red = (a2_color >> 8) & 0xf; + green = (a2_color >> 4) & 0xf; + blue = (a2_color) & 0xf; + red = ((red << 4) + red); + green = ((green << 4) + green); + blue = ((blue << 4) + blue); - newred = red >> g_red_right_shift; - newgreen = green >> g_green_right_shift; - newblue = blue >> g_blue_right_shift; + newred = red >> g_red_right_shift; + newgreen = green >> g_green_right_shift; + newblue = blue >> g_blue_right_shift; - tmp = ((newred & g_red_mask) << g_red_left_shift) + - ((newgreen & g_green_mask) << g_green_left_shift) + - ((newblue & g_blue_mask) << g_blue_left_shift); - g_palette_8to1624[col_num] = tmp; + tmp = ((newred & g_red_mask) << g_red_left_shift) + + ((newgreen & g_green_mask) << g_green_left_shift) + + ((newblue & g_blue_mask) << g_blue_left_shift); + g_palette_8to1624[col_num] = tmp; - x_update_color(col_num, red, green, blue, tmp); + x_update_color(col_num, red, green, blue, tmp); } -void -video_update_color_array(int col_num, int a2_color) -{ - int palette; - int full; +void video_update_color_array(int col_num, int a2_color) { + int palette; + int full; - if(col_num >= 256 || col_num < 0) { - halt_printf("video_update_color_array: col: %03x\n", col_num); - return; - } + if(col_num >= 256 || col_num < 0) { + halt_printf("video_update_color_array: col: %03x\n", col_num); + return; + } - full = g_installed_full_superhires_colormap; + full = g_installed_full_superhires_colormap; - palette = col_num >> 4; - if(!full && palette == g_a2vid_palette) { - return; - } + palette = col_num >> 4; + if(!full && palette == g_a2vid_palette) { + return; + } -#if 0 - if(g_screen_depth != 8) { - /* redraw whole superhires for now */ - g_full_refresh_needed = -1; - } -#endif - - video_update_color_raw(col_num, a2_color); + video_update_color_raw(col_num, a2_color); } -void -video_update_colormap() -{ - int palette; - int full; - int i; +void video_update_colormap() { + int palette; + int full; + int i; - full = g_installed_full_superhires_colormap; + full = g_installed_full_superhires_colormap; - if(!full) { - palette = g_a2vid_palette << 4; - for(i = 0; i < 16; i++) { - video_update_color_raw(palette + i, g_lores_colors[i]); - } - x_update_physical_colormap(); - } + if(!full) { + palette = g_a2vid_palette << 4; + for(i = 0; i < 16; i++) { + video_update_color_raw(palette + i, g_lores_colors[i]); + } + x_update_physical_colormap(); + } } -void -video_update_status_line(int line, const char *string) -{ - char *buf; - const char *ptr; - int i; +void video_update_status_line(int line, const char *string) { + char *buf; + const char *ptr; + int i; - if(line >= MAX_STATUS_LINES || line < 0) { - printf("update_status_line: line: %d!\n", line); - exit(1); - } + if(line >= MAX_STATUS_LINES || line < 0) { + printf("update_status_line: line: %d!\n", line); + exit(1); + } - ptr = string; - buf = &(g_status_buf[line][0]); - g_status_ptrs[line] = buf; - for(i = 0; i < STATUS_LINE_LENGTH; i++) { - if(*ptr) { - buf[i] = *ptr++; - } else { - buf[i] = ' '; - } - } + ptr = string; + buf = &(g_status_buf[line][0]); + g_status_ptrs[line] = buf; + for(i = 0; i < STATUS_LINE_LENGTH; i++) { + if(*ptr) { + buf[i] = *ptr++; + } else { + buf[i] = ' '; + } + } - buf[STATUS_LINE_LENGTH] = 0; + buf[STATUS_LINE_LENGTH] = 0; } -void -video_show_debug_info() -{ - word32 tmp1; +void video_show_debug_info() { + word32 tmp1; - printf("g_cur_dcycs: %f, last_vbl: %f\n", g_cur_dcycs, - g_last_vbl_dcycs); - tmp1 = get_lines_since_vbl(g_cur_dcycs); - printf("lines since vbl: %06x\n", tmp1); - printf("Last line updated: %d\n", g_vid_update_last_line); + printf("g_cur_dcycs: %f, last_vbl: %f\n", g_cur_dcycs, + g_last_vbl_dcycs); + tmp1 = get_lines_since_vbl(g_cur_dcycs); + printf("lines since vbl: %06x\n", tmp1); + printf("Last line updated: %d\n", g_vid_update_last_line); } -word32 -float_bus(double dcycs) -{ - word32 val; - int lines_since_vbl; - int line, eff_line, line24; - int all_stat; - int byte_offset; - int hires, page2; - int addr; +word32 float_bus(double dcycs) { + word32 val; + int lines_since_vbl; + int line, eff_line, line24; + int all_stat; + int byte_offset; + int hires, page2; + int addr; - lines_since_vbl = get_lines_since_vbl(dcycs); + lines_since_vbl = get_lines_since_vbl(dcycs); /* For floating bus, model hires style: Visible lines 0-191 are simply the */ /* data being displayed at that time. Lines 192-255 are lines 0 - 63 again */ @@ -3645,46 +3559,46 @@ float_bus(double dcycs) /* nor during veritical blanking. The data seems to be 0 or related to */ /* the instruction fetches on a real IIgs during blankings */ - line = lines_since_vbl >> 8; - byte_offset = lines_since_vbl & 0xff; - /* byte offset is from 0 to 65, where the visible screen is drawn */ - /* from 25 to 65 */ + line = lines_since_vbl >> 8; + byte_offset = lines_since_vbl & 0xff; + /* byte offset is from 0 to 65, where the visible screen is drawn */ + /* from 25 to 65 */ - eff_line = line; - if(line >= 192) { - eff_line = line - 192; - if(line >= 256) { - eff_line = line - 262 + 64; - } - } - all_stat = g_cur_a2_stat; - hires = all_stat & ALL_STAT_HIRES; - if((all_stat & ALL_STAT_MIX_T_GR) && (line >= 160)) { - hires = 0; - } - page2 = EXTRU(all_stat, 31 - BIT_ALL_STAT_PAGE2, 1); - if(all_stat & ALL_STAT_ST80) { - page2 = 0; - } + eff_line = line; + if(line >= 192) { + eff_line = line - 192; + if(line >= 256) { + eff_line = line - 262 + 64; + } + } + all_stat = g_cur_a2_stat; + hires = all_stat & ALL_STAT_HIRES; + if((all_stat & ALL_STAT_MIX_T_GR) && (line >= 160)) { + hires = 0; + } + page2 = EXTRU(all_stat, 31 - BIT_ALL_STAT_PAGE2, 1); + if(all_stat & ALL_STAT_ST80) { + page2 = 0; + } - line24 = (eff_line >> 3) & 0x1f; - addr = g_screen_index[line24] & 0x3ff; - addr = (addr & 0x380) + (((addr & 0x7f) - 25 + byte_offset) & 0x7f); - if(hires) { - addr = 0x2000 + addr + ((eff_line & 7) << 10) + (page2 << 13); - } else { - addr = 0x400 + addr + (page2 << 10); - } + line24 = (eff_line >> 3) & 0x1f; + addr = g_screen_index[line24] & 0x3ff; + addr = (addr & 0x380) + (((addr & 0x7f) - 25 + byte_offset) & 0x7f); + if(hires) { + addr = 0x2000 + addr + ((eff_line & 7) << 10) + (page2 << 13); + } else { + addr = 0x400 + addr + (page2 << 10); + } - val = g_slow_memory_ptr[addr]; - if(byte_offset < 10) { - /* Bob Bishop's sample program seems to get confused by */ - /* these bytes--so mask some off to prevent seeing some */ - val = 0; - } + val = g_slow_memory_ptr[addr]; + if(byte_offset < 10) { + /* Bob Bishop's sample program seems to get confused by */ + /* these bytes--so mask some off to prevent seeing some */ + val = 0; + } #if 0 - printf("For %04x (%d) addr=%04x, val=%02x, dcycs:%9.2f\n", - lines_since_vbl, eff_line, addr, val, dcycs - g_last_vbl_dcycs); + printf("For %04x (%d) addr=%04x, val=%02x, dcycs:%9.2f\n", + lines_since_vbl, eff_line, addr, val, dcycs - g_last_vbl_dcycs); #endif - return val; + return val; }